[BACK]Return to rmail.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / rmail

Annotation of src/libexec/rmail/rmail.c, Revision 1.15

1.15    ! cgd         1: /*     $NetBSD: rmail.c,v 1.14 2000/10/10 19:54:39 is Exp $    */
1.7       cgd         2:
1.1       cgd         3: /*
1.4       jtc         4:  * Copyright (c) 1988, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
1.9       mrg        36: #include <sys/cdefs.h>
1.1       cgd        37: #ifndef lint
1.9       mrg        38: __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
                     39:        The Regents of the University of California.  All rights reserved.\n");
1.7       cgd        40: #if 0
1.8       jtc        41: static char sccsid[] = "@(#)rmail.c    8.3 (Berkeley) 5/15/95";
1.7       cgd        42: #else
1.15    ! cgd        43: __RCSID("$NetBSD: rmail.c,v 1.14 2000/10/10 19:54:39 is Exp $");
1.7       cgd        44: #endif
1.1       cgd        45: #endif /* not lint */
                     46:
                     47: /*
                     48:  * RMAIL -- UUCP mail server.
                     49:  *
1.4       jtc        50:  * This program reads the >From ... remote from ... lines that UUCP is so
                     51:  * fond of and turns them into something reasonable.  It then execs sendmail
                     52:  * with various options built from these lines.
                     53:  *
                     54:  * The expected syntax is:
                     55:  *
                     56:  *      <user> := [-a-z0-9]+
                     57:  *      <date> := ctime format
                     58:  *      <site> := [-a-z0-9!]+
                     59:  * <blank line> := "^\n$"
                     60:  *      <from> := "From" <space> <user> <space> <date>
                     61:  *               [<space> "remote from" <space> <site>]
                     62:  *    <forward> := ">" <from>
                     63:  *         msg := <from> <forward>* <blank-line> <body>
                     64:  *
                     65:  * The output of rmail(8) compresses the <forward> lines into a single
                     66:  * from path.
1.1       cgd        67:  */
1.4       jtc        68: #include <sys/param.h>
                     69: #include <sys/stat.h>
                     70: #include <sys/wait.h>
1.1       cgd        71:
1.4       jtc        72: #include <ctype.h>
1.15    ! cgd        73: #include <err.h>
1.13      kleink     74: #include <errno.h>
1.4       jtc        75: #include <fcntl.h>
                     76: #include <paths.h>
                     77: #include <stdio.h>
                     78: #include <stdlib.h>
                     79: #include <string.h>
1.1       cgd        80: #include <sysexits.h>
1.4       jtc        81: #include <unistd.h>
1.1       cgd        82:
1.8       jtc        83: #ifndef MAX
                     84: # define MAX(a, b)     ((a) < (b) ? (b) : (a))
                     85: #endif
                     86:
1.4       jtc        87: void usage __P((void));
1.9       mrg        88: int main __P((int, char *[]));
1.1       cgd        89:
1.4       jtc        90: int
1.1       cgd        91: main(argc, argv)
                     92:        int argc;
1.4       jtc        93:        char *argv[];
1.1       cgd        94: {
1.4       jtc        95:        FILE *fp;
                     96:        struct stat sb;
                     97:        size_t fplen, fptlen, len;
                     98:        off_t offset;
                     99:        int ch, debug, i, pdes[2], pid, status;
                    100:        char *addrp, *domain, *p, *t;
                    101:        char *from_path, *from_sys, *from_user;
                    102:        char *args[100], buf[2048], lbuf[2048];
                    103:
1.9       mrg       104:        addrp = NULL;   /* XXX gcc */
                    105:        fplen = fptlen = 0;     /* XXX gcc */
1.4       jtc       106:        debug = 0;
                    107:        domain = "UUCP";                /* Default "domain". */
1.10      enami     108:        while ((ch = getopt(argc, argv, "D:T")) != -1)
1.4       jtc       109:                switch (ch) {
                    110:                case 'T':
                    111:                        debug = 1;
                    112:                        break;
                    113:                case 'D':
                    114:                        domain = optarg;
                    115:                        break;
                    116:                case '?':
                    117:                default:
                    118:                        usage();
                    119:                }
                    120:        argc -= optind;
                    121:        argv += optind;
                    122:
                    123:        if (argc < 1)
                    124:                usage();
                    125:
                    126:        from_path = from_sys = from_user = NULL;
                    127:        for (offset = 0;;) {
1.1       cgd       128:
1.4       jtc       129:                /* Get and nul-terminate the line. */
                    130:                if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
                    131:                        exit (EX_DATAERR);
                    132:                if ((p = strchr(lbuf, '\n')) == NULL)
                    133:                        err(EX_DATAERR, "line too long");
                    134:                *p = '\0';
                    135:
                    136:                /* Parse lines until reach a non-"From" line. */
                    137:                if (!strncmp(lbuf, "From ", 5))
                    138:                        addrp = lbuf + 5;
                    139:                else if (!strncmp(lbuf, ">From ", 6))
                    140:                        addrp = lbuf + 6;
                    141:                else if (offset == 0)
                    142:                        err(EX_DATAERR,
                    143:                            "missing or empty From line: %s", lbuf);
                    144:                else {
                    145:                        *p = '\n';
1.1       cgd       146:                        break;
1.4       jtc       147:                }
                    148:
                    149:                if (*addrp == '\0')
                    150:                        err(EX_DATAERR, "corrupted From line: %s", lbuf);
                    151:
                    152:                /* Use the "remote from" if it exists. */
                    153:                for (p = addrp; (p = strchr(p + 1, 'r')) != NULL;)
                    154:                        if (!strncmp(p, "remote from ", 12)) {
                    155:                                for (t = p += 12; *t && !isspace(*t); ++t);
                    156:                                *t = '\0';
                    157:                                if (debug)
                    158:                                        (void)fprintf(stderr,
                    159:                                            "remote from: %s\n", p);
                    160:                                break;
                    161:                        }
                    162:
                    163:                /* Else use the string up to the last bang. */
1.12      ross      164:                if (p == NULL) {
1.4       jtc       165:                        if (*addrp == '!')
                    166:                                err(EX_DATAERR,
                    167:                                    "bang starts address: %s", addrp);
                    168:                        else if ((t = strrchr(addrp, '!')) != NULL) {
                    169:                                *t = '\0';
                    170:                                p = addrp;
                    171:                                addrp = t + 1;
                    172:                                if (*addrp == '\0')
                    173:                                        err(EX_DATAERR,
                    174:                                            "corrupted From line: %s", lbuf);
                    175:                                if (debug)
                    176:                                        (void)fprintf(stderr, "bang: %s\n", p);
                    177:                        }
1.12      ross      178:                }
1.4       jtc       179:
                    180:                /* 'p' now points to any system string from this line. */
                    181:                if (p != NULL) {
                    182:                        /* Nul terminate it as necessary. */
                    183:                        for (t = p; *t && !isspace(*t); ++t);
                    184:                        *t = '\0';
                    185:
                    186:                        /* If the first system, copy to the from_sys string. */
                    187:                        if (from_sys == NULL) {
                    188:                                if ((from_sys = strdup(p)) == NULL)
                    189:                                        err(EX_TEMPFAIL, NULL);
                    190:                                if (debug)
                    191:                                        (void)fprintf(stderr,
                    192:                                            "from_sys: %s\n", from_sys);
1.1       cgd       193:                        }
1.4       jtc       194:
                    195:                        /* Concatenate to the path string. */
                    196:                        len = t - p;
                    197:                        if (from_path == NULL) {
                    198:                                fplen = 0;
                    199:                                if ((from_path = malloc(fptlen = 256)) == NULL)
                    200:                                        err(EX_TEMPFAIL, NULL);
                    201:                        }
                    202:                        if (fplen + len + 2 > fptlen) {
                    203:                                fptlen += MAX(fplen + len + 2, 256);
                    204:                                if ((from_path =
                    205:                                    realloc(from_path, fptlen)) == NULL)
                    206:                                        err(EX_TEMPFAIL, NULL);
                    207:                        }
                    208:                        memmove(from_path + fplen, p, len);
                    209:                        fplen += len;
                    210:                        from_path[fplen++] = '!';
                    211:                        from_path[fplen] = '\0';
1.1       cgd       212:                }
1.4       jtc       213:
                    214:                /* Save off from user's address; the last one wins. */
                    215:                for (p = addrp; *p && !isspace(*p); ++p);
                    216:                *p = '\0';
1.8       jtc       217:                if (*addrp == '\0')
                    218:                        addrp = "<>";
1.4       jtc       219:                if (from_user != NULL)
                    220:                        free(from_user);
                    221:                if ((from_user = strdup(addrp)) == NULL)
                    222:                        err(EX_TEMPFAIL, NULL);
                    223:
                    224:                if (debug) {
                    225:                        if (from_path != NULL)
                    226:                                (void)fprintf(stderr,
                    227:                                    "from_path: %s\n", from_path);
                    228:                        (void)fprintf(stderr, "from_user: %s\n", from_user);
1.1       cgd       229:                }
1.4       jtc       230:
                    231:                if (offset != -1)
                    232:                        offset = (off_t)ftell(stdin);
1.1       cgd       233:        }
1.4       jtc       234:
                    235:        i = 0;
                    236:        args[i++] = _PATH_SENDMAIL;     /* Build sendmail's argument list. */
                    237:        args[i++] = "-oee";             /* No errors, just status. */
                    238:        args[i++] = "-odq";             /* Queue it, don't try to deliver. */
                    239:        args[i++] = "-oi";              /* Ignore '.' on a line by itself. */
                    240:
1.8       jtc       241:        /* set from system and protocol used */
                    242:        if (from_sys == NULL)
                    243:                (void)snprintf(buf, sizeof(buf), "-p%s", domain);
                    244:        else if (strchr(from_sys, '.') == NULL)
                    245:                (void)snprintf(buf, sizeof(buf), "-p%s:%s.%s",
                    246:                        domain, from_sys, domain);
                    247:        else
                    248:                (void)snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
1.4       jtc       249:        if ((args[i++] = strdup(buf)) == NULL)
                    250:                err(EX_TEMPFAIL, NULL);
                    251:
                    252:                                        /* Set name of ``from'' person. */
                    253:        (void)snprintf(buf, sizeof(buf), "-f%s%s",
                    254:            from_path ? from_path : "", from_user);
                    255:        if ((args[i++] = strdup(buf)) == NULL)
                    256:                err(EX_TEMPFAIL, NULL);
1.1       cgd       257:
                    258:        /*
1.4       jtc       259:         * Don't copy arguments beginning with - as they will be
                    260:         * passed to sendmail and could be interpreted as flags.
1.8       jtc       261:         * To prevent confusion of sendmail wrap < and > around
                    262:         * the address (helps to pass addrs like @gw1,@gw2:aa@bb)
1.1       cgd       263:         */
1.8       jtc       264:        while (*argv) {
                    265:                if (**argv == '-')
1.4       jtc       266:                        err(EX_USAGE, "dash precedes argument: %s", *argv);
1.8       jtc       267:                if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
                    268:                        args[i++] = *argv;
                    269:                else {
                    270:                        if ((args[i] = malloc(strlen(*argv) + 3)) == NULL)
                    271:                                err(EX_TEMPFAIL, "Cannot malloc");
                    272:                        sprintf (args [i++], "<%s>", *argv);
                    273:                }
                    274:                argv++;
                    275:        }
                    276:        args[i] = 0;
1.4       jtc       277:
                    278:        if (debug) {
                    279:                (void)fprintf(stderr, "Sendmail arguments:\n");
                    280:                for (i = 0; args[i]; i++)
                    281:                        (void)fprintf(stderr, "\t%s\n", args[i]);
1.1       cgd       282:        }
                    283:
1.4       jtc       284:        /*
                    285:         * If called with a regular file as standard input, seek to the right
                    286:         * position in the file and just exec sendmail.  Could probably skip
                    287:         * skip the stat, but it's not unreasonable to believe that a failed
                    288:         * seek will cause future reads to fail.
                    289:         */
                    290:        if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) {
                    291:                if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
                    292:                        err(EX_TEMPFAIL, "stdin seek");
                    293:                execv(_PATH_SENDMAIL, args);
                    294:                err(EX_OSERR, "%s", _PATH_SENDMAIL);
1.1       cgd       295:        }
1.4       jtc       296:
                    297:        if (pipe(pdes) < 0)
                    298:                err(EX_OSERR, NULL);
                    299:
                    300:        switch (pid = vfork()) {
                    301:        case -1:                                /* Err. */
                    302:                err(EX_OSERR, NULL);
                    303:        case 0:                                 /* Child. */
                    304:                if (pdes[0] != STDIN_FILENO) {
                    305:                        (void)dup2(pdes[0], STDIN_FILENO);
                    306:                        (void)close(pdes[0]);
                    307:                }
                    308:                (void)close(pdes[1]);
                    309:                execv(_PATH_SENDMAIL, args);
                    310:                _exit(127);
                    311:                /* NOTREACHED */
1.1       cgd       312:        }
1.4       jtc       313:
                    314:        if ((fp = fdopen(pdes[1], "w")) == NULL)
                    315:                err(EX_OSERR, NULL);
                    316:        (void)close(pdes[0]);
                    317:
                    318:        /* Copy the file down the pipe. */
                    319:        do {
                    320:                (void)fprintf(fp, "%s", lbuf);
                    321:        } while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
                    322:
                    323:        if (ferror(stdin))
                    324:                err(EX_TEMPFAIL, "stdin: %s", strerror(errno));
                    325:
                    326:        if (fclose(fp))
                    327:                err(EX_OSERR, NULL);
                    328:
                    329:        if ((waitpid(pid, &status, 0)) == -1)
                    330:                err(EX_OSERR, "%s", _PATH_SENDMAIL);
                    331:
                    332:        if (!WIFEXITED(status))
                    333:                err(EX_OSERR,
                    334:                    "%s: did not terminate normally", _PATH_SENDMAIL);
                    335:
                    336:        if (WEXITSTATUS(status))
                    337:                err(status, "%s: terminated with %d (non-zero) status",
                    338:                    _PATH_SENDMAIL, WEXITSTATUS(status));
                    339:        exit(EX_OK);
                    340: }
                    341:
                    342: void
                    343: usage()
                    344: {
                    345:        (void)fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
                    346:        exit(EX_USAGE);
1.1       cgd       347: }

CVSweb <webmaster@jp.NetBSD.org>