jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit 5437013588e4ecde4f70b3cd626e2c61f859839f
parent 170bdde0cad4de99e8fdd13f4c39971e715a4888
Author: Jaromil <jaromil@dyne.org>
Date:   Sat,  5 Dec 2015 18:28:05 +0100

password storage refactoring

less code and obsoleted native keyring, now only supporting
OSX or GNOME keyrings, or insecure cleartext configuration in Accounts

Diffstat:
Msrc/jaro | 12+++++-------
Msrc/zlibs/email | 4++--
Msrc/zlibs/keyring | 245++++++++++++++++++++++---------------------------------------------------------
3 files changed, 76 insertions(+), 185 deletions(-)

diff --git a/src/jaro b/src/jaro @@ -184,14 +184,7 @@ ADDRESSBOOK="$MAILDIRS/whitelist.abook" mkdir="`command -v mkdir` -m 700 -p" -act "Maildirs in $MAILDIRS" act "System in $WORKDIR" -${=mkdir} "$MAILDIRS" -#${=mkdir} $WORKDIR - -# make sure the permissions are private -#chmod 700 $WORKDIR -chmod 700 "$MAILDIRS" PATH=$WORKDIR/bin:/bin:/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin::/opt/local/bin @@ -262,6 +255,11 @@ hostname=$(hostname) # gather the current hostname # make sure we have an addressbook [[ -r "$ADDRESSBOOK" ]] || { create_addressbook "$ADDRESSBOOK" } + ${=mkdir} "$MAILDIRS" + + # make sure the permissions are private + chmod 700 "$MAILDIRS" + ${=mkdir} "$MAILDIRS/logs" # ${=mkdir} "$MAILDIRS/certs" diff --git a/src/zlibs/email b/src/zlibs/email @@ -373,7 +373,7 @@ smtp_send() { [[ "$password" = "" ]] && { ask_password [[ $? = 0 ]] || { - error "Error retrieving smtp password for $login on $smtp" + error "Error retrieving smtp password for $login on $host" unset password return 1 } } @@ -477,7 +477,7 @@ BEGIN { body=0 } else # normal send with msmtp - act "Sending out email via ${account:-default}" + act "Sending out email via ${account:-default} account" hdr "$qbody" | awk ' /^From:/ { print " . " $0 } /^To:/ { print " . " $0 } diff --git a/src/zlibs/keyring b/src/zlibs/keyring @@ -54,89 +54,56 @@ EOF # put it in variable password # up to the caller to unset it after use ask_password() { + fn ask_password + req=(login host email account) + ckreq || return 1 + + password="" + act "retrieving login credentials for ${email} ($account)" + act "username '$login' on host '$host'" + func "keyring path: jaromail/${login}/${host}" + + # $host is set by the caller case $OS in MAC) - func "Looking for password in Mac/OSX keyring for $email ($account)" + act "looking for password in Mac/OSX keyring" security find-internet-password \ - -c JARO -a $email -s $host > /dev/null - if [ $? != 0 ]; then # its a new password - new_password - { test $? != 0 } && { - error "Password input aborted." - return 1 } - else - password=`security find-internet-password -c JARO -a $email -s $host -g 2>&1| awk '/^password:/ { print $2 }' | sed -e 's/"//g'` - fi - return 0 + -c JARO -a $login -s $host > /dev/null + [[ $? = 0 ]] && { + act "saved password found in keyring" + password=`security find-internet-password -c JARO -a $login -s $host -g 2>&1| awk '/^password:/ { print $2 }' | sed -e 's/"//g'` + } ;; ##################################### GNU) ################### # USE GNOME KEYRING if [ "$GNOMEKEY" = "1" ]; then - func "Looking for password in Gnome keyring for $email ($account)" - func "path: jaromail/${email}" + act "looking for password in Gnome keyring" + func "path: jaromail/${login}/${host}" - print "protocol=email\npath=jaromail/${email}\nusername=${login}\nhost=${host}\n\n" \ + print "protocol=email\npath=jaromail/${login}/${host}\nusername=${login}\nhost=${host}\n\n" \ | "$WORKDIR/bin/jaro-gnome-keyring" check - if [ $? != 0 ]; then # its a new password - new_password - { test $? != 0 } && { - error "Password input aborted." - return 1 } - else # password found into gnome keyring - act "Using saved password for $login @ $host" - password=`print "protocol=email\npath=jaromail/${email}\nusername=${login}\nhost=${host}\n\n" | "$WORKDIR/bin/jaro-gnome-keyring" get` - fi - return 0 - elif [ -r "$KEYRING" ]; then - func "looking for password in local keyring for $email ($account)" - func "new pass hash for: $login:$host" - _hash=`print "$login:$host" | shasum | awk '{print $1}'` - - typeset -A keyring - zkv.load $MAILDIRS/Keyring.zkv - lookup=${keyring[$_hash]} - unset keyring - - { test "$lookup" = "" } || { - act "saved password found for $email ($transport on $host)" - notice "type the password to unlock this keyring entry:" - password="`print - $lookup | base64 -d | gpg -d --cipher-algo aes256 --openpgp --no-options`" - { test "$?" = 0 } || { error "incorrect password to unlock local keyring entry, operation aborted."; return 1 } - return 0 + [[ $? = 0 ]] && { + act "saved password found in keyring" + password=`print - "protocol=email\npath=jaromail/${login}/${host}\nusername=${login}\nhost=${host}\n\n" | "$WORKDIR/bin/jaro-gnome-keyring" get` } fi - #################### - # USE PINENTRY ALONE - new_password - { test $? != 0 } && { - error "Password input aborted." - return 1 } - return 0 ;; - *) - func "looking for password in local keyring for $email ($account)" - func "new pass hash for: $login:$host" - _hash=`print "$login:$host" | shasum | awk '{print $1}'` - lookup="`lookup_secret ${_hash}`" - { test "$lookup" = "" } || { - act "saved password found for $email ($transport on $host)" - notice "type the password to unlock this keyring entry:" - password="`print - $lookup | base64 -d | gpg -d --cipher-algo aes256 --openpgp --no-options`" - { test "$?" = 0 } || { error "incorrect password to unlock local keyring entry, operation aborted."; return 1 } - return 0 - } - #################### - # USE PINENTRY ALONE - new_password - { test $? != 0 } && { - error "Password input aborted." - return 1 } - return 0 - ;; - + *) ;; esac + + [[ "$password" = "" ]] && { + act "no password found in keyring" + # use pinentry alone + new_password + [[ $? = 0 ]] || { + error "Password input aborted." + return 1 } + } + + return 0 + } lookup_secret() { @@ -150,131 +117,57 @@ EOF } new_password() { - - read_account ${account} - + fn new_password + req=(login host email account) + ckreq || return 1 + notice "Setting a new password for account $account" - act "please enter password for username '$login'" + act "Enter password for login '$login' on host '$host'" password=`pin_entry $login "on $account"` - res=0 - case $OS in - MAC) - [[ "$password" = "" ]] && { - error "No password given, operation aborted" - return 1 - } - - [[ "$imap" = "" ]] || { - security delete-internet-password \ - -c JARO -a $email -s $imap > /dev/null - res=$(( $? + $res )) - security add-internet-password \ - -c JARO -a $email -s $imap -w "${password}" - res=$(( $? + $res )) + [[ "$password" = "" ]] && { + error "No password given, operation aborted" + return 1 + } - } - - [[ "$smtp" = "" ]] || { - security delete-internet-password \ - -c JARO -a $email -s $smtp > /dev/null - res=$(( $? + $res )) - security add-internet-password \ - -c JARO -a $email -s $smtp -w "${password}" - res=$(( $? + $res )) - } - - [[ $res = 0 ]] || { - error "Error adding password to keyring." - return 1 - } - - act "New password saved in keyring" - return 0 + case $OS in + MAC) + act "using Mac/OSX keyring password storage" + security delete-internet-password \ + -c JARO -a $login -s $host > /dev/null + # we are ignoring the success of delete + security add-internet-password \ + -c JARO -a $login -s $host -w "${password}" + + if [[ $? = 0 ]]; then + notice "New password saved in Mac/OSX keyring" + else + error "Error adding password to Mac/OSX keyring." + fi ;; GNU) - - [[ "$password" = "" ]] && { - error "No password given, operation aborted" - return 1 - } - # USE GNOME KEYRING if [ "$GNOMEKEY" = "1" ]; then act "using gnome-keyring password storage" - func "path: jaromail/${email}" - for h in "$imap" "$smtp"; do - cat <<EOF | "$WORKDIR/bin/jaro-gnome-keyring" store + func "path: jaromail/${login}/${host}" + cat <<EOF | "$WORKDIR/bin/jaro-gnome-keyring" store protocol=email -path=jaromail/${email} +path=jaromail/${login}/${host} username=${login} -host=${h} +host=${host} password=${password} EOF - done - { test $? != 0 } && { error "Error saving password in Gnome keyring" } - - else # USE LOCAL KEYRING - - { test -r "$KEYRING" } || { create_keyring "$KEYRING" } - - for h in "$imap" "$smtp"; do - # calculate the hash for this entry - _hash=`print "$login:$host" | shasum | awk '{print $1}'` - typeset -A keyring - - [[ -r $MAILDIRS/Keyring.zkv ]] && { - # check if the entry is already present - zkv.load $MAILDIRS/Keyring.zkv - } - - notice "Select the password to lock this keyring entry:" - _password="`print - $password | gpg -c --cipher-algo AES256 --openpgp --no-options | base64`" - - keyring[$_hash]="$_password" - - act "saved new password in local keyring" - zkv.save keyring $MAILDIRS/Keyring.zkv - - done - + if [[ $? = 0 ]]; then + notice "New password saved in GNOME keyring" + else + error "Error saving password in GNOME keyring" + fi fi - return 0 - - ;; - *) - - { test -r "$KEYRING" } || { create_keyring "$KEYRING" } - - for h in "$imap" "$smtp"; do - # calculate the hash for this entry - _hash=`print "$login:$host" | shasum | awk '{print $1}'` - # check if the entry is already present - func "new pass hash for: $login:$host" - lookup="`lookup_secret ${_hash} rowid`" - notice "Select the password to lock this keyring entry:" - _password="`print - $password | gpg -c --cipher-algo AES256 --openpgp --no-options | base64`" - - if [ "$lookup" = "" ]; then # new entry - cat <<EOF | ${SQL} -batch "$KEYRING" -INSERT INTO secrets (hash, password) -VALUES ("${_hash}", "${_password}"); -EOF - act "saved new password in local keyring" - else # update entry - cat <<EOF | ${SQL} -batch "$KEYRING" -UPDATE secrets SET password="${_password}" WHERE hash LIKE "${_hash}"; -EOF - act "updated local keyring with new password" - fi - done - - - - ;; + *) ;; esac + return 0 }