summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/mail.local
diff options
context:
space:
mode:
authorgshapiro <gshapiro@FreeBSD.org>2000-08-12 22:19:16 +0000
committergshapiro <gshapiro@FreeBSD.org>2000-08-12 22:19:16 +0000
commit74c280481f7b3087059573dc63b94ac093b17466 (patch)
tree7f1b2dddabe7373f19a658433a351ef5464ef883 /contrib/sendmail/mail.local
parentc3cd75415d60bc002b20182ffd3383ea9e901a80 (diff)
downloadFreeBSD-src-74c280481f7b3087059573dc63b94ac093b17466.zip
FreeBSD-src-74c280481f7b3087059573dc63b94ac093b17466.tar.gz
Fix conflicts from merge of sendmail 8.11.0.
PR: bin/11552 misc/18512 bin/15088
Diffstat (limited to 'contrib/sendmail/mail.local')
-rw-r--r--contrib/sendmail/mail.local/mail.local.8136
-rw-r--r--contrib/sendmail/mail.local/mail.local.c1556
2 files changed, 1048 insertions, 644 deletions
diff --git a/contrib/sendmail/mail.local/mail.local.8 b/contrib/sendmail/mail.local/mail.local.8
index 541a7ee..246a952 100644
--- a/contrib/sendmail/mail.local/mail.local.8
+++ b/contrib/sendmail/mail.local/mail.local.8
@@ -1,4 +1,5 @@
-.\" Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+.\" All rights reserved.
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -7,46 +8,60 @@
.\" the sendmail distribution.
.\"
.\"
-.\" @(#)mail.local.8 8.7 (Berkeley) 5/19/1998
+.\" $Id: mail.local.8,v 8.14 1999/08/26 15:49:20 ca Exp $
.\"
-.Dd May 19, 1998
-.Dt MAIL.LOCAL 8
-.Os
-.Sh NAME
-.Nm mail.local
-.Nd store mail in a mailbox
-.Sh SYNOPSIS
-.Nm mail.local
-.Op Fl f Ar from
-.Op Fl b
-.Op Fl s
-.Ar user ...
-.Sh DESCRIPTION
-.Nm Mail.local
+.\" $FreeBSD$
+.\"
+.TH MAIL.LOCAL 8 "$Date: 1999/08/26 15:49:20 $"
+.SH NAME
+.B mail.local
+\- store mail in a mailbox
+.SH SYNOPSIS
+.B mail.local
+.RB [ \-7 "] [" \-B "] [" \-d "] [" \-l "] [" \-s "] [" \-f
+.IR from "] " "user ..."
+.SH DESCRIPTION
+.B Mail.local
reads the standard input up to an end-of-file and appends it to each
-.Ar user's
-.Pa mail
-file.
-The
-.Ar user
+.I user's
+.B mail
+file. The
+.I user
must be a valid user name.
-.Pp
+.PP
The options are as follows:
-.Bl -tag -width xxxfrom
-.It Fl f Ar from
-Specify the sender's name.
-.It Fl b
+.TP 1i
+.B \-7
+Do not advertise 8BITMIME support in LMTP mode.
+.TP
+.B \-B
Turn off the attempts to notify the
.Dq biff
service.
-.It Fl s
+.TP
+.B \-b
+Return a permanent error instead of a temporary error
+if a mailbox exceeds quota.
+.TP
+.B \-d
+Specify this is a delivery (for backward compatibility).
+.TP
+.BI \-f " from"
+Specify the sender's name.
+.TP
+.B \-l
+Turn on LMTP mode.
+.TP
+.B \-s
Turn off the
.Xr fsync 2
call that forces the mailbox to be committed to disk before returning a
.Dq success
status.
-.El
-.Pp
+.TP
+.BI \-r " from"
+Specify the sender's name (for backward compatibility).
+.PP
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
@@ -57,47 +72,48 @@ which could be mistaken for a ``From '' delimiter line
(that is,
a line beginning with the five characters
``From '' following a blank line).
-.Pp
+.PP
The mail files are exclusively locked with
-.Xr flock 2
-while mail is appended,
+flock(2)
+while mail is appended,
and a
-.Pa user.lock
-file also is created while the mailbox is locked
+.B user.lock
+file also is created while the mailbox is locked
for compatibility with older MUAs.
-.Pp
-If the ``biff'' service is returned by
-.Xr getservbyname 3 ,
+.PP
+If the ``biff'' service is returned by
+getservbyname(3),
the biff server is notified of delivered mail.
-.Pp
+.PP
The
-.Nm mail.local
+.B mail.local
utility exits 0 on success, and >0 if an error occurs.
-.Sh ENVIRONMENT
-.Bl -tag -width indent
-.It Ev TZ
+.SH ENVIRONMENT
+.IP TZ
Used to set the appropriate time zone on the timestamp.
-.El
-.Sh FILES
-.Bl -tag -width /tmp/local.XXXXXX -compact
-.It Pa /tmp/local.XXXXXX
+.SH FILES
+.PD 0.2v
+.TP 2.2i
+/tmp/local.XXXXXX
temporary files
-.It Pa /var/mail/user
+.TP
+/var/mail/user
user's mailbox directory
-.It Pa /var/mail/user.lock
+.TP
+/var/mail/user.lock
lock file for a user's mailbox
-.El
-.Sh SEE ALSO
-.Xr mail 1 ,
-.Xr flock 2 ,
-.Xr getservbyname 3 ,
-.Xr comsat 8 ,
-.Xr sendmail 8
-.Sh HISTORY
+.PD
+.SH SEE ALSO
+mail(1),
+flock(2),
+getservbyname(3),
+comsat(8),
+sendmail(8)
+.SH HISTORY
A superset of
-.Nm mail.local
+.B mail.local
(handling mailbox reading as well as mail delivery)
-appeared in
-.At v7 .
+appeared in
+Version 7 AT&T UNIX
as the program
-.Nm mail .
+.BR mail .
diff --git a/contrib/sendmail/mail.local/mail.local.c b/contrib/sendmail/mail.local/mail.local.c
index 2a405c5e..03fe02c 100644
--- a/contrib/sendmail/mail.local/mail.local.c
+++ b/contrib/sendmail/mail.local/mail.local.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
+ * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
@@ -11,31 +12,37 @@
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1990, 1993, 1994\n\
+"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
+ All rights reserved.\n\
+ Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
+#endif /* ! lint */
#ifndef lint
-static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/1998";
-#endif /* not lint */
+static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.13 2000/07/18 05:41:38 gshapiro Exp $";
+#endif /* ! lint */
+
+/* $FreeBSD$ */
/*
- * This is not intended to work on System V derived systems
- * such as Solaris or HP-UX, since they use a totally different
- * approach to mailboxes (essentially, they have a setgid program
- * rather than setuid, and they rely on the ability to "give away"
- * files to do their work). IT IS NOT A BUG that this doesn't
- * work on such architectures.
- */
+** This is not intended to work on System V derived systems
+** such as Solaris or HP-UX, since they use a totally different
+** approach to mailboxes (essentially, they have a setgid program
+** rather than setuid, and they rely on the ability to "give away"
+** files to do their work). IT IS NOT A BUG that this doesn't
+** work on such architectures.
+*/
+
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
+#include <arpa/nameser.h>
-#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
@@ -47,73 +54,100 @@ static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/1998";
#include <unistd.h>
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
-#endif
+#endif /* EX_OK */
#include <sysexits.h>
#include <ctype.h>
+#ifndef __P
+# include "sendmail/cdefs.h"
+#endif /* ! __P */
+#include "sendmail/useful.h"
+
+extern size_t strlcpy __P((char *, const char *, size_t));
+extern size_t strlcat __P((char *, const char *, size_t));
+
+#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
+# ifndef HASSTRERROR
+# define HASSTRERROR 1
+# endif /* ! HASSTRERROR */
+#endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
+ defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+
+#include "sendmail/errstring.h"
+
+
+#ifndef LOCKTO_RM
+# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
+#endif /* LOCKTO_RM */
+#ifndef LOCKTO_GLOB
+# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
+#endif /* LOCKTO_GLOB */
+
#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
+# include <stdarg.h>
+# define REALLOC(ptr, size) realloc(ptr, size)
+#else /* __STDC__ */
+# include <varargs.h>
+/* define a realloc() which works for NULL pointers */
+# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
+#endif /* __STDC__ */
#if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
# define USE_LOCKF 1
# define USE_SETEUID 1
-# define _PATH_MAILDIR "/var/mail"
-#endif
+# define _PATH_MAILDIR "/var/mail"
+#endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
-#if (defined(sun) && !defined(__svr4__)) && !defined(__SVR4)
-# ifdef __dead
-# undef __dead
-# define __dead
-# endif
-#endif
+#ifdef NCR_MP_RAS3
+# define USE_LOCKF 1
+# define HASSNPRINTF 1
+# define _PATH_MAILDIR "/var/mail"
+#endif /* NCR_MP_RAS3 */
#if defined(_AIX)
# define USE_LOCKF 1
# define USE_SETEUID 1
# define USE_VSYSLOG 0
-#endif
+#endif /* defined(_AIX) */
#if defined(__hpux)
# define USE_LOCKF 1
# define USE_SETRESUID 1
# define USE_VSYSLOG 0
-# ifdef __dead
-# undef __dead
-# define __dead
-# endif
-#endif
+#endif /* defined(__hpux) */
+
+#ifdef DGUX
+# define HASSNPRINTF 1
+# define USE_LOCKF 1
+# define USE_VSYSLOG 0
+#endif /* DGUX */
#if defined(_CRAY)
# if !defined(MAXPATHLEN)
# define MAXPATHLEN PATHSIZE
-# endif
+# endif /* !defined(MAXPATHLEN) */
# define USE_VSYSLOG 0
-# define _PATH_MAILDIR "/usr/spool/mail"
-#endif
+# define _PATH_MAILDIR "/usr/spool/mail"
+#endif /* defined(_CRAY) */
#if defined(ultrix)
# define USE_VSYSLOG 0
-#endif
+#endif /* defined(ultrix) */
#if defined(__osf__)
# define USE_VSYSLOG 0
-#endif
+#endif /* defined(__osf__) */
#if defined(NeXT) && !defined(__APPLE__)
# include <libc.h>
-# define _PATH_MAILDIR "/usr/spool/mail"
-# define __dead /* empty */
+# define _PATH_MAILDIR "/usr/spool/mail"
# define S_IRUSR S_IREAD
# define S_IWUSR S_IWRITE
-#endif
+#endif /* defined(NeXT) && !defined(__APPLE__) */
#if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# include <paths.h>
-# define HASSTRERROR 1 /* has strerror(3) */
-#endif
+# include <paths.h>
+#endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
/*
* If you don't have flock, you could try using lockf instead.
@@ -121,119 +155,126 @@ static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/1998";
#ifdef USE_LOCKF
# define flock(a, b) lockf(a, b, 0)
+# ifdef LOCK_EX
+# undef LOCK_EX
+# endif /* LOCK_EX */
# define LOCK_EX F_LOCK
-#endif
+#endif /* USE_LOCKF */
#ifndef USE_VSYSLOG
# define USE_VSYSLOG 1
-#endif
+#endif /* ! USE_VSYSLOG */
#ifndef LOCK_EX
# include <sys/file.h>
-#endif
+#endif /* ! LOCK_EX */
#if defined(BSD4_4) || defined(__GLIBC__)
-# include "pathnames.h"
-#endif
-
-#ifndef __P
-# ifdef __STDC__
-# define __P(protos) protos
-# else
-# define __P(protos) ()
-# define const
-# endif
-#endif
-#ifndef __dead
-# if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__)
-# define __dead __volatile
-# else
-# define __dead
-# endif
-#endif
+# include <paths.h>
+# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
+#endif /* defined(BSD4_4) || defined(__GLIBC__) */
#ifdef BSD4_4
# define HAS_ST_GEN 1
-#else
+#else /* BSD4_4 */
# ifndef _BSD_VA_LIST_
# define _BSD_VA_LIST_ va_list
-# endif
-#endif
+# endif /* ! _BSD_VA_LIST_ */
+#endif /* BSD4_4 */
#if defined(BSD4_4) || defined(linux)
# define HASSNPRINTF 1
-#else
+#else /* defined(BSD4_4) || defined(linux) */
# ifndef ultrix
extern FILE *fdopen __P((int, const char *));
-# endif
-#endif
+# endif /* ! ultrix */
+#endif /* defined(BSD4_4) || defined(linux) */
+
+#if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
+# define CONTENTLENGTH 1 /* Needs the Content-Length header */
+#endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
#if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-#endif
+#endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
+
+#ifdef HPUX11
+# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
+#endif /* HPUX11 */
+
+#if _AIX4 >= 40300
+# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
+#endif /* _AIX4 >= 40300 */
#if !HASSNPRINTF
extern int snprintf __P((char *, size_t, const char *, ...));
# ifndef _CRAY
extern int vsnprintf __P((char *, size_t, const char *, ...));
-# endif
-#endif
-
-#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__)
-# ifndef HASSTRERROR
-# define HASSTRERROR 1
-# endif
-#endif
-
-#if !HASSTRERROR
-extern char *strerror __P((int));
-#endif
+# endif /* ! _CRAY */
+#endif /* !HASSNPRINTF */
/*
- * If you don't have setreuid, and you have saved uids, and you have
- * a seteuid() call that doesn't try to emulate using setuid(), then
- * you can try defining USE_SETEUID.
- */
+** If you don't have setreuid, and you have saved uids, and you have
+** a seteuid() call that doesn't try to emulate using setuid(), then
+** you can try defining USE_SETEUID.
+*/
#ifdef USE_SETEUID
# define setreuid(r, e) seteuid(e)
-#endif
+#endif /* USE_SETEUID */
/*
- * And of course on hpux you have setresuid()
- */
+** And of course on hpux you have setresuid()
+*/
#ifdef USE_SETRESUID
# define setreuid(r, e) setresuid(-1, e, -1)
-#endif
+#endif /* USE_SETRESUID */
#ifndef _PATH_LOCTMP
-# define _PATH_LOCTMP "/tmp/local.XXXXXX"
-#endif
-#ifndef _PATH_MAILDIR
-# define _PATH_MAILDIR "/var/spool/mail"
-#endif
+# define _PATH_LOCTMP "/var/tmp/local.XXXXXX"
+#endif /* ! _PATH_LOCTMP */
+# ifndef _PATH_MAILDIR
+# define _PATH_MAILDIR "/var/spool/mail"
+# endif /* ! _PATH_MAILDIR */
#ifndef S_ISREG
# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
-#endif
+#endif /* ! S_ISREG */
+
+#ifdef MAILLOCK
+# include <maillock.h>
+#endif /* MAILLOCK */
+
+#ifndef INADDRSZ
+# define INADDRSZ 4 /* size of an IPv4 address in bytes */
+#endif /* ! INADDRSZ */
#ifndef MAILER_DAEMON
# define MAILER_DAEMON "MAILER-DAEMON"
-#endif
-
-int eval = EX_OK; /* sysexits.h error value. */
-int lmtpmode = 0;
-u_char tTdvect[100];
-
-void deliver __P((int, char *, int, int));
-void e_to_sys __P((int));
-void notifybiff __P((char *));
-int store __P((char *, int));
-void usage __P((void));
-void vwarn __P((const char *, _BSD_VA_LIST_));
-void lockmbox __P((char *));
-void unlockmbox __P((void));
-void mailerr __P((const char *, const char *, ...));
-void dolmtp __P((int, int));
+#endif /* ! MAILER_DAEMON */
+
+#ifdef CONTENTLENGTH
+char ContentHdr[40] = "Content-Length: ";
+off_t HeaderLength;
+off_t BodyLength;
+#endif /* CONTENTLENGTH */
+
+bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */
+int ExitVal = EX_OK; /* sysexits.h error value. */
+bool LMTPMode = FALSE;
+bool bouncequota = FALSE; /* permanent error when over quota */
+bool nobiff = FALSE;
+bool nofsync = FALSE;
+
+void deliver __P((int, char *, bool));
+int e_to_sys __P((int));
+void notifybiff __P((char *));
+int store __P((char *, int));
+void usage __P((void));
+void vwarn __P((const char *, _BSD_VA_LIST_));
+int lockmbox __P((char *));
+void unlockmbox __P((void));
+void mailerr __P((const char *, const char *, ...));
+
int
main(argc, argv)
@@ -241,11 +282,13 @@ main(argc, argv)
char *argv[];
{
struct passwd *pw;
- int ch, fd, nobiff, nofsync;
+ int ch, fd;
uid_t uid;
char *from;
extern char *optarg;
extern int optind;
+ extern void dolmtp __P((bool));
+
/* make sure we have some open file descriptors */
for (fd = 10; fd < 30; fd++)
@@ -254,79 +297,103 @@ main(argc, argv)
/* use a reasonable umask */
(void) umask(0077);
-#ifdef LOG_MAIL
+# ifdef LOG_MAIL
openlog("mail.local", 0, LOG_MAIL);
-#else
+# else /* LOG_MAIL */
openlog("mail.local", 0);
-#endif
+# endif /* LOG_MAIL */
from = NULL;
- nobiff = 0;
- nofsync = 0;
- while ((ch = getopt(argc, argv, "bdf:r:ls")) != -1)
- switch(ch) {
- case 'b':
- nobiff++;
+ while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1)
+ {
+ switch(ch)
+ {
+ case '7': /* Do not advertise 8BITMIME */
+ EightBitMime = FALSE;
+ break;
+
+ case 'B':
+ nobiff = TRUE;
+ break;
+
+ case 'b': /* bounce mail when over quota. */
+ bouncequota = TRUE;
break;
- case 'd': /* Backward compatible. */
+
+ case 'd': /* Backward compatible. */
break;
- case 'f':
- case 'r': /* Backward compatible. */
- if (from != NULL) {
+
+ case 'f':
+ case 'r': /* Backward compatible. */
+ if (from != NULL)
+ {
mailerr(NULL, "multiple -f options");
usage();
}
from = optarg;
break;
- case 'l':
- lmtpmode++;
+
+ case 'l':
+ LMTPMode = TRUE;
break;
- case 's':
+
+ case 's':
nofsync++;
break;
- case '?':
- default:
+
+ case '?':
+ default:
usage();
}
+ }
argc -= optind;
argv += optind;
- if (lmtpmode)
- dolmtp(nobiff, nofsync);
+ /* initialize biff structures */
+ if (!nobiff)
+ notifybiff(NULL);
+
+ if (LMTPMode)
+ dolmtp(bouncequota);
- if (!*argv)
+ if (*argv == '\0')
usage();
/*
- * 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.
- */
+ ** 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 : "???";
+
+ if (from == NULL && ((from = getlogin()) == NULL ||
+ (pw = getpwnam(from)) == NULL ||
+ pw->pw_uid != uid))
+ from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
/*
- * There is no way to distinguish the error status of one delivery
- * from the rest of the deliveries. So, if we failed hard on one
- * or more deliveries, but had no failures on any of the others, we
- * return a hard failure. If we failed temporarily on one or more
- * deliveries, we return a temporary failure regardless of the other
- * failures. This results in the delivery being reattempted later
- * at the expense of repeated failures and multiple deliveries.
- */
+ ** There is no way to distinguish the error status of one delivery
+ ** from the rest of the deliveries. So, if we failed hard on one
+ ** or more deliveries, but had no failures on any of the others, we
+ ** return a hard failure. If we failed temporarily on one or more
+ ** deliveries, we return a temporary failure regardless of the other
+ ** failures. This results in the delivery being reattempted later
+ ** at the expense of repeated failures and multiple deliveries.
+ */
for (fd = store(from, 0); *argv; ++argv)
- deliver(fd, *argv, nobiff, nofsync);
- exit(eval);
+ deliver(fd, *argv, bouncequota);
+ exit(ExitVal);
+ /* NOTREACHED */
+ return ExitVal;
}
char *
-parseaddr(s)
+parseaddr(s, rcpt)
char *s;
+ bool rcpt;
{
char *p;
- int len;
+ int l;
if (*s++ != '<')
return NULL;
@@ -334,94 +401,79 @@ parseaddr(s)
p = s;
/* at-domain-list */
- while (*p == '@') {
+ while (*p == '@')
+ {
p++;
- if (*p == '[') {
+ while (*p != ',' && *p != ':' && *p != '\0')
p++;
- while (isascii(*p) &&
- (isalnum(*p) || *p == '.' ||
- *p == '-' || *p == ':'))
- p++;
- if (*p++ != ']')
- return NULL;
- } else {
- while ((isascii(*p) && isalnum(*p)) ||
- strchr(".-_", *p))
- p++;
- }
- if (*p == ',' && p[1] == '@')
- p++;
- else if (*p == ':' && p[1] != '@')
- p++;
- else
+ if (*p == '\0')
return NULL;
+
+ /* Skip over , or : */
+ p++;
}
s = p;
/* local-part */
- if (*p == '\"') {
- p++;
- while (*p && *p != '\"') {
- if (*p == '\\') {
- if (!*++p)
- return NULL;
- }
- p++;
- }
- if (!*p++)
- return NULL;
- } else {
- while (*p && *p != '@' && *p != '>') {
- if (*p == '\\') {
- if (!*++p)
- return NULL;
- } else {
- if (*p <= ' ' || (*p & 128) ||
- strchr("<>()[]\\,;:\"", *p))
+ while (*p != '\0' && *p != '@' && *p != '>')
+ {
+ if (*p == '\\')
+ {
+ if (*++p == '\0')
return NULL;
- }
+ }
+ else if (*p == '\"')
+ {
p++;
+ while (*p != '\0' && *p != '\"')
+ {
+ if (*p == '\\')
+ {
+ if (*++p == '\0')
+ return NULL;
+ }
+ p++;
+ }
+ if (*p == '\0' || *(p + 1) == '\0')
+ return NULL;
}
+ /* +detail ? */
+ if (*p == '+' && rcpt)
+ *p = '\0';
+ p++;
}
/* @domain */
- if (*p == '@') {
- p++;
- if (*p == '[') {
+ if (*p == '@')
+ {
+ if (rcpt)
+ *p++ = '\0';
+ while (*p != '\0' && *p != '>')
p++;
- while (isascii(*p) &&
- (isalnum(*p) || *p == '.' ||
- *p == '-' || *p == ':'))
- p++;
- if (*p++ != ']')
- return NULL;
- } else {
- while ((isascii(*p) && isalnum(*p)) ||
- strchr(".-_", *p))
- p++;
- }
}
- if (*p++ != '>')
+ if (*p != '>')
return NULL;
- if (*p && *p != ' ')
+ else
+ *p = '\0';
+ p++;
+
+ if (*p != '\0' && *p != ' ')
return NULL;
- len = p - s - 1;
- if (*s == '\0' || len <= 0)
- {
+
+ if (*s == '\0')
s = MAILER_DAEMON;
- len = strlen(s);
- }
- p = malloc(len + 1);
- if (p == NULL) {
+ l = strlen(s) + 1;
+ p = malloc(l);
+ if (p == NULL)
+ {
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
- strncpy(p, s, len);
- p[len] = '\0';
+ (void) strlcpy(p, s, l);
return p;
}
@@ -429,51 +481,51 @@ char *
process_recipient(addr)
char *addr;
{
- if (getpwnam(addr) == NULL) {
+ if (getpwnam(addr) == NULL)
return "550 5.1.1 user unknown";
- }
-
return NULL;
}
-
#define RCPT_GROW 30
void
-dolmtp(nobiff, nofsync)
- int nobiff, nofsync;
+dolmtp(bouncequota)
+ bool bouncequota;
{
char *return_path = NULL;
char **rcpt_addr = NULL;
int rcpt_num = 0;
int rcpt_alloc = 0;
- char myhostname[1024];
- char buf[4096];
+ bool gotlhlo = FALSE;
char *err;
int msgfd;
char *p;
int i;
+ char myhostname[1024];
+ char buf[4096];
- gethostname(myhostname, sizeof myhostname - 1);
+ (void) gethostname(myhostname, sizeof myhostname - 1);
printf("220 %s LMTP ready\r\n", myhostname);
- for (;;) {
- fflush(stdout);
- if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
+ for (;;)
+ {
+ (void) fflush(stdout);
+ if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
exit(EX_OK);
- }
p = buf + strlen(buf) - 1;
if (p >= buf && *p == '\n')
*p-- = '\0';
if (p >= buf && *p == '\r')
*p-- = '\0';
- switch (buf[0]) {
-
- case 'd':
- case 'D':
- if (strcasecmp(buf, "data") == 0) {
- if (rcpt_num == 0) {
+ switch (buf[0])
+ {
+ case 'd':
+ case 'D':
+ if (strcasecmp(buf, "data") == 0)
+ {
+ if (rcpt_num == 0)
+ {
printf("503 5.5.1 No recipients\r\n");
continue;
}
@@ -481,36 +533,56 @@ dolmtp(nobiff, nofsync)
if (msgfd == -1)
continue;
- for (i = 0; i < rcpt_num; i++) {
+ for (i = 0; i < rcpt_num; i++)
+ {
p = strchr(rcpt_addr[i], '+');
if (p != NULL)
*p++ = '\0';
- deliver(msgfd, rcpt_addr[i], nobiff,
- nofsync);
+ deliver(msgfd, rcpt_addr[i], bouncequota);
}
- close(msgfd);
+ (void) close(msgfd);
goto rset;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'l':
- case 'L':
- if (strncasecmp(buf, "lhlo ", 5) == 0) {
- printf("250-%s\r\n250-8BITMIME\r\n250-ENHANCEDSTATUSCODES\r\n250 PIPELINING\r\n",
- myhostname);
+ case 'l':
+ case 'L':
+ if (strncasecmp(buf, "lhlo ", 5) == 0)
+ {
+ /* check for duplicate per RFC 1651 4.2 */
+ if (gotlhlo)
+ {
+ printf("503 %s Duplicate LHLO\r\n",
+ myhostname);
+ continue;
+ }
+ gotlhlo = TRUE;
+ printf("250-%s\r\n", myhostname);
+ if (EightBitMime)
+ printf("250-8BITMIME\r\n");
+ printf("250-ENHANCEDSTATUSCODES\r\n");
+ printf("250 PIPELINING\r\n");
continue;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'm':
- case 'M':
- if (strncasecmp(buf, "mail ", 5) == 0) {
- if (return_path != NULL) {
+ case 'm':
+ case 'M':
+ if (strncasecmp(buf, "mail ", 5) == 0)
+ {
+ if (return_path != NULL)
+ {
printf("503 5.5.1 Nested MAIL command\r\n");
continue;
}
if (strncasecmp(buf+5, "from:", 5) != 0 ||
- ((return_path = parseaddr(buf+10)) == NULL)) {
+ ((return_path = parseaddr(buf + 10,
+ FALSE)) == NULL))
+ {
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
@@ -518,46 +590,62 @@ dolmtp(nobiff, nofsync)
continue;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'n':
- case 'N':
- if (strcasecmp(buf, "noop") == 0) {
+ case 'n':
+ case 'N':
+ if (strcasecmp(buf, "noop") == 0)
+ {
printf("250 2.0.0 ok\r\n");
continue;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'q':
- case 'Q':
- if (strcasecmp(buf, "quit") == 0) {
+ case 'q':
+ case 'Q':
+ if (strcasecmp(buf, "quit") == 0)
+ {
printf("221 2.0.0 bye\r\n");
exit(EX_OK);
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'r':
- case 'R':
- if (strncasecmp(buf, "rcpt ", 5) == 0) {
- if (return_path == NULL) {
+ case 'r':
+ case 'R':
+ if (strncasecmp(buf, "rcpt ", 5) == 0)
+ {
+ if (return_path == NULL)
+ {
printf("503 5.5.1 Need MAIL command\r\n");
continue;
}
- if (rcpt_num >= rcpt_alloc) {
+ if (rcpt_num >= rcpt_alloc)
+ {
rcpt_alloc += RCPT_GROW;
rcpt_addr = (char **)
- realloc((char *)rcpt_addr,
- rcpt_alloc * sizeof(char **));
- if (rcpt_addr == NULL) {
+ REALLOC((char *)rcpt_addr,
+ rcpt_alloc *
+ sizeof(char **));
+ if (rcpt_addr == NULL)
+ {
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
}
- if (strncasecmp(buf+5, "to:", 3) != 0 ||
- ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) {
+ if (strncasecmp(buf + 5, "to:", 3) != 0 ||
+ ((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
+ TRUE)) == NULL))
+ {
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
- if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) {
+ if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL)
+ {
printf("%s\r\n", err);
continue;
}
@@ -565,32 +653,39 @@ dolmtp(nobiff, nofsync)
printf("250 2.1.5 ok\r\n");
continue;
}
- else if (strcasecmp(buf, "rset") == 0) {
+ else if (strcasecmp(buf, "rset") == 0)
+ {
printf("250 2.0.0 ok\r\n");
- rset:
- while (rcpt_num) {
+rset:
+ while (rcpt_num)
free(rcpt_addr[--rcpt_num]);
- }
if (return_path != NULL)
free(return_path);
return_path = NULL;
continue;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- case 'v':
- case 'V':
- if (strncasecmp(buf, "vrfy ", 5) == 0) {
+ case 'v':
+ case 'V':
+ if (strncasecmp(buf, "vrfy ", 5) == 0)
+ {
printf("252 2.3.3 try RCPT to attempt delivery\r\n");
continue;
}
goto syntaxerr;
+ /* NOTREACHED */
+ break;
- default:
+ default:
syntaxerr:
printf("500 5.5.2 Syntax error\r\n");
continue;
+ /* NOTREACHED */
+ break;
}
}
}
@@ -602,135 +697,258 @@ store(from, lmtprcpts)
{
FILE *fp = NULL;
time_t tval;
- int fd, eline;
+ bool eline;
+ bool fullline = TRUE; /* current line is terminated */
+ bool prevfl; /* previous line was terminated */
char line[2048];
+ int fd;
char tmpbuf[sizeof _PATH_LOCTMP + 1];
- strcpy(tmpbuf, _PATH_LOCTMP);
- if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
- if (lmtprcpts) {
+ (void) umask(0077);
+ (void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
+ if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL)
+ {
+ if (lmtprcpts)
+ {
printf("451 4.3.0 unable to open temporary file\r\n");
return -1;
- } else {
+ }
+ else
+ {
mailerr("451 4.3.0", "unable to open temporary file");
- exit(eval);
+ exit(ExitVal);
}
}
- (void)unlink(tmpbuf);
+ (void) unlink(tmpbuf);
- if (lmtpmode) {
+ if (LMTPMode)
+ {
printf("354 go ahead\r\n");
- fflush(stdout);
+ (void) fflush(stdout);
}
- (void)time(&tval);
- (void)fprintf(fp, "From %s %s", from, ctime(&tval));
+ (void) time(&tval);
+ (void) fprintf(fp, "From %s %s", from, ctime(&tval));
+
+#ifdef CONTENTLENGTH
+ HeaderLength = 0;
+ BodyLength = -1;
+#endif /* CONTENTLENGTH */
line[0] = '\0';
- for (eline = 1; fgets(line, sizeof(line), stdin);) {
- size_t line_len = strlen(line);
+ eline = TRUE;
+ while (fgets(line, sizeof(line), stdin) != (char *)NULL)
+ {
+ size_t line_len = 0;
+ int peek;
- if (line_len >= 2 &&
- line[line_len - 2] == '\r' &&
- line[line_len - 1] == '\n') {
- strcpy(line + line_len - 2, "\n");
- }
- if (lmtprcpts && line[0] == '.') {
- char *src = line + 1, *dest = line;
+ prevfl = fullline; /* preserve state of previous line */
+ while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
+ line_len++;
+ line_len++;
- if (line[1] == '\n')
+ /* Check for dot-stuffing */
+ if (prevfl && lmtprcpts && line[0] == '.')
+ {
+ if (line[1] == '\n' ||
+ (line[1] == '\r' && line[2] == '\n'))
goto lmtpdot;
- while (*src != '\0')
- *dest++ = *src++;
- *dest = '\0';
+ memcpy(line, line + 1, line_len);
+ line_len--;
}
- if (line[0] == '\n')
- eline = 1;
- else {
+
+ /* Check to see if we have the full line from fgets() */
+ fullline = FALSE;
+ if (line_len > 0)
+ {
+ if (line[line_len - 1] == '\n')
+ {
+ if (line_len >= 2 &&
+ line[line_len - 2] == '\r')
+ {
+ line[line_len - 2] = '\n';
+ line[line_len - 1] = '\0';
+ line_len--;
+ }
+ fullline = TRUE;
+ }
+ else if (line[line_len - 1] == '\r')
+ {
+ /* Did we just miss the CRLF? */
+ peek = fgetc(stdin);
+ if (peek == '\n')
+ {
+ line[line_len - 1] = '\n';
+ fullline = TRUE;
+ }
+ else
+ (void) ungetc(peek, stdin);
+ }
+ }
+ else
+ fullline = TRUE;
+
+#ifdef CONTENTLENGTH
+ if (prevfl && line[0] == '\n' && HeaderLength == 0)
+ {
+ eline = FALSE;
+ HeaderLength = ftell(fp);
+ if (HeaderLength <= 0)
+ {
+ /*
+ ** shouldn't happen, unless ftell() is
+ ** badly broken
+ */
+
+ HeaderLength = -1;
+ }
+ }
+#else /* CONTENTLENGTH */
+ if (prevfl && line[0] == '\n')
+ eline = TRUE;
+#endif /* CONTENTLENGTH */
+ else
+ {
if (eline && line[0] == 'F' &&
!memcmp(line, "From ", 5))
(void)putc('>', fp);
- eline = 0;
+ eline = FALSE;
+#ifdef CONTENTLENGTH
+ /* discard existing "Content-Length:" headers */
+ if (prevfl && HeaderLength == 0 &&
+ (line[0] == 'C' || line[0] == 'c') &&
+ strncasecmp(line, ContentHdr, 15) == 0)
+ {
+ /*
+ ** be paranoid: clear the line
+ ** so no "wrong matches" may occur later
+ */
+ line[0] = '\0';
+ continue;
+ }
+#endif /* CONTENTLENGTH */
+
}
- (void)fprintf(fp, "%s", line);
- if (ferror(fp)) {
- if (lmtprcpts) {
- while (lmtprcpts--) {
+ (void) fwrite(line, sizeof(char), line_len, fp);
+ if (ferror(fp))
+ {
+ if (lmtprcpts)
+ {
+ while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
- }
- fclose(fp);
+ (void) fclose(fp);
return -1;
- } else {
+ }
+ else
+ {
mailerr("451 4.3.0",
"temporary file write error");
- fclose(fp);
- exit(eval);
+ (void) fclose(fp);
+ exit(ExitVal);
}
}
}
- if (lmtprcpts) {
+ if (lmtprcpts)
+ {
/* Got a premature EOF -- toss message and exit */
exit(EX_OK);
}
/* If message not newline terminated, need an extra. */
if (strchr(line, '\n') == NULL)
- (void)putc('\n', fp);
+ (void) putc('\n', fp);
lmtpdot:
+#ifdef CONTENTLENGTH
+ BodyLength = ftell(fp);
+ if (HeaderLength == 0 && BodyLength > 0) /* empty body */
+ {
+ HeaderLength = BodyLength;
+ BodyLength = 0;
+ }
+ else
+ BodyLength = BodyLength - HeaderLength - 1 ;
+
+ if (HeaderLength > 0 && BodyLength >= 0)
+ {
+ extern char *quad_to_string();
+
+ if (sizeof BodyLength > sizeof(long))
+ snprintf(line, sizeof line, "%s\n",
+ quad_to_string(BodyLength));
+ else
+ snprintf(line, sizeof line, "%ld\n", (long) BodyLength);
+ strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16);
+ }
+ else
+ BodyLength = -1; /* Something is wrong here */
+#endif /* CONTENTLENGTH */
+
/* Output a newline; note, empty messages are allowed. */
- (void)putc('\n', fp);
+ (void) putc('\n', fp);
- if (fflush(fp) == EOF || ferror(fp)) {
- if (lmtprcpts) {
- while (lmtprcpts--) {
+ if (fflush(fp) == EOF || ferror(fp) != 0)
+ {
+ if (lmtprcpts)
+ {
+ while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
- }
- fclose(fp);
+ (void) fclose(fp);
return -1;
- } else {
+ }
+ else
+ {
mailerr("451 4.3.0", "temporary file write error");
- fclose(fp);
- exit(eval);
+ (void) fclose(fp);
+ exit(ExitVal);
}
}
- return (fd);
+ return fd;
}
void
-deliver(fd, name, nobiff, nofsync)
+deliver(fd, name, bouncequota)
int fd;
char *name;
- int nobiff, nofsync;
+ bool bouncequota;
{
- struct stat fsb, sb;
+ struct stat fsb;
+ struct stat sb;
struct passwd *pw;
- int mbfd, nr, nw, off;
+ char path[MAXPATHLEN];
+ int mbfd, nr = 0, nw, off;
char *p;
- char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
off_t curoff;
+#ifdef CONTENTLENGTH
+ off_t headerbytes;
+ int readamount;
+#endif /* CONTENTLENGTH */
+ char biffmsg[100], buf[8*1024];
extern char *quad_to_string();
+
/*
- * Disallow delivery to unknown names -- special mailboxes can be
- * handled in the sendmail aliases file.
- */
- if ((pw = getpwnam(name)) == NULL) {
- if (eval != EX_TEMPFAIL)
- eval = EX_UNAVAILABLE;
- if (lmtpmode) {
- if (eval == EX_TEMPFAIL) {
+ ** Disallow delivery to unknown names -- special mailboxes can be
+ ** handled in the sendmail aliases file.
+ */
+ if ((pw = getpwnam(name)) == NULL)
+ {
+ if (ExitVal != EX_TEMPFAIL)
+ ExitVal = EX_UNAVAILABLE;
+ if (LMTPMode)
+ {
+ if (ExitVal == EX_TEMPFAIL)
printf("451 4.3.0 cannot lookup name: %s\r\n", name);
- } else {
+ else
printf("550 5.1.1 unknown name: %s\r\n", name);
- }
}
- else {
+ else
+ {
char *errcode = NULL;
- if (eval == EX_TEMPFAIL)
+ if (ExitVal == EX_TEMPFAIL)
errcode = "451 4.3.0";
else
errcode = "550 5.1.1";
@@ -741,12 +959,12 @@ deliver(fd, name, nobiff, nofsync)
endpwent();
/*
- * Keep name reasonably short to avoid buffer overruns.
- * This isn't necessary on BSD because of the proper
- * definition of snprintf(), but it can cause problems
- * on other systems.
- * Also, clear out any bogus characters.
- */
+ ** Keep name reasonably short to avoid buffer overruns.
+ ** This isn't necessary on BSD because of the proper
+ ** definition of snprintf(), but it can cause problems
+ ** on other systems.
+ ** Also, clear out any bogus characters.
+ */
if (strlen(name) > 40)
name[40] = '\0';
@@ -758,89 +976,140 @@ deliver(fd, name, nobiff, nofsync)
*p = '.';
}
- (void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
+
+ (void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
+
/*
- * If the mailbox is linked or a symlink, fail. There's an obvious
- * race here, that the file was replaced with a symbolic link after
- * the lstat returned, but before the open. We attempt to detect
- * this by comparing the original stat information and information
- * returned by an fstat of the file descriptor returned by the open.
- *
- * NB: this is a symptom of a larger problem, that the mail spooling
- * directory is writeable by the wrong users. If that directory is
- * writeable, system security is compromised for other reasons, and
- * it cannot be fixed here.
- *
- * If we created the mailbox, set the owner/group. If that fails,
- * just return. Another process may have already opened it, so we
- * can't unlink it. Historically, binmail set the owner/group at
- * each mail delivery. We no longer do this, assuming that if the
- * ownership or permissions were changed there was a reason.
- *
- * XXX
- * open(2) should support flock'ing the file.
- */
+ ** If the mailbox is linked or a symlink, fail. There's an obvious
+ ** race here, that the file was replaced with a symbolic link after
+ ** the lstat returned, but before the open. We attempt to detect
+ ** this by comparing the original stat information and information
+ ** returned by an fstat of the file descriptor returned by the open.
+ **
+ ** NB: this is a symptom of a larger problem, that the mail spooling
+ ** directory is writeable by the wrong users. If that directory is
+ ** writeable, system security is compromised for other reasons, and
+ ** it cannot be fixed here.
+ **
+ ** If we created the mailbox, set the owner/group. If that fails,
+ ** just return. Another process may have already opened it, so we
+ ** can't unlink it. Historically, binmail set the owner/group at
+ ** each mail delivery. We no longer do this, assuming that if the
+ ** ownership or permissions were changed there was a reason.
+ **
+ ** XXX
+ ** open(2) should support flock'ing the file.
+ */
+
tryagain:
- lockmbox(path);
- if (lstat(path, &sb) < 0) {
- mbfd = open(path,
- O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
+#ifdef MAILLOCK
+ p = name;
+#else /* MAILLOCK */
+ p = path;
+#endif /* MAILLOCK */
+ if ((off = lockmbox(p)) != 0)
+ {
+ if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
+ {
+ ExitVal = EX_TEMPFAIL;
+ mailerr("451 4.3.0",
+ "lockmailbox %s failed; error code %d %s",
+ p, off, errno > 0 ? errstring(errno) : "");
+ }
+ else
+ {
+ mailerr("551 5.3.0",
+ "lockmailbox %s failed; error code %d %s",
+ p, off, errno > 0 ? errstring(errno) : "");
+ }
+ return;
+ }
+
+ if (lstat(path, &sb) < 0)
+ {
+ int save_errno;
+ int mode = S_IRUSR|S_IWUSR;
+ gid_t gid = pw->pw_gid;
+
+#ifdef MAILGID
+ (void) umask(0007);
+ gid = MAILGID;
+ mode |= S_IRGRP|S_IWGRP;
+#endif /* MAILGID */
+
+ mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, mode);
+
+ save_errno = errno;
+
if (lstat(path, &sb) < 0)
{
- eval = EX_CANTCREAT;
+ ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0",
"%s: lstat: file changed after open", path);
goto err1;
}
else
sb.st_uid = pw->pw_uid;
- if (mbfd == -1) {
- if (errno == EEXIST)
+ if (mbfd == -1)
+ {
+ if (save_errno == EEXIST)
goto tryagain;
- } else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) {
+ }
+ else if (fchown(mbfd, pw->pw_uid, gid) < 0)
+ {
mailerr("451 4.3.0", "chown %u.%u: %s",
- pw->pw_uid, pw->pw_gid, name);
+ pw->pw_uid, gid, name);
goto err1;
}
- } else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
+ }
+ else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode))
+ {
mailerr("550 5.2.0", "%s: irregular file", path);
goto err0;
- } else if (sb.st_uid != pw->pw_uid) {
- eval = EX_CANTCREAT;
+ }
+ else if (sb.st_uid != pw->pw_uid)
+ {
+ ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0", "%s: wrong ownership (%d)",
- path, sb.st_uid);
+ path, sb.st_uid);
goto err0;
- } else {
- mbfd = open(path, O_APPEND|O_WRONLY, 0);
}
+ else
+ mbfd = open(path, O_APPEND|O_WRONLY, 0);
- if (mbfd == -1) {
- mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
+ if (mbfd == -1)
+ {
+ mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err0;
- } else if (fstat(mbfd, &fsb) < 0 ||
- fsb.st_nlink != 1 ||
- sb.st_nlink != 1 ||
- !S_ISREG(fsb.st_mode) ||
- sb.st_dev != fsb.st_dev ||
- sb.st_ino != fsb.st_ino ||
+ }
+ else if (fstat(mbfd, &fsb) < 0 ||
+ fsb.st_nlink != 1 ||
+ sb.st_nlink != 1 ||
+ !S_ISREG(fsb.st_mode) ||
+ sb.st_dev != fsb.st_dev ||
+ sb.st_ino != fsb.st_ino ||
#if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */
- sb.st_gen != fsb.st_gen ||
-#endif
- sb.st_uid != fsb.st_uid) {
- eval = EX_TEMPFAIL;
+ sb.st_gen != fsb.st_gen ||
+#endif /* HAS_ST_GEN && 0 */
+ sb.st_uid != fsb.st_uid)
+ {
+ ExitVal = EX_TEMPFAIL;
mailerr("550 5.2.0", "%s: fstat: file changed after open",
path);
goto err1;
}
+
/* Wait until we can get a lock on the file. */
- if (flock(mbfd, LOCK_EX)) {
- mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
+ if (flock(mbfd, LOCK_EX) < 0)
+ {
+ mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err1;
}
- if (!nobiff) {
+ if (!nobiff)
+ {
/* Get the starting offset of the new message for biff. */
curoff = lseek(mbfd, (off_t)0, SEEK_END);
if (sizeof curoff > sizeof(long))
@@ -852,193 +1121,314 @@ tryagain:
}
/* Copy the message into the file. */
- if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
+ {
mailerr("450 4.2.0", "temporary file: %s",
- strerror(errno));
+ errstring(errno));
goto err1;
}
- if (setreuid(0, pw->pw_uid) < 0) {
+ if (setreuid(0, pw->pw_uid) < 0)
+ {
mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
- pw->pw_uid, strerror(errno), getuid(), geteuid());
+ pw->pw_uid, errstring(errno), getuid(), geteuid());
goto err1;
}
#ifdef DEBUG
- printf("new euid = %d\n", geteuid());
-#endif
+ fprintf(stderr, "new euid = %d\n", geteuid());
+#endif /* DEBUG */
+#ifdef CONTENTLENGTH
+ headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
+ for (;;)
+ {
+ if (headerbytes == 0)
+ {
+ snprintf(buf, sizeof buf, "%s", ContentHdr);
+ nr = strlen(buf);
+ headerbytes = -1;
+ readamount = 0;
+ }
+ else if (headerbytes > sizeof(buf) || headerbytes < 0)
+ readamount = sizeof(buf);
+ else
+ readamount = headerbytes;
+ if (readamount != 0)
+ nr = read(fd, buf, readamount);
+ if (nr <= 0)
+ break;
+ if (headerbytes > 0)
+ headerbytes -= nr ;
+
+#else /* CONTENTLENGTH */
while ((nr = read(fd, buf, sizeof(buf))) > 0)
+ {
+#endif /* CONTENTLENGTH */
for (off = 0; off < nr; off += nw)
- if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
+ {
+ if ((nw = write(mbfd, buf + off, nr - off)) < 0)
+ {
+#ifdef EDQUOT
+ if (errno == EDQUOT && bouncequota)
+ mailerr("552 5.2.2", "%s: %s",
+ path, errstring(errno));
+ else
+#endif /* EDQUOT */
mailerr("450 4.2.0", "%s: %s",
- path, strerror(errno));
+ path, errstring(errno));
goto err3;
}
- if (nr < 0) {
+ }
+ }
+ if (nr < 0)
+ {
mailerr("450 4.2.0", "temporary file: %s",
- strerror(errno));
+ errstring(errno));
goto err3;
}
/* Flush to disk, don't wait for update. */
- if (!nofsync && fsync(mbfd)) {
- mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
+ if (!nofsync && fsync(mbfd) < 0)
+ {
+ mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
err3:
- if (setreuid(0, 0) < 0) {
+ if (setreuid(0, 0) < 0)
+ {
#if 0
/* already printed an error above for this recipient */
- e_to_sys(errno);
+ (void) e_to_sys(errno);
mailerr("450 4.2.0", "setreuid(0, 0): %s",
- strerror(errno));
-#endif
+ errstring(errno));
+#endif /* 0 */
}
#ifdef DEBUG
- printf("reset euid = %d\n", geteuid());
-#endif
- (void)ftruncate(mbfd, curoff);
-err1: (void)close(mbfd);
+ fprintf(stderr, "reset euid = %d\n", geteuid());
+#endif /* DEBUG */
+ (void) ftruncate(mbfd, curoff);
+err1: (void) close(mbfd);
err0: unlockmbox();
return;
}
/* Close and check -- NFS doesn't write until the close. */
- if (close(mbfd)) {
- mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
- truncate(path, curoff);
- } else if (!nobiff)
+ if (close(mbfd))
+ {
+#ifdef EDQUOT
+ if (errno == EDQUOT && bouncequota)
+ mailerr("552 5.2.2", "%s: %s", path, errstring(errno));
+ else
+#endif /* EDQUOT */
+ mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
+ (void) truncate(path, curoff);
+ }
+ else if (!nobiff)
notifybiff(biffmsg);
- if (setreuid(0, 0) < 0) {
+ if (setreuid(0, 0) < 0)
+ {
mailerr("450 4.2.0", "setreuid(0, 0): %s",
- strerror(errno));
+ errstring(errno));
goto err0;
}
#ifdef DEBUG
- printf("reset euid = %d\n", geteuid());
-#endif
+ fprintf(stderr, "reset euid = %d\n", geteuid());
+#endif /* DEBUG */
unlockmbox();
- if (lmtpmode) {
+ if (LMTPMode)
printf("250 2.1.5 %s OK\r\n", name);
- }
}
/*
- * user.lock files are necessary for compatibility with other
- * systems, e.g., when the mail spool file is NFS exported.
- * Alas, mailbox locking is more than just a local matter.
- * EPA 11/94.
- */
+** user.lock files are necessary for compatibility with other
+** systems, e.g., when the mail spool file is NFS exported.
+** Alas, mailbox locking is more than just a local matter.
+** EPA 11/94.
+*/
-char lockname[MAXPATHLEN];
-int locked = 0;
+bool Locked = FALSE;
+
+#ifdef MAILLOCK
+int
+lockmbox(name)
+ char *name;
+{
+ int r;
+
+ if (Locked)
+ return 0;
+ if ((r = maillock(name, 15)) == L_SUCCESS)
+ {
+ Locked = TRUE;
+ return 0;
+ }
+ switch (r)
+ {
+ case L_TMPLOCK: /* Can't create tmp file */
+ case L_TMPWRITE: /* Can't write pid into lockfile */
+ case L_MAXTRYS: /* Failed after retrycnt attempts */
+ errno = 0;
+ r = EX_TEMPFAIL;
+ break;
+ case L_ERROR: /* Check errno for reason */
+ r = errno;
+ break;
+ default: /* other permanent errors */
+ errno = 0;
+ r = EX_UNAVAILABLE;
+ break;
+ }
+ return r;
+}
void
+unlockmbox()
+{
+ if (Locked)
+ mailunlock();
+ Locked = FALSE;
+}
+#else /* MAILLOCK */
+
+char LockName[MAXPATHLEN];
+
+int
lockmbox(path)
char *path;
{
int statfailed = 0;
-
- if (locked)
- return;
- if (strlen(path) + 6 > sizeof lockname)
- return;
- snprintf(lockname, sizeof lockname, "%s.lock", path);
- for (;; sleep(5)) {
+ time_t start;
+
+ if (Locked)
+ return 0;
+ if (strlen(path) + 6 > sizeof LockName)
+ return EX_SOFTWARE;
+ (void) snprintf(LockName, sizeof LockName, "%s.lock", path);
+ (void) time(&start);
+ for (; ; sleep(5))
+ {
int fd;
struct stat st;
time_t now;
- fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0);
- if (fd >= 0) {
+ /* global timeout */
+ (void) time(&now);
+ if (now > start + LOCKTO_GLOB)
+ {
+ errno = 0;
+ return EX_TEMPFAIL;
+ }
+ fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, 0);
+ if (fd >= 0)
+ {
/* defeat lock checking programs which test pid */
- write(fd, "0", 2);
- locked = 1;
- close(fd);
- return;
+ (void) write(fd, "0", 2);
+ Locked = TRUE;
+ (void) close(fd);
+ return 0;
}
- if (stat(lockname, &st) < 0) {
+ if (stat(LockName, &st) < 0)
+ {
if (statfailed++ > 5)
- return;
+ {
+ errno = 0;
+ return EX_TEMPFAIL;
+ }
continue;
}
statfailed = 0;
- time(&now);
- if (now < st.st_ctime + 300)
+ (void) time(&now);
+ if (now < st.st_ctime + LOCKTO_RM)
continue;
- unlink(lockname);
+
+ /* try to remove stale lockfile */
+ if (unlink(LockName) < 0)
+ return errno;
}
}
void
unlockmbox()
{
- if (!locked)
+ if (!Locked)
return;
- unlink(lockname);
- locked = 0;
+ (void) unlink(LockName);
+ Locked = FALSE;
}
+#endif /* MAILLOCK */
void
notifybiff(msg)
char *msg;
{
- static struct sockaddr_in addr;
+ static bool initialized = FALSE;
static int f = -1;
struct hostent *hp;
struct servent *sp;
int len;
+ static struct sockaddr_in addr;
+
+ if (!initialized)
+ {
+ initialized = TRUE;
- if (addr.sin_family == 0) {
/* Be silent if biff service not available. */
- if ((sp = getservbyname("biff", "udp")) == NULL)
- return;
- if ((hp = gethostbyname("localhost")) == NULL) {
+ if ((sp = getservbyname("biff", "udp")) == NULL ||
+ (hp = gethostbyname("localhost")) == NULL ||
+ hp->h_length != INADDRSZ)
return;
- }
+
addr.sin_family = hp->h_addrtype;
- memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+ memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ);
addr.sin_port = sp->s_port;
}
- if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+
+ /* No message, just return */
+ if (msg == NULL)
+ return;
+
+ /* Couldn't initialize addr struct */
+ if (addr.sin_family == AF_UNSPEC)
+ return;
+
+ if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return;
- }
len = strlen(msg) + 1;
- (void) sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr));
+ (void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr));
}
void
usage()
{
- eval = EX_USAGE;
- mailerr(NULL, "usage: mail.local [-b] [-l] [-f from] [-s] user ...");
- exit(eval);
+ ExitVal = EX_USAGE;
+ mailerr(NULL, "usage: mail.local [-B] [-l] [-f from] [-s] user ...");
+ exit(ExitVal);
}
void
#ifdef __STDC__
mailerr(const char *hdr, const char *fmt, ...)
-#else
+#else /* __STDC__ */
mailerr(hdr, fmt, va_alist)
const char *hdr;
const char *fmt;
va_dcl
-#endif
+#endif /* __STDC__ */
{
va_list ap;
#ifdef __STDC__
va_start(ap, fmt);
-#else
+#else /* __STDC__ */
va_start(ap);
-#endif
- if (lmtpmode)
+#endif /* __STDC__ */
+ if (LMTPMode)
{
if (hdr != NULL)
printf("%s ", hdr);
- vprintf(fmt, ap);
- printf("\r\n");
+ (void) vprintf(fmt, ap);
+ (void) printf("\r\n");
}
else
{
- e_to_sys(errno);
+ (void) e_to_sys(errno);
vwarn(fmt, ap);
}
}
@@ -1049,142 +1439,133 @@ vwarn(fmt, ap)
_BSD_VA_LIST_ ap;
{
/*
- * Log the message to stderr.
- *
- * Don't use LOG_PERROR as an openlog() flag to do this,
- * it's not portable enough.
- */
- if (eval != EX_USAGE)
- (void)fprintf(stderr, "mail.local: ");
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
+ ** Log the message to stderr.
+ **
+ ** Don't use LOG_PERROR as an openlog() flag to do this,
+ ** it's not portable enough.
+ */
+
+ if (ExitVal != EX_USAGE)
+ (void) fprintf(stderr, "mail.local: ");
+ (void) vfprintf(stderr, fmt, ap);
+ (void) fprintf(stderr, "\n");
#if USE_VSYSLOG
/* Log the message to syslog. */
vsyslog(LOG_ERR, fmt, ap);
-#else
+#else /* USE_VSYSLOG */
{
char fmtbuf[10240];
(void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap);
syslog(LOG_ERR, "%s", fmtbuf);
}
-#endif
+#endif /* USE_VSYSLOG */
}
/*
* e_to_sys --
* Guess which errno's are temporary. Gag me.
*/
-void
+int
e_to_sys(num)
int num;
{
/* Temporary failures override hard errors. */
- if (eval == EX_TEMPFAIL)
- return;
+ if (ExitVal == EX_TEMPFAIL)
+ return ExitVal;
- switch(num) { /* Hopefully temporary errors. */
-#ifdef EAGAIN
- case EAGAIN: /* Resource temporarily unavailable */
-#endif
+ switch (num) /* Hopefully temporary errors. */
+ {
#ifdef EDQUOT
- case EDQUOT: /* Disc quota exceeded */
-#endif
+ case EDQUOT: /* Disc quota exceeded */
+ if (bouncequota)
+ {
+ ExitVal = EX_UNAVAILABLE;
+ break;
+ }
+ /* FALLTHROUGH */
+#endif /* EDQUOT */
+#ifdef EAGAIN
+ case EAGAIN: /* Resource temporarily unavailable */
+#endif /* EAGAIN */
#ifdef EBUSY
- case EBUSY: /* Device busy */
-#endif
+ case EBUSY: /* Device busy */
+#endif /* EBUSY */
#ifdef EPROCLIM
- case EPROCLIM: /* Too many processes */
-#endif
+ case EPROCLIM: /* Too many processes */
+#endif /* EPROCLIM */
#ifdef EUSERS
- case EUSERS: /* Too many users */
-#endif
+ case EUSERS: /* Too many users */
+#endif /* EUSERS */
#ifdef ECONNABORTED
- case ECONNABORTED: /* Software caused connection abort */
-#endif
+ case ECONNABORTED: /* Software caused connection abort */
+#endif /* ECONNABORTED */
#ifdef ECONNREFUSED
- case ECONNREFUSED: /* Connection refused */
-#endif
+ case ECONNREFUSED: /* Connection refused */
+#endif /* ECONNREFUSED */
#ifdef ECONNRESET
- case ECONNRESET: /* Connection reset by peer */
-#endif
+ case ECONNRESET: /* Connection reset by peer */
+#endif /* ECONNRESET */
#ifdef EDEADLK
- case EDEADLK: /* Resource deadlock avoided */
-#endif
+ case EDEADLK: /* Resource deadlock avoided */
+#endif /* EDEADLK */
#ifdef EFBIG
- case EFBIG: /* File too large */
-#endif
+ case EFBIG: /* File too large */
+#endif /* EFBIG */
#ifdef EHOSTDOWN
- case EHOSTDOWN: /* Host is down */
-#endif
+ case EHOSTDOWN: /* Host is down */
+#endif /* EHOSTDOWN */
#ifdef EHOSTUNREACH
- case EHOSTUNREACH: /* No route to host */
-#endif
+ case EHOSTUNREACH: /* No route to host */
+#endif /* EHOSTUNREACH */
#ifdef EMFILE
- case EMFILE: /* Too many open files */
-#endif
+ case EMFILE: /* Too many open files */
+#endif /* EMFILE */
#ifdef ENETDOWN
- case ENETDOWN: /* Network is down */
-#endif
+ case ENETDOWN: /* Network is down */
+#endif /* ENETDOWN */
#ifdef ENETRESET
- case ENETRESET: /* Network dropped connection on reset */
-#endif
+ case ENETRESET: /* Network dropped connection on reset */
+#endif /* ENETRESET */
#ifdef ENETUNREACH
- case ENETUNREACH: /* Network is unreachable */
-#endif
+ case ENETUNREACH: /* Network is unreachable */
+#endif /* ENETUNREACH */
#ifdef ENFILE
- case ENFILE: /* Too many open files in system */
-#endif
+ case ENFILE: /* Too many open files in system */
+#endif /* ENFILE */
#ifdef ENOBUFS
- case ENOBUFS: /* No buffer space available */
-#endif
+ case ENOBUFS: /* No buffer space available */
+#endif /* ENOBUFS */
#ifdef ENOMEM
- case ENOMEM: /* Cannot allocate memory */
-#endif
+ case ENOMEM: /* Cannot allocate memory */
+#endif /* ENOMEM */
#ifdef ENOSPC
- case ENOSPC: /* No space left on device */
-#endif
+ case ENOSPC: /* No space left on device */
+#endif /* ENOSPC */
#ifdef EROFS
- case EROFS: /* Read-only file system */
-#endif
+ case EROFS: /* Read-only file system */
+#endif /* EROFS */
#ifdef ESTALE
- case ESTALE: /* Stale NFS file handle */
-#endif
+ case ESTALE: /* Stale NFS file handle */
+#endif /* ESTALE */
#ifdef ETIMEDOUT
- case ETIMEDOUT: /* Connection timed out */
-#endif
+ case ETIMEDOUT: /* Connection timed out */
+#endif /* ETIMEDOUT */
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
- case EWOULDBLOCK: /* Operation would block. */
-#endif
- eval = EX_TEMPFAIL;
+ case EWOULDBLOCK: /* Operation would block. */
+#endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */
+ ExitVal = EX_TEMPFAIL;
break;
- default:
- eval = EX_UNAVAILABLE;
+
+ default:
+ ExitVal = EX_UNAVAILABLE;
break;
}
+ return ExitVal;
}
-#if !HASSTRERROR
-
-char *
-strerror(eno)
- int eno;
-{
- extern int sys_nerr;
- extern char *sys_errlist[];
- static char ebuf[60];
-
- if (eno >= 0 && eno < sys_nerr)
- return sys_errlist[eno];
- (void) sprintf(ebuf, "Error %d", eno);
- return ebuf;
-}
-
-#endif /* !HASSTRERROR */
-
#if defined(ultrix) || defined(_CRAY)
-
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
@@ -1218,16 +1599,16 @@ strerror(eno)
* SUCH DAMAGE.
*/
-#if defined(LIBC_SCCS) && !defined(lint)
+# if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
+# endif /* defined(LIBC_SCCS) && !defined(lint) */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <ctype.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <stdio.h>
+# include <ctype.h>
static int _gettemp();
@@ -1239,14 +1620,14 @@ mkstemp(path)
return (_gettemp(path, &fd) ? fd : -1);
}
-/*
+# if 0
char *
mktemp(path)
char *path;
{
return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
}
-*/
+# endif /* 0 */
static
_gettemp(path, doopen)
@@ -1260,7 +1641,8 @@ _gettemp(path, doopen)
pid = getpid();
for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
- while (*--trv == 'X') {
+ while (*--trv == 'X')
+ {
*trv = (pid % 10) + '0';
pid /= 10;
}
@@ -1269,14 +1651,17 @@ _gettemp(path, doopen)
* check the target directory; if you have six X's and it
* doesn't exist this runs for a *very* long time.
*/
- for (start = trv + 1;; --trv) {
+ for (start = trv + 1;; --trv)
+ {
if (trv <= path)
break;
- if (*trv == '/') {
+ if (*trv == '/')
+ {
*trv = '\0';
if (stat(path, &sbuf) < 0)
return(0);
- if (!S_ISDIR(sbuf.st_mode)) {
+ if (!S_ISDIR(sbuf.st_mode))
+ {
errno = ENOTDIR;
return(0);
}
@@ -1285,8 +1670,10 @@ _gettemp(path, doopen)
}
}
- for (;;) {
- if (doopen) {
+ for (;;)
+ {
+ if (doopen)
+ {
if ((*doopen =
open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
return(1);
@@ -1297,12 +1684,14 @@ _gettemp(path, doopen)
return(errno == ENOENT ? 1 : 0);
/* tricky little algorithm for backward compatibility */
- for (trv = start;;) {
+ for (trv = start;;)
+ {
if (!*trv)
return(0);
if (*trv == 'z')
*trv++ = 'a';
- else {
+ else
+ {
if (isascii(*trv) && isdigit(*trv))
*trv = 'a';
else
@@ -1311,7 +1700,6 @@ _gettemp(path, doopen)
}
}
}
- /*NOTREACHED*/
+ /* NOTREACHED */
}
-
-#endif /* ultrix */
+#endif /* defined(ultrix) || defined(_CRAY) */
OpenPOWER on IntegriCloud