分享

LDAP API

 bluecrystal 2007-04-30

LDAP  API
 
介绍
这篇文档定义了 LDAP API (C语言版)。它使用方便,功能强大,大致内容有以下几个方面:
简单浏览LDAP模型
应用程序怎样使用API去获取LDAP信息
详细介绍API 调用函数
举例使用API 及部分样本代码
      下面我们分别介绍。
简单浏览LDAP模型
       LDAP 是以client-server 模型为基础的,在此模型中,客户机可以建立与LDAP服务器的连接,从而发送请求,接收应答。
       LDAP的信息模型是基于实体(entry)的,每个实体都代表着某种对象类型的特例。比如组织机构、用户、网络、计算机等。每一种实体又包含有许多属性,每种属性又由它的实体所代表的对象的类型决定。
      实体用树型结构组织再一起,通常根据政治上的,地理学的,和组织的关系进行分类。每一个实体都有唯一的名字通过它的RDN与它的同属实体相连,至于RDN及DN的命名和使用在《毕业设计报告(一)》中已经介绍过了,这里不在详述。
三、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 );

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多