NO

Author Topic: Active Directory object-related operation  (Read 6483 times)

liut

  • Guest
Active Directory object-related operation
« on: November 07, 2013, 03:10:30 AM »
Hi everybody, another question from me... Can anybody provide an example how to operate an AD object, such get/set some properties of an AD user?

For the normal info of an AD user, we can use NetUserGetInfo() to get it. But for the further properties, such as Telephone/Address info, MS SDK assembled them into a CPP interface (that's a little out of my knowing). The following example is from the SDK doc:



The following C++ code example shows how to use the ADsGetObject function to bind to an object.

Code: [Select]
IADs *pObject;
HRESULT hr;

// Initialize COM.
CoInitialize(NULL);

hr = ADsGetObject(L"LDAP://CN=jeffsmith,DC=fabrikam,DC=com",
        IID_IADs,
        (void**) &pObject);

if(SUCCEEDED(hr))
{
    // Use the object.

    // Release the object.
    pObject->Release()
}

// Uninitialize COM.
CoUninitialize();

So if I want to access this info in my C program, I need to have the C-std function/variable declare, and know how to use it.
I look into the head file "iads.h", actually they all are there:
Code: [Select]
typedef struct IADsUserVtbl {
    BEGIN_INTERFACE
    HRESULT (STDMETHODCALLTYPE * QueryInterface) (IADsUser * This, REFIID riid, void **ppvObject);
    ....
    HRESULT (STDMETHODCALLTYPE * get_TelephoneHome) (IADsUser * This, VARIANT * retval);
    HRESULT (STDMETHODCALLTYPE * put_TelephoneHome) (IADsUser * This, VARIANT vTelephoneHome);

#define IADsUser_QueryInterface(This,riid,ppvObject)  (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
...

If there is a simple C-std example showing how to use them or any tips for it, I'll appreciate you very much!
« Last Edit: November 07, 2013, 06:23:23 PM by Stefan Pendl »

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Active Directory object-related operation
« Reply #1 on: November 07, 2013, 06:59:57 PM »
For C
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//#define INITGUID
#include <ole2.h>
#include <Iads.h>
#include <Adshlp.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Activeds.lib")
//#pragma comment(lib, "ADSIid.lib") // missing from PellesC
//#pragma comment(lib, "uuid.lib")

const IID IID_IADs = {0xFD8256D0, 0xFD15, 0x11CE, {0xAB,0xC4,0x02,0x60,0x8C,0x9E,0x75,0x53}};

IADs *pObject;
HRESULT hr;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{

// Initialize COM.
CoInitialize(NULL);

hr = ADsGetObject(L"LDAP://CN=jeffsmith,DC=fabrikam,DC=com", &IID_IADs, (void **)&pObject);

if (SUCCEEDED(hr)) {
// Use the object.

// Release the object.
pObject->lpVtbl->Release(pObject);
}
// Uninitialize COM.
CoUninitialize();

return 0;
}
May the source be with you

liut

  • Guest
Re: Active Directory object-related operation
« Reply #2 on: November 15, 2013, 04:46:33 AM »
Thanks Timovjl! I can use the functions to get the AD user properties now. This is the source code for reference:

Code: [Select]
#include <wchar.h>
#include <stdio.h>
#include <windows.h>

#include <iads.h>
#include <adshlp.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "Activeds.lib")

const IID iadsuser={0x3e37e320,0x17e2,0x11cf,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};

int main(int argc,char *argv[])
{
IADsUser *pObject;
HRESULT hr,hr1;

BSTR bstr;
VARIANT var;

// Initialize COM.
CoInitialize(NULL);

hr = ADsGetObject(L"LDAP://CN=Full Name,OU=XX,OU=YY,DC=ABC,DC=COM",&iadsuser,(void**)&pObject);
//hr = ADsGetObject(L"WinNT://ABC.COM/Shortname,user",&iadsuser,(void**)&pObject);

if(hr==S_OK)
{
    // Use the object.
printf("Success -> ADsGetObject()\n");

char text[100];
memset(text,0,sizeof(text));

hr1=pObject->lpVtbl->get_FullName(pObject,&bstr);
if(hr1==S_OK){
printf("Success -> get_FullName()\n");
wcstombs(text,bstr,wcslen((wchar_t *)bstr));

printf("%s\n",text);
SysFreeString(bstr);
}
else printf("Fail code=%lx -> get_FullName()\n",hr1);

memset(text,0,sizeof(text));
hr1=pObject->lpVtbl->get_EmailAddress(pObject,&bstr);
if(hr1==S_OK){
printf("Success -> get_EmailAddress()\n");
wcstombs(text,bstr,wcslen((wchar_t *)bstr));

printf("%s\n",text);
SysFreeString(bstr);
}
else printf("Fail code=%lx -> get_EmailAddress()\n",hr1);

memset(text,0,sizeof(text));
hr1=pObject->lpVtbl->get_TelephonePager(pObject,&var);
if(hr1==S_OK){
printf("Success -> get_TelephonePager()\n");
wcstombs(text,V_BSTR(&var),wcslen((wchar_t *)V_BSTR(&var)));

printf("%s\n",text);
VariantClear(&var);
}
else printf("Fail code=%lx -> get_TelephonePager()\n",hr1);

    // Release the object.
//     pObject->Release();
pObject->lpVtbl->Release(pObject);
}
else printf("Fail code=%lx -> Release()\n",hr);

// Uninitialize COM.
CoUninitialize();

return 0;
}

For the ADsGetObject(), if I use WinNT format string, then many properties can't be got (this is mentioned in Win SDK document); if I use LDAP format string, I have to use an 'exact' path and full name string to get the object. Then I have further questions now:
1) If I only know the AD user's login name (shortname), I don't know how to find it out or convert it to the full LDAP string;
2) I don't know how to enum or set filter to search a mass of AD users, although I know it's possible technically.
« Last Edit: November 16, 2013, 10:59:14 AM by Stefan Pendl »

liut

  • Guest
Re: Active Directory object-related operation
« Reply #3 on: November 15, 2013, 08:09:39 AM »
I just found another set of interface of MS native api for ldap. Here is an example:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa367016(v=vs.85).aspx

It works with a little modification. There is 2 notices:
1) in ldap_bind_s(), if the method is LDAP_AUTH_NEGOTIATE, the DN and Cred can be set to NULL (use current user);
2) in ldap_search_s(), this link is the description of syntax:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa746475(v=vs.85).aspx

Now I'm studying what info/entry the ldap can provide to me.

liut

  • Guest
Re: Active Directory object-related operation
« Reply #4 on: November 15, 2013, 08:34:39 AM »
Use ldap_get_dn() to retrieve the full DN string with following the ldap_first_entry() and ldap_next_entry()

liut

  • Guest
Re: Active Directory object-related operation
« Reply #5 on: November 15, 2013, 09:14:00 AM »

liut

  • Guest
Re: Active Directory object-related operation
« Reply #6 on: December 03, 2013, 04:26:30 AM »
I have create a simle program showing how to walk through and enum all objects/users' information under a certain OU.
Code: [Select]
#define UNICODE
#define COBJMACROS

#include <windows.h>
#include <wchar.h>

#include <iads.h>
#include <adshlp.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "Activeds.lib")
#pragma comment(lib, "User32.lib")

const IID iads_container={0x001677d0,0xfd16,0x11ce,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};
const IID iads={0xfd8256d0,0xfd15,0x11ce,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};

int read_all_objects(IADsContainer *p_container)
{
int num_objects=0;
HRESULT hr;

// 1. Build Enumerator for the AD Object
IEnumVARIANT *p_enum=NULL;
hr=ADsBuildEnumerator(p_container,&p_enum);
if(hr!=S_OK) return 0;

// 2. Enum Each Object
VARIANT var;
while(TRUE){
// 2.1 Enum One Object
hr=ADsEnumerateNext(p_enum,1,&var,NULL);
if(hr==S_FALSE) break; // No more object

num_objects++;

// 2.2 Query Object's Interface
IADs *p_ads=NULL;
//hr=V_DISPATCH(&var)->QueryInterface(&iads,(void **)&p_ads);
hr=IADs_QueryInterface(V_DISPATCH(&var),&iads,(void **)&p_ads);
if(hr==S_OK){
// 2.2.1 Get Object's Name
BSTR name_str;
HRESULT hr1;
hr1=p_ads->lpVtbl->get_Name(p_ads,&name_str);
if(hr1==S_OK){
HRESULT hr2;

// 2.2.1.1 Output Object's Name
wprintf(L"Object name: %ls\n",(wchar_t *)name_str);

// 2.2.1.2 Get & Output Object's Full Name
wprintf(L"Full name: %ls\n",wcschr((wchar_t *)name_str,L'=')+1);

// 2.2.1.3 Get & Output Object's Principal Name if it's a regular user, Format: accountname@domainname
VARIANT var_principalname;

hr2=p_ads->lpVtbl->Get(p_ads,L"userPrincipalName",&var_principalname);
if(hr2==S_OK){
wprintf(L"Principal name: %ls\n",(wchar_t *)V_BSTR(&var_principalname));

VariantClear(&var_principalname);
}

// 2.2.1.4 Get & Output Object's Email Address if there is this information
VARIANT var_mail;

hr2=p_ads->lpVtbl->Get(p_ads,L"mail",&var_mail);
if(hr2==S_OK){
wprintf(L"Email address: %ls\n\n",(wchar_t *)V_BSTR(&var_mail));

VariantClear(&var_mail);
}

// 2.2.1.n-1 Read Sub-Objects
IADsContainer *p_child_ads;

hr2=IADsContainer_QueryInterface(p_ads,&iads_container,(void **)&p_child_ads);
if(hr2==S_OK){
num_objects+=read_all_objects(p_child_ads);
}

// 2.2.1.n Release str space
SysFreeString(name_str);
}

// 2.2.n Release Object
p_ads->lpVtbl->Release(p_ads);
}

// 2.n Clean up VAR
VariantClear(&var);
}

// n. Free Enumerator
ADsFreeEnumerator(p_enum);

return num_objects;
}

int read_ad_tree(wchar_t *ldap_tree_name)
{
HRESULT hr;
IADsContainer *p_container=NULL;

hr=ADsGetObject(ldap_tree_name,&iads_container,(void **)&p_container);
if(hr!=S_OK) return -1;

return read_all_objects(p_container);
}

int main(int argc,char *argv[])
{
int ret;

CoInitialize(NULL);

ret=read_ad_tree(L"LDAP://OU=DEPTNAME,DC=ABC,DC=COM");
if(ret>=0) wprintf(L"Success & found %d objects.\n",ret);
if(ret==-1) wprintf(L"ADsGetObject() error.\n");

CoUninitialize();

return 0;
}
« Last Edit: December 04, 2013, 12:11:34 AM by Stefan Pendl »