#!/usr/bin/perl # # Script to populate LDAP server to support # nss_ldap and pam_ldap clients. # # Name: GuruLabs.com LDAP migrate script # Version: 0.83 # Copyright 2003 Dax Kelson 2003 # # This program is free software; you can redistribute it and/or # modify it under the terms of the latest version of the GNU # General Public License as published by the Free Software # Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # http://www.gnu.org/licenses/gpl.txt use strict; use Getopt::Long; use Net::LDAP; Getopt::Long::Configure ("bundling"); # All that is really needed my @containers = ('People', 'Group', 'Mounts'); # There is an outside chance you may need these my @extcontainers = ('Protocols', 'Services' ,'Netgroup'); my $container; my $dc; my $ldap; my $result; my $dbcount; my %Users; my %ShadowFile; my %Groups; # Defaults for command line options my $debug = 0; my $quiet = 0; my $basedn = ''; my $password = ''; my $binddn = ''; my $host = "127.0.0.1"; my $secure = 0; my $database = ''; my $file = ''; my $help = 0; my $prepdb = 0; my $extconts = 0; my $minuid = 500; my $maxuid = 65500; my $extschema = 0; my $usage = 0; GetOptions ('v' => \$debug, 'quiet' => \$quiet, 'pass|w=s' => \$password, 'basedn|b=s' => \$basedn, 'host|h|=s' => \$host, 'binddn|D=s' => \$binddn, 'help|?' => \$help, 'file|f=s' => \$file, 'Z' => \$secure, '<>' => \&process, 'prepdb|P' => \$prepdb, 'extconts' => \$extconts, 'extschema' => \$extschema, 'usage' => \$usage, 'minuid=i' => \$minuid, 'maxuid=i' => \$maxuid, 'mingid=i' => \$minuid, 'maxgid=i' => \$maxuid); if ($help == 0 && (($database eq "" && $prepdb == 0) || $usage || ($database ne "" && $file eq ""))) { print <); system("/bin/stty","echo"); } if ($prepdb) { $ldap = Net::LDAP->new("$host", version => 3); $ldap->start_tls("$host") if ($secure); $ldap->bind ( $binddn, password => $password); ($dc) = $basedn =~ /^dc=(.*?),dc=/; $result = $ldap->add ( "$basedn", attr => [ 'dc' => "$dc", 'objectclass' => ['top', 'domain' ], ] ); $result->code && warn "failed to add entry $basedn: ", $result->error; &addcontainers($ldap, $basedn, @containers); if ($extconts) { &addcontainers($ldap, $basedn, @extcontainers); } } if ($database eq 'passwd') { print "Found db=passwd\n" if ($debug); # Populate the %ShadowFile hash &ReadShadowFile; # Populate the %Users hash &ReadPassdFile; # Insert into LDAP &AddPeople; } elsif ($database eq 'group') { print "Found db=group\n" if ($debug); # Populate the %Groups hash &ReadGroupFile; # Insert into LDAP &AddGroups; } elsif ($database eq "") { # --prepdb with no db specified } else { print "Database: $database not supported yet\n"; exit 1; } sub addcontainers { my ($ldap, $basedn, @containers) = @_; my $conainter; my $result; foreach $container (@containers) { $result = $ldap->add ( "ou=$container,$basedn", attr => [ 'ou' => "$container", 'objectclass' => ['top', 'organizationalUnit' ], ] ); $result->code && warn "failed to add entry $container: ", $result->error; } } sub AddPeople { my $ldap; my $result; my $user; $ldap = Net::LDAP->new("$host", version => 3); $ldap->start_tls if ($secure); $ldap->bind ( $binddn, password => $password); foreach $user (sort keys %Users) { print "About to import user: $user\n" if ($debug); $result = $ldap->add ( dn => "uid=$user,ou=People,$basedn", attr => [ %{$Users{$user}} ], ); $result->code && warn "failed to add entry $user: ", $result->error; } } sub process { ($database) = @_; if ($dbcount == 1) { die "ERROR: Only one database can be specified. Run $0 --help\n"; } $dbcount = 1; } sub ReadShadowFile { my $user; open(SHADOW, "/etc/shadow") || warn "WARNING: Unable to open /etc/shadow\n"; while() { next if /^[#\+]/; chop; ($user) = split(/:/); $ShadowFile{$user} = $_; } close(SHADOW); } sub ReadPassdFile { my $pwd; my $lastchg; my $min; my $max; my $warn; my $inactive; my $expire; my $flag; open(PASSWD, "/etc/passwd") || die "FATAL: Unable to open /etc/passwd\n"; while () { next if /^[#\+]/; my($user, $pwd, $uid, $gid, $gecos, $homedir, $shell) = split(/:/); chomp($shell); if ($uid >= $minuid && $uid <= $maxuid) { print "found passwd uid: $uid\n" if ($debug); $Users{$user}{'uid'} = $user; $Users{$user}{'cn'} = $user; $Users{$user}{'uidNumber'} = $uid; $Users{$user}{'gidNumber'} = $gid; $Users{$user}{'gecos'} = $gecos if ($gecos); $Users{$user}{'homeDirectory'} = $homedir if ($homedir); $Users{$user}{'loginShell'} = $shell if ($shell); $Users{$user}{'objectClass'} = ['posixAccount', 'top']; # See if there is a shadow file entry if ( (undef,$pwd,$lastchg,$min,$max,$warn,$inactive,$expire,$flag) = split(/:/, $ShadowFile{$user})) { print "found shadow uid: $uid\n" if ($debug); push(@{$Users{$user}{'objectClass'}}, 'shadowAccount'); $Users{$user}{'userPassword'} = "{crypt}$pwd" if ($pwd); $Users{$user}{'shadowLastChange'} = "$lastchg" if ($lastchg); $Users{$user}{'shadowMin'} = "$min" if ($min); $Users{$user}{'shadowMax'} = "$max" if ($max); $Users{$user}{'shadowWarning'} = "$warn" if ($warn); $Users{$user}{'shadowInactive'} = "$inactive" if ($inactive); $Users{$user}{'shadowExpire'} = "$expire" if ($expire); $Users{$user}{'shadowFlag'} = "$flag" if ($flag); } else { $Users{$user}{'userPassword'} = "{crypt}$pwd"; } if ($extschema) { # If you use extschema, the person objectclass must have # an attribute 'sn'. Try using last name from the gecos field ($Users{$user}{'sn'}) = $gecos =~ /.* (.*)$/ if ($gecos); push(@{$Users{$user}{'objectClass'}},'person'); push(@{$Users{$user}{'objectClass'}},'organizationalPerson'); push(@{$Users{$user}{'objectClass'}},'inetOrgPerson'); } else { push(@{$Users{$user}{'objectClass'}}, 'account'); } } undef $user; undef $pwd; undef $uid; undef $gid; undef $gecos; undef $homedir; undef $shell; undef $lastchg; undef $min; undef $max; undef $warn; undef $inactive; undef $expire; undef $flag; } close(PASSWD); } sub ReadGroupFile { my $user; my @members; my $group; my $pwd; my $gid; my $users; open(GROUP, "/etc/group") || die "FATAL: Unable to open /etc/group\n"; while () { next if /^[#\+]/; ($group, $pwd, $gid, $users) = split(/:/); chomp($users); @members = split(/,/, $users); if ($gid >= $minuid && $gid <= $maxuid) { $Groups{$group}{'cn'} = $group; if ($pwd ne 'x') { $Groups{$group}{'UserPassword'} = "{crypt}$pwd"; } $Groups{$group}{'gidNumber'} = $gid; $Groups{$group}{'objectClass'} = ['posixGroup', 'top']; foreach $user (@members) { push(@{$Groups{$group}{'memberUid'}},"$user"); } } undef $group; undef $pwd; undef $gid; undef $users; } close(GROUP); } sub AddGroups { my $ldap; my $result; my $group; $ldap = Net::LDAP->new("$host", version => 3); $ldap->start_tls if ($secure); $ldap->bind ( $binddn, password => $password); foreach $group (sort keys %Groups) { print "About to import group: $group\n" if ($debug); $result = $ldap->add ( dn => "cn=$group,ou=Group,$basedn", attr => [ %{$Groups{$group}} ], ); $result->code && warn "failed to add entry $group: ", $result->error; } }