1#!/usr/bin/perl
2
3use 5.006001;
4use strict;
5
6use File::Basename qw(basename);
7use Getopt::Long qw(GetOptions);
8use String::MkPasswd qw(mkpasswd);
9use Text::Wrap qw(wrap);
10
11# Defaults.
12use constant LENGTH		=> 9;
13use constant MINNUM		=> 2;
14use constant MINLOWER	=> 2;
15use constant MINUPPER	=> 2;
16use constant MINSPECIAL	=> 1;
17use constant DISTRIBUTE	=> "";
18#use constant VERBOSE	=> "";
19#use constant PASSWD		=> "/bin/passwd";
20
21# Configuration.
22my $length		= LENGTH;
23my $minnum		= MINNUM;
24my $minlower	= MINLOWER;
25my $minupper	= MINUPPER;
26my $minspecial	= MINSPECIAL;
27my $distribute	= DISTRIBUTE;
28#my $verbose	= VERBOSE;
29#my $passwd		= PASSWD;
30my $help		= "";
31
32Getopt::Long::Configure("bundling");
33my $getopt = GetOptions(
34	"length|l=i"	=> \$length,
35	"digits|d=i"	=> \$minnum,
36	"lower|c=i"		=> \$minlower,
37	"upper|C=i"		=> \$minupper,
38	"special|s=i"	=> \$minspecial,
39	"distribute|2"	=> \$distribute,
40	#"verbose|v"		=> \$verbose,
41	#"passwd|p"		=> \$passwd,
42	"help|h"		=> \$help,
43
44	# Getopt::Long doesn't support combining '--no' with options that take
45	# arguments, so this is just my way of faking it.
46	"nodigits|no-digits"	=> sub { $minnum = 0 },
47	"nolower|no-lower"		=> sub { $minlower = 0 },
48	"noupper|no-upper"		=> sub { $minupper = 0 },
49	"nospecial|no-special"	=> sub { $minspecial = 0 },
50);
51
52if ( $help ) {
53	&usage();
54	exit 0;
55}
56
57if ( !$getopt ) {
58	&usage();
59	exit 1;
60}
61
62my $pass = mkpasswd(
63	-length		=> $length,
64	-minnum		=> $minnum,
65	-minlower	=> $minlower,
66	-minupper	=> $minupper,
67	-minspecial	=> $minspecial,
68	-distribute	=> $distribute,
69);
70
71if ( !$pass ) {
72	$Text::Wrap::columns = 72;
73	print STDERR wrap("", "",
74		"Impossible to generate $length-character password with $minnum "
75		. "numbers, $minlower lowercase letters, $minupper uppercase letters "
76		. "and $minspecial special characters.\n"
77	);
78	exit 1;
79}
80
81print "$pass\n";
82exit 0;
83
84sub usage {
85	print <<EOF;
86Usage: @{[ basename $0 ]} [-options]
87    -l # | --length=#   length of password (default = @{[ LENGTH ]})
88    -d # | --digits=#   min # of digits (default = @{[ MINNUM ]})
89    -c # | --lower=#    min # of lowercase chars (default = @{[ MINLOWER ]})
90    -C # | --upper=#    min # of uppercase chars (default = @{[ MINUPPER ]})
91    -s # | --special=#  min # of special chars (default = @{[ MINSPECIAL ]})
92    -2 | --distribute   alternate hands
93	--nodigits          alias for --digits=0
94	--nolower           alias for --lower=0
95	--noupper           alias for --upper=0
96	--nospecial         alias for --special=0
97EOF
98}
99
100__END__
101
102=head1 NAME
103
104mkpasswd.pl - example to generate new password with String::MkPasswd
105
106=head1 SYNOPSIS
107
108  mkpasswd.pl [-options]
109
110  #!/bin/sh
111  NEW_PASSWD=`mkpasswd.pl`
112
113=head1 DESCRIPTION
114
115This program generates a random password, allowing for some tuning of
116character distribution.  The password is sent to standard output.
117
118=head2 OPTIONS
119
120=over 4
121
122=item -l # | --length=#
123
124The total length of the password.  The default is 9.
125
126=item -d # | --digits=#
127
128The minimum number of digits that will appear in the final password.
129The default is 2.
130
131=item -c # | --lower=#
132
133The minimum number of lower-case characters that will appear in the
134final password.  The default is 2.
135
136=item -C # | --upper=#
137
138The minimum number of upper-case characters that will appear in the
139final password.  The default is 2.
140
141=item -s # | --special=#
142
143The minimum number of non-alphanumeric characters that will appear in
144the final password.  The default is 1.
145
146=item -2 | --distribute
147
148If specified, password characters will be distributed between the left-
149and right-hand sides of the keyboard.  This makes it more difficult for
150an onlooker to see the password as it is typed.
151
152=item --nodigits | --no-digits
153
154Alias for --digits=0.
155
156=item --nolower | --no-lower
157
158Alias for --lower=0.
159
160=item --noupper | --no-upper
161
162Alias for --upper=0.
163
164=item --nospecial | --no-special
165
166Alias for --special=0.
167
168=back
169
170=head1 BUGS
171
172=over 4
173
174=item *
175
176While not really a bug, the .pl extension has been added to avoid
177conflict with the program of the same name distributed with Expect.
178
179=back
180
181=head1 TODO
182
183=over 4
184
185=item *
186
187For completeness, add user password setting functionality as found in
188Expect's L<mkpasswd(1)> example.
189
190=back
191
192=head1 SEE ALSO
193
194L<http://expect.nist.gov/#examples>,
195L<mkpasswd(1)>,
196L<String::MkPasswd>
197
198=head1 AKNOWLEDGEMENTS
199
200Don Libes of the National Institute of Standards and Technology, who
201wrote the Expect example, L<mkpasswd(1)>.
202
203=head1 AUTHOR
204
205Chris Grau E<lt>cgrau@cpan.orgE<gt>
206
207=head1 COPYRIGHT AND LICENSE
208
209Copyright (C) 2003-2004 by Chris Grau
210
211This library is free software; you can redistribute it and/or modify it
212under the same terms as Perl itself, either Perl version 5.8.1 or, at
213your option, any later version of Perl 5 you may have available.
214
215=cut
216