X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/8bb0f8000b86df9270f2410de3fb6f41fa63e88b..6db45651:/uip/slocal.c?ds=inline diff --git a/uip/slocal.c b/uip/slocal.c index bb9b5ac4..b249dc4b 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -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,9 +27,10 @@ #include #include #include +#include "../sbr/lock_file.h" +#include "../sbr/m_mktemp.h" #include -#include #include #include @@ -55,39 +54,30 @@ #include #endif /* HAVE_GETUTXENT */ -static struct swit switches[] = { -#define ADDRSW 0 - { "addr address", 0 }, -#define USERSW 1 - { "user name", 0 }, -#define FILESW 2 - { "file file", 0 }, -#define SENDERSW 3 - { "sender address", 0 }, -#define MAILBOXSW 4 - { "mailbox file", 0 }, -#define HOMESW 5 - { "home directory", -4 }, -#define INFOSW 6 - { "info data", 0 }, -#define MAILSW 7 - { "maildelivery file", 0 }, -#define VERBSW 8 - { "verbose", 0 }, -#define NVERBSW 9 - { "noverbose", 0 }, -#define SUPPRESSDUP 10 - { "suppressdup", 0 }, -#define NSUPPRESSDUP 11 - { "nosuppressdup", 0 }, -#define DEBUGSW 12 - { "debug", 0 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - { NULL, 0 } -}; +#define SLOCAL_SWITCHES \ + X("addr address", 0, ADDRSW) \ + X("user name", 0, USERSW) \ + X("file file", 0, FILESW) \ + X("sender address", 0, SENDERSW) \ + X("mailbox file", 0, MAILBOXSW) \ + X("home directory", -4, HOMESW) \ + X("info data", 0, INFOSW) \ + X("maildelivery file", 0, MAILSW) \ + X("verbose", 0, VERBSW) \ + X("noverbose", 0, NVERBSW) \ + X("suppressdup", 0, SUPPRESSDUP) \ + X("nosuppressdup", 0, NSUPPRESSDUP) \ + X("debug", 0, DEBUGSW) \ + X("version", 0, VERSIONSW) \ + X("help", 0, HELPSW) \ + +#define X(sw, minchars, id) id, +DEFINE_SWITCH_ENUM(SLOCAL); +#undef X + +#define X(sw, minchars, id) { sw, minchars, id }, +DEFINE_SWITCH_ARRAY(SLOCAL, switches); +#undef X static int globbed = 0; /* have we built "vars" table yet? */ static int parsed = 0; /* have we built header field table yet */ @@ -193,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; @@ -290,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 = ""; @@ -327,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) @@ -351,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"); @@ -431,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; @@ -460,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); @@ -494,7 +484,8 @@ usr_delivery (int fd, char *delivery, int su) * do this - else fall through */ if (!next) - continue; /* else fall */ + continue; + /* FALLTHRU */ case '?': /* @@ -502,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': @@ -525,7 +517,7 @@ usr_delivery (int fd, char *delivery, int su) } if (vecp > 5) { - if (!mh_strcasecmp (vec[5], "select")) { + if (!strcasecmp (vec[5], "select")) { if (logged_in () != -1) continue; if (vecp > 7 && timely (vec[6], vec[7]) == -1) @@ -544,11 +536,12 @@ usr_delivery (int fd, char *delivery, int su) * "default" matches only if the message hasn't * been delivered yet. */ - if (!mh_strcasecmp (field, "default")) { + if (!strcasecmp (field, "default")) { if (won) continue; break; - } /* else fall */ + } + /* FALLTHRU */ default: /* parse message and build lookup table */ @@ -574,8 +567,9 @@ usr_delivery (int fd, char *delivery, int su) switch (*action) { case 'q': /* deliver to quoted pipe */ - if (mh_strcasecmp (action, "qpipe")) - continue; /* else fall */ + if (strcasecmp (action, "qpipe")) + continue; + /* FALLTHRU */ case '^': expand (tmpbuf, string, fd); if (split (tmpbuf, vec) < 1) @@ -585,8 +579,9 @@ usr_delivery (int fd, char *delivery, int su) case 'p': /* deliver to pipe */ - if (mh_strcasecmp (action, "pipe")) - continue; /* else fall */ + if (strcasecmp (action, "pipe")) + continue; + /* FALLTHRU */ case '|': vec[2] = "sh"; vec[3] = "-c"; @@ -598,26 +593,28 @@ usr_delivery (int fd, char *delivery, int su) case 'f': /* mbox format */ - if (!mh_strcasecmp (action, "file")) { + if (!strcasecmp (action, "file")) { status = usr_file (fd, string, MBOX_FORMAT); break; } /* deliver to nmh folder */ - else if (mh_strcasecmp (action, "folder")) - continue; /* else fall */ + else if (strcasecmp (action, "folder")) + continue; + /* FALLTHRU */ case '+': status = usr_folder (fd, string); break; case 'm': /* mmdf format */ - if (!mh_strcasecmp (action, "mmdf")) { + if (!strcasecmp (action, "mmdf")) { status = usr_file (fd, string, MMDF_FORMAT); break; } /* mbox format */ - else if (mh_strcasecmp (action, "mbox")) - continue; /* else fall */ + else if (strcasecmp (action, "mbox")) + continue; + /* FALLTHRU */ case '>': /* mbox format */ @@ -626,7 +623,7 @@ usr_delivery (int fd, char *delivery, int su) case 'd': /* ignore message */ - if (mh_strcasecmp (action, "destroy")) + if (strcasecmp (action, "destroy")) continue; status = 0; break; @@ -654,7 +651,7 @@ static int split (char *cp, char **vec) { int i; - unsigned char *s; + char *s; s = cp; @@ -663,7 +660,7 @@ split (char *cp, char **vec) vec[i] = NULL; /* zap any whitespace and comma's */ - while (isspace (*s) || *s == ',') + while (isspace ((unsigned char) *s) || *s == ',') *s++ = 0; /* end of buffer, time to leave */ @@ -693,7 +690,7 @@ split (char *cp, char **vec) vec[i++] = s++; /* move forward to next field delimiter */ - while (*s && !isspace (*s) && *s != ',') + while (*s && !isspace ((unsigned char) *s) && *s != ',') s++; } vec[i] = NULL; @@ -713,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; @@ -740,19 +737,20 @@ 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++) { - if (!mh_strcasecmp (p->p_name, name)) { + if (!strcasecmp (p->p_name, name)) { if (!(p->p_flags & P_HID)) { if ((cp = p->p_value)) { if (p->p_flags & P_ADR) { @@ -771,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++; @@ -785,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; } @@ -882,7 +880,7 @@ 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); @@ -904,7 +902,7 @@ static struct pair * lookup (struct pair *pairs, char *key) { for (; pairs->p_name; pairs++) - if (!mh_strcasecmp (pairs->p_name, key)) + if (!strcasecmp (pairs->p_name, key)) return pairs; return NULL; @@ -974,19 +972,11 @@ timely (char *t1, char *t2) static int usr_file (int fd, char *mailbox, int mbx_style) { - int md, mapping; + int md; - if (verbose) - verbose_printf ("delivering to file \"%s\"", mailbox); - - 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 */ @@ -996,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; @@ -1052,8 +1042,9 @@ 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; struct stat st; @@ -1061,7 +1052,7 @@ usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress) if (verbose && !suppress) verbose_printf ("delivering to pipe \"%s\"", cmd); - lseek (fd, (off_t) 0, SEEK_SET); + lseek(fd, 0, SEEK_SET); for (i = 0; (child_id = fork()) == -1 && i < 5; i++) sleep (5); @@ -1077,8 +1068,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); @@ -1093,9 +1088,9 @@ usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress) setpgid ((pid_t) 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); @@ -1123,23 +1118,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; } } @@ -1162,15 +1155,15 @@ static void get_sender (char *envelope, char **sender) { int i; - unsigned char *cp; - unsigned char buffer[BUFSIZ]; + char *cp; + 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; @@ -1183,11 +1176,11 @@ get_sender (char *envelope, char **sender) *cp = 0; for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (isspace (*cp)) + if (isspace ((unsigned char) *cp)) *cp = 0; else break; - *sender = getcpy (buffer); + *sender = mh_xstrdup(buffer); } @@ -1207,7 +1200,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) { @@ -1215,12 +1207,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; } @@ -1257,13 +1249,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); @@ -1286,7 +1277,7 @@ you_lose: return -1; } fclose (qfp); - lseek (fd1, (off_t) 0, SEEK_SET); + lseek(fd1, 0, SEEK_SET); return fd1; @@ -1305,7 +1296,7 @@ static char * trim (char *cp) { char buffer[BUFSIZ*4]; - unsigned char *bp, *sp; + char *bp, *sp; if (cp == NULL) return NULL; @@ -1315,12 +1306,12 @@ trim (char *cp) bp = buffer; /* skip over leading whitespace */ - while (isspace(*bp)) + while (isspace((unsigned char) *bp)) bp++; /* start at the end and zap trailing whitespace */ for (sp = bp + strlen(bp) - 1; sp >= bp; sp--) { - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = 0; else break; @@ -1328,11 +1319,11 @@ trim (char *cp) /* replace remaining whitespace with spaces */ for (sp = bp; *sp; sp++) - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = ' '; /* now return a copy */ - return getcpy(bp); + return mh_xstrdup(bp); } /* @@ -1345,7 +1336,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 */ @@ -1365,22 +1356,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); } @@ -1410,11 +1401,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; @@ -1424,25 +1415,27 @@ 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: /* Search for the message ID */ - if (mh_strcasecmp (name, "Message-ID")) { + 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); @@ -1462,7 +1455,8 @@ suppress_duplicates (int fd, char *file) * This will fail if your Maildelivery file doesn't * exist. */ - if ((lockfd = lkopen(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); @@ -1483,11 +1477,10 @@ suppress_duplicates (int fd, char *file) } dbm_close (db); - lkclose(lockfd, file); + lkclosedata(lockfd, file); free (cp); fclose (in); return result; - break; case BODY: case FILEEOF: