使用C++获取本地计算机所属的OU(组织单位)名称

4

我需要使用WinAPI/C++查找本地计算机(连接到Active Directory)所属的OU名称。 有任何想法吗?


如果可以使用托管C++,请查看https://dev59.com/rV3Va4cB1Zd3GeqPDcGb。 - Joachim Isaksson
谢谢,但不,托管 C++ 不是一个选项…… - ahmd0
3个回答

2
理论上,这很简单:使用ADsOpenObject连接服务器,实例化一个IDirectorySearch并调用其ExecuteSearch方法,然后使用GetFirstRowGetNextRow来遍历结果数据(但是针对此查询,您只期望得到一行)。
然而,在现实中,所有这些都是基于COM的--因此,预计在至少几百行COM混乱代码中会有大约六个(或更多)函数调用(当代码稳定且健壮时,不要惊讶如果代码接近1000行,其中大部分与Active Directory没有明显的关联)。
我应该补充说明,几乎肯定还有其他方法可以完成这个任务--据我回忆,微软提供了至少两三种不同的访问LDAP类型数据的方法。当我为此编写一些代码时,我最初尝试找到哪种方式最简洁,但最终放弃了。看起来没有希望做得最简洁--至少在那个时候,我选择了“丑陋但有些文档”。

1

如果想要在 C 或 C++ 中以简单的 WINAPI(非 COM)方式访问 Active Directory,请参见 轻量级目录访问协议


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);
}

2
补充一下之前的内容,刚刚发现了这个有关在 DN 中转义“坏”字符的页面:http://msdn.microsoft.com/en-us/library/windows/desktop/aa366101(v=vs.85).aspx - ahmd0

0
    ///////////////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是你想要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接