Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 274 lines (248 sloc) 7.14 KB
#!/bin/sh
fatal() {
echo "$*" >&2
exit 1
}
[ -n "$PWMRC" ] || PWMRC=~/.pwmrc
if [ -f "$PWMRC" ]; then
[ $(stat -c'%a' "$PWMRC") = 600 ] || fatal "Access mode on \`$PWMRC' is too permissive: please set to 600."
. "$PWMRC"
fi
[ -n "$cipher" ] || cipher=-aes256
[ -n "$dbfile" ] || dbfile=~/.pwmdb
[ -n "$default_pwlen" ] || default_pwlen=30
[ -n "$EDITOR" ] || EDITOR=vi
# this has to be set before we create the history file
umask 177
if [ "$SHELL" = "$BASH" ]; then
readline_flags="-e"
[ -n "$history_file" ] || history_file=~/.pwm_history
[ -f "$history_file" ] || touch "$history_file"
history -r "$history_file"
fi
if [ -f "$dbfile" ]; then
[ $(stat -c'%a' "$dbfile") = 600 ] || fatal "Access mode on password database \`$dbfile' is too permissive: please set to 600."
fi
type openssl 2>/dev/null >&2 || fatal "OpenSSL suite is required to use Password Manager."
set -e
at_exit="echo 'Operation failed!' >&2"
trap "$at_exit" EXIT
backup_db() {
if [ -f "$dbfile" ]; then
cp "$dbfile" "${dbfile}~"
fi
}
encrypt() {
backup_db
( echo "$masterpw"; cat ) | openssl enc "$cipher" -salt -pass stdin >"$dbfile"
}
decrypt() {
if [ -f "$dbfile" ]; then
( echo "$masterpw"; cat "$dbfile" ) | openssl enc "$cipher" -d -pass stdin
else
echo -n ""
fi
}
read_masterpw() {
[ -z "$masterpw" ] || return 0
stty -echo
prompt="$1"
[ -n "$prompt" ] || prompt="master password"
read -p "${prompt}: " masterpw; echo
stty echo
}
# only prompts for master password and confirmation actually
create_db() {
echo "About to create new password database: \`$dbfile'..."
# force read
unset masterpw
read_masterpw "choose master password"
new_masterpw="$masterpw"
unset masterpw
read_masterpw "confirm master password"
if [ "$new_masterpw" != "$masterpw" ]; then
echo "Confirmation doesn't match master password: operation aborted." >&2
unset masterpw
false
fi
}
with_tempfile() {
tmp=$(tempfile -p .pwm -d "$HOME")
old_at_exit="$at_exit"
rm_tempfile_cmd="rm -f -- '$tmp'"
at_exit="$rm_tempfile_cmd; $old_at_exit"
trap "$at_exit" EXIT
eval $*
eval $rm_tempfile_cmd
at_exit="$old_at_exit"
trap "$at_exit" EXIT
tmp=''
}
read_key() {
read $readline_flags -p "$*: " key
[ -n "$history_file" ] && history -s "$key" && history -w "$history_file"
true
}
lookup() {
( decrypt | grep "${key}" ) || unset masterpw
}
store_password() {
if [ -z "$tmp" ]; then
with_tempfile store_password
else
if decrypt >"$tmp"; then
( <"$tmp" grep -v "^${key}:" || true; echo "${key}:${pw}" ) | encrypt
echo "password stored"
else
unset masterpw
fi
fi
}
edit_db() {
if [ -z "$tmp" ]; then
with_tempfile edit_db
else
if decrypt >"$tmp"; then
"$EDITOR" "$tmp"
# TODO: check if file was modified actually. mtime?
encrypt <"$tmp"
echo "password database updated"
else
unset masterpw
fi
fi
}
change_masterpw() {
if [ -z "$tmp" ]; then
with_tempfile change_masterpw
else
if masterpw="$old_masterpw" decrypt >"$tmp"; then
masterpw="$new_masterpw" encrypt <"$tmp"
echo "master password updated"
fi
fi
}
have_xclip() {
type xclip 2>/dev/null >&2
}
soak_xclip() {
xclip -in -selection clipboard -l 0
}
echo "Password Manager v0.1"
[ -f "$dbfile" ] && echo "Database file is: $dbfile"
[ -f "$history_file" ] && echo "Key history file is: $history_file"
echo
print_help() {
echo "l) Lookup password"
have_xclip && echo "x) Copy password to X clipboard (using xclip command)"
echo "s) Store password"
if have_xclip; then
echo "g[sx]) Generate password (also store and/or copy to X clipboard)"
else
echo "g[s]) Generate password (also store in the database)"
fi
echo "e) Edit password database"
echo "m) Change master password"
echo "k) Lock database"
echo "h) Print this help message"
echo "q) Quit"
}
print_help
while true; do
read -p "> " action
case "$action" in
l)
if [ ! -f "$dbfile" ]; then
echo "Password database doesn't exist yet: \`$dbfile'"
continue
fi
read_key "lookup key"
read_masterpw
key="${key}[^:]*:" lookup || echo "not found"
;;
x)
if [ ! -f "$dbfile" ]; then
echo "Password database doesn't exist yet: \`$dbfile'"
continue
fi
read_key "key to copy"
read_masterpw
pw=$(key="^${key}:" lookup || true)
if [ -z "$pw" ]; then
echo "not found"
unset masterpw
else
echo "$pw" | cut -d: -f2 | tr -d '\n' | soak_xclip
echo "soaked password for paste from X clipboard"
fi
;;
s)
[ -f "$dbfile" ] || create_db || continue
read_key "key to store"
stty -echo
read -p "password to store: " pw; echo
stty echo
read_masterpw
store_password
;;
g|gs|gx|gsx)
read -p "password length ($default_pwlen): " pwlen
[ "$pwlen" = "$(echo)" ] && pwlen="$default_pwlen"
pw=$(openssl rand -base64 "$pwlen" | tr -d '\n=' | cut -b-"$pwlen")
if [ "$action" = g ]; then
echo "$pw"
else
if [ "$action" = gs -o "$action" = gsx ]; then
[ -f "$dbfile" ] || create_db || continue
read_key "key to store"
read_masterpw
store_password
fi
if [ "$action" = gx -o "$action" = gsx ]; then
echo -n "$pw" | soak_xclip
fi
fi
;;
e)
if [ -f "$dbfile" ]; then
read_masterpw
else
create_db || continue
fi
edit_db
;;
m)
if [ ! -f "$dbfile" ]; then
echo "Password database doesn't exist yet: \`$dbfile'"
continue
fi
# force read
unset masterpw
read_masterpw "old master password"
old_masterpw="$masterpw"
unset masterpw
read_masterpw "new master password"
new_masterpw="$masterpw"
unset masterpw
read_masterpw "confirm new master password"
if [ "$new_masterpw" != "$masterpw" ]; then
echo "Confirmation doesn't match new master password: operation aborted." >&2
unset masterpw
else
change_masterpw
fi
;;
k)
unset masterpw
echo "forgot master password"
;;
h) print_help;;
q)
echo "Bye!"
break
;;
*) echo "unknown action: 'h' for help";;
esac
done
trap - EXIT
exit 0
You can’t perform that action at this time.