#!/usr/bin/perl -w my $rcsid = '$Id: pwran,v 1.3 2004/09/23 18:40:29 vogelke Exp $'; =head1 NAME pwran =head1 SYNOPSIS pwran [-hpv] [-m min] [-n num] =head1 DESCRIPTION Generates random passwords. =head1 OPTIONS -h prints usage message. -m min minimum password length is "min"; default = 6, must be > 3. -n num generate "num" passwords; default = 5, must be > 0. -p include rough hint for pronunciation with passwords. -v prints the version and exits. =head1 AUTHOR Karl Vogel Sumaria Systems, Inc. =head1 HISTORY Based on http://www.cgi-interactive-uk.com/random_password_generator.html =cut # To generate manpage: # pod2man -c 'User docs' -r "`date`" -d version pwran #--------------------------------------------------------------------- use strict; use subs qw(pronounce randompw usage version); use File::Basename; my $myname = basename($0, ".pl"); my $pflag = 0; my $plen = 0; my $pcount = 0; # Handle any command line arguments. ARG: while (@ARGV) { $_ = shift @ARGV; /^-h/ and do { usage(); }; /^-p/ and do { $pflag++; next ARG; }; /^-v/ and do { my $vers = version(); warn "$vers\n"; exit(0); }; /^-m(.*)/ and do { $plen = $1 || shift @ARGV; usage("-m requires a number") unless defined($plen) && $plen =~ m/^\d+$/; next ARG; }; /^-n(.*)/ and do { $pcount = $1 || shift @ARGV; usage("-n requires a number") unless defined($pcount) && $pcount =~ m/^\d+$/; next ARG; }; /^-.*/ and do { usage("unrecognized option: $_"); }; } $pcount = 5 if $pcount <= 0; $plen = 6 if $plen <= 3; # Real work starts here. foreach (1 .. $pcount) { print randompw($plen, $pflag), "\n"; } exit(0); #--------------------------------------------------------------------- # Print a usage message from the comment header and exit. sub usage { my ($emsg) = @_; require Pod::Text; import Pod::Text; my $formatter = 'Pod::Text'; my $parser = $formatter->new(); warn "$emsg\n" if defined($emsg); $parser->parse_from_file($0); exit(1); } #--------------------------------------------------------------------- # Return the current version. sub version { $_ = $rcsid; s/,v / /; @_ = split; return "$_[1] v$_[2] $_[3] $_[4]"; } #--------------------------------------------------------------------- # Generate a password. sub randompw { my $plen = $_[0] || 6; # password length. my $needhelp = $_[1] || 0; # want a pronunciation returned? my $password = ''; my $r; my $k; my %parr; # Leave out lower-case L and upper-case I (often confused with # number one), upper-case S (often confused with number five), # upper-case O (often confused with number zero), my @alpha = qw( a b c d e f g h i j k m n o p q r s t u v w x y z A B C D E F G H I J K L M N P Q R T U V W X Y Z ); my @digits = qw( 0 1 2 3 4 5 6 7 8 9 ); # Skip '#' and ',' to avoid stupid warnings. my @other = qw( ! " $ % & ' ( ) * + - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ ); # # Mix some letters, at least one digit, and at least one # special character. Don't use srand() explicitly --- perl # will auto-seed the PRNG from /dev/urandom if left to its # own devices. # foreach (1 .. $plen - 2) { $k = int(rand(10000)); $r = int(rand($#alpha)); $parr{$k} = $alpha[$r]; } $k = int(rand(10000)); $r = int(rand($#digits)); $parr{$k} = $digits[$r]; $k = int(rand(10000)); $r = int(rand($#other)); $parr{$k} = $other[$r]; # Join the results randomly, so the digits and special # characters don't always appear in the same places. my $help = ''; foreach (sort keys %parr) { $password .= $parr{$_}; $help .= pronounce($parr{$_}) . ' ' if $needhelp; } if ($needhelp) { chop($help); $password .= "\t($help)"; } return $password; } #--------------------------------------------------------------------- # Return a rough pronunciation for a letter. sub pronounce { my $letter = $_[0]; # Set names for digits and symbols, so we can give rough # pronunciation of password. my %sym = ( '0' => 'ZERO', '1' => 'ONE', '2' => 'TWO', '3' => 'THREE', '4' => 'FOUR', '5' => 'FIVE', '6' => 'SIX', '7' => 'SEVEN', '8' => 'EIGHT', '9' => 'NINE', '!' => 'EXCLAMATION_POINT', '"' => 'QUOTATION_MARK', '$' => 'DOLLAR_SIGN', '%' => 'PERCENT_SIGN', '&' => 'AMPERSAND', '\'' => 'APOSTROPHE', '(' => 'LEFT_PARENTHESIS', ')' => 'RIGHT_PARENTHESIS', '*' => 'ASTERISK', '+' => 'PLUS_SIGN', '-' => 'HYPHEN', '.' => 'PERIOD', '/' => 'SLASH', ':' => 'COLON', ';' => 'SEMICOLON', '<' => 'LESS_THAN', '=' => 'EQUAL_SIGN', '>' => 'GREATER_THAN', '?' => 'QUESTION_MARK', '@' => 'AT_SIGN', '[' => 'LEFT_BRACKET', '\\' => 'BACKSLASH', ']' => 'RIGHT_BRACKET', '^' => 'CIRCUMFLEX', '_' => 'UNDERSCORE', '`' => 'GRAVE', '{' => 'LEFT_BRACE', '|' => 'VERTICAL_BAR', '}' => 'RIGHT_BRACE', '~' => 'TILDE' ); return defined($sym{$letter}) ? $sym{$letter} : $letter; }