#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
+#include <fcntl.h>
#include <string.h>
#include <signal.h>
+#include <getopt.h>
#if defined(HAVE_SYSLOG)
#include <syslog.h>
#endif
#include <pwd.h>
+#ifdef __FreeBSD__
+#include <grp.h>
+#endif
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#endif /* HAVE_SETRLIMIT */
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
-#endif
+#endif /* HAVE_SYS_WAIT_H */
#ifdef HAVE_GETHOSTBYNAME
#include <netdb.h>
#include "fetchmail.h"
#include "tunable.h"
#include "smtp.h"
-#include "getopt.h"
#include "netrc.h"
#include "i18n.h"
char *program_name; /* the name to prefix error messages with */
flag configdump; /* dump control blocks for configurator */
const char *fetchmailhost; /* either `localhost' or the host's FQDN */
+volatile int lastsig; /* last signal received */
#if NET_SECURITY
void *request = NULL;
static char *lockfile; /* name of lockfile */
static int querystatus; /* status of query */
static int successes; /* count number of successful polls */
-static int lastsig; /* last signal received */
static struct runctl cmd_run; /* global options set from command line */
static void termhook(int); /* forward declaration of exit hook */
}
#endif
-int main (int argc, char **argv)
+#ifdef __FreeBSD__
+/* drop SGID kmem privileage until we need it */
+static void dropprivs(void)
+{
+ struct group *gr;
+ gid_t egid;
+ gid_t rgid;
+
+ egid = getegid();
+ rgid = getgid();
+ gr = getgrgid(egid);
+
+ if (gr && !strcmp(gr->gr_name, "kmem"))
+ {
+ extern void interface_set_gids(gid_t egid, gid_t rgid);
+ interface_set_gids(egid, rgid);
+ setegid(rgid);
+ }
+}
+#endif
+
+int main(int argc, char **argv)
{
int st, bkgd = FALSE;
int parsestatus, implicitmode = FALSE;
char *netrc_file, *tmpbuf;
pid_t pid;
+#ifdef __FreeBSD__
+ dropprivs();
+#endif
+
envquery(argc, argv);
#ifdef ENABLE_NLS
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef RPA_ENABLE
printf("+RPA");
#endif /* RPA_ENABLE */
+#ifdef NTLM_ENABLE
+ printf("+NTLM");
+#endif /* NTLM_ENABLE */
#ifdef SDPS_ENABLE
printf("+SDPS");
#endif /* SDPS_ENABLE */
}
#undef FETCHMAIL_PIDFILE
+#ifdef HAVE_SETRLIMIT
+ /*
+ * Before getting passwords, disable core dumps unless -v -d0 mode is on.
+ * Core dumps could otherwise contain passwords to be scavenged by a
+ * cracker.
+ */
+ if (outlevel < O_VERBOSE || run.poll_interval > 0)
+ {
+ struct rlimit corelimit;
+ corelimit.rlim_cur = 0;
+ corelimit.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &corelimit);
+ }
+#endif /* HAVE_SETRLIMIT */
+
+#define NETRC_FILE ".netrc"
+ /* parse the ~/.netrc file (if present) for future password lookups. */
+ xalloca(netrc_file, char *, strlen (home) + strlen(NETRC_FILE) + 2);
+ strcpy (netrc_file, home);
+ strcat (netrc_file, "/");
+ strcat (netrc_file, NETRC_FILE);
+ netrc_list = parse_netrc(netrc_file);
+#undef NETRC_FILE
+
+ /* pick up passwords where we can */
+ for (ctl = querylist; ctl; ctl = ctl->next)
+ {
+ if (ctl->active && !(implicitmode && ctl->server.skip)&&!ctl->password)
+ {
+ if (ctl->server.preauthenticate == A_KERBEROS_V4 ||
+ ctl->server.preauthenticate == A_KERBEROS_V5 ||
+#ifdef GSSAPI
+ ctl->server.protocol == P_IMAP_GSS ||
+#endif /* GSSAPI */
+ ctl->server.protocol == P_IMAP_K4)
+ /* Server won't care what the password is, but there
+ must be some non-null string here. */
+ ctl->password = ctl->remotename;
+ else
+ {
+ netrc_entry *p;
+
+ /* look up the pollname and account in the .netrc file. */
+ p = search_netrc(netrc_list,
+ ctl->server.pollname, ctl->remotename);
+ /* if we find a matching entry with a password, use it */
+ if (p && p->password)
+ ctl->password = xstrdup(p->password);
+
+ /* otherwise try with "via" name if there is one */
+ else if (ctl->server.via)
+ {
+ p = search_netrc(netrc_list,
+ ctl->server.via, ctl->remotename);
+ if (p && p->password)
+ ctl->password = xstrdup(p->password);
+ }
+ }
+ }
+ }
+
/* perhaps we just want to check options? */
if (versioninfo)
{
}
}
- /* parse the ~/.netrc file (if present) for future password lookups. */
- xalloca(netrc_file, char *, strlen (home) + 8);
- strcpy (netrc_file, home);
- strcat (netrc_file, "/.netrc");
- netrc_list = parse_netrc(netrc_file);
-
-#ifdef HAVE_SETRLIMIT
- /*
- * Before getting passwords, disable core dumps unless -v -d0 mode is on.
- * Core dumps could otherwise contain passwords to be scavenged by a
- * cracker.
- */
- if (outlevel < O_VERBOSE || run.poll_interval > 0)
- {
- struct rlimit corelimit;
- corelimit.rlim_cur = 0;
- corelimit.rlim_max = 0;
- setrlimit(RLIMIT_CORE, &corelimit);
- }
-#endif /* HAVE_SETRLIMIT */
-
/* pick up interactively any passwords we need but don't have */
for (ctl = querylist; ctl; ctl = ctl->next)
{
- if (ctl->active && !(implicitmode && ctl->server.skip)&&!ctl->password)
- {
- if (ctl->server.preauthenticate == A_KERBEROS_V4 ||
- ctl->server.preauthenticate == A_KERBEROS_V5 ||
-#ifdef GSSAPI
- ctl->server.protocol == P_IMAP_GSS ||
-#endif /* GSSAPI */
- ctl->server.protocol == P_IMAP_K4)
- /* Server won't care what the password is, but there
- must be some non-null string here. */
- ctl->password = ctl->remotename;
- else
- {
- netrc_entry *p;
-
- /* look up the pollname and account in the .netrc file. */
- p = search_netrc(netrc_list, ctl->server.pollname);
- while (p && strcmp(p->account, ctl->remotename))
- p = search_netrc(p->next, ctl->remotename);
- /* if we find a matching entry with a password, use it */
- if (p && p->password)
- ctl->password = xstrdup(p->password);
-
- /* otherwise try with "via" name if there is one */
- else if (ctl->server.via)
- {
- p = search_netrc(netrc_list, ctl->server.via);
- while (p && strcmp(p->account, ctl->remotename))
- p = search_netrc(p->next, ctl->remotename);
- if (p && p->password)
- ctl->password = xstrdup(p->password);
- }
- }
-
- if (ctl->server.protocol != P_ETRN && ctl->server.protocol != P_IMAP_K4
+ if (ctl->active && !(implicitmode && ctl->server.skip)
+ && ctl->server.protocol != P_ETRN
+ && ctl->server.protocol != P_IMAP_K4
#ifdef GSSAPI
- && ctl->server.protocol != P_IMAP_GSS
+ && ctl->server.protocol != P_IMAP_GSS
#endif /* GSSAPI */
- && !ctl->password)
- {
- char* password_prompt = _("Enter password for %s@%s: ");
-
- xalloca(tmpbuf, char *, strlen(password_prompt) +
- strlen(ctl->remotename) +
- strlen(ctl->server.pollname) + 1);
- (void) sprintf(tmpbuf, password_prompt,
- ctl->remotename, ctl->server.pollname);
- ctl->password = xstrdup((char *)getpassword(tmpbuf));
- }
+ && !ctl->password)
+ {
+ char* password_prompt = _("Enter password for %s@%s: ");
+
+ xalloca(tmpbuf, char *, strlen(password_prompt) +
+ strlen(ctl->remotename) +
+ strlen(ctl->server.pollname) + 1);
+ (void) sprintf(tmpbuf, password_prompt,
+ ctl->remotename, ctl->server.pollname);
+ ctl->password = xstrdup((char *)getpassword(tmpbuf));
}
}
if (run.use_syslog)
{
openlog(program_name, LOG_PID, LOG_MAIL);
- error_init(-1);
+ report_init(-1);
}
else
#endif
- error_init((run.poll_interval == 0 || nodetach) && !run.logfile);
+ report_init((run.poll_interval == 0 || nodetach) && !run.logfile);
if (run.poll_interval)
{
if (!nodetach)
daemonize(run.logfile, termhook);
- progress( 0, 0, _("starting fetchmail %s daemon "), VERSION);
+ report(stdout, _("starting fetchmail %s daemon \n"), VERSION);
/*
* We'll set up a handler for these when we're sleeping,
signal(SIGHUP, SIG_IGN);
}
+#ifdef linux
+ interface_init();
+#endif /* linux */
+
/* beyond here we don't want more than one fetchmail running per user */
umask(0077);
signal(SIGABRT, termhook);
signal(SIGQUIT, termhook);
/* here's the exclusion lock */
- if ((lockfp = fopen(lockfile,"w")) != NULL) {
- fprintf(lockfp,"%d",getpid());
+ if ((st = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666)) != -1) {
+ sprintf(tmpbuf,"%d", getpid());
+ write(st, tmpbuf, strlen(tmpbuf));
if (run.poll_interval)
- fprintf(lockfp," %d", run.poll_interval);
- fclose(lockfp);
+ {
+ sprintf(tmpbuf," %d", run.poll_interval);
+ write(st, tmpbuf, strlen(tmpbuf));
+ }
+ close(st);
#ifdef HAVE_ATEXIT
atexit(unlockit);
{
if (ctl->wedged)
{
- error(0, -1,
- _("poll of %s skipped (failed authentication or too many timeouts)"),
+ report(stderr,
+ _("poll of %s skipped (failed authentication or too many timeouts)\n"),
ctl->server.pollname);
continue;
}
if (ctl->server.poll_count++ % ctl->server.interval)
{
if (outlevel >= O_VERBOSE)
- progress(0, -1,
- _("interval not reached, not querying %s"),
+ report(stdout,
+ _("interval not reached, not querying %s\n"),
ctl->server.pollname);
continue;
}
}
-#if defined(linux) && !INET6
+#if (defined(linux) && !INET6) || defined(__FreeBSD__)
/* interface_approve() does its own error logging */
if (!interface_approve(&ctl->server))
continue;
-#endif /* defined(linux) && !INET6 */
+#endif /* (defined(linux) && !INET6) || defined(__FreeBSD__) */
querystatus = query_host(ctl);
{
write_saved_lists(querylist, run.idfile);
if (outlevel >= O_DEBUG)
- progress(0, 0, _("saved UID List"));
+ report(stdout, _("saved UID List\n"));
}
#endif /* POP3_ENABLE */
}
else if (!check_only &&
((querystatus!=PS_NOMAIL) || (outlevel==O_DEBUG)))
- progress(0, 0, _("Query status=%d"), querystatus);
+ report(stdout, _("Query status=%d\n"), querystatus);
-#if defined(linux) && !INET6
+#if (defined(linux) && !INET6) || defined (__FreeBSD__)
if (ctl->server.monitor)
{
/*
sleep(3);
interface_note_activity(&ctl->server);
}
-#endif /* defined(linux) && !INET6 */
+#endif /* (defined(linux) && !INET6) || defined(__FreeBSD__) */
}
}
unwedged++;
if (!unwedged)
{
- error(0, -1, _("All connections are wedged. Exiting."));
+ report(stderr, _("All connections are wedged. Exiting.\n"));
exit(PS_AUTHFAIL);
}
if (outlevel >= O_VERBOSE)
- progress(0, -1, _("fetchmail: sleeping at %s"), rfc822timestamp());
+ report(stdout,
+ _("fetchmail: sleeping at %s\n"), rfc822timestamp());
/*
* With this simple hack, we make it possible for a foreground
timeout.tv_sec = run.poll_interval;
timeout.tv_usec = 0;
- lastsig = 0;
- select(0,0,0,0, &timeout);
+ do {
+ lastsig = 0;
+ select(0,0,0,0, &timeout);
+ } while (lastsig == SIGCHLD);
#endif
#else /* EMX */
alarm_latch = FALSE;
|| ((run.poll_interval && !getuid()) && lastsig == SIGHUP))
{
#ifdef SYS_SIGLIST_DECLARED
- progress(0, 0, _("awakened by %s"), sys_siglist[lastsig]);
+ report(stdout,
+ _("awakened by %s\n"), sys_siglist[lastsig]);
#else
- progress(0, 0, _("awakened by signal %d"), lastsig);
+ report(stdout,
+ _("awakened by signal %d\n"), lastsig);
#endif
/* received a wakeup - unwedge all servers in case */
/* the problem has been manually repaired */
signal(SIGHUP, SIG_IGN);
if (outlevel >= O_VERBOSE)
- progress(0, -1, _("awakened at %s"), rfc822timestamp());
+ report(stdout, _("awakened at %s\n"), rfc822timestamp());
}
} while
(run.poll_interval);
if (outlevel >= O_VERBOSE)
- progress(0, -1, _("normal termination, status %d"),
+ report(stdout, _("normal termination, status %d\n"),
successes ? PS_SUCCESS : querystatus);
termhook(0);
FLAG_MERGE(server.checkalias);
FLAG_MERGE(server.uidl);
-#ifdef linux
+#if defined(linux) || defined(__FreeBSD__)
FLAG_MERGE(server.interface);
FLAG_MERGE(server.monitor);
FLAG_MERGE(server.interface_pair);
-#endif /* linux */
+#endif /* linux || defined(__FreeBSD__) */
FLAG_MERGE(server.plugin);
FLAG_MERGE(server.plugout);
struct passwd *pw;
struct query def_opts, *ctl;
+ run.bouncemail = TRUE;
+
memset(&def_opts, '\0', sizeof(struct query));
def_opts.smtp_socket = -1;
def_opts.smtpaddress = (char *)0;
- save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 571;
- save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 550;
- save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 501;
+#define ANTISPAM(n) save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = (n)
+ ANTISPAM(571); /* sendmail */
+ ANTISPAM(550); /* old exim */
+ ANTISPAM(501); /* new exim */
+ ANTISPAM(554); /* Postfix */
+#undef ANTISPAM
def_opts.server.protocol = P_AUTO;
def_opts.server.timeout = CLIENT_TIMEOUT;
def_opts.warnings = WARNING_INTERVAL;
def_opts.remotename = user;
- def_opts.expunge = 1;
def_opts.listener = SMTP_MODE;
/* this builds the host list */
DEFAULT(ctl->forcecr, FALSE);
DEFAULT(ctl->pass8bits, FALSE);
DEFAULT(ctl->dropstatus, FALSE);
- DEFAULT(ctl->mimedecode, FALSE);
+ DEFAULT(ctl->mimedecode, TRUE);
DEFAULT(ctl->server.dns, TRUE);
DEFAULT(ctl->server.uidl, FALSE);
DEFAULT(ctl->server.checkalias, FALSE);
free(ctl->server.via);
ctl->server.via = xstrdup(hes_p->po_host);
} else {
- error(0, errno, _("couldn't find HESIOD pobox for %s"),
- ctl->remotename);
+ report(stderr,
+ _("couldn't find HESIOD pobox for %s\n"),
+ ctl->remotename);
}
}
#endif /* HESIOD */
namerec = gethostbyname(ctl->server.queryname);
if (namerec == (struct hostent *)NULL)
{
- error(0, errno,
- _("couldn't find canonical DNS name of %s"),
+ report(stderr,
+ _("couldn't find canonical DNS name of %s\n"),
ctl->server.pollname);
exit(PS_DNS);
}
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;
/* check and daemon options are not compatible */
if (check_only && run.poll_interval)
*/
if (sig != 0)
- progress(0, 0, _("terminated with signal %d"), sig);
+ report(stdout, _("terminated with signal %d\n"), sig);
else
/* terminate all SMTP connections cleanly */
for (ctl = querylist; ctl; ctl = ctl->next)
{
int i, st;
- if (outlevel >= O_VERBOSE)
+ /*
+ * If we're syslogging the progress messages are automatically timestamped.
+ * Force timestamping if we're going to a logfile.
+ */
+ if (outlevel >= O_VERBOSE || (run.logfile && outlevel > O_SILENT))
{
- time_t now;
-
- time(&now);
- progress(0, -1, _("%s querying %s (protocol %s) at %s"),
- VERSION,
- ctl->server.pollname, showproto(ctl->server.protocol), ctime(&now));
+ report(stdout, _("%s querying %s (protocol %s) at %s\n"),
+ VERSION,
+ ctl->server.pollname,
+ showproto(ctl->server.protocol),
+ rfc822timestamp());
}
switch (ctl->server.protocol) {
case P_AUTO:
}
ctl->server.protocol = P_AUTO;
return(st);
- break;
case P_POP2:
#ifdef POP2_ENABLE
return(doPOP2(ctl));
#else
- error(0, -1, _("POP2 support is not configured.\n"));
+ report(stderr, _("POP2 support is not configured.\n"));
return(PS_PROTOCOL);
#endif /* POP2_ENABLE */
break;
#ifdef POP3_ENABLE
return(doPOP3(ctl));
#else
- error(0, -1, _("POP3 support is not configured.\n"));
+ report(stderr, _("POP3 support is not configured.\n"));
return(PS_PROTOCOL);
#endif /* POP3_ENABLE */
break;
#ifdef IMAP_ENABLE
return(doIMAP(ctl));
#else
- error(0, -1, _("IMAP support is not configured.\n"));
+ report(stderr, _("IMAP support is not configured.\n"));
return(PS_PROTOCOL);
#endif /* IMAP_ENABLE */
- break;
case P_ETRN:
#ifndef ETRN_ENABLE
- error(0, -1, _("ETRN support is not configured.\n"));
+ report(stderr, _("ETRN support is not configured.\n"));
return(PS_PROTOCOL);
#else
#ifdef HAVE_GETHOSTBYNAME
return(doETRN(ctl));
#else
- error(0, -1, _("Cannot support ETRN without gethostbyname(2).\n"));
+ report(stderr, _("Cannot support ETRN without gethostbyname(2).\n"));
return(PS_PROTOCOL);
#endif /* HAVE_GETHOSTBYNAME */
#endif /* ETRN_ENABLE */
default:
- error(0, 0, _("unsupported protocol selected."));
+ report(stderr, _("unsupported protocol selected.\n"));
return(PS_PROTOCOL);
}
}
printf(_("Fetchmail will forward misaddressed multidrop messages to %s.\n"),
runp->postmaster);
+ if (!runp->bouncemail)
+ printf(_("Fetchmail will direct error mail to the postmaster.\n"));
+ else if (outlevel >= O_VERBOSE)
+ printf(_("Fetchmail will direct error mail to the sender.\n"));
+
for (ctl = querylist; ctl; ctl = ctl->next)
{
if (!ctl->active || (implicit && ctl->server.skip))
* Don't poll for password when there is one or when using the ETRN
* or IMAP-GSS protocol
*/
- if (!ctl->password && (ctl->server.protocol != P_ETRN)
+ /* ETRN, IMAP_GSS, and IMAP_K4 do not need a password, so skip this */
+ if ( (ctl->server.protocol != P_ETRN)
#ifdef GSSAPI
- && (ctl->server.protocol != P_IMAP_GSS)
+ && (ctl->server.protocol != P_IMAP_GSS)
#endif /* GSSAPI */
- )
- printf(_(" Password will be prompted for.\n"));
- else if (outlevel >= O_VERBOSE)
- if (ctl->server.protocol == P_APOP)
- printf(_(" APOP secret = \"%s\".\n"), visbuf(ctl->password));
- else if (ctl->server.protocol == P_RPOP)
- printf(_(" RPOP id = \"%s\".\n"), visbuf(ctl->password));
- else
- printf(_(" Password = \"%s\".\n"), visbuf(ctl->password));
+ && (ctl->server.protocol != P_IMAP_K4) ) {
+ if (!ctl->password)
+ printf(_(" Password will be prompted for.\n"));
+ else if (outlevel >= O_VERBOSE)
+ if (ctl->server.protocol == P_APOP)
+ printf(_(" APOP secret = \"%s\".\n"),
+ visbuf(ctl->password));
+ else if (ctl->server.protocol == P_RPOP)
+ printf(_(" RPOP id = \"%s\".\n"),
+ visbuf(ctl->password));
+ else
+ printf(_(" Password = \"%s\".\n"),
+ visbuf(ctl->password));
+ }
+
if (ctl->server.protocol == P_POP3
#if INET6
&& !strcmp(ctl->server.service, KPOP_PORT)
printf(_(" No SMTP message batch limit (--batchlimit 0).\n"));
if (ctl->server.protocol == P_IMAP)
if (NUM_NONZERO(ctl->expunge))
- printf(_(" Deletion interval between expunges is %d (--expunge %d).\n"), ctl->expunge, ctl->expunge);
+ printf(_(" Deletion interval between expunges forced to %d (--expunge %d).\n"), ctl->expunge, ctl->expunge);
else if (outlevel >= O_VERBOSE)
- printf(_(" No expunges (--expunge 0).\n"));
+ printf(_(" No forced expunges (--expunge 0).\n"));
}
if (ctl->bsmtp)
printf(_(" Messages will be appended to %s as BSMTP\n"), visbuf(ctl->bsmtp));
}
}
}
-#ifdef linux
+#if defined(linux) || defined(__FreeBSD__)
if (ctl->server.interface)
printf(_(" Connection must be through interface %s.\n"), ctl->server.interface);
else if (outlevel >= O_VERBOSE)