commit 22cb9f38bbd02be39310c63ec847b5a1ece9da7e
parent 82ede1c06ce4d3c0666832de2b1f48cab58fbc90
Author: Jaromil <jaromil@dyne.org>
Date: Fri, 2 May 2014 14:39:30 +0200
fixes to keyring handling and configuration checks for gnu systems
Diffstat:
5 files changed, 319 insertions(+), 261 deletions(-)
diff --git a/src/jaro b/src/jaro
@@ -180,6 +180,10 @@ else
exit 1
fi
+ACCOUNTS="$MAILDIRS/Accounts"
+KEYRING="$MAILDIRS/Keyring"
+addressbook="$MAILDIRS/Addressbook"
+
# temporary directory
TMPDIR="$MAILDIRS/tmp/jaromil.$USER"
case $OS in
@@ -190,6 +194,20 @@ case $OS in
TMPDIR=/dev/shm/tmp.jaromail.$USER
TMPRAM=1
}
+
+ # backward compatibility tests for old paths in JaroMail <1.3
+ { test -d $WORKDIR/Accounts } && { test ! -d $ACCOUNTS } && {
+ act "Updating accounts location: $ACCOUNTS"
+ cp -ra $WORKDIR/Accounts $ACCOUNTS }
+
+ { test -r "$WORKDIR/keyring" } && { test ! -r "$KEYRING" } && {
+ act "Updating keyring location: $KEYRING"
+ cp $WORKDIR/keyring "$KEYRING" }
+
+ { test -r $WORKDIR/addressbook } && { test ! -r $addressbook } && {
+ act "Updating addressbook location: $addressbook"
+ cp $WORKDIR/addressbook $addressbook }
+
;;
MAC)
mount | grep 'JaroTmp' > /dev/null
@@ -201,38 +219,25 @@ case $OS in
;;
esac
+# use the TMP in RAM if possible, for acceleration
{ test $TMPRAM = 1 } && {
act "Using temporary directory in volatile RAM" }
-
# make sure we have a temp dir
${=mkdir} "$TMPDIR"
{ test $? != 0 } && {
error "Cannot create temporary directory: $TMPDIR"
return 1 }
-# make sure we have an addressbook
-# use the one in RAM if present, for acceleration
hostname=$(hostname) # gather the current hostname
+# make sure we have a directory for account configurations
+{ test -d $ACCOUNTS } || { mkdir -p $ACCOUNTS }
-ACCOUNTS="$MAILDIRS/Accounts"
-KEYRING="$MAILDIRS/Keyring"
-addressbook="$MAILDIRS/Addressbook"
-
-# backward compatibility tests for old paths in JaroMail <1.3
-{ test -r $WORKDIR/Accounts } && { test ! -r $ACCOUNTS } && {
- act "Updating accounts location: $ACCOUNTS"
- cp -r $WORKDIR/Accounts $ACCOUNTS }
-
-{ test -r $WORKDIR/keyring } && { test ! -r $KEYRING } && {
- act "Updating keyring location: $KEYRING"
- cp $WORKDIR/keyring $KEYRING }
-
-{ test -r $WORKDIR/addressbook } && { test ! -r $addressbook } && {
- act "Updating addressbook location: $addressbook"
- cp $WORKDIR/addressbook $addressbook }
+# make sure we have a local keyring in case system-wide not found
+{ test -r "$KEYRING" } || { create_keyring "$KEYRING" }
+# make sure we have an addressbook
addressbook_tmp=$TMPDIR/${USER}.${hostname}.addressbook
{ test -r "$addressbook" } || { create_addressbook }
{ test -r "$addressbook_tmp" } && { addressbook="$addressbook_tmp" }
@@ -244,6 +249,30 @@ PROCMAILDIR=$MAILDIRS/.procmail
MUTTDIR=$MAILDIRS/.mutt
+# make sure we have Filters.txt Applications.txt Mutt.txt
+if ! [ -r $MAILDIRS/Filters.txt ]; then
+ cp -v doc/Filters.txt $MAILDIRS/Filters.txt
+ act "Default filters created"
+else
+ error "Existing configuration $MAILDIRS/Filters.txt skipped"
+fi
+
+if ! [ -r $MAILDIRS/Applications.txt ]; then
+ cp -v doc/Applications.txt $MAILDIRS/Applications.txt
+ act "Default helper applications settings created"
+else
+ error "Existing configuration $MAILDIRS/Applications.txt skipped"
+fi
+
+
+if ! [ -r $MAILDIRS/Mutt.txt ]; then
+ cp -v doc/Mutt.txt $MAILDIRS/Mutt.txt
+ act "Default Mutt configuration template created"
+else
+ error "Existing configuration $MAILDIRS/Mutt.txt skipped"
+fi
+
+
# use gnome-keyring for passwords on GNU systems
GNOMEKEY=0
{ test $GNOME_KEYRING_CONTROL } && {
@@ -326,10 +355,10 @@ check_bin() {
done
# make sure a gnupg dir exists
- { test -r $HOME/.gnupg/pubring.gpg } || {
- mkdir -p $HOME/.gnupg
- touch $HOME/.gnupg/pubring.gpg
- touch $HOME/.gnupg/secring.gpg
+ { test -r $HOME/.gnupg/pubring.gpg } || {
+ mkdir -p $HOME/.gnupg
+ touch $HOME/.gnupg/pubring.gpg
+ touch $HOME/.gnupg/secring.gpg
}
# which find command to use
@@ -338,7 +367,7 @@ check_bin() {
MAC) find="gfind -O3" ;;
*) find="find"
esac
-
+
# which wipe command to use
if command -v wipe > /dev/null; then
rm="wipe -f -s -q -R /dev/urandom"
@@ -442,15 +471,15 @@ a pipe | in front indicate they take an email body from stdin
account names correspond to the filenames, i.e. imap.default
fetch downloads emails locally from an $account on-line
- option "keep" (default) to avoid deleting from servers
+ option "keep" (default) to avoid deleting from servers
send send all emails queued in outbox/ to an smtp.$account
peek connect to an imap.$account with ncurses terminal mutt
- remote folders supported. use to delete without download
+ remote folders supported. use to delete without download
passwd set account passwords in the OS native keyring
- or into a simple, file based, gpg encrypted database.
+ or into a simple, file based, gpg encrypted database.
|queue queue a mail in outbox/ for send
@@ -462,7 +491,7 @@ maildirs are directories of mails downloaded in Mail/
open open a maildir folder (can use -R for read-only)
backup (mairix) move mails from a maildir to another one
- match mails to move based on date ranges or strings
+ match mails to move based on date ranges or strings
rmdupes remove all duplicated e-mails into a maildir
@@ -572,7 +601,7 @@ main()
act "try -h for help"
CLEANEXIT=0
}
- return $exitcode
+ return $exitcode
fi
argv=(${oldstar})
diff --git a/src/zlibs/accounts b/src/zlibs/accounts
@@ -4,7 +4,7 @@
#
# a tool to easily and privately handle your e-mail communication
#
-# Copyleft (C) 2010-2012 Denis Roio <jaromil@dyne.org>
+# Copyleft (C) 2010-2014 Denis Roio <jaromil@dyne.org>
#
# This source code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Public License as published by
@@ -156,228 +156,3 @@ read_account() {
return 0
}
-
-# we use pinentry
-# comes from gpg project and is secure
-# it also conveniently uses the right toolkit
-pin_entry() {
- cat <<EOF | pinentry 2>/dev/null | awk '/^D / { sub(/^D /, ""); print }'
-OPTION ttyname=$TTY
-OPTION lc-ctype=$LANG
-SETTITLE Type your password
-SETDESC Type the password for $1 @ $2
-SETPROMPT Password:
-GETPIN
-EOF
-}
-
-
-# retrieve a password for user @ domain
-# put it in variable password
-# up to the caller to unset it after use
-ask_password() {
- case $OS in
- MAC)
- func "Looking for password in Mac/OSX keyring for $email on $host over $type"
- security find-internet-password \
- -c JARO -a $email -s $host \
- -p $transport -P $port > /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 -p $transport -P $port -g 2>&1| awk '/^password:/ { print $2 }' | sed -e 's/"//g'`
- fi
- return 0
- ;;
- #####################################
- GNU)
- ###################
- # USE GNOME KEYRING
- if [ "$GNOMEKEY" = "1" ]; then
- func "Looking for password in Gnome keyring for $email on $host over $type"
- func "path: jaromail/${type}/${email}"
-
- print "protocol=${type}\npath=jaromail/${type}/${email}\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 $1 @ $2"
- password=`print "protocol=${type}\npath=jaromail/${type}/${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 $type account $account on $host"
- func "new pass hash for: $type:$login:$host"
- _hash=`print "$type:$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
- }
- fi
- ####################
- # USE PINENTRY ALONE
- new_password
- { test $? != 0 } && {
- error "Password input aborted."
- return 1 }
- return 0
- ;;
- *)
- error "Unknown system, can't figure out how to handle passwords"
- return 1
- esac
-}
-
-lookup_secret() {
- _hash=$1
- if [ "$2" = "" ]; then key=password
- else key="$2"; fi
- cat <<EOF | ${SQL} -column -batch $KEYRING
-SELECT ${key} FROM secrets
-WHERE hash IS "${_hash}";
-EOF
-}
-
-new_password() {
- notice "Setting a new password for $type account $account on $host"
- act "please enter password for username '$login'"
- password=`pin_entry $login $host`
- res=0
- case $OS in
- MAC)
- if [ "$password" != "" ]; then
-
- security delete-internet-password \
- -c JARO -a $email -s $host \
- -p $transport -P $port > /dev/null
-
- security add-internet-password \
- -c JARO -a $email -s $host \
- -p $transport -P $port -w "${password}"
-
- if [ $? != 0 ]; then
- error "Error adding password to keyring."
- else
- act "New password saved in keyring"
- fi
- return 0
-
- else
- error "No password given, operation aborted"
- return 1
-
- # we are not deleting passwords anymore
- security delete-internet-password \
- -c JARO -a $email -s $host \
- -p $transport -P $port > /dev/null
- res=$?; unset password
- { test $res != 0 } && {
- echo
- error "Error deleting password from keyring."
- return 1 }
- act "No new password given, old password erased."
- return 0
- #########
-
- fi
- ;;
- GNU)
- if [ "$password" != "" ]; then # password was written
-
- # USE GNOME KEYRING
- if [ "$GNOMEKEY" = "1" ]; then
- act "using gnome-keyring password storage"
- func "path: jaromail/${type}/${email}"
- cat <<EOF | $WORKDIR/bin/jaro-gnome-keyring store
-protocol=${type}
-path=jaromail/${type}/${email}
-username=${login}
-host=${host}
-password=${password}
-EOF
- { test $? != 0 } && { error "Error saving password in Gnome keyring" }
-
- else # save it into local keyring
-
- { test -r $KEYRING } || {
- # make sure the local keyring exists
- touch $KEYRING
- chmod 600 $KEYRING
- chown $_uid:$_gid $KEYRING
- cat <<EOF | ${SQL} -batch $KEYRING
-CREATE TABLE secrets
-(
- hash text unique,
- password text
-);
-EOF
- }
- # calculate the hash for this entry
- _hash=`print "$type:$login:$host" | shasum | awk '{print $1}'`
- # check if the entry is already present
- func "new pass hash for: $type:$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
- fi
-
- return 0
-
- else # password is blank or aborted
-
- # save it into gnome keyring
- if [ $GNOMEKEY = 1 ]; then
-
- cat <<EOF | $WORKDIR/bin/jaro-gnome-keyring erase
-protocol=${type}
-path=jaromail/${email}
-username=${login}
-host=${host}
-EOF
- { test $? != 0 } && {
- error "Error accessing password in Gnome keyring"
- return 1 }
- act "No new password given, old password erased."
- return 0
- fi
- # TODO: delete from local keyring
-
- fi
- ;;
- *)
- error "Unknown system, can't figure out how to handle passwords"
- return 1
- esac
-}
-
-change_password() {
-
- read_account ${=PARAM}
-
- { test $? = 0 } && { test $DRYRUN != 1 } && {
- new_password }
-
-}
diff --git a/src/zlibs/addressbook b/src/zlibs/addressbook
@@ -27,11 +27,11 @@ ADDRESSBOOK=$MAILDIRS/Addressbook
# Jaro Brother DB
create_addressbook() {
func "create addressbook"
- { test -r "$ADDRESSBOOK" } && {
- error "Addressbook already exists: $ADDRESSBOOK"
+ { test -r "$1" } && {
+ error "Addressbook already exists: $1"
return 1
}
- cat <<EOF | ${SQL} -batch $ADDRESSBOOK
+ cat <<EOF | ${SQL} -batch "$1"
CREATE TABLE whitelist
(
email text collate nocase unique,
@@ -47,8 +47,8 @@ EOF
error "Error creating addressbook database."
return 1 }
# make sure is private
- chmod 600 $ADDRESSBOOK
- chown $_uid:$_gid $ADDRESSBOOK
+ chmod 600 "$1"
+ chown $_uid:$_gid "$1"
return 0
}
diff --git a/src/zlibs/filters b/src/zlibs/filters
@@ -126,6 +126,8 @@ text/html; lynx -dump -assume_charset=%{charset} %s; nametemplate=%s.html; copio
EOF
fi
+ { test -r ${MAILDIRS}/Applications.txt } && {
+
apptypes=`cat ${MAILDIRS}/Applications.txt`
for t in ${(f)apptypes}; do
eval `print $t | awk '
@@ -137,6 +139,8 @@ EOF
cat <<EOF >> $MUTTDIR/mailcap
application/*; a="${TMPDIR}" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && jaro preview "\$a"/"\$f"
EOF
+ } # Applications.txt
+
# this one is empty and sources files in temp when necessary
# touch $TMPDIR/muttpass
@@ -197,7 +201,7 @@ EOF
# continue later on while we parse filters
-
+touch $MAILDIRS/Filters.txt
##########
# PROCMAIL
diff --git a/src/zlibs/keyring b/src/zlibs/keyring
@@ -0,0 +1,250 @@
+#!/usr/bin/env zsh
+#
+# Jaro Mail, your humble and faithful electronic postman
+#
+# a tool to easily and privately handle your e-mail communication
+#
+# Copyleft (C) 2014 Denis Roio <jaromil@dyne.org>
+#
+# This source code is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This source code is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# Please refer to the GNU Public License for more details.
+#
+# You should have received a copy of the GNU Public License along with
+# this source code; if not, write to:
+# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+create_keyring() {
+ # make sure the local keyring exists
+ touch "$1"
+ chmod 600 "$1"
+ chown $_uid:$_gid "$1"
+ cat <<EOF | ${SQL} -batch "$1"
+CREATE TABLE secrets
+(
+ hash text unique,
+ password text
+);
+EOF
+}
+
+
+# we use pinentry
+# comes from gpg project and is secure
+# it also conveniently uses the right toolkit
+pin_entry() {
+ cat <<EOF | pinentry 2>/dev/null | awk '/^D / { sub(/^D /, ""); print }'
+OPTION ttyname=$TTY
+OPTION lc-ctype=$LANG
+SETTITLE Type your password
+SETDESC Type the password for $1 @ $2
+SETPROMPT Password:
+GETPIN
+EOF
+}
+
+
+# retrieve a password for user @ domain
+# put it in variable password
+# up to the caller to unset it after use
+ask_password() {
+ case $OS in
+ MAC)
+ func "Looking for password in Mac/OSX keyring for $email on $host over $type"
+ security find-internet-password \
+ -c JARO -a $email -s $host \
+ -p $transport -P $port > /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 -p $transport -P $port -g 2>&1| awk '/^password:/ { print $2 }' | sed -e 's/"//g'`
+ fi
+ return 0
+ ;;
+ #####################################
+ GNU)
+ ###################
+ # USE GNOME KEYRING
+ if [ "$GNOMEKEY" = "1" ]; then
+ func "Looking for password in Gnome keyring for $email on $host over $type"
+ func "path: jaromail/${type}/${email}"
+
+ print "protocol=${type}\npath=jaromail/${type}/${email}\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 $1 @ $2"
+ password=`print "protocol=${type}\npath=jaromail/${type}/${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 $type account $account on $host"
+ func "new pass hash for: $type:$login:$host"
+ _hash=`print "$type:$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
+ }
+ fi
+ ####################
+ # USE PINENTRY ALONE
+ new_password
+ { test $? != 0 } && {
+ error "Password input aborted."
+ return 1 }
+ return 0
+ ;;
+ *)
+ error "Unknown system, can't figure out how to handle passwords"
+ return 1
+ esac
+}
+
+lookup_secret() {
+ _hash=$1
+ if [ "$2" = "" ]; then key=password
+ else key="$2"; fi
+ cat <<EOF | ${SQL} -column -batch $KEYRING
+SELECT ${key} FROM secrets
+WHERE hash IS "${_hash}";
+EOF
+}
+
+new_password() {
+ notice "Setting a new password for $type account $account on $host"
+ act "please enter password for username '$login'"
+ password=`pin_entry $login $host`
+ res=0
+ case $OS in
+ MAC)
+ if [ "$password" != "" ]; then
+
+ security delete-internet-password \
+ -c JARO -a $email -s $host \
+ -p $transport -P $port > /dev/null
+
+ security add-internet-password \
+ -c JARO -a $email -s $host \
+ -p $transport -P $port -w "${password}"
+
+ if [ $? != 0 ]; then
+ error "Error adding password to keyring."
+ else
+ act "New password saved in keyring"
+ fi
+ return 0
+
+ else
+ error "No password given, operation aborted"
+ return 1
+
+ # we are not deleting passwords anymore
+ security delete-internet-password \
+ -c JARO -a $email -s $host \
+ -p $transport -P $port > /dev/null
+ res=$?; unset password
+ { test $res != 0 } && {
+ echo
+ error "Error deleting password from keyring."
+ return 1 }
+ act "No new password given, old password erased."
+ return 0
+ #########
+
+ fi
+ ;;
+ GNU)
+ if [ "$password" != "" ]; then # password was written
+
+ # USE GNOME KEYRING
+ if [ "$GNOMEKEY" = "1" ]; then
+ act "using gnome-keyring password storage"
+ func "path: jaromail/${type}/${email}"
+ cat <<EOF | $WORKDIR/bin/jaro-gnome-keyring store
+protocol=${type}
+path=jaromail/${type}/${email}
+username=${login}
+host=${host}
+password=${password}
+EOF
+ { test $? != 0 } && { error "Error saving password in Gnome keyring" }
+
+ else # save it into local keyring
+
+ { test -r "$KEYRING" } || { create_keyring "$KEYRING" }
+
+ # calculate the hash for this entry
+ _hash=`print "$type:$login:$host" | shasum | awk '{print $1}'`
+ # check if the entry is already present
+ func "new pass hash for: $type:$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
+ fi
+
+ return 0
+
+ else # password is blank or aborted
+
+ # save it into gnome keyring
+ if [ $GNOMEKEY = 1 ]; then
+
+ cat <<EOF | $WORKDIR/bin/jaro-gnome-keyring erase
+protocol=${type}
+path=jaromail/${email}
+username=${login}
+host=${host}
+EOF
+ { test $? != 0 } && {
+ error "Error accessing password in Gnome keyring"
+ return 1 }
+ act "No new password given, old password erased."
+ return 0
+ fi
+ # TODO: delete from local keyring
+
+ fi
+ ;;
+ *)
+ error "Unknown system, can't figure out how to handle passwords"
+ return 1
+ esac
+}
+
+change_password() {
+
+ read_account ${=PARAM}
+
+ { test $? = 0 } && { test $DRYRUN != 1 } && {
+ new_password }
+
+}