Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | #!/bin/sh |
2 | # \ | |
3 | exec expect -- "$0" ${1+"$@"} | |
4 | # mkpasswd - make a password, if username given, set it. | |
5 | # Author: Don Libes, NIST | |
6 | ||
7 | # defaults | |
8 | set length 9 | |
9 | set minnum 2 | |
10 | set minlower 2 | |
11 | set minupper 2 | |
12 | set minspecial 1 | |
13 | set verbose 0 | |
14 | set distribute 0 | |
15 | ||
16 | if {[file executable /bin/nispasswd]} { | |
17 | set defaultprog /bin/nispasswd | |
18 | } elseif {[file executable /bin/yppasswd]} { | |
19 | set defaultprog /bin/yppasswd | |
20 | } elseif {[file executable /bin/passwd]} { | |
21 | set defaultprog /bin/passwd | |
22 | } else { | |
23 | set defaultprog passwd | |
24 | } | |
25 | set prog $defaultprog | |
26 | ||
27 | while {[llength $argv]>0} { | |
28 | set flag [lindex $argv 0] | |
29 | switch -- $flag \ | |
30 | "-l" { | |
31 | set length [lindex $argv 1] | |
32 | set argv [lrange $argv 2 end] | |
33 | } "-d" { | |
34 | set minnum [lindex $argv 1] | |
35 | set argv [lrange $argv 2 end] | |
36 | } "-c" { | |
37 | set minlower [lindex $argv 1] | |
38 | set argv [lrange $argv 2 end] | |
39 | } "-C" { | |
40 | set minupper [lindex $argv 1] | |
41 | set argv [lrange $argv 2 end] | |
42 | } "-s" { | |
43 | set minspecial [lindex $argv 1] | |
44 | set argv [lrange $argv 2 end] | |
45 | } "-v" { | |
46 | set verbose 1 | |
47 | set argv [lrange $argv 1 end] | |
48 | } "-p" { | |
49 | set prog [lindex $argv 1] | |
50 | set argv [lrange $argv 2 end] | |
51 | } "-2" { | |
52 | set distribute 1 | |
53 | set argv [lrange $argv 1 end] | |
54 | } default { | |
55 | set user [lindex $argv 0] | |
56 | set argv [lrange $argv 1 end] | |
57 | break | |
58 | } | |
59 | } | |
60 | ||
61 | if {[llength $argv]} { | |
62 | puts "usage: mkpasswd \[args] \[user]" | |
63 | puts " where arguments are:" | |
64 | puts " -l # (length of password, default = $length)" | |
65 | puts " -d # (min # of digits, default = $minnum)" | |
66 | puts " -c # (min # of lowercase chars, default = $minlower)" | |
67 | puts " -C # (min # of uppercase chars, default = $minupper)" | |
68 | puts " -s # (min # of special chars, default = $minspecial)" | |
69 | puts " -v (verbose, show passwd interaction)" | |
70 | puts " -p prog (program to set password, default = $defaultprog)" | |
71 | exit 1 | |
72 | } | |
73 | ||
74 | if {$minnum + $minlower + $minupper + $minspecial > $length} { | |
75 | puts "impossible to generate $length-character password\ | |
76 | with $minnum numbers, $minlower lowercase letters,\ | |
77 | $minupper uppercase letters and\ | |
78 | $minspecial special characters." | |
79 | exit 1 | |
80 | } | |
81 | ||
82 | # if there is any underspecification, use additional lowercase letters | |
83 | set minlower [expr {$length - ($minnum + $minupper + $minspecial)}] | |
84 | ||
85 | set lpass "" ;# password chars typed by left hand | |
86 | set rpass "" ;# password chars typed by right hand | |
87 | ||
88 | # insert char into password at a random position, thereby spreading | |
89 | # the different kinds of characters throughout the password | |
90 | proc insert {pvar char} { | |
91 | upvar $pvar p | |
92 | ||
93 | set p [linsert $p [rand [expr {(1+[llength $p])}]] $char] | |
94 | } | |
95 | ||
96 | proc rand {m} { | |
97 | expr {int($m*rand())} | |
98 | } | |
99 | ||
100 | # choose left or right starting hand | |
101 | set initially_left [set isleft [rand 2]] | |
102 | ||
103 | # given a size, distribute between left and right hands | |
104 | # taking into account where we left off | |
105 | proc psplit {max lvar rvar} { | |
106 | upvar $lvar left $rvar right | |
107 | global isleft | |
108 | ||
109 | if {$isleft} { | |
110 | set right [expr $max/2] | |
111 | set left [expr $max-$right] | |
112 | set isleft [expr !($max%2)] | |
113 | } else { | |
114 | set left [expr $max/2] | |
115 | set right [expr $max-$left] | |
116 | set isleft [expr $max%2] | |
117 | } | |
118 | } | |
119 | ||
120 | if {$distribute} { | |
121 | set lkeys {q w e r t a s d f g z x c v b} | |
122 | set rkeys {y u i o p h j k l n m} | |
123 | set lnums {1 2 3 4 5 6} | |
124 | set rnums {7 8 9 0} | |
125 | set lspec {! @ # \$ %} | |
126 | set rspec {^ & * ( ) - = _ + [ ] "{" "}" \\ | ; : ' \" < > , . ? /} | |
127 | } else { | |
128 | 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} | |
129 | 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} | |
130 | set lnums {0 1 2 3 4 5 6 7 8 9} | |
131 | set rnums {0 1 2 3 4 5 6 7 8 9} | |
132 | set lspec {! @ # \$ % ~ ^ & * ( ) - = _ + [ ] "{" "}" \\ | ; : ' \" < > , . ? /} | |
133 | set rspec {! @ # \$ % ~ ^ & * ( ) - = _ + [ ] "{" "}" \\ | ; : ' \" < > , . ? /} | |
134 | } | |
135 | ||
136 | set lkeys_length [llength $lkeys] | |
137 | set rkeys_length [llength $rkeys] | |
138 | set lnums_length [llength $lnums] | |
139 | set rnums_length [llength $rnums] | |
140 | set lspec_length [llength $lspec] | |
141 | set rspec_length [llength $rspec] | |
142 | ||
143 | psplit $minnum left right | |
144 | for {set i 0} {$i<$left} {incr i} { | |
145 | insert lpass [lindex $lnums [rand $lnums_length]] | |
146 | } | |
147 | for {set i 0} {$i<$right} {incr i} { | |
148 | insert rpass [lindex $rnums [rand $rnums_length]] | |
149 | } | |
150 | ||
151 | psplit $minlower left right | |
152 | for {set i 0} {$i<$left} {incr i} { | |
153 | insert lpass [lindex $lkeys [rand $lkeys_length]] | |
154 | } | |
155 | for {set i 0} {$i<$right} {incr i} { | |
156 | insert rpass [lindex $rkeys [rand $rkeys_length]] | |
157 | } | |
158 | ||
159 | psplit $minupper left right | |
160 | for {set i 0} {$i<$left} {incr i} { | |
161 | insert lpass [string toupper [lindex $lkeys [rand $lkeys_length]]] | |
162 | } | |
163 | for {set i 0} {$i<$right} {incr i} { | |
164 | insert rpass [string toupper [lindex $rkeys [rand $rkeys_length]]] | |
165 | } | |
166 | ||
167 | psplit $minspecial left right | |
168 | for {set i 0} {$i<$left} {incr i} { | |
169 | insert lpass [lindex $lspec [rand $lspec_length]] | |
170 | } | |
171 | for {set i 0} {$i<$right} {incr i} { | |
172 | insert rpass [lindex $rspec [rand $rspec_length]] | |
173 | } | |
174 | ||
175 | # merge results together | |
176 | foreach l $lpass r $rpass { | |
177 | if {$initially_left} { | |
178 | append password $l $r | |
179 | } else { | |
180 | append password $r $l | |
181 | } | |
182 | } | |
183 | ||
184 | if {[info exists user]} { | |
185 | if {!$verbose} { | |
186 | log_user 0 | |
187 | } | |
188 | ||
189 | spawn $prog $user | |
190 | expect { | |
191 | "assword*:" { | |
192 | # some systems say "Password (again):" | |
193 | send "$password\r" | |
194 | exp_continue | |
195 | } | |
196 | } | |
197 | ||
198 | # if user isn't watching, check status | |
199 | if {!$verbose} { | |
200 | if {[lindex [wait] 3]} { | |
201 | puts -nonewline "$expect_out(buffer)" | |
202 | exit 1 | |
203 | } | |
204 | } | |
205 | ||
206 | if {$verbose} { | |
207 | puts -nonewline "password for $user is " | |
208 | } | |
209 | } | |
210 | ||
211 | puts "$password" |