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.
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:
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!
For C#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;
}
Thanks Timovjl! I can use the functions to get the AD user properties now. This is the source code for reference:
#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.
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.
Use ldap_get_dn() to retrieve the full DN string with following the ldap_first_entry() and ldap_next_entry()
http://msdn.microsoft.com/en-us/library/windows/desktop/ms675089(v=vs.85).aspx
Here all the attributes can be found out.
I have create a simle program showing how to walk through and enum all objects/users' information under a certain OU.
#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;
}