#!/usr/bin/perl # Add a new user to and LDAP database, and do other necessary things such as # create the new user's home directory. Some of this script is copied from # Debian's adduser script. Thus, this script is licenced under the GNU GPL. # Author: Nick Barkas # N.B. There is a possibility of a race condition if more than one instance of # this script is being run simultaneously using the same LDAP directory. Both # instances may find the same free UID number before the users are actually # added to LDAP, and hence create two users with the same UID. This would # obviously be bad. use strict; use Net::LDAP; # set some default configuration options my %CONF = ( "dshell" => "/bin/bash", "dhome" => "/home", "dgroup" => "users", "dhost" => "ldap", "first_uid" => 1000, "last_uid" => 29999, # start with lowercase alpha, and allow numbers and - later in name "name_regex" => "^[a-z][-a-z0-9]*\$", # start with /, can contain /, -, and alphanumeric. escape / with \\ here "home_regex" => "^\\/[-\\/a-z0-9]*\$", "server" => "ldap.example.org", "root_dn" => "cn=admin,dc=ldap,dc=example,dc=org", "dn_suffix" => "ou=People,dc=ldap,dc=example,dc=org", "obj_class" => ["account","posixAccount","top","shadowAccount"], ); # make sure the person running this is root unless($< == 0) { die "You cannot add users unless you are root.\n" } # get username print "Enter username: "; chomp(my $user = ); # make sure name given is valid (matches name_regex) if ($user !~ qr/$CONF{"name_regex"}/) { die "Sorry, invalid username.\n" } # make sure username is not in use already if (getpwnam($user)) { die "Sorry, $user is already in use.\n" } # get user's real name, and optional information for gecos print "User's real name: "; chomp(my $name = ); unless ($name) { die "Please enter a name for this user\n" } print "Office: "; chomp(my $office = ); print "Work phone: "; chomp(my $work_phone = ); print "Home phone: "; chomp(my $home_phone = ); print "Other information: "; chomp(my $other = ); my $gecos = $name.",".$office.",".$work_phone.",".$home_phone.",".$other; # get optional parameters from user, or use defaults if nothing is entered print "Login shell [".$CONF{"dshell"}."]: "; chomp(my $shell = ); print "Home directory [".$CONF{"dhome"}."/$user]: "; chomp(my $home = ); print "Login group [".$CONF{"dgroup"}."]: "; chomp(my $group = ); print "Host user allowed to log in to [".$CONF{"dhost"}."]: "; chomp(my $host = ); unless ($shell) { $shell = $CONF{"dshell"} } unless ($home) { $home = $CONF{"dhome"}."/$user" } unless ($group) { $group = $CONF{"dgroup"} } unless ($host) { $host = $CONF{"dhost"} } # make sure homedir given is valid (matches home_regex) if ($home !~ qr/$CONF{"home_regex"}/) { die "Sorry, invalid home directory.\n" } # make sure group given is valid unless (getgrnam($group)) { die "Sorry, $group is not a valid group.\n" } # get the next valid, available uid number my $uid = &first_avail_id($CONF{"first_uid"},$CONF{"last_uid"},&get_current_uids); if ($uid < 0) { die "No more uids available! That's just no good at all\n" } # translate group name into a gid my $gid = (getgrnam($group))[2]; # read administrative ldap password out of /etc/ldap.secret. the password should # be the only line in that file, and should be by itself on the first line. open(PW,")[0]); close(PW); # make ldap bind my $ldap = Net::LDAP->new($CONF{"server"}); my $msg = $ldap->bind($CONF{"root_dn"},password=>$pass); # add the user to ldap db my $res = $ldap->add("uid=$user,".$CONF{"dn_suffix"}, attr => [ "uid" => $user, "cn" => $name, "objectClass" => $CONF{"obj_class"}, "uidNumber" => $uid, "gidNumber" => $gid, "homeDirectory" => $home, "host" => $host, "loginShell" => $shell, "gecos" => $gecos, "userPassword" => "{crypt}x", ] ); $res->code && die "failed to add entry: ", $res->error; # disconnect $msg = $ldap->unbind; # create user's home directory mkdir($home,0755) or die "Can not create $home"; # copy contents from /etc/skel and set all the permissions properly. system("cp -a /etc/skel/* $home/"); system("cp -a /etc/skel/.[!.]* $home/"); system("chown -R $uid:$gid $home"); print < $b} @ids; while ($min <= $max) { return $min if ($min < $ids[0] || @ids==0); shift @ids if ($min > $ids[0]); $min++ if ($min == $ids[0]); } -1; # nothing available }