#!/usr/bin/perl -w use strict; ##### # ldapuseradd # Reguires Net::LDAP (http://perl-ldap.sourceforge.net). # Requires at least the core, nis and inetorgperson schemata on the server side. # TODO: Perform more sanity checking ;) Replace calls to system(). # huw@munted.org ######################################################################### use Net::LDAP qw(:all); use Net::LDAP::Util qw(ldap_error_name ldap_error_text); use Getopt::Long; use Pod::Usage; # the base ou of your users my $base = "ou=People,dc=example,dc=com"; my $binddn = "uid=$binduser,$base"; # you ldap server my $ldapserver = "myldapserver.example.com"; # the upper and lower bounds of (u|g)ids for new users my %id_ranges = (uidNumbermin => 1000, uidNumbermax => 1500, gidNumbermin => 1000, gidNumbermax => 1500, ); my %opts; GetOptions (\%opts, 'username=s', 'forname=s', 'surname=s', 'email=s', 'loginshell=s', 'help', 'binduser=s'); $opts{loginshell} = '/bin/bash' if !$opts{loginshell}; $opts{username} = $opts{forname} if !$opts{username}; die `perldoc $0` if $opts{help}; die pod2usage(1) if !$opts{username} || !$opts{binduser} || !$opts{forname} || !$opts{surname} || !$opts{email} system "stty -echo"; print "Please enter your bind password: "; my $bindpw; chop($bindpw = ); print "\n"; system "stty echo"; my $ldaph = ldap_bind($ldapserver); my $exists = doiexist($opts{username}); die "This username is in use. Please specify another and try again\n" if $exists; my $uidNumber = getId('uidNumber'); my $gidNumber = getId('gidNumber'); create('user'); create('group'); $exists = doiexist($opts{username}); my $invoking_user = getpwuid($<); if ($exists) { print "Account created\n"; print "You will now need to create the new users homedirectory and set their password.\n"; exit 0; } exit 1; ################################ ### Main program flow ends here. ################################ sub create { my ($type) = @_; my ($newuservars,$newdn); if ($type eq "user") { my $homedir = "/home/$opts{username}"; $newuservars = [ objectClass => ["top","account","posixAccount","shadowAccount","person","organizationalPerson","inetOrgPerson","trustAccount"], uid => $opts{username}, gidNumber => $gidNumber, uidNumber => $uidNumber, givenName => $opts{forname}, sn => $opts{surname}, cn => $opts{username}, gecos => $opts{username}, loginShell => $opts{loginshell}, homeDirectory => $homedir, mail => $opts{email}, trustModel => "fullaccess" ]; $newdn = "uid=$opts{username},$base"; } if ($type eq "group") { $newuservars = [ objectClass => ["top","posixGroup"], cn => $opts{username}, gidNumber => $gidNumber ]; $newdn = "cn=$opts{username},$base"; } my $result = $ldaph->add($newdn, attrs => [ @$newuservars ]); ldap_error($result) if $result->code; } sub ldap_error { my ($mesg) = @_; print "Return code : ",$mesg->code; print "\tMessage: ", ldap_error_name($mesg->code); print " :", ldap_error_text($mesg->code); print "MessageID: ",$mesg->mesg_id; print "\tDN: ",$mesg->dn; } sub getId { my ($type) = @_; my @attribs = ($type); my $results = search(\@attribs,$type); my @values; for my $result ($results->entries) { push @values,($result->get_value($type)) if (($result->get_value($type) >= $id_ranges{$type."min"}) && ($result->get_value($type) <= $id_ranges{$type."max"})); } my @sorted_values = sort {$a <=> $b} @values; my $val = pop @sorted_values; $val++; return $val if $val <= $id_ranges{$type."max"}; die "You have reached the maximum number of $type. Please increase the maximum range\n"; } sub doiexist { my ($username) = @_; my @search_attributes = qw(uid); my $filter = 'uid'; my $exists = search(\@search_attributes,$filter); for my $result ($exists->entries) { my $uid = $result->get_value('uid'); return 1 if ($username eq $uid); } } sub search { my ($attrs,$filter) = @_; my $result = $ldaph->search (base => $base, scope => "sub", filter => "$filter=*", attrs => $attrs ); if ($result->code) { ldap_error($result); } return $result; } sub ldap_bind { my ($ldapserver) = @_; my $ldap = Net::LDAP->new($ldapserver); $ldap->bind ( dn => $binddn, password => $bindpw ) || die "$@"; return $ldap; } __END__ =head1 NAME ldapuseradd =head1 SYNOPSIS ldapuseradd -option [parameter] =head1 OPTIONS Option Parameter/Notes -username Username for the new user -forname Forename (will be used as the username is no username specified) -surname Surname -email Email address -loginshell Loginshell (If not specified will default to /bin/bash) -binduser User to bind to the server as -help Help (with examples) [boolean] =head1 Notes Not all fields are mandatory. Example 1 shows the minimum fields required for a user. =head1 Examples 1) ldapuseradd -forname huw -surname selley -email huw@munted.org -binduser "uid=huw,ou=People,dc=example,dc=com" Create a user. =head1 BUGS Please report all bugs to the author. =head1 CREDITS Written by Huw Selley (huw@munted.org). =cut