LDAP API

LDAP  API
 
介紹
這篇文檔定義了 LDAP API (C語言版)。它使用方便,功能強大,大致內容有以下幾個方面:
簡單瀏覽LDAP模型
應用程序怎樣使用API去獲取LDAP信息
詳細介紹API 調用函數
舉例使用API 及部分樣本代碼
      下面我們分別介紹。
簡單瀏覽LDAP模型
       LDAP 是以client-server 模型爲基礎的,在此模型中,客戶機可以建立與LDAP服務器的連接,從而發送請求,接收應答。
       LDAP的信息模型是基於實體(entry)的,每個實體都代表着某種對象類型的特例。比如組織機構、用戶、網絡、計算機等。每一種實體又包含有許多屬性,每種屬性又由它的實體所代表的對象的類型決定。
      實體用樹型結構組織再一起,通常根據政治上的,地理學的,和組織的關係進行分類。每一個實體都有唯一的名字通過它的RDN與它的同屬實體相連。
三、LDAP API使用瀏覽
      一個應用使用LDAP API 的一般步驟:
建立與LDAP server的連接。如使用函數調用 ldap_open()等。
覈對身份 ldap server 和(或)X.500 DSA,如可以使用ldap_bind().
執行某些LDAP操作,返回某些結果。
最後斷開連接。
API的操作可以被同步執行,也可以異步執行。同步的函數調用以_s結尾。例如:同步查找操作可以通過調用ldap_search_s()來完成。異步調用將返回一個result,用來表示操作結果(如,常量LDAP_SUCCESS或者其它錯誤代碼)。異步調用還將返回初始化操作的消息id。異步操作可以通過調用ldap_abandon()而拋棄。
結果和錯誤信息被作爲一個不透明的結構LDAPMessage 返回,函數調用的目的就是分析這一結構,進一步研究被返回的實體和屬性等。有時也負責解釋這些屬性。下面我們將詳細介紹API函數調用。
四、  LDAP API函數調用
      這裏所有的調用都含有一個“連接手柄”(connection handle)它指向關於每個連接的信息的LDAP結構。許多調用的返回結果都是LDAPMessage結構形式。下面我們會描繪出這些必要的結構。
    1.  建立連接
   ldap_open() 建立一個同 LDAP server的連接。有關定義如下:
               LDAP *ldap_open( char *hostname, int portno );

      參數說明:
      hostname 空格分開的主機名字表或點分開的LDAP server 可以連接到的主機的IP地址串。主機試着依次連接表中列出的每個名字直到某個連接成功時才停止。
      portno   欲連接的TCP端口號。如果省略則爲 LDAP_PORT.
   如果連接不能建立,則返回值爲NULL。
2.  Authenticating to the directory
       ldap_bind() 和它的同類派生常用來識別目錄:         
          int ldap_bind( LDAP *ld, char *dn, char *cred, int method );
          int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method );
          int ldap_simple_bind( LDAP *ld, char *dn, char *passwd );
          int ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd );
          int ldap_kerberos_bind( LDAP *ld, char *dn );
          int ldap_kerberos_bind_s( LDAP *ld, char *dn );
 參數說明:
   ld    連接手柄;
   dn    被bind的實體名;
   cred  識別證書;
   method  LDAP_AUTH_SIMPLE, LDAP_AUTH_KRBV41, 或
          LDAP_AUTH_KRBV42, 用以表明要使用的識別方法。
   passwd    爲 ldap_simple_bind()而準備的口令,並與實體中的
            userPassword 屬性比較。
   3.  Closing the connection
   ldap_unbind() 用來解開同目錄的聯繫並斷開建立的連接。
           int ldap_unbind( LDAP *ld );

   參數說明:
      ld   連接手柄;
 通過調用ldap_unbind() ,則ld 連接手柄就無效了。 
4.  Searching
   ldap_search() 等用來查找 LDAP目錄,返回與實體匹配的屬性。
           struct timeval {
                   long    tv_sec;
                   long    tv_usec;
           };
           int ldap_search(
                   LDAP    *ld,
                   char    *base,
                   int     scope,
                   char    *filter,
                   char    *attrs[],
                   int     attrsonly
           );
           int ldap_search_s(
                   LDAP            *ld,
                   char            *base,


                   int             scope,
                   char            *filter,
                   char            *attrs[],
                   int             attrsonly,
                   LDAPMessage     **res
           );
           int ldap_search_st(
                   LDAP            *ld,
                   char            *base,
                   int             scope,
                   char            *filter,
                   char            *attrs[],
                   int             attrsonly,
                   struct timeval  *timeout,
                   LDAPMessage     **res
           );

參數說明:
   ld        連接手柄;
   base      開始尋找的基礎對象的DN
   Scope :LDAP_SCOPE_BASE,LDAP_SCOPE_ONELEVEL, 或LDAP_SCOPE_SUBTREE,用來表明查找的範圍。
filter  :是一個表示LDAP查詢的filter,是字符串表示,它的格式      
       定義在RFC 1588中。
attrs   :一系列指針字符用於表徵查找返回屬性
attrsevly:布爾參數:0表示返回屬性類型和值;非0,僅返回類型。
timeout   爲 ldap_search_st() 而說明當地查找操作的超時值。
res       爲同步調用準備的結果參數,記錄查找完成的結果。
 在ld連接手柄中有三個域控制查找操作的進行。它們是:
 ld_sizelimit  查找實體實體返回的個數,如果爲零,表示無限制。
 ld_timelimit 查找時間限制,如果爲零,表示無限制。
 ld_deref   LDAP_DEREF_NEVER,LDAP_DEREF_SEARCHING,
         LDAP_DEREF_FINDING,LDAP_DEREF_ALWAYS之一。
        用來說明再查找中別名怎麼處理。
         LDAP_DEREF_NEVER: 在搜索中或者查找那基礎對象時
            做不復引用別名。
          LDAP_DEREF_SEARCHING: 在基礎對象的附屬的搜索
            中而不是查找那基礎對象時做復引用別名。
          LDAP_DEREF_FINDING:  在基礎對象而不是其附屬的
           搜索中做復引用別名。
           LDAP_DEREF_ALWAYS: 在搜索中或者查找那基礎對
            象時做都復引用別名。
         一個異步查找通過調用ldap_search()進行初始化.該操作返
回本初始化查找的消息id,要想得到這個結果,可以調用ldap_result().
     一個同步查找可以調用ldap_search_s() 或 ldap_search_st()來
實現.除了 ldap_search_st() 多了一個參數描述查找時限外,這兩個
函數的功能基本是一樣的。他們都返回一個查找結果,是LDAP
_SUCCESS 或一些錯誤信息(看下面的錯誤處理Error  Handling).
查找操作返回的實體(如果有)必包含一個參數res .這個參數對調
用者來說是不透明的。Entries, attributes, values等等都必須調用下面
的分析程序才能進行分析。包含參數 res 的 結果只有不再使用且調
用 ldap_msgfree()時才被釋放掉。
5.  Reading an entry
   LDAP 不直接支持讀操作,但此操作可以基於實體的DN的查找來仿效。其參數設置如下:
            scope     LDAP_SCOPE_BASE,
            filter    "(objectclass=*)".
    則attrs 包含有返回的屬性表。
6.  Listing the children of an entry
   LDAP 也不直接支持表操作,同上我們有:
           scope      LDAP_SCOPE_ONELEVEL,
           filter    "(objectclass=*)".
     則attrs 就包含了要返回的每個子女實體的屬性表。
7.  Modifying an entry
ldap_modify() 和 ldap_modify_s() 常用來修改現存的LDAP
實體。有關定義如下:
           typedef struct ldapmod {
                   int             mod_op;
                   char            *mod_type;
                   union {
                           char            **modv_strvals;
                           struct berval   **modv_bvals;
                   } mod_vals;
           } LDAPMod;
           #define mod_values      mod_vals.modv_strvals
           #define mod_bvalues     mod_vals.modv_bvals

    int ldap_modify( LDAP *ld, char *dn, LDAPMod *mods[] );
    int ldap_modify_s( LDAP *ld, char *dn, LDAPMod *mods[] );
  參數說明:
     ld       連接手柄;
     dn       被修改的實體名;
     mods     修改表,填入修改方式,如ADD、DELETE等。
  LDAPMod 結構中的域解釋如下:
      mod_op        修改操作,它可以是LDAP_MOD_ADD,
            LDAP_MOD_DELETE,或LDAP_MOD_REPLACE.
            這個域也用來表明包含在mod_vals union中的值的類
            型.
   mod_type 被修改的屬性的類型。
   mod_vals  需要增加、刪除或替換的值。
  ldap_modify_s() 返回的是來自修改操作的LDAP 錯誤代碼,可以
調用ldap_perror()及其一類的函數來解釋。
  ldap_modify() 返回的是它對請求初始化的消息 id ,或者是代表錯誤的值 -1 ,這個操作結果可以通過調用 ldap_result()來獲得。
Modifying the RDN of an entry
   ldap_modrdn()和 ldap_modrdn_s() 常用來改變LDAP 實體的名字。
            int ldap_modrdn(
                   LDAP    *ld,
                   char    *dn,
                   char    *newrdn,
                   int     deleteoldrdn
           );
           int ldap_modrdn_s(
                   LDAP    *ld,
                   char    *dn,
                   char    *newrdn,
                   int     deleteoldrdn
           );

 參數說明:
   ld       連接手柄 ;
   dn       實體名,它的RDN要被改變;
   newrdn   新的 RDN ;
   deleteoldrdn  是一個布爾值;用來控制舊的RDN屬性值是作爲表的某一屬性保存下來(0),還是把它刪掉(非0)。
  ldap_modrdn_s() 是同步的,返回一個LDAP 錯誤代碼,表示操作出口。
  ldap_modrdn() 則是異步的,返回的是它對請求初始化的消息 id ,或者是代表錯誤的值 -1 ,這個操作結果可以通過調用 ldap_result()來獲得。
 9.  Adding an entry
   ldap_add() 和 ldap_add_s() 用來增加實體到 LDAP目錄上。
           int ldap_add( LDAP *ld, char *dn, LDAPMod *attrs[] );
           int ldap_add_s( LDAP *ld, char *dn, LDAPMod *attrs[] );
   參數說明:
      ld    連接手柄;
      dn    被增加的實體名;
     attrs   實體的屬性表,詳細說明在ldap_modify()裏定義的
LDAPMod 結構中。其中mod_type 和 mod_vals 兩個域應被填上。
注意一點被加實體的父母節點必須已經存在。
     ldap_add_s() 和ldap_add()的區別同上面的解釋一樣。
10.  Deleting an entry
   ldap_delete() 和 ldap_delete_s() 用於從LDAP 目錄中刪除實體。
            int ldap_delete( LDAP *ld, char *dn );
            int ldap_delete_s( LDAP *ld, char *dn );
參數說明:
   ld     連接手柄;
  dn      被刪實體的名字.
注意一點:被刪實體在LDAP結構中必須是一個葉實體,不能有子女,至於刪除完整子樹,LDAP還不支持。
   ldap_delete_s() 和ldap_delete() 與前面的解釋雷同。
五、放棄操作的調用
       ldap_abandon() 用於執行放棄操作的命令。
           int ldap_abandon( LDAP *ld, int msgid );
   ldap_abandon() 放棄的操作是由消息 id  msgid確定的. 如果放棄操作成功,則返回值爲0,否則爲 -1.如果該次調用成功,那麼通過調用ldap_result(),則不返回任何結果。
Calls for obtaining results
   ldap_result() 就是用來獲得上次異步初始化操作的結果。ldap_ms
-gfree() 用於釋放ldap_result()或某個同步查找調用之前的調用獲得的結果。
          int ldap_result(
                   LDAP            *ld,
                   int             msgid,
                   int             all,
                   struct timeval  *timeout,
                   LDAPMessage     **res
           );

           int ldap_msgfree( LDAPMessage *res );
參數說明:
    ld       連接手柄;
   msgid    信息id ,用以確定那個結果需要返回的操作或者
           是 LDAP_RES_ANY (如果需要結果);
   all      布爾參數,僅對查找結果有意義。如果爲零,則查找結
           果(實體)一產生就返回;否則查找結果變化時返回。
   timeout  結果返回的等待時間。如果爲 NULL ,則 ldap_result()
           會一直等到結果有效才返回。如果它的值爲零則指定爲
           一個探詢行爲。
   res      對 ldap_result()來說,它是包含此次操作結果的參數;對
           ldap_msgfree()來說,它是將被釋放的結果鏈。
  如果完成成功,ldap_result() 將返回結果的類型,存於參數res 中。
它必是下列常量之一:
             LDAP_RES_BIND
             LDAP_RES_SEARCH_ENTRY
             LDAP_RES_SEARCH_RESULT
             LDAP_RES_MODIFY
             LDAP_RES_ADD
             LDAP_RES_DELETE
             LDAP_RES_MODRDN
             LDAP_RES_COMPARE
     如果超時, ldap_result() 返回爲0;如果錯誤產生,則返回-1
同時ld結構中的ld_errno 域也相應地被設置。
   ldap_msgfree() 釋放被指定爲參數res的結果結構並且返回它釋放的消息的類型。
七、  Calls for error handling
   下面的調用用來解釋其它LDAP API 返回的錯誤信息:
            int ldap_result2error(
                   LDAP            *ld,
                   LDAPMessage     *res,
                   int             freeit
           );

           char *ldap_err2string( int err );

           void ldap_perror( LDAP *ld, char *msg );

 參數說明:
   ld       連接手柄;
   res    LDAP 操作結果如ldap_result()或其它同步API操作調用
     的返回結果;
   freeit   布爾參數,用以確定參數res 是否被釋放(如果沒有則
     它的值爲0);
   err     LDAP的錯誤代碼,如ldap_result2error() 或其它同步API
          的返回;
   msg    顯示在LDAP錯誤信息之前的信息。
         ldap_result2error()用來把 LDAP 結果信息轉換爲數字的
  LDAP 錯誤代碼,LDAP結果信息可能來自ldap_result(), 也可能
是某個同步API操作調用返回的信息 res。它也用來分析結果信息
中的 ld_matched 和ld_error 兩部分,進而把它們組成連接手柄信
息。所有的同步操作在返回之前都要調用ldap_result2error(),從而
確保這些域被正確地設置。在連接結構中相關的域有:
   ld_matched 在LDAP_NO_SUCH_OBJECT錯誤返回事件中,這個參數包含DN匹配的程度;
   ld_error   這個參數包含了被LDAP 服務器返回的錯誤信息;
   ld_errno   LDAP 錯誤代碼,指示操作結果,它是下列常量內容之一:
           LDAP_SUCCESS
           LDAP_OPERATIONS_ERROR
           LDAP_PROTOCOL_ERROR
           LDAP_TIMELIMIT_EXCEEDED
           LDAP_SIZELIMIT_EXCEEDED
           LDAP_COMPARE_FALSE
           LDAP_COMPARE_TRUE
           LDAP_STRONG_AUTH_NOT_SUPPORTED
           LDAP_STRONG_AUTH_REQUIRED
           LDAP_NO_SUCH_ATTRIBUTE
           LDAP_UNDEFINED_TYPE
           LDAP_INAPPROPRIATE_MATCHING
           LDAP_CONSTRAINT_VIOLATION
           LDAP_TYPE_OR_VALUE_EXISTS
           LDAP_INVALID_SYNTAX
           LDAP_NO_SUCH_OBJECT
           LDAP_ALIAS_PROBLEM
           LDAP_INVALID_DN_SYNTAX
           LDAP_IS_LEAF
           LDAP_ALIAS_DEREF_PROBLEM
           LDAP_INAPPROPRIATE_AUTH
           LDAP_INVALID_CREDENTIALS
           LDAP_INSUFFICIENT_ACCESS
           LDAP_BUSY
           LDAP_UNAVAILABLE
           LDAP_UNWILLING_TO_PERFORM
           LDAP_LOOP_DETECT
           LDAP_NAMING_VIOLATION
           LDAP_OBJECT_CLASS_VIOLATION
           LDAP_NOT_ALLOWED_ON_NONLEAF
           LDAP_NOT_ALLOWED_ON_RDN
           LDAP_ALREADY_EXISTS
           LDAP_NO_OBJECT_CLASS_MODS
           LDAP_RESULTS_TOO_LARGE
           LDAP_OTHER
           LDAP_SERVER_DOWN
           LDAP_LOCAL_ERROR
           LDAP_ENCODING_ERROR
           LDAP_DECODING_ERROR
           LDAP_TIMEOUT
           LDAP_AUTH_UNKNOWN
           LDAP_FILTER_ERROR
           LDAP_USER_CANCELLED
           LDAP_PARAM_ERROR
           LDAP_NO_MEMORY

       ldap_err2string() 用來轉換數字的 LDAP 錯誤代碼爲常用的
描述錯誤的NULL-terminated 字符串,數字的 LDAP 錯誤代碼可能
來自ldap_result2error() ,或者某個同步的API操作調用。它返回一個指向靜態數據的指針。
       ldap_perror()用來輸出由msg提供的信息, followed
   by an indication of the error contained in the ld_errno field of the
   ld connection handle, to standard error.
八、  Calls for parsing(分析) search entries
     下面的 調用是用來分析由ldap_search()及其友函數返回的實體的。這些實體是不透明的,只有通過調用下面描述的函數才能訪問。
      1.  Stepping through a set of entries
          ldap_first_entry() 和 ldap_next_entry() 用來步查搜尋結果中的實體序列。 ldap_count_entries() 用來統計返回的實體個數。
   LDAPMesage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
   LDAPMesage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
       int ldap_count_entries( LDAP *ld, LDAPMessage *res );
參數說明:
   ld     連接手柄;
   res   LDAP 操作結果如ldap_result()或其它同步API操作調用
     的返回結果;
   entry  在ldap_first_entry() 或ldap_next_entry()之前的調用的返
          回實體。
     ldap_first_entry() 和 ldap_next_entry()如果沒有實體返回,就
  返回爲NULL 。而在出現錯誤時,也返回NULL ,這時就要設
  置連接手柄中的ld_errno 來指示這個錯誤。
ldap_count_entries() 返回包含在實體鏈中的實體個數,也用來
  統計調用ldap_first_entry() 或 ldap_next_entry()之後,鏈中剩餘的
  實體個數。
     2.  Stepping through the attributes of an entry
       ldap_first_attribute() 和 ldap_next_attribute() 用來步查實體
   返回的屬性類型表。
           char *ldap_first_attribute(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   void            **ptr
           );
           char *ldap_next_attribute(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   void            *ptr
           );

參數說明:
   ld     連接手柄;
   entry  被步查屬性的實體 ,如ldap_first_entry() 或ldap_next
         _entry()返回的;
   ptr    在 ldap_first_attribute()中,它是內部跟蹤實體當前位置的
          指針地址;在ldap_next_attribute()中,它是在ldap_first_
          attribute()之前的調用返回的指針。
   如果到達屬性表的底端時,或有錯誤時,ldap_first_attribute()和
 ldap_next_attribute() 都返回NULL,而在出現錯誤時就要設置連接
 手柄中的ld_errno 來指示這個錯誤。
3.  Retrieving the values of an attribute
     ldap_get_values() 和 ldap_get_values_len() 用來恢復給定的實體的屬性值。ldap_count_values() 和 ldap_count_values_len() 用來統計返回的值。ldap_value_free() 和 ldap_value_free_len() 用來釋放屬性值。
           typedef struct berval {
                   unsigned long   bv_len;
                   char            *bv_val;
           };
           char **ldap_get_values(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   char            *attr
           );
           struct berval **ldap_get_values_len(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   char            *attr
           );
           int ldap_count_values( char **vals );
           int ldap_count_values_len( struct berval **vals );
           int ldap_value_free( char **vals );
           int ldap_value_free_len( struct berval **vals );
參數說明:
   ld     連接手柄;
   entry  被恢復屬性值的實體 ,如ldap_first_entry() 或ldap_next
         _entry()返回的;
   attr   被恢復值的屬性 ,如ldap_first_attribute() 或 ldap_next
         _attribute()返回的; or a caller- supplied string (e.g., "mail");
   vals   在ldap_get_values() 或 ldap_get_values_len()之前的調用
         返回值。
  4.  Retrieving the name of an entry
      ldap_get_dn()用來恢復實體名。ldap_explode_dn()用來把名字
 分開,形成若干部分。ldap_dn2ufn()用來把名字轉換成 "user friendly"
 格式。
           char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
           char **ldap_explode_dn( char *dn, int notypes );
           char *ldap_dn2ufn( char *dn );
參數說明:
   ld     連接手柄;
   entry   被恢復名字的實體 ,如ldap_first_entry() 或ldap_next
         _entry()返回的;
   dn      要被分開的 dn ,如 ldap_get_dn()的返回;
   notypes  布爾參數,如果非零,則dn的各成分應該使它們的類
           型信息成條帶狀(如: "cn=Babs" 應變爲 "Babs")。
   五、舉例使用API 及部分樣本代碼

   #include <ldap.h>

   main()
   {
           LDAP            *ld;
           LDAPMessage     *res, *e;
           int             i;
           char            *a, *dn;
           void            *ptr;
           char            **vals;

           /* open a connection */
           if ( (ld = ldap_open( "dotted.host.name", LDAP_PORT ))
                   == NULL )
                   exit( 1 );

           /* authenticate as nobody */
           if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
                   ldap_perror( ld, "ldap_simple_bind_s" );
                   exit( 1 );
           }

           /* search for entries with cn of "Babs Jensen",
                   return all attrs  */
           if ( ldap_search_s( ld, "o=University of Michigan, c=US",
               LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res )
               != LDAP_SUCCESS ) {
                   ldap_perror( ld, "ldap_search_s" );
                   exit( 1 );
           }

           /* step through each entry returned */
           for ( e = ldap_first_entry( ld, res ); e != NULL;
               e = ldap_next_entry( ld, e ) ) {
                   /* print its name */
                   dn = ldap_get_dn( ld, e );
                   printf( "dn: %s0, dn );
                   free( dn );

                   /* print each attribute */
                   for ( a = ldap_first_attribute( ld, e, &ptr );
                           a != NULL;
                       a = ldap_next_attribute( ld, e, ptr ) ) {
                           printf( "attribute: %s0, a );

                           /* print each value */
                           vals = ldap_get_values( ld, e, a );
                           for ( i = 0; vals[i] != NULL; i++ ) {
                                   printf( "value: %s0, vals[i] );
                           }
                           ldap_value_free( vals );
                   }
           }
           /* free the search results */
           ldap_msgfree( res );

           /* close and free connection resources */
           ldap_unbind( ld );
   }


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章