LDAP技術報告(z)

←手機掃碼閱讀     火星人 @ 2014-03-05 , reply:0

LDAP技術報告(z)

LDAP技術報告
一,目錄和目錄服務
LDAP(Lightweight Directory Access Protocol)輕型目錄訪問協議是目錄訪問協議的一種.因此下面首先介紹什麼是目錄和目錄服務.
目錄是一個以一定規則排列的對象的屬性集合,是一個存儲著關於對象各種屬性的特殊資料庫,這些屬性可以供訪問和管理對象時使用,類似電話簿和圖書館卡片分類系統.這裡,我們所談的目錄服務是指網路目錄服務.目錄服務是指一個存儲著用於訪問,管理或配置網路資源信息的特殊資料庫(also called data repository),它把網路環境中的各種資源都作為目錄信息,在目錄樹結構中分層存儲,對這些信息可以存儲,訪問,管理並使用.網路中的這些資源包括用戶,各個應用系統,硬體設備,網路設備,數據,信息等.目錄服務是為有效的集成管理網路目錄中的信息提供服務,是支持網路系統的重要底層基礎技術之一.
目錄服務將分散式系統中的用戶,資源和組成分散式系統的其它對象統一的組織起來,提供一個單一的邏輯視圖,允許用戶和應用透明地訪問網路上的資源.一個由目錄服務支持的網路系統是一個集成的,網路化的,統一的系統,而不是各個獨立功能部分的簡單聚合.在目錄服務系統中對象可以根據名字或功能,屬性訪問,而不是根據機器地址,文件伺服器名字和mail地址等訪問.在目錄服務的基礎上開發的應用,易於使用,功能增強和易於管理,目錄信息的共享為應用的開發提供了方便.下一代分散式網路的信息模型和模式是一種基於目錄的,當我們進入網路時,是登錄到一個基於目錄的網路中,而不是登錄到某個機器上.
目錄服務可以存儲信息種類:
用戶帳戶信息(登入名,口令,許可權)
用戶個人信息(電話號碼,地址,僱員ID號)
外圍設備配置信息(印表機,調製借調器,傳真)
應用程序配置信息
安全信息
網路基礎設施配置信息(路由器,代理伺服器,INTERNET訪問設置)
人們可以想得到的,網路目錄中都可以存儲
這些信息集中在一個標準資料庫中,就可以有多種不同的使用方法.其中,最普通的是供系統管理員用於網路訪問控制和網路資源訪問控制.目錄將成為對許多網路活動進行集中控制的地方.
控制的例子:
用戶登入進入一個網路,系統進行認證和許可權判定;
用戶進入網路后,訪問網路中的資源,系統向目錄服務查詢該用戶是否具有使用該資源的許可權,並返回所請求資源的物理地址.
個人用戶可以使用目錄服務存儲個人設置信息,並可以對其所有環境進行集中存儲和控制.
隨著目錄服務技術的成熟,人們可以使用該技術通過一些網路設備監視和控制網路傳輸情況.
目錄服務的基本功能:
資源信息的目錄式表示,分佈存儲,資源定位和查找,用戶的統一認證,系統資源的統一授權,系統資源信息的共享,系統資源的單點統一管理,安全傳輸的保證,資源的統一監控等.
目錄服務的主要優點:
網路管理工作大大減輕,包括管理網路上的各個應用;
網路的集中管理點;
訪問用戶信息的集中控制點;
存儲在其它條件下很難處理的管理信息
系統資源信息的利用率高,管理的可擴展性好
簡單地說,目錄的發展經歷了書面目錄(電話目錄,醫士列表)——基於計算機的目錄(PIM,不易共享,必須訪問到響應的軟體和計算機)——網路目錄(公共的,共享的,統一的).
傳統的目錄是計算機或網路基礎結目錄的一個構件,它向其它應用程序提供服務,但沒有提供集成管理的機制,網路上的計算和服務需要一種公共的,分散式的目錄,能夠跨平台地對應用程序和用戶提供集中,統一的服務.目錄服務將使網路上的系統資源管理朝著單一的,全網路的目標發展,並能夠讓用戶,管理員以更容易的方式來管理網路環境.目錄服務作為一種工具來減少大型網路的管理負擔,提供了集中的單點管理和適應複雜環境所必須的靈活性,減輕了非目錄服務系統中存在的冗餘管理.
通過網路資源邏輯介面,目錄服務(ADS)減少了人們為了利用網路功能而必須對網路掌握的程度.也就是說,普通用戶只需要很少的網路知識,就可以通過複雜網路訪問和使用資源.用戶不需要再了解資源的物理分佈,訪問本地印表機的方法和訪問遠程網路資源的方法相同.目錄服務(ADS)提供了邏輯表示與資源的網路上的物理位置的連接,從用戶的角度看,這可能是轉移到基於目錄的網路操作系統具有的最大優點.)
目錄服務和資料庫的區別:
讀多於寫
一般不支持事務處理
信息訪問方式不同(一個是SQL,一個是LDAP的API)
目錄中的信息一般不要求嚴格的一致性
傳統的資料庫是平面的,無法表示資源之間及資源使用控制的複雜邏輯關係而遠遠不能滿足當前資源信息管理的各種要求.
目錄服務與DNS系統的相同之處和不同之處
相同之處:
分佈存儲
樹型層次結構
容錯
不同之處:
DNS的功能和目錄服務不同,DNS功能單一,本質上是將主機名解析成IP地址.目錄服務是可以為多個應用提供網路資源的信息存儲和管理,具有廣泛的應用特性;
DNS是以一系列文本文件為基礎,是一種純文本式的資料庫,無法進行擴展,適應其它功能的要求;
與分散式文件系統的相同在於採用了准樹型層次結構,具有一定的授權功能,區別在於:
目錄服務表示資源的各種屬性信息,可為各種應用提供服務,文件不能表示;
目錄服務有很強的邏輯表示和分類,文件的組織邏輯性單一,主要按存儲位置;
文件系統的認證功能較差
獨立性強
目錄服務的應用舉例
C4ISR系統:由多個大的子系統構成,管理問題更為複雜和嚴重
新的應用:電子商務(IBM),操作系統(WINDOWS2000)
網路的監控管理
會議系統和PIM
搜索功能
太多的應用——基於目錄的應用
原有應用的資源管理的重新開發
二, LDAP協議的特點
X.500協議是為了便於建立全局,分散式的目錄信息而設計的一套協議.它是一種C---S(Client—Server)結構的應用協議,支持用戶通過網路訪問和維護資源信息,另外還具有幾個突出的特點:
支持分散式的目錄信息維護,所以每一個運行X.500的伺服器都只需負責自己所管轄的資源信息,只需在本地就可完成信息的更新;
提供強大查詢能力,可以讓用戶隨心所欲的設計查詢方式;
全局的信息標示,通過這種標示可以唯一的定位信息位置,獲取內容;
結構化的信息模式,支持開發者的本地擴展;
遵循統一的標準,所以可以通過標準的方式訪問任何一個X.500伺服器,獲取信息;
X.500協議中包含了這諸多的強大功能,可以說在很大的程度上滿足了用戶和開發者的要求,但是在用戶和開發制的使用過程中卻逐漸暴露出其許多的不足之處,阻礙了它的應用和推廣,主要集中在使用方式和性能開銷上這兩個方面,由於X.500是在OSI協議棧上實現的,雖然X.500提供了強大的信息查詢功能,但是協議所要求的訪問格式卻十分複雜,往往難以掌握;其次在運行X.500伺服器時對系統的開銷要求較高.為了兼顧保留協議的優點和克服這些不盡人意的地方,推出了由X.500目錄服務協議延伸發展而來的輕型目錄訪問協議(Lightweight Drectory Access Protocol,簡稱LDAP).LDAP協議繼承了X.500的90%左右的功能,同時兼容所有使用X.500協議建立的服務端資料庫,避免了重複開發的浪費;在運行開銷上卻只是X.500的10%.正是由於LDAP具有巨大的優越性,它從一開始僅僅是作為X.500客戶層的另一種實現方式,到現在在許多應用中完全替代了X.500協議,成為一個完整實用的應用開發協議.
LDAP在以下四個方面對X.500進行了簡化:
傳輸 : LDAP直接運行在TCP上,避免了OSI多層通信的高層開銷;
功能: LDAP簡化了X.500的功能,拋棄了較少用到的功能和冗餘的操作;
數據表示:X.500的數據表示結構複雜,LDAP採用簡單的字元串對數據進行表示;
編碼: LDAP用於網路傳輸的編碼規則比 X.500的編碼規則更加簡單.
總到來說,基於LDAP的目錄服務有以下特點.
目的是存儲網路資源的信息
結構化的信息框架(面向對象的信息存儲方法),採用樹型層次式結構表示
在系統中的單點集中(不指物理位置)管理資源,可實現單一登入點
讀多於寫
基於TCP 協議
Client/Server邏輯結構
標準的訪問協議LDAP
強大的搜索功能,允許用戶組織複雜的查詢要求
維護的分散性(信息可分佈存儲,具有集中式資料庫無可比擬的優越性)
可全球唯一的命名
動態添加和修改信息
容錯功能
自動更新和維護存儲的信息
方便的備份和恢復功能
安全訪問和信息傳輸的安全
易對資源進行授權管理
三, LDAP協議的內容
LDAP定義了四種基本模型:
信息模型說明了LDAP目錄中可以存儲哪些信息;
命名模型說明了如何組織和引用LDAP目錄中的信息;
功能模型說明了LDAP目錄中的信息處理,特別是如何訪問和更新信息;
安全模型說明如何保護LDAP目錄中的信息不受非授權訪問和修改.
信息模型
LDAP的信息模型是以模式(Schema)為基礎的,以項目(Entry)為核心的.模式由若干項目組成,項目是描述客觀實體的基本單位,項目(如圖3)由描述客觀實體具體信息的一組屬性(Attribute)構成.屬性(如圖3)只能有一種類型(Type),可以有一個或多個值(Value).屬性的類型具體說明屬性值可以存儲哪些信息,以及這些信息的行為特性.例如,屬性cn的類型是caseIgnoreString,它意味著屬性值是按照詞典排序的字元串,並且在比較時忽略大小寫,如BEIJING和Beijing是相同的;屬性tele的類型是telephoneNumber,它具有caseIgnoreString的全部特性,另外在比較時忽略空格和破折號,如0731-4573670和07314573670是相同的.每個項目都有一個屬性objectClass,用於說明項目的類型,以及項目中的必選屬性和可選屬性.屬性objectClass的取值可以是一個或多個,其中必須有一個用於說明項目的基本結構的結構對象類(Structural object class),結構對象類不能輕易改變;除此之外,還可以有若干個對項目結構進行輔助說明的輔助對象類(Auxiliary object class),在訪問控制允許的範圍內可以新增或刪除輔助對象類.
命名模型
在LDAP目錄中,項目是按照樹形結構組織的,根據項目在樹形結構中的位置對項目進行命名,這樣的命名通常稱為標識(Distinguished name),簡稱DN.DN由若干元素構成,每個元素稱為相對標識(Relative distinguished name),簡稱RDN.RDN由項目的一個或多個屬性構成.
LDAP的命名模型(如圖4)與我們熟悉的文件系統有很多相似之處,RDN與文件系統中的文件名很相似,DN與文件的絕對路徑名很相似.另外,與文件系統一樣,兄弟項目(即,具有相同父項目的子項目)必然具有不同的RDN.LDAP的命名模型與文件系統之間的區別主要有:
在LDAP目錄中,位於葉節點和非葉節點的項目都擁有各自的屬性;在文件系統中,只有位於葉節點的文件擁有較豐富的內容,而位於非葉節點的目錄的內容相對簡單.
在LDAP目錄中,DN中各元素的排序是從葉到根;在文件系統中,文件絕對路徑名中各元素的排序是從根到葉.
在LDAP目錄中,DN中各元素之間的分隔符是",";在文件系統中,文件絕對路徑名中各元素之間的分隔符是"/"或"\".
在LDAP目錄中,允許超越樹形結構的別名項目(Alias entry),它指向其它項目.
功能模型
LDAP的功能模型涉及以下三個方面:
詢問(Interrogation)
LDAP在信息詢問方面主要定義了查找(Search)和比較(Compare)兩個操作.在查找操作中,根據選取標準在指定範圍內選擇項目,這個選取標準通常稱作查找過濾器(Search filter),並且可以規定一組需要返回的屬性.另外,還可以規定查找結果的大小和客戶端等待結果的時間.比較操作主要是判斷指定項目是否包含指定屬性(包括類型和值).
更新(Update)
LDAP在信息更新方面定義了新增(Add),刪除(Delete),修改(Modify)和修改RDN(Modify RDN)等四個操作.新增操作主要是在LDAP目錄中插入一個新的項目.刪除操作主要是從LDAP目錄中刪除已有項目.修改操作主要是修改已有項目的屬性,具體地說,可以增加,刪除,修改屬性或屬性值.修改RDN操作主要是修改項目的名字.
身份驗證(Authentication)
LDAP在身份驗證方面定義了連接(Bind),斷接(Unbind)和作廢(Abandon)等三個操作.連接操作主要是客戶端向伺服器提供身份信息,包括DN和口令,以便於伺服器驗證客戶端的身份,身份驗證成功即建立客戶端與伺服器之間的會話(session).斷接操作主要是結束客戶端與伺服器的會話.作廢操作主要是中止正在執行的操作.

安全模型
如何控制從網路上來的各種訪問請求,防止非授權的訪問發生 這對於一個系統而言,也是十分重要的,因為許多的用戶信息(如密碼,費用)以及許多系統的配置數據等都屬於敏感信息,它們不希望被隨便一個普通的使用者訪問,而只允許管理員擁有查詢和修改的許可權.LDAP的安全模型是以客戶端的身份信息為基礎的.客戶端的身份信息通過連接操作提供給伺服器,伺服器根據身份信息對客戶端提出的訪問請求進行控制.在LDAP中存在一個被稱為訪問控制列表(Access Control List,以下簡稱ACL)的文件,控制各類訪問請求具有的許可權.ACL文件中的控制方式具有極大的彈性:即可以在大範圍上控制某一類資源可以被某類甚至某個用戶訪問,還可以具體到資源類中的任何一個屬性.其授權的種類有讀,搜索,比較,寫這幾種,可以單獨,也可以組合使用.一般的格式是
access to "cn=*,ou=nudt,o=cs,c=cn"
by "cn=tom,ou=nudt,o=cs,c=cn" write
上面的控制設置就賦予了Tom對NUDT部門下的所有資源信息寫的權利,當然也就有了讀等這些權利了.詳細的定製和完善ACL文件,可以使目錄服務系統提供較好的安全性.此外,開發者還可以根據安全程度的需要,在LDAP中集成其它的安全工具,如KERBOUS, SSL等應用廣泛的安全技術,適用不同層次用戶的需要.
四, LDAP如何工作以及如何開發LDAP的應用
LDAP是以伺服器—客戶端方式工作的,目錄服務將資料庫軟體的邏輯結構分為前端(客戶端)和後端(服務端和倉庫)(圖1)

(圖1)
客戶端是直接面對一般開發者和用戶的;服務端是用於接收和解釋客戶請求,然後以客戶的身份完成請求,並將完成結果返回給用戶;倉庫則是真正存儲信息的地方.在LDAP中,服務端和倉庫之間的連接採用了ODBC機制,所以可以使用任何支持和具有ODBC驅動程序的資料庫軟體,簡單的可以是Linux系統中自帶的GDBM或Alpha中的NDBM等資料庫管理系統;也可以選用在功能和性能上更優越的Oracle和Sybase等系統,這樣,可以提高系統的可移植性.
現在已經有了許多基於LDAP協議開發出的資源管理系統和工具,如Openldap,NDS(Novell Directory Service)和ADS(Active Directory Service)等.它們已經逐漸的被使用在了各個需要目錄服務的領域,並且應用的趨勢在增強.
Openldap是Michigan大學發布的免費軟體,實現了LDAP v2的功能,並部分支持LDAP v3.它提供原代碼,可以在大多數的Unix和Linux系統中安裝.開發者能夠直接利用它所附帶的一些SHELL工具開發簡單的應用,這些SHELL包括了查詢(ldapsearch),修改(ldapmodify),刪除(ldapdelete),增加(ldapadd)等,關於他們的使用方法可以參照幫助文件;也可以調用它提供的程序介面(API)來開發應用,介面包括了查詢(ldap_search),修改(ldap_modify),增加(ldap_add),刪除(ldap_delete)等.從模版的定製到資源信息的組織和輸入都可以按照用戶的要求進行,開發出滿足你要求的應用軟體.
我們以openldap1.2.7為例,進一步說明LDAP的工作方式.也就是如何使用openldap1.2.7來建立一個基於LDAP應用開發.Openldap1.2.7的後台資料庫選用gdbm 1.8.0,Openldap實現了與gdbm的介面ldbm.SLAPD是Openldap實現的獨立的LDAP服務的守護進程,SLURPD是Openldap實現的獨立的LDAP更新和複製的守護進程.gdbm 是GNU發布的免費dbm,使用哈希排序的資料庫常式集,與標準的UNIX下的dbm常式一樣工作.gdbm有比Berkeley dbm更快的快速排序,並且它是可重入的.
進行開發前,先要安裝gdbm和openldap.
得到gdbm1.8.0.tar,tar xvf gdbm1.8.0.tar
cd ./gdbm
./configure
make
make install
然後安裝openldap:
tar xvf openldap.tar
cd ./ldap
./configure - - with-ldbm-api=gdbm,使ldap服務進程在後端使用gdbm資料庫
make depend
make
make install
接下來,進行基於LDAP協議的應用開發,大致分為四個步驟,這四個步驟同時也分別對應了建立協議中四種基本模型的過程:信息模型,命名模型,功能模型和安全模型.
首先是建立信息模型,既計劃需要管理的資源範圍,在LDAP中所建立的信息以"實體"(entry)為單位,資料庫的框架被稱為"模版"(schema),每個實體的屬性範圍都會在模版中說明.模版的內容可以根據你的需要隨意定製,可以將具有類似屬性範圍的信息歸為一類,對於一類實體的說明採用了基於面向對象的機制,將模版中的每一個信息框架稱為一個類"class",而可以用這個類定義出你需要的事例,也就是一個個信息實體.
例如在模版文件中寫入這樣內容:
objectclass person
{
requires
account,
userpassword
allows
sex,
……
}
其中requires所包含的屬性是每一個登記的用戶都必須填寫的屬性範圍,而allows所包含的則是可有可無的內容,這也給信息的存儲控制增添了許多靈活性;其中,象系統管理員這種資源可以與一般用戶合併,只是需要在屬性中加入"類型"這樣的屬性用以區分是用戶還是,為了安全,也可以將管理員單獨設置為一類資源,在他的屬性範圍中包括帳號名,密碼,管轄的範圍(機器等設備的標示),和聯繫方式等.對於其它的資源則根據實際情況分別設計,最後生成一個完整的模版文件.在openldap中,模版文件包括編輯yourname.oc.conf(定義信息對象類的文件)和yourname.at.conf(定義對象類中屬性的文件).
對照上面的信息模型所建立的信息庫還僅僅是一個個零散的資源記錄,為了表現出它們之間的邏輯聯繫,需要完成LDAP中的命名模型.在平面式資料庫中定位信息記錄是通過每一條記錄前面的標號或通過某些域的關鍵字匹配來完成的,實現過程大多是通過輪詢,這在提高處理性能上就造成了許多障礙.LDAP中採用了更加合理的樹形存儲方式,將資源信息記錄分別放置在樹的根到葉的位置上,這種方式總是從不同的方面表現出了信息記錄之間的某種從屬的邏輯關係.
對於每一個信息實體的定位使用全球唯一的命名方式既"可區分的名字"(DN:Distinguished Name),信息間的邏輯關係同時從DN中得到體現.可以參照Internet中的域名來理解DN的表示方法,如果你將所管理的信息按照地域進行分類,那麼DN中就回包含你的分類標準,如從國家,到地區,在具體到某個部門中的人或者機器等等,格式是"cn= ,ou= ,o= ,c= ".(其中的cn,ou,o,c都是一些標示關鍵字,分別表示用戶名字,部門,地區和國家)這樣當用戶需要尋找某人的一些信息(如電話號碼,Email地址等),如果知道他的工作地址,那麼可以查找這個單位中所有符合條件的人員信息,如果查找的條件較具體,那麼可以直接找到這個人的信息實體,即使是給的查找條件比較模糊,也可以找出單位中所有符合條件的人員信息,然後由用戶從中挑選出需要的,信息的邏輯結構見(圖2)
cn 中國

o 長沙 上海 北京

ou 國防科大 市政府

cn 張三 李四
當然,分類方式完全可以按照你的需要進行選擇,將所有的信息組織在資料庫中.建立了信息模版之後,就可以開始生成資料庫本身了.添加資料庫信息可以是先寫一個LDIF(Ldap Data Information Format)格式的文檔,(每個ldif文件對應一個資料庫,在LDAP中可以有多個資料庫,)這種格式是與模版是對應的,將一個個信息實體羅列在文件中,然後使用SHELL工具"ldif2ldbm"將其轉換為當前使用的資料庫軟體的格式,並且在啟動服務端時告訴這些資料庫文件的存儲路徑;
如何真正的訪問LDAP信息庫中的記錄則是在其功能模型中定義的內容,在應用開發中即開發一個LDAP的客戶端和該客戶端如何訪問LDAP伺服器.Openldap提供的僅僅是一系列的shell命令和API,我們要依靠這些底層調用來建立一個完整的用戶訪問和顯示環境.如果不進行這方面的開發,可以使用普通的瀏覽器或者直接通過shell命令來操作,不過這種操作方式需要對LDAP的環境,配置情況,存儲內容都有相當詳細的了解,還要記住LDAP中複雜而又繁瑣命令格式.普通用戶根本不可能掌握.
一個完整的訪問過程包括四個步驟:初始化,綁定伺服器,訪問資源信息和斷開連接.其中初始化是分配一個操作句柄;綁定伺服器是向服務端提供自己的身份標示(含用戶名和密碼等);訪問資源信息則是提出自己的訪問請求(如查詢和更新,他們分別有對應的標準API),等待並獲取訪問結果;斷開連接是在所有的訪問工作完成之後斷開與服務端的連接,釋放佔用的資源.LDAP是簡化了X.500中的許多操作,它在訪問資源的方式中主要提供與"讀"和"寫"相關的操作手段.與"讀"相關的有查找(search)和比較(compare),在查找時可以通過設置不同的"過濾器"(filter)達到獲得自己需要的結果,過濾器中的內容可以涉及到任何相關屬性的名稱及取值範圍等,並且支持與,或,非等關係表達式;"比較"則是將特定記錄中某屬性的值取出與自己的設定進行關係比較.與"寫"相關的操作有增加,刪除,修改和更名.增加是在信息庫中增加新的信息記錄,當然不能有相同唯一標示的記錄存在;刪除是將被認定為無用的信息記錄從庫中刪除;修改是對於庫中資源信息的某些屬性值進行修改;更名則是更替唯一標示中最後一部分的內容,往往使用在僅僅這個資源的名稱有了改變的情況下.
如何防止資源信息的非授權訪問和處理數據備份以及恢復是在安全模型中解決的問題.我們在下一章進行詳細說明.
在處理好以上四個方面后 ,我們就可以啟動LDAP服務了,在openldap中,啟動伺服器端的SLAPD(LDAP伺服器進程),就可以響應用戶的訪問了.
LDAP中的訪問控制
LDAP通過安全控制列表ACL(Access Control List)可以對信息庫中的所有資源進行訪問控制,甚至可以具體到一個資源記錄中的某個屬性.在openldap中,是在slapd.conf中定義的.Slapd.conf是LDAP最主要的配置文件,它說明了LDAP中使用的模板文件,日誌文件,資料庫位置,系統管理員帳號,系統管理員口令和各種安全機制等,其中主要是定義用戶訪問許可權和建立LDAP的主從和主備關係.
對於用戶訪問許可權,舉例說明,我們可以將用戶信件信息只授權給收件人,那麼當該用戶在綁定伺服器並提供正確的帳號名和密碼之後可以訪問所有寄給他的信件,而其他用戶試圖超越自身的許可權,獲取其他用戶的信件信息時會被立即拒絕.可以這樣來描述許可權的設置:
access to dn=".*, User=Tom, o=XY, c=A" by dn="User=Tom, o=XY, c=A".
通過這條限制就將信件的訪問許可權完全的賦給了信件的收取者.同樣,設備的訪問許可權是授予了相應的設備管理員,而用戶這類資源則只能由系統管理員來控制.
對於用戶密碼這個屬性,可以這樣定義.
access to dn=".*,grp=general,ou=nudt,o=cs,c=cn" attr=userpassword
by self write
by * none
在slapd.conf中還可以定義referral配置,它的值應是另一個LDAP伺服器或多個LDAP伺服器的 URL,當用戶進行查詢時,沒在本地找到,就會去referral指定的其它LDAP伺服器進行查找.openldap直接在伺服器上實現了referral,而是返回給客戶referral地址,如圖1.①向server發出請求;需要指向其它server時,②返回referral地址;③客戶需重新向referral地址發出請求;④返回結果.為了網格用戶的方便,需要屏蔽掉信息所在地址即referral,實現Chaining,即在伺服器上自動支持referral,如圖2.①向server發出請求;需要指向其它server時,②自動指向referral地址;③自動向referral地址發出請求;④返回結果.
圖1
圖2
有了referral的功能,我們就可以把網路內的LDAP伺服器都建立這樣一種聯繫,使得用戶不必記住每個LDAP伺服器都存儲些什麼內容以及它們的地址,只要記住離自己最近的LDAP伺服器就可以了,如果用戶要操作的內容不在該伺服器上,會自動地尋找直到找到正確的伺服器,得到正確的內容為止.
六,LDAP的主從備份功能
安全機制中一個重要的內容就是備份和恢復,在LDAP中提供了主從備份伺服器的機制,它方便和經濟地實現了備份和恢復的功能.下面介紹主從伺服器的配置方法和運行過程.
主伺服器為了表明當前所運行服務進程的身份,必須在其配置文件(slapd.conf)中註明,並且還標明所有從(備份)服務進程的地址(IP或域名);從(備份)服務進程中需要標明它所面對的主服務進程的地址(IP或域名).
主服務進程配置文件:
# Just show the necessary portion for replicate, '389' is the port number
replica host=172.26.20.98:389
binddn="adm=replica99,ou=nudt,o=cs,c=cn"
bindmethod=simple credentials=passwd
# The second slave server
replica host=172.26.20.97:389
.
.
.
(注):
binddn是主server向該從server發出操作命令時使用的身份.
Bindmethod是標明使用的身份驗證的方法,可以是"用戶名+密碼"也可以是kerberos方法.
Credentials分別為密碼和認證書
從server配置文件:
# Just show the necessary portion for replicate,98 is the IP of the master server
referral ldap://172.26.20.98
updatedn "adm=replica99,ou=nudt,o=cs,c=cn"
# Give updatedn the right to write the Directory Tree
access to ".*,o=cs,c=cn"
by "cn=replica99,ou=nudt,o=cs,c=cn" write
(注):
referral:是當在本地無法提供信息數據時,提供下一個伺服器的地址,可以通過再一次查詢獲取數據.
在備份服務進程的配置文件中,不必使用referral,因為它不真正的提供索引服務.
啟動順序
將主服務進程上的資料庫文件拷貝給各個從(備份)服務進程,達到最初的一致.
啟動主服務進程上的slapd進程
啟動從服務進程上的slapd進程
啟動主服務進程上的slurpd進程
slurpd是可以定時把主伺服器上的修改進行備份,依據是由寫操作產生的日誌,如果由於網路的原因導致了備份失敗,slurpd會自動進行重試,直到備份成功.
日誌
設置在主服務進程r伺服器上,需要修改配置文件:
# For log of the LDAP server ,you can set the file name you like
replogfile /home/ldap/nhpce.replog
實際此文件只是給slurpd進程使用,作為一個廣播操作命令的中轉站,真正的日誌文件在/var/tmp下,文件名稱為slurpd.replog.
一個主伺服器的從伺服器個數是沒有限制的,通過以上設置,可以產生了一個由主伺服器進程和一個或幾個從服務進程組成的服務機群,主守護進程作為整個服務機群的核心,其始終維持系統信息的一致性,因為除了查詢以外的請求都首先由它操作自己的信息庫,然後再將該操作廣播給各個從伺服器,同步更新各自的信息庫.而對於查詢請求,由於不會造成信息內容的改變,所以可以由各個從伺服器完成,這樣的方式特別適用於象目錄服務這樣查詢請求遠遠多於修改等請求的應用.
下面是一個主伺服器和多個從伺服器組成的服務機群處理訪問的步驟:
客戶向服務機群發出請求(客戶使用的可能是IP或域名),此請求可以被一個前端的域名伺服器轉給一個從服務進程.
從服務進程將除了搜索以外的請求發向主服務進程.
主服務進程根據請求成功完成相應操作之後,將操作廣播給所有的從服務進程.
從服務進程r此時完成主服務進程要求的操作.
從服務進程將操作結果返回給客戶.
從服務進程
域名伺服器

客戶 主服務進程
3.
1.
5. 2.

4.
圖3
這樣的伺服器機群,每個從伺服器都有一個主伺服器信息的完全備份,當出現主伺服器因為各種原因無法提供服務或無法恢復其信息數據時,則可將備份伺服器上的數據信息轉移到主伺服器上,繼續提供服務;或者直接將備份伺服器的配置文件進行修改,從新啟動服務進程,將其身份變為主服務進程.而且這些處理都十分方便.如果在平時就做好準備,那麼可以在極短的時間內恢復服務.
實際上,不但一個主伺服器可以對應多個從伺服器,而且一個從伺服器可以從多個主伺服器上備份信息,形成一個主備的服務機群.
採用主備關係服務機群的系統邏輯視圖如下:

圖4
在上圖中,設置了兩個主服務信息庫,它們平時可以是各不相干的角色,管理各自的域內事務,而後面的兩個備份信息庫則為了提高使用效率,同時作為了兩個主服務信息庫的備份庫.對於上面兩種方式的實現,其配置文件的寫法大體相同.
不僅如此,多個LDAP伺服器之間可以互為主從關係,即每個伺服器都把自己管理部分定義為主服務信息庫,而其他所有的LDAP伺服器把與之相應的信息庫定義為該主信息庫的從信息庫.這樣,實際上每個LDAP伺服器的地位是平等的,存儲的信息則包括了全局的信息.每個單位只有對本單位的LDAP伺服器上本單位的信息具有寫和修改的許可權.而修改的同時各個單位的LDAP伺服器上的相應的信息就都修改了,每個單位的用戶都可以在本地的LDAP上訪問全局的信息,而且基本上能保證是最新的信息,這種方式有響應時間短,資源利用率高,抗毀能力強的優點.充分地發揮了分散式系統特點.缺點是每一次寫操作都要廣播到每個LDAP伺服器,增加了網路的負擔.但因為目錄服務的特點是讀操作遠遠大於寫操作,實際上對網路負載影響不大.具體邏輯關係見下圖.
圖5
在配置上需要在每個LDAP伺服器上建立相應的slapd.conf文件,在配置文件中聲明自那部分是主伺服器並定義每個從伺服器的位置和許可權.自己作為從伺服器從那些LDAP伺服器中以什麼身份取得那些信息.下面舉例說明.在國家高性能計算環境中基於LDAP的目錄服務採用了這種組織形式,它的LDAP的配置文件如下,本地伺服器是國防科大.
下面是slapd.conf簡化了的寫法.
#NHPCE Slapd Configure File
include /etc/openldap/slapd.oc.conf
include /etc/openldap/slapd.at.conf
schemacheck on
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
access to attr=userpassword
by self read
by dn="cn=Manager_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN" read
by * none
#ldbm definition for the NUDT master database
database ldbm
suffix "ou=NUDT,o=CS,c=CN"
directory /etc/openldap/database/nudt_db
rootdn "cn=Manager_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN"
replogfile /etc/openldap/database/nudt_db/slapd.replog
replica host=159.226.39.173:389
binddn="cn=Replicator_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN"
bindmethod=simple
credentials=secret
replica host=159.226.39.144:389
binddn="cn=Replicator_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN"
bindmethod=simple
credentials=secret
index default none
defaultaccess read
access to dn=".*,grp=general,ou=nudt,o=cs,c=cn" attr=userpassword
by self write
by * none
access to dn=".*,grp=general,ou=nudt,o=cs,c=cn" attrs=email,telephone,description
by self write
by * read
access to dn="cn=Manager_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN"
by * none
access to dn="cn=Replicator_nudt,grp=GENERAL,ou=NUDT,o=CS,c=CN"
by self write
by * none
lastmod on
#ldbm definition for the NUDT slave database
database ldbm
suffix "ou=CAS,o=BJ,c=CN"
directory /etc/openldap/database/cas_db
rootdn "cn=Replicator_cas,grp=GENERAL,ou=CAS,o=BJ,c=CN"
updatedn "cn=Replicator_cas,grp=GENERAL,ou=CAS,o=BJ,c=CN"
index default none
defaultaccess read

#ldbm definition for the JNICT slave database
database ldbm
suffix "ou=JNICT,o=WX,c=CN"
directory /etc/openldap/database/jnict_db
rootdn "cn=Replicator_jnict,grp=GENERAL,ou=JNICT,o=WX,c=CN"
updatedn "cn=Replicator_jnict,grp=GENERAL,ou=JNICT,o=WX,c=CN"
index default none
defaultaccess read
七, LDAP的應用前景
目錄服務系統將在越來越多的網路應用系統中使用,特別是一些大型的網路應用(一些大型網站也會需要)當中,這也是各個大公司為什麼要將此作為網路基礎軟體來看待.
集中單點管理,分佈容錯和單一登入點(包括合理的認證服務)的功能是具有巨大的誘人優勢.
使用LDAP可以開發大的應用軟體項目,比如可以應用在C4ISR中,當然會還有其它應用.
小的項目也會需要目錄服務的的支持,目錄服務是一個在邏輯上集中存儲資源信息的特殊資料庫,許多資料庫開發都可以用LDAP替代,而且LDAP更易於開發,更靈活.
目錄服務系統將從現行的V2,V3繼續發展,具有目錄服務功能的網路DEN(發布,發現和獲取)即將出現,不經對網路上的高層資源進行集中管理,而且對網路基礎設備的集中管理,例如:具有目錄路由器.一句話:就是DEN將網路服務和網路設備的管理更好地繼承到普通管理技術中.
附錄 LDAP API
提供有關Internet 通信的信息,它沒有詳細說明Internet的任何一種標準,但其作用卻是無限的.

介紹
這篇文檔定義了 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
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 != NULL; i++ ) {
printf( "value: %s0, vals );
}
ldap_value_free( vals );
}
}
/* free the search results */
ldap_msgfree( res );
/* close and free connection resources */
ldap_unbind( ld );
}
(有關LDAP API 的更詳細的信息請參閱 英文文檔 RFC 1823)
服務端
倉 庫
主庫B
B備份庫
A備份庫
B備份庫
主庫A
A備份庫
客戶端
entry
entry
entry
entry
Alias entry
Value
Value
……
Value
Type
……
Attribute
Attribute
A信息備份庫
B信息備份庫
C信息主庫
C信息備份庫
B信息備份庫
A信息主庫
4
3
2
1
LDAP
Client
LDAP
Server 2
LDAP
Server 1
3
2
1
LDAP
Client
LDAP
Server 2
LDAP
Server 1
C信息備份庫
A信息備份庫
B信息主庫
《解決方案》

回復 1樓 qzqfirst 的帖子

請問圖呢?




[火星人 ] LDAP技術報告(z)已經有510次圍觀

http://www.coctec.com/docs/service/show-post-38419.html