commit 07089619b2d0e2a6a86df600c88e71a38a4e9fdd
parent 3acb6ce9fbc3d99d1bd14e8d6a9da44cc1bb6cd2
Author: Jaromil <jaromil@dyne.org>
Date:   Sun,  3 Jun 2012 18:06:32 +0200
password handling using gnome-keyring on GNU systems
Diffstat:
4 files changed, 151 insertions(+), 31 deletions(-)
diff --git a/build-gnu.sh b/build-gnu.sh
@@ -27,12 +27,12 @@ case $distro in
 	    gcc -Os -static -o fetchaddr fetchaddr.o helpers.o rfc2047.o rfc822.o;
 	cd - > /dev/null
 	echo
-	# echo "gnome-keyring"
-	# cd src/gnome-keyring
-	# [ -x jaro-gnome-keyring ] || \
-	#     gcc `pkg-config --cflags --libs glib-2.0 gnome-keyring-1` \
-	#     -O2 -o jaro-gnome-keyring jaro-gnome-keyring.c
-	# cd - > /dev/null
+	echo "gnome-keyring"
+	cd src/gnome-keyring
+#	[ -x jaro-gnome-keyring ] || \
+	    gcc `pkg-config --cflags --libs glib-2.0 gnome-keyring-1` \
+	    -O2 -o jaro-gnome-keyring jaro-gnome-keyring.c
+	cd - > /dev/null
 	echo "Done compiling."
 	echo "Now run ./install.sh and Jaro Mail will be ready in ~/Mail"
 	echo "or \"./install.sh path\" to install it somewhere else."
diff --git a/install.sh b/install.sh
@@ -244,6 +244,7 @@ for mod in ${lbdb_modules}; do
 done
 cp src/lbdb/dotlock $WORKDIR/.lbdb/
 cp src/lbdb/fetchaddr $WORKDIR/.lbdb/
+cp src/gnome-keyring/jaro-gnome-keyring $WORKDIR/bin/
 chmod +x $WORKDIR/.lbdb/*
 ln -sf $WORKDIR/.lbdb/lbdb-fetchaddr $WORKDIR/bin/
 ln -sf $WORKDIR/.lbdb/lbdbq $WORKDIR/bin/
diff --git a/src/gnome-keyring/jaro-gnome-keyring.c b/src/gnome-keyring/jaro-gnome-keyring.c
@@ -1,3 +1,26 @@
+/* Jaro Mail gnome keyring handler
+
+   Originally from some Gnome example code, slightly modified
+
+   Copyright (C) 2012 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.
+   
+*/
+
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -36,7 +59,7 @@ error(const char *err, ...)
     va_end(params);
 }
 
-static void
+static int
 get_password(git_credential_t *cred)
 {
     GnomeKeyringResult keyres;
@@ -50,13 +73,34 @@ get_password(git_credential_t *cred)
 					      "username", cred->username,
 					      NULL);
     if (keyres != GNOME_KEYRING_RESULT_OK) {
-	return;
+	return 1;
     }
-    g_printf("password=%s\n", pass);
+    g_printf("%s\n", pass);
     gnome_keyring_free_password(pass);
+    return 0;
 }
 
-static void
+static int
+check_password(git_credential_t *cred)
+{
+    GnomeKeyringResult keyres;
+    gchar *pass = NULL;
+    
+    keyres = gnome_keyring_find_password_sync(&git_schema,
+					      &pass,
+					      "protocol", cred->protocol,
+					      "host", cred->host,
+					      "path", cred->path,
+					      "username", cred->username,
+					      NULL);
+    if (keyres != GNOME_KEYRING_RESULT_OK) {
+	return 1;
+    }
+    gnome_keyring_free_password(pass);
+    return 0;
+}
+
+static int
 store_password(git_credential_t *cred)
 {
     gchar desc[1024];
@@ -65,7 +109,7 @@ store_password(git_credential_t *cred)
     /* Only store complete credentials */
     if (!cred->protocol || !cred->host ||
        	!cred->username || !cred->password)
-	return;
+      return 1;
 
     g_snprintf(desc, sizeof(desc), "Git %s", cred->host);
     keyres = gnome_keyring_store_password_sync(&git_schema,
@@ -79,11 +123,12 @@ store_password(git_credential_t *cred)
 					       NULL);
     if (keyres != GNOME_KEYRING_RESULT_OK) {
 	error("failed to store password");
-	return;
+	return 1;
     }
+    return 0;
 }
 
-static void
+static int
 erase_password(git_credential_t *cred)
 {
     GnomeKeyringResult keyres;
@@ -96,8 +141,9 @@ erase_password(git_credential_t *cred)
 						NULL);
     if (keyres != GNOME_KEYRING_RESULT_OK) {
 	error("failed to delete password");
-	return;
+	return 1;
     }
+    return 0;
 }
 
 static int
@@ -147,6 +193,7 @@ int
 main(int argc, const char **argv)
 {
     git_credential_t cred = {0};
+    int res = 0;
 
     if (argc < 2) {
 	error("Usage: git credential-gnomekeyring <get|store|erase>");
@@ -159,15 +206,18 @@ main(int argc, const char **argv)
     }
 
     if (strcmp(argv[1], "get") == 0) {
-	get_password(&cred);
+      res = get_password(&cred);
+    }
+    if (strcmp(argv[1], "check") == 0) {
+      res = check_password(&cred);
     }
     else if (strcmp(argv[1], "store") == 0) {
-	store_password(&cred);
+      res = store_password(&cred);
     }
     else if (strcmp(argv[1], "erase") == 0) {
-	erase_password(&cred);
+      res = erase_password(&cred);
     }
     clear_credential(&cred);
 
-    return 0;
+    return res;
 }
diff --git a/src/jaro b/src/jaro
@@ -222,9 +222,10 @@ ask_password() {
 	    func "Looking for password in keyring: $1 @ $2"
 	    security find-internet-password -a $1 -s $2 > /dev/null
 	    if [ $? != 0 ]; then # its a new password
-		password=`pin_entry $1 @ $2`
-		act "New password set for $1 @ $2"
-		security add-internet-password -a $1 -s $2 -w "${password}"
+		new_password
+		{ test $? = 0 } && {
+		    error "Password input aborted."
+		    return 1 }
 	    else
 		act "Using saved password for $1 @ $2"
 		password=`security find-internet-password -a $1 -s $2 -g \
@@ -232,20 +233,70 @@ ask_password() {
 	    fi
 	    return 0
 	    ;;
+	#####################################
 	GNU)
+	    func "Looking for password in keyring: $1 @ $2"
+	    echo "protocol=${type}\npath=jaromail/${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=`echo "protocol=${type}\npath=jaromail/${email}\nusername=${login}\nhost=${host}\n\n" | $WORKDIR/bin/jaro-gnome-keyring get`
+	    fi
+	    return 0
+	    ;;
+	*)
+	    error "Unknown system, can't figure out how to handle passwords"
+	    return 1
+    esac
+}
+
+new_password() {
+    case $OS in
+	MAC)
+	    password=`pin_entry $1 $2`
+	    act "New password set for $1 @ $2"
+	    security add-internet-password -a $1 -s $2 -w "${password}"
+	    # TODO: erase and error codes
+	    ;;
+	GNU)
+	    notice "Setting a new password for $login @ $host"
 	    password=`pin_entry $login $host`
 	    if [ "$password" != "" ]; then
+		cat <<EOF | $WORKDIR/bin/jaro-gnome-keyring store
+protocol=${type}
+path=jaromail/${email}
+username=${login}
+host=${host}
+password=${password}
+EOF
+		{ test $? != 0 } && {
+		    unset password
+		    error "Error saving password in Gnome keyring"
+		    return 1 }
 		return 0
 	    else
-		return 1
-	    fi
+		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		
 	    ;;
 	*)
 	    error "Unknown system, can't figure out how to handle passwords"
 	    return 1
     esac
 }
-
 switch_identity() {
     if [ "$name" != "" ]; then
 	act "switch to identity: $name <$login>"
@@ -304,8 +355,9 @@ maildirmake() {
 read_account() {
     typeset -al all
 
-    if [ -z $1 ]; then type="*"
-
+    if [ -z $1 ]; then
+	type=`echo $account | cut -d. -f1`
+	account=`echo $account | cut -d. -f2`
     else type=$1 # smtp, imap, pop ... file prefixes"
     fi
 
@@ -313,12 +365,14 @@ read_account() {
     for a in `find $WORKDIR/Accounts -name "$type.$account*"`; do all+=($a); done
     if [ ${#all} = 0 ]; then
 	error "No $type account found: $account"
+	error "Refine your argument using 'type.account'"
+	error "For instance: imap.default or smtp.default"
 	return 1
     elif [ ${#all} != 1 ]; then
 	error "Too many $type accounts named $account"
 	act -n ""
 	for i in ${=all}; do echo -n "`basename ${i}` "; done
-	echo; error "Refine your account keyword"
+	echo; error "Refine your account keyword using -a option"
 	return 1
     fi
 
@@ -557,11 +611,10 @@ fetch() {
 
     notice "Fetching mails for $name"
     ask_password $login $host
-    if [ $? != 0 ]; then
+    { test $? != 0 } && {
 	error "Error retrieving password for $login on $host"
-	unset password all
-	return 1
-    fi
+	unset password all; return 1
+    }
 
     newlock $WORKDIR/tmp/$host.fetch
     cat <<EOF > $WORKDIR/tmp/$host.fetch
@@ -663,6 +716,10 @@ send() {
 
 
     ask_password $login $host
+    { test $? != 0 } && {
+	error "Error retrieving password for $login on $host"
+	unset password all; return 1
+    }
 
     newlock $WORKDIR/tmp/$host.send
     cat <<EOF > $WORKDIR/tmp/$host.send
@@ -733,6 +790,12 @@ peek() {
     sleep 2
     # escape at sign in login
     ilogin=`echo $login | sed 's/@/\\@/'`
+    ask_password $login $host
+    { test $? != 0 } && {
+	error "Error retrieving password for $login on $host"
+	unset password all; return 1
+    }
+
     mutt -F $MUTTDIR/rc -f ${iproto}://${ilogin}@${host}${folder}
     # TODO automatic input of password in mutt
     return $?
@@ -1142,6 +1205,8 @@ Options:
 
 Maintenance commands:
 
+ passwd   reset password for the account in use
+
  update   refresh configurations
  queue    add a mail into outbox
 
@@ -1190,6 +1255,7 @@ main()
     subcommands_opts[merge]=""
     subcommands_opts[filter]=""
 
+    subcommands_opts[passwd]=""
     subcommands_opts[cert]=""
 
     subcommands_opts[source]=""
@@ -1290,6 +1356,9 @@ main()
 	merge)   merge ${PARAM} ;;
 	filter)  filter ${PARAM} ;;
 
+	passwd)  read_account;
+	    { test $? = 0 } && { new_password ${PARAM} }
+	    ;;
 	cert)    cert ${PARAM} ;;
 
 	'source')   CLEANEXIT=0; return 0 ;;