diff --git a/src/drv_imap.c b/src/drv_imap.c index e6b4009..1f40bf2 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -31,6 +31,7 @@ #include #include #include +#include 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 index af92444..1816aa7 100644 --- 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 index fe0adb6..f642b3f 100644 --- 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