Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:16.0:FactoryCandidates
fetchmail
fetchmail-add-passwordfile-and-passwordfd-optio...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fetchmail-add-passwordfile-and-passwordfd-options.patch of Package fetchmail
From: Matthew Ogilvie <mmogilvi+fml@zoho.com> Date: Sun, 28 May 2017 00:01:02 -0600 Subject: add passwordfile and passwordfd options Git-repo: https://gitlab.com/fetchmail/fetchmail.git Git-commit: cdd7182f65734c97723ba5f282040e08d830e650 --- fetchmail.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- fetchmail.h | 2 + fetchmail.man | 40 +++++++++++++++++++++++++++- options.c | 16 +++++++++++ rcfile_l.l | 2 + rcfile_y.y | 6 ++++ 6 files changed, 145 insertions(+), 3 deletions(-) --- a/fetchmail.c +++ b/fetchmail.c @@ -451,7 +451,7 @@ int main(int argc, char **argv) /* Server won't care what the password is, but there must be some non-null string here. */ ctl->password = ctl->remotename; - else + else if (!ctl->passwordfile && ctl->passwordfd==-1) { netrc_entry *p; @@ -618,8 +618,81 @@ int main(int argc, char **argv) if (ctl->active && !(implicitmode && ctl->server.skip) && !NO_PASSWORD(ctl) && !ctl->password) { - if (!isatty(0)) + if (ctl->passwordfd != -1) { + char msg[PASSWORDLEN+1]; + char *mi; + + /* Read one character at a time to avoid reading too + * much if more than one password sent in through this FD + * (although that would be a questionable practice). + */ + for (mi = msg; mi<msg+sizeof(msg)-1; ++mi) { + int res = read(ctl->passwordfd, mi, 1); + if(res == -1) { + int saveErrno = errno; + fprintf(stderr, + GT_("fetchmail: unable to read password from fd=%d: %s\n"), + ctl->passwordfd, + strerror(saveErrno)); + memset(msg, 0x55, mi-msg); + return PS_AUTHFAIL; + } + if (res == 0 || *mi == '\n') + break; + } + *mi = '\0'; + if (mi == msg) { + fprintf(stderr, + GT_("fetchmail: empty password read from fd=%d\n"), + ctl->passwordfd); + return PS_AUTHFAIL; + } + + ctl->password = xstrdup(msg); + memset(msg, 0x55, mi-msg); + } else if (ctl->passwordfile) { + int fd = open(ctl->passwordfile, O_RDONLY); + char msg[PASSWORDLEN+1]; + char *newline; + int res; + + if (fd == -1) { + int saveErrno = errno; + fprintf(stderr, + GT_("fetchmail: unable to open %s: %s\n"), + ctl->passwordfile, + strerror(saveErrno)); + return PS_AUTHFAIL; + } + + res = read(fd, msg, sizeof(msg)-1); + if (res == -1 || close(fd) == -1) { + int saveErrno = errno; + fprintf(stderr, + GT_("fetchmail: error reading %s: %s\n"), + ctl->passwordfile, + strerror(saveErrno)); + return PS_AUTHFAIL; + } + msg[res] = '\0'; + + newline = memchr(msg, '\n', res); + if (newline != NULL) { + *newline = '\0'; + } + + if (strlen(msg) == 0) { + fprintf(stderr, + GT_("fetchmail: empty password read from %s\n"), + ctl->passwordfile); + memset(msg, 0x55, res); + return PS_AUTHFAIL; + } + + ctl->password = xstrdup(msg); + memset(msg, 0x55, res); + } else if (!isatty(0)) { fprintf(stderr, GT_("fetchmail: can't find a password for %s@%s.\n"), ctl->remotename, ctl->server.pollname); @@ -1035,6 +1108,10 @@ static void optmerge(struct query *h2, s FLAG_MERGE(wildcard); STRING_MERGE(remotename); STRING_MERGE(password); + FLAG_MERGE(passwordfile); + if (force ? h1->passwordfd!=-1 : h2->passwordfd==-1) { + h2->passwordfd = h1->passwordfd; + } STRING_MERGE(mda); STRING_MERGE(bsmtp); FLAG_MERGE(listener); @@ -1099,6 +1176,7 @@ static int load_params(int argc, char ** def_opts.smtp_socket = -1; def_opts.smtpaddress = (char *)0; def_opts.smtpname = (char *)0; + def_opts.passwordfd = -1; def_opts.server.protocol = P_AUTO; def_opts.server.timeout = CLIENT_TIMEOUT; def_opts.server.esmtp_name = user; --- a/fetchmail.h +++ b/fetchmail.h @@ -326,6 +326,8 @@ struct query int wildcard; /* should unmatched names be passed through */ char *remotename; /* remote login name to use */ char *password; /* remote password to use */ + char *passwordfile; /* filename; first line contains password */ + int passwordfd; /* fileno that password will be piped into */ struct idlist *mailboxes; /* list of mailboxes to check */ /* per-forwarding-target data */ --- a/fetchmail.man +++ b/fetchmail.man @@ -949,6 +949,37 @@ The default is your login name on the cl \fBfetchmail\fP. See USER AUTHENTICATION below for a complete description. .TP +.B \-\-passwordfile <filename> +(Keyword: passwordfile) +.br +Specifies a file name from which to read the first line to use as the password. +Useful if something changes the password/token often without regenerating a +long fetchmailrc file, such as with typical xoauth2 authentication tokens. +Protect the file with appropriate permissions to avoid leaking your password. +Fetchmail might not re-read the file in daemon mode (-d) unless the +fetchmailrc file also changes, so it might make sense to run it in +non-daemon mode from some other background process (cron and/or whatever +updates the password). +.TP +.B \-\-passwordfd <integer> +(Keyword: passwordfd) +.br +Specifies a file descriptor number inherited from the calling process, +from which fetchmail should read one line to use as the password. +The descriptor will usually be the receiving end of a pipe (equivalent +to "something | fetchmail \-\-passwordfd 5 5<\&0"), +although it could also be a redirected input file +(equivalent to "fetchmail \-\-passwordfd 5 5</path/to/file"). +Useful if something wants to manage password ownership more securely +than files, or if the password/token changes often, +such as with typical xoauth2 authentication tokens. Normal interactive +mode passwords requires that standard input is a terminal and disables +echo, but passwordfd does not care. Do not do something +like "echo 'password' | fetchmail ...", since echo's arguments are +likely to (briefly) be publicly visible in process listings. +This probably doesn't interact well with deamon mode: when will it +re-read a new password? +.TP .B \-I <specification> | \-\-interface <specification> (Keyword: interface) .br @@ -1040,7 +1071,8 @@ setting also allows the non-standard "xo the same token) if the server only claims to support "xoauth2". External tools are necessary to obtain such tokens. Access tokens often expire fairly quickly (e.g. 1 hour), -and new ones need to be generated from renewal tokens. See the +and new ones need to be generated from renewal tokens, so the +"passwordfile", "passwordfd", or "pwmd_*" options may be useful. See the oauth2.py script from .URL https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough "Google's Oauth2 Run Through" , and other oauth2 documentation. For services like gmail, an "App Password" @@ -1953,6 +1985,12 @@ T} pass[word] \& \& T{ Specify remote account password T} +passwordfile \-\-... \& T{ +File name with password in first line. +T} +passwordfd \-\-... \& T{ +Inherited file descriptor from which to read one line for the password. +T} ssl \& \& T{ Connect to server over the specified base protocol using SSL encryption T} --- a/options.c +++ b/options.c @@ -31,6 +31,8 @@ enum { LA_POSTMASTER, LA_NOBOUNCE, LA_AUTH, + LA_PASSWORDFILE, + LA_PASSWORDFD, LA_FETCHDOMAINS, LA_BSMTP, LA_LMTP, @@ -94,6 +96,8 @@ static const struct option longoptions[] {"port", required_argument, (int *) 0, 'P' }, {"service", required_argument, (int *) 0, 'P' }, {"auth", required_argument, (int *) 0, LA_AUTH}, + {"passwordfile", required_argument, (int *) 0, LA_PASSWORDFILE }, + {"passwordfd", required_argument, (int *) 0, LA_PASSWORDFD }, {"timeout", required_argument, (int *) 0, 't' }, {"envelope", required_argument, (int *) 0, 'E' }, {"qvirtual", required_argument, (int *) 0, 'Q' }, @@ -261,6 +265,7 @@ int parsecmdline (int argc /** argument memset(ctl, '\0', sizeof(struct query)); /* start clean */ ctl->smtp_socket = -1; + ctl->passwordfd = -1; while (!errflag && (c = getopt_long(argc,argv,shortoptions, @@ -428,6 +433,17 @@ int parsecmdline (int argc /** argument errflag++; } break; + case LA_PASSWORDFILE: + ctl->passwordfile = optarg; + break; + case LA_PASSWORDFD: + ctl->passwordfd = xatoi(optarg, &errflag); + if (ctl->passwordfd < 0) { + fprintf(stderr,GT_("Invalid file descriptor %d\n"), + ctl->passwordfd); + errflag++; + } + break; case 't': ctl->server.timeout = xatoi(optarg, &errflag); if (ctl->server.timeout == 0) --- a/rcfile_l.l +++ b/rcfile_l.l @@ -118,6 +118,8 @@ accept { return ACCEPT; } reject { return REJECT_; } user(name)? {SETSTATE(NAME); return USERNAME; } +passwordfile { return PASSWORDFILE; } +passwordfd { return PASSWORDFD; } <INITIAL,NAME>pass(word)? {SETSTATE(NAME); return PASSWORD; } folder(s)? { return FOLDER; } smtp(host)? { return SMTPHOST; } --- a/rcfile_y.y +++ b/rcfile_y.y @@ -63,6 +63,7 @@ extern char * yytext; %token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL %token AUTHENTICATE TIMEOUT KPOP SDPS ENVELOPE QVIRTUAL %token USERNAME PASSWORD FOLDER SMTPHOST FETCHDOMAINS MDA BSMTP LMTP +%token PASSWORDFILE PASSWORDFD %token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS %token INTERFACE MONITOR PLUGIN PLUGOUT %token IS HERE THERE TO MAP @@ -307,6 +308,8 @@ user_option : TO mapping_list HERE | IS STRING THERE {current.remotename = $2;} | PASSWORD STRING {current.password = $2;} + | PASSWORDFILE STRING {current.passwordfile = $2;} + | PASSWORDFD NUMBER {current.passwordfd = NUM_VALUE_IN($2);} | FOLDER folder_list | SMTPHOST smtp_list | FETCHDOMAINS fetch_list @@ -505,6 +508,7 @@ static void reset_server(const char *nam trailer = FALSE; memset(¤t,'\0',sizeof(current)); current.smtp_socket = -1; + current.passwordfd = -1; current.server.pollname = xstrdup(name); current.server.skip = skip; current.server.principal = (char *)NULL; @@ -526,6 +530,7 @@ static void user_reset(void) memset(¤t, '\0', sizeof(current)); current.smtp_socket = -1; + current.passwordfd = -1; current.server = save; } @@ -546,6 +551,7 @@ struct query *hostalloc(struct query *in { memset(node, '\0', sizeof(struct query)); node->smtp_socket = -1; + node->passwordfd = -1; } /* append to end of list */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor