Bläddra i källkod

add PassCmd option to query IMAP password dynamically

inspired by patches by
Aurélien Francillon <aurelien.francillon@eurecom.fr>,
Martin Stenberg <martin@gnutiken.se> and
sbfnk@users.sf.net.
Oswald Buddenhagen 12 år sedan
förälder
incheckning
bf049d6466
3 ändrade filer med 64 tillägg och 3 borttagningar
  1. 41 1
      src/drv_imap.c
  2. 9 2
      src/mbsync.1
  3. 14 0
      src/mbsyncrc.sample

+ 41 - 1
src/drv_imap.c

@@ -31,6 +31,7 @@
 #include <limits.h>
 #include <string.h>
 #include <ctype.h>
+#include <sys/wait.h>
 
 typedef struct imap_server_conf {
 	struct imap_server_conf *next;
@@ -38,6 +39,7 @@ typedef struct imap_server_conf {
 	server_conf_t sconf;
 	char *user;
 	char *pass;
+	char *pass_cmd;
 	int max_in_progress;
 #ifdef HAVE_LIBSSL
 	unsigned require_ssl:1;
@@ -1404,7 +1406,35 @@ imap_open_store_authenticate2( imap_store_t *ctx )
 		error( "Skipping account %s, no user\n", srvc->name );
 		goto bail;
 	}
-	if (!srvc->pass) {
+	if (srvc->pass_cmd) {
+		FILE *fp;
+		int ret;
+		char buffer[80];
+
+		if (!(fp = popen( srvc->pass_cmd, "r" ))) {
+		  pipeerr:
+			sys_error( "Skipping account %s, password command failed", srvc->name );
+			goto bail;
+		}
+		if (!fgets( buffer, sizeof(buffer), fp ))
+			buffer[0] = 0;
+		if ((ret = pclose( fp )) < 0)
+			goto pipeerr;
+		if (ret) {
+			if (WIFSIGNALED( ret ))
+				error( "Skipping account %s, password command crashed\n", srvc->name );
+			else
+				error( "Skipping account %s, password command exited with status %d\n", srvc->name, WEXITSTATUS( ret ) );
+			goto bail;
+		}
+		if (!buffer[0]) {
+			error( "Skipping account %s, password command produced no output\n", srvc->name );
+			goto bail;
+		}
+		buffer[strcspn( buffer, "\n" )] = 0; /* Strip trailing newline */
+		free( srvc->pass ); /* From previous runs */
+		srvc->pass = nfstrdup( buffer );
+	} else if (!srvc->pass) {
 		char prompt[80];
 		sprintf( prompt, "Password (%s): ", srvc->name );
 		arg = getpass( prompt );
@@ -1958,6 +1988,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			server->user = nfstrdup( cfg->val );
 		else if (!strcasecmp( "Pass", cfg->cmd ))
 			server->pass = nfstrdup( cfg->val );
+		else if (!strcasecmp( "PassCmd", cfg->cmd ))
+			server->pass_cmd = nfstrdup( cfg->val );
 		else if (!strcasecmp( "Port", cfg->cmd ))
 			server->sconf.port = parse_int( cfg );
 		else if (!strcasecmp( "PipelineDepth", cfg->cmd )) {
@@ -2028,6 +2060,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			cfg->err = 1;
 			return 1;
 		}
+		if (server->pass && server->pass_cmd) {
+			if (store)
+				error( "IMAP store '%s' has both Pass and PassCmd\n", store->gen.name );
+			else
+				error( "IMAP account '%s' has both Pass and PassCmd\n", server->name );
+			cfg->err = 1;
+			return 1;
+		}
 	}
 	if (store) {
 		if (!store->server) {

+ 9 - 2
src/mbsync.1

@@ -249,8 +249,15 @@ Specify the login name on the IMAP server.  (Default: current local user)
 \fBPass\fR \fIpassword\fR
 Specify the password for \fIusername\fR on the IMAP server.
 Note that this option is \fBNOT\fR required.
-If no password is specified in the configuration file, \fBmbsync\fR
-will prompt you for it.
+If neither a password nor a password command is specified in the
+configuration file, \fBmbsync\fR will prompt you for a password.
+..
+.TP
+\fBPassCmd\fR \fIcommand\fR
+Specify a shell command to obtain a password rather than specifying a
+password directly. This allows you to use password files and agents.
+The command must produce exactly one line on stdout; the trailing newline is
+optional.
 ..
 .TP
 \fBTunnel\fR \fIcommand\fR

+ 14 - 0
src/mbsyncrc.sample

@@ -11,7 +11,21 @@ Trash Trash
 
 IMAPStore work
 Host work.host.com
+User tehuser
 Pass xxxxxxxx
+# Fetch password from gnome-keyring:
+#PassCmd "gnome-keyring-query get mail_pw"
+# Fetch password from .netrc:
+#PassCmd "sed -n -e 's,^machine work\.host\.com login tehuser password \(.*\),\1,p' < $HOME/.netrc"
+# Fetch password from a gpg-encrypted file:
+#PassCmd "gpg --quiet --for-your-eyes-only --decrypt $HOME/imappassword.gpg"
+# Fetch password from pwmd (http://bjk.sourceforge.net/pwmd/):
+#PassCmd "echo -ne 'GET myIsp\tpassword' | pwmc datafile"
+# On Mac OS X, run "KeyChain Access" -- File->New Password Item. Fill out form using
+#  "Keychain Item Name" http://IMAPSERVER  (note: the "http://" is a hack)
+#  "Account Name" USERNAME
+#  "Password" PASSWORD
+#PassCmd "/usr/bin/security find-internet-password -w -a USERNAME -s IMAPSERVER ~/Library/Keychains/login.keychain"
 CertificateFile /etc/ssl/certs/ca-certificates.crt
 
 Channel work