from scratch -- /bin/mail was a security problem, and not worth fixing
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 18 Jan 1991 06:39:32 +0000 (22:39 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 18 Jan 1991 06:39:32 +0000 (22:39 -0800)
SCCS-vsn: libexec/mail.local/Makefile 5.3
SCCS-vsn: libexec/mail.local/mail.local.8 6.7
SCCS-vsn: libexec/mail.local/mail.local.c 4.38
SCCS-vsn: libexec/mail.local/pathnames.h 5.3

usr/src/libexec/mail.local/Makefile
usr/src/libexec/mail.local/mail.local.8
usr/src/libexec/mail.local/mail.local.c
usr/src/libexec/mail.local/pathnames.h

index 56e821a..e8a915f 100644 (file)
@@ -1,7 +1,7 @@
-#      @(#)Makefile    5.2 (Berkeley) %G%
+#      @(#)Makefile    5.3 (Berkeley) %G%
 
 
-PROG=  delivermail
-MAN8=  delivermail.0
+PROG=  mail.local
+MAN8=  mail.local.0
 BINOWN=        root
 BINMODE=4555
 
 BINOWN=        root
 BINMODE=4555
 
index 68e6d09..6b88775 100644 (file)
-.\" Copyright (c) 1990 Regents of the University of California.
-.\" All rights reserved.  The Berkeley software License Agreement
-.\" specifies the terms and conditions for redistribution.
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
 .\"
 .\"
-.\"     @(#)mail.local.8       6.6 (Berkeley) %G%
+.\" %sccs.include.redist.man%
+.\"
+.\"    @(#)mail.local.8        6.7 (Berkeley) %G%
 .\"
 .Dd 
 .\"
 .Dd 
-.Dt DELIVERMAIL 8
+.Dt MAIL.LOCAL 8
 .Os ATT 7th
 .Sh NAME
 .Os ATT 7th
 .Sh NAME
-.Nm delivermail
-.Nd send or receive mail among users
+.Nm mail.local
+.Nd store mail in a mailbox
 .Sh SYNOPSIS
 .Sh SYNOPSIS
-.Nm delivermail
-.Op Ic +
-.Op Fl i
-.Op Ar person
-.Op \&...
-.Nm delivermail
-.Op Ic +
-.Op Fl i
-.Fl f
-.Ar file
+.Nm mail.local
+.Op Fl f Ar from
+.Ar user ...
 .Pp
 .Sh DESCRIPTION
 .Pp
 .Sh DESCRIPTION
-Note: This is the old version 7 UNIX system mail program.  The default
-.Nm mail
-command is described in
-.Xr Mail  1  .
+.Nm Mail.local
+reads the standard input up to an end-of-file and appends it to each
+.Sf Ar user \'s
+.Pa mail
+file.
+The
+.Ar user
+must be a valid user name.
 .Pp
 .Pp
-.Nm Mail
-with no argument prints a user's mail, message-by-message,
-in last-in, first-out order; the optional argument
-.Ic +
-displays the mail messages in first-in, first-out order.
-For each message, it reads a line from the standard input
-to direct disposition of the message.
+The options are as follows:
 .Tw Fl
 .Tw Fl
-.Tp Li newline
-Go on to next message.
-.Tp Ic d
-Delete message and go on to the next.
-.Tp Ic p
-Print message again.
-.Tp Fl
-Go back to previous message.
-.Tc Ic s
-.Op Ar file
-.Cx \&...
-.Cx
-Save the message in the named
-.Ar files
-(`mbox' default).
-.Tc Ic w
-.Op Ar file
-.Cx \&...
-.Cx
-Save the message, without a header, in the named
-.Ar files ,
-.Pa mbox
-is the default.
-.Tc Ic m
-.Op Ar person
-.Cx \&...
-.Cx
-Mail the message to the named
-.Ar persons
-(yourself is default).
-.Tp Li EOT
-(control-D)
-Put unexamined mail back in the mailbox and stop.
-.Tp Ic q
-Same as
-.Li EOT .
-.Tc Ic \&!
-.Ar command
+.Tc Fl f
+.Ws
+.Ar from
 .Cx
 .Cx
-Escape to the Shell to do
-.Ar command  .
-.Tp Ic \&*
-Print a command summary.
+Specify the sender's name.
 .Tp
 .Pp
 .Tp
 .Pp
-An interrupt normally terminates the
-.Ar mail
-command; the mail file is unchanged.  The optional argument
-.Fl i
-tells
-.Ar mail
-to continue after interrupts.
+Individual mail messages in the mailbox are delimited by an empty
+line followed by a line beginning with the string ``From ''.
+A line containing the string ``From '', the sender's name and a time stamp
+is prepended to each delivered mail message.
+A blank line is appended to each message.
+A greater-than character (``>'') is prepended to any line in the message
+which could be mistaken for a ``From '' delimiter line.
 .Pp
 .Pp
-When
-.Ar persons
-are named,
-.Ar mail
-takes the standard input up to an end-of-file (or a line with just `.')
-and adds it to each
-.Sf Ar person \'s
-.Pa mail
-file.  The message is preceded by the sender's name and a postmark.
-Lines that look like postmarks are prepended with `>'.  A
-.Ar person
-is usually a user name recognized by
-.Xr login  1  .
-To denote a recipient on a remote system, prefix
-.Ar person
-by the system name and exclamation mark (see
-.Xr uucp  1  ) .
+The mail files are exclusively locked with 
+.Xr flock 2
+while mail is appended.
 .Pp
 .Pp
-The
-.Fl f
-option causes the named file, for example,
-.Pa mbox ,
-to be printed as if it were the mail file.
+If the ``biff'' service is returned by
+.Xr getservbyname 3 ,
+the biff server is notified of delivered mail.
 .Pp
 .Pp
-When a user logs in he is informed of the presence of mail.
+The
+.Nm mail.local
+utility exits 0 on success, and >0 if an error occurs.
 .Sh ENVIRONMENT
 .Tw Fl
 .Sh ENVIRONMENT
 .Tw Fl
-.Tp Ev HOME
-The
-.Ev HOME
-variable is used by
-.Nm delivermail
-to find the file
-.Pa mbox.
-.Tp Ev HOSTALIASES
-Used to find host aliases.
-.Tp Ev NAME
-.Nm Delivermail
-extracts the users full name from the
-.Ev NAME
-variable.
 .Tp Ev TZ
 .Tp Ev TZ
-Used to set the appropriate time zone
-on the postmark.
+Used to set the appropriate time zone on the timestamp.
 .Sh FILES
 .Sh FILES
-.Dw /var/spool/mail/*
+.Dw /tmp/local.XXXXXX
 .Di L
 .Di L
-.Dp Pa /etc/passwd
-to identify sender and locate persons
-.Dp Pa /var/spool/mail/*
-incoming mail for user *
-.Dp Pa mbox
-saved mail
-.Dp Pa /tmp/ma*
-temp file
-.Dp Pa dead.letter
-unmailable text
+.Dp Pa /tmp/local.XXXXXX
+temporary files
+.Dp Pa /var/mail/user
+user's mailbox directory
 .Dp
 .Sh SEE ALSO
 .Dp
 .Sh SEE ALSO
-.Xr Mail 1 ,
-.Xr write 1 ,
-.Xr uucp 1 ,
-.Xr uux 1 ,
+.Xr mail 1 ,
 .Xr xsend 1 ,
 .Xr xsend 1 ,
+.Xr flock 2 ,
+.Xr getservbyname 3 ,
+.Xr comsat 8 ,
 .Xr sendmail 8
 .Sh HISTORY
 .Xr sendmail 8
 .Sh HISTORY
-.Nm Delivermail
+A superset of
+.Nm mail.local
+(handling mailbox reading as well as mail delivery)
 appeared in Version 7 AT&T Unix as the program
 appeared in Version 7 AT&T Unix as the program
-.Nm mail.
-.Sh BUGS
-Race conditions sometimes result in a failure to remove a lock file.
-.Pp
-Normally anybody can read your mail, unless it is sent by
-.Xr xsend  1  .
-An installation can overcome this by making
-.Nm mail
-a set-user-id command that owns the mail directory.
+.Nm mail .
index 32c8212..bd5a271 100644 (file)
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)mail.local.c       4.37 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)mail.local.c       4.38 (Berkeley) %G%";
+#endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/file.h>
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/file.h>
-
-#include <ctype.h>
-#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <netdb.h>
 #include <pwd.h>
 #include <pwd.h>
-#include <utmp.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sysexits.h>
+#include <time.h>
+#include <varargs.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 #include "pathnames.h"
 
 #include "pathnames.h"
 
-       /* copylet flags */
-#define REMOTE         1               /* remote mail, add rmtmsg */
-#define ORDINARY       2
-#define ZAP            3               /* zap header and trailing empty line */
-#define        FORWARD         4
-
-#define        LSIZE           256
-#define        MAXLET          300             /* maximum number of letters */
-#define        MAILMODE        0600            /* mode of created mail */
-
-char   line[LSIZE];
-char   resp[LSIZE];
-struct let {
-       long    adr;
-       char    change;
-} let[MAXLET];
-int    nlet    = 0;
-char   lfil[50];
-long   iop, time();
-char   *getenv();
-char   *index();
-char   lettmp[] = _PATH_TMP;
-char   maildir[sizeof(_PATH_MAILDIR) + 5] = _PATH_MAILDIR;
-char   mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-char   dead[] = "dead.letter";
-char   forwmsg[] = " forwarded\n";
-FILE   *tmpf;
-FILE   *malf;
-char   my_name[60];
-char   *getlogin();
-int    error;
-int    changed;
-int    forward;
-char   from[] = "From ";
-long   ftell();
-int    delex();
-char   *ctime();
-int    flgf;
-int    flgp;
-int    delflg = 1;
-int    hseqno;
-jmp_buf        sjbuf;
-int    rmail;
+#define        FATAL           1
+#define        NOTFATAL        0
 
 main(argc, argv)
 
 main(argc, argv)
-char **argv;
-{
-       register int i;
-       char *name;
-       struct passwd *pwent;
-
-       (void)strcat(maildir, "/");
-       if (!(name = getlogin()) || !*name || !(pwent = getpwnam(name)) ||
-           getuid() != pwent->pw_uid) 
-               pwent = getpwuid(getuid());
-       strncpy(my_name, pwent ? pwent->pw_name : "???", sizeof(my_name)-1);
-       if (setjmp(sjbuf))
-               done();
-       for (i=SIGHUP; i<=SIGTERM; i++)
-               setsig(i, delex);
-       i = mkstemp(lettmp);
-       tmpf = fdopen(i, "r+");
-       if (i < 0 || tmpf == NULL)
-               panic("mail: %s: cannot open for writing", lettmp);
-       /*
-        * This protects against others reading mail from temp file and
-        * if we exit, the file will be deleted already.
-        */
-       unlink(lettmp);
-       if (argv[0][0] == 'r')
-               rmail++;
-       if (argv[0][0] != 'r' &&        /* no favors for rmail*/
-          (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd")))
-               printmail(argc, argv);
-       else
-               bulkmail(argc, argv);
-       done();
-}
-
-setsig(i, f)
-int i;
-int (*f)();
-{
-       if (signal(i, SIG_IGN) != SIG_IGN)
-               signal(i, f);
-}
-
-any(c, str)
-       register int c;
-       register char *str;
-{
-
-       while (*str)
-               if (c == *str++)
-                       return(1);
-       return(0);
-}
-
-printmail(argc, argv)
+       int argc;
        char **argv;
 {
        char **argv;
 {
-       int flg, i, j, print;
-       char *p, *getarg();
-       struct stat statb;
-
-       setuid(getuid());
-       cat(mailfile, maildir, my_name);
-#ifdef notdef
-       if (stat(mailfile, &statb) >= 0
-           && (statb.st_mode & S_IFMT) == S_IFDIR) {
-               strcat(mailfile, "/");
-               strcat(mailfile, my_name);
-       }
-#endif
-       for (; argc > 1; argv++, argc--) {
-               if (argv[1][0] != '-')
-                       break;
-               switch (argv[1][1]) {
+       extern int optind;
+       extern char *optarg;
+       struct passwd *pw;
+       int ch, fd, eval;
+       uid_t uid;
+       char *from;
 
 
-               case 'p':
-                       flgp++;
-                       /* fall thru... */
-               case 'q':
-                       delflg = 0;
-                       break;
+       openlog("mail.local", LOG_PERROR, LOG_MAIL);
 
 
-               case 'f':
-                       if (argc >= 3) {
-                               strcpy(mailfile, argv[2]);
-                               argv++, argc--;
-                       }
+       from = NULL;
+       while ((ch = getopt(argc, argv, "df:r:")) != EOF)
+               switch(ch) {
+               case 'd':               /* backward compatible */
                        break;
                        break;
-
-               case 'b':
-                       forward = 1;
+               case 'f':
+               case 'r':               /* backward compatible */
+                       if (from)
+                           error(FATAL, "multiple -f options.");
+                       from = optarg;
                        break;
                        break;
-
+               case '?':
                default:
                default:
-                       panic("unknown option %c", argv[1][1]);
-                       /*NOTREACHED*/
-               }
-       }
-       malf = fopen(mailfile, "r");
-       if (malf == NULL) {
-               printf("No mail.\n");
-               return;
-       }
-       flock(fileno(malf), LOCK_SH);
-       copymt(malf, tmpf);
-       fclose(malf);                   /* implicit unlock */
-       fseek(tmpf, 0L, L_SET);
-
-       changed = 0;
-       print = 1;
-       for (i = 0; i < nlet; ) {
-               j = forward ? i : nlet - i - 1;
-               if (setjmp(sjbuf)) {
-                       print = 0;
-               } else {
-                       if (print)
-                               copylet(j, stdout, ORDINARY);
-                       print = 1;
-               }
-               if (flgp) {
-                       i++;
-                       continue;
+                       usage();
                }
                }
-               setjmp(sjbuf);
-               fputs("? ", stdout);
-               fflush(stdout);
-               if (fgets(resp, LSIZE, stdin) == NULL)
-                       break;
-               switch (resp[0]) {
+       argc -= optind;
+       argv += optind;
 
 
-               default:
-                       printf("usage\n");
-               case '?':
-                       print = 0;
-                       printf("q\tquit\n");
-                       printf("x\texit without changing mail\n");
-                       printf("p\tprint\n");
-                       printf("s[file]\tsave (default mbox)\n");
-                       printf("w[file]\tsame without header\n");
-                       printf("-\tprint previous\n");
-                       printf("d\tdelete\n");
-                       printf("+\tnext (no delete)\n");
-                       printf("m user\tmail to user\n");
-                       printf("! cmd\texecute cmd\n");
-                       break;
+       if (!*argv)
+               usage();
 
 
-               case '+':
-               case 'n':
-               case '\n':
-                       i++;
-                       break;
-               case 'x':
-                       changed = 0;
-               case 'q':
-                       goto donep;
-               case 'p':
-                       break;
-               case '^':
-               case '-':
-                       if (--i < 0)
-                               i = 0;
-                       break;
-               case 'y':
-               case 'w':
-               case 's':
-                       flg = 0;
-                       if (resp[1] != '\n' && resp[1] != ' ') {
-                               printf("illegal\n");
-                               flg++;
-                               print = 0;
-                               continue;
-                       }
-                       if (resp[1] == '\n' || resp[1] == '\0') {
-                               p = getenv("HOME");
-                               if (p != 0)
-                                       cat(resp+1, p, "/mbox");
-                               else
-                                       cat(resp+1, "", "mbox");
-                       }
-                       for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
-                               malf = fopen(lfil, "a");
-                               if (malf == NULL) {
-                                       printf("mail: %s: cannot append\n",
-                                           lfil);
-                                       flg++;
-                                       continue;
-                               }
-                               copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
-                               fclose(malf);
-                       }
-                       if (flg)
-                               print = 0;
-                       else {
-                               let[j].change = 'd';
-                               changed++;
-                               i++;
-                       }
-                       break;
-               case 'm':
-                       flg = 0;
-                       if (resp[1] == '\n' || resp[1] == '\0') {
-                               i++;
-                               continue;
-                       }
-                       if (resp[1] != ' ') {
-                               printf("invalid command\n");
-                               flg++;
-                               print = 0;
-                               continue;
-                       }
-                       for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
-                               if (!sendmail(j, lfil, my_name))
-                                       flg++;
-                       if (flg)
-                               print = 0;
-                       else {
-                               let[j].change = 'd';
-                               changed++;
-                               i++;
-                       }
-                       break;
-               case '!':
-                       system(resp+1);
-                       printf("!\n");
-                       print = 0;
-                       break;
-               case 'd':
-                       let[j].change = 'd';
-                       changed++;
-                       i++;
-                       if (resp[1] == 'q')
-                               goto donep;
-                       break;
-               }
-       }
-   donep:
-       if (changed)
-               copyback();
+       /*
+        * If from not specified, use the name from getlogin() if the
+        * uid matches, otherwise, use the name from the password file
+        * corresponding to the uid.
+        */
+       uid = getuid();
+       if (!from || !(from = getlogin()) ||
+           !(pw = getpwnam(from)) || pw->pw_uid != uid)
+               from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
+
+       fd = store(from);
+       for (eval = 0; *argv; ++argv)
+               eval |= deliver(fd, *argv);
+       exit(eval);
 }
 
 }
 
-/* copy temp or whatever back to /usr/spool/mail */
-copyback()
+store(from)
+       char *from;
 {
 {
-       register int i, c;
-       long oldmask;
-       int fd, new = 0;
-       struct stat stbuf;
-
-       oldmask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)|sigmask(SIGQUIT));
-       fd = open(mailfile, O_RDWR | O_CREAT, MAILMODE);
-       if (fd >= 0) {
-               flock(fd, LOCK_EX);
-               malf = fdopen(fd, "r+");
-       }
-       if (fd < 0 || malf == NULL)
-               panic("can't rewrite %s", lfil);
-       fstat(fd, &stbuf);
-       if (stbuf.st_size != let[nlet].adr) {   /* new mail has arrived */
-               fseek(malf, let[nlet].adr, L_SET);
-               fseek(tmpf, let[nlet].adr, L_SET);
-               while ((c = getc(malf)) != EOF)
-                       putc(c, tmpf);
-               let[++nlet].adr = stbuf.st_size;
-               new = 1;
-               fseek(malf, 0L, L_SET);
-       }
-       ftruncate(fd, 0L);
-       for (i = 0; i < nlet; i++)
-               if (let[i].change != 'd')
-                       copylet(i, malf, ORDINARY);
-       fclose(malf);           /* implict unlock */
-       if (new)
-               printf("New mail has arrived.\n");
-       sigsetmask(oldmask);
-}
+       FILE *fp;
+       time_t tval;
+       int fd, eline;
+       char *tn, line[2048];
 
 
-/* copy mail (f1) to temp (f2) */
-copymt(f1, f2)
-       FILE *f1, *f2;
-{
-       long nextadr;
-
-       nlet = nextadr = 0;
-       let[0].adr = 0;
-       while (fgets(line, LSIZE, f1) != NULL) {
-               if (isfrom(line))
-                       let[nlet++].adr = nextadr;
-               nextadr += strlen(line);
-               fputs(line, f2);
-       }
-       let[nlet].adr = nextadr;        /* last plus 1 */
-}
+       tn = _PATH_LOCTMP;
+       if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
+               error(FATAL, "unable to open temporary file.");
+       (void)unlink(tn);
 
 
-copylet(n, f, type)
-       FILE *f;
-{
-       int ch;
-       long k;
-       char hostname[MAXHOSTNAMELEN];
-
-       fseek(tmpf, let[n].adr, L_SET);
-       k = let[n+1].adr - let[n].adr;
-       while (k-- > 1 && (ch = getc(tmpf)) != '\n')
-               if (type != ZAP)
-                       putc(ch, f);
-       switch (type) {
-
-       case REMOTE:
-               gethostname(hostname, sizeof (hostname));
-               fprintf(f, " remote from %s\n", hostname);
-               break;
-
-       case FORWARD:
-               fprintf(f, forwmsg);
-               break;
-
-       case ORDINARY:
-               putc(ch, f);
-               break;
-
-       case ZAP:
-               break;
-
-       default:
-               panic("Bad letter type %d to copylet.", type);
-       }
-       while (k-- > 1) {
-               ch = getc(tmpf);
-               putc(ch, f);
+       (void)time(&tval);
+       (void)fprintf(fp, "From %s %s", from, ctime(&tval));
+
+       line[0] = '\0';
+       for (eline = 1; fgets(line, sizeof(line), stdin);) {
+               if (line[0] == '\n')
+                       eline = 1;
+               else {
+                       if (eline && line[0] == 'F' && !bcmp(line, "From ", 5))
+                               (void)putc('>', fp);
+                       eline = 0;
+               }
+               (void)fprintf(fp, "%s", line);
+               if (ferror(fp))
+                       break;
        }
        }
-       if (type != ZAP || ch != '\n')
-               putc(getc(tmpf), f);
-}
 
 
-isfrom(lp)
-register char *lp;
-{
-       register char *p;
+       /* If message not newline terminated, need an extra. */
+       if (!index(line, '\n'))
+               (void)putc('\n', fp);
+       /* Output a newline; note, empty messages are allowed. */
+       (void)putc('\n', fp);
 
 
-       for (p = from; *p; )
-               if (*lp++ != *p++)
-                       return(0);
-       return(1);
+       (void)fflush(fp);
+       if (ferror(fp))
+               error(FATAL, "temporary file write error.");
+       return(fd);
 }
 
 }
 
-bulkmail(argc, argv)
-char **argv;
+deliver(fd, name)
+       int fd;
+       char *name;
 {
 {
-       char *truename;
-       int first;
-       register char *cp;
-       char *newargv[1000];
-       register char **ap;
-       register char **vp;
-       int dflag;
-
-       dflag = 0;
-       delflg = 0;
-       if (argc < 1) {
-               fprintf(stderr, "puke\n");
-               return;
-       }
-       for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++)
-               if (ap[0][0] == '-' && ap[0][1] == 'd')
-                       dflag++;
-       if (!dflag) {
-               /* give it to sendmail, rah rah! */
-               unlink(lettmp);
-               ap = newargv+1;
-               if (rmail)
-                       *ap-- = "-s";
-               *ap = "-sendmail";
-               setuid(getuid());
-               execv(_PATH_SENDMAIL, ap);
-               perror(_PATH_SENDMAIL);
-               exit(EX_UNAVAILABLE);
-       }
-
-       truename = 0;
-       line[0] = '\0';
+       struct stat sb;
+       struct passwd *pw;
+       int created, mbfd, nr, nw, off, rval;
+       char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
+       off_t curoff, lseek();
 
        /*
 
        /*
-        * When we fall out of this, argv[1] should be first name,
-        * argc should be number of names + 1.
+        * Disallow delivery to unknown names -- special mailboxes can be
+        * handled in the sendmail aliases file.
         */
         */
+       if (!(pw = getpwnam(name))) {
+               error(NOTFATAL, "unknown name: %s.", name);
+               return(1);
+       }
 
 
-       while (argc > 1 && *argv[1] == '-') {
-               cp = *++argv;
-               argc--;
-               switch (cp[1]) {
-               case 'r':
-                       if (argc <= 1)
-                               usage();
-                       if (strcmp(my_name, "root") == 0 ||
-                           strcmp(my_name, "daemon") == 0 ||
-                           strcmp(my_name, "network") == 0 ||
-                           strcmp(my_name, "uucp")) {
-                               gaver++;
-                               strcpy(truename, argv[1]);
-                               fgets(line, LSIZE, stdin);
-                               if (strncmp("From", line, 4) == 0)
-                                       line[0] = '\0';
-                       }
-                       argv++;
-                       argc--;
-                       break;
+       (void)sprintf(path, "%s/%s", _PATH_MAILDIR, name);
 
 
-               case 'h':
-                       if (argc <= 1)
-                               usage();
-                       hseqno = atoi(argv[1]);
-                       argv++;
-                       argc--;
-                       break;
-
-               case 'd':
-                       break;
-               
-               default:
-                       usage();
-               }
-       }
-       if (argc <= 1)
-               usage();
-       if (truename == 0)
-               truename = my_name;
-       time(&iop);
-       fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop));
-       iop = ftell(tmpf);
-       flgf = first = 1;
-       for (;;) {
-               if (first) {
-                       first = 0;
-                       if (*line == '\0' && fgets(line, LSIZE, stdin) == NULL)
-                               break;
-               } else {
-                       if (fgets(line, LSIZE, stdin) == NULL)
-                               break;
-               }
-               if (*line == '.' && line[1] == '\n' && isatty(fileno(stdin)))
-                       break;
-               if (isfrom(line))
-                       putc('>', tmpf);
-               fputs(line, tmpf);
-               flgf = 0;
+       if (!(created = lstat(path, &sb)) &&
+           (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
+               error(NOTFATAL, "%s: linked file.", path);
+               return(1);
        }
        }
-       putc('\n', tmpf);
-       nlet = 1;
-       let[0].adr = 0;
-       let[1].adr = ftell(tmpf);
-       if (flgf)
-               return;
-       while (--argc > 0)
-               if (!sendmail(0, *++argv, truename))
-                       error++;
-       if (error && safefile(dead)) {
-               setuid(getuid());
-               malf = fopen(dead, "w");
-               if (malf == NULL) {
-                       printf("mail: cannot open %s\n", dead);
-                       fclose(tmpf);
-                       return;
-               }
-               copylet(0, malf, ZAP);
-               fclose(malf);
-               printf("Mail saved in %s\n", dead);
-       }
-       fclose(tmpf);
-}
 
 
-sendrmt(n, name)
-char *name;
-{
-       FILE *rmf, *popen();
-       register char *p;
-       char rsys[64], cmd[64];
-       register pid;
-       int sts;
-
-#ifdef notdef
-       if (any('^', name)) {
-               while (p = index(name, '^'))
-                       *p = '!';
-               if (strncmp(name, "researc", 7)) {
-                       strcpy(rsys, "research");
-                       if (*name != '!')
-                               --name;
-                       goto skip;
-               }
+       /*
+        * There's a race here -- two processes think they both created
+        * the file.  This means the file cannot be unlinked.
+        */
+       if ((mbfd =
+           open(path, O_APPEND|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+               error(NOTFATAL, "%s: %s.", path, strerror(errno));
+               return(1);
        }
        }
-#endif
-       for (p=rsys; *name!='!'; *p++ = *name++)
-               if (*name=='\0')
-                       return(0);      /* local address, no '!' */
-       *p = '\0';
-       if (name[1]=='\0') {
-               printf("null name\n");
-               return(0);
+
+       rval = 0;
+       /* XXX: Open should allow flock'ing the file; see 4.4BSD. */
+       if (flock(mbfd, LOCK_EX)) {
+               error(NOTFATAL, "%s: %s.", path, strerror(errno));
+               rval = 1;
+               goto bad;
        }
        }
-skip:
-       if ((pid = fork()) == -1) {
-               fprintf(stderr, "mail: can't create proc for remote\n");
-               return(0);
+
+       curoff = lseek(mbfd, 0L, SEEK_END);
+       (void)sprintf(biffmsg, "%s@%ld\n", name, curoff);
+       if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
+               error(FATAL, "temporary file: %s.", strerror(errno));
+               rval = 1;
+               goto bad;
        }
        }
-       if (pid) {
-               while (wait(&sts) != pid) {
-                       if (wait(&sts)==-1)
-                               return(0);
-               }
-               return(!sts);
+
+       while ((nr = read(fd, buf, sizeof(buf))) > 0)
+               for (off = 0; off < nr; nr -= nw, off += nw)
+                       if ((nw = write(mbfd, buf + off, nr)) < 0) {
+                               error(NOTFATAL,
+                                   "%s: %s.", path, strerror(errno));
+                               goto trunc;
+                       }
+       if (nr < 0) {
+               error(FATAL, "temporary file: %s.", strerror(errno));
+trunc:         (void)ftruncate(mbfd, curoff);
+               rval = 1;
        }
        }
-       setuid(getuid());
-       if (any('!', name+1))
-               (void)sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
-       else
-               (void)sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
-       if ((rmf=popen(cmd, "w")) == NULL)
-               exit(1);
-       copylet(n, rmf, REMOTE);
-       exit(pclose(rmf) != 0);
-}
 
 
-usage()
-{
+       /*
+        * Set the owner and group.  Historically, binmail repeated this at
+        * each mail delivery.  We no longer do this, assuming that if the
+        * ownership or permissions were changed there was a reason for doing
+        * so.
+        */
+bad:   if (created) 
+               (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
 
 
-       fprintf(stderr, "Usage: mail [ -f ] people . . .\n");
-       error = EX_USAGE;
-       done();
-}
+       /* Implicit unlock. */
+       (void)close(mbfd);
 
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
+       if (!rval)
+               notifybiff(biffmsg);
+       return(rval);
+}
 
 notifybiff(msg)
        char *msg;
 {
        static struct sockaddr_in addr;
        static int f = -1;
 
 notifybiff(msg)
        char *msg;
 {
        static struct sockaddr_in addr;
        static int f = -1;
+       struct hostent *hp;
+       struct servent *sp;
+       int len;
 
 
-       if (addr.sin_family == 0) {
-               struct hostent *hp = gethostbyname("localhost");
-               struct servent *sp = getservbyname("biff", "udp");
-
-               if (hp && sp) {
-                       addr.sin_family = hp->h_addrtype;
-                       bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
-                       addr.sin_port = sp->s_port;
+       if (!addr.sin_family) {
+               /* Be silent if biff service not available. */
+               if (!(sp = getservbyname("biff", "udp")))
+                       return;
+               if (!(hp = gethostbyname("localhost"))) {
+                       error(NOTFATAL, "localhost: %s.", strerror(errno));
+                       return;
                }
                }
+               addr.sin_family = hp->h_addrtype;
+               bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
+               addr.sin_port = sp->s_port;
        }
        }
-       if (addr.sin_family) {
-               if (f < 0)
-                       f = socket(AF_INET, SOCK_DGRAM, 0);
-               if (f >= 0)
-                       sendto(f, msg, strlen(msg)+1, 0, &addr, sizeof (addr));
-       }
-}
-
-sendmail(n, name, fromaddr)
-       int n;
-       char *name, *fromaddr;
-{
-       char file[256];
-       int mask, fd;
-       struct passwd *pw;
-#ifdef notdef
-       struct stat statb;
-#endif
-       char buf[128];
-
-       if (*name=='!')
-               name++;
-       if (any('!', name))
-               return (sendrmt(n, name));
-       if ((pw = getpwnam(name)) == NULL) {
-               printf("mail: can't send to %s\n", name);
-               return(0);
-       }
-       cat(file, maildir, name);
-#ifdef notdef
-       if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) {
-               strcat(file, "/");
-               strcat(file, name);
-       }
-#endif
-       if (!safefile(file))
-               return(0);
-       fd = open(file, O_WRONLY | O_CREAT, MAILMODE);
-       if (fd >= 0) {
-               flock(fd, LOCK_EX);
-               malf = fdopen(fd, "a");
-       }
-       if (fd < 0 || malf == NULL) {
-               close(fd);
-               printf("mail: %s: cannot append\n", file);
-               return(0);
-       }
-       fchown(fd, pw->pw_uid, pw->pw_gid);
-       (void)sprintf(buf, "%s@%ld\n", name, ftell(malf));
-       copylet(n, malf, ORDINARY);
-       fclose(malf);
-       notifybiff(buf);
-       return(1);
-}
-
-delex(i)
-{
-       if (i != SIGINT) {
-               setsig(i, SIG_DFL);
-               sigsetmask(sigblock(0L) &~ sigmask(i));
+       if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+               error(NOTFATAL, "socket: %s.", strerror(errno));
+               return;
        }
        }
-       putc('\n', stderr);
-       if (delflg)
-               longjmp(sjbuf, 1);
-       if (error == 0)
-               error = i;
-       done();
-}
-
-done()
-{
-
-       unlink(lettmp);
-       exit(error);
+       len = strlen(msg) + 1;
+       if (sendto(f, msg, len, 0, &addr, sizeof(addr)) != len)
+               error(NOTFATAL, "sendto biff: %s.", strerror(errno));
 }
 
 }
 
-cat(to, from1, from2)
-       char *to, *from1, *from2;
-{
-       register char *cp, *dp;
-
-       cp = to;
-       for (dp = from1; *cp = *dp++; cp++)
-               ;
-       for (dp = from2; *cp++ = *dp++; )
-               ;
-}
-
-/* copy p... into s, update p */
-char *
-getarg(s, p)
-       register char *s, *p;
+usage()
 {
 {
-       while (*p == ' ' || *p == '\t')
-               p++;
-       if (*p == '\n' || *p == '\0')
-               return(NULL);
-       while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
-               *s++ = *p++;
-       *s = '\0';
-       return(p);
+       error(FATAL, "usage: mail.local [-f from] user ...");
 }
 
 }
 
-safefile(f)
-       char *f;
+/* VARARGS */
+error(va_alist)
+va_dcl
 {
 {
-       struct stat statb;
-
-       if (lstat(f, &statb) < 0)
-               return (1);
-       if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) {
-               fprintf(stderr,
-                   "mail: %s has more than one link or is a symbolic link\n",
-                   f);
-               return (0);
-       }
-       return (1);
-}
-
-panic(msg, a1, a2, a3)
-       char *msg;
-{
-
-       fprintf(stderr, "mail: ");
-       fprintf(stderr, msg, a1, a2, a3);
-       fprintf(stderr, "\n");
-       done();
+       va_list ap;
+       int isfatal;
+       char *fmt;
+
+       va_start(ap);
+       isfatal = va_arg(ap, int);
+       fmt = va_arg(ap, char *);
+       vsyslog(LOG_ERR, fmt, ap);
+       va_end(ap);
+       if (isfatal)
+               exit(1);
 }
 }
index d504a38..23c5819 100644 (file)
@@ -4,10 +4,8 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)pathnames.h 5.2 (Berkeley) %G%
+ *     @(#)pathnames.h 5.3 (Berkeley) %G%
  */
  */
-
 #include <paths.h>
 
 #include <paths.h>
 
-#undef _PATH_TMP
-#define _PATH_TMP      "/tmp/maXXXXX"
+#define _PATH_LOCTMP   "/tmp/local.XXXXXX"