Working with Users and Groups in the NT Accounts Database

Suppose the notifier runs on an NT-based intranet, all the subscribers are listed in the NT domain’s Security Accounts Manager (SAM) directory, and the FullName slot of each user’s directory entry includes an email address as well as a first and last name. In this situation it makes sense to define the group of subscribers using NT’sUser Manager and then let the notifier consult the NT directory in order to enumerate subscribers and fetch their email addresses.

As usual there’s more than one way to do it. You can manipulate the necessary Win32 APIs from a number of scripting languages, including Visual Basic, Python, and Perl. Hooking directly into the low-level Win32 APIs used to query the directory is, however, a wholly NT-centric approach. What if you’d also like to be able to work with a Novell NDS directory or an LDAP directory? Happily Microsoft has provided Active Directory Services Interface (ADSI), a component that works with all three of these directories—and potentially others as well. ADSI will be included as a standard component of Windows 2000. Until then, it’s (freely) available separately at http://www.microsoft.com/windows/server/Technical/directory/adsilinks.asp .

ADSI works on the ODBC model. It’s a driver manager that provides a generalized interface to data sources—in this case, directories—and that accepts pluggable drivers that adapt it to a range of specific data sources. As its name implies, ADSI’s eventual purpose is to connect applications to Microsoft’s own Active Directory. Since that product won’t be widely deployed anytime soon, ADSI’s immediate role is to encourage the development of directory-aware applications that will be compatible with Active Directory.

Example 11.4 shows Group::NTGroup , which supports the same interface as Group::SimpleGroup but which connects to an NT domain instead of a Perl-managed data structure. It’s written in Perl, which means our notifier can use it interchangeably with Group::SimpleGroup . But since ADSI runs as an OLE automation server, any OLE-aware scripting languages can use it. ADSI services are also available to those languages that can embed in ASP web pages—including VBScript, JavaScript, Python, and Perl.

Example 11-4. Group::NTGroup, a Simple NT-Oriented Group Directory

package Group::NTGroup;
use strict;
use Win32::OLE;

sub new
  {
  my ($pkg,$domain,$group_name) = @_;
  my $self = 
    {
    'domain' => $domain,
    'group'  =>  Win32::OLE->GetObject("WinNT://$domain/$group_name,Group"),
    };
  bless $self,$pkg;
  return $self;
  }

sub members
  {
  my ($self) = @_;
  my @members = ();
  my $group = $self->{group};
  my $m = $group->Members();
  foreach my $member (in $m)
    {   push (@members, $member->{Name}); }
  return @members;
  }

sub isMember
  {
  my ($self,$member) = @_;
  return grep  ( /^$member$/, $self->members ) ? 1 : 0;
  }

sub setMember
  {
  my ($self,$member) = @_;

  if (! $self->existsUser($member) )        # if user doesn't exist
    {
    my $dn = "WinNT://$self->{domain}";
    my $d = Win32::OLE->GetObject($dn);
    my $u = $d->Create("user",$member);     # create user
    $u->SetInfo;
    }

  my $group = $self->{group};               # then add to group
  $group->add("WinNT://$self->{domain}/$member");
  $group->SetInfo;    
  }

sub getMember
  {
  my ($self,$member) = @_;
  my $dn = "WinNT://$self->{domain}/$member";
  $member = Win32::OLE->GetObject($dn);
  $member->GetInfo;
  my $member_hash = {};
  for (1..$member->{PropertyCount})
    { 
    my $prop = $member->Next;
    $member_hash->{$prop->Name} = $member->Get($prop->Name);
    }
  return $member_hash;
  }

sub delMember
  {
  my ($self,$member) = @_;
  my $group = $self->{group};
  $group->remove("WinNT://$self->{domain}/$member");
  $group->SetInfo;
  }

sub setProperty
  {
  my ($self,$member,$prop_name,$prop_val) = @_;
  my $dn = "WinNT://$self->{domain}/$member";
  $member = Win32::OLE->GetObject($dn);
  $member->GetInfo;
  $member->Put($prop_name,$prop_val);
  $member->SetInfo;
  }

sub getProperty
  {
  my ($self,$member,$prop_name) = @_;
  my $dn = "WinNT://$self->{domain}/$member";
  $member = Win32::OLE->GetObject($dn);
  $member->GetInfo;
  return $member->Get($prop_name);
  }

sub existsUser
  {   
  my ($self,$member) = @_;
  my $dn = "WinNT://$self->{domain}/$member,User";
  my $u = Win32::OLE->GetObject($dn);
  return (defined $u) ? 1 : 0;
  }

sub dumpGroup
  {
  my ($self) = @_;
  my $group_hash = {};
  foreach my $member ($self->members)
    { $group_hash->{$member} = $self->getMember($member); }
  return $group_hash;
  }

1;

Group::NTGroup’s constructor shows how you tap into ADSI. The parameter you pass to GetObject( ), called an AdsPath, has two components. The leading part, which can be WinNT://, or NDS://, or LDAP://, selects the directory provider that will satisfy all subsequent requests to the object created by this call. The trailing part of the AdsPath names the location in a directory tree to which the object will refer.

In a Novell environment, you’d initialize the module with an AdsPath like NDS://RONIN/o=RoninHouse/cn=Subscribers. In an LDAP context, it would look similar: LDAP://RoninHouse.com/o=RoninHouse/cn=Subscribers.

An ADSI group object answers the Members( ) method call with a handle to an OLE collection of its members. In VBScript you can enumerate that collection like this:

set group   = GetObject("WinNT://UDELL/Subscribers")
set members = group.Members

for each user in members
        Wscript.echo user.name
next

As you can see in Example 11.4, Win32 Perl supports the same idiom. Perl wizards unfamiliar with Win32 Perl may not recognize the construct (in $m), which isn’t part of Perl’s standard repertoire. It’s a Win32 extension added to the ActiveState version of Win32 Perl so that scripts can navigate OLE collections.

To operate on other parts of the directory, you call GetObject( ) with different AdsPath strings. For example, the getMember( ) method calls GetObject("WinNT://DOMAIN/USERNAME") to get a handle to a user object so it can work with that user’s directory entry.

We can’t get and set arbitrary properties here; the module only works with the schema that governs the directory it’s talking to. NDS, Active Directory, and others are extensible, but NT domains aren’t. In this case the notifier can’t get and set an email attribute because there isn’t one. But there are a couple of fields available for its use. As I mentioned, one solution would be to always append an email address to the FullName field, for example: Jon Udell <[email protected]>. Alternatively, you could tuck an email address into the Description slot of the NT directory entry.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.96.146