home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / libexec / mail.local / mail.local.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-19  |  7.5 KB  |  309 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)mail.local.c    5.6 (Berkeley) 6/19/91";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46. #include <sys/socket.h>
  47. #include <netinet/in.h>
  48. #include <syslog.h>
  49. #include <fcntl.h>
  50. #include <netdb.h>
  51. #include <pwd.h>
  52. #include <time.h>
  53. #include <unistd.h>
  54. #include <errno.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include "pathnames.h"
  59.  
  60. #define    FATAL        1
  61. #define    NOTFATAL    0
  62.  
  63. int    deliver __P((int, char *));
  64. void    err __P((int, const char *, ...));
  65. void    notifybiff __P((char *));
  66. int    store __P((char *));
  67. void    usage __P((void));
  68.  
  69. main(argc, argv)
  70.     int argc;
  71.     char **argv;
  72. {
  73.     extern int optind;
  74.     extern char *optarg;
  75.     struct passwd *pw;
  76.     int ch, fd, eval;
  77.     uid_t uid;
  78.     char *from;
  79.  
  80.     openlog("mail.local", LOG_PERROR, LOG_MAIL);
  81.  
  82.     from = NULL;
  83.     while ((ch = getopt(argc, argv, "df:r:")) != EOF)
  84.         switch(ch) {
  85.         case 'd':        /* backward compatible */
  86.             break;
  87.         case 'f':
  88.         case 'r':        /* backward compatible */
  89.             if (from)
  90.                 err(FATAL, "multiple -f options");
  91.             from = optarg;
  92.             break;
  93.         case '?':
  94.         default:
  95.             usage();
  96.         }
  97.     argc -= optind;
  98.     argv += optind;
  99.  
  100.     if (!*argv)
  101.         usage();
  102.  
  103.     /*
  104.      * If from not specified, use the name from getlogin() if the
  105.      * uid matches, otherwise, use the name from the password file
  106.      * corresponding to the uid.
  107.      */
  108.     uid = getuid();
  109.     if (!from && (!(from = getlogin()) ||
  110.         !(pw = getpwnam(from)) || pw->pw_uid != uid))
  111.         from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
  112.  
  113.     fd = store(from);
  114.     for (eval = 0; *argv; ++argv)
  115.         eval |= deliver(fd, *argv);
  116.     exit(eval);
  117. }
  118.  
  119. store(from)
  120.     char *from;
  121. {
  122.     FILE *fp;
  123.     time_t tval;
  124.     int fd, eline;
  125.     char *tn, line[2048];
  126.  
  127.     tn = strdup(_PATH_LOCTMP);
  128.     if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
  129.         err(FATAL, "unable to open temporary file");
  130.     (void)unlink(tn);
  131.     free(tn);
  132.  
  133.     (void)time(&tval);
  134.     (void)fprintf(fp, "From %s %s", from, ctime(&tval));
  135.  
  136.     line[0] = '\0';
  137.     for (eline = 1; fgets(line, sizeof(line), stdin);) {
  138.         if (line[0] == '\n')
  139.             eline = 1;
  140.         else {
  141.             if (eline && line[0] == 'F' && !bcmp(line, "From ", 5))
  142.                 (void)putc('>', fp);
  143.             eline = 0;
  144.         }
  145.         (void)fprintf(fp, "%s", line);
  146.         if (ferror(fp))
  147.             break;
  148.     }
  149.  
  150.     /* If message not newline terminated, need an extra. */
  151.     if (!index(line, '\n'))
  152.         (void)putc('\n', fp);
  153.     /* Output a newline; note, empty messages are allowed. */
  154.     (void)putc('\n', fp);
  155.  
  156.     (void)fflush(fp);
  157.     if (ferror(fp))
  158.         err(FATAL, "temporary file write error");
  159.     return(fd);
  160. }
  161.  
  162. deliver(fd, name)
  163.     int fd;
  164.     char *name;
  165. {
  166.     struct stat sb;
  167.     struct passwd *pw;
  168.     int created, mbfd, nr, nw, off, rval;
  169.     char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
  170.     off_t curoff, lseek();
  171.  
  172.     /*
  173.      * Disallow delivery to unknown names -- special mailboxes can be
  174.      * handled in the sendmail aliases file.
  175.      */
  176.     if (!(pw = getpwnam(name))) {
  177.         err(NOTFATAL, "unknown name: %s", name);
  178.         return(1);
  179.     }
  180.  
  181.     (void)sprintf(path, "%s/%s", _PATH_MAILDIR, name);
  182.  
  183.     if (!(created = lstat(path, &sb)) &&
  184.         (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
  185.         err(NOTFATAL, "%s: linked file", path);
  186.         return(1);
  187.     }
  188.  
  189.     /*
  190.      * There's a race here -- two processes think they both created
  191.      * the file.  This means the file cannot be unlinked.
  192.      */
  193.     if ((mbfd =
  194.         open(path, O_APPEND|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
  195.         err(NOTFATAL, "%s: %s", path, strerror(errno));
  196.         return(1);
  197.     }
  198.  
  199.     rval = 0;
  200.     /* XXX: Open should allow flock'ing the file; see 4.4BSD. */
  201.     if (flock(mbfd, LOCK_EX)) {
  202.         err(NOTFATAL, "%s: %s", path, strerror(errno));
  203.         rval = 1;
  204.         goto bad;
  205.     }
  206.  
  207.     curoff = lseek(mbfd, 0L, SEEK_END);
  208.     (void)sprintf(biffmsg, "%s@%ld\n", name, curoff);
  209.     if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
  210.         err(FATAL, "temporary file: %s", strerror(errno));
  211.         rval = 1;
  212.         goto bad;
  213.     }
  214.  
  215.     while ((nr = read(fd, buf, sizeof(buf))) > 0)
  216.         for (off = 0; off < nr; nr -= nw, off += nw)
  217.             if ((nw = write(mbfd, buf + off, nr)) < 0) {
  218.                 err(NOTFATAL, "%s: %s", path, strerror(errno));
  219.                 goto trunc;
  220.             }
  221.     if (nr < 0) {
  222.         err(FATAL, "temporary file: %s", strerror(errno));
  223. trunc:        (void)ftruncate(mbfd, curoff);
  224.         rval = 1;
  225.     }
  226.  
  227.     /*
  228.      * Set the owner and group.  Historically, binmail repeated this at
  229.      * each mail delivery.  We no longer do this, assuming that if the
  230.      * ownership or permissions were changed there was a reason for doing
  231.      * so.
  232.      */
  233. bad:    if (created) 
  234.         (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
  235.  
  236.     (void)fsync(mbfd);        /* Don't wait for update. */
  237.     (void)close(mbfd);        /* Implicit unlock. */
  238.  
  239.     if (!rval)
  240.         notifybiff(biffmsg);
  241.     return(rval);
  242. }
  243.  
  244. void
  245. notifybiff(msg)
  246.     char *msg;
  247. {
  248.     static struct sockaddr_in addr;
  249.     static int f = -1;
  250.     struct hostent *hp;
  251.     struct servent *sp;
  252.     int len;
  253.  
  254.     if (!addr.sin_family) {
  255.         /* Be silent if biff service not available. */
  256.         if (!(sp = getservbyname("biff", "udp")))
  257.             return;
  258.         if (!(hp = gethostbyname("localhost"))) {
  259.             err(NOTFATAL, "localhost: %s", strerror(errno));
  260.             return;
  261.         }
  262.         addr.sin_family = hp->h_addrtype;
  263.         bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
  264.         addr.sin_port = sp->s_port;
  265.     }
  266.     if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  267.         err(NOTFATAL, "socket: %s", strerror(errno));
  268.         return;
  269.     }
  270.     len = strlen(msg) + 1;
  271.     if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
  272.         != len)
  273.         err(NOTFATAL, "sendto biff: %s", strerror(errno));
  274. }
  275.  
  276. void
  277. usage()
  278. {
  279.     err(FATAL, "usage: mail.local [-f from] user ...");
  280. }
  281.  
  282. #if __STDC__
  283. #include <stdarg.h>
  284. #else
  285. #include <varargs.h>
  286. #endif
  287.  
  288. void
  289. #if __STDC__
  290. err(int isfatal, const char *fmt, ...)
  291. #else
  292. err(isfatal, fmt)
  293.     int isfatal;
  294.     char *fmt;
  295.     va_dcl
  296. #endif
  297. {
  298.     va_list ap;
  299. #if __STDC__
  300.     va_start(ap, fmt);
  301. #else
  302.     va_start(ap);
  303. #endif
  304.     vsyslog(LOG_ERR, fmt, ap);
  305.     va_end(ap);
  306.     if (isfatal)
  307.         exit(1);
  308. }
  309.