#!/usr/bin/perl use warnings; use strict; use utf8; use Text::Unidecode; use Encode; #### # Coded by Daenyth # Daenyth@gmail.com ## checkusage(); #### # Configuration # # dauser is the Open Directory Administrator account, eg diradmin # dapass should not be set (storing passwords in plaintext is bad), but undef can be replaced by the quoted password if you really need to # startuid is the UniqueID to start checking at. In other words, what is the _lowest_ UID you want to use. # ldap is the source we are adding users to # If verbose is on, print a list of successfully added users (to STDOUT) ## my $dauser= 'diradmin'; my $ldap = '/LDAPv3/127.0.0.1'; my $dapass = getpass() || undef; my $startuid = 20000; my $verbose = 1; #### # Was the program invoked correctly? ## sub checkusage { if (@ARGV != 1) { usage() } if ($ARGV[0] =~ /^-+[h?]/) { usage() } } sub usage { print "Usage: $0 \n"; exit 1; } #### # Make a list of users to add, based on CLI input # return AoA, with form of # $return = [ ["Full Name", "password", age], [], ] ## sub getlist { my @userlist; my $infile = shift @ARGV; open(INFILE, "< $infile") or die "$!\n"; local $/ = "\r"; while (my $line = ) { chomp $line; if ($line =~ /^(.+?)\t(.+?)\t(\S+)\t(\d\d\.\d+)$/) { push( @userlist, ["$1 $2", "$3", $4] ); } else { print STDERR "Couldn't match regex to line $. from $infile\n"; } } close INFILE or die "Couldn't close input file: $? $!\n"; return @userlist; } #### # Ask for the admin password ## sub getpass { print "Please enter the password for '$dauser' at '$ldap': "; my $stty_orig=`stty -g`; system "stty -echo"; my $pass = ; chomp $pass; system "stty $stty_orig"; print "\n"; return $pass; } #### # Find the next available UID and return it ## sub finduid { for (my $testuid = $startuid; $testuid < 65535; $testuid++) { if (0 == `dscl '$ldap' -search /Users UniqueID '$testuid' | wc -l`) { return $testuid; } } die "Cannot find a usable UniqueID between $startuid and 65535!\n"; } #### # Check for user conflicts. # If there is a conflict, call faileduser() to note it # Returns 0 = No conflicts found # 1+ = Number of conflicts found ## sub checkuser { my ($shortname, $longname) = @_; my $fails = 0; if ('' eq "$shortname") { faileduser(@_, 'null shortname', ++$fails) } if ('' eq "$longname") { faileduser(@_, 'null longname', ++$fails) } if (0 != `dscl '$ldap' -search /Users RecordName '$shortname' | wc -l`) { faileduser(@_, 'shortname already exists', ++$fails) } if (0 != `dscl '$ldap' -search /Users RealName '$longname' | wc -l`) { faileduser(@_, 'longname already exists', ++$fails) } return $fails; } #### # Call this sub to note an error adding a user ## sub faileduser { my ($shortname, $longname, $failtype, $fails) = @_; print STDERR "ERROR: ['$longname' ('$shortname') $fails] $failtype\n"; return 0; #OK } #### # The main part of the program, adds a user to the Open Directory Database ## sub adduser { my ($longname, $password, $age) = @_; $longname = decode("MacRoman", $longname); my $shortname = shortdecode("$longname"); my $group = ($age > (30-1/12)) ? 'execs' : 'mainlab'; my $uid = finduid(); return 1 if checkuser("$shortname", "$longname"); system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname'"; system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname' RealName '$longname'"; system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname' UniqueID '$uid'" ; system "dscl -u '$dauser' -P '$dapass' '$ldap' -passwd '/Users/$shortname' '$password'" ; system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname' NFSHomeDirectory '/Network/Servers/executive.nese.com/Library/NESE_Accounts/$shortname'" ; system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname' UserShell '/bin/bash'"; system "dscl -u '$dauser' -P '$dapass' '$ldap' -create '/Users/$shortname' PrimaryGroupID 20" ; system "dscl -u '$dauser' -P '$dapass' '$ldap' -append '/Groups/$group' GroupMembership '$shortname'"; print "OK: $longname ($shortname)\n" if $verbose; return 0; #OK } #### # Take the potentially-unicode long name, and turn it into something we can use for a shortname ## sub shortdecode { local $_ = shift; s/\s//g; s/\x{8e}/e/; s/-//; $_ = unidecode("$_"); return lc $_; } my @addusers = getlist(); for (my $i=0; $i<@addusers; $i++) { adduser( "$addusers[$i]->[0]", "$addusers[$i]->[1]", $addusers[$i]->[2] ); }