Initial import
[samba] / examples / LDAP / smbldap-tools-0.9.1 / doc / smbldap-migrate-unix-accounts
diff --git a/examples/LDAP/smbldap-tools-0.9.1/doc/smbldap-migrate-unix-accounts b/examples/LDAP/smbldap-tools-0.9.1/doc/smbldap-migrate-unix-accounts
new file mode 100644 (file)
index 0000000..1035ee9
--- /dev/null
@@ -0,0 +1,371 @@
+#!/usr/bin/perl -w
+
+# Created by P.Wieleba@iem.pw.edu.pl in 2004
+
+use strict;
+use Getopt::Std;
+use FindBin;
+use FindBin qw($RealBin);
+use lib "$RealBin/";
+use smbldap_tools;
+
+# function declaration
+sub migrate_user;
+sub migrate_shadow_user;
+sub get_user_entry;
+sub exist_in_tab;
+sub del_from_tab;
+sub add_to_tab;
+sub read_shadow_file;
+
+# smbldap-migrate-unix-accounts (-? or -h for help)
+#
+#
+
+my %Options;
+
+my $ok = getopts('M:P:S:vn?hd:a', \%Options);
+
+if ( (!$ok) || ($Options{'?'}) || ($Options{'h'}) || (!keys(%Options)) ) {
+  print "Usage: $0 [-PSMvn?hda]\n";
+  print "  -?|-h      show this help message\n";
+  print "  -P file    import passwd file\n";
+  print "  -S file    import shadow file\n";
+  print "  -M file    import FreeBSD master.passwd\n";
+  print "  -v         displays modified entries to STDOUT\n";
+  print "  -n         do everything execpt updating LDAP\n";
+  print "  -d obj_nam delete and add (not just update) existing entry in LDAP\n";
+  print "  -a         adds sambaSamAccount objectClass\n";  
+  exit (1);
+}
+
+my $INFILE = undef;
+my %shadowUsers;
+
+if ( $Options{'M'} ) {
+  open($INFILE,$Options{'M'}) or
+    die "I cannot open file: " . $Options{'M'} . "\n";
+} elsif ( $Options{'P'} ) {
+  open($INFILE,$Options{'P'}) or
+    die "I cannot open file: " . $Options{'P'} . "\n";
+  # if defined -S option also read shadow file
+  if ( $Options{'S'} ) {
+    %shadowUsers = read_shadow_file($Options{'S'});
+    (%shadowUsers) or ( close($INFILE) and 
+                        die "I cannot open file: " . $Options{'S'} . "\n" ); 
+  }
+} elsif ( $Options{'S'} ) {
+  open($INFILE,$Options{'S'}) or
+    die "I cannot open file: " . $Options{'S'} . "\n";
+}
+
+my $ldap_master=connect_ldap_master();
+
+while ( my $line=<$INFILE> ) {
+  chop($line);
+  next if ( $line =~ /^\s*$/ ); # whitespace
+  next if ( $line =~ /^#/ );
+  next if ( $line =~ /^\+/ );
+  my $entry = undef;
+  if ($Options{'M'}) {
+    my($user,$pwd,$uid,$gid,$class,$change,$expire,$gecos,$homedir,$shell) = split(/:/,$line);
+    # if user is not in LDAP new entry will be created
+    $entry = get_user_entry($ldap_master,$user);
+    $entry = migrate_user($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell);
+    # for master.passwd file (nss_ldap)
+    if ($entry) {
+      my @objectClass = $entry->get_value( 'objectClass' );
+      $entry->replace( 'objectClass' => [add_to_tab(\@objectClass,'shadowAccount')] );
+    }
+  } elsif ($Options{'P'}) {
+    my($user,$pwd,$uid,$gid,$gecos,$homedir,$shell) = split(/:/,$line);
+    # if user is not in LDAP new entry will be created
+    $entry = get_user_entry($ldap_master,$user);
+    $entry = migrate_user($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell,undef);
+               
+    # should I delete next functionality
+    # add shadow entries if also -S defined
+    if ($Options{'S'} and $shadowUsers{$user}) {
+      my($user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag) = split(/:/,$shadowUsers{$user});
+      $entry = migrate_shadow_user($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag);
+    }
+  } elsif ($Options{'S'}) {
+    my($user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag)=split(/:/,$line);
+    # if user is not in LDAP new entry will be created
+    $entry = get_user_entry($ldap_master,$user);
+    $entry = migrate_shadow_user($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag);
+  }
+
+  if ($entry) {
+    # objectClass $Options{'d'} will be removed
+    # from entry if it exists
+    if ($Options{'d'}) {
+      my @objectClass = $entry->get_value( 'objectClass' );
+      $entry->replace( 'objectClass' => [del_from_tab(\@objectClass,$Options{'d'})] );
+      #$entry->delete( 'objectClass' => [ $Options{'d'} ] );
+    }
+    # if used "-a" and sambaSamAccount doesn't exist.
+    if ( $Options{'a'} and !exist_in_tab([$entry->get_value('objectClass')],'sambaSamAccount') ) {
+      my @objectClass = $entry->get_value( 'objectClass' );
+      $entry->replace( 'objectclass' => [add_to_tab(\@objectClass,'sambaSamAccount')] );
+                       
+      # the below part comes from smbldap-useradd and
+      # maybe it should be replaced by a new subroutine.
+      my $userUidNumber = $entry->get_value('uidNumber');
+      # as rid we use 2 * uid + 1000
+      my $userRid = 2 * $userUidNumber + 1000;
+      # let's test if this SID already exist
+      my $user_sid = "$config{SID}-$userRid";
+      my $test_exist_sid = does_sid_exist($user_sid,$config{usersdn});
+      if ($test_exist_sid->count == 1) {
+       print "User SID already owned by\n";
+                               # there should not exist more than one entry, but ...
+       foreach my $entry ($test_exist_sid->all_entries) {
+         my $dn= $entry->dn;
+         chomp($dn);
+         print "$dn\n";
+       }
+      } else {
+       $entry->replace( 'sambaSID' => $user_sid );
+      }
+    }
+    if ($Options{'v'}) {
+      $entry->dump();
+    }
+    if (!$Options{'n'}) {
+      my $mesg;
+      if ( $Options{'d'} ) {
+                               # delete entry from LDAP if it exists
+       $mesg = $ldap_master->search( base => $entry->dn(),
+                                     scope => 'sub',
+                                     filter => '(objectClass=*)'
+                                   );
+       if ( $mesg->count() == 1 ) {
+         $mesg = $ldap_master->delete($entry->dn());
+         if ($mesg->is_error()) {
+           print "Error: " . $mesg->error() . "\n";
+         }
+         $entry->changetype('add');
+       }
+      }
+      $mesg = $entry->update($ldap_master);
+      if ($mesg->is_error()) {
+       print "Error: " . $mesg->error() . "\n";
+      }
+    }
+  }
+}
+
+$INFILE and close($INFILE);
+# take down the session
+$ldap_master and $ldap_master->unbind;
+
+# returns updated $entry
+sub migrate_user
+  {
+    my($entry,$user,$pwd,$uid,$gid,$gecos,$homedir,$shell) = @_;
+    my($name,$office,$wphone,$hphone)=split(/,/,$gecos);
+    my($cn);
+       
+    # posixAccount MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+    my @objectClass = $entry->get_value( 'objectClass' );
+    @objectClass = add_to_tab(\@objectClass,'posixAccount');
+    @objectClass = add_to_tab(\@objectClass,'inetOrgPerson');
+    $entry->replace( 'objectClass' => \@objectClass );
+
+    $entry->replace( 'uid' => $user );
+    if ($name) {
+      $cn = $name;
+    } else {
+      $cn = $user;
+    }
+    $entry->replace( 'cn' => $cn );
+    # perhaps I should delete it
+    if ( exist_in_tab(\@objectClass,'inetOrgPerson') ) {
+      # 'sn' is required by person objectClass from core.schema
+      my @tmp = split(/\s+/,$cn);
+      my $sn = $tmp[$#tmp];
+      $entry->replace( 'sn' => $sn );
+      # perhaps 'telephoneNumber' 'roomNumber' 'homePhone' 
+      # and 'givenName' also should be modified ???????
+    }
+    ($pwd)       and $entry->replace( 'userPassword'  => "{crypt}" . $pwd );
+    ($uid ne "") and $entry->replace( 'uidNumber'     => $uid );
+    ($gid ne "") and $entry->replace( 'gidNumber'     => $gid );
+    ($gecos)     and $entry->replace( 'gecos'         => $gecos );
+    ($homedir)   and $entry->replace( 'homeDirectory' => $homedir );
+    ($shell)     and $entry->replace( 'loginShell'    => $shell );
+
+    return $entry;
+  }
+
+# returns updated $entry
+sub migrate_shadow_user
+  {
+    my($entry,$user,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag) = @_;
+       
+    # shadowAccount MUST uid
+    my @objectClass = $entry->get_value( 'objectClass' );
+    # if the entry doesn't exist, it needs structural objectclass
+    (@objectClass) or push(@objectClass,'account');
+    $entry->replace( 'objectClass' => [add_to_tab(\@objectClass,'shadowAccount')] );
+       
+    $entry->replace( 'uid' => $user );
+    ($pwd)      and $entry->replace( 'userPassword'     => "{crypt}" . $pwd );
+    ($lastchg)  and $entry->replace( 'shadowLastChange' => $lastchg );
+    ($min)      and $entry->replace( 'shadowMin'        => $min );
+    ($max)      and $entry->replace( 'shadowMax'        => $max );
+    ($warn)     and $entry->replace( 'shadowWarning'    => $warn );
+    ($inactive) and $entry->replace( 'shadowInactive'   => $inactive );
+    ($expire)   and $entry->replace( 'shadowExpire'     => $expire );
+    ($flag)     and $entry->replace( 'shadowFlag'       => $flag );
+       
+    return $entry;
+  }
+
+# creates a _new_entry_ if user doesn't exist in ldap
+# else return's ldap user entry
+sub get_user_entry
+  {
+    my($ldap_master,$user) = @_;
+       
+    # do not use read_user_entry()
+    my $mesg = $ldap_master->search( base => $config{usersdn},
+                                    scope => 'one',
+                                    filter => "(uid=$user)"
+                                  );
+    my $entry;
+    if ( $mesg->count() != 1 ) {
+      $entry = Net::LDAP::Entry->new();
+      $entry->dn("uid=$user,$config{usersdn}");
+    } else {
+      $entry = $mesg->entry(0); # ????
+    }
+    return $entry;
+  }
+
+# Check if a $text element exists in @table
+# eg. exist_in_tab(\@table,$text);
+sub exist_in_tab
+  {
+    my($ref_tab,$text) = @_;
+    my @tab = @$ref_tab;
+
+    foreach my $elem (@tab) {
+      if ( lc($elem) eq lc($text) ) {
+       return 1;
+      }
+    }
+    return 0;
+  }
+
+# Delete $text element from @table
+# eg. del_from_tab(\@table,$text);
+sub del_from_tab
+  {
+    my($ref_tab,$text) = @_;
+    my @tab = @$ref_tab;
+    my @new_tab;
+               
+    foreach my $elem (@tab) {
+      if ( lc($elem) ne lc($text) ) {
+       push(@new_tab,$elem);
+      }
+    }
+    return @new_tab;
+  }
+
+# Add $text to tab if it doesn't exist there
+sub add_to_tab
+  {
+    my($ref_tab,$text) = @_;
+    my @tab = @$ref_tab;
+       
+    if ( !exist_in_tab(\@tab,$text) ) {
+      push(@tab,$text);
+    }
+    return @tab;
+  }
+
+# reads shadow file entries and places them in a hash
+sub read_shadow_file
+  {
+    my($shadow) = @_;
+
+    my $shadowUser;
+    my %shadowUsers;
+    open(SHADOW,$shadow) or
+      return ;
+    while (my $line=<SHADOW>) {
+      chop($line);
+      next if ( $line =~ /^\s*$/ ); # whitespace
+      next if ( $line =~ /^#/ );
+      ($shadowUser) = split(/:/, $line);
+      $shadowUsers{$shadowUser} = $line;
+    }
+    close(SHADOW);
+    return %shadowUsers;
+  }
+
+########################################
+
+=head1 NAME
+
+smbldap-migrate-unix-accounts - Migrate unix accounts to LDAP
+
+=head1 SYNOPSIS
+
+smbldap-migrate-unix-accounts [-P file] [-S file] [-M file] [-n] [-v]
+[-h] [-?] [-d]
+
+=head1 DESCRIPTION
+
+This command processes one file as defined by option and
+creates new or changes existing ldap user entry.
+New attributes are added, and existing are changed.
+None of the existing attributes is deleted.
+
+-P passwd_file
+       Processes passwd_file and uptades LDAP. Creates new ldap user
+       entry or just adds posixAccount objectclass and corresponding
+       attributes to the ldap user entry or just uptades their values.
+
+-S shadow_file
+       Reads shadow_file and uptades LDAP. Creates new ldap user
+       entry or just adds shadowAccount objectclass and corresponding
+       attributes to the ldap user entry or just uptades their values.
+
+-M master.passwd_file
+       Reads master.passwd_file and uptades LDAP. Creates new ldap user
+       entry or just adds shadowAccount and posixAccount objectclass
+       and corresponding attributes to the ldap user entry or just 
+       uptades their values.
+
+-h     show the help message
+
+-?     the same as -h
+
+-v     displayes modified entries to STDOUT
+
+-n     do everything execpt updating LDAP. It is useful when used
+       with -v switch.
+
+-d objeClass_name
+       In spite of just updating existing user entry, the entry will be 
+       deleted from LDAP and a new one will be added.
+       It is essential to use this option if you update users in LDAP
+       and want to change their structural objectClass. 
+       Use it in the example schema:
+       There are no users in LDAP, and you migrate samba first.
+       # pdbedit -e ldapsam:ldap://localhost
+       # smbldap-migrate-passwd -P passwd -d 'account'
+
+-a     adds sambaSamAccount objectClass and generates sambaSID attribute
+
+=cut
+
+#'
+
+# The End
+
+