X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fetchmail.c;h=4327c6e4bce21c3da471e2a174a5195a1fe48d02;hb=2629c4511c68729d98acfd08637c1f00d3807f49;hp=84fed2c437ea1baf664622bc762c127c6988f1f1;hpb=2cabbf89f9f696a4786476a4eda7a59a1c16d486;p=~andy%2Ffetchmail diff --git a/fetchmail.c b/fetchmail.c index 84fed2c4..4327c6e4 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -43,6 +43,12 @@ #include "smtp.h" #include "netrc.h" #include "i18n.h" +#include "lock.h" + +/* need these (and sys/types.h) for res_init() */ +#include +#include +#include #ifndef ENETUNREACH #define ENETUNREACH 128 /* Interactive doesn't know this */ @@ -60,14 +66,17 @@ int outlevel; /* see the O_.* constants above */ struct runctl run; /* global controls for this run */ flag nodetach; /* if TRUE, don't detach daemon process */ flag quitmode; /* if --quit was set */ +int quitind; /* optind after position of last --quit option */ flag check_only; /* if --probe was set */ flag versioninfo; /* emit only version info */ char *user; /* the name of the invoking user */ char *home; /* invoking user's home directory */ char *fmhome; /* fetchmail's home directory */ -char *program_name; /* the name to prefix error messages with */ +const char *program_name; /* the name to prefix error messages with */ flag configdump; /* dump control blocks for configurator */ -char *fetchmailhost; /* either `localhost' or the host's FQDN */ +const char *fetchmailhost; /* either `localhost' or the host's FQDN */ + +static int quitonly; /* if we should quit after killing the running daemon */ static int querystatus; /* status of query */ static int successes; /* count number of successful polls */ @@ -124,6 +133,22 @@ static RETSIGTYPE donothing(int sig) lastsig = sig; } +static void printcopyright(FILE *fp) { + fprintf(fp, GT_("Copyright (C) 2002, 2003 Eric S. Raymond\n" + "Copyright (C) 2004 Matthias Andree, Eric S. Raymond,\n" + " Robert M. Funk, Graham Wilson\n" + "Copyright (C) 2005 - 2006, 2010 - 2012 Sunil Shetye\n" + "Copyright (C) 2005 - 2012 Matthias Andree\n" + )); + fprintf(fp, GT_("Fetchmail comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n" + "are welcome to redistribute it under certain conditions. For details,\n" + "please see the file COPYING in the source or documentation directory.\n")); +#ifdef SSL_ENABLE + /* Do not translate this */ + fprintf(fp, "This product includes software developed by the OpenSSL Project\nfor use in the OpenSSL Toolkit. (http://www.openssl.org/)\n"); +#endif +} + const char *iana_charset; int main(int argc, char **argv) @@ -184,7 +209,7 @@ int main(int argc, char **argv) * call near the beginning of the polling loop for details). We want * to be sure the lock gets nuked on any error exit, basically. */ - lock_dispose(); + fm_lock_dispose(); #ifdef HAVE_GETCWD /* save the current directory */ @@ -194,8 +219,16 @@ int main(int argc, char **argv) } #endif - if ((parsecmdline(argc,argv, &cmd_run, &cmd_opts)) < 0) - exit(PS_SYNTAX); + { + int i; + + i = parsecmdline(argc, argv, &cmd_run, &cmd_opts); + if (i < 0) + exit(PS_SYNTAX); + + if (quitmode && quitind == argc) + quitonly = 1; + } if (versioninfo) { @@ -210,7 +243,7 @@ int main(int argc, char **argv) "-IMAP" #endif /* IMAP_ENABLE */ #ifdef GSSAPI - "+IMAP-GSS" + "+GSS" #endif /* GSSAPI */ #ifdef RPA_ENABLE "+RPA" @@ -233,9 +266,6 @@ int main(int argc, char **argv) #ifdef OPIE_ENABLE "+OPIE" #endif /* OPIE_ENABLE */ -#ifdef INET6_ENABLE - "+INET6" -#endif /* INET6_ENABLE */ #ifdef HAVE_PKG_hesiod "+HESIOD" #endif @@ -245,9 +275,21 @@ int main(int argc, char **argv) #ifdef ENABLE_NLS "+NLS" #endif /* ENABLE_NLS */ - "\n"; +#ifdef KERBEROS_V4 + "+KRB4" +#endif /* KERBEROS_V4 */ +#ifdef KERBEROS_V5 + "+KRB5" +#endif /* KERBEROS_V5 */ +#ifndef HAVE_RES_SEARCH + "-DNS" +#endif + ".\n"; printf(GT_("This is fetchmail release %s"), VERSION); fputs(features, stdout); + puts(""); + printcopyright(stdout); + puts(""); fputs("Fallback MDA: ", stdout); #ifdef FALLBACK_MDA fputs(FALLBACK_MDA, stdout); @@ -258,13 +300,18 @@ int main(int argc, char **argv) fflush(stdout); /* this is an attempt to help remote debugging */ - system("uname -a"); + if (system("uname -a")) { /* NOOP to quench GCC complaint */ } } - /* avoid parsing the config file if all we're doing is killing a daemon */ - if (!(quitmode && argc == 2)) + /* avoid parsing the config file if all we're doing is killing a daemon */ + if (!quitonly) implicitmode = load_params(argc, argv, optind); + /* precedence: logfile (if effective) overrides syslog. */ + if (run.logfile && run.poll_interval && !nodetach) { + run.use_syslog = 0; + } + #if defined(HAVE_SYSLOG) /* logging should be set up early in case we were restarted from exec */ if (run.use_syslog) @@ -281,8 +328,20 @@ int main(int argc, char **argv) #endif report_init((run.poll_interval == 0 || nodetach) && !run.logfile); +#ifdef POP3_ENABLE + /* initialize UID handling */ + { + int st; + + if (!versioninfo && (st = prc_filecheck(run.idfile, !versioninfo)) != 0) + exit(st); + else + initialize_saved_lists(querylist, run.idfile); + } +#endif /* POP3_ENABLE */ + /* construct the lockfile */ - lock_setup(); + fm_lock_setup(&run); #ifdef HAVE_SETRLIMIT /* @@ -338,6 +397,9 @@ int main(int argc, char **argv) } } + free_netrc(netrc_list); + netrc_list = 0; + /* perhaps we just want to check options? */ if (versioninfo) { @@ -364,12 +426,12 @@ int main(int argc, char **argv) } /* check for another fetchmail running concurrently */ - pid = lock_state(); + pid = fm_lock_state(); bkgd = (pid < 0); pid = bkgd ? -pid : pid; /* if no mail servers listed and nothing in background, we're done */ - if (!(quitmode && argc == 2) && pid == 0 && querylist == NULL) { + if (!quitonly && pid == 0 && querylist == NULL) { (void)fputs(GT_("fetchmail: no mailservers have been specified.\n"),stderr); exit(PS_SYNTAX); } @@ -377,36 +439,40 @@ int main(int argc, char **argv) /* perhaps user asked us to kill the other fetchmail */ if (quitmode) { - if (pid == 0) - { - fprintf(stderr,GT_("fetchmail: no other fetchmail is running\n")); - if (argc == 2) - exit(PS_EXCLUDE); - } - else if (getpid() == pid) + if (pid == 0 || pid == getpid()) + /* this test enables re-execing on a changed rcfile + * for pid == getpid() */ { - /* this test enables re-execing on a changed rcfile */ - if (argc == 2) - { + if (quitonly) { fprintf(stderr,GT_("fetchmail: no other fetchmail is running\n")); exit(PS_EXCLUDE); } } else if (kill(pid, SIGTERM) < 0) { - fprintf(stderr,GT_("fetchmail: error killing %s fetchmail at %d; bailing out.\n"), - bkgd ? GT_("background") : GT_("foreground"), pid); + fprintf(stderr,GT_("fetchmail: error killing %s fetchmail at %ld; bailing out.\n"), + bkgd ? GT_("background") : GT_("foreground"), (long)pid); exit(PS_EXCLUDE); } else { - fprintf(stderr,GT_("fetchmail: %s fetchmail at %d killed.\n"), - bkgd ? GT_("background") : GT_("foreground"), pid); - fm_lock_release(); - if (argc == 2) + int maxwait; + + if (outlevel > O_SILENT) + fprintf(stderr,GT_("fetchmail: %s fetchmail at %ld killed.\n"), + bkgd ? GT_("background") : GT_("foreground"), (long)pid); + /* We used to nuke the other process's lock here, with + * fm_lock_release(), which is broken. The other process + * needs to clear its lock by itself. */ + if (quitonly) exit(0); - else - pid = 0; + + /* wait for other process to exit */ + maxwait = 10; /* seconds */ + while (kill(pid, 0) == 0 && --maxwait >= 0) { + sleep(1); + } + pid = 0; } } @@ -422,20 +488,20 @@ int main(int argc, char **argv) else if (!implicitmode) { fprintf(stderr, - GT_("fetchmail: can't poll specified hosts with another fetchmail running at %d.\n"), - pid); + GT_("fetchmail: can't poll specified hosts with another fetchmail running at %ld.\n"), + (long)pid); return(PS_EXCLUDE); } else if (!bkgd) { fprintf(stderr, - GT_("fetchmail: another foreground fetchmail is running at %d.\n"), - pid); + GT_("fetchmail: another foreground fetchmail is running at %ld.\n"), + (long)pid); return(PS_EXCLUDE); } else if (getpid() == pid) /* this test enables re-execing on a changed rcfile */ - lock_assert(); + fm_lock_assert(); else if (argc > 1) { fprintf(stderr, @@ -445,8 +511,8 @@ int main(int argc, char **argv) else if (kill(pid, SIGUSR1) == 0) { fprintf(stderr, - GT_("fetchmail: background fetchmail at %d awakened.\n"), - pid); + GT_("fetchmail: background fetchmail at %ld awakened.\n"), + (long)pid); return(0); } else @@ -457,8 +523,8 @@ int main(int argc, char **argv) * SIGUSR1/SIGHUP transmission. */ fprintf(stderr, - GT_("fetchmail: elder sibling at %d died mysteriously.\n"), - pid); + GT_("fetchmail: elder sibling at %ld died mysteriously.\n"), + (long)pid); return(PS_UNDEFINED); } } @@ -479,7 +545,7 @@ int main(int argc, char **argv) const char* password_prompt = GT_("Enter password for %s@%s: "); size_t pplen = strlen(password_prompt) + strlen(ctl->remotename) + strlen(ctl->server.pollname) + 1; - tmpbuf = xmalloc(pplen); + tmpbuf = (char *)xmalloc(pplen); snprintf(tmpbuf, pplen, password_prompt, ctl->remotename, ctl->server.pollname); ctl->password = xstrdup((char *)fm_getpassword(tmpbuf)); @@ -500,14 +566,29 @@ int main(int argc, char **argv) /* avoid zombies from plugins */ deal_with_sigchld(); + /* Fix up log destination - if the if() is true, the precedence rule + * above hasn't killed off the syslog option, because the logfile + * option is ineffective (because we're not detached or not in + * deamon mode), so kill it for the benefit of other parts of the + * code. */ + if (run.logfile && run.use_syslog) + run.logfile = 0; + /* * Maybe time to go to demon mode... */ if (run.poll_interval) { - if (!nodetach) - daemonize(run.logfile, terminate_run); - report(stdout, GT_("starting fetchmail %s daemon \n"), VERSION); + if (!nodetach) { + int rc; + + rc = daemonize(run.logfile); + if (rc) { + report(stderr, GT_("fetchmail: Cannot detach into background. Aborting.\n")); + exit(rc); + } + } + report(stdout, GT_("starting fetchmail %s daemon\n"), VERSION); /* * We'll set up a handler for these when we're sleeping, @@ -519,18 +600,19 @@ int main(int argc, char **argv) } else { + /* not in daemon mode */ if (run.logfile && !nodetach && access(run.logfile, F_OK) == 0) { if (!freopen(run.logfile, "a", stdout)) - report(stderr, GT_("could not open %s to append logs to \n"), run.logfile); + report(stderr, GT_("could not open %s to append logs to\n"), run.logfile); if (!freopen(run.logfile, "a", stderr)) - report(stdout, GT_("could not open %s to append logs to \n"), run.logfile); + report(stdout, GT_("could not open %s to append logs to\n"), run.logfile); + if (run.use_syslog) + report(stdout, GT_("fetchmail: Warning: syslog and logfile are set. Check both for logs!\n")); } } -#ifdef linux interface_init(); -#endif /* linux */ /* beyond here we don't want more than one fetchmail running per user */ umask(0077); @@ -538,11 +620,15 @@ int main(int argc, char **argv) set_signal_handler(SIGINT, terminate_run); set_signal_handler(SIGTERM, terminate_run); set_signal_handler(SIGALRM, terminate_run); - set_signal_handler(SIGPIPE, terminate_run); + set_signal_handler(SIGPIPE, SIG_IGN); set_signal_handler(SIGQUIT, terminate_run); /* here's the exclusion lock */ - lock_or_die(); + fm_lock_or_die(); + + if (check_only && outlevel >= O_VERBOSE) { + report(stdout, GT_("--check mode enabled, not fetching mail\n")); + } /* * Query all hosts. If there's only one, the error return will @@ -558,8 +644,9 @@ int main(int argc, char **argv) */ struct stat rcstat; - if (stat(rcfile, &rcstat) == -1) - { + if (strcmp(rcfile, "-") == 0) { + /* do nothing */ + } else if (stat(rcfile, &rcstat) == -1) { if (errno != ENOENT) report(stderr, GT_("couldn't time-check %s (error %d)\n"), @@ -602,19 +689,21 @@ int main(int argc, char **argv) report(stderr, GT_("attempt to re-exec fetchmail failed\n")); } -#if defined(HAVE_RES_SEARCH) && defined(USE_TCPIP_FOR_DNS) - /* - * This was an efficiency hack that backfired. The theory - * was that using TCP/IP for DNS queries would get us better - * reliability and shave off some per-UDP-packet costs. - * Unfortunately it interacted badly with diald, which effectively - * filters out DNS queries over TCP/IP for reasons having to do - * with some obscure Linux kernel problem involving bootstrapping of - * dynamically-addressed links. I don't understand this mess - * and don't want to, so it's "See ya!" to this hack. - */ - sethostent(TRUE); /* use TCP/IP for mailserver queries */ -#endif /* HAVE_RES_SEARCH */ +#ifdef HAVE_RES_SEARCH + /* Boldly assume that we also have res_init() if we have + * res_search(), and call res_init() to re-read the resolv.conf + * file, so that we can pick up changes to that file that are + * written by dhpccd, dhclient, pppd, openvpn and similar. */ + + /* NOTE: This assumes that /etc/resolv.conf is written + * atomically (i. e. a temporary file is written, flushed and + * then renamed into place). To fix Debian Bug#389270. */ + + /* NOTE: If this leaks memory or doesn't re-read + * /etc/resolv.conf, we're in trouble. The res_init() interface + * is only lightly documented :-( */ + res_init(); +#endif activecount = 0; batchcount = 0; @@ -645,14 +734,14 @@ int main(int argc, char **argv) } } -#if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) +#ifdef CAN_MONITOR /* * Don't do monitoring if we were woken by a signal. * Note that interface_approve() does its own error logging. */ if (!interface_approve(&ctl->server, !lastsig)) continue; -#endif /* (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) */ +#endif /* CAN_MONITOR */ dofastuidl = 0; /* this is reset in the driver if required */ @@ -709,7 +798,7 @@ int main(int argc, char **argv) break; } -#if (defined(linux) && !defined(INET6_ENABLE)) || defined (__FreeBSD__) +#ifdef CAN_MONITOR if (ctl->server.monitor) { /* @@ -720,14 +809,10 @@ int main(int argc, char **argv) sleep(3); interface_note_activity(&ctl->server); } -#endif /* (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) */ +#endif /* CAN_MONITOR */ } } -#if defined(HAVE_RES_SEARCH) && defined(USE_TCPIP_FOR_DNS) - endhostent(); /* release TCP/IP connection to nameserver */ -#endif /* HAVE_RES_SEARCH */ - /* close connections cleanly */ terminate_poll(0); @@ -756,9 +841,10 @@ int main(int argc, char **argv) exit(PS_AUTHFAIL); } - if (outlevel > O_SILENT) - report(stdout, - GT_("sleeping at %s\n"), timestamp()); + if ((outlevel > O_SILENT && !run.use_syslog && isatty(1)) + || outlevel > O_NORMAL) + report(stdout, + GT_("sleeping at %s for %d seconds\n"), timestamp(), run.poll_interval); /* * With this simple hack, we make it possible for a foreground @@ -768,7 +854,7 @@ int main(int argc, char **argv) * for people who think all system daemons wake up on SIGHUP. */ set_signal_handler(SIGUSR1, donothing); - if (getuid() != ROOT_UID) + if (getuid() == ROOT_UID) set_signal_handler(SIGHUP, donothing); /* @@ -791,11 +877,11 @@ int main(int argc, char **argv) ctl->wedged = FALSE; } - if (outlevel > O_SILENT) + if ((outlevel > O_SILENT && !run.use_syslog && isatty(1)) + || outlevel > O_NORMAL) report(stdout, GT_("awakened at %s\n"), timestamp()); } - } while - (run.poll_interval); + } while (run.poll_interval); if (outlevel >= O_VERBOSE) report(stdout, GT_("normal termination, status %d\n"), @@ -853,15 +939,16 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(server.uidl); FLAG_MERGE(server.principal); -#if defined(linux) || defined(__FreeBSD__) +#ifdef CAN_MONITOR FLAG_MERGE(server.interface); - FLAG_MERGE(server.monitor); FLAG_MERGE(server.interface_pair); -#endif /* linux || defined(__FreeBSD__) */ + FLAG_MERGE(server.monitor); +#endif FLAG_MERGE(server.plugin); FLAG_MERGE(server.plugout); FLAG_MERGE(server.tracepolls); + FLAG_MERGE(server.badheader); FLAG_MERGE(wildcard); FLAG_MERGE(remotename); @@ -876,6 +963,7 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(keep); FLAG_MERGE(flush); + FLAG_MERGE(limitflush); FLAG_MERGE(fetchall); FLAG_MERGE(rewrite); FLAG_MERGE(forcecr); @@ -897,7 +985,9 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(sslcert); FLAG_MERGE(sslproto); FLAG_MERGE(sslcertck); + FLAG_MERGE(sslcertfile); FLAG_MERGE(sslcertpath); + FLAG_MERGE(sslcommonname); FLAG_MERGE(sslfingerprint); #endif FLAG_MERGE(expunge); @@ -906,6 +996,9 @@ static void optmerge(struct query *h2, struct query *h1, int force) #undef FLAG_MERGE } +/** Load configuration files. + * \return - true if no servers found on the command line + * - false if servers found on the command line */ static int load_params(int argc, char **argv, int optind) { int implicitmode, st; @@ -915,6 +1008,7 @@ static int load_params(int argc, char **argv, int optind) char *p; run.bouncemail = TRUE; + run.softbounce = TRUE; /* treat permanent errors as temporary */ run.spambounce = FALSE; /* don't bounce back to innocent bystanders */ memset(&def_opts, '\0', sizeof(struct query)); @@ -924,16 +1018,17 @@ static int load_params(int argc, char **argv, int optind) def_opts.server.protocol = P_AUTO; def_opts.server.timeout = CLIENT_TIMEOUT; def_opts.server.esmtp_name = user; + def_opts.server.badheader = BHREJECT; def_opts.warnings = WARNING_INTERVAL; def_opts.remotename = user; def_opts.listener = SMTP_MODE; def_opts.fetchsizelimit = 100; - def_opts.fastuidl = 10; + def_opts.fastuidl = 4; /* get the location of rcfile */ rcfiledir[0] = 0; p = strrchr (rcfile, '/'); - if (p && (p - rcfile) < sizeof (rcfiledir)) { + if (p && (size_t)(p - rcfile) < sizeof (rcfiledir)) { *p = 0; /* replace '/' by '0' */ strlcpy (rcfiledir, rcfile, sizeof(rcfiledir)); *p = '/'; /* restore '/' */ @@ -942,11 +1037,14 @@ static int load_params(int argc, char **argv, int optind) } /* note the parse time, so we can pick up on modifications */ - parsetime = 0; /* foil compiler warnings */ - if (stat(rcfile, &rcstat) != -1) - parsetime = rcstat.st_mtime; - else if (errno != ENOENT) - report(stderr, GT_("couldn't time-check the run-control file\n")); + if (strcmp(rcfile, "-") == 0) + parsetime = time(NULL); + else { + if (stat(rcfile, &rcstat) != -1) + parsetime = rcstat.st_mtime; + else if (errno != ENOENT) + report(stderr, GT_("couldn't time-check the run-control file\n")); + } /* this builds the host list */ if ((st = prc_parse_file(rcfile, !versioninfo)) != 0) @@ -978,7 +1076,7 @@ static int load_params(int argc, char **argv, int optind) || str_in_list(&ctl->server.akalist, argv[optind], TRUE)) { /* Is this correct? */ - if (predeclared && outlevel == O_VERBOSE) + if (predeclared && outlevel >= O_VERBOSE) fprintf(stderr,GT_("Warning: multiple mentions of host %s in config file\n"),argv[optind]); ctl->active = TRUE; predeclared = TRUE; @@ -1001,18 +1099,27 @@ static int load_params(int argc, char **argv, int optind) /* * If there's a defaults record, merge it and lose it. + * FIXME: we don't currently free all entries that might be in struct query. */ if (querylist && strcmp(querylist->server.pollname, "defaults") == 0) { + struct query *tmpq; + for (ctl = querylist->next; ctl; ctl = ctl->next) optmerge(ctl, querylist, FALSE); + tmpq = querylist; querylist = querylist->next; + free(tmpq->server.pollname); + free(tmpq); } /* don't allow a defaults record after the first */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl != querylist && strcmp(ctl->server.pollname, "defaults") == 0) + for (ctl = querylist; ctl; ctl = ctl->next) { + if (ctl != querylist && strcmp(ctl->server.pollname, "defaults") == 0) { + fprintf(stderr, GT_("fetchmail: Error: multiple \"defaults\" records in config file.\n")); exit(PS_SYNTAX); + } + } /* use localhost if we never fetch the FQDN of this host */ fetchmailhost = "localhost"; @@ -1022,19 +1129,23 @@ static int load_params(int argc, char **argv, int optind) run.logfile = cmd_run.logfile; if (cmd_run.idfile) run.idfile = cmd_run.idfile; + if (cmd_run.pidfile) + run.pidfile = cmd_run.pidfile; /* do this before the keep/fetchall test below, otherwise -d0 may fail */ if (cmd_run.poll_interval >= 0) run.poll_interval = cmd_run.poll_interval; if (cmd_run.invisible) - run.invisible = cmd_run.invisible; + run.invisible = (cmd_run.invisible == FLAG_TRUE); if (cmd_run.showdots) - run.showdots = cmd_run.showdots; + run.showdots = (cmd_run.showdots == FLAG_TRUE); if (cmd_run.use_syslog) run.use_syslog = (cmd_run.use_syslog == FLAG_TRUE); if (cmd_run.postmaster) run.postmaster = cmd_run.postmaster; if (cmd_run.bouncemail) - run.bouncemail = cmd_run.bouncemail; + run.bouncemail = (cmd_run.bouncemail == FLAG_TRUE); + if (cmd_run.softbounce) + run.softbounce = (cmd_run.softbounce == FLAG_TRUE); /* check and daemon options are not compatible */ if (check_only && run.poll_interval) @@ -1059,10 +1170,13 @@ static int load_params(int argc, char **argv, int optind) || ctl->server.authenticate == A_KERBEROS_V4 || ctl->server.authenticate == A_KERBEROS_V5)) { - fetchmailhost = host_fqdn(); + fetchmailhost = host_fqdn(1); break; } + if (!ctl) /* list exhausted */ + fetchmailhost = host_fqdn(0); + /* this code enables flags to be turned off */ #define DEFAULT(flag, dflt) if (flag == FLAG_TRUE)\ flag = TRUE;\ @@ -1070,8 +1184,6 @@ static int load_params(int argc, char **argv, int optind) flag = FALSE;\ else\ flag = (dflt) - /* one global gets treated specially */ - DEFAULT(run.showdots, run.poll_interval==0 || nodetach); /* merge in wired defaults, do sanity checks and prepare internal fields */ for (ctl = querylist; ctl; ctl = ctl->next) @@ -1105,6 +1217,7 @@ static int load_params(int argc, char **argv, int optind) DEFAULT(ctl->keep, FALSE); DEFAULT(ctl->fetchall, FALSE); DEFAULT(ctl->flush, FALSE); + DEFAULT(ctl->limitflush, FALSE); DEFAULT(ctl->rewrite, TRUE); DEFAULT(ctl->stripcr, (ctl->mda != (char *)NULL)); DEFAULT(ctl->forcecr, FALSE); @@ -1130,12 +1243,30 @@ static int load_params(int argc, char **argv, int optind) } #endif /* SSL_ENABLE */ #undef DEFAULT +#ifndef KERBEROS_V4 + if (ctl->server.authenticate == A_KERBEROS_V4) { + report(stderr, GT_("KERBEROS v4 support is configured, but not compiled in.\n")); + exit(PS_SYNTAX); + } +#endif +#ifndef KERBEROS_V5 + if (ctl->server.authenticate == A_KERBEROS_V5) { + report(stderr, GT_("KERBEROS v5 support is configured, but not compiled in.\n")); + exit(PS_SYNTAX); + } +#endif +#ifndef GSSAPI + if (ctl->server.authenticate == A_GSSAPI) { + report(stderr, GT_("GSSAPI support is configured, but not compiled in.\n")); + exit(PS_SYNTAX); + } +#endif /* * Make sure we have a nonempty host list to forward to. */ if (!ctl->smtphunt) - save_str(&ctl->smtphunt, fetchmailhost, FALSE); + save_str(&ctl->smtphunt, "localhost", FALSE); /* * Make sure we have a nonempty list of domains to fetch from. @@ -1151,14 +1282,14 @@ static int load_params(int argc, char **argv, int optind) if (!ctl->localnames) /* for local delivery via SMTP */ save_str_pair(&ctl->localnames, user, NULL); -#if !defined(HAVE_GETHOSTBYNAME) || !defined(HAVE_RES_SEARCH) +#ifndef HAVE_RES_SEARCH /* can't handle multidrop mailboxes unless we can do DNS lookups */ if (MULTIDROP(ctl) && ctl->server.dns) { ctl->server.dns = FALSE; report(stderr, GT_("fetchmail: warning: no DNS available to check multidrop fetches from %s\n"), ctl->server.pollname); } -#endif /* !HAVE_GETHOSTBYNAME || !HAVE_RES_SEARCH */ +#endif /* !HAVE_RES_SEARCH */ /* * can't handle multidrop mailboxes without "envelope" @@ -1179,21 +1310,20 @@ static int load_params(int argc, char **argv, int optind) if (ctl->server.timeout == -1) ctl->server.timeout = CLIENT_TIMEOUT; -#ifndef INET6_ENABLE /* sanity checks */ if (ctl->server.service) { int port = servport(ctl->server.service); if (port < 0) { (void) fprintf(stderr, - GT_("%s configuration invalid, port number cannot be negative\n"), + GT_("fetchmail: %s configuration invalid, specify positive port number for service or port\n"), ctl->server.pollname); exit(PS_SYNTAX); } if (ctl->server.protocol == P_RPOP && port >= 1024) { (void) fprintf(stderr, - GT_("%s configuration invalid, RPOP requires a privileged port\n"), + GT_("fetchmail: %s configuration invalid, RPOP requires a privileged port\n"), ctl->server.pollname); exit(PS_SYNTAX); } @@ -1206,9 +1336,9 @@ static int load_params(int argc, char **argv, int optind) { char *cp; - if (!(cp = strrchr(idp->id, '/')) || - ++cp, (0 == strcmp(cp, SMTP_PORT)) - || servport(cp) == SMTP_PORT_NUM) + if (!(cp = strrchr(idp->id, '/')) + || (0 == strcmp(cp + 1, SMTP_PORT)) + || servport(cp + 1) == SMTP_PORT_NUM) { (void) fprintf(stderr, GT_("%s configuration invalid, LMTP can't use default SMTP port\n"), @@ -1217,29 +1347,19 @@ static int load_params(int argc, char **argv, int optind) } } } -#endif /* !INET6_ENABLE */ /* - * "I beg to you, have mercy on the week minds like myself." + * "I beg to you, have mercy on the we[a]k minds like myself." * wrote Pehr Anderson. Your petition is granted. */ - if (ctl->fetchall && ctl->keep && run.poll_interval && !nodetach) + if (ctl->fetchall && ctl->keep && (run.poll_interval || ctl->idle) && !nodetach && !configdump) { (void) fprintf(stderr, - GT_("Both fetchall and keep on in daemon mode is a mistake!\n")); - exit(PS_SYNTAX); + GT_("Both fetchall and keep on in daemon or idle mode is a mistake!\n")); } } } -#ifdef POP3_ENABLE - /* initialize UID handling */ - if (!versioninfo && (st = prc_filecheck(run.idfile, !versioninfo)) != 0) - exit(st); - else - initialize_saved_lists(querylist, run.idfile); -#endif /* POP3_ENABLE */ - /* * If the user didn't set a last-resort user to get misaddressed * multidrop mail, set an appropriate default here. @@ -1258,38 +1378,9 @@ static int load_params(int argc, char **argv, int optind) static RETSIGTYPE terminate_poll(int sig) /* to be executed at the end of a poll cycle */ { - /* - * Close all SMTP delivery sockets. For optimum performance - * we'd like to hold them open til end of run, but (1) this - * loses if our poll interval is longer than the MTA's inactivity - * timeout, and (2) some MTAs (like smail) don't deliver after - * each message, but rather queue up mail and wait to actually - * deliver it until the input socket is closed. - * - * Sending SMTP QUIT on signal is theoretically nice, but led to a - * subtle bug. If fetchmail was terminated by signal while it was - * shipping message text, it would hang forever waiting for a - * command acknowledge. In theory we could enable the QUIT - * only outside of the message send. In practice, we don't - * care. All mailservers hang up on a dropped TCP/IP connection - * anyway. - */ if (sig != 0) report(stdout, GT_("terminated with signal %d\n"), sig); - else - { - struct query *ctl; - - /* terminate all SMTP connections cleanly */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl->smtp_socket != -1) - { - /* don't send QUIT for ODMR case because we're acting - as a proxy between the SMTP server and client. */ - smtp_close(ctl, ctl->server.protocol != P_ODMR); - } - } #ifdef POP3_ENABLE /* @@ -1324,7 +1415,7 @@ static RETSIGTYPE terminate_run(int sig) if (ctl->password) memset(ctl->password, '\0', strlen(ctl->password)); -#if !defined(HAVE_ATEXIT) && !defined(HAVE_ON_EXIT) +#if !defined(HAVE_ATEXIT) fm_lock_release(); #endif @@ -1353,7 +1444,8 @@ static const int autoprobe[] = static int query_host(struct query *ctl) /* perform fetch transaction with single host */ { - int i, st = 0; + size_t i; + int st = 0; /* * If we're syslogging the progress messages are automatically timestamped. @@ -1417,12 +1509,7 @@ static int query_host(struct query *ctl) report(stderr, GT_("ETRN support is not configured.\n")); st = PS_PROTOCOL; #else -#ifdef HAVE_GETHOSTBYNAME st = doETRN(ctl); -#else - report(stderr, GT_("Cannot support ETRN without gethostbyname(2).\n")); - st = PS_PROTOCOL; -#endif /* HAVE_GETHOSTBYNAME */ break; #endif /* ETRN_ENABLE */ case P_ODMR: @@ -1430,12 +1517,7 @@ static int query_host(struct query *ctl) report(stderr, GT_("ODMR support is not configured.\n")); st = PS_PROTOCOL; #else -#ifdef HAVE_GETHOSTBYNAME st = doODMR(ctl); -#else - report(stderr, GT_("Cannot support ODMR without gethostbyname(2).\n")); - st = PS_PROTOCOL; -#endif /* HAVE_GETHOSTBYNAME */ #endif /* ODMR_ENABLE */ break; default: @@ -1488,6 +1570,11 @@ static void dump_params (struct runctl *runp, else if (outlevel >= O_VERBOSE) printf(GT_("Fetchmail will direct error mail to the sender.\n")); + if (!runp->softbounce) + printf(GT_("Fetchmail will treat permanent errors as permanent (drop messages).\n")); + else if (outlevel >= O_VERBOSE) + printf(GT_("Fetchmail will treat permanent errors as temporary (keep messages).\n")); + for (ctl = querylist; ctl; ctl = ctl->next) { if (!ctl->active || (implicit && ctl->server.skip)) @@ -1551,6 +1638,9 @@ static void dump_params (struct runctl *runp, case A_PASSWORD: printf(GT_(" Password authentication will be forced.\n")); break; + case A_MSN: + printf(GT_(" MSN authentication will be forced.\n")); + break; case A_NTLM: printf(GT_(" NTLM authentication will be forced.\n")); break; @@ -1558,7 +1648,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" OTP authentication will be forced.\n")); break; case A_CRAM_MD5: - printf(GT_(" CRAM-Md5 authentication will be forced.\n")); + printf(GT_(" CRAM-MD5 authentication will be forced.\n")); break; case A_GSSAPI: printf(GT_(" GSSAPI authentication will be forced.\n")); @@ -1582,9 +1672,13 @@ static void dump_params (struct runctl *runp, printf(GT_(" SSL protocol: %s.\n"), ctl->sslproto); if (ctl->sslcertck) { printf(GT_(" SSL server certificate checking enabled.\n")); - if (ctl->sslcertpath != NULL) - printf(GT_(" SSL trusted certificate directory: %s\n"), ctl->sslcertpath); } + if (ctl->sslcertfile != NULL) + printf(GT_(" SSL trusted certificate file: %s\n"), ctl->sslcertfile); + if (ctl->sslcertpath != NULL) + printf(GT_(" SSL trusted certificate directory: %s\n"), ctl->sslcertpath); + if (ctl->sslcommonname != NULL) + printf(GT_(" SSL server CommonName: %s\n"), ctl->sslcommonname); if (ctl->sslfingerprint != NULL) printf(GT_(" SSL key fingerprint (checked against the server key): %s\n"), ctl->sslfingerprint); #endif @@ -1605,7 +1699,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" Selected mailboxes are:")); for (idp = ctl->mailboxes; idp; idp = idp->next) - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); printf("\n"); } printf(ctl->fetchall @@ -1617,6 +1711,9 @@ static void dump_params (struct runctl *runp, printf(ctl->flush ? GT_(" Old messages will be flushed before message retrieval (--flush on).\n") : GT_(" Old messages will not be flushed before message retrieval (--flush off).\n")); + printf(ctl->limitflush + ? GT_(" Oversized messages will be flushed before message retrieval (--limitflush on).\n") + : GT_(" Oversized messages will not be flushed before message retrieval (--limitflush off).\n")); printf(ctl->rewrite ? GT_(" Rewrite of server-local addresses is enabled (--norewrite off).\n") : GT_(" Rewrite of server-local addresses is disabled (--norewrite on).\n")); @@ -1640,7 +1737,8 @@ static void dump_params (struct runctl *runp, : GT_(" Nonempty Status lines will be kept (dropstatus off)\n")); printf(ctl->dropdelivered ? GT_(" Delivered-To lines will be discarded (dropdelivered on)\n") - : GT_(" Delivered-To lines will be kept (dropdelivered off)\n")); if (NUM_NONZERO(ctl->limit)) + : GT_(" Delivered-To lines will be kept (dropdelivered off)\n")); + if (NUM_NONZERO(ctl->limit)) { if (NUM_NONZERO(ctl->limit)) printf(GT_(" Message size limit is %d octets (--limit %d).\n"), @@ -1691,7 +1789,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" Domains for which mail will be fetched are:")); for (idp = ctl->domainlist; idp; idp = idp->next) { - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); if (!idp->val.status.mark) printf(GT_(" (default)")); } @@ -1711,7 +1809,7 @@ static void dump_params (struct runctl *runp, ctl->listener); for (idp = ctl->smtphunt; idp; idp = idp->next) { - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); if (!idp->val.status.mark) printf(GT_(" (default)")); } @@ -1769,9 +1867,9 @@ static void dump_params (struct runctl *runp, { for (idp = ctl->localnames; idp; idp = idp->next) if (idp->val.id2) - printf("\t%s -> %s\n", (char *)idp->id, (char *)idp->val.id2); + printf("\t%s -> %s\n", idp->id, idp->val.id2); else - printf("\t%s\n", (char *)idp->id); + printf("\t%s\n", idp->id); if (ctl->wildcard) fputs("\t*\n", stdout); } @@ -1793,9 +1891,9 @@ static void dump_params (struct runctl *runp, else { printf(GT_(" Envelope header is assumed to be: %s\n"), - ctl->server.envelope ? ctl->server.envelope:GT_("Received")); - if (ctl->server.envskip > 1 || outlevel >= O_VERBOSE) - printf(GT_(" Number of envelope header to be parsed: %d\n"), + ctl->server.envelope ? ctl->server.envelope : "Received"); + if (ctl->server.envskip || outlevel >= O_VERBOSE) + printf(GT_(" Number of envelope headers to be skipped over: %d\n"), ctl->server.envskip); if (ctl->server.qvirtual) printf(GT_(" Prefix %s will be removed from user id\n"), @@ -1806,26 +1904,23 @@ static void dump_params (struct runctl *runp, if (ctl->server.akalist) { - struct idlist *idp; - printf(GT_(" Predeclared mailserver aliases:")); for (idp = ctl->server.akalist; idp; idp = idp->next) - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); putchar('\n'); } + if (ctl->server.localdomains) { - struct idlist *idp; - printf(GT_(" Local domains:")); for (idp = ctl->server.localdomains; idp; idp = idp->next) - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); putchar('\n'); } } } } -#if defined(linux) || defined(__FreeBSD__) +#ifdef CAN_MONITOR if (ctl->server.interface) printf(GT_(" Connection must be through interface %s.\n"), ctl->server.interface); else if (outlevel >= O_VERBOSE) @@ -1860,14 +1955,24 @@ static void dump_params (struct runctl *runp, printf(GT_(" %d UIDs saved.\n"), count); if (outlevel >= O_VERBOSE) for (idp = ctl->oldsaved; idp; idp = idp->next) - printf("\t%s\n", (char *)idp->id); + printf("\t%s\n", idp->id); } } if (ctl->server.tracepolls) printf(GT_(" Poll trace information will be added to the Received header.\n")); else if (outlevel >= O_VERBOSE) - printf(GT_(" No poll trace information will be added to the Received header.\n.\n")); + printf(GT_(" No poll trace information will be added to the Received header.\n")); + + switch (ctl->server.badheader) { + case BHREJECT: + if (outlevel >= O_VERBOSE) + printf(GT_(" Messages with bad headers will be rejected.\n")); + break; + case BHACCEPT: + printf(GT_(" Messages with bad headers will be passed on.\n")); + break; + } if (ctl->properties) printf(GT_(" Pass-through properties \"%s\".\n"),