#!/depot/path/expect -- # mkpasswd - make a password, if username given, set it. # Author: Don Libes, NIST # defaults set length 9 set minnum 2 set minlower 2 set minupper 2 set verbose 0 set distribute 0 if [file executable /bin/yppasswd] { set defaultprog /bin/yppasswd } elseif [file executable /bin/passwd] { set defaultprog /bin/passwd } else { set defaultprog passwd } set prog $defaultprog while {[llength $argv]>0} { set flag [lindex $argv 0] switch -- $flag \ "-l" { set length [lindex $argv 1] set argv [lrange $argv 2 end] } "-d" { set minnum [lindex $argv 1] set argv [lrange $argv 2 end] } "-c" { set minlower [lindex $argv 1] set argv [lrange $argv 2 end] } "-C" { set minupper [lindex $argv 1] set argv [lrange $argv 2 end] } "-v" { set verbose 1 set argv [lrange $argv 1 end] } "-p" { set prog [lindex $argv 1] set argv [lrange $argv 2 end] } "-2" { set distribute 1 set argv [lrange $argv 1 end] } default { set user [lindex $argv 0] set argv [lrange $argv 1 end] break } } if {[llength $argv]} { puts "usage: mkpasswd \[args] \[user]" puts " where arguments are:" puts " -l # (length of password, default = $length)" puts " -d # (min # of digits, default = $minnum)" puts " -c # (min # of lowercase chars, default = $minlower)" puts " -C # (min # of uppercase chars, default = $minupper)" puts " -v (verbose, show passwd interaction)" puts " -p prog (program to set password, default = $defaultprog)" exit 1 } if {$minnum + $minlower + $minupper > $length} { puts "impossible to generate $length-character password\ with $minnum numbers, $minlower lowercase letters,\ and $minupper uppercase letters" exit 1 } # if there is any underspecification, use additional lowercase letters set minlower [expr $length - ($minnum + $minupper)] set lpass "" ;# password chars typed by left hand set rpass "" ;# password chars typed by right hand # insert char into password at a random position proc insert {pvar char} { upvar $pvar p set p [linsert $p [rand [expr 1+[llength $p]]] $char] } set _ran [pid] proc rand {m} { global _ran set period 259200 set _ran [expr ($_ran*7141 + 54773) % $period] expr int($m*($_ran/double($period))) } # choose left or right starting hand set initially_left [set isleft [rand 2]] # given a size, distribute between left and right hands # taking into account where we left off proc psplit {max lvar rvar} { upvar $lvar left $rvar right global isleft if {$isleft} { set right [expr $max/2] set left [expr $max-$right] set isleft [expr !($max%2)] } else { set left [expr $max/2] set right [expr $max-$left] set isleft [expr $max%2] } } if {$distribute} { set lkeys {q w e r t a s d f g z x c v b} set rkeys {y u i o p h j k l n m} set lnums {1 2 3 4 5 6} set rnums {7 8 9 0} } else { set lkeys {a b c d e f g h i j k l m n o p q r s t u v w x y z} set rkeys {a b c d e f g h i j k l m n o p q r s t u v w x y z} set lnums {0 1 2 3 4 5 6 7 8 9} set rnums {0 1 2 3 4 5 6 7 8 9} } set lkeys_length [llength $lkeys] set rkeys_length [llength $rkeys] set lnums_length [llength $lnums] set rnums_length [llength $rnums] psplit $minnum left right for {set i 0} {$i<$left} {incr i} { insert lpass [lindex $lnums [rand $lnums_length]] } for {set i 0} {$i<$right} {incr i} { insert rpass [lindex $rnums [rand $rnums_length]] } psplit $minlower left right for {set i 0} {$i<$left} {incr i} { insert lpass [lindex $lkeys [rand $lkeys_length]] } for {set i 0} {$i<$right} {incr i} { insert rpass [lindex $rkeys [rand $rkeys_length]] } psplit $minupper left right for {set i 0} {$i<$left} {incr i} { insert lpass [string toupper [lindex $lkeys [rand $lkeys_length]]] } for {set i 0} {$i<$right} {incr i} { insert rpass [string toupper [lindex $rkeys [rand $rkeys_length]]] } # merge results together if {$initially_left} { regexp "(\[^ ]*) *(.*)" "$lpass" x password lpass while {[llength $lpass]} { regexp "(\[^ ]*) *(.*)" "$password$rpass" x password rpass regexp "(\[^ ]*) *(.*)" "$password$lpass" x password lpass } if {[llength $rpass]} { append password $rpass } } else { regexp "(\[^ ]*) *(.*)" "$rpass" x password rpass while {[llength $rpass]} { regexp "(\[^ ]*) *(.*)" "$password$lpass" x password lpass regexp "(\[^ ]*) *(.*)" "$password$rpass" x password rpass } if {[llength $lpass]} { append password $lpass } } if {[info exists user]} { if {!$verbose} { log_user 0 } spawn $prog $user expect { "assword*:" { # some systems say "Password (again):" send "$password\r" exp_continue } } # if user isn't watching, check status if {!$verbose} { if {[lindex [wait] 3]} { puts -nonewline "$expect_out(buffer)" exit 1 } } } if {$verbose} { puts -nonewline "password for $user is " } puts "$password"