diff -ru fetchmail-6.3.8.orig/README.pwmd fetchmail-6.3.8/README.pwmd --- fetchmail-6.3.8.orig/README.pwmd 1969-12-31 19:00:00.000000000 -0500 +++ fetchmail-6.3.8/README.pwmd 2007-06-23 21:40:04.000000000 -0400 @@ -0,0 +1,33 @@ +When compiled with pwmd (Password Manager Daemon) support (--enable-pwmd), +fetchmail can retrieve server details from pwmd. Two new configuration +parameters are added: pwmd_socket, to specify the socket to connect to, and +pwmd_file (required) which specifies the filename on the server to open. + +The data that fetchmail will use is stored in an encrypted XML file and has +the following structure: + + + - Optional (--username/username) + - Optional (--password/password) + - POP3/IMAP/etc. + - Required (servername/via) + - Required (--service/protocol) + - Optional (--ssl/ssl) + - Optional (--sslfingerprint/sslfingerprint) + + + +A minimal fetchmailrc might look like this: + +poll isp proto POP3: + pwmd_file default + +Or from the command line: + fetchmail -f fetchmailrc isp + fetchmail --pwmd-file somefile -p POP3 isp + +The password to open the encrypted data file is either cached on the server +(the file has been opened before), or gotten from pinentry(1). + +Ben Kibbey +http://bjk.sourceforge.net/pwmd/. diff -ru fetchmail-6.3.8.orig/configure.ac fetchmail-6.3.8/configure.ac --- fetchmail-6.3.8.orig/configure.ac 2007-04-06 14:10:58.000000000 -0400 +++ fetchmail-6.3.8/configure.ac 2007-06-23 21:38:56.000000000 -0400 @@ -256,6 +256,22 @@ AC_MSG_RESULT(root-mode pid file will go in $dir) AC_DEFINE_UNQUOTED(PID_DIR, "$dir", directory for PID lock files) +AC_ARG_ENABLE(pwmd, + [ --enable-pwmd enable Password Manager Daemon support], + , [enable_pwmd=no]) + +if test "$enable_pwmd" = "yes"; then + PKG_CHECK_EXISTS([libpwmd], have_libpwmd=1, + AC_MSG_ERROR([Could not find libpwmd pkg-config module.])) + + + PKG_CHECK_MODULES([libpwmd], [libpwmd >= 3.0.0]) + AM_CONDITIONAL(HAVE_LIBPWMD, true) + AC_DEFINE(HAVE_LIBPWMD, 1, [Define if you have libPWMD installed.]) +else + AM_CONDITIONAL(HAVE_LIBPWMD, false) +fi + # We may have a fallback MDA available in case the socket open to the # local SMTP listener fails. Best to use procmail for this, as we know # it won't try delivering through local SMTP and cause a mail loop. diff -ru fetchmail-6.3.8.orig/fetchmail.c fetchmail-6.3.8/fetchmail.c --- fetchmail-6.3.8.orig/fetchmail.c 2007-03-30 03:52:16.000000000 -0400 +++ fetchmail-6.3.8/fetchmail.c 2007-06-23 22:12:06.000000000 -0400 @@ -146,6 +146,64 @@ const char *iana_charset; +#ifdef HAVE_LIBPWMD +static void exit_with_pwmd_error() +{ + gpg_err_code_t code = gpg_err_code(pwmd_error); + + warnx(GT_("pwmd: error %i: %s"), code, pwmd_strerror(pwmd_error)); + exit(PS_UNDEFINED); +} + +static void pwmd_set_agent_strings(const char *filename) +{ + char buf[255]; + + /* + * Use pinentry for password retrieval. Since version 0.3 of pwmd + * there is an option to push files into the file cache when the + * server starts up. For a daemonized fetchmail, this may be + * required because there won't be a way to get the key without a + * tty that pinentry requires. + */ + if (pwmd_setopt(pwm, &pwmd_error, PWMD_OPTION_PINENTRY, 1) != PWMD_OK) + exit_with_pwmd_error(); + + /* + * Set the text to be used in the pinentry dialog. + */ + if (pwmd_setopt(pwm, &pwmd_error, PWMD_OPTION_TITLE, + "Password Manager Daemon: Fetchmail") != PWMD_OK) + exit_with_pwmd_error(); + + snprintf(buf, sizeof(buf), + "A password is needed to open the file \"%s\". Please\n" + "enter the password below.", filename); + + if (pwmd_setopt(pwm, &pwmd_error, PWMD_OPTION_DESC, buf) != PWMD_OK) + exit_with_pwmd_error(); +} + +static void pwmd_do_connect(const char *socketname, const char *filename) +{ + /* + * Try and connect to pwmd. + */ + if ((pwm = pwmd_connect(socketname, &pwmd_error)) == NULL) + exit_with_pwmd_error(); + + pwmd_set_agent_strings(filename); + + /* + * Try and open the file so we can later get account/server credentials. If + * the file is not cached on the server, pinentry(1) will ask for the + * password. + */ + if (pwmd_open(pwm, &pwmd_error, filename) != PWMD_OK) + exit_with_pwmd_error(); +} +#endif + int main(int argc, char **argv) { int bkgd = FALSE; @@ -276,6 +334,9 @@ #ifdef KERBEROS_V5 "+KRB5" #endif /* KERBEROS_V5 */ +#ifdef HAVE_LIBPWMD + "+PWMD" +#endif /* HAVE_LIBPWMD */ ".\n"; printf(GT_("This is fetchmail release %s"), VERSION); fputs(features, stdout); @@ -988,6 +1049,146 @@ #undef FLAG_MERGE } +#ifdef HAVE_LIBPWMD +static char *protocol_to_service(int protocol) +{ + switch (protocol) { +#ifdef POP2_ENABLE + case P_POP2: + return "POP2"; +#endif +#ifdef POP3_ENABLE + case P_POP3: + return "POP3"; +#endif +#ifdef IMAP_ENABLE + case P_IMAP: + return "IMAP"; +#endif + case P_APOP: + return "APOP"; + case P_RPOP: + return "RPOP"; + case P_ETRN: + return "ETRN"; + case P_ODMR: + return "ODMR"; + default: + return NULL; + } + + return NULL; +} + +static int pwmd_get_details(const char *pwmd_account, int protocol, + struct query *ctl) +{ + char *prot = protocol_to_service(protocol); + char *p; + + /* + * Get the hostname for this protocol. Element path must be + * account->[protocol]->hostname. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\t%s\thostname", pwmd_account, prot) != PWMD_OK) { + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) { + warnx(GT_("%s->%s->hostname: %s"), pwmd_account, prot, pwmd_strerror(pwmd_error)); + exit(PS_SYNTAX); + } + else + exit_with_pwmd_error(); + } + + ctl->server.pollname = xstrdup(pwmd_account); + ctl->server.via = xstrdup(pwmd_result); + pwmd_free_result(pwmd_result); + + /* + * Server port. Element path must be account->[protocol]->port. Should be + * required because the element path wouldn't exist with out it. But + * maybe not because fetchmail trys standard ports if not specified. This + * may be a security risk. Might be better to have 'ssl' required. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\t%s\tport", pwmd_account, prot) != PWMD_OK) { + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) { + warnx(GT_("%s->%s->port: %s"), pwmd_account, prot, pwmd_strerror(pwmd_error)); + exit(PS_SYNTAX); + } + else + exit_with_pwmd_error(); + } + + p = xstrdup(pwmd_result); + ctl->server.service = p; + pwmd_free_result(pwmd_result); + + /* + * Get the remote username. Element must be account->username. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\tusername", pwmd_account) != PWMD_OK) { + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) + warnx(GT_("%s->username: %s"), pwmd_account, pwmd_strerror(pwmd_error)); + else + exit_with_pwmd_error(); + } + else { + ctl->remotename = xstrdup(pwmd_result); + ctl->server.esmtp_name = xstrdup(ctl->remotename); + pwmd_free_result(pwmd_result); + } + + /* + * Get the remote password. Element must be account->password. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\tpassword", pwmd_account) != PWMD_OK) + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) + warnx(GT_("%s->password: %s"), pwmd_account, pwmd_strerror(pwmd_error)); + else + exit_with_pwmd_error(); + else { + ctl->password= xstrdup(pwmd_result); + pwmd_free_result(pwmd_result); + } + +#ifdef SSL_ENABLE + /* + * If there is a ssl element and set to 1, enable ssl for this account. + * Element path must be account->[protocol]->ssl. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\t%s\tssl", pwmd_account, prot) != PWMD_OK) { + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) + warnx(GT_("%s->%s->ssl: %s"), pwmd_account, prot, pwmd_strerror(pwmd_error)); + else + exit_with_pwmd_error(); + } + else { + p = xstrdup(pwmd_result); + ctl->use_ssl = atoi(p); + ctl->use_ssl = (ctl->use_ssl >= 1) ? FLAG_TRUE : FLAG_FALSE; + pwmd_free_result(pwmd_result); + free(p); + } + + /* + * account->[protocol]->sslfingerprint. + */ + if (pwmd_command(pwm, &pwmd_result, &pwmd_error, "GET %s\t%s\tsslfingerprint", pwmd_account, prot) != PWMD_OK) { + if (gpg_err_code(pwmd_error) == EPWMD_ELEMENT_NOT_FOUND) + warnx(GT_("%s->%s->sslfingerprint: %s"), pwmd_account, prot, pwmd_strerror(pwmd_error)); + else + exit_with_pwmd_error(); + } + else { + p = xstrdup(pwmd_result); + ctl->sslfingerprint = p; + pwmd_free_result(pwmd_result); + } +#endif + + return 0; +} +#endif + /** Load configuration files. * \return - true if no servers found on the command line * - false if servers found on the command line */ @@ -1045,8 +1246,30 @@ if ((implicitmode = (optind >= argc))) { +#ifdef HAVE_LIBPWMD + for (ctl = querylist; ctl; ctl = ctl->next) { + ctl->active = !ctl->server.skip; + + if (ctl->pwmd_file) { + /* + * Cannot get an element path without a service. + */ + if (ctl->server.protocol <= 1) { + warnx(GT_("fetchmail: %s configuration invalid, pwmd_file requires a protocol specification"), + ctl->server.pollname); + exit(PS_SYNTAX); + } + + pwmd_do_connect(ctl->pwmd_socket, ctl->pwmd_file); + pwmd_get_details(ctl->server.pollname, + ctl->server.protocol, ctl); + pwmd_close(pwm); + } + } +#else for (ctl = querylist; ctl; ctl = ctl->next) ctl->active = !ctl->server.skip; +#endif } else for (; optind < argc; optind++) @@ -1067,6 +1290,24 @@ fprintf(stderr,GT_("Warning: multiple mentions of host %s in config file\n"),argv[optind]); ctl->active = TRUE; predeclared = TRUE; + +#ifdef HAVE_LIBPWMD + if (ctl->pwmd_file) { + /* + * Cannot get an element path without a service. + */ + if (ctl->server.protocol <= 1) { + warnx(GT_("%s configuration invalid, pwmd_file requires a protocol specification"), + ctl->server.pollname); + exit(PS_SYNTAX); + } + + pwmd_do_connect(ctl->pwmd_socket, ctl->pwmd_file); + pwmd_get_details(ctl->server.pollname, + ctl->server.protocol, ctl); + pwmd_close(pwm); + } +#endif } if (!predeclared) @@ -1077,8 +1318,29 @@ * call later on. */ ctl = hostalloc((struct query *)NULL); - ctl->server.via = - ctl->server.pollname = xstrdup(argv[optind]); + +#ifdef HAVE_LIBPWMD + if (cmd_opts.pwmd_file) { + /* + * Cannot get an element path without a service. + */ + if (cmd_opts.server.protocol == 0 || cmd_opts.server.protocol == 1) { + warnx(GT_("Option --pwmd-file needs a service (-p) parameter.")); + exit(PS_SYNTAX); + } + + pwmd_do_connect(cmd_opts.pwmd_socket, cmd_opts.pwmd_file); + pwmd_get_details(argv[optind], cmd_opts.server.protocol, + ctl); + pwmd_close(pwm); + } + else + ctl->server.via = + ctl->server.pollname = xstrdup(argv[optind]); +#else + ctl->server.via = + ctl->server.pollname = xstrdup(argv[optind]); +#endif ctl->active = TRUE; ctl->server.lead_server = (struct hostdata *)NULL; } diff -ru fetchmail-6.3.8.orig/fetchmail.h fetchmail-6.3.8/fetchmail.h --- fetchmail-6.3.8.orig/fetchmail.h 2007-03-17 21:11:43.000000000 -0400 +++ fetchmail-6.3.8/fetchmail.h 2007-06-23 21:42:42.000000000 -0400 @@ -39,6 +39,10 @@ # include "trio/trio.h" #endif +#ifdef HAVE_LIBPWMD +#include +#endif + /* We need this for strstr */ #if !defined(HAVE_STRSTR) && !defined(strstr) char *strstr(const char *, const char *); @@ -313,6 +317,11 @@ char *password; /* remote password to use */ struct idlist *mailboxes; /* list of mailboxes to check */ +#ifdef HAVE_LIBPWMD + char *pwmd_socket; /* socket to connect to */ + char *pwmd_file; /* file to open on the server */ +#endif + /* per-forwarding-target data */ struct idlist *smtphunt; /* list of SMTP hosts to try forwarding to */ struct idlist *domainlist; /* domainlist to fetch from */ @@ -455,6 +464,11 @@ extern char *sdps_envfrom; extern char *sdps_envto; #endif /* SDPS_ENABLE */ +#ifdef HAVE_LIBPWMD +pwm_t *pwm; /* the handle */ +char *pwmd_result; /* server result */ +gpg_error_t pwmd_error; /* return value from pwmd_command() */ +#endif extern const char *iana_charset; /* IANA assigned charset name */ diff -ru fetchmail-6.3.8.orig/Makefile.am fetchmail-6.3.8/Makefile.am --- fetchmail-6.3.8.orig/Makefile.am 2007-04-06 14:09:17.000000000 -0400 +++ fetchmail-6.3.8/Makefile.am 2007-06-23 21:38:56.000000000 -0400 @@ -18,6 +18,11 @@ pys= fetchmailconf.py pym= fetchmailconf.man +if HAVE_LIBPWMD +CFLAGS += @libpwmd_CFLAGS@ +LDFLAGS += @libpwmd_LIBS@ +endif + if HAVE_PYTHON nodist_bin_SCRIPTS= fetchmailconf python_PYTHON= $(pys) diff -ru fetchmail-6.3.8.orig/options.c fetchmail-6.3.8/options.c --- fetchmail-6.3.8.orig/options.c 2006-08-14 19:04:02.000000000 -0400 +++ fetchmail-6.3.8/options.c 2007-06-23 21:38:56.000000000 -0400 @@ -53,12 +53,21 @@ LA_IDLE }; +#ifdef HAVE_LIBPWMD +static const char *shortoptions = + "C:G:?Vcsvd:NqL:f:i:p:UP:A:t:E:Q:u:akKFnl:r:S:Z:b:B:e:m:I:M:yw:D:"; +#else /* options still left: CgGhHjJoORTWxXYz */ static const char *shortoptions = "?Vcsvd:NqL:f:i:p:UP:A:t:E:Q:u:akKFnl:r:S:Z:b:B:e:m:I:M:yw:D:"; +#endif static const struct option longoptions[] = { /* this can be const because all flag fields are 0 and will never get set */ +#ifdef HAVE_LIBPWMD + {"pwmd-socket", required_argument, (int *) 0, 'C' }, + {"pwmd-file", required_argument, (int *) 0, 'G' }, +#endif {"help", no_argument, (int *) 0, '?' }, {"version", no_argument, (int *) 0, 'V' }, {"check", no_argument, (int *) 0, 'c' }, @@ -248,6 +257,14 @@ longoptions, &option_index)) != -1) { switch (c) { +#ifdef HAVE_LIBPWMD + case 'C': + ctl->pwmd_socket = prependdir(optarg, currentwd); + break; + case 'G': + ctl->pwmd_file = xstrdup(optarg); + break; +#endif case 'V': versioninfo = TRUE; break; @@ -618,6 +635,11 @@ P(GT_(" --plugout specify external command to open smtp connection\n")); P(GT_(" -p, --protocol specify retrieval protocol (see man page)\n")); +#ifdef HAVE_LIBPWMD + P(GT_(" -C, --pwmd-socket pwmd socket path (~/.pwmd/socket)\n")); + P(GT_(" -G, --pwmd-file filename to use on the pwmd server\n")); +#endif + P(GT_(" -U, --uidl force the use of UIDLs (pop3 only)\n")); P(GT_(" --port TCP port to connect to (obsolete, use --service)\n")); P(GT_(" -P, --service TCP service to connect to (can be numeric TCP port)\n")); diff -ru fetchmail-6.3.8.orig/rcfile_l.l fetchmail-6.3.8/rcfile_l.l --- fetchmail-6.3.8.orig/rcfile_l.l 2006-08-14 19:04:02.000000000 -0400 +++ fetchmail-6.3.8/rcfile_l.l 2007-06-23 21:38:56.000000000 -0400 @@ -114,6 +114,8 @@ user(name)? {SETSTATE(NAME); return USERNAME; } +pwmd_socket { return PWMD_SOCKET; } +pwmd_file { return PWMD_FILE; } pass(word)? {SETSTATE(NAME); return PASSWORD; } folder(s)? { return FOLDER; } smtp(host)? { return SMTPHOST; } diff -ru fetchmail-6.3.8.orig/rcfile_y.y fetchmail-6.3.8/rcfile_y.y --- fetchmail-6.3.8.orig/rcfile_y.y 2006-12-08 07:09:09.000000000 -0500 +++ fetchmail-6.3.8/rcfile_y.y 2007-06-23 21:38:56.000000000 -0400 @@ -63,7 +63,7 @@ %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 PWMD_SOCKET PWMD_FILE USERNAME PASSWORD FOLDER SMTPHOST FETCHDOMAINS MDA BSMTP LMTP %token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS %token INTERFACE MONITOR PLUGIN PLUGOUT %token IS HERE THERE TO MAP WILDCARD @@ -243,6 +243,20 @@ userdef : USERNAME STRING {current.remotename = xstrdup($2);} | USERNAME mapping_list HERE | USERNAME STRING THERE {current.remotename = xstrdup($2);} + | PWMD_SOCKET STRING { +#ifdef HAVE_LIBPWMD + current.pwmd_socket = xstrdup($2); +#else + yyerror(GT_("pwmd not enabled")); +#endif + } + | PWMD_FILE STRING { +#ifdef HAVE_LIBPWMD + current.pwmd_file = xstrdup($2); +#else + yyerror(GT_("pwmd not enabled")); +#endif + } ; user0opts : /* EMPTY */