一、簡介;
????????a)??X500目錄服務;
????????OSL X.500目錄是基于OSI網絡協議的目錄服務協議,也是LDAP的前身。但是X。500的缺點是不支持TCP/IP,而是支持OSI協議,顯然,在 Windows等個人電腦上不可以使用OSI協議,在此前提下,也就產生了訪問X500目錄的網關--LDAP。
????????b)??LDAP;
????????LDAP(Lightweight Directory Access Protocal, 輕型目錄訪問協議),是針對以X500目錄為主的目錄服務的前端訪問協議,是OSL X.500目錄訪問網關。由于X500原來不是為TCP/IP網絡設計的,而目錄服務的最大使用者偏偏是TCP/IP客戶,因此,LDAP就被設計成使用 TCP/IP訪問OSI 目錄服務的服務協議,而隨著互聯網成為網絡的主流,LDAP也成為一個具備目錄的大部分服務的協議。
????????LDAP主要解決目錄服務的前端訪問形式,而不是對目錄服務本身制定的的協議,理論上,LDAP支持后臺的任何存儲形式,包括X500,關系數據庫,文本數據庫或文件目錄等。LDAP繼承了X500目錄的大部分定義,無論是訪問樣式還是語法都與X500相似。
????????c)?? Active Directory 活動目錄;
????????Active Directory (AD)是微軟為.net中的對象訪問定義的目錄服務,包括目錄服務本身,以及客戶端API(ADSI)。Ad并不是LDAP在.net中的實現,而是 X500在.net中的實現,但AD前端支持并主要以LDAP形式進行訪問。完整地說,AD是基于微軟自身定義的X500擴展的一系列Schema實現的 X500目錄服務及相關的訪問控制工具的集合,其前端支持LDAP的查詢,目的是對.net中涉及的所有網絡對象提供目錄服務。各個schema在一個樹森林中是唯一的。
????????普通的LDAP客戶端工具與AD并不兼容。WINDOWS2000自帶有一些LDAP客戶端工具,包括ldifde.exe, ldp.exe。并提供專門的LDAP程序接口ASDI。同時,可以在WINDOWS管理臺上添加AD管理snap-in,配合已有的AD基本管理工作。使用以上工具可以得到微軟樣式的詳情,但總的來說,WINDOWS2000原則上不鼓勵用戶在AD的基礎上進一步的開發,沒有開發更多的資料。
????????WINDOWS2000中,訪問AD記錄的API被集成到了內核,服務于WINDOWS2000從主機權限和對象管理,直接網絡的權限和對象管理,同時API細節沒有對外公開。因此,某種程度上,AD是一個只對WINDOWS2000有用的目錄服務,AD連同訪問API,形成一個基于 X500-LDAP的孤島,從一開始就沒有打算與其他廠商產品有兼容的余地,這也是微軟的一貫風格。參考:
????
http://www.microsoft.com/windows2000/en/server/help/default.asp? url=/windows2000/en/server/help/sag_ADschema_Intro.htm????
http://msdn.microsoft.com/library/default.asp? url=/library/en-us/netdir/ad/schema_implementation.asp ????????AD在WINDOWS2000中注冊表中的位置是:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\
????????使用AD時,用戶可以自行在微軟樣式的基礎上添加新的類和屬性,微軟稱這個就是schema的增添,這與UNIX環境下有一些不同,用戶余地較少。如果真的需要添加,可以使用按:
http://www.microsoft.com/ windows2000/techinfo/planning/activedirectory/adschemasteps.asp的指示一步步做,也可以預先做好ldif文件,使用ldifde.exe一次性地進行添加,效果是一樣的。 ????????在默認的狀況下,WINDOWS2000的AD初始具備三個上下文對象:
????????dc=domainname; 微軟定義domainname必須是examples.com格式,即dc=example,dc=com;
????????cn=Configuration,dc=example,dc=com; 這一條目和上下文存儲設置信息;
cn=schema,cn=configuration,dc=example,dc=com;
????
二、服務器實現方式;????用戶可以選擇購買商業的LDAP服務器,如SUN的iplanet directory server;但在大部分情況下,使用openldap足以完成所需要的目錄服務工作。另外,包括windows 2000以及如domino6這樣的系統軟件中,通常也都集成了一個自身使用的LDAP服務器。
????
三、數據結構原理;????????不少LDAP開發人員喜歡把LDAP與關系數據庫相比,認為是另一種的存貯方式,然后在讀性能上進行比較。實際上,這種對比的基礎是錯誤的。LDAP和關系數據庫是兩種不同層次的概念,后者是存貯方式(同一層次如網格數據庫,對象數據庫),前者是存貯模式和訪問協議。LDAP是一個比關系數據庫抽象層次更高的存貯概念,與關系數據庫的查詢語言SQL屬同一級別。 LDAP是實現了指定的數據結構的存貯,它包括以下可以用關系數據庫實現的結構要求:樹狀組織、條目認證、類型定義、許可樹形記錄拷貝。
????????a)?? 樹狀組織;
????????無論是X500還是LDAP都是采用樹狀方式進行記錄。每一個樹目錄都有一個樹根的入口條目,子記錄全部是這一根條目的子孫。這是目錄與關系數據類型最大的區別(關系數據庫的應用結構也可實現樹狀記錄)。因此,把目錄看作是更高級的樹狀數據庫也未嘗不可,只不過除此外,它不能實現關系存貯的重要功能。
????????b)?? 條目和條目認證;
????????LDAP是以條目作為認證的根據。ROOT的權限認證與目錄本身無關,但除此外所有條目的認證權限由條目本身的密碼進行認證。LDAP可以配置成各種各樣不同的父子條目權限繼承方式。
????????每一個條目相當于一個單一的平面文本記錄,由條目自身或指定的條目認證進行訪問控制。因此,LDAP定義的存貯結構等同于一批樹狀組織的平面數據庫,并提供相應的訪問控制。
????????條目中的記錄以名-值對的形式存在,每一個名值對必須由數據樣式schema預定義。因此,LDAP可以看作是以規定的值類型以名值對形式存貯在一系列以樹狀組織的平面數據庫的記錄的集合。
????????c)?? 數據樣式(schema);
????????數據樣式schema是針對不同的應用,由用戶指定(設計)類和屬性類型預定義,條目中的類(objectclass)和屬性必須在在 LDAP服務器啟動時載入內存的schema已有定義。因此,AD活動目錄中的條目記錄就必須符合Active Directory的schema中。如果已提供的schema中的定義不夠用,用戶可以自行定義新的schema.
????????在
這里 中可以看到常用的schema。
????????d)?? 類型分類(objectClass);
????????條目中的記錄通過objectclass實現分類,objectClass是一個繼承性的類定義,每一個類定義指定必須具備的屬性。如某一條目指定必須符合unit類型,則它必須具備chinacfirm類形指定的屬性,象法人代表什么的。
通過objectclass分類,分散的條目中的記錄就實際上建立了一個索引結構,為高速的讀查詢打下了基礎。Objectclass也是過濾器的主要查詢對象。
????????e)?? 過濾器和語法;
????????LDAP是一個查詢為主的記錄結構,無論是何種查詢方式,最終都由過濾器缺點查詢的條件。過濾器相當于SQL中的WHERE子句。任何LDAP的類過濾和字符串都必須放在括號內,如(objectclass=*),指列出所有類型的記錄(不過分類)。
????????可以使用=,>=,<=,~=(約等于)進行比較,如(number<=100)。合并條件是最怪的,必須把操作符放在兩個操作對象的前面而不是中間,單一操作對象用括號括起來。如
????????A與B,不是A&B,而是(&(A)(B))。
????????或使用"|"表示;
????????非使用"!"表示。
????????對于"與",或"或"在操作符后可以跟多個條件表達式,但非后則只參是單個表達式。
????????詳見RFC1558。
????????f)?? 樹移植;
????????LDAP最重要的特性和要求并不是讀性能,而是擴展性。這一特性是通過樹移植和樹復制實現的。按LDAP的RFC要求,LDAP目錄應該可以任意地在不同的目錄間連接、合并并實現自動復制,及自動性同步。這意味著用戶可以在任一LDAP中訪問條目,而不用管其中某一部分是否復制自全世界另一目錄中的記錄,同時另一目錄中的記錄同樣在正常運作。
????????這一特性如果在關系數據庫中實現,意味著要使用程序化的非規范化預復制。類似于匯總帳目的設計。
????????g)?? LDIF交換文件
????????LDIF是LDAP約定的記錄交換格式,以平面文本的形式存在,是大部分LDAP內容交換的基礎,如拷貝、添加、修改等操作,都是基于LDIF文件進行操作。
????????f)?? JAVA或CORBA對象串行化存儲
????????網絡高效率的訪問加上JAVA的跨平臺能力,當把JAVA或CORBA對象串行化后存儲到LDAP目錄上時,可以產生非同一般的集成效果--實際上,這正是EJB和.NET的網絡定位基礎技術。
????????使用JAVA或CORBA對象存儲時,必須首先讓LDAP服務支持該對象定義,也就是說包含qmail.schema或corba.schema。
????????JAVA必須存儲在objectclass=javacontainer的條目中,而且必須帶有cn屬性,這意味著除非該JAVA類專門實現了DirContext接口,對于大多數JAVA類來說,只能采用DirContext代替Context實現bind的添加操作。取出JAVA類相對要簡單得多,只需使用context.lookup()獲得該對象的句柄,然后強制造型成所需要的對象就可以了,如:
????????Person p=(Person)contex.lookup("cn=elvis,dc=daifu,dc=com");
這個句法在EJB的程序中,是經常用到的。
???????? 使用CORBA的跨語言性質,使用CORBA存儲對象比JAVA更加誘人,這意味著所存儲的對象可以被任何語言編寫的客戶端訪問。其實,微軟的.net說到底也非常簡單,無非是把COM對象存儲到微軟自家的目錄ActiveDirectory里面,從而可以在網絡范圍內使用任何微軟平臺的語言進行對象訪問而已。眾所周知,COM就是與CORBA相對的微軟規范。
???????? 使用對象串行化技術,可以把常用對象如某個打印機,某個客戶直接存儲到LDAP中,然后快速獲取該對象的引用,這樣,就比把對象信息存儲到關系數據庫中,分別取出屬性,然后再初始化對象操作的做法,效率要高得多了。這是LDAP目前比普通關系數據庫存儲要優秀的地方,而對象數據庫還不成熟。
客戶端訪問工具;
a)??????? openldap命令行;
Openldap提供了在UNIX命令行下的訪問工具集。包括ldapsearch,ldapadd,ldapmodify,ldappassword,ldapdelete等必要的工具。除了使用man獲得使用幫助外,還可以在http://www.tldp.org/HOWTO/LDAP-HOWTO/,及http://www.csis.gvsu.edu/GeneralInfo/Oracle/network.920/a96579/,獲得使用的支持。
例子:通過查詢根上下文判斷LDAP服務器是否正常工作:
$ ldapsearch -x -b "" -s base "objectclass=*" namingContexts
注:該命令查詢該當前服務器上的命令上下文,通常就是rootdn的上下文記錄。
-x??? 指該查詢使用目錄認證而不是使用SASL認證,;
-b “” 是查詢的起點,即base,空指從根開始查詢;
-s base 指查詢范圍。有三種選項,one指一層,包括兄弟條目;base指當前條目,sub,子孫記錄。默認是sub.
“objectclass=*” 是過濾器,表示所有記錄類型都加以選擇;
namingContexts是約定的特殊屬性,可以選擇其他屬性值進行查詢。
$ ldapsearch -x -b "dc=daifu,dc=com" -s base "objectclass=organization" dn dc
注:
-b “dc=daifu,dc=com” 指查詢的是“dc=daifu,dc=com”的條目,需要注意的是,slapd.conf中指定rootdn為“dc=daifu,dc=com”,并不等同于目錄中已經具有真實的“dc=daifu,dc=com”條目。
"objectclass=organization" 指查詢條件是organization類的。
“dc dc”指只需列出dn,dc兩項屬性。
?(ldapadd),ldapmodify的操作是基于LDIF文件的,所以必須先按規則生成LDIF文本文件,然后執行導入。要注意的是,新裝的LDAP具備一個上下文,并不等于在目錄中有相應的條目。如,OPENLDAP的slapd.conf中已經定義了一個根“dc=daifu,dc=com”,并不等于可以把新的條目添加到”dc=daifu,dc=com”,因此實際上并沒有這一條目,必須先執行添加相應的條目,然后才可以添加后續條目。
其次,LDIF的格式文件非常嚴格,空間被認為是確定的字符,因此,需要特別注意每行后面不應帶有空格。
b)??????? ldapbrowser;
??? ldapbrowser是開源的LDAP瀏覽工具,并帶有不太強的條目編輯功能。Ldapbrowser是純JAVA的程序,可跨平臺運行,在開源的程序中,是最優秀的一個。缺點是不能瀏覽服務器端的schema對象,從而限制了條目編輯(添加)的能力。
其次,由于JAVA對LDAP的訪問方式在添加時,必須預先生成一個實現DirContext接口的類,因此,這也令訂制型的添加操作在JAVA實現時相當困難。
?c)???????? ldapadministrator;
ldapadministrator是一個windows的收費程序,試用一個月。Ldapadministrator除了具備ldapbrowser的功能外,在條目編輯上的功能大為增強。
但從另一個角度看,LDAP總是涉及到大量的條目,當需要編輯的條目急速增加時,使用ldapadminstrator就不是輕松的事情,此時還是使用LDIF文件交??? 換為佳。
???? ??? d)??????? 瀏覽器;
??? 根據rfc2255.txt的約定,可以使用URI定義LDAP查詢,因此,理論上,只要瀏覽器內嵌支持,就可以作為LDAP客戶端使用。?? IE瀏覽器支持簡單的LDAP查詢。此時,IE把LDAP的URI看作是查詢的對象。但是IE以及Exchange server非常狹隘地把LDAP看作是純粹為EMAIL地址查詢服務的,只能以“圖形”的方式顯示查到的郵件地址什么的。因此,IE準確地說,是對LDAP存儲的郵件地址信息的查詢工具。
URI查詢語法是:
ldapurl??? = scheme "://" [hostport] ["/"
?????????????? ????[dn ["?" [attributes] ["?" [scope]
??????????????????? ["?" [filter] ["?" extensions]]]]]]
????? scheme???? = "ldap"
?????? attributes = attrdesc *("," attrdesc)
?????? scope????? = "base" / "one" / "sub"
?????? dn???????? = distinguishedName from Section 3 of [1]
?????? hostport?? = hostport from Section 5 of RFC 1738 [5]
?????? attrdesc?? = AttributeDescription from Section 4.1.5 of [2]
?????? filter???? = filter from Section 4 of [4]
?????? extensions = extension *("," extension)
?????? extension? = ["!"] extype ["=" exvalue]
?????? extype???? = token / xtoken
?????? exvalue??? = LDAPString from section 4.1.2 of [2]
?????? token????? = oid from section 4.1 of [3]
?????? xtoken???? = ("X-" / "x-") token
?
例:
類似
#ldapsearch –x –h 192.168.0.2 –p 389 -b “dc=daifu,dc=com” –b “sub” “objectclass=qmailuser”
的URI查詢是:
ldap://192.168.0.2:389/dc=daifu,dc=com??sub?objectclass=qmailuser?
?????? 瀏覽器并不是完全的LDAP客戶工具。
e)??????? ldapexplorer(PHP)
一個用PHP寫的LDAP處理工具?
?
二、???????????? 編寫LDAP訪問程序;
a)??????? JAVA
??????????????????????? i.????????????? JNDI(JAVA 命名及目錄接口)
JNDI是JAVA為命名及目錄服務訪問制定的基礎接口標準,用于訪問包括DNS,NIS,LDAP,文件系統等任何以樹目錄形式存在目標對象,并且基本上可保持訪問方式的一致(意味著代碼共用)。對于不同的目錄類型,JNDI通過使用不同的目錄驅動,以保證訪問方式的一致。
以下連接可獲得較詳細的講解和例程:http://java.sun.com/products/jndi/tutorial/
經常使用的LDAP驅動有JDK自帶的LDAP provider,還有IBM的PROVIDER,以及NOVEL的JNDI產品。需要提醒的是,JNDI中最重要的概念是上下文context,即定位從那一個入口開始操作,相當于openldap命令行中的-D開關的作用。其他的操作都是該上下文對象的調用。
LDAP通過JNDI添加條目是基于DirContext類的操作。由于JAVA只能以對象方式向LDAP添加條目,因此,必須首先具備實現DirContext接口的類,或使用DirContext(擴充了context接口)代替context,然后才能通過ctx.bind()的方法把該類添加到目錄中。
JAVA-LDAP-ADD的操作可以有三種方式:
Context.bind()或ctx.createSubcontext("name");
或DirContext.bind(“dn”,attrs,object)的方式。對于沒有預先編寫實現DirContext接口的類對象的添加,這是唯一的辦法。
?????????????????????? ii.????????????? JLDAP
JLDAP是由novel開發的,原是針對Novel的NDS目錄設計的JAVA訪問工具。NOVEL的NDS和網景(NETSCAPE)的目錄是工具界最早的目錄產品。JLDAP并非JNDI的服務供應者,而是同一抽象層次下的訪問工具集。與JNDI-LDAP相比,JLDAP更接近于類關系數據庫的訪問方式。
NDS是遵守LDAP協議的并進行了擴展的類MAD產品。而NOVEL也已把JLDAP捐獻給了OPENLDAP開源項目,可以世界范圍內自由使用。與JNDI相比,JLDAP無須繼承DirContext才能實現添加,也無需預先生成添加的類,可以象普通數據訪問那樣,生成連接,然后使用::add方法添加。這樣,添加的靈活性要強于JNDI。
但由于JLDAP目前是訪問NDS,因此,它不具備JNDI完全面向對象存儲的能力,對于高級的LDAP應用,JLDAP不是合適的選擇。
例:
import com.novell.ldap.*;
public class AddEntry
{
??? public static void main( String[] args )
??? {
??????? if (args.length != 4) {
??????????? System.err.println("Usage:?? java AddEntry <host name> <login dn>"
??????????????????????????? ????????????????????+ " <password> <container>");
??????????? System.err.println("Example: java AddEntry Acme.com"
??????????????????????? + " \"cn=admin,o=Acme\" secret \"ou=Sales,o=Acme\"");
??????????? System.exit(1);
??????? }
???????????????
??????? int ldapPort = LDAPConnection.DEFAULT_PORT;
??????? int ldapVersion? = LDAPConnection.LDAP_V3;
??????? String ldapHost?????? = args[0];
??????? String loginDN??????? = args[1];
??????? String password?????? = args[2];
??????? String containerName? = args[3];
??????? LDAPConnection lc = new LDAPConnection();
??????? LDAPAttribute? attribute = null;
??????? LDAPAttributeSet attributeSet = new LDAPAttributeSet();
??????? /* To Add an entry to the directory,
???????? *?? -- Create the attributes of the entry and add them to an attribute set
???????? *?? -- Specify the DN of the entry to be created
???????? *?? -- Create an LDAPEntry object with the DN and the attribute set
???????? *?? -- Call the LDAPConnection add method to add it to the directory
???? ????*/??????????
??????? String objectclass_values[] = { "inetOrgPerson" };
??????? attribute = new LDAPAttribute( "objectclass", objectclass_values );
??????? attributeSet.add( attribute );?????
??????? String cn_values[] = { "James Smith", "Jim Smith", "Jimmy Smith" };
??????? attribute = new LDAPAttribute( "cn", cn_values );
??????? attributeSet.add( attribute );
??????? String givenname_values[] = { "James", "Jim", "Jimmy" };
??????? attribute = new LDAPAttribute( "givenname", givenname_values );
??? ????attributeSet.add( attribute );
??????? attributeSet.add( new LDAPAttribute( "sn", "Smith" ) );
??????? attributeSet.add( new LDAPAttribute( "telephonenumber",
???????????????????????????????????????????????????? "1 801 555 1212" ) );
??????? attributeSet.add( new LDAPAttribute( "mail", "JSmith@Acme.com" ) );
??????? String? dn? = "cn=JSmith," + containerName;?????
??????? LDAPEntry newEntry = new LDAPEntry( dn, attributeSet );
??????? try {
??????????? // connect to the server
??????????? lc.connect( ldapHost, ldapPort );
??????????? // authenticate to the server
??????????? lc.bind( ldapVersion, loginDN, password );
??????????? lc.add( newEntry );
??????????? System.out.println( "\nAdded object: " + dn + " successfully." );
??????????? // disconnect with the server
??????????? lc.disconnect();
??????? }
??????? catch( LDAPException e ) {
??????????? System.out.println( "Error:? " + e.toString());
??????? }??????????????????????????????????
??????? System.exit(0);
??? }
}
????????????????????? iii.????????????? JdbcLDAP
JDBCLDAP是OcterString提供的,能過類SQL實現LDAP訪問的工具。JDBCLDAP是針對大量熟悉SQL而對LDAP欠缺了解的程序員而設計的,可以完成簡單的LDAP查詢、插入、更新、刪除這樣的工作。
JdbcLDAP使用LDAP-JDBC驅動訪問“LDAP數據庫”:
Class.forName("com.octetstring.jdbcLdap.sql.JdbcLdapDriver");
連接時使用各個DN的具體權限建立連接:
String ldapConnectString = ??"jdbc:ldap://localhost:389/dc=examples,dc=com?SEARCH_SCOPE:=subTreeScope";
java.sql.Connection con;
con = DriverManager.getConnection(ldapConnectString,"cn=Admin","manager");
連接字符串遵從標準的LDAP-URL格式,(RFC2255)。
SQL操作時,將每一個目錄ENTRY看作是一個統一表的一行,然后把屬性看作列,如:
String SQL = "INSERT INTO cn,ou (objectClass,objectClass,objectClass,ou,sn,cn) " +
??"VALUES (top,person,organizationalPerson,Product Development,Boorshtein," +
??"Marc Boorshtein)";
Statement insert = con.createStatement();
int count = insert.executeUpdate(SQL);
if (count < 1) {
??System.out.println("Insert Failed");
} else {
??System.out.println("Insert Succeeded");
}
??? Ou,sn,cn是新條目的入口標識。
??????? Jdbc-LDAP不可以完成串行化binding,因此,只適宜對已有的LDAP進行臨時訪問(如程序員不熟悉,或保持舊程序,僅修改必要的連接項),不宜把整個項目建筑在JDBC-LDAP上。實際上,LDAP本身就是一種訪問的前端協議,硬要把SQL再作為前端使用,是完全沒有必要的。
?b)??????? C語言:
包括openldap,netscape(sun),mozilla, novell,ibm等,都提供了LDAP的C SDK和接口函數。作為RFC標準的LDAP結構,struct LDAP是定義為對用戶隱藏的,并在各個實現函數中各自定義,以便適應不同的LDAP訪問。
#typedef struct ldap LDAP在ldap.h中定義;在2.0版以后,struct LDAP改為隱藏,只能能過函數ldap_set_option 和ldap_get_option訪問。(draft-ldapext-ldap-c-api-xx.txt)
使用時:
如:
LDAP *Ld=null;? //聲明并初始化LDAP類型的變量指針 *ld;
Ld?????? =ldap_init( ldaphost, ldapport );? //獲取LDAP的會話;
?
獲得會話后,調用ldap_simple_bind_s獲得訪問LDAP的權限,然后就可以調用不同的函數,如
ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
?????? ?????? sctrls, cctrls, timeout, sizelimit, &msgid );
即可完成相關的操作。
即步驟為:1。獲得會話;2。綁定對象;3。執行操作。
?
連接例子:
#include <stdio.h>
#include "ldap.h"
/* Adjust these setting for your own LDAP server */
#define HOSTNAME "localhost"
#define PORT_NUMBERLDAP_PORT
#define FIND_DN "uid=bjensen, ou=People, o=Airius.com"
int
main( int argc, char **argv )
{
LDAP*ld;
LDAPMessage*result, *e;
BerElement*ber;
char*a;
char**vals;
int i, rc;
/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, PORT_NUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the LDAP server. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Search for the entry. */
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
"(objectclass=*)", NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Since we are doing a base search, there should be only
one matching entry. */
e = ldap_first_entry( ld, result );
if ( e != NULL ) {
printf( "\nFound %s:\n\n", FIND_DN );
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, e, &ber );
a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
/* For each attribute, print the attribute name and values. */
if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}
??????????????????????? i.????????????? Novell函數庫:
Novel提供了基于普通LDAP函數庫的擴展,主要包括兩個部分:針對Novel eDirectory服務器產品的擴展,其次是對如ldapsearch等常用函數的擴展。詳情可從:http://developer.novell.com/ndk/qstart/opensource.htm#ldapc? 獲得幫助;
????????????????????? ii.????????????? Netscape函數庫;
Netscape一度是企業級目錄服務提供者,許多LDAP的C例子,實際上都是基于Netscape服務器的。但在Netscape被收購后,其目錄服務成了iPlanet和SUN eDirectory產品的一部分,出于支持JAVA和iplanet產品的緣故,SUN對該產品和相關庫的支持遠不夠積極,特別是對linux的支持不夠充分,估計也與保護solaris產品有關。
??????????????????? iii.????????????? Mozilla函數庫:
Mozilla可以看作是Netscape的另一個分支。準確地說,Netscape本來就是源于Mozilla。Mozilla是也是一個開源的項目,提供完整的C-SDK,缺點是對linux的支持不夠充分。
c)???????? Perl接口
?? Perl 的NET::LDAP模塊中包括有完整的LDAP目錄訪問函數,只要安裝NET::LDAP就可以完成正常的LDAP目錄訪問;但在安裝NET::LDAP模塊前,必須先安裝Convert::ASN1模塊,該模塊可以從CPAN下載。
?? 例:
#!/usr/bin/perl
?
use warnings;
use strict;
?
use Net::LDAP;
use Net::LDAP::Util qw(ldap_error_text);
?
my $server = "localhost";
my $ldap = new Net::LDAP($server) ||
?? die("failed to connect to server.$!\n");
?
my $mesg = $ldap->bind("cn=Manager,dc=daifu,dc=com", password => "secret");
?
die ("bind failed with ",ldap_error_text($mesg->code()),"\n")
?? if $mesg->code();
?
$mesg = $ldap->search(base => "dc=daifu,dc=com", scope => "sub",
?? filter => "sn=*",);
?
die ("search failed with ",ldap_error_text($mesg->code()),"\n")
?? if $mesg->code();
?
print "Count is ",$mesg->count(),"\n";
?
while (my $entry = $mesg->shift_entry()) {
?? print "dn:",$entry->dn(),"\n";
?? for my $attr($entry->attributes()) {
????? for my $val($entry->get_value($attr)) {
???????? print "$attr:$val\n";
????? }
?? }
?
?? print "\n";
}
操作過程實際上與C和JAVA是一樣的。
原文鏈接:http://www.daifusecure.com/articles/ldap.php