Selaa lähdekoodia

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 vuotta sitten
vanhempi
sitoutus
bf049d6466
3 muutettua tiedostoa jossa 64 lisäystä ja 3 poistoa
  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 <limits.h>
 #include <string.h>
 #include <string.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <sys/wait.h>
 
 
 typedef struct imap_server_conf {
 typedef struct imap_server_conf {
 	struct imap_server_conf *next;
 	struct imap_server_conf *next;
@@ -38,6 +39,7 @@ typedef struct imap_server_conf {
 	server_conf_t sconf;
 	server_conf_t sconf;
 	char *user;
 	char *user;
 	char *pass;
 	char *pass;
+	char *pass_cmd;
 	int max_in_progress;
 	int max_in_progress;
 #ifdef HAVE_LIBSSL
 #ifdef HAVE_LIBSSL
 	unsigned require_ssl:1;
 	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 );
 		error( "Skipping account %s, no user\n", srvc->name );
 		goto bail;
 		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];
 		char prompt[80];
 		sprintf( prompt, "Password (%s): ", srvc->name );
 		sprintf( prompt, "Password (%s): ", srvc->name );
 		arg = getpass( prompt );
 		arg = getpass( prompt );
@@ -1958,6 +1988,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			server->user = nfstrdup( cfg->val );
 			server->user = nfstrdup( cfg->val );
 		else if (!strcasecmp( "Pass", cfg->cmd ))
 		else if (!strcasecmp( "Pass", cfg->cmd ))
 			server->pass = nfstrdup( cfg->val );
 			server->pass = nfstrdup( cfg->val );
+		else if (!strcasecmp( "PassCmd", cfg->cmd ))
+			server->pass_cmd = nfstrdup( cfg->val );
 		else if (!strcasecmp( "Port", cfg->cmd ))
 		else if (!strcasecmp( "Port", cfg->cmd ))
 			server->sconf.port = parse_int( cfg );
 			server->sconf.port = parse_int( cfg );
 		else if (!strcasecmp( "PipelineDepth", cfg->cmd )) {
 		else if (!strcasecmp( "PipelineDepth", cfg->cmd )) {
@@ -2028,6 +2060,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			cfg->err = 1;
 			cfg->err = 1;
 			return 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) {
 		if (!store->server) {
 		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
 \fBPass\fR \fIpassword\fR
 Specify the password for \fIusername\fR on the IMAP server.
 Specify the password for \fIusername\fR on the IMAP server.
 Note that this option is \fBNOT\fR required.
 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
 .TP
 \fBTunnel\fR \fIcommand\fR
 \fBTunnel\fR \fIcommand\fR

+ 14 - 0
src/mbsyncrc.sample

@@ -11,7 +11,21 @@ Trash Trash
 
 
 IMAPStore work
 IMAPStore work
 Host work.host.com
 Host work.host.com
+User tehuser
 Pass xxxxxxxx
 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
 CertificateFile /etc/ssl/certs/ca-certificates.crt
 
 
 Channel work
 Channel work