http://www.lisdn.com/html/03/n-11703.html
一、 LDAP模型概览:
1、 LDAP的数据存储在众多的Entry(条目)里;
2、 LDAP中所有的Entry以树型结构组织在一起;
3、 Entry由唯一的DN(Distinguished Name)标识和定位,DN就是树上到该Entry的路
径标识;
4、 Entry的数据以属性形式组织,每个属性可以拥有一个或多个值;
5、 属性有各自的类型,一个Entry所能拥有的属性是由这个Entry的ObjectClass属性
规定的;
6、 每个Entry的Objectclass属性中必须包含top这个值,因为在top这个ObjectClass
中定义了属性ObjectClass,Entry只有设置了该属性值才能拥有ObjectClass的属
性(这是个递归定义,有点向pascal和c里的向前声明);
7、 Entry能容纳的属性个数、属性值的类型、属性的名称(标识)都由该Entry的
ObjectCalss规定(注意一个Entry的ObjectClass象它的其它属性一样是可以有多
个值的)。以下是两个Entry的定义:
以下两个Entry是同时由top,uidobject,person三个ObjectClass规范的Entry,注意
它们的三个ObjectClass属性;由于这三个ObjectClass属性的规范,在增加、修改
这两个Entry时必须要提供ObjectClass、uid、cn、sn的属性值。(关于Object参
见下面的描述)
dn: uid=10207, ou=People, o=VinSide, c=CN
objectclass: top
objectclass: uidobject
objectclass: person
uid: 10001
cn: gang
sn: liu
dn: uid=10209, ou=People, o=VinSide, c=CN
objectclass: top
objectclass: uidobject
objectclass: person
uid: 10002
cn: yuqing
sn: tang
8、 以下是ObjectClass(top,uidobject,person)的定义:
其中在requires下的属性是设成该ObjectClass的Entry必须要设置的属性;
其中在allow下的属性是设成该ObjectClass的Entry可以设置的属性,但不是必
须的。
objectclass top
requires
objectClass
objectclass uidobject
requires
objectClass,
uid
objectclass person
requires
objectClass,
sn,
cn
allows
description,
seeAlso,
telephoneNumber,
userPassword
9、 Entry的DN描述这个Entry处于LDAP树型数据组织中的位置,如DN: uid=10207,
ou=People, o=VinSide, c=CN的Entry就描述该Entry是DN: ou=People, o=VinSide,
c=CN的Entry的子结点,故在添加DN: uid=10207, ou=People, o=VinSide, c=CN的
Entry前DN: ou=People, o=VinSide, c=CN的Entry必须已经加入LDAP中;在删除
结点时也存在同样的问题。
二、 使用LDAP API的步骤:
1、 用ldap_open() API打开与LDAP服务器的连接,该API返回一个struct LDAP的
指针,该指针将用于整个LDAP的操作过程直到结束;
2、 用ldap_bind()族(如ldap_simple_bind、ldap_kerberos_bind等)API取得LDAP服
务器的认证,只有获得认证(包括匿名认证)后才能对LDAP服务器提出请求;
3、 执行具体的LDAP操作(如ldap_search()、ldap_add()、ldap_modify()、ldap_delet
()、
ldap_first_entry()等);
4、 关闭连接ldap_unbind();(这样整个操作过程就结束了)
三、 使用OpenLDAP API所需的头文件和连接库:
1、 头文件(缺省安装在/usr/local/include):
#include
#include
2、 连接库(缺省安装在/usr/local/lib):
libldap.a
liblber.a
3、 某些API需要额外的头文件,如
ldap_simple_bind_s )。
四、 LDAP API详述:
说明:以下API中带"_s"后缀的API是同步API,即调用后会以阻塞方式运行;没有"
s"
后缀的是异步API,调用后会立刻返回,然后在适当的时候用ldap_result()取回结
?
1、 ldap_open() 打开到LDAP服务器的连接:
typedef struct ldap {
/* ... opaque parameters ... */
int ld_deref;
int ld_timelimit;
int ld_sizelimit;
int ld_errno;
char *ld_matched;
char *ld_error;
/* ... opaque parameters ... */
} LDAP;
LDAP *ldap_open( char *hostname, int portno );
> hostname是LDAP服务器的地址,可以是IP或域名;
> portno是LDAP服务器的端口号,缺省的端口是常数:LDAP_PORT;
> 返回值:成功返回一个struct LDAP指针是一个连接句柄用于以后的操作,
失败返回NULL。
2、 ldap_bind()族API获得访问目录的认证:
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是要连接的Entry的DN。
说明:该Entry会作为LDAP判断用ld句柄是否有权进行操作的依据(可
以用帐号去理解,一般系统在配置时会设置一个rootdn可看作超级用户帐
号)
> passwd是对应dn的帐号密码。
> method是验证方法:LDAP_AUTH_SIMPLE,LDAP_AUTH_KRBV41,或
LDAP_AUTH_KRBV42
> 一般用简单的绑定就可以了:ldap_simple_bind_s、ldap_simple_bind
3、 ldap_unbind()关闭连接:
int ldap_unbind( LDAP *ld );
> ld是连接句柄
4、 ldap_search()族API查询LDAP目录:
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
);
需要了解的结构:
struct timeval {
long tv_sec;
long tv_usec;
};
> ld连接句柄
> base搜索起始处那个Entry的DN
> scope搜索范围:
1. LDAP_SCOPE_BASE:只搜索该base Entry
2. LDAP_SCOPE_ONELEVEL:搜索该base Entry的所有子Entry,但
只限于子Entry的那一层
3. LDAP_SCOPE_SUBTREE:搜索该base Entry的整个子树(包括base
Entry)
> filter是搜索过滤串,具体的描述在RFC1558,以下是简单的BNF描述:
说明:filtertype中的~=是专门用于近似匹配的
> attrs是指出搜索将要返回哪些属性,它是以NULL标志结束的字符指针数
组,如:attrs={"uid","sn","cn",NULL}。如果把attrs设成NULL表示传回所
有的属性。
> attrsonly是一个布尔值,0表示回传属性类型值和属性值,非0只传回属性
类型。
> timeout是专门用于ldap_search_st(),指出操作的超时时间。
> res是同步API使用的,用于得到搜索结果。
额外说明:(在ld这个连接句柄中有三个域影响搜索的进行)
> ld_sizelimit:搜索结果中最大的Entry数
> ld_timelimit:搜索消耗的时间限制(单位秒)
> ld_deref:与别名有关的处理,具体看manual!
5、 目录查找结果分析API:
i. 遍历结果目录项集(Entries Set)(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_search()族函数或ldap_result()返回的。
> entry是ldap_next_entry API中使用的,它是上次调用ldap_first_entry、
ldap_next_entry的返回值,用于遍历正个Entry结果集。
> 如果没有更多的Entry在结果集中,这两个API返回NULL。
> 遍历开始先调用一次ldap_first_entry取得首个entry,然后调用ldap_next_ent
y
遍历剩下的entry。