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

Annotation of src/libexec/mail.local/mail.local.c, Revision 1.13

1.13    ! enami       1: /*     $NetBSD: mail.local.c,v 1.12 1997/10/07 13:13:41 mrg Exp $      */
1.10      mrg         2:
1.1       cgd         3: /*-
1.11      mrg         4:  * Copyright (c) 1990, 1993, 1994
                      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.11      mrg        36: #include <sys/cdefs.h>
1.1       cgd        37: #ifndef lint
1.11      mrg        38: __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
                     39:        The Regents of the University of California.  All rights reserved.\n");
                     40: #if 0
                     41: static char sccsid[] = "@(#)mail.local.c       8.22 (Berkeley) 6/21/95";
                     42: #else
1.13    ! enami      43: __RCSID("$NetBSD: mail.local.c,v 1.12 1997/10/07 13:13:41 mrg Exp $");
1.11      mrg        44: #endif
1.1       cgd        45: #endif /* not lint */
                     46:
                     47: #include <sys/param.h>
                     48: #include <sys/stat.h>
                     49: #include <sys/socket.h>
1.11      mrg        50:
1.1       cgd        51: #include <netinet/in.h>
1.11      mrg        52:
                     53: #include <errno.h>
1.1       cgd        54: #include <fcntl.h>
1.11      mrg        55: #include <pwd.h>
1.1       cgd        56: #include <netdb.h>
                     57: #include <stdio.h>
                     58: #include <stdlib.h>
                     59: #include <string.h>
1.11      mrg        60: #include <syslog.h>
                     61: #include <time.h>
                     62: #include <unistd.h>
                     63:
1.1       cgd        64: #include "pathnames.h"
                     65:
                     66: #define        FATAL           1
                     67: #define        NOTFATAL        0
                     68:
1.2       deraadt    69: int    deliver __P((int, char *, int));
1.1       cgd        70: void   err __P((int, const char *, ...));
                     71: void   notifybiff __P((char *));
                     72: int    store __P((char *));
                     73: void   usage __P((void));
1.11      mrg        74: int    main __P((int, char **));
1.1       cgd        75:
1.11      mrg        76: int
1.1       cgd        77: main(argc, argv)
                     78:        int argc;
                     79:        char **argv;
                     80: {
                     81:        struct passwd *pw;
1.11      mrg        82:        int ch, fd, eval, lockfile = 0;
1.1       cgd        83:        uid_t uid;
                     84:        char *from;
                     85:
1.11      mrg        86:        /* use a reasonable umask */
                     87:        (void) umask(0077);
                     88:
1.1       cgd        89:        openlog("mail.local", LOG_PERROR, LOG_MAIL);
                     90:
                     91:        from = NULL;
1.13    ! enami      92:        while ((ch = getopt(argc, argv, "ldf:r:")) != -1)
1.1       cgd        93:                switch(ch) {
                     94:                case 'd':               /* backward compatible */
                     95:                        break;
                     96:                case 'f':
                     97:                case 'r':               /* backward compatible */
                     98:                        if (from)
1.10      mrg        99:                                err(FATAL, "multiple -f options");
1.1       cgd       100:                        from = optarg;
                    101:                        break;
1.2       deraadt   102:                case 'l':
                    103:                        lockfile++;
                    104:                        break;
1.1       cgd       105:                case '?':
                    106:                default:
                    107:                        usage();
                    108:                }
                    109:        argc -= optind;
                    110:        argv += optind;
                    111:
                    112:        if (!*argv)
                    113:                usage();
                    114:
                    115:        /*
                    116:         * If from not specified, use the name from getlogin() if the
                    117:         * uid matches, otherwise, use the name from the password file
                    118:         * corresponding to the uid.
                    119:         */
                    120:        uid = getuid();
                    121:        if (!from && (!(from = getlogin()) ||
                    122:            !(pw = getpwnam(from)) || pw->pw_uid != uid))
                    123:                from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
                    124:
                    125:        fd = store(from);
                    126:        for (eval = 0; *argv; ++argv)
1.2       deraadt   127:                eval |= deliver(fd, *argv, lockfile);
1.10      mrg       128:        exit (eval);
1.1       cgd       129: }
                    130:
1.10      mrg       131: int
1.1       cgd       132: store(from)
                    133:        char *from;
                    134: {
1.11      mrg       135:        FILE *fp = NULL;        /* XXX gcc */
1.1       cgd       136:        time_t tval;
                    137:        int fd, eline;
                    138:        char *tn, line[2048];
                    139:
                    140:        tn = strdup(_PATH_LOCTMP);
                    141:        if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
                    142:                err(FATAL, "unable to open temporary file");
                    143:        (void)unlink(tn);
                    144:        free(tn);
                    145:
                    146:        (void)time(&tval);
                    147:        (void)fprintf(fp, "From %s %s", from, ctime(&tval));
                    148:
                    149:        line[0] = '\0';
                    150:        for (eline = 1; fgets(line, sizeof(line), stdin);) {
                    151:                if (line[0] == '\n')
                    152:                        eline = 1;
                    153:                else {
                    154:                        if (eline && line[0] == 'F' && !bcmp(line, "From ", 5))
                    155:                                (void)putc('>', fp);
                    156:                        eline = 0;
                    157:                }
                    158:                (void)fprintf(fp, "%s", line);
                    159:                if (ferror(fp))
                    160:                        break;
                    161:        }
                    162:
                    163:        /* If message not newline terminated, need an extra. */
                    164:        if (!index(line, '\n'))
                    165:                (void)putc('\n', fp);
                    166:        /* Output a newline; note, empty messages are allowed. */
                    167:        (void)putc('\n', fp);
                    168:
                    169:        (void)fflush(fp);
                    170:        if (ferror(fp))
                    171:                err(FATAL, "temporary file write error");
                    172:        return(fd);
                    173: }
                    174:
1.10      mrg       175: int
1.2       deraadt   176: deliver(fd, name, lockfile)
1.1       cgd       177:        int fd;
                    178:        char *name;
1.2       deraadt   179:        int lockfile;
1.1       cgd       180: {
                    181:        struct stat sb;
                    182:        struct passwd *pw;
1.5       briggs    183:        int created, mbfd, nr, nw, off, rval=0, lfd=-1;
1.2       deraadt   184:        char biffmsg[100], buf[8*1024], path[MAXPATHLEN], lpath[MAXPATHLEN];
1.6       pk        185:        off_t curoff;
1.1       cgd       186:
                    187:        /*
                    188:         * Disallow delivery to unknown names -- special mailboxes can be
                    189:         * handled in the sendmail aliases file.
                    190:         */
                    191:        if (!(pw = getpwnam(name))) {
                    192:                err(NOTFATAL, "unknown name: %s", name);
                    193:                return(1);
                    194:        }
                    195:
1.10      mrg       196:        (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name);
1.1       cgd       197:
1.10      mrg       198:        if (lockfile) {
                    199:                (void)snprintf(lpath, sizeof lpath, "%s/%s.lock",
                    200:                    _PATH_MAILDIR, name);
1.2       deraadt   201:
                    202:                if((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL,
                    203:                    S_IRUSR|S_IWUSR)) < 0) {
                    204:                        err(NOTFATAL, "%s: %s", lpath, strerror(errno));
                    205:                        return(1);
                    206:                }
                    207:        }
                    208:
1.1       cgd       209:        if (!(created = lstat(path, &sb)) &&
                    210:            (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
                    211:                err(NOTFATAL, "%s: linked file", path);
                    212:                return(1);
                    213:        }
1.10      mrg       214:        if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK,
1.2       deraadt   215:            S_IRUSR|S_IWUSR)) < 0) {
                    216:                if ((mbfd = open(path, O_APPEND|O_CREAT|O_WRONLY|O_EXLOCK,
                    217:                    S_IRUSR|S_IWUSR)) < 0) {
1.10      mrg       218:                        err(NOTFATAL, "%s: %s", path, strerror(errno));
                    219:                        return(1);
                    220:                }
1.1       cgd       221:        }
                    222:
1.6       pk        223:        curoff = lseek(mbfd, 0, SEEK_END);
1.12      mrg       224:        (void)snprintf(biffmsg, sizeof biffmsg, "%s@%qd\n", name,
                    225:            (long long)curoff);
1.6       pk        226:        if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
1.1       cgd       227:                err(FATAL, "temporary file: %s", strerror(errno));
                    228:                rval = 1;
                    229:                goto bad;
                    230:        }
                    231:
                    232:        while ((nr = read(fd, buf, sizeof(buf))) > 0)
1.3       mycroft   233:                for (off = 0; off < nr;  off += nw)
                    234:                        if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
1.1       cgd       235:                                err(NOTFATAL, "%s: %s", path, strerror(errno));
                    236:                                goto trunc;
                    237:                        }
                    238:        if (nr < 0) {
                    239:                err(FATAL, "temporary file: %s", strerror(errno));
                    240: trunc:         (void)ftruncate(mbfd, curoff);
                    241:                rval = 1;
                    242:        }
                    243:
                    244:        /*
                    245:         * Set the owner and group.  Historically, binmail repeated this at
                    246:         * each mail delivery.  We no longer do this, assuming that if the
                    247:         * ownership or permissions were changed there was a reason for doing
                    248:         * so.
                    249:         */
1.2       deraadt   250: bad:
1.10      mrg       251:        if (lockfile) {
                    252:                if (lfd >= 0) {
1.2       deraadt   253:                        unlink(lpath);
                    254:                        close(lfd);
                    255:                }
                    256:        }
                    257:        if (created)
1.1       cgd       258:                (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
                    259:
                    260:        (void)fsync(mbfd);              /* Don't wait for update. */
                    261:        (void)close(mbfd);              /* Implicit unlock. */
                    262:
                    263:        if (!rval)
                    264:                notifybiff(biffmsg);
                    265:        return(rval);
                    266: }
                    267:
                    268: void
                    269: notifybiff(msg)
                    270:        char *msg;
                    271: {
                    272:        static struct sockaddr_in addr;
                    273:        static int f = -1;
                    274:        struct hostent *hp;
                    275:        struct servent *sp;
                    276:        int len;
                    277:
                    278:        if (!addr.sin_family) {
                    279:                /* Be silent if biff service not available. */
                    280:                if (!(sp = getservbyname("biff", "udp")))
                    281:                        return;
                    282:                if (!(hp = gethostbyname("localhost"))) {
                    283:                        err(NOTFATAL, "localhost: %s", strerror(errno));
                    284:                        return;
                    285:                }
1.9       mycroft   286:                addr.sin_len = sizeof(struct sockaddr_in);
1.1       cgd       287:                addr.sin_family = hp->h_addrtype;
1.9       mycroft   288:                addr.sin_port = sp->s_port;
1.1       cgd       289:                bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
                    290:        }
                    291:        if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
                    292:                err(NOTFATAL, "socket: %s", strerror(errno));
                    293:                return;
                    294:        }
                    295:        len = strlen(msg) + 1;
                    296:        if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
                    297:            != len)
                    298:                err(NOTFATAL, "sendto biff: %s", strerror(errno));
                    299: }
                    300:
                    301: void
                    302: usage()
                    303: {
                    304:        err(FATAL, "usage: mail.local [-f from] user ...");
                    305: }
                    306:
                    307: #if __STDC__
                    308: #include <stdarg.h>
                    309: #else
                    310: #include <varargs.h>
                    311: #endif
                    312:
                    313: void
                    314: #if __STDC__
                    315: err(int isfatal, const char *fmt, ...)
                    316: #else
                    317: err(isfatal, fmt)
                    318:        int isfatal;
                    319:        char *fmt;
                    320:        va_dcl
                    321: #endif
                    322: {
                    323:        va_list ap;
                    324: #if __STDC__
                    325:        va_start(ap, fmt);
                    326: #else
                    327:        va_start(ap);
                    328: #endif
                    329:        vsyslog(LOG_ERR, fmt, ap);
                    330:        va_end(ap);
                    331:        if (isfatal)
                    332:                exit(1);
                    333: }

CVSweb <webmaster@jp.NetBSD.org>