|
mkrandpwd_k93
Random Password Generator - Korn Shell 93 Script
As a result of recent IT security requirements imposed upon many
businesses, user passwords are typically required to be unintelligible
strings of random characters. These random character strings are
normally required to contain some predefined minimum number of upper and
lower case letters, digits, and/or punctuation symbols. And while it
can be argued whether this is a security enhancement or a security hole,
since remembering these passwords requires they be written down
somewhere, it is not the purpose of this script to validate or
invalidate this argument. The purpose of this script is to generate
random strings of characters that can be used as secure passwords to
comply with IT security requirements.
The reason this script was written was out of frustration in
attempting to manually create a string of characters that complies with
IT security requirements defining how many letters, digits, and symbols
are required in a secure password.
Additionally this script is used as part of an automated process
for creating new users and
automatically initializing the new users password to a secure and
compliant value.
#!/usr/bin/ksh93
################################################################
function usagemsg_mkrandpwd_k93 {
print "
Program: mkrandpwd_k93
This script generates a random password string
Usage: ${1##*/} [-?] [-vV] [-luadsn] [-m minimum] [-M maximum]
[-O minother] [-A minalpha] [-R maxrepeats]
[-L minlower] [-U minupper] [-D mindigit]
[-S minsymbol]
Where:
-l = Convert upper case letters to lower case in random password string.
-u = Convert lower case letters to upper case in random password string.
-a = Only return alphabetic characters in random password string.
-d = Only return numeric digits in random password string.
-s = Only return punctuation symbols in random password string.
-n = Only return alphanumeric characters in random password string.
-m minimum = Specify the minimum number of characters
to be returned in the random password.
Default: 8
-M maximum = Specify the maximum number of characters
to be returned in the random password string.
Default: 8
-O minother = Specify the minimum number of non-alphabetic
characters in the random password.
Default: 0
-A minalpha = Specify the minimum number of alphabetic
characters in the random password.
Default: 0
-L minlower = Specify the minimum number of lowercase
letters in the random password.
Default: 0
-U minupper = Specify the minimum number of uppercase
letters in the random password.
Default: 0
-D mindigit = Specify the minimum number of numeric digit
characters in the random password.
Default: 0
-S minsymbol = Specify the minimum number of punctuation
symbol characters in the random password.
Default: 0
-R maxrepeats = Specify the maximum number of times a character
can be repeated in the random password string.
Default: 8
-v = Verbose mode
-V = Very Verbose Mode
Example: mkrandpwd_k93
Author: Dana French (dfrench@mtxia.com)
Copyright 2006 by Dana French
\"AutoContent\" enabled
"
}
################################################################
function mkrandpwd_k93 {
typeset TRUE="1"
typeset FALSE="0"
typeset RETCODE="0"
typeset VERBOSE="${FALSE}"
typeset VERYVERB="${FALSE}"
typeset AONLY="${FALSE}"
typeset DONLY="${FALSE}"
typeset NONLY="${FALSE}"
typeset SONLY="${FALSE}"
typeset LONLY="${FALSE}"
typeset UONLY="${FALSE}"
typeset MINIMUM="8"
typeset MAXIMUM="${MINIMUM}"
typeset MAXLEN="8"
typeset MINOTHER="0" OTHER="-1"
typeset MINLOWER="0" LOWER="-1"
typeset MINUPPER="0" UPPER="-1"
typeset MINALPHA="0" ALPHA="-1"
typeset MINDIGIT="0" DIGIT="-1"
typeset MINSYMBOL="0" SYMBOL="-1"
typeset MAXREPEATS="8" REPEATS="-1"
typeset POSCNT
typeset RANDSTR
typeset ITERATION="0"
####
#### Set the array of valid characters to be all upper and
#### lower case letters, all digits, and a selected set of
#### punctuation symbols.
####
typeset CHARS
CHARS=( 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 \
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 \
0 1 2 3 4 5 6 7 8 9 \; \: \. \~ \! \@ \# \$ \% \^ \& \* - + = \? )
typeset CNUM="${#CHARS[@]}"
while getopts ":vVluadsnm#M#O#A#L#U#D#S#R#" OPTION
do
case "${OPTION}" in
'v') VERBOSE="${TRUE}";;
'V') VERYVERB="${TRUE}";;
'm') MINIMUM="${OPTARG}";;
'M') MAXIMUM="${OPTARG}";;
'O') MINOTHER="${OPTARG}";;
'A') MINALPHA="${OPTARG}";;
'L') MINLOWER="${OPTARG}";;
'U') MINUPPER="${OPTARG}";;
'D') MINDIGIT="${OPTARG}";;
'S') MINSYMBOL="${OPTARG}";;
'R') MAXREPEATS="${OPTARG}";;
'l') typeset -l CHARS=( "${CHARS[@]}" )
LONLY="${TRUE}"
;;
'u') typeset -u CHARS=( "${CHARS[@]}" )
UONLY="${TRUE}"
;;
####
#### If the ALPHA ONLY option was selected on the command
#### line, reset the array of valid characters to be a list
#### of upper and lower case letters.
####
'a') AONLY="${TRUE}"
CHARS=( 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 \
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 )
(( LONLY == TRUE )) && typeset -l CHARS=( "${CHARS[@]}" )
(( UONLY == TRUE )) && typeset -u CHARS=( "${CHARS[@]}" )
typeset CNUM="${#CHARS[@]}"
;;
####
#### If the DIGITS ONLY option was selected on the command
#### line, reset the array of valid characters to be a list
#### of digits.
####
'd') DONLY="${TRUE}"
CHARS=( 0 1 2 3 4 5 6 7 8 9 )
typeset CNUM="${#CHARS[@]}"
;;
####
#### If the SYMBOLS ONLY option was selected on the command
#### line, reset the array of valid characters to be a list
#### of punctuation symbols.
####
's') SONLY="${TRUE}"
CHARS=( \; \: \. \~ \! \@ \# \$ \% \^ \& \* - + = \? )
typeset CNUM="${#CHARS[@]}"
;;
####
#### If ALPHANUMERIC option was selected on the command line, reset
#### the array of valid characters to be upper and lower case
#### letters, and digits.
####
'n') NONLY="${TRUE}"
CHARS=( 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 \
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 \
0 1 2 3 4 5 6 7 8 9 )
(( LONLY == TRUE )) && typeset -l CHARS=( "${CHARS[@]}" )
(( UONLY == TRUE )) && typeset -u CHARS=( "${CHARS[@]}" )
typeset CNUM="${#CHARS[@]}"
;;
'?') usagemsg_mkrandpwd_k93 "${0}" && return 1 ;;
':') usagemsg_mkrandpwd_k93 "${0}" && return 1 ;;
'#') usagemsg_mkrandpwd_k93 "${0}" && return 1 ;;
esac
done
shift $(( ${OPTIND} - 1 ))
################################################################
trap "usagemsg_mkrandpwd_k93 ${0}" EXIT
#### Check to ensure the minimum number of characters allowed
#### in the random password is less than or equal to the maximum.
RETCODE="10"
if ! (( MINIMUM <= MAXIMUM ))
then
print -u 2 "# ERROR: MINIMUM number of characters must be less than or equal to"
print -u 2 "# MAXIMUM."
return ${RETCODE}
fi
#### The minimum number of characters in the password must be
#### greater than or equal to the minimum number of other
#### characters plus the minimum number of alpha characters.
(( ++RETCODE ))
if ! (( MINIMUM >= ( MINOTHER + MINALPHA ) ))
then
print -u 2 "# ERROR: MINIMUM number of characters must be greater than or equal to"
print -u 2 "# MINOTHER + MINALPHA."
return ${RETCODE}
fi
#### The minimum number of characters in the password must be
#### greater than or equal to the sum of the minimum number
#### of lowercase letters, uppercase letters, digits, and
#### symbols.
(( ++RETCODE ))
if ! (( MINIMUM >= ( MINLOWER + MINUPPER + MINDIGIT + MINSYMBOL ) ))
then
print -u 2 "# ERROR: MINIMUM number of characters must be greater than or equal to"
print -u 2 "# MINLOWER + MINUPPER + MINDIGIT + MINSYMBOL."
return ${RETCODE}
fi
#### The minimum number of characters in the password minus
#### the minimum number of other characters must be greater
#### than or equal to the sum of the minimum number of
#### lowercase letters plus the minimum number of uppercase
#### letters.
(( ++RETCODE ))
if ! (( ( MINIMUM - MINOTHER ) >= ( MINLOWER + MINUPPER ) ))
then
print -u 2 "# ERROR: MINIMUM minus MINOTHER characters must be greater than or equal to"
print -u 2 "# MINLOWER + MINUPPER."
return ${RETCODE}
fi
#### The minimum number of characters in the password minus
#### the minimum number of alphabetic characters must be greater
#### than or equal to the sum of the minimum number of
#### digit characters plus the minimum number of symbol
#### characters.
(( ++RETCODE ))
if ! (( ( MINIMUM - MINALPHA ) >= ( MINDIGIT + MINSYMBOL ) ))
then
print -u 2 "# ERROR: MINIMUM minus MINALPHA characters must be greater than or equal to"
print -u 2 "# MINDIGIT + MINSYMBOL."
return ${RETCODE}
fi
#### If the minimum number of alphabetic characters was
#### provided on the command line, then the minimum number of
#### alphabetic characters must be greater than or equal to
#### the sum of the minimum number of lowercase characters
#### plus the minimum number of uppercase characters.
(( ++RETCODE ))
if (( MINALPHA != 0 )) && ! (( MINALPHA >= ( MINLOWER + MINUPPER ) ))
then
print -u 2 "# ERROR: MINALPHA number of characters must be greater than or equal to"
print -u 2 "# MINLOWER + MINUPPER."
return ${RETCODE}
fi
#### If the minimum number of other characters was
#### provided on the command line, then the minimum number of
#### other characters must be greater than or equal to
#### the sum of the minimum number of digits
#### plus the minimum number of symbols.
(( ++RETCODE ))
if (( MINOTHER != 0 )) && ! (( MINOTHER >= ( MINDIGIT + MINSYMBOL ) ))
then
print -u 2 "# ERROR: MINOTHER number of characters must be greater than or equal to"
print -u 2 "# MINDIGIT + MINSYMBOL."
return ${RETCODE}
fi
#### If the alphabetic only option was selected on the
#### command line, then the minimum number of other
#### characters, the minimum number of digits, and the
#### minimum number of symbols must all be zero (0).
(( ++RETCODE ))
if (( ( AONLY == TRUE ) &&
( MINOTHER != 0 ||
MINDIGIT != 0 ||
MINSYMBOL != 0 ) ))
then
print -u 2 "# ERROR: ALPHA ONLY command line option was selected, therefore"
print -u 2 "# MINOTHER, MINDIGIT, AND MINSYMBOL values must be zero."
return ${RETCODE}
fi
#### If the alphanumeric only option was selected on the
#### command line, then the minimum number of symbols
#### must be zero (0).
(( ++RETCODE ))
if (( ( NONLY == TRUE ) && ( MINSYMBOL != 0 ) ))
then
print -u 2 "# ERROR: ALPHANUMERIC ONLY command line option was selected, therefore"
print -u 2 "# MINSYMBOL value must be zero."
return ${RETCODE}
fi
#### If the digit only option was selected on the command
#### line, then the minimum number of other characters, the
#### minimum number of alphabetic characters, and the minimum
#### number of symbols must all be zero (0).
(( ++RETCODE ))
if (( ( DONLY == TRUE ) &&
( MINALPHA != 0 ||
MINOTHER != 0 ||
MINSYMBOL != 0 ) ))
then
print -u 2 "# ERROR: DIGIT ONLY command line option was selected, therefore"
print -u 2 "# MINALPHA, MINOTHER, AND MINSYMBOL values must be zero."
return ${RETCODE}
fi
#### If the symbol only option was selected on the command
#### line, then the minimum number of alphabetic characters,
#### the minimum number of other characters, and the minimum
#### number of symbols must all be zero (0).
(( ++RETCODE ))
if (( ( SONLY == TRUE ) &&
( MINALPHA != 0 ||
MINOTHER != 0 ||
MINDIGIT != 0 ) ))
then
print -u 2 "# ERROR: SYMBOL ONLY command line option was selected, therefore"
print -u 2 "# MINALPHA, MINOTHER, AND MINDIGIT values must be zero."
return ${RETCODE}
fi
#### If the convert to lowercase letters option was selected
#### on the command line, then the minimum number of
#### uppercase letters must be zero (0).
(( ++RETCODE ))
if (( ( LONLY == TRUE ) && ( MINUPPER != 0 ) ))
then
print -u 2 "# ERROR: Convert to LOWERCASE command line option was selected, therefore"
print -u 2 "# MINUPPER value must be zero."
return ${RETCODE}
fi
#### If the convert to uppercase letters option was selected
#### on the command line, then the minimum number of
#### lowercase letters must be zero (0).
(( ++RETCODE ))
if (( ( UONLY == TRUE ) && ( MINLOWER != 0 ) ))
then
print -u 2 "# ERROR: Convert to UPPERCASE command line option was selected, therefore"
print -u 2 "# MINLOWER value must be zero."
return ${RETCODE}
fi
#### If the alphabetic only option was selected on the
#### command line, then the alphanumeric, digit, and symbol
#### only options must not be selected.
(( ++RETCODE ))
if (( AONLY == TRUE && ( NONLY == TRUE || DONLY == TRUE || SONLY == TRUE ) ))
then
print -u 2 "# ERROR: ALPHA ONLY command line option was selected, therefore"
print -u 2 "# ALPHANUMERIC, DIGIT, and SYMBOL ONLY options must not be selected."
return ${RETCODE}
fi
#### If the alphanumeric only option was selected on the
#### command line, then the alphabetic, digit, and symbol
#### only options must not be selected.
(( ++RETCODE ))
if (( NONLY == TRUE && ( DONLY == TRUE || SONLY == TRUE || AONLY == TRUE ) ))
then
print -u 2 "# ERROR: ALPHANUMERIC ONLY command line option was selected, therefore"
print -u 2 "# ALPHA, DIGIT, and SYMBOL ONLY options must not be selected."
return ${RETCODE}
fi
#### If the digit only option was selected on the command
#### line, then the alphabetic, alphanumeric, and symbol only
#### options must not be selected.
(( ++RETCODE ))
if (( DONLY == TRUE && ( SONLY == TRUE || AONLY == TRUE || NONLY == TRUE ) ))
then
print -u 2 "# ERROR: DIGIT ONLY command line option was selected, therefore"
print -u 2 "# ALPHA, ALPHANUMERIC, and SYMBOL ONLY options must not be selected."
return ${RETCODE}
fi
#### If the symbol only option was selected on the command
#### line, then the alphabetic, alphanumeric, and digit only
#### options must not be selected.
(( ++RETCODE ))
if (( SONLY == TRUE && ( AONLY == TRUE || NONLY == TRUE || DONLY == TRUE ) ))
then
print -u 2 "# ERROR: SYMBOL ONLY command line option was selected, therefore"
print -u 2 "# ALPHA, ALPHANUMERIC, and DIGIT only options must not be selected."
return ${RETCODE}
fi
RETCODE="0"
trap "-" EXIT
################################################################
(( VERYVERB == TRUE )) && set -x
(( VERBOSE == TRUE )) && print -u 2 -- "# Min length of random password string: ${MINIMUM}"
(( VERBOSE == TRUE )) && print -u 2 -- "# Max length of random password string: ${MAXIMUM}"
####
#### Calculate a random length for the random password string between the
#### MINIMUM and MAXIMUM values provided
####
(( MAXIMUM != MINIMUM )) && (( MAXIMUM++ ))
(( MINIMUM == MAXIMUM )) &&
MAXLEN=${MINIMUM} ||
MAXLEN=$(( MINIMUM + ( RANDOM % ( MAXIMUM - MINIMUM ) ) ))
(( VERBOSE == TRUE )) && print -u 2 -- "# Actual length of random password string: ${MAXLEN}"
#### Test the randomly generated password to see if it
#### conforms to the security requirements provided by
#### default or from options provided on the command line.
#### If not, regenerate a new password and retest.
while (( OTHER < MINOTHER )) ||
(( ALPHA < MINALPHA )) ||
(( LOWER < MINLOWER )) ||
(( UPPER < MINUPPER )) ||
(( DIGIT < MINDIGIT )) ||
(( SYMBOL < MINSYMBOL )) ||
(( REPEATS > ( MAXREPEATS + 1 ) ))
do
(( VERBOSE == TRUE )) && print -u 2 -- "#\n# Iteration: $(( ++ITERATION ))"
####
#### extract a random character from the CHARS array for each position
#### of the random password string. The length of the random string
#### determined by the MAXLEN variable.
####
RANDSTR=""
for (( POSCNT=0; POSCNT < MAXLEN; ++POSCNT ))
do
####
#### Using the modulo of a random number divided by the number of
#### characters (array elements) in the CHARS array, provides a
#### random array element position. The random array element position
#### is used to append a single character at a time from the CHARS array
#### onto the random password string variable RANDSTR.
####
RANDSTR="${RANDSTR}${CHARS[${RANDOM}%${CNUM}]}"
done
#### Determine the number of alphabetic characters in the password
typeset AVAL="${RANDSTR//[[:digit:][:punct:]]/}"
ALPHA="${#AVAL}"
#### Determine the number of non-alphabetic characters in the password
typeset OVAL="${RANDSTR//[[:lower:][:upper:]]/}"
OTHER="${#OVAL}"
#### Determine the number of alphanumeric characters in the password
typeset NVAL="${RANDSTR//[[:punct:]]/}"
ALNUM="${#NVAL}"
#### Determine the number of lowercase letters in the password
typeset LVAL="${RANDSTR//[[:upper:][:digit:][:punct:]]/}"
LOWER="${#LVAL}"
#### Determine the number of uppercase letters in the password
typeset UVAL="${RANDSTR//[[:lower:][:digit:][:punct:]]/}"
UPPER="${#UVAL}"
#### Determine the number of digits in the password
typeset DVAL="${RANDSTR//[[:lower:][:upper:][:punct:]]/}"
DIGIT="${#DVAL}"
#### Determine the number of punctuation symbols in the password
typeset SVAL="${RANDSTR//[[:lower:][:upper:][:digit:]]/}"
SYMBOL="${#SVAL}"
#### Determine how many times each character occurs in the password
typeset REPEATS="-1"
unset ARY
typeset -A ARY
for (( POSCNT=0; POSCNT < MAXLEN; ++POSCNT ))
do
(( ARY[${RANDSTR:POSCNT:1}] = ${ARY[${RANDSTR:POSCNT:1}]:-0} + 1 ))
done
#### Determine the maximum value of repeated characters in the password
for IVAL in "${!ARY[@]}"
do
VAL="${ARY[${IVAL}]}"
(( VAL > REPEATS )) && REPEATS="${VAL}" && RVAL="${IVAL}"
done
if (( VERBOSE == TRUE ))
then
print -u 2 -- "# Randomly generated password:|${RANDSTR}|"
print -u 2 -- "# Min Alpha Chars: wanted at least ${MINALPHA}: got ${ALPHA}: ${AVAL}"
print -u 2 -- "# Min Other Chars: wanted at least ${MINOTHER}: got ${OTHER}: ${OVAL}"
print -u 2 -- "# Min Lower Chars: wanted at least ${MINLOWER}: got ${LOWER}: ${LVAL}"
print -u 2 -- "# Min Upper Chars: wanted at least ${MINUPPER}: got ${UPPER}: ${UVAL}"
print -u 2 -- "# Min Digit Chars: wanted at least ${MINDIGIT}: got ${DIGIT}: ${DVAL}"
print -u 2 -- "# Min Symbol Chars: wanted at least ${MINSYMBOL}: got ${SYMBOL}: ${SVAL}"
print -u 2 -- "# Max Repeat Chars: wanted at most ${MAXREPEATS}: got $(( REPEATS - 1)): ${RVAL} "
fi
done
print -r -- "${RANDSTR}"
return 0
}
################################################################
mkrandpwd_k93 "${@}"
|
|