]> diplodocus.org Git - nmh/blobdiff - uip/slocal.c
lock_file.c: close(2) file descriptor on failure, avoiding leak.
[nmh] / uip / slocal.c
index 11a44cc952c6e17705e409d72444292c4d565923..fe027ee2f8b3f00c3a44e722a154a42222a0d3a0 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * slocal.c -- asynchronously filter and deliver new mail
+/* slocal.c -- asynchronously filter and deliver new mail
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
@@ -29,6 +27,8 @@
 #include <h/tws.h>
 #include <h/mts.h>
 #include <h/utils.h>
+#include "sbr/lock_file.h"
+#include "sbr/m_mktemp.h"
 
 #include <pwd.h>
 #include <sys/ioctl.h>
@@ -163,7 +163,7 @@ static int split (char *, char **);
 static int parse (int);
 static void expand (char *, char *, int);
 static void glob (int);
-static struct pair *lookup (struct pair *, char *);
+static struct pair *lookup (struct pair *, char *) PURE;
 static int logged_in (void);
 static int timely (char *, char *);
 static int usr_file (int, char *, int);
@@ -172,9 +172,9 @@ static int usr_folder (int, char *);
 static void alrmser (int);
 static void get_sender (char *, char **);
 static int copy_message (int, char *, int);
-static void verbose_printf (char *fmt, ...);
-static void adorn (char *, char *, ...);
-static void debug_printf (char *fmt, ...);
+static void verbose_printf (char *fmt, ...) CHECK_PRINTF(1, 2);
+static void adorn (char *, char *, ...) CHECK_PRINTF(2, 3);
+static void debug_printf (char *fmt, ...) CHECK_PRINTF(1, 2);
 static int suppress_duplicates (int, char *);
 static char *trim (char *);
 
@@ -183,21 +183,14 @@ int
 main (int argc, char **argv)
 {
     int fd, status;
-    FILE *fp = stdin;
+    FILE *fp;
     char *cp, *mdlvr = NULL, buf[BUFSIZ];
     char mailbox[BUFSIZ], tmpfil[BUFSIZ];
     char **argp, **arguments;
 
-#ifdef LOCALE
-    setlocale(LC_ALL, "");
-#endif
-    invo_name = r1bindex (*argv, '/');
-
-    /* foil search of user profile/context */
-    if (context_foil (NULL) == -1)
-       done (1);
+    if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
 
-    mts_init (invo_name);
+    mts_init ();
     arguments = getarguments (invo_name, argc, argv, 0);
     argp = arguments;
 
@@ -280,21 +273,28 @@ main (int argc, char **argv)
 
     if (addr == NULL)
        addr = getusername ();
-    if (user == NULL)
-       user = (cp = strchr(addr, '.')) ? ++cp : addr;
+    if (user == NULL) {
+       user = getusername ();
+    }
     if ((pw = getpwnam (user)) == NULL)
        adios (NULL, "no such local user as %s", user);
 
     if (chdir (pw->pw_dir) == -1)
-       chdir ("/");
+       if (chdir ("/") < 0) {
+           advise ("/", "chdir");
+       }
     umask (0077);
 
     if (geteuid() == 0) {
-       setgid (pw->pw_gid);
+       if (setgid (pw->pw_gid) != 0) {
+           adios ("setgid", "unable to set group to %ld", (long) pw->pw_gid);
+       }
        initgroups (pw->pw_name, pw->pw_gid);
-       setuid (pw->pw_uid);
+       if (setuid (pw->pw_uid) != 0) {
+           adios ("setuid", "unable to set user to %ld", (long) pw->pw_uid);
+       }
     }
-    
+
     if (info == NULL)
        info = "";
 
@@ -317,14 +317,16 @@ main (int argc, char **argv)
        if (debug)
            debug_printf ("retrieving message from file \"%s\"\n", file);
        if ((fd = copy_message (tempfd, tmpfil, 1)) == -1)
-           adios (NULL, "unable to create temporary file");
+           adios(NULL, "unable to create temporary file in %s",
+                  get_temp_dir());
        close (tempfd);
     } else {
        /* getting message from stdin */
        if (debug)
            debug_printf ("retrieving message from stdin\n");
        if ((fd = copy_message (fileno (stdin), tmpfil, 1)) == -1)
-           adios (NULL, "unable to create temporary file");
+           adios(NULL, "unable to create temporary file in %s",
+                  get_temp_dir());
     }
 
     if (debug)
@@ -341,7 +343,7 @@ main (int argc, char **argv)
        thing would be to delay this unlink() until later if debug == 1, but I'll
        leave that for someone who cares about the temp-file-accessing
        functionality (they'll have to watch out for cases where we adios()). */
-    unlink (tmpfil);
+    (void) m_unlink (tmpfil);
 
     if (!(fp = fdopen (fd, "r+")))
        adios (NULL, "unable to access temporary file");
@@ -421,7 +423,7 @@ usr_delivery (int fd, char *delivery, int su)
     int i, accept, status=1, won, vecp, next;
     char *field, *pattern, *action, *result, *string;
     char buffer[BUFSIZ], tmpbuf[BUFSIZ];
-    char *cp, *vec[NVEC];
+    char *vec[NVEC];
     struct stat st;
     struct pair *p;
     FILE *fp;
@@ -450,9 +452,7 @@ usr_delivery (int fd, char *delivery, int su)
        if (*buffer == '#' || *buffer == '\n')
            continue;
 
-       /* zap trailing newline */
-       if ((cp = strchr(buffer, '\n')))
-           *cp = 0;
+        trim_suffix_c(buffer, '\n');
 
        /* split buffer into fields */
        vecp = split (buffer, vec);
@@ -484,7 +484,8 @@ usr_delivery (int fd, char *delivery, int su)
                 * do this - else fall through
                 */
                if (!next)
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
 
            case '?': 
                /*
@@ -492,7 +493,8 @@ usr_delivery (int fd, char *delivery, int su)
                 * consider delivered if action is successful.
                 */
                if (won)
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
 
            case 'A': 
            case 'a': 
@@ -538,7 +540,8 @@ usr_delivery (int fd, char *delivery, int su)
                    if (won)
                        continue;
                    break;
-               }               /* else fall */
+               }
+               /* FALLTHRU */
 
            default: 
                /* parse message and build lookup table */
@@ -565,7 +568,8 @@ usr_delivery (int fd, char *delivery, int su)
            case 'q':
                /* deliver to quoted pipe */
                if (strcasecmp (action, "qpipe"))
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
            case '^':
                expand (tmpbuf, string, fd);
                if (split (tmpbuf, vec) < 1)
@@ -576,7 +580,8 @@ usr_delivery (int fd, char *delivery, int su)
            case 'p': 
                /* deliver to pipe */
                if (strcasecmp (action, "pipe"))
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
            case '|': 
                vec[2] = "sh";
                vec[3] = "-c";
@@ -594,7 +599,8 @@ usr_delivery (int fd, char *delivery, int su)
                }
                /* deliver to nmh folder */
                else if (strcasecmp (action, "folder"))
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
            case '+':
                status = usr_folder (fd, string);
                break;
@@ -607,7 +613,8 @@ usr_delivery (int fd, char *delivery, int su)
                }
                /* mbox format */
                else if (strcasecmp (action, "mbox"))
-                   continue;   /* else fall */
+                   continue;
+               /* FALLTHRU */
 
            case '>': 
                /* mbox format */
@@ -703,10 +710,10 @@ parse (int fd)
     int i, state;
     int fd1;
     char *cp, *dp, *lp;
-    char name[NAMESZ], field[BUFSIZ];
+    char name[NAMESZ], field[NMH_BUFSIZ];
     struct pair *p, *q;
     FILE  *in;
-    m_getfld_state_t gstate = 0;
+    m_getfld_state_t gstate;
 
     if (parsed++)
        return 0;
@@ -730,15 +737,16 @@ parse (int fd)
      * Scan the headers of the message and build
      * a lookup table.
      */
+    gstate = m_getfld_state_init(in);
     for (i = 0;;) {
        int fieldsz = sizeof field;
-       switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) {
+       switch (state = m_getfld2(&gstate, name, field, &fieldsz)) {
            case FLD: 
            case FLDPLUS: 
-               lp = add (field, NULL);
+               lp = mh_xstrdup(field);
                while (state == FLDPLUS) {
                    fieldsz = sizeof field;
-                   state = m_getfld (&gstate, name, field, &fieldsz, in);
+                   state = m_getfld2(&gstate, name, field, &fieldsz);
                    lp = add (field, lp);
                }
                for (p = hdrs; p->p_name; p++) {
@@ -761,7 +769,7 @@ parse (int fd)
                    }
                }
                if (p->p_name == NULL && i < NVEC) {
-                   p->p_name = getcpy (name);
+                   p->p_name = mh_xstrdup(name);
                    p->p_value = lp;
                    p->p_flags = P_NIL;
                    p++, i++;
@@ -775,11 +783,11 @@ parse (int fd)
 
            case LENERR: 
            case FMTERR: 
-               advise (NULL, "format error in message");
+               inform("format error in message");
                break;
 
            default: 
-               advise (NULL, "internal error in m_getfld");
+               inform("internal error in m_getfld2");
                fclose (in);
                return -1;
        }
@@ -794,12 +802,12 @@ parse (int fd)
        p->p_value = getcpy (q ? q->p_value : "");
        p->p_flags &= ~P_CHK;
        if (debug)
-           debug_printf ("vars[%d]: name=\"%s\" value=\"%s\"\n",
+           debug_printf ("vars[%ld]: name=\"%s\" value=\"%s\"\n",
                    p - vars, p->p_name, trim(p->p_value));
     }
     if (debug) {
        for (p = hdrs; p->p_name; p++)
-           debug_printf ("hdrs[%d]: name=\"%s\" value=\"%s\"\n",
+           debug_printf ("hdrs[%ld]: name=\"%s\" value=\"%s\"\n",
                p - hdrs, p->p_name, p->p_value ? trim(p->p_value) : "");
     }
 
@@ -872,14 +880,14 @@ glob (int fd)
     if ((p = lookup (vars, "size"))) {
        snprintf (buffer, sizeof(buffer), "%d",
                fstat (fd, &st) != -1 ? (int) st.st_size : 0);
-       p->p_value = getcpy (buffer);
+       p->p_value = mh_xstrdup(buffer);
     }
     if ((p = lookup (vars, "info")))
        p->p_value = getcpy (info);
 
     if (debug) {
        for (p = vars; p->p_name; p++)
-           debug_printf ("vars[%d]: name=\"%s\" value=\"%s\"\n",
+           debug_printf ("vars[%ld]: name=\"%s\" value=\"%s\"\n",
                    p - vars, p->p_name, trim(p->p_value));
     }
 }
@@ -964,19 +972,11 @@ timely (char *t1, char *t2)
 static int
 usr_file (int fd, char *mailbox, int mbx_style)
 {
-    int        md, mapping;
-
-    if (verbose)
-       verbose_printf ("delivering to file \"%s\"", mailbox);
+    int        md;
 
-    if (mbx_style == MBOX_FORMAT) {
-       if (verbose)
-           verbose_printf (" (mbox style)");
-       mapping = 0;
-    } else {
-       if (verbose)
-           verbose_printf (" (mmdf style)");
-       mapping = 1;
+    if (verbose) {
+        verbose_printf("delivering to file \"%s\" (%s style)", mailbox,
+            mbx_style == MBOX_FORMAT ? "mbox" : "mmdf");
     }
 
     /* open and lock the file */
@@ -986,10 +986,10 @@ usr_file (int fd, char *mailbox, int mbx_style)
        return -1;
     }
 
-    lseek (fd, (off_t) 0, SEEK_SET);
+    lseek(fd, 0, SEEK_SET);
 
     /* append message to file */
-    if (mbx_copy (mailbox, mbx_style, md, fd, mapping, NULL, verbose) == -1) {
+    if (mbx_copy (mailbox, mbx_style, md, fd, NULL) == -1) {
        if (verbose)
            adorn ("", "error writing to:");
        return -1;
@@ -1042,20 +1042,19 @@ usr_folder (int fd, char *string)
  */
 
 static int
-usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress)
+usr_pipe (int fd_arg, char *cmd, char *pgm, char **vec, int suppress)
 {
+    volatile int fd = fd_arg;
     pid_t child_id;
-    int i, bytes, seconds, status;
+    int bytes, seconds, status;
     struct stat st;
 
     if (verbose && !suppress)
        verbose_printf ("delivering to pipe \"%s\"", cmd);
 
-    lseek (fd, (off_t) 0, SEEK_SET);
-
-    for (i = 0; (child_id = fork()) == -1 && i < 5; i++)
-       sleep (5);
+    lseek(fd, 0, SEEK_SET);
 
+    child_id = fork();
     switch (child_id) {
        case -1: 
            /* fork error */
@@ -1067,8 +1066,12 @@ usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress)
            /* child process */
            if (fd != 0)
                dup2 (fd, 0);
-           freopen ("/dev/null", "w", stdout);
-           freopen ("/dev/null", "w", stderr);
+           if (freopen ("/dev/null", "w", stdout) == NULL) {
+               advise ("stdout", "freopen");
+           }
+           if (freopen ("/dev/null", "w", stderr) == NULL) {
+               advise ("stderr", "freopen");
+           }
            if (fd != 3)
                dup2 (fd, 3);
            closefds (4);
@@ -1080,12 +1083,12 @@ usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress)
            }
 #endif /* TIOCNOTTY */
 
-           setpgid ((pid_t) 0, getpid ());     /* put in own process group */
+            setpgid(0, getpid());      /* put in own process group */
 
            *environ = NULL;
-           m_putenv ("USER", pw->pw_name);
-           m_putenv ("HOME", pw->pw_dir);
-           m_putenv ("SHELL", pw->pw_shell);
+           setenv("USER", pw->pw_name, 1);
+           setenv("HOME", pw->pw_dir, 1);
+           setenv("SHELL", pw->pw_shell, 1);
 
            execvp (pgm, vec);
            _exit (-1);
@@ -1113,23 +1116,21 @@ usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress)
                if (verbose) {
                    if (status == 0)
                        verbose_printf (", success.\n");
-                   else
-                       if ((status & 0xff00) == 0xff00)
-                           verbose_printf (", system error\n");
-                       else
-                           pidstatus (status, stdout, ", failed");
+                   else if ((status & 0xff00) == 0xff00)
+                        verbose_printf (", system error\n");
+                    else
+                        pidstatus (status, stdout, ", failed");
                }
                return (status == 0 ? 0 : -1);
-           } else {
-               /*
-                * Ruthlessly kill the child and anything
-                * else in its process group.
-                */
-               killpg(child_id, SIGKILL);
-               if (verbose)
-                   verbose_printf (", timed-out; terminated\n");
-               return -1;
            }
+            /*
+             * Ruthlessly kill the child and anything
+             * else in its process group.
+             */
+            killpg(child_id, SIGKILL);
+            if (verbose)
+                verbose_printf (", timed-out; terminated\n");
+            return -1;
     }
 }
 
@@ -1156,11 +1157,11 @@ get_sender (char *envelope, char **sender)
     char buffer[BUFSIZ];
 
     if (envelope == NULL) {
-       *sender = getcpy ("");
+       *sender = mh_xstrdup("");
        return;
     }
 
-    i = strlen ("From ");
+    i = LEN("From ");
     strncpy (buffer, envelope + i, sizeof(buffer));
     if ((cp = strchr(buffer, '\n'))) {
        *cp = 0;
@@ -1177,7 +1178,7 @@ get_sender (char *envelope, char **sender)
            *cp = 0;
        else
            break;
-    *sender = getcpy (buffer);
+    *sender = mh_xstrdup(buffer);
 }
 
 
@@ -1197,7 +1198,6 @@ copy_message (int qd, char *tmpfil, int fold)
 
     tfile = m_mktemp2(NULL, invo_name, &fd1, NULL);
     if (tfile == NULL) return -1;
-    fchmod(fd1, 0600);
     strncpy (tmpfil, tfile, BUFSIZ);
 
     if (!fold) {
@@ -1205,12 +1205,12 @@ copy_message (int qd, char *tmpfil, int fold)
            if (write (fd1, buffer, i) != i) {
 you_lose:
                close (fd1);
-               unlink (tmpfil);
+               (void) m_unlink (tmpfil);
                return -1;
            }
        if (i == -1)
            goto you_lose;
-       lseek (fd1, (off_t) 0, SEEK_SET);
+       lseek(fd1, 0, SEEK_SET);
        return fd1;
     }
 
@@ -1247,13 +1247,12 @@ you_lose:
      * and massage the headers.  Save
      * a copy of the "From " line for later.
      */
-    i = strlen ("From ");
     while (fgets (buffer, sizeof(buffer), qfp)) {
        if (first) {
            first = 0;
-           if (!strncmp (buffer, "From ", i)) {
+           if (has_prefix(buffer, "From ")) {
                /* get copy of envelope information ("From " line) */
-               envelope = getcpy (buffer);
+               envelope = mh_xstrdup(buffer);
 
                /* Put the delivery date in message */
                fputs (ddate, ffp);
@@ -1276,7 +1275,7 @@ you_lose:
        return -1;
     }
     fclose (qfp);
-    lseek (fd1, (off_t) 0, SEEK_SET);
+    lseek(fd1, 0, SEEK_SET);
     return fd1;
 
 
@@ -1294,7 +1293,7 @@ fputs_error:
 static char *
 trim (char *cp)
 {
-    char buffer[BUFSIZ*4];
+    static char buffer[BUFSIZ * 4];
     char *bp, *sp;
 
     if (cp == NULL)
@@ -1321,8 +1320,7 @@ trim (char *cp)
        if (isspace((unsigned char) *sp))
            *sp = ' ';
 
-    /* now return a copy */
-    return getcpy(bp);
+    return bp;
 }
 
 /*
@@ -1335,7 +1333,7 @@ verbose_printf (char *fmt, ...)
     va_list ap;
 
     va_start(ap, fmt);
-    vfprintf (stdout, fmt, ap);
+    vprintf(fmt, ap);
     va_end(ap);
 
     fflush (stdout);   /* now flush output */
@@ -1355,22 +1353,22 @@ adorn (char *what, char *fmt, ...)
     char *s;
 
     eindex = errno;    /* save the errno */
-    fprintf (stdout, ", ");
+    printf(", ");
 
     va_start(ap, fmt);
-    vfprintf (stdout, fmt, ap);
+    vprintf(fmt, ap);
     va_end(ap);
 
     if (what) {
        if (*what)
-           fprintf (stdout, " %s: ", what);
+           printf(" %s: ", what);
        if ((s = strerror (eindex)))
-           fprintf (stdout, "%s", s);
+           fputs(s, stdout);
        else
-           fprintf (stdout, "Error %d", eindex);
+           printf("Error %d", eindex);
     }
 
-    fputc ('\n', stdout);
+    putchar('\n');
     fflush (stdout);
 }
 
@@ -1400,11 +1398,11 @@ static int
 suppress_duplicates (int fd, char *file)
 {
     int        fd1, lockfd, state, result;
-    char *cp, buf[BUFSIZ], name[NAMESZ];
+    char *cp, buf[NMH_BUFSIZ], name[NAMESZ];
     datum key, value;
     DBM *db;
     FILE *in;
-    m_getfld_state_t gstate = 0;
+    m_getfld_state_t gstate;
 
     if ((fd1 = dup (fd)) == -1)
        return -1;
@@ -1414,9 +1412,11 @@ suppress_duplicates (int fd, char *file)
     }
     rewind (in);
 
+    gstate = m_getfld_state_init(in);
     for (;;) {
+        int failed_to_lock = 0;
        int bufsz = sizeof buf;
-       state = m_getfld (&gstate, name, buf, &bufsz, in);
+       state = m_getfld2(&gstate, name, buf, &bufsz);
        switch (state) {
            case FLD:
            case FLDPLUS:
@@ -1424,15 +1424,15 @@ suppress_duplicates (int fd, char *file)
                if (strcasecmp (name, "Message-ID")) {
                    while (state == FLDPLUS) {
                        bufsz = sizeof buf;
-                       state = m_getfld (&gstate, name, buf, &bufsz, in);
+                       state = m_getfld2(&gstate, name, buf, &bufsz);
                    }
                    continue;
                }
 
-               cp = add (buf, NULL);
+               cp = mh_xstrdup(buf);
                while (state == FLDPLUS) {
                    bufsz = sizeof buf;
-                   state = m_getfld (&gstate, name, buf, &bufsz, in);
+                   state = m_getfld2(&gstate, name, buf, &bufsz);
                    cp = add (buf, cp);
                }
                key.dptr = trimcpy (cp);
@@ -1452,7 +1452,8 @@ suppress_duplicates (int fd, char *file)
                 * This will fail if your Maildelivery file doesn't
                 * exist.
                 */
-               if ((lockfd = lkopendata(file, O_RDWR, 0)) == -1) {
+               if ((lockfd = lkopendata(file, O_RDWR, 0, &failed_to_lock))
+                   == -1) {
                    advise (file, "unable to perform file locking on");
                    free (cp);
                    fclose (in);
@@ -1477,7 +1478,6 @@ suppress_duplicates (int fd, char *file)
                free (cp);
                fclose (in);
                return result;
-               break;
 
           case BODY:
           case FILEEOF: