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.
This commit is contained in:
Oswald Buddenhagen 2013-07-27 10:37:15 +02:00
parent 5ad83b4e6a
commit bf049d6466
3 changed files with 64 additions and 3 deletions

View File

@ -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) {

View File

@ -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 If neither a password nor a password command is specified in the
will prompt you for it. 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

View File

@ -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