@ -50,6 +50,7 @@ typedef struct imap_server_conf {
char * name ;
char * name ;
server_conf_t sconf ;
server_conf_t sconf ;
char * user ;
char * user ;
char * user_cmd ;
char * pass ;
char * pass ;
char * pass_cmd ;
char * pass_cmd ;
int max_in_progress ;
int max_in_progress ;
@ -1936,12 +1937,50 @@ imap_open_store_authenticate_p3( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED,
}
}
# endif
# endif
static char *
cred_from_cmd ( const char * cred , const char * cmd , const char * srv_name )
{
FILE * fp ;
int ret ;
char buffer [ 8192 ] ; // Hopefully more than enough room for XOAUTH2, etc. tokens
if ( * cmd = = ' + ' ) {
flushn ( ) ;
cmd + + ;
}
if ( ! ( fp = popen ( cmd , " r " ) ) ) {
pipeerr :
sys_error ( " Skipping account %s, %s failed " , srv_name , cred ) ;
return NULL ;
}
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, %s crashed \n " , srv_name , cred ) ;
else
error ( " Skipping account %s, %s exited with status %d \n " , srv_name , cred , WEXITSTATUS ( ret ) ) ;
return NULL ;
}
if ( ! buffer [ 0 ] ) {
error ( " Skipping account %s, %s produced no output \n " , srv_name , cred ) ;
return NULL ;
}
buffer [ strcspn ( buffer , " \n " ) ] = 0 ; /* Strip trailing newline */
return nfstrdup ( buffer ) ;
}
static const char *
static const char *
ensure_user ( imap_server_conf_t * srvc )
ensure_user ( imap_server_conf_t * srvc )
{
{
if ( ! srvc - > user ) {
if ( ! srvc - > user ) {
error ( " Skipping account %s, no user \n " , srvc - > name ) ;
if ( srvc - > user_cmd ) {
return NULL ;
srvc - > user = cred_from_cmd ( " UserCmd " , srvc - > user_cmd , srvc - > name ) ;
} else {
error ( " Skipping account %s, no user \n " , srvc - > name ) ;
}
}
}
return srvc - > user ;
return srvc - > user ;
}
}
@ -1949,56 +1988,25 @@ ensure_user( imap_server_conf_t *srvc )
static const char *
static const char *
ensure_password ( imap_server_conf_t * srvc )
ensure_password ( imap_server_conf_t * srvc )
{
{
char * cmd = srvc - > pass_cmd ;
if ( ! srvc - > pass ) {
if ( srvc - > pass_cmd ) {
if ( cmd ) {
srvc - > pass = cred_from_cmd ( " PassCmd " , srvc - > pass_cmd , srvc - > name ) ;
FILE * fp ;
} else {
int ret ;
char buffer [ 8192 ] ; // Hopefully more than enough room for XOAUTH2, etc. tokens
if ( * cmd = = ' + ' ) {
flushn ( ) ;
flushn ( ) ;
cmd + + ;
char prompt [ 80 ] ;
}
sprintf ( prompt , " Password (%s): " , srvc - > name ) ;
if ( ! ( fp = popen ( cmd , " r " ) ) ) {
char * pass = getpass ( prompt ) ;
pipeerr :
if ( ! pass ) {
sys_error ( " Skipping account %s, password command failed " , srvc - > name ) ;
perror ( " getpass " ) ;
return NULL ;
exit ( 1 ) ;
}
}
if ( ! fgets ( buffer , sizeof ( buffer ) , fp ) )
if ( ! * pass ) {
buffer [ 0 ] = 0 ;
error ( " Skipping account %s, no password \n " , srvc - > name ) ;
if ( ( ret = pclose ( fp ) ) < 0 )
return NULL ;
goto pipeerr ;
}
if ( ret ) {
/* getpass() returns a pointer to a static buffer. Make a copy for long term storage. */
if ( WIFSIGNALED ( ret ) )
srvc - > pass = nfstrdup ( pass ) ;
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 ) ) ;
return NULL ;
}
if ( ! buffer [ 0 ] ) {
error ( " Skipping account %s, password command produced no output \n " , srvc - > name ) ;
return NULL ;
}
buffer [ strcspn ( buffer , " \n " ) ] = 0 ; /* Strip trailing newline */
free ( srvc - > pass ) ; /* From previous runs */
srvc - > pass = nfstrdup ( buffer ) ;
} else if ( ! srvc - > pass ) {
char * pass , prompt [ 80 ] ;
flushn ( ) ;
sprintf ( prompt , " Password (%s): " , srvc - > name ) ;
pass = getpass ( prompt ) ;
if ( ! pass ) {
perror ( " getpass " ) ;
exit ( 1 ) ;
}
if ( ! * pass ) {
error ( " Skipping account %s, no password \n " , srvc - > name ) ;
return NULL ;
}
}
/* getpass() returns a pointer to a static buffer. Make a copy for long term storage. */
srvc - > pass = nfstrdup ( pass ) ;
}
}
return srvc - > pass ;
return srvc - > pass ;
}
}
@ -2182,6 +2190,17 @@ imap_open_store_authenticate2( imap_store_t *ctx )
char saslmechs [ 1024 ] , * saslend = saslmechs ;
char saslmechs [ 1024 ] , * saslend = saslmechs ;
# endif
# endif
// Ensure that there are no leftovers from previous runs. This is needed in case
// the credentials have a timing dependency or otherwise lose validity after use.
if ( srvc - > user_cmd ) {
free ( srvc - > user ) ;
srvc - > user = NULL ;
}
if ( srvc - > pass_cmd ) {
free ( srvc - > pass ) ;
srvc - > pass = NULL ;
}
info ( " Logging in... \n " ) ;
info ( " Logging in... \n " ) ;
for ( mech = srvc - > auth_mechs ; mech ; mech = mech - > next ) {
for ( mech = srvc - > auth_mechs ; mech ; mech = mech - > next ) {
int any = ! strcmp ( mech - > string , " * " ) ;
int any = ! strcmp ( mech - > string , " * " ) ;
@ -3268,6 +3287,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
}
}
else if ( ! strcasecmp ( " User " , cfg - > cmd ) )
else if ( ! strcasecmp ( " User " , cfg - > cmd ) )
server - > user = nfstrdup ( cfg - > val ) ;
server - > user = nfstrdup ( cfg - > val ) ;
else if ( ! strcasecmp ( " UserCmd " , cfg - > cmd ) )
server - > user_cmd = 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 ) )
else if ( ! strcasecmp ( " PassCmd " , cfg - > cmd ) )
@ -3431,6 +3452,11 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
cfg - > err = 1 ;
cfg - > err = 1 ;
return 1 ;
return 1 ;
}
}
if ( server - > user & & server - > user_cmd ) {
error ( " %s '%s' has both User and UserCmd \n " , type , name ) ;
cfg - > err = 1 ;
return 1 ;
}
if ( server - > pass & & server - > pass_cmd ) {
if ( server - > pass & & server - > pass_cmd ) {
error ( " %s '%s' has both Pass and PassCmd \n " , type , name ) ;
error ( " %s '%s' has both Pass and PassCmd \n " , type , name ) ;
cfg - > err = 1 ;
cfg - > err = 1 ;