X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fetchmail.c;h=37abf44baf93e0f03733f9acc79e260e078f2bc0;hb=ca66045dfe48faa985f39c0208aded9f93d3da96;hp=9ee0d62734e9f9a383338aa5d791c874df252bc6;hpb=335cb5e4606e4f5265292ae76b95793b2ed9f047;p=~andy%2Ffetchmail diff --git a/fetchmail.c b/fetchmail.c index 9ee0d627..37abf44b 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 */ @@ -127,6 +133,17 @@ 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, Robert M. Funk, Graham Wilson\n" + "Copyright (C) 2005 - 2006 Sunil Shetye\n" + "Copyright (C) 2005 - 2009 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")); +} + const char *iana_charset; int main(int argc, char **argv) @@ -187,7 +204,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 */ @@ -221,7 +238,7 @@ int main(int argc, char **argv) "-IMAP" #endif /* IMAP_ENABLE */ #ifdef GSSAPI - "+IMAP-GSS" + "+GSS" #endif /* GSSAPI */ #ifdef RPA_ENABLE "+RPA" @@ -253,9 +270,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); @@ -266,13 +295,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 (!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) @@ -289,8 +323,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 /* @@ -346,6 +392,9 @@ int main(int argc, char **argv) } } + free_netrc(netrc_list); + netrc_list = 0; + /* perhaps we just want to check options? */ if (versioninfo) { @@ -372,7 +421,7 @@ 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; @@ -447,7 +496,7 @@ int main(int argc, char **argv) } else if (getpid() == pid) /* this test enables re-execing on a changed rcfile */ - lock_assert(); + fm_lock_assert(); else if (argc > 1) { fprintf(stderr, @@ -491,7 +540,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)); @@ -512,13 +561,28 @@ 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); + 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); /* @@ -531,12 +595,15 @@ 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); if (!freopen(run.logfile, "a", stderr)) 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")); } } @@ -548,11 +615,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 @@ -568,8 +639,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"), @@ -612,19 +684,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; @@ -734,10 +808,6 @@ int main(int argc, char **argv) } } -#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); @@ -766,9 +836,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 @@ -778,7 +849,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); /* @@ -801,11 +872,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"), @@ -909,6 +980,7 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(sslproto); FLAG_MERGE(sslcertck); FLAG_MERGE(sslcertpath); + FLAG_MERGE(sslcommonname); FLAG_MERGE(sslfingerprint); #endif FLAG_MERGE(expunge); @@ -929,6 +1001,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)); @@ -942,12 +1015,12 @@ static int load_params(int argc, char **argv, int optind) 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 '/' */ @@ -957,7 +1030,7 @@ 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) + if (strcmp(rcfile, "-") == 0 || stat(rcfile, &rcstat) != -1) parsetime = rcstat.st_mtime; else if (errno != ENOENT) report(stderr, GT_("couldn't time-check the run-control file\n")); @@ -992,7 +1065,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; @@ -1039,6 +1112,8 @@ 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; @@ -1052,6 +1127,8 @@ static int load_params(int argc, char **argv, int optind) run.postmaster = cmd_run.postmaster; if (cmd_run.bouncemail) run.bouncemail = cmd_run.bouncemail; + if (cmd_run.softbounce) + run.softbounce = cmd_run.softbounce; /* check and daemon options are not compatible */ if (check_only && run.poll_interval) @@ -1090,8 +1167,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) @@ -1151,6 +1226,24 @@ 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. @@ -1226,9 +1319,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"), @@ -1242,23 +1335,14 @@ static int load_params(int argc, char **argv, int optind) * "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. @@ -1343,7 +1427,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. @@ -1468,6 +1553,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 messsages).\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)) @@ -1568,6 +1658,8 @@ static void dump_params (struct runctl *runp, 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 @@ -1588,7 +1680,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 @@ -1678,7 +1770,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)")); } @@ -1698,7 +1790,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)")); } @@ -1756,9 +1848,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); } @@ -1797,7 +1889,7 @@ static void dump_params (struct runctl *runp, 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) @@ -1806,7 +1898,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" Local domains:")); for (idp = ctl->server.localdomains; idp; idp = idp->next) - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); putchar('\n'); } } @@ -1847,7 +1939,7 @@ 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); } }