commit bf049d64663f8c4158bd8e3c21feb88aaaf7bd26
parent 5ad83b4e6a59e023a43deffb28b6da3f35262c0e
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Sat, 27 Jul 2013 10:37:15 +0200
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.
Diffstat:
3 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/src/drv_imap.c b/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) {
diff --git a/src/mbsync.1 b/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
diff --git a/src/mbsyncrc.sample b/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