#!/usr/bin/perl -w # $Id: smbldap-useradd-bulk,v 1.11 2005/01/20 19:39:10 moquist Exp moquist $ ############################################ # smbldap-useradd-bulk # -- Bulk-add users to a Samba/LDAP system using smbldap-tools # # Copyright (C) 2005 SAU16 School District, Exeter, NH # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Matt Oquist # Props to David Trask for his original shell script ############################################ use Getopt::Std; # Randomize... srand; my @badinput = (); my @errors = (); my @dict = (); my $pw_spchr = undef; my $pw_ucchr = undef; my $pw_random = undef; my $min_len = my $max_len = 8; my $default_gid = 513; my $default_password = undef; $ENV{PATH} = "/opt/IDEALX/sbin:$ENV{PATH}"; if (defined $ARGV[0] and $ARGV[0] eq "--help") { &usage; exit; } getopts("cf:g:hil:o:p:"); if (defined($opt_h)) { $opt_h = 1; &usage; exit; } if (defined($opt_i)) { $opt_i = 1; } if (defined($opt_f) && ! -f "$opt_f") { print STDERR "#$0: input file ($opt_f) cannot be found\n"; exit; } elsif ($opt_f) { open INPUT, "<$opt_f"; } else { open INPUT, "<&STDIN"; } if (defined($opt_g)) { $default_gid = $opt_g; } if (defined($opt_o)) { open OUTPUT, ">>$opt_o"; } else { open OUTPUT, ">&STDOUT"; } if (defined($opt_l)) { $opt_p =~ s/[ \t]//g; if ($opt_l !~ /^[0-9]+,[0-9]+$/) { print STDERR "#$0: argument to -l must be in the form min-length,max-length\n"; exit(1); } ($min_len, $max_len) = split /,/, $opt_l; } if (defined($opt_p)) { $opt_p =~ s/[ \t]//g; if ($opt_p =~ /default=([^,]+)/) { $default_password = $1; } else { foreach my $pwopt (split /,/, $opt_p) { if ($pwopt eq "sp") { # turn on special characters $pw_spchr = 1; } elsif ($pwopt eq "uc") { # turn on uppercase characters $pw_ucchr = 1; } elsif ($pwopt eq "random") { # turn on total randomness $pw_random = 1; } else { print STDERR "#$0: -p $pwopt not recognized.\n"; &usage; exit(1); } } } } # The dictionary of password chunks is long and ugly, so set it down # below in a subroutine &set_dict; if (!defined($opt_i)) { # ask the user some stuff if (!defined($opt_g)) { # the user did not pass a -g option, so we should ask about the # default GID print "What GID do you want these users to have by default? [$default_gid] "; chomp (my $new_defgid = readline STDIN); if (length($new_defgid) > 0 and $new_defgid =~ /^[0-9]+$/) { $default_gid = $new_defgid; } } } my $date = localtime; print OUTPUT "\n#################################\n"; print OUTPUT "$date\n"; # read each line of standard input foreach my $line () { # get rid of the newline at the end of our $line chomp $line; # ignore comments if ($line =~ /^[ \t]*#/ or $line !~ /./) { next; } # Delete any whitespace in our $line $line =~ s/[ \t]//g; if ($line !~ /^.+,.+,.+,?.*,?.*$/) { push @badinput, "$line"; next; } # Divide the line into its fields my ($first,$last,$uname,$gid,$shell,$home,$tutor,$password) = split /,/, $line; if (!defined($gid) or length($gid) == 0 or $gid eq "default") { $gid = $default_gid; } if ($gid =~ /[^0-9]/) { push @badinput, "$line ($gid has non-numeric characters)"; next; } if (!defined($password) or length($password) == 0 or $password eq "generate") { if (defined($default_password)) { $password = $default_password; } else { $password = &create_password; } } # Add the user $rc = system("smbldap-useradd -a -m -g $gid -c \"$first $last\" -s $shell -d $home$tutor/$uname $uname"); if ($rc == 0) { # the user was successfully added print OUTPUT "$first,$last,$uname,$gid,$password\n"; if (!defined($opt_i) and defined($opt_o)) { print STDOUT "$first,$last,$uname,$gid,$password\n"; } # Silently change the user's LDAP password # (If we don't redirect stderr into /dev/null, smbldap-passwd # complains.) open PWD, "| smbldap-passwd $uname 2>/dev/null 1>&2"; print PWD "$password\n$password"; close PWD; } else { push @errors, "smbldap-useradd error for $uname: $rc."; if (-d "/$home/$uname") { my (undef,undef,undef,undef,$fuid,$fgid,undef,undef,undef,undef,undef,undef,undef) = stat("/$home/$uname"); my $id = `id $uname`; $id =~ /uid=([0-9]+).*gid=([0-9]+)/; ($uid,$gid) = ($1,$2); if ($uid != $fuid or $gid != $fgid) { push @errors, "ownership of /$home/$uname doesn't match the user/group of $uname"; } } } } if ($#badinput >= 0) { print "The following lines contain errors and were not processed:\n"; foreach my $error (@badinput) { print "$error\n"; } } if ($#errors>= 0) { print "The errors were encountered during processing:\n"; foreach my $error (@errors) { print "$error\n"; } } sub usage() { my $me = $0; print "Usage: $me [-f ] [-o ]\n"; print " [-p { sp,uc,random [ -l min,max ] | default=pass } ]\n"; print " [ -g GID ] [ -i ]\n"; print " -f Use the named file for input.\n"; print " You must either supply this option or pipe your\n"; print " userinfo data into this script.\n"; print " -g Use this group ID for all users without GID in the input.\n"; print " -i This turns OFF interactivity and uses the following default values:\n"; print " GID: $default_gid"; print " -l min,max Set the minimum and maximum password lengths.\n"; print " This argument is only effective if \"-p random\" is passed.\n"; print " -o Use the named file for output.\n"; print " If you don't specify this option, output will print\n"; print " to standard output.\n"; print " -p You must choose at least one of the following options,\n"; print " and multiple selections must be separated by commans:\n"; print " sp: turns on special characters\n"; print " uc: turns on uppercase characters\n"; print " random: turns on complete randomness\n"; print " default=pass: turns off password generation, and sets all\n"; print " blank (or \"generate\") passwords to \"pass\".\n"; print " Each line of your input file must be in this format:\n"; print " Ralph,Walf,rwalf,525,password3\n"; print " In the above example,\n"; print " Ralph = first name\n"; print " Walf = last name\n"; print " rwalf = username\n"; print " 525 = group ID\n"; print " password3 = password\n\n"; print " You may set the password field to \"generate\" (or leave it blank)\n"; print " if you wish for a random password to be generated automatically and\n"; print " printed in the specified output file (or standard outout).\n"; print " Input lines that start with '#' are ignored.\n"; } sub create_password() { my $new_password = undef; if (defined($pw_random)) { while (!$new_password) { # new passwords will have 6> <15 characters $len = (rand $max_len-$min_len) + $min_len + 1; # generate the new random password for (my $i = 2; $i < $len; $i++) { $new_password .= chr ((rand 93) + 33); } $new_password =~ s/[<>\']//g; if (length $new_password < $min_len) { $new_password = undef; } } } else { while (!$new_password) { $p1 = int rand($#dict); $p2 = int rand(89) + 10; $p3 = int rand($#dict); # get rid of zeros and ones; people might confuse them with # letters $p2 =~ s/[01]/2/g; # Get rid of the number 69. # Kids, kids, kids... $p2 =~ s/69/96/g; $new_password = "$dict[$p1]$p2$dict[$p3]"; if ($pw_spchr) { # insert a random symbol my $symbols = '!"#$%^&()*+,-_.:;=?@{}[]'; my $symbol = int (rand length($symbols) - 1); $symbols =~ /.{$symbol,$symbol}(.)/; $symbol = $1; my $pos = int rand (length($new_password)-1); $new_password =~ s/(.{$pos,$pos})./$1$symbol/; } if ($pw_ucchr) { # insert a random uppercase letter my $letter = uc chr ((rand 26) + 65); my $pos = int rand (length($new_password)-1); $new_password =~ s/(.{$pos,$pos})./$1$letter/; if ($new_password !~ /[A-Z]/) { $new_password = undef; } } } } return $new_password; } sub set_dict() { @dict = ("aal","aam","aba","abb","abu","aby","ace","ach","act","add", "ade","ado","ady","adz","aer","aes","aft","aga","age","ago","agy", "aha","aho","ahu","aid","ail","aim","air","ait","aka","ake","ako", "aku","ala","alb","ale","alf","alk","aln","alo","alp","alt","aly", "ama","ame","ami","amt","amy","ana","and","ani","ann","ant","any", "apa","ape","apt","ara","arc","are","ark","arm","arn","art","aru", "arx","ary","ase","ash","ask","asp","ast","ate","auh","auk","aum", "ava","ave","avo","awa","awd","awe","awl","awn","axe","aye","ayu", "azo","baa","bac","bad","bae","bag","bah","bal","bam","ban","bap", "bar","bas","bat","baw","bay","bed","bee","beg","bel","ben","ber", "bes","bet","bey","bib","bid","big","bin","bis","biz","blo","boa", "bob","bod","bog","bom","bon","boo","bop","bor","bot","bow","boy", "bra","bub","bud","bug","bum","bun","bur","bus","but","buy","bye", "cab","cad","cag","cal","cam","can","cap","car","cat","caw","cay", "cee","cep","cha","che","chi","cho","cig","cit","cly","cob","cod", "coe","cog","col","con","coo","cop","cor","cos","cot","cow", "coy","coz","cro","cry","cub","cud","cue","cup","cur","cut", "cwm","cyp","dab","dad","dae","dag","dah","dak","dal","dan", "dao","dap","dar","das","daw","day","deb","dee","deg","den","dev", "dew","dey","dha","dhu","dib","did","die","dig","dim","din","dip", "dis","dit","div","dob","doc","dod","doe","dog","dom","don","dop", "dor","dos","dot","dow","dry","dub","dud","due","dug","dum","dun", "duo","dup","dux","dye","ean","ear","eat","ebb","edh","eel","eer", "eft","egg","ego","eke","elb","eld","elf","elk","ell","elm","els", "elt","eme","emu","end","ens","eon","era","erd","ere","erg","err", "ers","ess","eta","eve","ewe","eye","eyn","fad","fae","fam", "fan","far","fay","fed","fee","fei","fen","fet","feu","few", "fey","fez","fib","fid","fie","fig","fin","fip","fir","fit","fix", "flu","fly","fob","fod","foe","fog","foo","fop","for","fot","fou", "fow","fox","foy","fra","fro","fry","fub","fud","fum","fun","fur", "fut","gab","gad","gag","gaj","gal","gam","gan","gap","gar","gas", "gat","gau","gaw","gaz","ged","gee","gel","gem","gen","geo", "ger","get","gey","gez","gib","gid","gie","gif","gig","gim","gin", "gio","gip","git","gnu","goa","gob","gog","goi","gol","gon", "goo","gor","gos","got","goy","gra","grr","gud","gue","gul","gum", "gun","gup","gur","gut","guy","guz","gym","gyn","gyp","had","hag", "hah","hak","ham","han","hao","hap","hat","hau","haw","hay","hei", "hem","hen","hep","her","het","hew","hex","hey","hia","hic","hie", "him","hin","hip","his","hit","hob","hod","hog","hoi","hop", "toh","how","hox","hoy","hub","hud","hue","hug","huh","hum","hup", "hut","hyp","iao","iba","ice","ich","icy","ide","ife","ihi","ilk", "ill","imi","imp","imu","ing","ink","inn","ion","ire","irk","ism", "iso","ist","its","iva","ivy","iwa","iyo","jab","jag","jam", "jar","jaw","jay","jed","jet","jib","jig","job","joe","jog","jot", "jow","joy","jud","jut","kai","kan","kat","kay","kea","keb", "ked","kef","keg","ken","kep","ket","kex","key","khu","kil","kim", "kin","kip","kit","koa","kob","koi","kon","kop","kor","kos","kou", "kra","kyl","lab","lac","lad","lag","lai","lak","lam","lan","lap", "lar","las","lat","law","lax","lay","lea","led","lee","leg","lei", "lek","let","leu","lev","lew","ley","lid","lie","lim","lin","lip", "lis","lit","loa","lob","lod","lof","log","loo","lop","lot","low", "lox","loy","lue","lug","lum","lut","lux","lye","lys","mac","mad", "mae","mag","mal","man","mao","map","mar","mas","mat","mau","maw", "may","mel","mem","men","met","mew","mho","mib","mid","mig","mil", "mim","min","mir","mix","mob","mog","mon","moo","mop","mor","mot", "mou","mow","moy","mud","mug","mum","mun","mux","naa","nab","nae", "nag","nak","nam","nan","nap","nar","nat","naw","nay","nea","neb", "nee","nef","nei","neo","nep","net","new","nib","nid","nig","nil", "nim","nip","nit","nix","noa","nob","nod","nog","non","nor","not", "now","noy","nth","nub","nul","nun","nut","nye","oaf","oak","oam", "oar","oat","obe","obi","och","ock","oda","odd","ode","oer","oes", "off","oft","ohm","oho","oii","oil","oka","oki","old","olm","ona", "one","ons","ope","opt","ora","orb","orc","ore","orf","ort","ory", "ose","ouf","our","out","ova","owd","owe","owk","owl","own","oxy", "pac","pad","pah","pal","pam","pan","pap","par","pat","pau","paw", "pax","pay","pea","ped","peg","pen","pep","per","pes","pet", "pew","phi","pho","phu","pia","pic","pie","pig","pik","pin","pip", "pir","pit","pix","ply","pob","pod","poe","poh","poi","pol","pom", "pon","pop","pot","pow","pox","poy","pro","pry","psi","pst","pua", "pub","pud","pug","pul","pun","pup","pur","put","pya","pyr","pyx", "qua","quo","rab","rad","rag","rah","raj","ram","ran","rap","ras", "rat","raw","rax","ray","rea","reb","red","ree","ref","reg","reh", "rel","rep","ret","rev","rex","rhe","rho","ria","rib","rid","rie", "rig","rim","rio","rip","rit","rix","rob","roc","rod","roe","rog", "roi","rot","row","rox","rub","rud","rue","rug","rum","run","rut", "rux","rye","saa","sab","sac","sad","sag","sah","sai","saj","sal", "sam","san","sao","sap","sar","sat","saw","sax","say","sea","sec", "see","seg","sen","ser","set","sew","sey","sha","she","shi","sho", "shy","sib","sic","sie","sig","sil","sin","sip","sir","sis","sit", "six","ski","sky","sla","sly","sma","sny","sob","soc","sod","soe", "sog","soh","sok","sol","son","sop","sot","sou","sov","sow","soy", "spa","spy","sri","ssu","sty","sub","sud","sue","sum","sun","sup", "sur","suz","swa","sye","taa","tab","tad","tae","tag","tai","taj", "tal","tam","tan","tao","tap","tar","tat","tau","tav","taw","tax", "tay","tch","tck","tea","tec","ted","tee","teg","ten","tew","tez", "tha","the","tho","thy","tib","tic","tid","tie","tig","til","tin", "tip","tji","toa","tod","toe","tog","toi","tol","ton","too","top", "tor","tot","tou","tow","tox","toy","tra","tri","try","tst","tua", "tub","tue","tug","tui","tum","tun","tup","tur","tut","tux","twa", "two","tye","tyg","ubi","udo","ugh","uji","uke","ula","ule", "ull","ulu","ume","ump","umu","upo","ura","urd","ure","urf","urn", "use","ush","ust","uta","utu","uva","vag","van","vas","vat","vau", "vee","vei","vet","vex","via","vie","vim","vis","voe","vog","vol", "vow","vug","vum","wab","wad","wae","wag","wah","wan","wap","war", "was","wat","waw","wax","way","web","wed","wee","wem","wen","wer", "wey","wha","who","why","wid","wig","wim","win","wir","wis", "wit","wiz","wob","wod","woe","wog","won","woo","wop","wot","wow", "woy","wro","wry","wud","wun","wup","wur","wut","wye","wyn","yad", "yah","yak","yam","yan","yap","yar","yas","yat","yaw","yea","yed", "yee","yen","yeo","yep","yer","yes","yet","yew","yex","yez","yin", "yip","yis","yoe","yoi","yok","yom","yon","yor","yot","you","yow", "yox","yoy","yuh","yus","zac","zad","zag","zak","zar","zat","zax", "zed","zee","zel","zer","zig","zip","zoa","zoo"); }