我需要使用 WinAPI/C++ 找出本地计算机(连接到 Active Directory)所属的 OU 的名称。有任何想法吗?
3 回答
理论上,这相当简单:使用 连接到服务器ADsOpenObject
,实例化 anIDirectorySearch
并调用其ExecuteSearch
方法,然后使用GetFirstRow
和GetNextRow
遍历结果数据(但对于此查询,您只会期望一行)。
然而,在现实中,所有这些都是 COM —— 所以预计这六个(左右)函数调用会在至少一百行 COM 粗略的代码中丢失(当代码变得可靠和健壮时,如果它接近 1000 行,请不要感到惊讶,其中大多数与 Active Directory 没有明显的联系)。
我应该补充一点,几乎可以肯定还有其他方法可以做到这一点——我记得,MS 至少提供了两种或三种不同的方法来访问 LDAP 类型的数据。当我为此编写一些代码时,我最初试图找到最干净的代码,但沮丧地放弃了。似乎没有最干净的希望 - 至少在那时,我选择了“丑陋但有点记录”。
有关以 C 或 C++ 访问 Active Directory 的简单 WINAPI(非 COM)方法,请参阅轻量级目录访问协议
void AfficheErreurLdap(char *fonction, ULONG rc);
/*
*
* Fonction d'entrée du programme
*
*/
void main(int argc, char* argv[])
{
LDAP *pSessionLdap; // Pointeur vers la session LDAP
char *pHote; // Pointeur vers la chaîne représentant le nom de l'hôte
char *pUtilisateur; // Pointeur vers la chaîne représentant l'utilisateur
char *pMotDePasse; // Pointeur vers la chaîne représentant le mot de passe
char *pRacineLdap; // Pointeur vers la racine Ldap
ULONG rc; // Récupération du code de retour des appels
LDAPMessage *pResultat; // Pointeur vers le message résultat de la réquête LDAP
LDAPMessage *pEntree; // Utilisée lors du parcours du résultat pour l'affichage
char *pDN; // Pointeur vers le DN d'une entrée du résultat
char *pAttribut; // Pointeur vers la chaîne représentant l'attribut
BerElement *pBer = NULL;// "curseur" interne à l'API LDAP pour le parcours des elts
char **pValeurs; // Valeurs de l'attribut lors de l'affichage du résultat
int i; // Indice pour la parcours des valeurs d'attribut
/* Analyse des Paramètres de lancement et affichage d’un message d’erreur si incorrect */
if (argc != 5)
{
fprintf(stderr,"Syntaxe :\n\tex_cldap_1 Hote Utilisateur MotDePasse RacineLdap\n");
exit (1);
}
/* Récupération des paramètres des lancement */
pHote = argv[1];
pUtilisateur = argv[2];
pMotDePasse = argv[3];
pRacineLdap = argv[4];
/* Ouverture de la session LDAP et récupération du handle de session */
pSessionLdap = ldap_open( pHote, 389); /* 389 est le numéro de port standard LDAP */
if ( pSessionLdap == NULL )
{
// En cas d'erreur : affichage du message d'erreur adéquat
perror( "ldap_open" );
exit( 2 );
}
printf("Ouverture de la session réalisée\n");
/* Authentification du client */
/* Pour l'exemple, l'authentification est faite en tant qu'anonyme */
rc = ldap_simple_bind_s(pSessionLdap, pUtilisateur, pMotDePasse);
if ( rc != LDAP_SUCCESS )
{
// Erreur lors de l'authentification, on termine après affichage d'un message
AfficheErreurLdap("ldap_simple_bind_s", rc);
exit( 3 );
}
printf("Authentification réalisée\n");
/* */
/* Recherche des données dans l'annuaire */
/* */
rc = ldap_search_s(pSessionLdap, // Session LDAP
pRacineLdap, // Base de la recherche
LDAP_SCOPE_SUBTREE, // Sccpe : LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
"(objectClass=*)", // Filtre de recherche
NULL, // Attributs que l'on souhaite visualiser
0, // Indique si l'on souhaite uniquement les types (1) ou
// Les attributs et les valeurs (0)
&pResultat ) ; // Pointeur vers le résultat
if (rc != LDAP_SUCCESS )
{
// Erreur lors de la recherche, on termine après affichage du message d'erreur
AfficheErreurLdap("ldap_search_s", rc);
exit (4);
}
printf("Requête réalisée\n");
/* On va maintenant parcourir le résultat et afficher les couples */
/* attributs, valeurs */
pEntree = ldap_first_entry( pSessionLdap, pResultat );
while (pEntree != NULL)
{
// Récupération du DN, et affichage de celui-ci
pDN = ldap_get_dn( pSessionLdap, pEntree );
if ( pDN != NULL )
{
printf( "dn: %s\n", pDN );
// Libération de la mémoire allouée par l'API LDAP
ldap_memfree( pDN );
}
// Pour chaque attribut, on va lire le couple attribut, valeur
pAttribut = ldap_first_attribute( pSessionLdap, pEntree, &pBer );
while ( pAttribut != NULL)
{
// Récupération des valeurs associées à un attribut
pValeurs = ldap_get_values( pSessionLdap, pEntree, pAttribut);
if (pValeurs != NULL )
{
for ( i = 0; pValeurs[i] != NULL; i++ )
printf( "%s: %s\n", pAttribut, pValeurs[i]);
// Libération des valeurs lues
ldap_value_free( pValeurs );
}
// Libération de la mémoire utilisée par l'attribut
ldap_memfree( pAttribut );
// Lecture de l'attribut suivant
pAttribut = ldap_next_attribute( pSessionLdap, pEntree, pBer );
}
// Passage à la ligne dans l'affichage
printf( "\n\n" );
// Récupération de l'entrée suivante de l'annuaire
pEntree = ldap_next_entry( pSessionLdap, pEntree );
}
// Libération du message de résultat
ldap_msgfree( pResultat );
/* Fin de la session LDAP */
ldap_unbind( pSessionLdap );
}
/*
*
* Fonction permettant d'afficher les erreurs des opérations LDAP
*
*
*/
void AfficheErreurLdap(char *fonction, ULONG rc)
{
fprintf(stderr,"Erreur LDAP dans la fonction '%s', Code : %ld (0x%xld)\n", fonction, rc,rc);
}
///////////////IDirectorySearch///////////////////////////////////////////////////////////
CComPtr<IDirectorySearch> pDSSearch;
hr = ADsGetObject( L"LDAP://DC=forest,DC=internal",
IID_IDirectorySearch,
(void**) &pDSSearch );
if ( !SUCCEEDED(hr) )
{
return 0;
}
LPWSTR pszAttr[] = { L"description", L"Name", L"distinguishedname" };
ADS_SEARCH_HANDLE hSearch;
DWORD dwCount = 0;
ADS_SEARCH_COLUMN col;
DWORD dwAttrNameSize = sizeof(pszAttr)/sizeof(LPWSTR);
// Search for all objects with the 'cn' property TESTCOMP.
hr = pDSSearch->ExecuteSearch(L"(&(objectClass=computer)(cn=TESTCOMP))",pszAttr ,dwAttrNameSize,&hSearch );
LPWSTR pszColumn;
while( pDSSearch->GetNextRow( hSearch) != S_ADS_NOMORE_ROWS )
{
// Get the property.
hr = pDSSearch->GetColumn( hSearch, L"distinguishedname", &col );
// If this object supports this attribute, display it.
if ( SUCCEEDED(hr) )
{
if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
wprintf(L"The description property:%s\r\n", col.pADsValues->CaseIgnoreString);
pDSSearch->FreeColumn( &col );
}
else
puts("description property NOT available");
puts("------------------------------------------------");
dwCount++;
}
pDSSearch->CloseSearchHandle(hSearch);
///////////////IDirectorySearch///////////////////////////////////////////////////////////
在此搜索中,您将获得
(*((col).pADsValues)).DNString "CN=TESTCOMP,OU=OUnit3,OU=OUnit,DC=forest,DC=internal"
所以这是通往 TESTCOMP 的道路,我相信 OUnit3 就是你想要的。