xref: /freebsd/contrib/sendmail/mail.local/mail.local.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
176b7bf71SPeter Wemm /*
2f9218d3dSGregory Neil Shapiro  * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1990, 1993, 1994
5c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
6c2aa98e2SPeter Wemm  *
7c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
8c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
9c2aa98e2SPeter Wemm  * the sendmail distribution.
10c2aa98e2SPeter Wemm  *
113edfa581SGregory Neil Shapiro  * $FreeBSD$
123edfa581SGregory Neil Shapiro  *
13c2aa98e2SPeter Wemm  */
14c2aa98e2SPeter Wemm 
1512ed1c7cSGregory Neil Shapiro #include <sm/gen.h>
1612ed1c7cSGregory Neil Shapiro 
1712ed1c7cSGregory Neil Shapiro SM_IDSTR(copyright,
18b4662009SGregory Neil Shapiro "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
193299c2f1SGregory Neil Shapiro 	All rights reserved.\n\
203299c2f1SGregory Neil Shapiro      Copyright (c) 1990, 1993, 1994\n\
2112ed1c7cSGregory Neil Shapiro 	The Regents of the University of California.  All rights reserved.\n")
22c2aa98e2SPeter Wemm 
23f9218d3dSGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: mail.local.c,v 8.239.2.4 2003/01/15 19:17:15 ca Exp $")
2412ed1c7cSGregory Neil Shapiro 
2512ed1c7cSGregory Neil Shapiro #include <stdlib.h>
2612ed1c7cSGregory Neil Shapiro #include <sm/errstring.h>
2712ed1c7cSGregory Neil Shapiro #include <sm/io.h>
2812ed1c7cSGregory Neil Shapiro #include <sm/limits.h>
2912ed1c7cSGregory Neil Shapiro # include <unistd.h>
3012ed1c7cSGregory Neil Shapiro # ifdef EX_OK
3112ed1c7cSGregory Neil Shapiro #  undef EX_OK		/* unistd.h may have another use for this */
3212ed1c7cSGregory Neil Shapiro # endif /* EX_OK */
3312ed1c7cSGregory Neil Shapiro #include <sm/mbdb.h>
3412ed1c7cSGregory Neil Shapiro #include <sm/sysexits.h>
353299c2f1SGregory Neil Shapiro 
36c2aa98e2SPeter Wemm /*
373299c2f1SGregory Neil Shapiro **  This is not intended to work on System V derived systems
383299c2f1SGregory Neil Shapiro **  such as Solaris or HP-UX, since they use a totally different
3912ed1c7cSGregory Neil Shapiro **  approach to mailboxes (essentially, they have a set-group-ID program
4012ed1c7cSGregory Neil Shapiro **  rather than set-user-ID, and they rely on the ability to "give away"
413299c2f1SGregory Neil Shapiro **  files to do their work).  IT IS NOT A BUG that this doesn't
423299c2f1SGregory Neil Shapiro **  work on such architectures.
43c2aa98e2SPeter Wemm */
44c2aa98e2SPeter Wemm 
453299c2f1SGregory Neil Shapiro 
4612ed1c7cSGregory Neil Shapiro #include <stdio.h>
4712ed1c7cSGregory Neil Shapiro #include <errno.h>
4812ed1c7cSGregory Neil Shapiro #include <fcntl.h>
4912ed1c7cSGregory Neil Shapiro #include <sys/types.h>
5012ed1c7cSGregory Neil Shapiro #include <sys/stat.h>
5112ed1c7cSGregory Neil Shapiro #include <time.h>
5212ed1c7cSGregory Neil Shapiro #include <stdlib.h>
5312ed1c7cSGregory Neil Shapiro # include <sys/socket.h>
5412ed1c7cSGregory Neil Shapiro # include <sys/file.h>
5512ed1c7cSGregory Neil Shapiro # include <netinet/in.h>
5612ed1c7cSGregory Neil Shapiro # include <arpa/nameser.h>
5712ed1c7cSGregory Neil Shapiro # include <netdb.h>
5812ed1c7cSGregory Neil Shapiro # include <pwd.h>
5912ed1c7cSGregory Neil Shapiro 
6012ed1c7cSGregory Neil Shapiro #include <sm/string.h>
6112ed1c7cSGregory Neil Shapiro #include <syslog.h>
6212ed1c7cSGregory Neil Shapiro #include <ctype.h>
6312ed1c7cSGregory Neil Shapiro 
6412ed1c7cSGregory Neil Shapiro #include <sm/conf.h>
6512ed1c7cSGregory Neil Shapiro #include <sendmail/pathnames.h>
6612ed1c7cSGregory Neil Shapiro 
6712ed1c7cSGregory Neil Shapiro 
68d995d2baSGregory Neil Shapiro /* additional mode for open() */
69d995d2baSGregory Neil Shapiro # define EXTRA_MODE 0
70d995d2baSGregory Neil Shapiro 
713299c2f1SGregory Neil Shapiro 
723299c2f1SGregory Neil Shapiro #ifndef LOCKTO_RM
733299c2f1SGregory Neil Shapiro # define LOCKTO_RM	300	/* timeout for stale lockfile removal */
74d995d2baSGregory Neil Shapiro #endif /* ! LOCKTO_RM */
753299c2f1SGregory Neil Shapiro #ifndef LOCKTO_GLOB
763299c2f1SGregory Neil Shapiro # define LOCKTO_GLOB	400	/* global timeout for lockfile creation */
77d995d2baSGregory Neil Shapiro #endif /* ! LOCKTO_GLOB */
783299c2f1SGregory Neil Shapiro 
793299c2f1SGregory Neil Shapiro /* define a realloc() which works for NULL pointers */
803299c2f1SGregory Neil Shapiro #define REALLOC(ptr, size)	(((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
81c2aa98e2SPeter Wemm 
82c2aa98e2SPeter Wemm /*
8312ed1c7cSGregory Neil Shapiro **  If you don't have flock, you could try using lockf instead.
84c2aa98e2SPeter Wemm */
85c2aa98e2SPeter Wemm 
8612ed1c7cSGregory Neil Shapiro #ifdef LDA_USE_LOCKF
87c2aa98e2SPeter Wemm # define flock(a, b)	lockf(a, b, 0)
883299c2f1SGregory Neil Shapiro # ifdef LOCK_EX
893299c2f1SGregory Neil Shapiro #  undef LOCK_EX
903299c2f1SGregory Neil Shapiro # endif /* LOCK_EX */
91c2aa98e2SPeter Wemm # define LOCK_EX	F_LOCK
9212ed1c7cSGregory Neil Shapiro #endif /* LDA_USE_LOCKF */
93c2aa98e2SPeter Wemm 
94c2aa98e2SPeter Wemm #ifndef LOCK_EX
95c2aa98e2SPeter Wemm # include <sys/file.h>
963299c2f1SGregory Neil Shapiro #endif /* ! LOCK_EX */
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm /*
993299c2f1SGregory Neil Shapiro **  If you don't have setreuid, and you have saved uids, and you have
1003299c2f1SGregory Neil Shapiro **  a seteuid() call that doesn't try to emulate using setuid(), then
10112ed1c7cSGregory Neil Shapiro **  you can try defining LDA_USE_SETEUID.
102c2aa98e2SPeter Wemm */
103b4662009SGregory Neil Shapiro 
10412ed1c7cSGregory Neil Shapiro #ifdef LDA_USE_SETEUID
105c2aa98e2SPeter Wemm # define setreuid(r, e)		seteuid(e)
10612ed1c7cSGregory Neil Shapiro #endif /* LDA_USE_SETEUID */
107c2aa98e2SPeter Wemm 
10812ed1c7cSGregory Neil Shapiro #ifdef LDA_CONTENTLENGTH
10912ed1c7cSGregory Neil Shapiro # define CONTENTLENGTH	1
11012ed1c7cSGregory Neil Shapiro #endif /* LDA_CONTENTLENGTH */
111d995d2baSGregory Neil Shapiro 
1123299c2f1SGregory Neil Shapiro #ifndef INADDRSZ
1133299c2f1SGregory Neil Shapiro # define INADDRSZ	4		/* size of an IPv4 address in bytes */
1143299c2f1SGregory Neil Shapiro #endif /* ! INADDRSZ */
115c2aa98e2SPeter Wemm 
11612ed1c7cSGregory Neil Shapiro #ifdef MAILLOCK
11712ed1c7cSGregory Neil Shapiro # include <maillock.h>
11812ed1c7cSGregory Neil Shapiro #endif /* MAILLOCK */
11912ed1c7cSGregory Neil Shapiro 
12076b7bf71SPeter Wemm #ifndef MAILER_DAEMON
12176b7bf71SPeter Wemm # define MAILER_DAEMON	"MAILER-DAEMON"
1223299c2f1SGregory Neil Shapiro #endif /* ! MAILER_DAEMON */
12376b7bf71SPeter Wemm 
1243299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
1253299c2f1SGregory Neil Shapiro char	ContentHdr[40] = "Content-Length: ";
1263299c2f1SGregory Neil Shapiro off_t	HeaderLength;
1273299c2f1SGregory Neil Shapiro off_t	BodyLength;
1283299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
129c2aa98e2SPeter Wemm 
13012ed1c7cSGregory Neil Shapiro bool	EightBitMime = true;		/* advertise 8BITMIME in LMTP */
131b4662009SGregory Neil Shapiro char	ErrBuf[10240];			/* error buffer */
1323299c2f1SGregory Neil Shapiro int	ExitVal = EX_OK;		/* sysexits.h error value. */
13312ed1c7cSGregory Neil Shapiro bool	nobiff = false;
13412ed1c7cSGregory Neil Shapiro bool	nofsync = false;
13512ed1c7cSGregory Neil Shapiro bool	HoldErrs = false;		/* Hold errors in ErrBuf */
13612ed1c7cSGregory Neil Shapiro bool	LMTPMode = false;
13712ed1c7cSGregory Neil Shapiro bool	BounceQuota = false;		/* permanent error when over quota */
13812ed1c7cSGregory Neil Shapiro char	*HomeMailFile = NULL;		/* store mail in homedir */
1393299c2f1SGregory Neil Shapiro 
140b4662009SGregory Neil Shapiro void	deliver __P((int, char *));
1413299c2f1SGregory Neil Shapiro int	e_to_sys __P((int));
142c2aa98e2SPeter Wemm void	notifybiff __P((char *));
14312ed1c7cSGregory Neil Shapiro int	store __P((char *, bool *));
144c2aa98e2SPeter Wemm void	usage __P((void));
1453299c2f1SGregory Neil Shapiro int	lockmbox __P((char *));
146c2aa98e2SPeter Wemm void	unlockmbox __P((void));
147c2aa98e2SPeter Wemm void	mailerr __P((const char *, const char *, ...));
148b4662009SGregory Neil Shapiro void	flush_error __P((void));
1493299c2f1SGregory Neil Shapiro 
150c2aa98e2SPeter Wemm 
151c2aa98e2SPeter Wemm int
152c2aa98e2SPeter Wemm main(argc, argv)
153c2aa98e2SPeter Wemm 	int argc;
154c2aa98e2SPeter Wemm 	char *argv[];
155c2aa98e2SPeter Wemm {
156c2aa98e2SPeter Wemm 	struct passwd *pw;
1573299c2f1SGregory Neil Shapiro 	int ch, fd;
158c2aa98e2SPeter Wemm 	uid_t uid;
159c2aa98e2SPeter Wemm 	char *from;
16012ed1c7cSGregory Neil Shapiro 	char *mbdbname = "pw";
16112ed1c7cSGregory Neil Shapiro 	int err;
162c2aa98e2SPeter Wemm 	extern char *optarg;
163c2aa98e2SPeter Wemm 	extern int optind;
1643299c2f1SGregory Neil Shapiro 
165c2aa98e2SPeter Wemm 
166c2aa98e2SPeter Wemm 	/* make sure we have some open file descriptors */
167c2aa98e2SPeter Wemm 	for (fd = 10; fd < 30; fd++)
168c2aa98e2SPeter Wemm 		(void) close(fd);
169c2aa98e2SPeter Wemm 
170c2aa98e2SPeter Wemm 	/* use a reasonable umask */
171c2aa98e2SPeter Wemm 	(void) umask(0077);
172c2aa98e2SPeter Wemm 
173c2aa98e2SPeter Wemm # ifdef LOG_MAIL
174c2aa98e2SPeter Wemm 	openlog("mail.local", 0, LOG_MAIL);
1753299c2f1SGregory Neil Shapiro # else /* LOG_MAIL */
176c2aa98e2SPeter Wemm 	openlog("mail.local", 0);
1773299c2f1SGregory Neil Shapiro # endif /* LOG_MAIL */
178c2aa98e2SPeter Wemm 
179c2aa98e2SPeter Wemm 	from = NULL;
18012ed1c7cSGregory Neil Shapiro 	while ((ch = getopt(argc, argv, "7BbdD:f:h:r:ls")) != -1)
1813299c2f1SGregory Neil Shapiro 	{
1823299c2f1SGregory Neil Shapiro 		switch(ch)
1833299c2f1SGregory Neil Shapiro 		{
1843299c2f1SGregory Neil Shapiro 		  case '7':		/* Do not advertise 8BITMIME */
18512ed1c7cSGregory Neil Shapiro 			EightBitMime = false;
186d615a192SPeter Wemm 			break;
1873299c2f1SGregory Neil Shapiro 
1883299c2f1SGregory Neil Shapiro 		  case 'B':
18939e37e72SGregory Neil Shapiro 			nobiff = true;
1903299c2f1SGregory Neil Shapiro 			break;
1913299c2f1SGregory Neil Shapiro 
1923299c2f1SGregory Neil Shapiro 		  case 'b':		/* bounce mail when over quota. */
19312ed1c7cSGregory Neil Shapiro 			BounceQuota = true;
1943299c2f1SGregory Neil Shapiro 			break;
1953299c2f1SGregory Neil Shapiro 
196c2aa98e2SPeter Wemm 		  case 'd':		/* Backward compatible. */
197c2aa98e2SPeter Wemm 			break;
1983299c2f1SGregory Neil Shapiro 
19912ed1c7cSGregory Neil Shapiro 		  case 'D':		/* mailbox database type */
20012ed1c7cSGregory Neil Shapiro 			mbdbname = optarg;
20112ed1c7cSGregory Neil Shapiro 			break;
20212ed1c7cSGregory Neil Shapiro 
203c2aa98e2SPeter Wemm 		  case 'f':
204c2aa98e2SPeter Wemm 		  case 'r':		/* Backward compatible. */
2053299c2f1SGregory Neil Shapiro 			if (from != NULL)
2063299c2f1SGregory Neil Shapiro 			{
207b4662009SGregory Neil Shapiro 				mailerr(NULL, "Multiple -f options");
208c2aa98e2SPeter Wemm 				usage();
209c2aa98e2SPeter Wemm 			}
210c2aa98e2SPeter Wemm 			from = optarg;
211c2aa98e2SPeter Wemm 			break;
2123299c2f1SGregory Neil Shapiro 
21312ed1c7cSGregory Neil Shapiro 		  case 'h':
21412ed1c7cSGregory Neil Shapiro 			if (optarg != NULL || *optarg != '\0')
21512ed1c7cSGregory Neil Shapiro 				HomeMailFile = optarg;
21612ed1c7cSGregory Neil Shapiro 			else
21712ed1c7cSGregory Neil Shapiro 			{
21812ed1c7cSGregory Neil Shapiro 				mailerr(NULL, "-h: missing filename");
21912ed1c7cSGregory Neil Shapiro 				usage();
22012ed1c7cSGregory Neil Shapiro 			}
22112ed1c7cSGregory Neil Shapiro 			break;
22212ed1c7cSGregory Neil Shapiro 
223c2aa98e2SPeter Wemm 		  case 'l':
22412ed1c7cSGregory Neil Shapiro 			LMTPMode = true;
225c2aa98e2SPeter Wemm 			break;
2263299c2f1SGregory Neil Shapiro 
227d615a192SPeter Wemm 		  case 's':
22805b73c60SPeter Wemm 			nofsync++;
229d615a192SPeter Wemm 			break;
2303299c2f1SGregory Neil Shapiro 
231c2aa98e2SPeter Wemm 		  case '?':
232c2aa98e2SPeter Wemm 		  default:
233c2aa98e2SPeter Wemm 			usage();
234c2aa98e2SPeter Wemm 		}
2353299c2f1SGregory Neil Shapiro 	}
236c2aa98e2SPeter Wemm 	argc -= optind;
237c2aa98e2SPeter Wemm 	argv += optind;
238c2aa98e2SPeter Wemm 
2393299c2f1SGregory Neil Shapiro 	/* initialize biff structures */
2403299c2f1SGregory Neil Shapiro 	if (!nobiff)
2413299c2f1SGregory Neil Shapiro 		notifybiff(NULL);
242c2aa98e2SPeter Wemm 
24312ed1c7cSGregory Neil Shapiro 	err = sm_mbdb_initialize(mbdbname);
24412ed1c7cSGregory Neil Shapiro 	if (err != EX_OK)
24512ed1c7cSGregory Neil Shapiro 	{
24612ed1c7cSGregory Neil Shapiro 		char *errcode = "521";
24712ed1c7cSGregory Neil Shapiro 
24812ed1c7cSGregory Neil Shapiro 		if (err == EX_TEMPFAIL)
24912ed1c7cSGregory Neil Shapiro 			errcode = "421";
25012ed1c7cSGregory Neil Shapiro 
25112ed1c7cSGregory Neil Shapiro 		mailerr(errcode, "Can not open mailbox database %s: %s",
25212ed1c7cSGregory Neil Shapiro 			mbdbname, sm_strexit(err));
25312ed1c7cSGregory Neil Shapiro 		exit(err);
25412ed1c7cSGregory Neil Shapiro 	}
25512ed1c7cSGregory Neil Shapiro 
2563299c2f1SGregory Neil Shapiro 	if (LMTPMode)
257b4662009SGregory Neil Shapiro 	{
258b4662009SGregory Neil Shapiro 		extern void dolmtp __P((void));
2593299c2f1SGregory Neil Shapiro 
260b4662009SGregory Neil Shapiro 		if (argc > 0)
261b4662009SGregory Neil Shapiro 		{
262b4662009SGregory Neil Shapiro 			mailerr("421", "Users should not be specified in command line if LMTP required");
263b4662009SGregory Neil Shapiro 			exit(EX_TEMPFAIL);
264b4662009SGregory Neil Shapiro 		}
265b4662009SGregory Neil Shapiro 
266b4662009SGregory Neil Shapiro 		dolmtp();
267b4662009SGregory Neil Shapiro 		/* NOTREACHED */
268b4662009SGregory Neil Shapiro 		exit(EX_OK);
269b4662009SGregory Neil Shapiro 	}
270b4662009SGregory Neil Shapiro 
271b4662009SGregory Neil Shapiro 	/* Non-LMTP from here on out */
2723299c2f1SGregory Neil Shapiro 	if (*argv == '\0')
273c2aa98e2SPeter Wemm 		usage();
274c2aa98e2SPeter Wemm 
275c2aa98e2SPeter Wemm 	/*
2763299c2f1SGregory Neil Shapiro 	**  If from not specified, use the name from getlogin() if the
2773299c2f1SGregory Neil Shapiro 	**  uid matches, otherwise, use the name from the password file
2783299c2f1SGregory Neil Shapiro 	**  corresponding to the uid.
279c2aa98e2SPeter Wemm 	*/
280b4662009SGregory Neil Shapiro 
281c2aa98e2SPeter Wemm 	uid = getuid();
2823299c2f1SGregory Neil Shapiro 	if (from == NULL && ((from = getlogin()) == NULL ||
2833299c2f1SGregory Neil Shapiro 			     (pw = getpwnam(from)) == NULL ||
2843299c2f1SGregory Neil Shapiro 			     pw->pw_uid != uid))
2853299c2f1SGregory Neil Shapiro 		from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
286c2aa98e2SPeter Wemm 
287c2aa98e2SPeter Wemm 	/*
2883299c2f1SGregory Neil Shapiro 	**  There is no way to distinguish the error status of one delivery
2893299c2f1SGregory Neil Shapiro 	**  from the rest of the deliveries.  So, if we failed hard on one
2903299c2f1SGregory Neil Shapiro 	**  or more deliveries, but had no failures on any of the others, we
2913299c2f1SGregory Neil Shapiro 	**  return a hard failure.  If we failed temporarily on one or more
2923299c2f1SGregory Neil Shapiro 	**  deliveries, we return a temporary failure regardless of the other
2933299c2f1SGregory Neil Shapiro 	**  failures.  This results in the delivery being reattempted later
2943299c2f1SGregory Neil Shapiro 	**  at the expense of repeated failures and multiple deliveries.
295c2aa98e2SPeter Wemm 	*/
296b4662009SGregory Neil Shapiro 
29712ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
29812ed1c7cSGregory Neil Shapiro 	fd = store(from, NULL);
29912ed1c7cSGregory Neil Shapiro 	HoldErrs = false;
300b4662009SGregory Neil Shapiro 	if (fd < 0)
301b4662009SGregory Neil Shapiro 	{
302b4662009SGregory Neil Shapiro 		flush_error();
303b4662009SGregory Neil Shapiro 		exit(ExitVal);
304b4662009SGregory Neil Shapiro 	}
305b4662009SGregory Neil Shapiro 	for (; *argv != NULL; ++argv)
306b4662009SGregory Neil Shapiro 		deliver(fd, *argv);
3073299c2f1SGregory Neil Shapiro 	exit(ExitVal);
3083299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
3093299c2f1SGregory Neil Shapiro 	return ExitVal;
310c2aa98e2SPeter Wemm }
311c2aa98e2SPeter Wemm 
312c2aa98e2SPeter Wemm char *
3133299c2f1SGregory Neil Shapiro parseaddr(s, rcpt)
314c2aa98e2SPeter Wemm 	char *s;
3153299c2f1SGregory Neil Shapiro 	bool rcpt;
316c2aa98e2SPeter Wemm {
317c2aa98e2SPeter Wemm 	char *p;
3183299c2f1SGregory Neil Shapiro 	int l;
319c2aa98e2SPeter Wemm 
320c2aa98e2SPeter Wemm 	if (*s++ != '<')
321c2aa98e2SPeter Wemm 		return NULL;
322c2aa98e2SPeter Wemm 
323c2aa98e2SPeter Wemm 	p = s;
324c2aa98e2SPeter Wemm 
325c2aa98e2SPeter Wemm 	/* at-domain-list */
3263299c2f1SGregory Neil Shapiro 	while (*p == '@')
3273299c2f1SGregory Neil Shapiro 	{
328c2aa98e2SPeter Wemm 		p++;
3293299c2f1SGregory Neil Shapiro 		while (*p != ',' && *p != ':' && *p != '\0')
330c2aa98e2SPeter Wemm 			p++;
3313299c2f1SGregory Neil Shapiro 		if (*p == '\0')
332c2aa98e2SPeter Wemm 			return NULL;
3333299c2f1SGregory Neil Shapiro 
3343299c2f1SGregory Neil Shapiro 		/* Skip over , or : */
335c2aa98e2SPeter Wemm 		p++;
336c2aa98e2SPeter Wemm 	}
337c2aa98e2SPeter Wemm 
33876b7bf71SPeter Wemm 	s = p;
33976b7bf71SPeter Wemm 
340c2aa98e2SPeter Wemm 	/* local-part */
3413299c2f1SGregory Neil Shapiro 	while (*p != '\0' && *p != '@' && *p != '>')
3423299c2f1SGregory Neil Shapiro 	{
3433299c2f1SGregory Neil Shapiro 		if (*p == '\\')
3443299c2f1SGregory Neil Shapiro 		{
3453299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
3463299c2f1SGregory Neil Shapiro 				return NULL;
3473299c2f1SGregory Neil Shapiro 		}
3483299c2f1SGregory Neil Shapiro 		else if (*p == '\"')
3493299c2f1SGregory Neil Shapiro 		{
350c2aa98e2SPeter Wemm 			p++;
3513299c2f1SGregory Neil Shapiro 			while (*p != '\0' && *p != '\"')
3523299c2f1SGregory Neil Shapiro 			{
3533299c2f1SGregory Neil Shapiro 				if (*p == '\\')
3543299c2f1SGregory Neil Shapiro 				{
3553299c2f1SGregory Neil Shapiro 					if (*++p == '\0')
356c2aa98e2SPeter Wemm 						return NULL;
357c2aa98e2SPeter Wemm 				}
358c2aa98e2SPeter Wemm 				p++;
359c2aa98e2SPeter Wemm 			}
3603299c2f1SGregory Neil Shapiro 			if (*p == '\0' || *(p + 1) == '\0')
361c2aa98e2SPeter Wemm 				return NULL;
362c2aa98e2SPeter Wemm 		}
3633299c2f1SGregory Neil Shapiro 		/* +detail ? */
3643299c2f1SGregory Neil Shapiro 		if (*p == '+' && rcpt)
3653299c2f1SGregory Neil Shapiro 			*p = '\0';
366c2aa98e2SPeter Wemm 		p++;
367c2aa98e2SPeter Wemm 	}
368c2aa98e2SPeter Wemm 
369c2aa98e2SPeter Wemm 	/* @domain */
3703299c2f1SGregory Neil Shapiro 	if (*p == '@')
37176b7bf71SPeter Wemm 	{
3723299c2f1SGregory Neil Shapiro 		if (rcpt)
3733299c2f1SGregory Neil Shapiro 			*p++ = '\0';
3743299c2f1SGregory Neil Shapiro 		while (*p != '\0' && *p != '>')
3753299c2f1SGregory Neil Shapiro 			p++;
37676b7bf71SPeter Wemm 	}
377c2aa98e2SPeter Wemm 
3783299c2f1SGregory Neil Shapiro 	if (*p != '>')
3793299c2f1SGregory Neil Shapiro 		return NULL;
3803299c2f1SGregory Neil Shapiro 	else
3813299c2f1SGregory Neil Shapiro 		*p = '\0';
3823299c2f1SGregory Neil Shapiro 	p++;
3833299c2f1SGregory Neil Shapiro 
3843299c2f1SGregory Neil Shapiro 	if (*p != '\0' && *p != ' ')
3853299c2f1SGregory Neil Shapiro 		return NULL;
3863299c2f1SGregory Neil Shapiro 
3873299c2f1SGregory Neil Shapiro 	if (*s == '\0')
3883299c2f1SGregory Neil Shapiro 		s = MAILER_DAEMON;
3893299c2f1SGregory Neil Shapiro 
3903299c2f1SGregory Neil Shapiro 	l = strlen(s) + 1;
39112ed1c7cSGregory Neil Shapiro 	if (l < 0)
39212ed1c7cSGregory Neil Shapiro 		return NULL;
3933299c2f1SGregory Neil Shapiro 	p = malloc(l);
3943299c2f1SGregory Neil Shapiro 	if (p == NULL)
3953299c2f1SGregory Neil Shapiro 	{
396b4662009SGregory Neil Shapiro 		mailerr("421 4.3.0", "Memory exhausted");
397c2aa98e2SPeter Wemm 		exit(EX_TEMPFAIL);
398c2aa98e2SPeter Wemm 	}
399c2aa98e2SPeter Wemm 
40012ed1c7cSGregory Neil Shapiro 	(void) sm_strlcpy(p, s, l);
401c2aa98e2SPeter Wemm 	return p;
402c2aa98e2SPeter Wemm }
403c2aa98e2SPeter Wemm 
404c2aa98e2SPeter Wemm char *
405c2aa98e2SPeter Wemm process_recipient(addr)
406c2aa98e2SPeter Wemm 	char *addr;
407c2aa98e2SPeter Wemm {
40812ed1c7cSGregory Neil Shapiro 	SM_MBDB_T user;
40912ed1c7cSGregory Neil Shapiro 
41012ed1c7cSGregory Neil Shapiro 	switch (sm_mbdb_lookup(addr, &user))
41112ed1c7cSGregory Neil Shapiro 	{
41212ed1c7cSGregory Neil Shapiro 	  case EX_OK:
413c2aa98e2SPeter Wemm 		return NULL;
41412ed1c7cSGregory Neil Shapiro 
41512ed1c7cSGregory Neil Shapiro 	  case EX_NOUSER:
41612ed1c7cSGregory Neil Shapiro 		return "550 5.1.1 User unknown";
41712ed1c7cSGregory Neil Shapiro 
41812ed1c7cSGregory Neil Shapiro 	  case EX_TEMPFAIL:
41912ed1c7cSGregory Neil Shapiro 		return "451 4.3.0 User database failure; retry later";
42012ed1c7cSGregory Neil Shapiro 
42112ed1c7cSGregory Neil Shapiro 	  default:
42212ed1c7cSGregory Neil Shapiro 		return "550 5.3.0 User database failure";
42312ed1c7cSGregory Neil Shapiro 	}
424c2aa98e2SPeter Wemm }
425c2aa98e2SPeter Wemm 
426c2aa98e2SPeter Wemm #define RCPT_GROW	30
427c2aa98e2SPeter Wemm 
428c2aa98e2SPeter Wemm void
429b4662009SGregory Neil Shapiro dolmtp()
430c2aa98e2SPeter Wemm {
431c2aa98e2SPeter Wemm 	char *return_path = NULL;
432c2aa98e2SPeter Wemm 	char **rcpt_addr = NULL;
433c2aa98e2SPeter Wemm 	int rcpt_num = 0;
434c2aa98e2SPeter Wemm 	int rcpt_alloc = 0;
43512ed1c7cSGregory Neil Shapiro 	bool gotlhlo = false;
436c2aa98e2SPeter Wemm 	char *err;
437c2aa98e2SPeter Wemm 	int msgfd;
438c2aa98e2SPeter Wemm 	char *p;
439c2aa98e2SPeter Wemm 	int i;
4403299c2f1SGregory Neil Shapiro 	char myhostname[1024];
4413299c2f1SGregory Neil Shapiro 	char buf[4096];
442c2aa98e2SPeter Wemm 
443b4662009SGregory Neil Shapiro 	memset(myhostname, '\0', sizeof myhostname);
4443299c2f1SGregory Neil Shapiro 	(void) gethostname(myhostname, sizeof myhostname - 1);
445b4662009SGregory Neil Shapiro 	if (myhostname[0] == '\0')
44612ed1c7cSGregory Neil Shapiro 		sm_strlcpy(myhostname, "localhost", sizeof myhostname);
447c2aa98e2SPeter Wemm 
448c2aa98e2SPeter Wemm 	printf("220 %s LMTP ready\r\n", myhostname);
4493299c2f1SGregory Neil Shapiro 	for (;;)
4503299c2f1SGregory Neil Shapiro 	{
4513299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
4523299c2f1SGregory Neil Shapiro 		if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
453c2aa98e2SPeter Wemm 			exit(EX_OK);
454c2aa98e2SPeter Wemm 		p = buf + strlen(buf) - 1;
455c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\n')
456c2aa98e2SPeter Wemm 			*p-- = '\0';
457c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\r')
458c2aa98e2SPeter Wemm 			*p-- = '\0';
459c2aa98e2SPeter Wemm 
4603299c2f1SGregory Neil Shapiro 		switch (buf[0])
4613299c2f1SGregory Neil Shapiro 		{
462c2aa98e2SPeter Wemm 		  case 'd':
463c2aa98e2SPeter Wemm 		  case 'D':
46412ed1c7cSGregory Neil Shapiro 			if (sm_strcasecmp(buf, "data") == 0)
4653299c2f1SGregory Neil Shapiro 			{
46612ed1c7cSGregory Neil Shapiro 				bool inbody = false;
467b4662009SGregory Neil Shapiro 
4683299c2f1SGregory Neil Shapiro 				if (rcpt_num == 0)
4693299c2f1SGregory Neil Shapiro 				{
470b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1", "No recipients");
471c2aa98e2SPeter Wemm 					continue;
472c2aa98e2SPeter Wemm 				}
47312ed1c7cSGregory Neil Shapiro 				HoldErrs = true;
47412ed1c7cSGregory Neil Shapiro 				msgfd = store(return_path, &inbody);
47512ed1c7cSGregory Neil Shapiro 				HoldErrs = false;
476b4662009SGregory Neil Shapiro 				if (msgfd < 0 && !inbody)
477b4662009SGregory Neil Shapiro 				{
478b4662009SGregory Neil Shapiro 					flush_error();
479c2aa98e2SPeter Wemm 					continue;
480b4662009SGregory Neil Shapiro 				}
481c2aa98e2SPeter Wemm 
4823299c2f1SGregory Neil Shapiro 				for (i = 0; i < rcpt_num; i++)
4833299c2f1SGregory Neil Shapiro 				{
484b4662009SGregory Neil Shapiro 					if (msgfd < 0)
485b4662009SGregory Neil Shapiro 					{
486b4662009SGregory Neil Shapiro 						/* print error for rcpt */
487b4662009SGregory Neil Shapiro 						flush_error();
488b4662009SGregory Neil Shapiro 						continue;
489b4662009SGregory Neil Shapiro 					}
490c2aa98e2SPeter Wemm 					p = strchr(rcpt_addr[i], '+');
491c2aa98e2SPeter Wemm 					if (p != NULL)
492b4662009SGregory Neil Shapiro 						*p = '\0';
493b4662009SGregory Neil Shapiro 					deliver(msgfd, rcpt_addr[i]);
494c2aa98e2SPeter Wemm 				}
495b4662009SGregory Neil Shapiro 				if (msgfd >= 0)
4963299c2f1SGregory Neil Shapiro 					(void) close(msgfd);
497c2aa98e2SPeter Wemm 				goto rset;
498c2aa98e2SPeter Wemm 			}
499c2aa98e2SPeter Wemm 			goto syntaxerr;
5003299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5013299c2f1SGregory Neil Shapiro 			break;
502c2aa98e2SPeter Wemm 
503c2aa98e2SPeter Wemm 		  case 'l':
504c2aa98e2SPeter Wemm 		  case 'L':
50512ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "lhlo ", 5) == 0)
5063299c2f1SGregory Neil Shapiro 			{
5073299c2f1SGregory Neil Shapiro 				/* check for duplicate per RFC 1651 4.2 */
5083299c2f1SGregory Neil Shapiro 				if (gotlhlo)
5093299c2f1SGregory Neil Shapiro 				{
510b4662009SGregory Neil Shapiro 					mailerr("503", "%s Duplicate LHLO",
511c2aa98e2SPeter Wemm 					       myhostname);
512c2aa98e2SPeter Wemm 					continue;
513c2aa98e2SPeter Wemm 				}
51412ed1c7cSGregory Neil Shapiro 				gotlhlo = true;
5153299c2f1SGregory Neil Shapiro 				printf("250-%s\r\n", myhostname);
5163299c2f1SGregory Neil Shapiro 				if (EightBitMime)
5173299c2f1SGregory Neil Shapiro 					printf("250-8BITMIME\r\n");
5183299c2f1SGregory Neil Shapiro 				printf("250-ENHANCEDSTATUSCODES\r\n");
5193299c2f1SGregory Neil Shapiro 				printf("250 PIPELINING\r\n");
5203299c2f1SGregory Neil Shapiro 				continue;
5213299c2f1SGregory Neil Shapiro 			}
522c2aa98e2SPeter Wemm 			goto syntaxerr;
5233299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5243299c2f1SGregory Neil Shapiro 			break;
525c2aa98e2SPeter Wemm 
526c2aa98e2SPeter Wemm 		  case 'm':
527c2aa98e2SPeter Wemm 		  case 'M':
52812ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "mail ", 5) == 0)
5293299c2f1SGregory Neil Shapiro 			{
5303299c2f1SGregory Neil Shapiro 				if (return_path != NULL)
5313299c2f1SGregory Neil Shapiro 				{
532b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1",
533b4662009SGregory Neil Shapiro 						"Nested MAIL command");
534c2aa98e2SPeter Wemm 					continue;
535c2aa98e2SPeter Wemm 				}
53612ed1c7cSGregory Neil Shapiro 				if (sm_strncasecmp(buf + 5, "from:", 5) != 0 ||
5373299c2f1SGregory Neil Shapiro 				    ((return_path = parseaddr(buf + 10,
53812ed1c7cSGregory Neil Shapiro 							      false)) == NULL))
5393299c2f1SGregory Neil Shapiro 				{
540b4662009SGregory Neil Shapiro 					mailerr("501 5.5.4",
541b4662009SGregory Neil Shapiro 						"Syntax error in parameters");
542c2aa98e2SPeter Wemm 					continue;
543c2aa98e2SPeter Wemm 				}
544b4662009SGregory Neil Shapiro 				printf("250 2.5.0 Ok\r\n");
545c2aa98e2SPeter Wemm 				continue;
546c2aa98e2SPeter Wemm 			}
547c2aa98e2SPeter Wemm 			goto syntaxerr;
5483299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5493299c2f1SGregory Neil Shapiro 			break;
550c2aa98e2SPeter Wemm 
551c2aa98e2SPeter Wemm 		  case 'n':
552c2aa98e2SPeter Wemm 		  case 'N':
55312ed1c7cSGregory Neil Shapiro 			if (sm_strcasecmp(buf, "noop") == 0)
5543299c2f1SGregory Neil Shapiro 			{
555b4662009SGregory Neil Shapiro 				printf("250 2.0.0 Ok\r\n");
556c2aa98e2SPeter Wemm 				continue;
557c2aa98e2SPeter Wemm 			}
558c2aa98e2SPeter Wemm 			goto syntaxerr;
5593299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5603299c2f1SGregory Neil Shapiro 			break;
561c2aa98e2SPeter Wemm 
562c2aa98e2SPeter Wemm 		  case 'q':
563c2aa98e2SPeter Wemm 		  case 'Q':
56412ed1c7cSGregory Neil Shapiro 			if (sm_strcasecmp(buf, "quit") == 0)
5653299c2f1SGregory Neil Shapiro 			{
566b4662009SGregory Neil Shapiro 				printf("221 2.0.0 Bye\r\n");
567c2aa98e2SPeter Wemm 				exit(EX_OK);
568c2aa98e2SPeter Wemm 			}
569c2aa98e2SPeter Wemm 			goto syntaxerr;
5703299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5713299c2f1SGregory Neil Shapiro 			break;
572c2aa98e2SPeter Wemm 
573c2aa98e2SPeter Wemm 		  case 'r':
574c2aa98e2SPeter Wemm 		  case 'R':
57512ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "rcpt ", 5) == 0)
5763299c2f1SGregory Neil Shapiro 			{
5773299c2f1SGregory Neil Shapiro 				if (return_path == NULL)
5783299c2f1SGregory Neil Shapiro 				{
579b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1",
580b4662009SGregory Neil Shapiro 						"Need MAIL command");
581c2aa98e2SPeter Wemm 					continue;
582c2aa98e2SPeter Wemm 				}
5833299c2f1SGregory Neil Shapiro 				if (rcpt_num >= rcpt_alloc)
5843299c2f1SGregory Neil Shapiro 				{
585c2aa98e2SPeter Wemm 					rcpt_alloc += RCPT_GROW;
586c2aa98e2SPeter Wemm 					rcpt_addr = (char **)
5873299c2f1SGregory Neil Shapiro 						REALLOC((char *) rcpt_addr,
5883299c2f1SGregory Neil Shapiro 							rcpt_alloc *
5893299c2f1SGregory Neil Shapiro 							sizeof(char **));
5903299c2f1SGregory Neil Shapiro 					if (rcpt_addr == NULL)
5913299c2f1SGregory Neil Shapiro 					{
592b4662009SGregory Neil Shapiro 						mailerr("421 4.3.0",
593b4662009SGregory Neil Shapiro 							"Memory exhausted");
594c2aa98e2SPeter Wemm 						exit(EX_TEMPFAIL);
595c2aa98e2SPeter Wemm 					}
596c2aa98e2SPeter Wemm 				}
59712ed1c7cSGregory Neil Shapiro 				if (sm_strncasecmp(buf + 5, "to:", 3) != 0 ||
5983299c2f1SGregory Neil Shapiro 				    ((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
59912ed1c7cSGregory Neil Shapiro 								      true)) == NULL))
6003299c2f1SGregory Neil Shapiro 				{
601b4662009SGregory Neil Shapiro 					mailerr("501 5.5.4",
602b4662009SGregory Neil Shapiro 						"Syntax error in parameters");
603c2aa98e2SPeter Wemm 					continue;
604c2aa98e2SPeter Wemm 				}
605b4662009SGregory Neil Shapiro 				err = process_recipient(rcpt_addr[rcpt_num]);
606b4662009SGregory Neil Shapiro 				if (err != NULL)
6073299c2f1SGregory Neil Shapiro 				{
608b4662009SGregory Neil Shapiro 					mailerr(NULL, "%s", err);
609c2aa98e2SPeter Wemm 					continue;
610c2aa98e2SPeter Wemm 				}
611c2aa98e2SPeter Wemm 				rcpt_num++;
612b4662009SGregory Neil Shapiro 				printf("250 2.1.5 Ok\r\n");
613c2aa98e2SPeter Wemm 				continue;
614c2aa98e2SPeter Wemm 			}
61512ed1c7cSGregory Neil Shapiro 			else if (sm_strcasecmp(buf, "rset") == 0)
6163299c2f1SGregory Neil Shapiro 			{
617b4662009SGregory Neil Shapiro 				printf("250 2.0.0 Ok\r\n");
618c2aa98e2SPeter Wemm 
619c2aa98e2SPeter Wemm rset:
620c46d91b7SGregory Neil Shapiro 				while (rcpt_num > 0)
621c2aa98e2SPeter Wemm 					free(rcpt_addr[--rcpt_num]);
622c2aa98e2SPeter Wemm 				if (return_path != NULL)
623c2aa98e2SPeter Wemm 					free(return_path);
624c2aa98e2SPeter Wemm 				return_path = NULL;
625c2aa98e2SPeter Wemm 				continue;
626c2aa98e2SPeter Wemm 			}
627c2aa98e2SPeter Wemm 			goto syntaxerr;
6283299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6293299c2f1SGregory Neil Shapiro 			break;
630c2aa98e2SPeter Wemm 
631c2aa98e2SPeter Wemm 		  case 'v':
632c2aa98e2SPeter Wemm 		  case 'V':
63312ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "vrfy ", 5) == 0)
6343299c2f1SGregory Neil Shapiro 			{
635b4662009SGregory Neil Shapiro 				printf("252 2.3.3 Try RCPT to attempt delivery\r\n");
636c2aa98e2SPeter Wemm 				continue;
637c2aa98e2SPeter Wemm 			}
638c2aa98e2SPeter Wemm 			goto syntaxerr;
6393299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6403299c2f1SGregory Neil Shapiro 			break;
641c2aa98e2SPeter Wemm 
642c2aa98e2SPeter Wemm 		  default:
643c2aa98e2SPeter Wemm   syntaxerr:
644b4662009SGregory Neil Shapiro 			mailerr("500 5.5.2", "Syntax error");
645c2aa98e2SPeter Wemm 			continue;
6463299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6473299c2f1SGregory Neil Shapiro 			break;
648c2aa98e2SPeter Wemm 		}
649c2aa98e2SPeter Wemm 	}
650c2aa98e2SPeter Wemm }
651c2aa98e2SPeter Wemm 
652c2aa98e2SPeter Wemm int
65312ed1c7cSGregory Neil Shapiro store(from, inbody)
654c2aa98e2SPeter Wemm 	char *from;
655b4662009SGregory Neil Shapiro 	bool *inbody;
656c2aa98e2SPeter Wemm {
65776b7bf71SPeter Wemm 	FILE *fp = NULL;
658c2aa98e2SPeter Wemm 	time_t tval;
65912ed1c7cSGregory Neil Shapiro 	bool eline;		/* previous line was empty */
66012ed1c7cSGregory Neil Shapiro 	bool fullline = true;	/* current line is terminated */
6613299c2f1SGregory Neil Shapiro 	bool prevfl;		/* previous line was terminated */
662c2aa98e2SPeter Wemm 	char line[2048];
6633299c2f1SGregory Neil Shapiro 	int fd;
664c2aa98e2SPeter Wemm 	char tmpbuf[sizeof _PATH_LOCTMP + 1];
665c2aa98e2SPeter Wemm 
666b4662009SGregory Neil Shapiro 	if (inbody != NULL)
66712ed1c7cSGregory Neil Shapiro 		*inbody = false;
668b4662009SGregory Neil Shapiro 
6693299c2f1SGregory Neil Shapiro 	(void) umask(0077);
67012ed1c7cSGregory Neil Shapiro 	(void) sm_strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
671b4662009SGregory Neil Shapiro 	if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL)
6723299c2f1SGregory Neil Shapiro 	{
6732ef40764SGregory Neil Shapiro 		if (fd >= 0)
6742ef40764SGregory Neil Shapiro 			(void) close(fd);
675b4662009SGregory Neil Shapiro 		mailerr("451 4.3.0", "Unable to open temporary file");
676c2aa98e2SPeter Wemm 		return -1;
6773299c2f1SGregory Neil Shapiro 	}
678c2aa98e2SPeter Wemm 	(void) unlink(tmpbuf);
679c2aa98e2SPeter Wemm 
6803299c2f1SGregory Neil Shapiro 	if (LMTPMode)
6813299c2f1SGregory Neil Shapiro 	{
682b4662009SGregory Neil Shapiro 		printf("354 Go ahead\r\n");
6833299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
684c2aa98e2SPeter Wemm 	}
685b4662009SGregory Neil Shapiro 	if (inbody != NULL)
68612ed1c7cSGregory Neil Shapiro 		*inbody = true;
687c2aa98e2SPeter Wemm 
688c2aa98e2SPeter Wemm 	(void) time(&tval);
689c2aa98e2SPeter Wemm 	(void) fprintf(fp, "From %s %s", from, ctime(&tval));
690c2aa98e2SPeter Wemm 
6913299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
6923299c2f1SGregory Neil Shapiro 	HeaderLength = 0;
6933299c2f1SGregory Neil Shapiro 	BodyLength = -1;
6943299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
6953299c2f1SGregory Neil Shapiro 
696c2aa98e2SPeter Wemm 	line[0] = '\0';
69712ed1c7cSGregory Neil Shapiro 	eline = true;
6983299c2f1SGregory Neil Shapiro 	while (fgets(line, sizeof(line), stdin) != (char *) NULL)
6993299c2f1SGregory Neil Shapiro 	{
7003299c2f1SGregory Neil Shapiro 		size_t line_len = 0;
7013299c2f1SGregory Neil Shapiro 		int peek;
70276b7bf71SPeter Wemm 
7033299c2f1SGregory Neil Shapiro 		prevfl = fullline;	/* preserve state of previous line */
7043299c2f1SGregory Neil Shapiro 		while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
7053299c2f1SGregory Neil Shapiro 			line_len++;
7063299c2f1SGregory Neil Shapiro 		line_len++;
70776b7bf71SPeter Wemm 
7083299c2f1SGregory Neil Shapiro 		/* Check for dot-stuffing */
709b4662009SGregory Neil Shapiro 		if (prevfl && LMTPMode && line[0] == '.')
7103299c2f1SGregory Neil Shapiro 		{
7113299c2f1SGregory Neil Shapiro 			if (line[1] == '\n' ||
7123299c2f1SGregory Neil Shapiro 			    (line[1] == '\r' && line[2] == '\n'))
713c2aa98e2SPeter Wemm 				goto lmtpdot;
7143299c2f1SGregory Neil Shapiro 			memcpy(line, line + 1, line_len);
7153299c2f1SGregory Neil Shapiro 			line_len--;
716c2aa98e2SPeter Wemm 		}
7173299c2f1SGregory Neil Shapiro 
7183299c2f1SGregory Neil Shapiro 		/* Check to see if we have the full line from fgets() */
71912ed1c7cSGregory Neil Shapiro 		fullline = false;
7203299c2f1SGregory Neil Shapiro 		if (line_len > 0)
7213299c2f1SGregory Neil Shapiro 		{
7223299c2f1SGregory Neil Shapiro 			if (line[line_len - 1] == '\n')
7233299c2f1SGregory Neil Shapiro 			{
7243299c2f1SGregory Neil Shapiro 				if (line_len >= 2 &&
7253299c2f1SGregory Neil Shapiro 				    line[line_len - 2] == '\r')
7263299c2f1SGregory Neil Shapiro 				{
7273299c2f1SGregory Neil Shapiro 					line[line_len - 2] = '\n';
7283299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\0';
7293299c2f1SGregory Neil Shapiro 					line_len--;
7303299c2f1SGregory Neil Shapiro 				}
73112ed1c7cSGregory Neil Shapiro 				fullline = true;
7323299c2f1SGregory Neil Shapiro 			}
7333299c2f1SGregory Neil Shapiro 			else if (line[line_len - 1] == '\r')
7343299c2f1SGregory Neil Shapiro 			{
7353299c2f1SGregory Neil Shapiro 				/* Did we just miss the CRLF? */
7363299c2f1SGregory Neil Shapiro 				peek = fgetc(stdin);
7373299c2f1SGregory Neil Shapiro 				if (peek == '\n')
7383299c2f1SGregory Neil Shapiro 				{
7393299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\n';
74012ed1c7cSGregory Neil Shapiro 					fullline = true;
7413299c2f1SGregory Neil Shapiro 				}
7423299c2f1SGregory Neil Shapiro 				else
7433299c2f1SGregory Neil Shapiro 					(void) ungetc(peek, stdin);
7443299c2f1SGregory Neil Shapiro 			}
7453299c2f1SGregory Neil Shapiro 		}
7463299c2f1SGregory Neil Shapiro 		else
74712ed1c7cSGregory Neil Shapiro 			fullline = true;
7483299c2f1SGregory Neil Shapiro 
7493299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
7503299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n' && HeaderLength == 0)
7513299c2f1SGregory Neil Shapiro 		{
75212ed1c7cSGregory Neil Shapiro 			eline = false;
753b4662009SGregory Neil Shapiro 			if (fp != NULL)
7543299c2f1SGregory Neil Shapiro 				HeaderLength = ftell(fp);
7553299c2f1SGregory Neil Shapiro 			if (HeaderLength <= 0)
7563299c2f1SGregory Neil Shapiro 			{
7573299c2f1SGregory Neil Shapiro 				/*
7583299c2f1SGregory Neil Shapiro 				**  shouldn't happen, unless ftell() is
7593299c2f1SGregory Neil Shapiro 				**  badly broken
7603299c2f1SGregory Neil Shapiro 				*/
7613299c2f1SGregory Neil Shapiro 
7623299c2f1SGregory Neil Shapiro 				HeaderLength = -1;
7633299c2f1SGregory Neil Shapiro 			}
7643299c2f1SGregory Neil Shapiro 		}
7653299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
7663299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n')
76712ed1c7cSGregory Neil Shapiro 			eline = true;
7683299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
7693299c2f1SGregory Neil Shapiro 		else
7703299c2f1SGregory Neil Shapiro 		{
771c2aa98e2SPeter Wemm 			if (eline && line[0] == 'F' &&
772b4662009SGregory Neil Shapiro 			    fp != NULL &&
773c2aa98e2SPeter Wemm 			    !memcmp(line, "From ", 5))
774c2aa98e2SPeter Wemm 				(void) putc('>', fp);
77512ed1c7cSGregory Neil Shapiro 			eline = false;
7763299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
7773299c2f1SGregory Neil Shapiro 			/* discard existing "Content-Length:" headers */
7783299c2f1SGregory Neil Shapiro 			if (prevfl && HeaderLength == 0 &&
7793299c2f1SGregory Neil Shapiro 			    (line[0] == 'C' || line[0] == 'c') &&
78012ed1c7cSGregory Neil Shapiro 			    sm_strncasecmp(line, ContentHdr, 15) == 0)
7813299c2f1SGregory Neil Shapiro 			{
7823299c2f1SGregory Neil Shapiro 				/*
7833299c2f1SGregory Neil Shapiro 				**  be paranoid: clear the line
7843299c2f1SGregory Neil Shapiro 				**  so no "wrong matches" may occur later
7853299c2f1SGregory Neil Shapiro 				*/
7863299c2f1SGregory Neil Shapiro 				line[0] = '\0';
7873299c2f1SGregory Neil Shapiro 				continue;
788c2aa98e2SPeter Wemm 			}
7893299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
7903299c2f1SGregory Neil Shapiro 
7913299c2f1SGregory Neil Shapiro 		}
792b4662009SGregory Neil Shapiro 		if (fp != NULL)
793b4662009SGregory Neil Shapiro 		{
7943299c2f1SGregory Neil Shapiro 			(void) fwrite(line, sizeof(char), line_len, fp);
7953299c2f1SGregory Neil Shapiro 			if (ferror(fp))
7963299c2f1SGregory Neil Shapiro 			{
79776b7bf71SPeter Wemm 				mailerr("451 4.3.0",
798b4662009SGregory Neil Shapiro 					"Temporary file write error");
7993299c2f1SGregory Neil Shapiro 				(void) fclose(fp);
800b4662009SGregory Neil Shapiro 				fp = NULL;
801b4662009SGregory Neil Shapiro 				continue;
802c2aa98e2SPeter Wemm 			}
803c2aa98e2SPeter Wemm 		}
804c2aa98e2SPeter Wemm 	}
805c2aa98e2SPeter Wemm 
806b4662009SGregory Neil Shapiro 	/* check if an error occurred */
807b4662009SGregory Neil Shapiro 	if (fp == NULL)
808b4662009SGregory Neil Shapiro 		return -1;
809b4662009SGregory Neil Shapiro 
810b4662009SGregory Neil Shapiro 	if (LMTPMode)
8113299c2f1SGregory Neil Shapiro 	{
812c2aa98e2SPeter Wemm 		/* Got a premature EOF -- toss message and exit */
813c2aa98e2SPeter Wemm 		exit(EX_OK);
814c2aa98e2SPeter Wemm 	}
815c2aa98e2SPeter Wemm 
816c2aa98e2SPeter Wemm 	/* If message not newline terminated, need an extra. */
817b4662009SGregory Neil Shapiro 	if (fp != NULL && strchr(line, '\n') == NULL)
818c2aa98e2SPeter Wemm 		(void) putc('\n', fp);
819c2aa98e2SPeter Wemm 
820c2aa98e2SPeter Wemm   lmtpdot:
821c2aa98e2SPeter Wemm 
8223299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
823b4662009SGregory Neil Shapiro 	if (fp != NULL)
8243299c2f1SGregory Neil Shapiro 		BodyLength = ftell(fp);
8253299c2f1SGregory Neil Shapiro 	if (HeaderLength == 0 && BodyLength > 0)	/* empty body */
8263299c2f1SGregory Neil Shapiro 	{
8273299c2f1SGregory Neil Shapiro 		HeaderLength = BodyLength;
8283299c2f1SGregory Neil Shapiro 		BodyLength = 0;
8293299c2f1SGregory Neil Shapiro 	}
8303299c2f1SGregory Neil Shapiro 	else
8313299c2f1SGregory Neil Shapiro 		BodyLength = BodyLength - HeaderLength - 1 ;
8323299c2f1SGregory Neil Shapiro 
8333299c2f1SGregory Neil Shapiro 	if (HeaderLength > 0 && BodyLength >= 0)
8343299c2f1SGregory Neil Shapiro 	{
83512ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(line, sizeof line, "%lld\n",
83612ed1c7cSGregory Neil Shapiro 				   (LONGLONG_T) BodyLength);
83712ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(&ContentHdr[16], line,
83812ed1c7cSGregory Neil Shapiro 				  sizeof(ContentHdr) - 16);
8393299c2f1SGregory Neil Shapiro 	}
8403299c2f1SGregory Neil Shapiro 	else
8413299c2f1SGregory Neil Shapiro 		BodyLength = -1;	/* Something is wrong here */
8423299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
8433299c2f1SGregory Neil Shapiro 
844c2aa98e2SPeter Wemm 	/* Output a newline; note, empty messages are allowed. */
845b4662009SGregory Neil Shapiro 	if (fp != NULL)
846c2aa98e2SPeter Wemm 		(void) putc('\n', fp);
847c2aa98e2SPeter Wemm 
848b4662009SGregory Neil Shapiro 	if (fp == NULL || fflush(fp) == EOF || ferror(fp) != 0)
8493299c2f1SGregory Neil Shapiro 	{
850b4662009SGregory Neil Shapiro 		mailerr("451 4.3.0", "Temporary file write error");
851b4662009SGregory Neil Shapiro 		if (fp != NULL)
8523299c2f1SGregory Neil Shapiro 			(void) fclose(fp);
853c2aa98e2SPeter Wemm 		return -1;
8543299c2f1SGregory Neil Shapiro 	}
8553299c2f1SGregory Neil Shapiro 	return fd;
856c2aa98e2SPeter Wemm }
857c2aa98e2SPeter Wemm 
858c2aa98e2SPeter Wemm void
859b4662009SGregory Neil Shapiro deliver(fd, name)
860c2aa98e2SPeter Wemm 	int fd;
861c2aa98e2SPeter Wemm 	char *name;
862c2aa98e2SPeter Wemm {
8633299c2f1SGregory Neil Shapiro 	struct stat fsb;
8643299c2f1SGregory Neil Shapiro 	struct stat sb;
8653299c2f1SGregory Neil Shapiro 	char path[MAXPATHLEN];
866c46d91b7SGregory Neil Shapiro 	int mbfd = -1, nr = 0, nw, off;
86712ed1c7cSGregory Neil Shapiro 	int exitval;
868c2aa98e2SPeter Wemm 	char *p;
869b4662009SGregory Neil Shapiro 	char *errcode;
870c2aa98e2SPeter Wemm 	off_t curoff;
8713299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
8723299c2f1SGregory Neil Shapiro 	off_t headerbytes;
8733299c2f1SGregory Neil Shapiro 	int readamount;
8743299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
8753299c2f1SGregory Neil Shapiro 	char biffmsg[100], buf[8 * 1024];
87612ed1c7cSGregory Neil Shapiro 	SM_MBDB_T user;
8773299c2f1SGregory Neil Shapiro 
878c2aa98e2SPeter Wemm 	/*
8793299c2f1SGregory Neil Shapiro 	**  Disallow delivery to unknown names -- special mailboxes can be
8803299c2f1SGregory Neil Shapiro 	**  handled in the sendmail aliases file.
881c2aa98e2SPeter Wemm 	*/
882b4662009SGregory Neil Shapiro 
88312ed1c7cSGregory Neil Shapiro 	exitval = sm_mbdb_lookup(name, &user);
88412ed1c7cSGregory Neil Shapiro 	switch (exitval)
8853299c2f1SGregory Neil Shapiro 	{
88612ed1c7cSGregory Neil Shapiro 	  case EX_OK:
88712ed1c7cSGregory Neil Shapiro 		break;
88812ed1c7cSGregory Neil Shapiro 
88912ed1c7cSGregory Neil Shapiro 	  case EX_NOUSER:
89012ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
89112ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: User unknown", name);
89212ed1c7cSGregory Neil Shapiro 		break;
89312ed1c7cSGregory Neil Shapiro 
89412ed1c7cSGregory Neil Shapiro 	  case EX_TEMPFAIL:
89512ed1c7cSGregory Neil Shapiro 		mailerr("451 4.3.0", "%s: User database failure; retry later",
89612ed1c7cSGregory Neil Shapiro 			name);
89712ed1c7cSGregory Neil Shapiro 		break;
89812ed1c7cSGregory Neil Shapiro 
89912ed1c7cSGregory Neil Shapiro 	  default:
90012ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
90112ed1c7cSGregory Neil Shapiro 		mailerr("550 5.3.0", "%s: User database failure", name);
90212ed1c7cSGregory Neil Shapiro 		break;
903c2aa98e2SPeter Wemm 	}
90412ed1c7cSGregory Neil Shapiro 
90512ed1c7cSGregory Neil Shapiro 	if (exitval != EX_OK)
90612ed1c7cSGregory Neil Shapiro 	{
90712ed1c7cSGregory Neil Shapiro 		if (ExitVal != EX_TEMPFAIL)
90812ed1c7cSGregory Neil Shapiro 			ExitVal = exitval;
909c2aa98e2SPeter Wemm 		return;
910c2aa98e2SPeter Wemm 	}
91112ed1c7cSGregory Neil Shapiro 
912c2aa98e2SPeter Wemm 	endpwent();
913c2aa98e2SPeter Wemm 
914c2aa98e2SPeter Wemm 	/*
9153299c2f1SGregory Neil Shapiro 	**  Keep name reasonably short to avoid buffer overruns.
9163299c2f1SGregory Neil Shapiro 	**	This isn't necessary on BSD because of the proper
9173299c2f1SGregory Neil Shapiro 	**	definition of snprintf(), but it can cause problems
9183299c2f1SGregory Neil Shapiro 	**	on other systems.
9193299c2f1SGregory Neil Shapiro 	**  Also, clear out any bogus characters.
920c2aa98e2SPeter Wemm 	*/
921c2aa98e2SPeter Wemm 
922c2aa98e2SPeter Wemm 	if (strlen(name) > 40)
923c2aa98e2SPeter Wemm 		name[40] = '\0';
924c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
925c2aa98e2SPeter Wemm 	{
926c2aa98e2SPeter Wemm 		if (!isascii(*p))
927c2aa98e2SPeter Wemm 			*p &= 0x7f;
928c2aa98e2SPeter Wemm 		else if (!isprint(*p))
929c2aa98e2SPeter Wemm 			*p = '.';
930c2aa98e2SPeter Wemm 	}
931c2aa98e2SPeter Wemm 
9323299c2f1SGregory Neil Shapiro 
93312ed1c7cSGregory Neil Shapiro 	if (HomeMailFile == NULL)
93412ed1c7cSGregory Neil Shapiro 	{
93512ed1c7cSGregory Neil Shapiro 		if (sm_snprintf(path, sizeof(path), "%s/%s",
93612ed1c7cSGregory Neil Shapiro 				_PATH_MAILDIR, name) >= sizeof(path))
93712ed1c7cSGregory Neil Shapiro 		{
93812ed1c7cSGregory Neil Shapiro 			exitval = EX_UNAVAILABLE;
93912ed1c7cSGregory Neil Shapiro 			mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
94012ed1c7cSGregory Neil Shapiro 			return;
94112ed1c7cSGregory Neil Shapiro 		}
94212ed1c7cSGregory Neil Shapiro 	}
94312ed1c7cSGregory Neil Shapiro 	else if (*user.mbdb_homedir == '\0')
94412ed1c7cSGregory Neil Shapiro 	{
94512ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
94612ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: User missing home directory", name);
94712ed1c7cSGregory Neil Shapiro 		return;
94812ed1c7cSGregory Neil Shapiro 	}
94912ed1c7cSGregory Neil Shapiro 	else if (sm_snprintf(path, sizeof(path), "%s/%s",
95012ed1c7cSGregory Neil Shapiro 			     user.mbdb_homedir, HomeMailFile) >= sizeof(path))
95112ed1c7cSGregory Neil Shapiro 	{
95212ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
95312ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
95412ed1c7cSGregory Neil Shapiro 		return;
95512ed1c7cSGregory Neil Shapiro 	}
956c2aa98e2SPeter Wemm 
9573299c2f1SGregory Neil Shapiro 
958c2aa98e2SPeter Wemm 	/*
9593299c2f1SGregory Neil Shapiro 	**  If the mailbox is linked or a symlink, fail.  There's an obvious
9603299c2f1SGregory Neil Shapiro 	**  race here, that the file was replaced with a symbolic link after
9613299c2f1SGregory Neil Shapiro 	**  the lstat returned, but before the open.  We attempt to detect
9623299c2f1SGregory Neil Shapiro 	**  this by comparing the original stat information and information
9633299c2f1SGregory Neil Shapiro 	**  returned by an fstat of the file descriptor returned by the open.
9643299c2f1SGregory Neil Shapiro 	**
9653299c2f1SGregory Neil Shapiro 	**  NB: this is a symptom of a larger problem, that the mail spooling
9663299c2f1SGregory Neil Shapiro 	**  directory is writeable by the wrong users.  If that directory is
9673299c2f1SGregory Neil Shapiro 	**  writeable, system security is compromised for other reasons, and
9683299c2f1SGregory Neil Shapiro 	**  it cannot be fixed here.
9693299c2f1SGregory Neil Shapiro 	**
9703299c2f1SGregory Neil Shapiro 	**  If we created the mailbox, set the owner/group.  If that fails,
9713299c2f1SGregory Neil Shapiro 	**  just return.  Another process may have already opened it, so we
9723299c2f1SGregory Neil Shapiro 	**  can't unlink it.  Historically, binmail set the owner/group at
9733299c2f1SGregory Neil Shapiro 	**  each mail delivery.  We no longer do this, assuming that if the
9743299c2f1SGregory Neil Shapiro 	**  ownership or permissions were changed there was a reason.
9753299c2f1SGregory Neil Shapiro 	**
9763299c2f1SGregory Neil Shapiro 	**  XXX
9773299c2f1SGregory Neil Shapiro 	**  open(2) should support flock'ing the file.
978c2aa98e2SPeter Wemm 	*/
9793299c2f1SGregory Neil Shapiro 
980c2aa98e2SPeter Wemm tryagain:
9813299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
9823299c2f1SGregory Neil Shapiro 	p = name;
9833299c2f1SGregory Neil Shapiro #else /* MAILLOCK */
9843299c2f1SGregory Neil Shapiro 	p = path;
9853299c2f1SGregory Neil Shapiro #endif /* MAILLOCK */
9863299c2f1SGregory Neil Shapiro 	if ((off = lockmbox(p)) != 0)
9873299c2f1SGregory Neil Shapiro 	{
9883299c2f1SGregory Neil Shapiro 		if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
9893299c2f1SGregory Neil Shapiro 		{
9903299c2f1SGregory Neil Shapiro 			ExitVal = EX_TEMPFAIL;
991b4662009SGregory Neil Shapiro 			errcode = "451 4.3.0";
9923299c2f1SGregory Neil Shapiro 		}
9933299c2f1SGregory Neil Shapiro 		else
994b4662009SGregory Neil Shapiro 			errcode = "551 5.3.0";
995b4662009SGregory Neil Shapiro 
996b4662009SGregory Neil Shapiro 		mailerr(errcode, "lockmailbox %s failed; error code %d %s",
99712ed1c7cSGregory Neil Shapiro 			p, off, errno > 0 ? sm_errstring(errno) : "");
9983299c2f1SGregory Neil Shapiro 		return;
9993299c2f1SGregory Neil Shapiro 	}
10003299c2f1SGregory Neil Shapiro 
1001c2aa98e2SPeter Wemm 	if (lstat(path, &sb) < 0)
1002c2aa98e2SPeter Wemm 	{
10033299c2f1SGregory Neil Shapiro 		int save_errno;
10043299c2f1SGregory Neil Shapiro 		int mode = S_IRUSR|S_IWUSR;
100512ed1c7cSGregory Neil Shapiro 		gid_t gid = user.mbdb_gid;
10063299c2f1SGregory Neil Shapiro 
10073299c2f1SGregory Neil Shapiro #ifdef MAILGID
10083299c2f1SGregory Neil Shapiro 		(void) umask(0007);
10093299c2f1SGregory Neil Shapiro 		gid = MAILGID;
10103299c2f1SGregory Neil Shapiro 		mode |= S_IRGRP|S_IWGRP;
10113299c2f1SGregory Neil Shapiro #endif /* MAILGID */
10123299c2f1SGregory Neil Shapiro 
1013d995d2baSGregory Neil Shapiro 		mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE,
1014d995d2baSGregory Neil Shapiro 			    mode);
10153299c2f1SGregory Neil Shapiro 		save_errno = errno;
10163299c2f1SGregory Neil Shapiro 
10173299c2f1SGregory Neil Shapiro 		if (lstat(path, &sb) < 0)
10183299c2f1SGregory Neil Shapiro 		{
10193299c2f1SGregory Neil Shapiro 			ExitVal = EX_CANTCREAT;
102076b7bf71SPeter Wemm 			mailerr("550 5.2.0",
102176b7bf71SPeter Wemm 				"%s: lstat: file changed after open", path);
1022c2aa98e2SPeter Wemm 			goto err1;
1023c2aa98e2SPeter Wemm 		}
1024b4662009SGregory Neil Shapiro 		if (mbfd < 0)
10253299c2f1SGregory Neil Shapiro 		{
10263299c2f1SGregory Neil Shapiro 			if (save_errno == EEXIST)
1027c2aa98e2SPeter Wemm 				goto tryagain;
1028d995d2baSGregory Neil Shapiro 
1029d995d2baSGregory Neil Shapiro 			/* open failed, don't try again */
1030d995d2baSGregory Neil Shapiro 			mailerr("450 4.2.0", "%s: %s", path,
103112ed1c7cSGregory Neil Shapiro 				sm_errstring(save_errno));
1032d995d2baSGregory Neil Shapiro 			goto err0;
10333299c2f1SGregory Neil Shapiro 		}
103412ed1c7cSGregory Neil Shapiro 		else if (fchown(mbfd, user.mbdb_uid, gid) < 0)
10353299c2f1SGregory Neil Shapiro 		{
1036c2aa98e2SPeter Wemm 			mailerr("451 4.3.0", "chown %u.%u: %s",
103712ed1c7cSGregory Neil Shapiro 				user.mbdb_uid, gid, name);
1038c2aa98e2SPeter Wemm 			goto err1;
1039c2aa98e2SPeter Wemm 		}
1040d995d2baSGregory Neil Shapiro 		else
1041d995d2baSGregory Neil Shapiro 		{
1042d995d2baSGregory Neil Shapiro 			/*
1043d995d2baSGregory Neil Shapiro 			**  open() was successful, now close it so can
1044d995d2baSGregory Neil Shapiro 			**  be opened as the right owner again.
1045d995d2baSGregory Neil Shapiro 			**  Paranoia: reset mbdf since the file descriptor
1046d995d2baSGregory Neil Shapiro 			**  is no longer valid; better safe than sorry.
1047d995d2baSGregory Neil Shapiro 			*/
1048d995d2baSGregory Neil Shapiro 
104912ed1c7cSGregory Neil Shapiro 			sb.st_uid = user.mbdb_uid;
1050d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
1051d995d2baSGregory Neil Shapiro 			mbfd = -1;
1052d995d2baSGregory Neil Shapiro 		}
10533299c2f1SGregory Neil Shapiro 	}
1054f9218d3dSGregory Neil Shapiro 	else if (sb.st_nlink != 1)
1055f9218d3dSGregory Neil Shapiro 	{
1056f9218d3dSGregory Neil Shapiro 		mailerr("550 5.2.0", "%s: too many links", path);
1057f9218d3dSGregory Neil Shapiro 		goto err0;
1058f9218d3dSGregory Neil Shapiro 	}
1059f9218d3dSGregory Neil Shapiro 	else if (!S_ISREG(sb.st_mode))
10603299c2f1SGregory Neil Shapiro 	{
1061c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: irregular file", path);
1062c2aa98e2SPeter Wemm 		goto err0;
10633299c2f1SGregory Neil Shapiro 	}
106412ed1c7cSGregory Neil Shapiro 	else if (sb.st_uid != user.mbdb_uid)
10653299c2f1SGregory Neil Shapiro 	{
10663299c2f1SGregory Neil Shapiro 		ExitVal = EX_CANTCREAT;
1067c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: wrong ownership (%d)",
106812ed1c7cSGregory Neil Shapiro 			path, (int) sb.st_uid);
1069c2aa98e2SPeter Wemm 		goto err0;
1070c2aa98e2SPeter Wemm 	}
1071c2aa98e2SPeter Wemm 
1072d995d2baSGregory Neil Shapiro 	/* change UID for quota checks */
107312ed1c7cSGregory Neil Shapiro 	if (setreuid(0, user.mbdb_uid) < 0)
1074d995d2baSGregory Neil Shapiro 	{
1075d995d2baSGregory Neil Shapiro 		mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
107612ed1c7cSGregory Neil Shapiro 			(int) user.mbdb_uid, sm_errstring(errno),
107712ed1c7cSGregory Neil Shapiro 			(int) getuid(), (int) geteuid());
1078d995d2baSGregory Neil Shapiro 		goto err1;
1079d995d2baSGregory Neil Shapiro 	}
1080d995d2baSGregory Neil Shapiro #ifdef DEBUG
108112ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "new euid = %d\n", (int) geteuid());
1082d995d2baSGregory Neil Shapiro #endif /* DEBUG */
1083d995d2baSGregory Neil Shapiro 	mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0);
1084d995d2baSGregory Neil Shapiro 	if (mbfd < 0)
10853299c2f1SGregory Neil Shapiro 	{
108612ed1c7cSGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
1087c2aa98e2SPeter Wemm 		goto err0;
10883299c2f1SGregory Neil Shapiro 	}
10893299c2f1SGregory Neil Shapiro 	else if (fstat(mbfd, &fsb) < 0 ||
1090c2aa98e2SPeter Wemm 		 fsb.st_nlink != 1 ||
1091c2aa98e2SPeter Wemm 		 sb.st_nlink != 1 ||
1092c2aa98e2SPeter Wemm 		 !S_ISREG(fsb.st_mode) ||
1093c2aa98e2SPeter Wemm 		 sb.st_dev != fsb.st_dev ||
1094c2aa98e2SPeter Wemm 		 sb.st_ino != fsb.st_ino ||
1095c2aa98e2SPeter Wemm # if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
1096c2aa98e2SPeter Wemm 		 sb.st_gen != fsb.st_gen ||
10973299c2f1SGregory Neil Shapiro # endif /* HAS_ST_GEN && 0 */
10983299c2f1SGregory Neil Shapiro 		 sb.st_uid != fsb.st_uid)
10993299c2f1SGregory Neil Shapiro 	{
11003299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
110176b7bf71SPeter Wemm 		mailerr("550 5.2.0", "%s: fstat: file changed after open",
110276b7bf71SPeter Wemm 			path);
1103c2aa98e2SPeter Wemm 		goto err1;
1104c2aa98e2SPeter Wemm 	}
1105c2aa98e2SPeter Wemm 
110612ed1c7cSGregory Neil Shapiro #if 0
110712ed1c7cSGregory Neil Shapiro 	/*
110812ed1c7cSGregory Neil Shapiro 	**  This code could be reused if we decide to add a
110912ed1c7cSGregory Neil Shapiro 	**  per-user quota field to the sm_mbdb interface.
111012ed1c7cSGregory Neil Shapiro 	*/
111112ed1c7cSGregory Neil Shapiro 
111212ed1c7cSGregory Neil Shapiro 	/*
111312ed1c7cSGregory Neil Shapiro 	**  Fail if the user has a quota specified, and delivery of this
111412ed1c7cSGregory Neil Shapiro 	**  message would exceed that quota.  We bounce such failures using
111512ed1c7cSGregory Neil Shapiro 	**  EX_UNAVAILABLE, unless there were internal problems, since
111612ed1c7cSGregory Neil Shapiro 	**  storing immense messages for later retries can cause queueing
111712ed1c7cSGregory Neil Shapiro 	**  issues.
111812ed1c7cSGregory Neil Shapiro 	*/
111912ed1c7cSGregory Neil Shapiro 
112012ed1c7cSGregory Neil Shapiro 	if (ui.quota > 0)
112112ed1c7cSGregory Neil Shapiro 	{
112212ed1c7cSGregory Neil Shapiro 		struct stat dsb;
112312ed1c7cSGregory Neil Shapiro 
112412ed1c7cSGregory Neil Shapiro 		if (fstat(fd, &dsb) < 0)
112512ed1c7cSGregory Neil Shapiro 		{
112612ed1c7cSGregory Neil Shapiro 			ExitVal = EX_TEMPFAIL;
112712ed1c7cSGregory Neil Shapiro 			mailerr("451 4.3.0",
112812ed1c7cSGregory Neil Shapiro 				"%s: fstat: can't stat temporary storage: %s",
112912ed1c7cSGregory Neil Shapiro 				ui.mailspool, sm_errstring(errno));
113012ed1c7cSGregory Neil Shapiro 			goto err1;
113112ed1c7cSGregory Neil Shapiro 		}
113212ed1c7cSGregory Neil Shapiro 
113312ed1c7cSGregory Neil Shapiro 		if (dsb.st_size + sb.st_size + 1 > ui.quota)
113412ed1c7cSGregory Neil Shapiro 		{
113512ed1c7cSGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
113612ed1c7cSGregory Neil Shapiro 			mailerr("551 5.2.2",
113712ed1c7cSGregory Neil Shapiro 				"%s: Mailbox full or quota exceeded",
113812ed1c7cSGregory Neil Shapiro 				ui.mailspool);
113912ed1c7cSGregory Neil Shapiro 			goto err1;
114012ed1c7cSGregory Neil Shapiro 		}
114112ed1c7cSGregory Neil Shapiro 	}
114212ed1c7cSGregory Neil Shapiro #endif /* 0 */
11433299c2f1SGregory Neil Shapiro 
1144c2aa98e2SPeter Wemm 	/* Wait until we can get a lock on the file. */
11453299c2f1SGregory Neil Shapiro 	if (flock(mbfd, LOCK_EX) < 0)
11463299c2f1SGregory Neil Shapiro 	{
114712ed1c7cSGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
1148c2aa98e2SPeter Wemm 		goto err1;
1149c2aa98e2SPeter Wemm 	}
1150c2aa98e2SPeter Wemm 
1151c2aa98e2SPeter Wemm 	/* Get the starting offset of the new message for biff. */
1152c2aa98e2SPeter Wemm 	curoff = lseek(mbfd, (off_t) 0, SEEK_END);
1153518536daSGregory Neil Shapiro 
1154518536daSGregory Neil Shapiro 	if (!nobiff)
1155518536daSGregory Neil Shapiro 	{
115612ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(biffmsg, sizeof(biffmsg), "%s@%lld\n",
115712ed1c7cSGregory Neil Shapiro 				   name, (LONGLONG_T) curoff);
1158d615a192SPeter Wemm 	}
1159c2aa98e2SPeter Wemm 
1160c2aa98e2SPeter Wemm 	/* Copy the message into the file. */
11613299c2f1SGregory Neil Shapiro 	if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1)
11623299c2f1SGregory Neil Shapiro 	{
1163b4662009SGregory Neil Shapiro 		mailerr("450 4.2.0", "Temporary file: %s",
116412ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1165c2aa98e2SPeter Wemm 		goto err1;
1166c2aa98e2SPeter Wemm 	}
1167c2aa98e2SPeter Wemm #ifdef DEBUG
116812ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "before writing: euid = %d\n", (int) geteuid());
11693299c2f1SGregory Neil Shapiro #endif /* DEBUG */
11703299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
11713299c2f1SGregory Neil Shapiro 	headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
11723299c2f1SGregory Neil Shapiro 	for (;;)
11733299c2f1SGregory Neil Shapiro 	{
11743299c2f1SGregory Neil Shapiro 		if (headerbytes == 0)
11753299c2f1SGregory Neil Shapiro 		{
117612ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof buf, "%s", ContentHdr);
11773299c2f1SGregory Neil Shapiro 			nr = strlen(buf);
11783299c2f1SGregory Neil Shapiro 			headerbytes = -1;
11793299c2f1SGregory Neil Shapiro 			readamount = 0;
11803299c2f1SGregory Neil Shapiro 		}
11813299c2f1SGregory Neil Shapiro 		else if (headerbytes > sizeof(buf) || headerbytes < 0)
11823299c2f1SGregory Neil Shapiro 			readamount = sizeof(buf);
11833299c2f1SGregory Neil Shapiro 		else
11843299c2f1SGregory Neil Shapiro 			readamount = headerbytes;
11853299c2f1SGregory Neil Shapiro 		if (readamount != 0)
11863299c2f1SGregory Neil Shapiro 			nr = read(fd, buf, readamount);
11873299c2f1SGregory Neil Shapiro 		if (nr <= 0)
11883299c2f1SGregory Neil Shapiro 			break;
11893299c2f1SGregory Neil Shapiro 		if (headerbytes > 0)
11903299c2f1SGregory Neil Shapiro 			headerbytes -= nr ;
11913299c2f1SGregory Neil Shapiro 
11923299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
1193c2aa98e2SPeter Wemm 	while ((nr = read(fd, buf, sizeof(buf))) > 0)
11943299c2f1SGregory Neil Shapiro 	{
11953299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
1196c2aa98e2SPeter Wemm 		for (off = 0; off < nr; off += nw)
11973299c2f1SGregory Neil Shapiro 		{
11983299c2f1SGregory Neil Shapiro 			if ((nw = write(mbfd, buf + off, nr - off)) < 0)
11993299c2f1SGregory Neil Shapiro 			{
1200b4662009SGregory Neil Shapiro 				errcode = "450 4.2.0";
12013299c2f1SGregory Neil Shapiro #ifdef EDQUOT
1202b4662009SGregory Neil Shapiro 				if (errno == EDQUOT && BounceQuota)
1203b4662009SGregory Neil Shapiro 					errcode = "552 5.2.2";
12043299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
1205b4662009SGregory Neil Shapiro 				mailerr(errcode, "%s: %s",
120612ed1c7cSGregory Neil Shapiro 					path, sm_errstring(errno));
1207c2aa98e2SPeter Wemm 				goto err3;
1208c2aa98e2SPeter Wemm 			}
12093299c2f1SGregory Neil Shapiro 		}
12103299c2f1SGregory Neil Shapiro 	}
12113299c2f1SGregory Neil Shapiro 	if (nr < 0)
12123299c2f1SGregory Neil Shapiro 	{
1213b4662009SGregory Neil Shapiro 		mailerr("450 4.2.0", "Temporary file: %s",
121412ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1215c2aa98e2SPeter Wemm 		goto err3;
1216c2aa98e2SPeter Wemm 	}
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 	/* Flush to disk, don't wait for update. */
12193299c2f1SGregory Neil Shapiro 	if (!nofsync && fsync(mbfd) < 0)
12203299c2f1SGregory Neil Shapiro 	{
122112ed1c7cSGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
1222c2aa98e2SPeter Wemm err3:
1223b4662009SGregory Neil Shapiro 		(void) setreuid(0, 0);
1224c2aa98e2SPeter Wemm #ifdef DEBUG
122512ed1c7cSGregory Neil Shapiro 		fprintf(stderr, "reset euid = %d\n", (int) geteuid());
12263299c2f1SGregory Neil Shapiro #endif /* DEBUG */
12272ef40764SGregory Neil Shapiro 		if (mbfd >= 0)
1228c2aa98e2SPeter Wemm 			(void) ftruncate(mbfd, curoff);
1229d995d2baSGregory Neil Shapiro err1:		if (mbfd >= 0)
1230d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
1231c2aa98e2SPeter Wemm err0:		unlockmbox();
1232c2aa98e2SPeter Wemm 		return;
1233c2aa98e2SPeter Wemm 	}
1234c2aa98e2SPeter Wemm 
1235c2aa98e2SPeter Wemm 	/* Close and check -- NFS doesn't write until the close. */
12363299c2f1SGregory Neil Shapiro 	if (close(mbfd))
12373299c2f1SGregory Neil Shapiro 	{
1238b4662009SGregory Neil Shapiro 		errcode = "450 4.2.0";
12393299c2f1SGregory Neil Shapiro #ifdef EDQUOT
1240b4662009SGregory Neil Shapiro 		if (errno == EDQUOT && BounceQuota)
1241b4662009SGregory Neil Shapiro 			errcode = "552 5.2.2";
12423299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
124312ed1c7cSGregory Neil Shapiro 		mailerr(errcode, "%s: %s", path, sm_errstring(errno));
12442ef40764SGregory Neil Shapiro 		mbfd = open(path, O_WRONLY|EXTRA_MODE, 0);
12452ef40764SGregory Neil Shapiro 		if (mbfd < 0
12462ef40764SGregory Neil Shapiro 		    || fstat(mbfd, &sb) < 0 ||
12472ef40764SGregory Neil Shapiro 		    sb.st_nlink != 1 ||
12482ef40764SGregory Neil Shapiro 		    !S_ISREG(sb.st_mode) ||
12492ef40764SGregory Neil Shapiro 		    sb.st_dev != fsb.st_dev ||
12502ef40764SGregory Neil Shapiro 		    sb.st_ino != fsb.st_ino ||
12512ef40764SGregory Neil Shapiro # if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
12522ef40764SGregory Neil Shapiro 		    sb.st_gen != fsb.st_gen ||
12532ef40764SGregory Neil Shapiro # endif /* HAS_ST_GEN && 0 */
12542ef40764SGregory Neil Shapiro 		    sb.st_uid != fsb.st_uid
12552ef40764SGregory Neil Shapiro 		   )
12562ef40764SGregory Neil Shapiro 		{
12572ef40764SGregory Neil Shapiro 			/* Don't use a bogus file */
12582ef40764SGregory Neil Shapiro 			if (mbfd >= 0)
12592ef40764SGregory Neil Shapiro 			{
12602ef40764SGregory Neil Shapiro 				(void) close(mbfd);
12612ef40764SGregory Neil Shapiro 				mbfd = -1;
12622ef40764SGregory Neil Shapiro 			}
12632ef40764SGregory Neil Shapiro 		}
12642ef40764SGregory Neil Shapiro 
12652ef40764SGregory Neil Shapiro 		/* Attempt to truncate back to pre-write size */
12662ef40764SGregory Neil Shapiro 		goto err3;
12673299c2f1SGregory Neil Shapiro 	}
12683299c2f1SGregory Neil Shapiro 	else if (!nobiff)
1269c2aa98e2SPeter Wemm 		notifybiff(biffmsg);
1270c2aa98e2SPeter Wemm 
12713299c2f1SGregory Neil Shapiro 	if (setreuid(0, 0) < 0)
12723299c2f1SGregory Neil Shapiro 	{
1273c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "setreuid(0, 0): %s",
127412ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1275c2aa98e2SPeter Wemm 		goto err0;
1276c2aa98e2SPeter Wemm 	}
1277c2aa98e2SPeter Wemm #ifdef DEBUG
127812ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "reset euid = %d\n", (int) geteuid());
12793299c2f1SGregory Neil Shapiro #endif /* DEBUG */
1280c2aa98e2SPeter Wemm 	unlockmbox();
12813299c2f1SGregory Neil Shapiro 	if (LMTPMode)
1282b4662009SGregory Neil Shapiro 		printf("250 2.1.5 %s Ok\r\n", name);
1283c2aa98e2SPeter Wemm }
1284c2aa98e2SPeter Wemm 
1285c2aa98e2SPeter Wemm /*
12863299c2f1SGregory Neil Shapiro **  user.lock files are necessary for compatibility with other
12873299c2f1SGregory Neil Shapiro **  systems, e.g., when the mail spool file is NFS exported.
12883299c2f1SGregory Neil Shapiro **  Alas, mailbox locking is more than just a local matter.
12893299c2f1SGregory Neil Shapiro **  EPA 11/94.
1290c2aa98e2SPeter Wemm */
1291c2aa98e2SPeter Wemm 
129212ed1c7cSGregory Neil Shapiro bool	Locked = false;
12933299c2f1SGregory Neil Shapiro 
12943299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
12953299c2f1SGregory Neil Shapiro int
12963299c2f1SGregory Neil Shapiro lockmbox(name)
12973299c2f1SGregory Neil Shapiro 	char *name;
12983299c2f1SGregory Neil Shapiro {
1299d995d2baSGregory Neil Shapiro 	int r = 0;
13003299c2f1SGregory Neil Shapiro 
13013299c2f1SGregory Neil Shapiro 	if (Locked)
13023299c2f1SGregory Neil Shapiro 		return 0;
13033299c2f1SGregory Neil Shapiro 	if ((r = maillock(name, 15)) == L_SUCCESS)
13043299c2f1SGregory Neil Shapiro 	{
130512ed1c7cSGregory Neil Shapiro 		Locked = true;
13063299c2f1SGregory Neil Shapiro 		return 0;
13073299c2f1SGregory Neil Shapiro 	}
13083299c2f1SGregory Neil Shapiro 	switch (r)
13093299c2f1SGregory Neil Shapiro 	{
13103299c2f1SGregory Neil Shapiro 	  case L_TMPLOCK:	/* Can't create tmp file */
13113299c2f1SGregory Neil Shapiro 	  case L_TMPWRITE:	/* Can't write pid into lockfile */
13123299c2f1SGregory Neil Shapiro 	  case L_MAXTRYS:	/* Failed after retrycnt attempts */
13133299c2f1SGregory Neil Shapiro 		errno = 0;
13143299c2f1SGregory Neil Shapiro 		r = EX_TEMPFAIL;
13153299c2f1SGregory Neil Shapiro 		break;
13163299c2f1SGregory Neil Shapiro 	  case L_ERROR:		/* Check errno for reason */
13173299c2f1SGregory Neil Shapiro 		r = errno;
13183299c2f1SGregory Neil Shapiro 		break;
13193299c2f1SGregory Neil Shapiro 	  default:		/* other permanent errors */
13203299c2f1SGregory Neil Shapiro 		errno = 0;
13213299c2f1SGregory Neil Shapiro 		r = EX_UNAVAILABLE;
13223299c2f1SGregory Neil Shapiro 		break;
13233299c2f1SGregory Neil Shapiro 	}
13243299c2f1SGregory Neil Shapiro 	return r;
13253299c2f1SGregory Neil Shapiro }
1326c2aa98e2SPeter Wemm 
1327c2aa98e2SPeter Wemm void
13283299c2f1SGregory Neil Shapiro unlockmbox()
13293299c2f1SGregory Neil Shapiro {
13303299c2f1SGregory Neil Shapiro 	if (Locked)
13313299c2f1SGregory Neil Shapiro 		mailunlock();
133212ed1c7cSGregory Neil Shapiro 	Locked = false;
13333299c2f1SGregory Neil Shapiro }
13343299c2f1SGregory Neil Shapiro #else /* MAILLOCK */
13353299c2f1SGregory Neil Shapiro 
13363299c2f1SGregory Neil Shapiro char	LockName[MAXPATHLEN];
13373299c2f1SGregory Neil Shapiro 
13383299c2f1SGregory Neil Shapiro int
1339c2aa98e2SPeter Wemm lockmbox(path)
1340c2aa98e2SPeter Wemm 	char *path;
1341c2aa98e2SPeter Wemm {
1342c2aa98e2SPeter Wemm 	int statfailed = 0;
13433299c2f1SGregory Neil Shapiro 	time_t start;
1344c2aa98e2SPeter Wemm 
13453299c2f1SGregory Neil Shapiro 	if (Locked)
13463299c2f1SGregory Neil Shapiro 		return 0;
13473299c2f1SGregory Neil Shapiro 	if (strlen(path) + 6 > sizeof LockName)
13483299c2f1SGregory Neil Shapiro 		return EX_SOFTWARE;
134912ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(LockName, sizeof LockName, "%s.lock", path);
13503299c2f1SGregory Neil Shapiro 	(void) time(&start);
13513299c2f1SGregory Neil Shapiro 	for (; ; sleep(5))
13523299c2f1SGregory Neil Shapiro 	{
1353c2aa98e2SPeter Wemm 		int fd;
1354c2aa98e2SPeter Wemm 		struct stat st;
1355c2aa98e2SPeter Wemm 		time_t now;
1356c2aa98e2SPeter Wemm 
13573299c2f1SGregory Neil Shapiro 		/* global timeout */
13583299c2f1SGregory Neil Shapiro 		(void) time(&now);
13593299c2f1SGregory Neil Shapiro 		if (now > start + LOCKTO_GLOB)
13603299c2f1SGregory Neil Shapiro 		{
13613299c2f1SGregory Neil Shapiro 			errno = 0;
13623299c2f1SGregory Neil Shapiro 			return EX_TEMPFAIL;
1363c2aa98e2SPeter Wemm 		}
13643299c2f1SGregory Neil Shapiro 		fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, 0);
13653299c2f1SGregory Neil Shapiro 		if (fd >= 0)
13663299c2f1SGregory Neil Shapiro 		{
13673299c2f1SGregory Neil Shapiro 			/* defeat lock checking programs which test pid */
13683299c2f1SGregory Neil Shapiro 			(void) write(fd, "0", 2);
136912ed1c7cSGregory Neil Shapiro 			Locked = true;
13703299c2f1SGregory Neil Shapiro 			(void) close(fd);
13713299c2f1SGregory Neil Shapiro 			return 0;
13723299c2f1SGregory Neil Shapiro 		}
13733299c2f1SGregory Neil Shapiro 		if (stat(LockName, &st) < 0)
13743299c2f1SGregory Neil Shapiro 		{
1375c2aa98e2SPeter Wemm 			if (statfailed++ > 5)
13763299c2f1SGregory Neil Shapiro 			{
13773299c2f1SGregory Neil Shapiro 				errno = 0;
13783299c2f1SGregory Neil Shapiro 				return EX_TEMPFAIL;
13793299c2f1SGregory Neil Shapiro 			}
1380c2aa98e2SPeter Wemm 			continue;
1381c2aa98e2SPeter Wemm 		}
1382c2aa98e2SPeter Wemm 		statfailed = 0;
13833299c2f1SGregory Neil Shapiro 		(void) time(&now);
13843299c2f1SGregory Neil Shapiro 		if (now < st.st_ctime + LOCKTO_RM)
1385c2aa98e2SPeter Wemm 			continue;
13863299c2f1SGregory Neil Shapiro 
13873299c2f1SGregory Neil Shapiro 		/* try to remove stale lockfile */
13883299c2f1SGregory Neil Shapiro 		if (unlink(LockName) < 0)
13893299c2f1SGregory Neil Shapiro 			return errno;
1390c2aa98e2SPeter Wemm 	}
1391c2aa98e2SPeter Wemm }
1392c2aa98e2SPeter Wemm 
1393c2aa98e2SPeter Wemm void
1394c2aa98e2SPeter Wemm unlockmbox()
1395c2aa98e2SPeter Wemm {
13963299c2f1SGregory Neil Shapiro 	if (!Locked)
1397c2aa98e2SPeter Wemm 		return;
13983299c2f1SGregory Neil Shapiro 	(void) unlink(LockName);
139912ed1c7cSGregory Neil Shapiro 	Locked = false;
1400c2aa98e2SPeter Wemm }
14013299c2f1SGregory Neil Shapiro #endif /* MAILLOCK */
1402c2aa98e2SPeter Wemm 
1403c2aa98e2SPeter Wemm void
1404c2aa98e2SPeter Wemm notifybiff(msg)
1405c2aa98e2SPeter Wemm 	char *msg;
1406c2aa98e2SPeter Wemm {
140712ed1c7cSGregory Neil Shapiro 	static bool initialized = false;
1408c2aa98e2SPeter Wemm 	static int f = -1;
1409c2aa98e2SPeter Wemm 	struct hostent *hp;
1410c2aa98e2SPeter Wemm 	struct servent *sp;
1411c2aa98e2SPeter Wemm 	int len;
14123299c2f1SGregory Neil Shapiro 	static struct sockaddr_in addr;
1413c2aa98e2SPeter Wemm 
14143299c2f1SGregory Neil Shapiro 	if (!initialized)
14153299c2f1SGregory Neil Shapiro 	{
141612ed1c7cSGregory Neil Shapiro 		initialized = true;
14173299c2f1SGregory Neil Shapiro 
1418c2aa98e2SPeter Wemm 		/* Be silent if biff service not available. */
14193299c2f1SGregory Neil Shapiro 		if ((sp = getservbyname("biff", "udp")) == NULL ||
14203299c2f1SGregory Neil Shapiro 		    (hp = gethostbyname("localhost")) == NULL ||
14213299c2f1SGregory Neil Shapiro 		    hp->h_length != INADDRSZ)
1422c2aa98e2SPeter Wemm 			return;
14233299c2f1SGregory Neil Shapiro 
1424c2aa98e2SPeter Wemm 		addr.sin_family = hp->h_addrtype;
14253299c2f1SGregory Neil Shapiro 		memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ);
1426c2aa98e2SPeter Wemm 		addr.sin_port = sp->s_port;
1427c2aa98e2SPeter Wemm 	}
14283299c2f1SGregory Neil Shapiro 
14293299c2f1SGregory Neil Shapiro 	/* No message, just return */
14303299c2f1SGregory Neil Shapiro 	if (msg == NULL)
1431c2aa98e2SPeter Wemm 		return;
14323299c2f1SGregory Neil Shapiro 
14333299c2f1SGregory Neil Shapiro 	/* Couldn't initialize addr struct */
14343299c2f1SGregory Neil Shapiro 	if (addr.sin_family == AF_UNSPEC)
14353299c2f1SGregory Neil Shapiro 		return;
14363299c2f1SGregory Neil Shapiro 
1437b4662009SGregory Neil Shapiro 	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
14383299c2f1SGregory Neil Shapiro 		return;
1439c2aa98e2SPeter Wemm 	len = strlen(msg) + 1;
144076b7bf71SPeter Wemm 	(void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr));
1441c2aa98e2SPeter Wemm }
1442c2aa98e2SPeter Wemm 
1443c2aa98e2SPeter Wemm void
1444c2aa98e2SPeter Wemm usage()
1445c2aa98e2SPeter Wemm {
14463299c2f1SGregory Neil Shapiro 	ExitVal = EX_USAGE;
144712ed1c7cSGregory Neil Shapiro 	mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-d] [-l] [-s] [-f from|-r from] [-h filename] user ...");
14483299c2f1SGregory Neil Shapiro 	exit(ExitVal);
1449c2aa98e2SPeter Wemm }
1450c2aa98e2SPeter Wemm 
1451c2aa98e2SPeter Wemm void
145212ed1c7cSGregory Neil Shapiro /*VARARGS2*/
1453c2aa98e2SPeter Wemm #ifdef __STDC__
1454c2aa98e2SPeter Wemm mailerr(const char *hdr, const char *fmt, ...)
14553299c2f1SGregory Neil Shapiro #else /* __STDC__ */
1456c2aa98e2SPeter Wemm mailerr(hdr, fmt, va_alist)
1457c2aa98e2SPeter Wemm 	const char *hdr;
1458c2aa98e2SPeter Wemm 	const char *fmt;
1459c2aa98e2SPeter Wemm 	va_dcl
14603299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
1461c2aa98e2SPeter Wemm {
1462b4662009SGregory Neil Shapiro 	size_t len = 0;
146312ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
1464c2aa98e2SPeter Wemm 
1465b4662009SGregory Neil Shapiro 	(void) e_to_sys(errno);
1466b4662009SGregory Neil Shapiro 
146712ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
1468b4662009SGregory Neil Shapiro 
146912ed1c7cSGregory Neil Shapiro 	if (LMTPMode && hdr != NULL)
1470c2aa98e2SPeter Wemm 	{
147112ed1c7cSGregory Neil Shapiro 		sm_snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr);
1472b4662009SGregory Neil Shapiro 		len = strlen(ErrBuf);
1473c2aa98e2SPeter Wemm 	}
147412ed1c7cSGregory Neil Shapiro 	(void) sm_vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap);
147512ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
1476b4662009SGregory Neil Shapiro 
1477b4662009SGregory Neil Shapiro 	if (!HoldErrs)
1478b4662009SGregory Neil Shapiro 		flush_error();
1479b4662009SGregory Neil Shapiro 
1480b4662009SGregory Neil Shapiro 	/* Log the message to syslog. */
1481b4662009SGregory Neil Shapiro 	if (!LMTPMode)
1482b4662009SGregory Neil Shapiro 		syslog(LOG_ERR, "%s", ErrBuf);
1483b4662009SGregory Neil Shapiro }
1484c2aa98e2SPeter Wemm 
1485c2aa98e2SPeter Wemm void
1486b4662009SGregory Neil Shapiro flush_error()
1487c2aa98e2SPeter Wemm {
1488b4662009SGregory Neil Shapiro 	if (LMTPMode)
1489b4662009SGregory Neil Shapiro 		printf("%s\r\n", ErrBuf);
1490b4662009SGregory Neil Shapiro 	else
1491b4662009SGregory Neil Shapiro 	{
14923299c2f1SGregory Neil Shapiro 		if (ExitVal != EX_USAGE)
1493c2aa98e2SPeter Wemm 			(void) fprintf(stderr, "mail.local: ");
1494b4662009SGregory Neil Shapiro 		fprintf(stderr, "%s\n", ErrBuf);
1495c2aa98e2SPeter Wemm 	}
1496c2aa98e2SPeter Wemm }
1497c2aa98e2SPeter Wemm 
1498c2aa98e2SPeter Wemm /*
1499c2aa98e2SPeter Wemm  * e_to_sys --
1500c2aa98e2SPeter Wemm  *	Guess which errno's are temporary.  Gag me.
1501c2aa98e2SPeter Wemm  */
1502b4662009SGregory Neil Shapiro 
15033299c2f1SGregory Neil Shapiro int
1504c2aa98e2SPeter Wemm e_to_sys(num)
1505c2aa98e2SPeter Wemm 	int num;
1506c2aa98e2SPeter Wemm {
1507c2aa98e2SPeter Wemm 	/* Temporary failures override hard errors. */
15083299c2f1SGregory Neil Shapiro 	if (ExitVal == EX_TEMPFAIL)
15093299c2f1SGregory Neil Shapiro 		return ExitVal;
1510c2aa98e2SPeter Wemm 
15113299c2f1SGregory Neil Shapiro 	switch (num)		/* Hopefully temporary errors. */
15123299c2f1SGregory Neil Shapiro 	{
1513c2aa98e2SPeter Wemm #ifdef EDQUOT
1514c2aa98e2SPeter Wemm 	  case EDQUOT:		/* Disc quota exceeded */
1515b4662009SGregory Neil Shapiro 		if (BounceQuota)
15163299c2f1SGregory Neil Shapiro 		{
15173299c2f1SGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
15183299c2f1SGregory Neil Shapiro 			break;
15193299c2f1SGregory Neil Shapiro 		}
15203299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
15213299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
15223299c2f1SGregory Neil Shapiro #ifdef EAGAIN
15233299c2f1SGregory Neil Shapiro 	  case EAGAIN:		/* Resource temporarily unavailable */
15243299c2f1SGregory Neil Shapiro #endif /* EAGAIN */
1525c2aa98e2SPeter Wemm #ifdef EBUSY
1526c2aa98e2SPeter Wemm 	  case EBUSY:		/* Device busy */
15273299c2f1SGregory Neil Shapiro #endif /* EBUSY */
1528c2aa98e2SPeter Wemm #ifdef EPROCLIM
1529c2aa98e2SPeter Wemm 	  case EPROCLIM:	/* Too many processes */
15303299c2f1SGregory Neil Shapiro #endif /* EPROCLIM */
1531c2aa98e2SPeter Wemm #ifdef EUSERS
1532c2aa98e2SPeter Wemm 	  case EUSERS:		/* Too many users */
15333299c2f1SGregory Neil Shapiro #endif /* EUSERS */
1534c2aa98e2SPeter Wemm #ifdef ECONNABORTED
1535c2aa98e2SPeter Wemm 	  case ECONNABORTED:	/* Software caused connection abort */
15363299c2f1SGregory Neil Shapiro #endif /* ECONNABORTED */
1537c2aa98e2SPeter Wemm #ifdef ECONNREFUSED
1538c2aa98e2SPeter Wemm 	  case ECONNREFUSED:	/* Connection refused */
15393299c2f1SGregory Neil Shapiro #endif /* ECONNREFUSED */
1540c2aa98e2SPeter Wemm #ifdef ECONNRESET
1541c2aa98e2SPeter Wemm 	  case ECONNRESET:	/* Connection reset by peer */
15423299c2f1SGregory Neil Shapiro #endif /* ECONNRESET */
1543c2aa98e2SPeter Wemm #ifdef EDEADLK
1544c2aa98e2SPeter Wemm 	  case EDEADLK:		/* Resource deadlock avoided */
15453299c2f1SGregory Neil Shapiro #endif /* EDEADLK */
1546c2aa98e2SPeter Wemm #ifdef EFBIG
1547c2aa98e2SPeter Wemm 	  case EFBIG:		/* File too large */
15483299c2f1SGregory Neil Shapiro #endif /* EFBIG */
1549c2aa98e2SPeter Wemm #ifdef EHOSTDOWN
1550c2aa98e2SPeter Wemm 	  case EHOSTDOWN:	/* Host is down */
15513299c2f1SGregory Neil Shapiro #endif /* EHOSTDOWN */
1552c2aa98e2SPeter Wemm #ifdef EHOSTUNREACH
1553c2aa98e2SPeter Wemm 	  case EHOSTUNREACH:	/* No route to host */
15543299c2f1SGregory Neil Shapiro #endif /* EHOSTUNREACH */
1555c2aa98e2SPeter Wemm #ifdef EMFILE
1556c2aa98e2SPeter Wemm 	  case EMFILE:		/* Too many open files */
15573299c2f1SGregory Neil Shapiro #endif /* EMFILE */
1558c2aa98e2SPeter Wemm #ifdef ENETDOWN
1559c2aa98e2SPeter Wemm 	  case ENETDOWN:	/* Network is down */
15603299c2f1SGregory Neil Shapiro #endif /* ENETDOWN */
1561c2aa98e2SPeter Wemm #ifdef ENETRESET
1562c2aa98e2SPeter Wemm 	  case ENETRESET:	/* Network dropped connection on reset */
15633299c2f1SGregory Neil Shapiro #endif /* ENETRESET */
1564c2aa98e2SPeter Wemm #ifdef ENETUNREACH
1565c2aa98e2SPeter Wemm 	  case ENETUNREACH:	/* Network is unreachable */
15663299c2f1SGregory Neil Shapiro #endif /* ENETUNREACH */
1567c2aa98e2SPeter Wemm #ifdef ENFILE
1568c2aa98e2SPeter Wemm 	  case ENFILE:		/* Too many open files in system */
15693299c2f1SGregory Neil Shapiro #endif /* ENFILE */
1570c2aa98e2SPeter Wemm #ifdef ENOBUFS
1571c2aa98e2SPeter Wemm 	  case ENOBUFS:		/* No buffer space available */
15723299c2f1SGregory Neil Shapiro #endif /* ENOBUFS */
1573c2aa98e2SPeter Wemm #ifdef ENOMEM
1574c2aa98e2SPeter Wemm 	  case ENOMEM:		/* Cannot allocate memory */
15753299c2f1SGregory Neil Shapiro #endif /* ENOMEM */
1576c2aa98e2SPeter Wemm #ifdef ENOSPC
1577c2aa98e2SPeter Wemm 	  case ENOSPC:		/* No space left on device */
15783299c2f1SGregory Neil Shapiro #endif /* ENOSPC */
1579c2aa98e2SPeter Wemm #ifdef EROFS
1580c2aa98e2SPeter Wemm 	  case EROFS:		/* Read-only file system */
15813299c2f1SGregory Neil Shapiro #endif /* EROFS */
1582c2aa98e2SPeter Wemm #ifdef ESTALE
1583c2aa98e2SPeter Wemm 	  case ESTALE:		/* Stale NFS file handle */
15843299c2f1SGregory Neil Shapiro #endif /* ESTALE */
1585c2aa98e2SPeter Wemm #ifdef ETIMEDOUT
1586c2aa98e2SPeter Wemm 	  case ETIMEDOUT:	/* Connection timed out */
15873299c2f1SGregory Neil Shapiro #endif /* ETIMEDOUT */
1588c2aa98e2SPeter Wemm #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
1589c2aa98e2SPeter Wemm 	  case EWOULDBLOCK:	/* Operation would block. */
15903299c2f1SGregory Neil Shapiro #endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */
15913299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
1592c2aa98e2SPeter Wemm 		break;
15933299c2f1SGregory Neil Shapiro 
1594c2aa98e2SPeter Wemm 	  default:
15953299c2f1SGregory Neil Shapiro 		ExitVal = EX_UNAVAILABLE;
1596c2aa98e2SPeter Wemm 		break;
1597c2aa98e2SPeter Wemm 	}
15983299c2f1SGregory Neil Shapiro 	return ExitVal;
1599c2aa98e2SPeter Wemm }
1600c2aa98e2SPeter Wemm 
1601c2aa98e2SPeter Wemm #if defined(ultrix) || defined(_CRAY)
1602c2aa98e2SPeter Wemm /*
1603c2aa98e2SPeter Wemm  * Copyright (c) 1987, 1993
1604c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
1605c2aa98e2SPeter Wemm  *
1606c2aa98e2SPeter Wemm  * Redistribution and use in source and binary forms, with or without
1607c2aa98e2SPeter Wemm  * modification, are permitted provided that the following conditions
1608c2aa98e2SPeter Wemm  * are met:
1609c2aa98e2SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1610c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1611c2aa98e2SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1612c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1613c2aa98e2SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1614c2aa98e2SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
1615c2aa98e2SPeter Wemm  *    must display the following acknowledgement:
1616c2aa98e2SPeter Wemm  *	This product includes software developed by the University of
1617c2aa98e2SPeter Wemm  *	California, Berkeley and its contributors.
1618c2aa98e2SPeter Wemm  * 4. Neither the name of the University nor the names of its contributors
1619c2aa98e2SPeter Wemm  *    may be used to endorse or promote products derived from this software
1620c2aa98e2SPeter Wemm  *    without specific prior written permission.
1621c2aa98e2SPeter Wemm  *
1622c2aa98e2SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1623c2aa98e2SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1624c2aa98e2SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1625c2aa98e2SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1626c2aa98e2SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1627c2aa98e2SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1628c2aa98e2SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1629c2aa98e2SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1630c2aa98e2SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1631c2aa98e2SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1632c2aa98e2SPeter Wemm  * SUCH DAMAGE.
1633c2aa98e2SPeter Wemm  */
1634c2aa98e2SPeter Wemm 
1635c2aa98e2SPeter Wemm # if defined(LIBC_SCCS) && !defined(lint)
1636c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
16373299c2f1SGregory Neil Shapiro # endif /* defined(LIBC_SCCS) && !defined(lint) */
1638c2aa98e2SPeter Wemm 
1639c2aa98e2SPeter Wemm # include <sys/types.h>
1640c2aa98e2SPeter Wemm # include <sys/stat.h>
1641c2aa98e2SPeter Wemm # include <fcntl.h>
1642c2aa98e2SPeter Wemm # include <errno.h>
1643c2aa98e2SPeter Wemm # include <stdio.h>
1644c2aa98e2SPeter Wemm # include <ctype.h>
1645c2aa98e2SPeter Wemm 
1646c2aa98e2SPeter Wemm static int _gettemp();
1647c2aa98e2SPeter Wemm 
1648c2aa98e2SPeter Wemm mkstemp(path)
1649c2aa98e2SPeter Wemm 	char *path;
1650c2aa98e2SPeter Wemm {
1651c2aa98e2SPeter Wemm 	int fd;
1652c2aa98e2SPeter Wemm 
1653c2aa98e2SPeter Wemm 	return (_gettemp(path, &fd) ? fd : -1);
1654c2aa98e2SPeter Wemm }
1655c2aa98e2SPeter Wemm 
1656c2aa98e2SPeter Wemm static
1657c2aa98e2SPeter Wemm _gettemp(path, doopen)
1658c2aa98e2SPeter Wemm 	char *path;
1659c2aa98e2SPeter Wemm 	register int *doopen;
1660c2aa98e2SPeter Wemm {
1661c2aa98e2SPeter Wemm 	extern int errno;
1662c2aa98e2SPeter Wemm 	register char *start, *trv;
1663c2aa98e2SPeter Wemm 	struct stat sbuf;
166412ed1c7cSGregory Neil Shapiro 	unsigned int pid;
1665c2aa98e2SPeter Wemm 
1666c2aa98e2SPeter Wemm 	pid = getpid();
1667c2aa98e2SPeter Wemm 	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
16683299c2f1SGregory Neil Shapiro 	while (*--trv == 'X')
16693299c2f1SGregory Neil Shapiro 	{
1670c2aa98e2SPeter Wemm 		*trv = (pid % 10) + '0';
1671c2aa98e2SPeter Wemm 		pid /= 10;
1672c2aa98e2SPeter Wemm 	}
1673c2aa98e2SPeter Wemm 
1674c2aa98e2SPeter Wemm 	/*
1675c2aa98e2SPeter Wemm 	 * check the target directory; if you have six X's and it
1676c2aa98e2SPeter Wemm 	 * doesn't exist this runs for a *very* long time.
1677c2aa98e2SPeter Wemm 	 */
16783299c2f1SGregory Neil Shapiro 	for (start = trv + 1;; --trv)
16793299c2f1SGregory Neil Shapiro 	{
1680c2aa98e2SPeter Wemm 		if (trv <= path)
1681c2aa98e2SPeter Wemm 			break;
16823299c2f1SGregory Neil Shapiro 		if (*trv == '/')
16833299c2f1SGregory Neil Shapiro 		{
1684c2aa98e2SPeter Wemm 			*trv = '\0';
1685c2aa98e2SPeter Wemm 			if (stat(path, &sbuf) < 0)
1686c2aa98e2SPeter Wemm 				return(0);
16873299c2f1SGregory Neil Shapiro 			if (!S_ISDIR(sbuf.st_mode))
16883299c2f1SGregory Neil Shapiro 			{
1689c2aa98e2SPeter Wemm 				errno = ENOTDIR;
1690c2aa98e2SPeter Wemm 				return(0);
1691c2aa98e2SPeter Wemm 			}
1692c2aa98e2SPeter Wemm 			*trv = '/';
1693c2aa98e2SPeter Wemm 			break;
1694c2aa98e2SPeter Wemm 		}
1695c2aa98e2SPeter Wemm 	}
1696c2aa98e2SPeter Wemm 
16973299c2f1SGregory Neil Shapiro 	for (;;)
16983299c2f1SGregory Neil Shapiro 	{
16993299c2f1SGregory Neil Shapiro 		if (doopen)
17003299c2f1SGregory Neil Shapiro 		{
1701d995d2baSGregory Neil Shapiro 			if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR,
1702d995d2baSGregory Neil Shapiro 					    0600)) >= 0)
1703c2aa98e2SPeter Wemm 				return(1);
1704c2aa98e2SPeter Wemm 			if (errno != EEXIST)
1705c2aa98e2SPeter Wemm 				return(0);
1706c2aa98e2SPeter Wemm 		}
1707c2aa98e2SPeter Wemm 		else if (stat(path, &sbuf) < 0)
1708c2aa98e2SPeter Wemm 			return(errno == ENOENT ? 1 : 0);
1709c2aa98e2SPeter Wemm 
1710c2aa98e2SPeter Wemm 		/* tricky little algorithm for backward compatibility */
17113299c2f1SGregory Neil Shapiro 		for (trv = start;;)
17123299c2f1SGregory Neil Shapiro 		{
1713c2aa98e2SPeter Wemm 			if (!*trv)
1714c2aa98e2SPeter Wemm 				return(0);
1715c2aa98e2SPeter Wemm 			if (*trv == 'z')
1716c2aa98e2SPeter Wemm 				*trv++ = 'a';
17173299c2f1SGregory Neil Shapiro 			else
17183299c2f1SGregory Neil Shapiro 			{
1719c2aa98e2SPeter Wemm 				if (isascii(*trv) && isdigit(*trv))
1720c2aa98e2SPeter Wemm 					*trv = 'a';
1721c2aa98e2SPeter Wemm 				else
1722c2aa98e2SPeter Wemm 					++*trv;
1723c2aa98e2SPeter Wemm 				break;
1724c2aa98e2SPeter Wemm 			}
1725c2aa98e2SPeter Wemm 		}
1726c2aa98e2SPeter Wemm 	}
1727c2aa98e2SPeter Wemm 	/* NOTREACHED */
1728c2aa98e2SPeter Wemm }
17293299c2f1SGregory Neil Shapiro #endif /* defined(ultrix) || defined(_CRAY) */
1730