pwd bug fix

This commit is contained in:
2026-10-13 14:46:18 +02:00
parent afe1a1b610
commit d28b602827
3 changed files with 79 additions and 14 deletions
+70 -12
View File
@@ -36,6 +36,42 @@
load_conf "pwd"
# ------------------------------------------------------------------------------
# Internal helper: put in _PWD_RAND an integer uniformly distributed in
# [0, $1), for 1 <= $1 <= 2^32. $RANDOM is NOT usable for passwords: it only
# has 15 bits, a state seeded from the time and the PID, and is predictable.
# The source is $SRANDOM (bash >= 5.1, from the kernel's random generator), or
# else /dev/urandom read through od, 256 words at a time to limit the number
# of processes. Values above the largest multiple of $1 are rejected, so that
# "% $1" introduces no bias.
# Usage: _pwd_rand <max>
_pwd_rand()
{
local max="$1" limit r
limit=$(( 4294967296 - 4294967296 % max ))
while :; do
if [[ -n "${SRANDOM+x}" ]]; then
r="$SRANDOM"
else
if (( ${#_PWD_POOL[@]} == 0 )); then
# shellcheck disable=SC2207 # whitespace-separated numbers
_PWD_POOL=( $(od -An -v -N1024 -tu4 /dev/urandom 2>/dev/null) )
if (( ${#_PWD_POOL[@]} == 0 )); then
disp E "No source of random numbers available (/dev/urandom)."
return 1
fi
fi
r="${_PWD_POOL[-1]}"
unset '_PWD_POOL[-1]'
fi
if (( r < limit )); then
_PWD_RAND=$(( r % max ))
return 0
fi
done
}
_PWD_POOL=()
# ------------------------------------------------------------------------------
# genpwd : generate a password with different criteria
# Usage: genpwd [options] [--extracars=<cars>] [--length=<n>] [nb_passwd]
@@ -68,10 +104,12 @@ genpwd()
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences:,occurrences: \
-n 'genpwd' -- "$@")
# shellcheck disable=SC2181 # getopt return code is checked immediately after
if [[ $? -ne 0 ]]; then return 1; fi
local -a _pargs=()
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
set -- "${_pargs[@]}"
if [[ $? -ne 0 ]]; then
disp E "Invalid options, use \"genpwd --help\" to display usage."
return 1
fi
# Restore the getopt-normalised (shell-quoted) argument list
eval set -- "$PARSED"
while true; do
case "$1" in
@@ -150,6 +188,21 @@ genpwd()
fi
local carset=""
# The defaults may come from the configuration file: bash evaluates a
# non-numeric string inside (( )) as an expression, so check them first.
local _v
for _v in "$symb" "$numb" "$maj" "$min"; do
if [[ $_v != 0 && $_v != 1 ]]; then
disp E "Invalid GENPWD_DEFAULT_* value '$_v': the character class switches must be 0 or 1."
return 1
fi
done
for _v in "$length" "$occurs" "$nbpwd"; do
if ! [[ $_v =~ ^[1-9][0-9]*$ ]]; then
disp E "Invalid GENPWD_DEFAULT_* value '$_v': length, occurrences and count must be positive integers."
return 1
fi
done
local unique_carset=""
local ch=""
local i=0
@@ -210,7 +263,9 @@ genpwd()
return 1
fi
disp I "Generating $nbpwd password(s), please wait..."
# On stderr: stdout carries the passwords only, so that "pw=$(genpwd)" or
# "genpwd | xclip" do not capture this message.
disp I "Generating $nbpwd password(s), please wait..." >&2
for (( n=1; n<=nbpwd; n++ )); do
local -a password_chars=()
local -A char_count=()
@@ -224,7 +279,8 @@ genpwd()
return 1
fi
idx=$(( RANDOM % ${#set} ))
_pwd_rand "${#set}" || return 1
idx=$_PWD_RAND
char=${set:idx:1}
count=${char_count["$char"]:-0}
@@ -246,7 +302,8 @@ genpwd()
return 1
fi
idx=$(( RANDOM % ${#carset} ))
_pwd_rand "${#carset}" || return 1
idx=$_PWD_RAND
char=${carset:idx:1}
count=${char_count["$char"]:-0}
@@ -261,7 +318,8 @@ genpwd()
done
for (( i=${#password_chars[@]} - 1; i>0; i-- )); do
idx=$(( RANDOM % (i + 1) ))
_pwd_rand "$(( i + 1 ))" || return 1
idx=$_PWD_RAND
char=${password_chars[i]}
password_chars[i]=${password_chars[idx]}
password_chars[idx]=$char
@@ -312,7 +370,7 @@ pwdscore()
break
;;
-*)
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage."
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage (a password starting with '-' must follow '--')."
return 1
;;
*)
@@ -373,17 +431,17 @@ pwdscore()
score=$(( length * 2 ))
fi
if [[ $password =~ [a-z] ]]; then
if [[ $password =~ [[:lower:]] ]]; then
has_lower=1
pool_size=$(( pool_size + 26 ))
score=$(( score + 12 ))
fi
if [[ $password =~ [A-Z] ]]; then
if [[ $password =~ [[:upper:]] ]]; then
has_upper=1
pool_size=$(( pool_size + 26 ))
score=$(( score + 12 ))
fi
if [[ $password =~ [0-9] ]]; then
if [[ $password =~ [[:digit:]] ]]; then
has_digit=1
pool_size=$(( pool_size + 10 ))
score=$(( score + 12 ))