之前用ldap_open API系列,在bind的时候老是提示无效认证,最后msdn还找到了一种COM接口获取AD域控服务器用户列表的方法,代码我在例子的基础上修改了下,测试通过,能获取到:
// ldapsearch.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Iads.h> #include <Adshlp.h> #include <activeds.h> #include <adserr.h> #include <comutil.h> #pragma comment(lib,"Activeds.lib") #pragma comment(lib,"adsiid.lib") #pragma comment(lib,"comsuppw.lib") // Define UNICODE. // Define version 5 for Windows 2000. #define _WIN32_WINNT 0x0500 #include <sddl.h> HRESULT FindUsers(IDirectorySearch *pContainerToSearch, // IDirectorySearch pointer to the container to search. LPOLESTR szFilter, // Filter to find specific users. // NULL returns all user objects. LPOLESTR *pszPropertiesToReturn, // Properties to return for user objects found. // NULL returns all set properties. BOOL bIsVerbose // TRUE indicates that display all properties for the found objects. // FALSE indicates that only the RDN. ); // Entry point for the application. void _tmain(int argc, wchar_t *argv[ ]) { // Handle the command line arguments. DWORD dwLength = MAX_PATH*2; LPOLESTR pszBuffer = new OLECHAR[dwLength]; wcsncpy(pszBuffer, L"",dwLength); BOOL bReturnVerbose = FALSE; wcsncpy(pszBuffer,L"(name=*)",dwLength-wcslen(pszBuffer)); if (_wcsicmp(pszBuffer,L"") == 0) wprintf(L"\nFinding all user objects...\n\n"); else wprintf(L"\nFinding user objects based on query: %s...\n\n", pszBuffer); // Initialize COM. CoInitialize(NULL); HRESULT hr = S_OK; // Get rootDSE and the current user domain container distinguished name. IDirectorySearch *pContainerToSearch = NULL; if (TRUE) { if (TRUE) { LPWSTR szUsername = _T("administrator"); // user name LPWSTR szPassword = _T("123"); // password // Build path to the domain container. hr = ADsOpenObject(L"LDAP://192.168.19.11:389", szUsername, szPassword, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (void **)&pContainerToSearch); if (SUCCEEDED(hr)) { hr = FindUsers(pContainerToSearch, // IDirectorySearch pointer to domainDNS container. pszBuffer, NULL, // Return all properties. bReturnVerbose ); if (SUCCEEDED(hr)) { if (S_FALSE==hr) wprintf(L"User object cannot be found.\n"); } else if (E_ADS_INVALID_FILTER==hr) wprintf(L"Cannot execute query. Invalid filter was specified.\n"); else wprintf(L"Query failed to run. HRESULT: %x\n",hr); } else { wprintf(L"Cannot execute query. Cannot bind to the container.\n"); } if (pContainerToSearch) pContainerToSearch->Release(); } } getchar(); // Uninitialize COM. CoUninitialize(); delete [] pszBuffer; return; } HRESULT FindUsers(IDirectorySearch *pContainerToSearch, // IDirectorySearch pointer to the container to search. LPOLESTR szFilter, // Filter for finding specific users. // NULL returns all user objects. LPOLESTR *pszPropertiesToReturn, // Properties to return for user objects found. // NULL returns all set properties. BOOL bIsVerbose // TRUE indicates that all properties for the found objects are displayed. // FALSE indicates only the RDN. ) { if (!pContainerToSearch) return E_POINTER; DWORD dwLength = MAX_PATH*2; // Create search filter. LPOLESTR pszSearchFilter = new OLECHAR[dwLength]; // Add the filter. swprintf_s(pszSearchFilter, dwLength, L"(&(objectClass=user)(objectCategory=person)%s)",szFilter); // Specify subtree search. ADS_SEARCHPREF_INFO SearchPrefs; SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; SearchPrefs.vValue.dwType = ADSTYPE_INTEGER; SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE; DWORD dwNumPrefs = 1; // COL for iterations. LPOLESTR pszColumn = NULL; ADS_SEARCH_COLUMN col; HRESULT hr = S_OK; // Search handle. ADS_SEARCH_HANDLE hSearch = NULL; // Set search preference. hr = pContainerToSearch->SetSearchPreference(&SearchPrefs, dwNumPrefs); if (FAILED(hr)) return hr; LPOLESTR pszBool = NULL; DWORD dwBool = 0; PSID pObjectSID = NULL; LPOLESTR szSID = NULL; LPOLESTR szDSGUID = new WCHAR [39]; LPGUID pObjectGUID = NULL; FILETIME filetime; SYSTEMTIME systemtime; DATE date; VARIANT varDate; LARGE_INTEGER liValue; LPOLESTR *pszPropertyList = NULL; LPOLESTR pszNonVerboseList[] = {L"name",L"distinguishedName"}; LPOLESTR szName = new OLECHAR[MAX_PATH]; LPOLESTR szDN = new OLECHAR[MAX_PATH]; VariantInit(&varDate); int iCount = 0; DWORD x = 0L; if (!bIsVerbose) { // Return non-verbose list properties only. hr = pContainerToSearch->ExecuteSearch(pszSearchFilter, pszNonVerboseList, sizeof(pszNonVerboseList)/sizeof(LPOLESTR), &hSearch ); } else { if (!pszPropertiesToReturn) { // Return all properties. hr = pContainerToSearch->ExecuteSearch(pszSearchFilter, NULL, (DWORD)-1, &hSearch ); } else { // Specified subset. pszPropertyList = pszPropertiesToReturn; // Return specified properties. hr = pContainerToSearch->ExecuteSearch(pszSearchFilter, pszPropertyList, sizeof(pszPropertyList)/sizeof(LPOLESTR), &hSearch ); } } if (SUCCEEDED(hr)) { // Call IDirectorySearch::GetNextRow() to retrieve the next data row. hr = pContainerToSearch->GetFirstRow(hSearch); if (SUCCEEDED(hr)) { while(hr != S_ADS_NOMORE_ROWS) { // Keep track of count. iCount++; if (bIsVerbose) wprintf(L"----------------------------------\n"); // Loop through the array of passed column names, // print the data for each column. while(pContainerToSearch->GetNextColumnName(hSearch, &pszColumn) != S_ADS_NOMORE_COLUMNS) { hr = pContainerToSearch->GetColumn(hSearch, pszColumn, &col); if (SUCCEEDED(hr)) { // Print the data for the column and free the column. if(bIsVerbose) { // Get the data for this column. wprintf(L"%s\n",col.pszAttrName); switch (col.dwADsType) { case ADSTYPE_DN_STRING: for (x = 0; x< col.dwNumValues; x++) { wprintf(L" %s\r\n",col.pADsValues[x].DNString); } break; case ADSTYPE_CASE_EXACT_STRING: case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_PRINTABLE_STRING: case ADSTYPE_NUMERIC_STRING: case ADSTYPE_TYPEDNAME: case ADSTYPE_FAXNUMBER: case ADSTYPE_PATH: for (x = 0; x< col.dwNumValues; x++) { wprintf(L" %s\r\n",col.pADsValues[x].CaseIgnoreString); } break; case ADSTYPE_BOOLEAN: for (x = 0; x< col.dwNumValues; x++) { dwBool = col.pADsValues[x].Boolean; pszBool = dwBool ? L"TRUE" : L"FALSE"; wprintf(L" %s\r\n",pszBool); } break; case ADSTYPE_INTEGER: for (x = 0; x< col.dwNumValues; x++) { wprintf(L" %d\r\n",col.pADsValues[x].Integer); } break; case ADSTYPE_OCTET_STRING: if (_wcsicmp(col.pszAttrName,L"objectSID") == 0) { for (x = 0; x< col.dwNumValues; x++) { pObjectSID = (PSID)(col.pADsValues[x].OctetString.lpValue); // Convert SID to string. ConvertSidToStringSid(pObjectSID, &szSID); wprintf(L" %s\r\n",szSID); LocalFree(szSID); } } else if ((_wcsicmp(col.pszAttrName,L"objectGUID") == 0)) { for (x = 0; x< col.dwNumValues; x++) { // Cast to LPGUID. pObjectGUID = (LPGUID)(col.pADsValues[x].OctetString.lpValue); // Convert GUID to string. ::StringFromGUID2(*pObjectGUID, szDSGUID, 39); // Print the GUID. wprintf(L" %s\r\n",szDSGUID); } } else wprintf(L" Value of type Octet String. No Conversion."); break; case ADSTYPE_UTC_TIME: for (x = 0; x< col.dwNumValues; x++) { systemtime = col.pADsValues[x].UTCTime; if (SystemTimeToVariantTime(&systemtime, &date) != 0) { // Pack in variant.vt. varDate.vt = VT_DATE; varDate.date = date; VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR); wprintf(L" %s\r\n",varDate.bstrVal); VariantClear(&varDate); } else wprintf(L" Could not convert UTC-Time.\n",pszColumn); } break; case ADSTYPE_LARGE_INTEGER: for (x = 0; x< col.dwNumValues; x++) { liValue = col.pADsValues[x].LargeInteger; filetime.dwLowDateTime = liValue.LowPart; filetime.dwHighDateTime = liValue.HighPart; if((filetime.dwHighDateTime==0) && (filetime.dwLowDateTime==0)) { wprintf(L" No value set.\n"); } else { // Verify properties of type LargeInteger that represent time. // If TRUE, then convert to variant time. if ((0==wcscmp(L"accountExpires", col.pszAttrName))| (0==wcscmp(L"badPasswordTime", col.pszAttrName))|| (0==wcscmp(L"lastLogon", col.pszAttrName))|| (0==wcscmp(L"lastLogoff", col.pszAttrName))|| (0==wcscmp(L"lockoutTime", col.pszAttrName))|| (0==wcscmp(L"pwdLastSet", col.pszAttrName)) ) { // Handle special case for Never Expires where low part is -1. if (filetime.dwLowDateTime==-1) { wprintf(L" Never Expires.\n"); } else { if (FileTimeToLocalFileTime(&filetime, &filetime) != 0) { if (FileTimeToSystemTime(&filetime, &systemtime) != 0) { if (SystemTimeToVariantTime(&systemtime, &date) != 0) { // Pack in variant.vt. varDate.vt = VT_DATE; varDate.date = date; VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR); wprintf(L" %s\r\n",varDate.bstrVal); VariantClear(&varDate); } else { wprintf(L" FileTimeToVariantTime failed\n"); } } else { wprintf(L" FileTimeToSystemTime failed\n"); } } else { wprintf(L" FileTimeToLocalFileTime failed\n"); } } } else { // Print the LargeInteger. wprintf(L" high: %d low: %d\r\n",filetime.dwHighDateTime, filetime.dwLowDateTime); } } } break; case ADSTYPE_NT_SECURITY_DESCRIPTOR: for (x = 0; x< col.dwNumValues; x++) { wprintf(L" Security descriptor.\n"); } break; default: wprintf(L"Unknown type %d.\n",col.dwADsType); } } else { // Verbose handles only the two single-valued attributes: cn and ldapdisplayname, // so this is a special case. if (0==wcscmp(L"name", pszColumn)) { wcscpy(szName,col.pADsValues->CaseIgnoreString); } if (0==wcscmp(L"distinguishedName", pszColumn)) { wcscpy(szDN,col.pADsValues->CaseIgnoreString); } } pContainerToSearch->FreeColumn(&col); } FreeADsMem(pszColumn); } if (!bIsVerbose) wprintf(L"%s\n DN: %s\n\n",szName,szDN); // Get the next row. hr = pContainerToSearch->GetNextRow(hSearch); } } // Close the search handle to cleanup. pContainerToSearch->CloseSearchHandle(hSearch); } if (SUCCEEDED(hr) && 0==iCount) hr = S_FALSE; delete [] szName; delete [] szDN; delete [] szDSGUID; delete [] pszSearchFilter; return hr; }