#!/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] );
}