]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmail.c
Initial revision
[~andy/fetchmail] / fetchmail.c
index 28ad2aa2457c095ce0df91431fdbff8de964323c..b75105136fe5ad5f311b0ca513f402ce7c46f2d4 100644 (file)
@@ -230,6 +230,9 @@ int main(int argc, char **argv)
 #ifndef ETRN_ENABLE
        printf("-ETRN");
 #endif /* ETRN_ENABLE */
+#ifndef ODMR_ENABLE
+       printf("-ODMR");
+#endif /* ODMR_ENABLE */
 #ifdef SSL_ENABLE
        printf("+SSL");
 #endif
@@ -320,13 +323,7 @@ int main(int argc, char **argv)
     {
        if (ctl->active && !(implicitmode && ctl->server.skip)&&!ctl->password)
        {
-           if (ctl->server.preauthenticate == A_KERBEROS_V4 ||
-                       ctl->server.preauthenticate == A_KERBEROS_V5 ||
-                       ctl->server.preauthenticate == A_SSH ||
-#ifdef GSSAPI
-                       ctl->server.protocol == P_IMAP_GSS ||
-#endif /* GSSAPI */
-                       ctl->server.protocol == P_IMAP_K4)
+           if (ctl->server.preauthenticate > A_PASSWORD)
                /* Server won't care what the password is, but there
                   must be some non-null string here.  */
                ctl->password = ctl->remotename;
@@ -496,11 +493,7 @@ int main(int argc, char **argv)
     for (ctl = querylist; ctl; ctl = ctl->next)
     {
        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
-#endif /* GSSAPI */
+               && ctl->server.preauthenticate <= A_PASSWORD
                && !ctl->password)
        {
            if (!isatty(0))
@@ -538,7 +531,9 @@ int main(int argc, char **argv)
      */
     if (run.poll_interval)
     {
-       if (!nodetach)
+       if (nodetach)
+           deal_with_sigchld();
+       else
            daemonize(run.logfile, terminate_run);
        report(stdout, _("starting fetchmail %s daemon \n"), VERSION);
 
@@ -574,17 +569,25 @@ int main(int argc, char **argv)
 #ifndef O_SYNC
 #define O_SYNC 0       /* use it if we have it */
 #endif
-    if ((st = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, 0666)) != -1)
+    if (!lock_acquired)
     {
-       sprintf(tmpbuf,"%d", getpid());
-       write(st, tmpbuf, strlen(tmpbuf));
-       if (run.poll_interval)
-       {
-           sprintf(tmpbuf," %d", run.poll_interval);
-           write(st, tmpbuf, strlen(tmpbuf));
-       }
-       close(st);      /* should be safe, fd was opened with O_SYNC */
-       lock_acquired = TRUE;
+      if ((st = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, 0666)) != -1)
+      {
+         sprintf(tmpbuf,"%d", getpid());
+         write(st, tmpbuf, strlen(tmpbuf));
+         if (run.poll_interval)
+         {
+             sprintf(tmpbuf," %d", run.poll_interval);
+             write(st, tmpbuf, strlen(tmpbuf));
+         }
+         close(st);    /* should be safe, fd was opened with O_SYNC */
+         lock_acquired = TRUE;
+      }
+      else
+      {
+         fprintf(stderr,       _("fetchmail: lock creation failed.\n"));
+         return(PS_EXCLUDE);
+      }
     }
 
     /*
@@ -611,7 +614,30 @@ int main(int argc, char **argv)
        else if (rcstat.st_mtime > parsetime)
        {
            report(stdout, _("restarting fetchmail (%s changed)\n"), rcfile);
-           execvp("fetchmail", argv);
+           /*
+            * Matthias Andree: Isn't this prone to introduction of
+            * "false" programs by interfering with PATH? Those
+            * path-searching execs might not be the best ideas for
+            * this reason.
+            *
+            * Rob Funk: But is there any way for someone to modify
+            * the PATH variable of a running fetchmail?  I don't know
+            * of a way.
+            *
+            * Dave's change makes fetchmail restart itself in exactly
+            * the way it was started from the shell (or shell script)
+            * in the first place.  If you're concerned about PATH
+            * contamination, call fetchmail initially with a full
+            * path, and use Dave's patch.
+            *
+            * Not using a -p variant of exec means that the restart
+            * will break if both (a) the user depended on PATH to
+            * call fetchmail in the first place, and (b) the system
+            * doesn't save the whole path in argv[0] if the whole
+            * path wasn't used in the initial call.  (If I recall
+            * correctly, Linux saves it but many other Unices don't.)
+            */
+           execvp(argv[0], argv);
            report(stderr, _("attempt to re-exec fetchmail failed\n"));
        }
 
@@ -622,7 +648,7 @@ int main(int argc, char **argv)
         * 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 kernel problem involving bootstrapping of
+        * 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.
         */
@@ -672,7 +698,7 @@ int main(int argc, char **argv)
 #ifdef POP3_ENABLE
                    /* leave the UIDL state alone if there have been any errors */
                    if (!check_only &&
-                               ((querystatus==PS_SUCCESS) || (querystatus==PS_NOMAIL)))
+                               ((querystatus==PS_SUCCESS) || (querystatus==PS_NOMAIL) || (querystatus==PS_MAXFETCH)))
                        uid_swap_lists(ctl);
 #endif  /* POP3_ENABLE */
 
@@ -796,7 +822,16 @@ int main(int argc, char **argv)
                successes ? PS_SUCCESS : querystatus);
 
     terminate_run(0);
-    exit(successes ? PS_SUCCESS : querystatus);
+
+    if (successes)
+       exit(PS_SUCCESS);
+    else if (querystatus)
+       exit(querystatus);
+    else
+       /* in case we interrupted before a successful fetch */
+       exit(PS_NOMAIL);
+
+    exit(successes ?  : querystatus);
 }
 
 static void list_merge(struct idlist **dstl, struct idlist **srcl, int force)
@@ -842,6 +877,7 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(server.dns);
     FLAG_MERGE(server.checkalias);
     FLAG_MERGE(server.uidl);
+    FLAG_MERGE(server.principal);
 
 #if defined(linux) || defined(__FreeBSD__)
     FLAG_MERGE(server.interface);
@@ -897,10 +933,12 @@ static int load_params(int argc, char **argv, int optind)
     struct stat rcstat;
 
     run.bouncemail = TRUE;
+    run.spambounce = FALSE;    /* don't bounce back to innocent bystanders */
 
     memset(&def_opts, '\0', sizeof(struct query));
     def_opts.smtp_socket = -1;
     def_opts.smtpaddress = (char *)0;
+    def_opts.smtpname = (char *)0;
 #define ANTISPAM(n)    save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = (n)
     ANTISPAM(571);     /* sendmail */
     ANTISPAM(550);     /* old exim */
@@ -1000,6 +1038,8 @@ static int load_params(int argc, char **argv, int optind)
        run.poll_interval = cmd_run.poll_interval;
     if (cmd_run.invisible)
        run.invisible = cmd_run.invisible;
+    if (cmd_run.showdots)
+       run.showdots = cmd_run.showdots;
     if (cmd_run.use_syslog)
        run.use_syslog = (cmd_run.use_syslog == FLAG_TRUE);
     if (cmd_run.postmaster)
@@ -1016,7 +1056,7 @@ static int load_params(int argc, char **argv, int optind)
     {
        ctl->wedged = FALSE;
 
-       if (configdump || (ctl->active && !(implicitmode && ctl->server.skip)))
+       if (configdump || ctl->active )
        {
            /* merge in defaults */
            optmerge(ctl, &def_opts, FALSE);
@@ -1055,17 +1095,16 @@ static int load_params(int argc, char **argv, int optind)
             * do this unconditionally, but it made fetchmail excessively
             * vulnerable to misconfigured DNS setups.
             *
-            * If we're using ETRN, the smtp hunt list is the list of
-            * systems we're polling on behalf of; these have to be 
-            * fully-qualified domain names.  The default for this list
-            * should be the FQDN of localhost.
+            * If we're using ETRN or ODMR, the smtp hunt list is the
+            * list of systems we're polling on behalf of; these have
+            * to be fully-qualified domain names.  The default for
+            * this list should be the FQDN of localhost.
             *
             * If we're using Kerberos for authentication, we need 
-            * the FQDN in order to generate capability keys.
-            */
-           if (ctl->server.protocol == P_ETRN
-                        || ctl->server.preauthenticate == A_KERBEROS_V4
-                        || ctl->server.preauthenticate == A_KERBEROS_V5)
+            * the FQDN in order to generate capability keys.  */
+           if (ctl->server.protocol==P_ETRN || ctl->server.protocol==P_ODMR
+               || ctl->server.preauthenticate == A_KERBEROS_V4
+               || ctl->server.preauthenticate == A_KERBEROS_V5)
                if (strcmp(fetchmailhost, "localhost") == 0)
                        fetchmailhost = host_fqdn();
 
@@ -1153,61 +1192,64 @@ static int load_params(int argc, char **argv, int optind)
                ctl->server.truename = xstrdup(leadname);
            }
 #ifdef HAVE_GETHOSTBYNAME
-           else if (!configdump && (ctl->server.preauthenticate==A_KERBEROS_V4 ||
-               ctl->server.preauthenticate==A_KERBEROS_V5 ||
-                     (ctl->server.dns && MULTIDROP(ctl))))
+           else if (!configdump)
            {
-               struct hostent  *namerec;
-
-               /* compute the canonical name of the host */
-               errno = 0;
-               namerec = gethostbyname(ctl->server.queryname);
-               if (namerec == (struct hostent *)NULL)
+               if (ctl->server.preauthenticate==A_KERBEROS_V4 ||
+                     ctl->server.preauthenticate==A_KERBEROS_V5 ||
+                   (ctl->server.dns && MULTIDROP(ctl)))
                {
-                   report(stderr,
-                         _("couldn't find canonical DNS name of %s\n"),
-                         ctl->server.pollname);
-                   ctl->server.truename = xstrdup(ctl->server.queryname);
-                   ctl->server.trueaddr = NULL;
+                   struct hostent      *namerec;
+
+                   /* compute the canonical name of the host */
+                   errno = 0;
+                   namerec = gethostbyname(ctl->server.queryname);
+                   if (namerec == (struct hostent *)NULL)
+                   {
+                       report(stderr,
+                              _("couldn't find canonical DNS name of %s\n"),
+                              ctl->server.pollname);
+                       ctl->server.truename = xstrdup(ctl->server.queryname);
+                       ctl->server.trueaddr = NULL;
+                   }
+                   else
+                       ctl->server.truename=xstrdup((char *)namerec->h_name);
                }
-               else
-                   ctl->server.truename=xstrdup((char *)namerec->h_name);
-           }
 #endif /* HAVE_GETHOSTBYNAME */
-           else {
+               else {
 #ifdef HAVE_GETHOSTBYNAME
-             struct hostent    *namerec;
-
-             /* <fetchmail@mail.julianhaight.com>
-                Get the host's IP, so we can report it like this:
-
-                Received: from hostname [10.0.0.1]
-
-                do we actually need to gethostbyname to find the IP?
-                it seems like it would be faster to do this later, when
-                we are actually resolving the hostname for a connection,
-                but I ain't that smart, so I don't know where to make
-                the change later..
-             */
-             errno = 0;
-             namerec = gethostbyname(ctl->server.queryname);
-             if (namerec == (struct hostent *)NULL)
-               {
-                 report(stderr,
-                        _("couldn't find canonical DNS name of %s\n"),
-                        ctl->server.pollname);
-                 exit(PS_DNS);
-               }
-             else {
-               ctl->server.truename=xstrdup((char *)namerec->h_name);
-               ctl->server.trueaddr=xmalloc(namerec->h_length);
-               memcpy(ctl->server.trueaddr, 
-                      namerec->h_addr_list[0],
-                      namerec->h_length);
-             }
+                   struct hostent      *namerec;
+                   
+                   /* <fetchmail@mail.julianhaight.com>
+                      Get the host's IP, so we can report it like this:
+
+                      Received: from hostname [10.0.0.1]
+
+                      do we actually need to gethostbyname to find the IP?
+                      it seems like it would be faster to do this later, when
+                      we are actually resolving the hostname for a connection,
+                      but I ain't that smart, so I don't know where to make
+                      the change later..
+                   */
+                   errno = 0;
+                   namerec = gethostbyname(ctl->server.queryname);
+                   if (namerec == (struct hostent *)NULL)
+                   {
+                       report(stderr,
+                              _("couldn't find canonical DNS name of %s\n"),
+                              ctl->server.pollname);
+                       exit(PS_DNS);
+                   }
+                   else {
+                       ctl->server.truename=xstrdup((char *)namerec->h_name);
+                       ctl->server.trueaddr=xmalloc(namerec->h_length);
+                       memcpy(ctl->server.trueaddr, 
+                              namerec->h_addr_list[0],
+                              namerec->h_length);
+                   }
 #else
-             ctl->server.truename = xstrdup(ctl->server.queryname);
+                   ctl->server.truename = xstrdup(ctl->server.queryname);
 #endif /* HAVE_GETHOSTBYNAME */
+               }
            }
 
            /* if no folders were specified, set up the null one as default */
@@ -1431,9 +1473,6 @@ static int query_host(struct query *ctl)
 #endif /* POP3_ENABLE */
        break;
     case P_IMAP:
-    case P_IMAP_K4:
-    case P_IMAP_CRAM_MD5:
-    case P_IMAP_LOGIN:
 #ifdef GSSAPI
     case P_IMAP_GSS:
 #endif /* GSSAPI */
@@ -1455,6 +1494,18 @@ static int query_host(struct query *ctl)
        return(PS_PROTOCOL);
 #endif /* HAVE_GETHOSTBYNAME */
 #endif /* ETRN_ENABLE */
+    case P_ODMR:
+#ifndef ODMR_ENABLE
+       report(stderr, _("ODMR support is not configured.\n"));
+       return(PS_PROTOCOL);
+#else
+#ifdef HAVE_GETHOSTBYNAME
+       return(doODMR(ctl));
+#else
+       report(stderr, _("Cannot support ODMR without gethostbyname(2).\n"));
+       return(PS_PROTOCOL);
+#endif /* HAVE_GETHOSTBYNAME */
+#endif /* ODMR_ENABLE */
     default:
        report(stderr, _("unsupported protocol selected.\n"));
        return(PS_PROTOCOL);
@@ -1479,6 +1530,8 @@ static void dump_params (struct runctl *runp,
 #endif
     if (runp->invisible)
        printf(_("Fetchmail will masquerade and will not generate Received\n"));
+    if (runp->showdots)
+       printf(_("Fetchmail will show progress dots even in logfiles.\n"));
     if (runp->postmaster)
        printf(_("Fetchmail will forward misaddressed multidrop messages to %s.\n"),
               runp->postmaster);
@@ -1496,7 +1549,7 @@ static void dump_params (struct runctl *runp,
        printf(_("Options for retrieving from %s@%s:\n"),
               ctl->remotename, visbuf(ctl->server.pollname));
 
-       if (ctl->server.via && (ctl->server.protocol != P_ETRN))
+       if (ctl->server.via && (ctl->server.protocol < P_ETRN))
            printf(_("  Mail will be retrieved via %s\n"), ctl->server.via);
 
        if (ctl->server.interval)
@@ -1507,30 +1560,22 @@ static void dump_params (struct runctl *runp,
        if (ctl->server.skip || outlevel >= O_VERBOSE)
            printf(_("  This host %s be queried when no host is specified.\n"),
                   ctl->server.skip ? _("will not") : _("will"));
-       /*
-        * Don't poll for password when there is one or when using the ETRN
-        * or IMAP-GSS protocol
-        */
-       /* 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)
-#endif /* GSSAPI */
-                                       && (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"),
+       if (ctl->server.preauthenticate <= A_PASSWORD)
+       {
+           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 
@@ -1556,16 +1601,33 @@ static void dump_params (struct runctl *runp,
 #endif /* INET6_ENABLE */
        else if (outlevel >= O_VERBOSE)
            printf(_(" (using default port)"));
-       if (ctl->server.uidl && (ctl->server.protocol != P_ETRN))
+       if (ctl->server.uidl && (ctl->server.protocol < P_ETRN))
            printf(_(" (forcing UIDL use)"));
        putchar('.');
        putchar('\n');
-       if (ctl->server.preauthenticate == A_KERBEROS_V4)
-           printf(_("  Kerberos V4 preauthentication enabled.\n"));
-       else if (ctl->server.preauthenticate == A_KERBEROS_V5)
-           printf(_("  Kerberos V5 preauthentication enabled.\n"));
-       else if (ctl->server.preauthenticate == A_SSH)
+       switch (ctl->server.preauthenticate)
+       {
+       case A_ANY:
+           printf(_("  All authentication methods will be described.\n"));
+           break;
+       case A_PASSWORD:
+           printf(_("  Password authentication will be forced.\n"));
+           break;
+       case A_GSSAPI:
+           printf(_("  GSSAPI preauthentication will be forced.\n"));
+           break;
+       case A_KERBEROS_V4:
+           printf(_("  Kerberos V4 preauthentication will be forced.\n"));
+           break;
+       case A_KERBEROS_V5:
+           printf(_("  Kerberos V5 preauthentication will be forced.\n"));
+           break;
+       case A_SSH:
            printf(_("  End-to-end encryption assumed.\n"));
+           break;
+       }
+       if (ctl->server.principal != (char *) NULL)
+           printf(_("  Mail service principal is: %s\n"), ctl->server.principal);
 #ifdef SSL_ENABLE
        if (ctl->use_ssl)
            printf("  SSL encrypted sessions enabled.\n");
@@ -1577,7 +1639,7 @@ static void dump_params (struct runctl *runp,
        else
            printf(".\n");
 
-       if (ctl->server.protocol != P_ETRN) {
+       if (ctl->server.protocol < P_ETRN) {
                if (!ctl->mailboxes->id)
                    printf(_("  Default mailbox selected.\n"));
                else
@@ -1644,7 +1706,7 @@ static void dump_params (struct runctl *runp,
                    printf(_("  SMTP message batch limit is %d.\n"), ctl->batchlimit);
                else if (outlevel >= O_VERBOSE)
                    printf(_("  No SMTP message batch limit (--batchlimit 0).\n"));
-               if (ctl->server.protocol != P_ETRN)
+               if (ctl->server.protocol < P_ETRN)
                {
                    if (NUM_NONZERO(ctl->expunge))
                        printf(_("  Deletion interval between expunges forced to %d (--expunge %d).\n"), ctl->expunge, ctl->expunge);
@@ -1654,7 +1716,7 @@ static void dump_params (struct runctl *runp,
        }
        if (ctl->bsmtp)
            printf(_("  Messages will be appended to %s as BSMTP\n"), visbuf(ctl->bsmtp));
-       else if (ctl->mda && (ctl->server.protocol != P_ETRN))
+       else if (ctl->mda && (ctl->server.protocol < P_ETRN))
            printf(_("  Messages will be delivered with \"%s\".\n"), visbuf(ctl->mda));
        else
        {
@@ -1671,8 +1733,11 @@ static void dump_params (struct runctl *runp,
            if (ctl->smtpaddress)
                printf(_("  Host part of MAIL FROM line will be %s\n"),
                       ctl->smtpaddress);
+           if (ctl->smtpname)
+               printf(_("  Address to be put in RCPT TO lines shipped to SMTP will be %s\n"),
+                      ctl->smtpname);
        }
-       if (ctl->server.protocol != P_ETRN)
+       if (ctl->server.protocol < P_ETRN)
        {
                if (ctl->antispam != (struct idlist *)NULL)
                {
@@ -1696,7 +1761,7 @@ static void dump_params (struct runctl *runp,
                   visbuf(ctl->postconnect));
        else if (outlevel >= O_VERBOSE)
            printf(_("  No post-connection command.\n"));
-       if (ctl->server.protocol != P_ETRN) {
+       if (ctl->server.protocol < P_ETRN) {
                if (!ctl->localnames)
                    printf(_("  No localnames declared for this host.\n"));
                else
@@ -1793,7 +1858,7 @@ static void dump_params (struct runctl *runp,
        else if (outlevel >= O_VERBOSE)
            printf(_("  No plugout command specified.\n"));
 
-       if (ctl->server.protocol > P_POP2 && (ctl->server.protocol != P_ETRN))
+       if (ctl->server.protocol > P_POP2 && (ctl->server.protocol < P_ETRN))
        {
            if (!ctl->oldsaved)
                printf(_("  No UIDs saved from this host.\n"));