活动目录服务接口ADSI(Active Directory Service Interface)

目录服务技术介绍——ADSI 潘爱民

北京大学计算机科学技术研究所 (100871)

【摘要】本文介绍了Microsoft提出的活动目录服务接口(ADSI)技术。文章首先讲述了ADSI的结构,然后介绍了ADSI的程序设计方法,最后通过例子简单说明了ADSI的用法。

一、ADSI简介

ADSI (Active Directory Services Interface)是Microsoft新推出的一项技术,它统一了许多底层服务的编程接口,程序员可以使用一致的对象技术来访问这些底层服务。 ADSI把这些服务的公共部分提取出来,同时隔离出相异的部分,程序员可以用统一的接口访问底层服务的公共部分,并延伸到底层服务的专有部分。

为了说明ADSI的接口标准和用法,首先我们解释几个重要的概念:

目录(Directory):目录类似于一个数据库,它通常包含一些描述性的、基于属性的信息。由于目录中的信息被读访问的频率比写访问的频率要高 得多,所以,目录并不象数据库那样必须实现复杂的事务或者回滚机制。在许可的条件下,目录的更新操作通常是简单的更改操作。对于大量的信息查找或者信息检 索要求,目录应该快速给出应答。为了提高性能和可靠性,并降低应答时间,分布式的目录信息可能枰 诠憷 耐 绶段 诮 懈粗撇僮鳌R蛭 肓烁粗苹 疲 栽诟粗频阒 洌 菔钡牟灰恢率悄岩员苊獾模 灰 钪漳芄煌 郊纯伞?br> 目录服务(Directory Service):目录服务所表达的含义与目录紧密相关,它是指目录信息源与针对这些信息源的服务结合起来使得这些信息可被用户使用。

一个典型的目录服务具有以下几个特性:

□       安全特性。管理员可以对目录强制使用安全特性,以便保护目录信息不被非法获取。

□       分布特性。一个目录可以跨越机器边界,也即目录信息可以在网络上的不同机器上。

□       复制特性。目录信息应尽量让更广阔范围的用户所利用。

目录服务既是一个信息管理工具,同时也是一个面向最终用户的工具。在网络上各种各样的对象数量迅速增长的今天,目录服务非常有意义。类似于网络硬件设施的集线器(hub)的概念,目录服务相当于软件集线器。

活动目录(Active Directory):活动目录是Microsoft在Windows 2000中实现的目录服务,它不仅实现了作为一般目录服务的特性,包括安全特性、分布特性以及复制特性等。它同时也扩充了一些新的特性,以便使得目录信息 更加易于管理和搜索。活动目录在实现目录服务的同时,充分考虑了目录信息的可伸缩性,从包含上百个对象的单服务器结构到成千上百服务器的百万以上的对象信 息,它都可以正常工作。

目录服务是一个抽象的概念,从用户使用的角度来看,通常最为关心的是目录的名字空间以及相关的访问协议。名字空间限定了目录服务的描述能力,而访问 协议必须要标准化,以便支持分布式特性。访问协议的标准为LDAP(Light-weight Directory Access Protocol)协议,它是建立在TCP/IP基础上的目录服务协议,它的信息模型包括了数据和名字空间。与其它Internet协议不同的 是,LDAP还提供了一组API以便简化LDAP应用的编写工作。

LDAP也遵守客户-服务器模型,包含目录数据的一个或多个LDAP服务器建立起一个LDAP目录树,LDAP客户通过网络连接到服务器,向服务器 发出请求或者执行一些操作。LDAP服务器响应客户的请求,或者把客户的请求指引到其它包含客户指定信息的另外的LDAP服务器上。不管客户连接到哪个 LDAP服务器上,他所看到的目录树视图应该是一样的。

Microsoft提供了ADSI用于开发客户方的目录服务应用系统。ADSI是一组COM接口标准,它通过LDAP协议访问目录服务。ADSI实 现了目录服务的客户模型,利用ADSI,我们可以在Windows平台上开发目录服务客户应用。如果不使用ADSI,那么用到目录服务的应用必须编写代码 处理每个它所用到的名字空间结构,当有新的名字空间加入时,必须修改代码以适应变化,而且,在访问目录服务时,可能要调用到底层与网络有关的API函数。

从技术角度来看,ADSI用到了与ADO(Active Data Object,Microsoft推出的一致数据访问接口)非常类似的技术,它通过一组双接口(dual interface,既可以通过vtable也可以通过自动化接口IDispatch访问属性和方法的自动化对象)提供了目录服务功能。客户程序可以根据 性能要求或者开发语言的特点选择不同的编程模型。

由于ADSI使用了COM和自动化对象技术,所以ADSI的编程用法比较简单,但要真正掌握ADSI,首先必须理解ADSI接口标准中用到的一些基本概念,下面列出如下:

(1) 名字空间(Namespace)。名字空间是LDAP的基本概念,也是ADSI的基本概念。名字空间是一个有界区域,每一个给定的名字都必须在特定的名字 空间中被解析,解析的过程是把名字翻译成某个对象或者名字所代表的信息。比如,电话簿形成了一个名字空间,每一个电话订户的名字被解析成电话号 码;NTFS文件系统也构成了一个名字空间,每个文件名可被解析成文件对象。活动目录也形成了一个名字空间,目录中的每个对象可被解析到对象本身。

(2) 对象(Object)或目录对象(Directory Object)。对象是指一组属性的集合,它往往代表了有形的实体,比如用户、文件等。对象通过属性描述它的基本特征,比如,用户的属性可能包括姓名、电话号码、电子邮件地址等。

(3) 包容器(Container)。包容器是名字空间的一部分,与目录对象一样,它也有属性,但与目录对象不同的是,它不代表有形的实体,而是其它目录对象或者包容器的容器。

(4) 目录树(Directory Tree)。在一个名字空间中,由包容器和对象构成了一个完整的树结构。在ADSI中,树是基本的结构,从每一个包容器对象作为起点,层层深入,都可以构 成一棵子树。一个简单的目录可以构成一棵树,一个计算机网络或者一个NT域也可以构成一棵树。

(5) 标识名(Distinguished Name,简称为DN名)。活动目录中的每一个对象都有一个标识名,标识名包含对象在名字空间中的完整路径名,从基本的名字空间包容器开始,通过层层包容 器对象,一直到达对象节点。不同的名字空间有不同的标识名命名规则,ADSI提供了一个命名框架,通过名字即可识别相应的目录服务和名字空间。

(6) 对象标识符(Object Identity)。对象除了其DN名之外,它还有一个128位的全局标识符(GUID)。在ADSI内部,对象是通过标识符来识别的,而不是名字。当对 象被创建时,目录服务代理程序首先为对象分配一个标识符,客户可以通过对象的“objectGUID”属性获得标识符,这是一个只读属性,不管对象被移动 或者改名,它的标识符都不会被改变。

(7) 命名环境(Naming Context)。命名环境是指任何一个目录子树,在ADSI中,一个服务器至少包含三个命名环境:表结构(schema)、配置(configuration)和用户命名环境。

(8) 域(Domain)。在ADSI中,域是Windows NT网络的安全性边界。ADSI由一个或多个域组成。在单独的计算机上,域即指计算机本身。当多个域通过信任关系连接起来之后,所有的域共享公共的表结 构、配置、全局目录(global catalog),从而形成域树(domain tree),多个域树连接在一起形成域林(domain forest)。域林中的所有域共享公共的表结构、配置、全局目录(global catalog)。

(9) 站点(site)。站点是指一个或多个通过TCP/IP连接起来的子网。通常,站点内部的子网通过可靠的网络连接起来。

从编程技术来看,ADSI只是一些COM接口和COM组件的标准,但ADSI表达信息的方式是革命性的。名字空间的概念体现了ADSI表达信息的广 泛性;域和站点的概念体现了ADSI的空间广阔性,从单机到局域网,再到广域网,都可以纳入ADSI的表达范围;命名环境的概念体现了ADSI对信息的自 组织、自描述特性。对象、包容器、目录树的概念体现了ADSI表达信息的基本结构方式。对象标识名和标识符两种机制结合起来,使得目录对象既有直接面对最 终用户的名字特性,又有内部唯一标识的可编程特性。

在ADSI出现之前,实际上,我们已经有了很多可按目录方式管理的应用系统,比如文件系统、用户管理、电子邮件应用等等。ADSI抽取了这些应用对 象的共性,通过一组标准化的接口实现目录对象的管理。虽然,我们还不能看到Windows 2000中ADSI的最终形式,但是在Windows NT 4.0版本基础上的一些应用系统,已经实现了ADSI标准,最为典型的是Microsoft Exchange Server,它充分体现了ADSI的基本概念。

下面列出目前已经实现的ADSI目录服务: (1)     Windows NT域用户管理。 (2)     LDAP (Exchange Server)目录服务。 (3)     Internet Information Server (4)     NDS(Novell NetWare Directory Services) 目前,在一个企业内部存在多个目录服务也会带来一些问题。对于管理员来说,它必须管理多个目录服务,这使得管理更为复杂;对于企业工作人员来说,为了访问 不同目录服务中的信息,他必须登录到多个目录服务中;对于开发人员来说,为了使用目录服务,他必须选择使用哪个目录服务或者使用多个目录服务。虽然 ADSI统一了目录服务的编程接口,但是为了在企业内部更好地使用目录服务功能,必须对目录服务的应用有所规划。由于Windows 2000全面采用了ADSI作为其应用编程接口,因此,建立在Windows 2000上的应用将可以更方便地访问系统提供的各种目录服务,应用程序与操作系统可以更好地结合起来。 二、ADSI结构 ADSI编程接口包括两个方面,实现ADSI目录服务的提供者(provider)和使用ADSI的客户。每一个当前被支持的目录服务必须有一个提供 者,ADSI提供者实现了ADSI对象以及与名字空间相关的对象;ADSI客户与普通的COM客户程序类似,它调用ADSI接口访问目录服务所提供的各种 功能,包括查找目录、读取目录对象的属性,如果允许的话,还可以修改对象的属性。 ADSI提供目录访问的基本结构如下图所示:


图1 ADSI目录服务层次结构图 ADSI提供了两种形式的编程接口,对于支持自动化的客户,它可以通过ADSI自动化接口调用目录服务提供者的属性和方法;对于性能要求比较高的客户,它 可以通过vtable形式的COM接口访问目录服务提供者。ADSI这种双接口结构几乎总能满足客户程序的需要,关于双接口的原理以及用法请读者参阅有关 自动化(Automation)方面的书籍,本文为简便起见,仅从自动化接口的角度讨论ADSI接口。 在ADSI所定义的接口规范中,对应于目录服务的目录对象,我们也称为活动目录对象(Active Directory Object)。另一个重要的对象为包容器(Container) 对象,包容器对象与目录对象的关系跟我们在文件系统中使用的目录与文件的关系类似,一个包容器对象可以包含许多其它的目录对象或者包容器对象,而目录对象 代表了一定的实体。对于每个ADSI提供者,它从基本的名字空间的根节点开始,通过包容器对象和目录对象,形成了一棵树,如图2所示。

图2 ADSI包容器对象与目录对象的树状结构示意图 ADSI的每个包容器对象或者目录对象都有一个与之相联系的类别对象,类别对象说明了对象的一些特征信息,比如,对象的属性、对象属于包容器还是目录对 象,等等。类别对象也描述一些属性,这些属性是所有属于此类别的对象所共有的属性,在这些属性中,有的属性是强制必须要有的,而有的属性则是可选的。属性 最重要的特征是它的语法,语法定义本身也是一个目录对象。类别、属性和语法都是某个包容器对象下面的目录对象,被称为表结构(schema)。 在ADSI定义的接口中,最基本的接口为IADs接口,它是一个从IDispatch接口派生出来的双接口,并且所有的目录对象都必须实现IADs接口。IADs接口的属性和方法如表1和表2所示。

 表1 IADs接口的属性

表2 IADs接口的方法

另一个重要的接口是IADsContainer,它是所有包容器对象必须要实现的接口。IADsContainer接口的属性和方法如表3和表4所示。

表3 IADsContainer接口的属性

 表4 IADsContainer接口的方法

方法名

参数

说明

GetObject

BSTR bstrClass,

BSTR bstrRelativeName,

LPDISPATCH *pNewObject

得到包容器对象中指定对象的IDispatch接口指针

Create

BSTR bstrClass,

BSTR bstrRelativeName,

LPDISPATCH *pNewObject

在包容器对象中创建指定名字的目录对象,并返回对象的IDispatch接口指针

Delete

BSTR bstrClass,

BSTR bstrRelativeName

删除包容器对象中指定的目录对象

CopyHere

BSTR bstrSource,

BSTR bstrNewName,

LPDISPATCH* pNewObject

拷贝目录对象到当前包容器对象中

MoveHere

BSTR bstrSource,

BSTR bstrNewName,

LPDISPATCH* pNewObject

移动目录对象到当前包容器对象中

IADs和IADsContainer接口分别代表了目录服务中的目录对象和包容器对象,为了对一个名字空间进行各种目录操作,我们必须从最基本的 根出发,ADSI为我们提供了接口IADsNamespaces用以表达名字空间对象。IADsNamespaces接口比较简单,它只有一个属性 “DefaultContainer”,此属性指定了客户程序访问的基本包容器对象的路径。

仅仅一个IADs接口还难以表达一个目录对象的全部特征,前面已经提到,ADSI用类别来定义目录对象的特征,并且类别对象本身也是目录对象,它除了实现IADs接口外,还实现了IADsClass接口。IADsClass接口从IADs派生,其属性如表5所示。

 表5 IADsClass接口的属性

IADsClass接口只有一个方法Qualifiers,用来返回描述附加限制对象的集合对象。在IADsClass接口的属性 中,PrimaryInterface属性可直接指示客户程序去请求对应的接口ID,以便访问该类别所指示的属性,比如,在目录服务中,“User”类指 示用户对象实现了一个ADSI接口IADsUser,它包含属性“姓”、“名”、“职称”、“电话”等等。

从类别到对象,它可以指定属性,那么目录对象的属性如何被指定呢?ADSI通过接口IADsProperty进行描述,IADsProperty接口的属性和方法如表6所示。

  表6 IADsProperty接口的属性

属性名

类型

说明

OID

BSTR

唯一的对象标识符

Syntax

BSTR

语法路径

MaxRange

long

对于多值属性,最大属性数

MinRange

Long

对于多值属性,最小属性数

MultiValued

VARIANT_BOOL

多值属性标志

最后一个重要接口为IADsSyntax,它只有一个属性,如表7所示。     
                                                      表7 IADsSyntax接口的属性

属性名

类型

说明

OleAutoDataType

long

代表此语法的自动化数据类型

ADSI定义了许多接口,上面介绍的只是ADSI的基本接口,从这些接口我们可以看到,ADSI用表结构的方式描述目录对象的属性,这种方式可扩展性很 强。目录对象本身是个抽象概念,它可以包含许多与应用有关的属性,ADSI目录服务提供者可以利用表结构描述这些属性,以便客户程序可以对目录对象进行有 效的访问。 ADSI还定义了一些常用的目录对象使用的接口,比如IADsUser、IADsO、IADsComputer、IADsGroup、IADsOU、IADsDomain、IADsService,它们分别代表了用户、组织、计算机、用户组、部门、域、系统服务。 除了使用以上介绍的ADSI接口访问ADSI目录服务之外,客户程序也可以使用ADO的标准接口访问目录服务,它可以利用ADO的记录集对象访问ADSI的包容器,对包容器对象进行枚举或者检索。ADO与ADSI的关系如图3所示。

图3 客户程序访问ADSI目录服务的两种方法

 

 

、ADSI编程模型

了解了ADSI的基本结构之后,现在我们再讨论ADSI的编程模型。首先,我们介绍目录对象的路径表示法,通常我们使用URL路径表示法,如下:

:

或者 ://

如果我们不知道名字空间的符号表示,可以从ADSI的最基础的根“ADS:”开始,比如,我们在NT 4.0下对“ADS:”进行枚举可以得到以下5个名字空间:

IIS

LDAP:

NDS:

NWCOMPAT:

WinNT:

如果我们要用ADSI访问NT用户信息,可以使用下面格式的路径:

WinNT:// /

如果我们要用ADSI访问Microsoft Exchange Server的用户信息,可以使用下面格式的路径:

LDAP:// /cn= ,cn=Recipients,ou= ,o=

这表示在 组织下的 站点中的帐户 , 为此站点的一个服务器,它提供LDAP服务。

下面我们讨论几个基本的编程问题:

(1) 绑定到路径指定的对象。

客户程序可以利用以下的方法绑定到路径所指定的对象:

由于目录对象的标识名可能在某些操作的影响下被改变,但目录对象的objectGUID属性永远不会改变,所以我们可以直接在LDAP路径中指定此GUID,客户程序直接绑定到此对象,下面的代码显示了这种用法: IADs *pADs; LPWSTR pszFilter = L"LDAP://MyServer/"; hr = ADsGetObject( pszFilter, IID_IADs, (void**)&pADs); 等价的VB代码如下: Dim myObject as IADs Set myObject = GetObject("LDAP://") (2) 包容器对象的枚举操作。 客户程序通过上面的方法可以直接到达指定的目录对象或者包容器对象,我们也可以从某个节点开始访问目录子树,利用IADsContainer接口所提供的方法,我们可以实现枚举操作,举例如下: Dim MyObject as IADs Dim Child as IADs Dim Container as IADsContainer On Error Resume Next Set MyObject = GetObject("LDAP://MyServer") Set Container = MyObject If Err = 0 Then   For Each Child in Container     Debug.Print Child.Name   Next Child EndIf 通过这种枚举操作,我们可以访问目录子树中的所有包容器对象和目录对象。 (3) 读取目录对象的属性。 读取对象属性最简单的方法莫过于直接通过对象的IADs::Get或者IADs::GetEx接口成员函数,比如: Dim MyUser as IADs Dim MyCommonName as String set MyUser = GetObject("WinNT://MyServer/MyName") MyCommonName = MyUser.Get("Fullname") 当然如果我们已经知道了目录对象的其它接口,也可以用更直接的方法访问属性,比如: Dim MyUser as IADsUser Dim MyName as String Set MyUser = GetObject("WinNT://MyServer/MyName") MyName = MyUser.Fullname 客户程序在访问目录对象时,通常ADSI已经为对象的属性作了缓存。当对象被创建时,其属性缓存为空,如果客户调用IADs::GetInfo从底层目录 服务装载对象属性,那么它就会填满缓存,因为Get或者其它的Get_propertymethod函数都隐式调用了GetInfo函数,所以客户只要调 用Get函数取一次属性值,以后的Get函数就直接从缓存中读取属性值。如果客户程序要刷新缓存中的属性值,可以显式调用IADs::GetInfo函 数。使用缓存可以避免频繁地从服务器读取属性数据,从而降低网络负担。 如果客户程序不希望在缓存状态下读取属性值,可以使用目录对象的另一个接口IDirectoryObject,它可以直接访问底层目录服务的对象属性数据,为了优化性能,每次它可以取多个属性值。 (4) 设置目录对象的属性。 与读取属性相对应,设置对象属性可通过对象的IADs::Put或者IADs::PutEx接口成员函数实现,但是这两个函数只是把属性值写到缓存中,客户程序必须显式调用IADs::SetInfo成员函数,以便使更新后的属性值反映到底层目录服务中。举例如下: Dim MyUser As IADsUser Dim NewName As Variant Set MyUser = GetObject("WinNT://MyServer/MyName") NewName = "Pan Aimin" User.Put "FullName", NewName User.SetInfo 当客户程序创建了一个新的目录对象之后,只有在调用了IADs::SetInfo函数后,目录对象才真正被永久创建,否则只是缓存中的对象而已。 (5) 表结构的用法。 ADSI提供了用表结构描述目录对象属性的机制,客户程序可以在运行时刻访问目录对象表结构信息,下面的代码演示了表结构的基本用法: Dim Computer As IADsComputer Dim Class As IADsClass Dim V As Variant Set Computer = GetObject("WinNT://MyDomain/MyMachine") Set Class = GetObject(c.Schema) Debug.Print "Properties in this Class: " For Each V In Class.MandatoryProperties   Debug.Print "  "; V Next V For Each V In Class.OptionalProperties   Debug.Print "  "; V Next V

客户程序也可以利用IADsClass、IADsProperty和IADsSyntax接口在运行时刻确定目录对象的详细属性信息。操作步骤如下: a.  先绑定到目录对象的表结构对象,可以直接访问目录对象的“schema”属性。 b.  用枚举的办法从表结构对象中找到强制属性或者可选属性,如果客户知道要访问的属性名则可以跳过这一步。 c.  绑定到表结构对象的包容器对象。 d.  从表结构对象的包容器对象获得属性的定义对象。 e.  从属性定义对象获取属性信息,包括属性的语法信息等。 下面的代码演示了如何从获得表结构对象到访问“Owner”属性的细节信息的过程: Dim obj As IADs Dim cl As IADsClass Dim pr As IADsProperty Dim sy As IADsSyntax Dim sc As IADsContainer Set obj = GetObject("WinNT://MyDomain/myMachine") Set cl = GetObject(obj.Schema) Set sc = GetObject(cl.Parent) Set pr = sc.GetObject("Property","Owner") MsgBox "Attribute: " & pr.Name MsgBox "Syntax:  " & pr.Syntax Set sy = GetObject(sc.AdsPath & "/" & pr.Syntax) MsgBox "Syntax object: " & sy.Name & " of OleAutoDataType: " & sy.OleAutoDataType (6) 增加或者删除目录对象。 利用包容器对象的IADsContainer接口的方法(见表4),我们可以很方便地增加或者删除目录对象,举例如下: Dim Container as IADsContainer Dim NewUser as IADsUser Set Container = GetObject("WinNT://MyDomain") ' Create the new wrapper. Set NewUser = Container.Create("user", "PanAimin") ' Write it back to the DS NewUser.SetInfo ' Set Jane's password. NewUser.SetPassword("123") ' Delete the user. Call Container.Delete("user","Mary") ADSI的各种操作比较简单,只要我们能够理解ADSI的基本结构,并且对核心的几个接口以及常用提供者的一些接口有所了解,就可以用一致的方法访问目录服务,这也说明了ADSI作为通用目录服务标准为程序员带来的最大益处。 实现ADSI提供者要比使用ADSI复杂得多,通常情况下,我们只需使用系统已经定义的ADSI提供者。但如果确实应用需要,我们可以实现自定义的 ADSI提供者。为了实现一个ADSI提供者,有一些特性是必须要支持的,而其它的特性则是可选的。下面是一些必须要实现的特性: (1)   路径解析使用COM的命名规范(moniker),其中名字空间对象必须要实现IParseDisplayName::ParseDisplayName函数以及IADsOpenDSObject接口。 (2)   IADs接口必须实现属性的缓存技术,只有IADs::GetInfo函数和IADs::SetInfo函数才刷新缓存或提交到底层目录服务。 (3)   每一个包容器对象必须实现IADsContainer接口。 (4)   所有的ADSI对象都支持IDispatch接口,以便自动化客户访问属性和方法。 (5)   对于非自动化客户通过IDirectoryObject访问ADSI目录对象,而不是IADs接口。 (6)   ADSI至少实现一个表结构包容器对象,以及相应的语法、属性和类别对象,分别支持接口IADsSyntax、IADsProperty或IADsClass,每个根节点必须包含它自己的表结构包容器对象。 为了让ADSI能够找到自定义的提供者,我们必须在实现了ADSI提供者之后,把它注册到系统注册表中。在 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/ADs/Providers键下添加新的提供者项(指向提供者组件的 ProgID),如果读者感兴趣,可以检查该键项,以便确定当前系统已经安装了哪些提供者。

了解了客户程序的编程方法以及ADSI提供者的基本内容之后,现在我们来看看从客户程序到ADSI提供者组件的交互过程(如图4所示),以便加深读者对ADSI的理解。

图4 客户程序与ADSI提供者的交互过程
客户程序首先向ADSI发一个对象绑定请求(图中步骤1),ADSI组件根据客户给出的ADSI对象路径,提取出标识提供者ProgID的字符串,比如 “WinNT”、“LDAP”或者自定义的提供者ProgID,进一步在注册表中找到此ProgID所对应的CLSID(图中步骤2)。然后装入提供者组 件程序(图中步骤3),接下去的任务就交给提供者组件,由它创建对象并返回给ADSI组件(图中步骤4),进一步返回给客户程序(图中步骤5)。以后客户 与目录对象直接进行通讯(图中步骤6)。这是客户绑定ADSI目录对象的实现过程。
四、ADSI例程序 这一部分我们将介绍一个ADSI例程序dsbrowse,它是一个VB表单窗口程序,此程序可以对当前机器上的所有ADSI提供者进行浏览,图5分别给出了dsbrowse运行的初始状态以及打开NT域之后的目录对象列表图。
(a) 初始运行状态
(b) 打开WinNT域之后的状态 图5 例程序dsbrowse运行示意图
dsbrowse例程序非常简单,在表单窗口的初始化函数中,根据程序指定的根路径,对它所包容的对象进行枚举。缺省情形是,我们在初始路径中指定 “ADS:”,它是ADSI的总根,包容了当前机器上的所有名字空间,如图5(a)所示,dsbrowse列出了当前机器上的5个名字空间:IIS、 LDAP、NDS、NWCOMPAT和WinNT。有的名字空间需要指定相应的服务器,不能进行无服务器枚举,所以我们不能直接用dsbrowse进行枚 举,但有的名字空间可以进行无服务器枚举,对这种名字空间我们可以点击名字空间前的加号即可列出它所包容的目录对象或者子包容器对象。比如,我们在 “WinNT”名字空间点击可列出当前网络环境下所有的NT域,进一步在某个NT域名上点击可列出此域中所有的目录对象,包括此域的用户、计算机、用户 组、服务等对象。 我们在窗口的树状控制中选中某个对象,再点击右上角的“Properties”按钮,dsbrowse程序会用一个对话框显示被选中对象的属性信息,如图 6所示。属性对话框列出了相应对象的名字、路径、是否为包容器对象、以及它的属性表,用户可以通过下部的控制修改对象的属性。
图6 例程序dsbrowse的属性对话框
读者可以从Visual Studio的Visual C++ Sample中得到dsbrowse程序的主要源代码,源代码位于Samples/sdk/netds/adsi/sampapp/dsbrowse目录 下。在sampapp目录下还有一个Visual C++的例程序AdsCmd,它可以直接通过命令行参数访问指定目录对象,也可以列出包容器对象的所有子对象。比如,我们可以通过AdsCmd列出 Microsoft Exchange Server的邮箱信息: AdsCmd list LDAP://MailServer/cn=Recipients,ou=MySite,o=MyOrganization 我们也可以让AdsCmd程序直接给出指定路径的目录对象的属性信息,例如: AdsCmd dump LDAP://MailServer/cn=PanAimin,cn=Recipients,ou=MySite,o=MyOrganization 当然,AdsCmd不仅可以访问Microsoft Exchange Server的用户信息,也可以访问其它任意名字空间的目录服务信息。 五、结束语
ADSI是一项正在发展中的技术,它体现了网络时代访问和管理信息的基本思想。Microsoft正逐步把它标准化,ADSI也将成为Windows 2000操作系统的一项新特性,虽然我们在Windows NT 4.0以及一些应用软件中已经看到了ADSI的应用,但无论是WinNT或者是用于Microsoft Exchange Server用户访问的LDAP协议,ADSI的支持都是不完全的,我们还无法通过WinNT名字空间添加NT用户。虽然ADSI支持Windows NT的安全特性,但实际上这种特性还有待于进一步完善。
ADSI技术的全面应用必须要等到Windows 2000发布之后才有可能。随着Windows 2000发布日的临近,ADSI最终必将统一目录服务接口。作为Windows程序员,我们必须对此作好准备。本文对ADSI作了基本的介绍,文中提到的 接口或者基本原则不会再变化,但个别细节有可能在新的版本中有所不同。请读者在使用中注意这一点。

    C或者C++程序可以使用ADsGetObject或者ADsOpenObject获得指定对象的接口指针,如果我们不能确定对象支持哪个接口,我们可以在函数中指定接口IADs,因为所有的ADSI目录对象都支持此接口,函数返回之后,再调用QueryInterface成员请求其它的接口指针。

    对于VB或者VBScript应用程序,可以调用GetObject函数得到指定的目录对象。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值