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