王朝网络
分享
 
 
 

LDAP API

王朝other·作者佚名  2006-07-13
宽屏版  字体: |||超大  

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

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有