xref: /freebsd/contrib/sendmail/mail.local/mail.local.c (revision d995d2ba6b346ad29395c43f83421c01a446d2ae)
176b7bf71SPeter Wemm /*
23299c2f1SGregory Neil Shapiro  * Copyright (c) 1998-2000 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  *
11c2aa98e2SPeter Wemm  */
12c2aa98e2SPeter Wemm 
13c2aa98e2SPeter Wemm #ifndef lint
14c2aa98e2SPeter Wemm static char copyright[] =
153299c2f1SGregory Neil Shapiro "@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
163299c2f1SGregory Neil Shapiro 	All rights reserved.\n\
173299c2f1SGregory Neil Shapiro      Copyright (c) 1990, 1993, 1994\n\
18c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
193299c2f1SGregory Neil Shapiro #endif /* ! lint */
20c2aa98e2SPeter Wemm 
21c2aa98e2SPeter Wemm #ifndef lint
22d995d2baSGregory Neil Shapiro static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.37 2000/09/22 00:49:10 doug Exp $";
233299c2f1SGregory Neil Shapiro #endif /* ! lint */
243299c2f1SGregory Neil Shapiro 
253299c2f1SGregory Neil Shapiro /* $FreeBSD$ */
26c2aa98e2SPeter Wemm 
27c2aa98e2SPeter Wemm /*
283299c2f1SGregory Neil Shapiro **  This is not intended to work on System V derived systems
293299c2f1SGregory Neil Shapiro **  such as Solaris or HP-UX, since they use a totally different
303299c2f1SGregory Neil Shapiro **  approach to mailboxes (essentially, they have a setgid program
313299c2f1SGregory Neil Shapiro **  rather than setuid, and they rely on the ability to "give away"
323299c2f1SGregory Neil Shapiro **  files to do their work).  IT IS NOT A BUG that this doesn't
333299c2f1SGregory Neil Shapiro **  work on such architectures.
34c2aa98e2SPeter Wemm */
35c2aa98e2SPeter Wemm 
363299c2f1SGregory Neil Shapiro 
37d995d2baSGregory Neil Shapiro /* additional mode for open() */
38d995d2baSGregory Neil Shapiro # define EXTRA_MODE 0
39d995d2baSGregory Neil Shapiro 
403299c2f1SGregory Neil Shapiro # include <sys/types.h>
41c2aa98e2SPeter Wemm # include <sys/param.h>
42c2aa98e2SPeter Wemm # include <sys/stat.h>
43c2aa98e2SPeter Wemm # include <sys/socket.h>
44c2aa98e2SPeter Wemm # include <sys/file.h>
45c2aa98e2SPeter Wemm 
46c2aa98e2SPeter Wemm # include <netinet/in.h>
473299c2f1SGregory Neil Shapiro # include <arpa/nameser.h>
48c2aa98e2SPeter Wemm 
49c2aa98e2SPeter Wemm # include <fcntl.h>
50c2aa98e2SPeter Wemm # include <netdb.h>
51c2aa98e2SPeter Wemm #  include <pwd.h>
52c2aa98e2SPeter Wemm # include <stdio.h>
53c2aa98e2SPeter Wemm # include <stdlib.h>
54c2aa98e2SPeter Wemm # include <string.h>
55c2aa98e2SPeter Wemm # include <syslog.h>
56c2aa98e2SPeter Wemm # include <time.h>
57c2aa98e2SPeter Wemm # include <unistd.h>
58c2aa98e2SPeter Wemm # ifdef EX_OK
59c2aa98e2SPeter Wemm #  undef EX_OK		/* unistd.h may have another use for this */
603299c2f1SGregory Neil Shapiro # endif /* EX_OK */
61c2aa98e2SPeter Wemm # include <sysexits.h>
62c2aa98e2SPeter Wemm # include <ctype.h>
63c2aa98e2SPeter Wemm 
643299c2f1SGregory Neil Shapiro # ifndef __P
653299c2f1SGregory Neil Shapiro #  include "sendmail/cdefs.h"
663299c2f1SGregory Neil Shapiro # endif /* ! __P */
673299c2f1SGregory Neil Shapiro # include "sendmail/useful.h"
683299c2f1SGregory Neil Shapiro 
693299c2f1SGregory Neil Shapiro extern size_t	strlcpy __P((char *, const char *, size_t));
703299c2f1SGregory Neil Shapiro extern size_t	strlcat __P((char *, const char *, size_t));
713299c2f1SGregory Neil Shapiro 
723299c2f1SGregory Neil Shapiro # if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
733299c2f1SGregory Neil Shapiro #  ifndef HASSTRERROR
743299c2f1SGregory Neil Shapiro #   define HASSTRERROR	1
753299c2f1SGregory Neil Shapiro #  endif /* ! HASSTRERROR */
76d995d2baSGregory Neil Shapiro # endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
773299c2f1SGregory Neil Shapiro 
783299c2f1SGregory Neil Shapiro # include "sendmail/errstring.h"
793299c2f1SGregory Neil Shapiro 
803299c2f1SGregory Neil Shapiro # ifndef LOCKTO_RM
813299c2f1SGregory Neil Shapiro #  define LOCKTO_RM	300	/* timeout for stale lockfile removal */
82d995d2baSGregory Neil Shapiro # endif /* ! LOCKTO_RM */
833299c2f1SGregory Neil Shapiro # ifndef LOCKTO_GLOB
843299c2f1SGregory Neil Shapiro #  define LOCKTO_GLOB	400	/* global timeout for lockfile creation */
85d995d2baSGregory Neil Shapiro # endif /* ! LOCKTO_GLOB */
863299c2f1SGregory Neil Shapiro 
87c2aa98e2SPeter Wemm # ifdef __STDC__
88c2aa98e2SPeter Wemm #  include <stdarg.h>
893299c2f1SGregory Neil Shapiro #  define REALLOC(ptr, size)	realloc(ptr, size)
903299c2f1SGregory Neil Shapiro # else /* __STDC__ */
91c2aa98e2SPeter Wemm #  include <varargs.h>
923299c2f1SGregory Neil Shapiro /* define a realloc() which works for NULL pointers */
933299c2f1SGregory Neil Shapiro #  define REALLOC(ptr, size)	(((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
943299c2f1SGregory Neil Shapiro # endif /* __STDC__ */
95c2aa98e2SPeter Wemm 
96c2aa98e2SPeter Wemm # if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
97c2aa98e2SPeter Wemm #  define USE_LOCKF	1
98c2aa98e2SPeter Wemm #  define USE_SETEUID	1
99c2aa98e2SPeter Wemm #   define _PATH_MAILDIR	"/var/mail"
1003299c2f1SGregory Neil Shapiro # endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
101c2aa98e2SPeter Wemm 
1023299c2f1SGregory Neil Shapiro # ifdef NCR_MP_RAS3
1033299c2f1SGregory Neil Shapiro #  define USE_LOCKF	1
1043299c2f1SGregory Neil Shapiro #  define HASSNPRINTF	1
1053299c2f1SGregory Neil Shapiro #   define _PATH_MAILDIR	"/var/mail"
1063299c2f1SGregory Neil Shapiro # endif /* NCR_MP_RAS3 */
107c2aa98e2SPeter Wemm 
108c2aa98e2SPeter Wemm # if defined(_AIX)
109c2aa98e2SPeter Wemm #  define USE_LOCKF	1
110c2aa98e2SPeter Wemm #  define USE_SETEUID	1
111c2aa98e2SPeter Wemm #  define USE_VSYSLOG	0
1123299c2f1SGregory Neil Shapiro # endif /* defined(_AIX) */
113c2aa98e2SPeter Wemm 
114c2aa98e2SPeter Wemm # if defined(__hpux)
115c2aa98e2SPeter Wemm #  define USE_LOCKF	1
116c2aa98e2SPeter Wemm #  define USE_SETRESUID	1
117c2aa98e2SPeter Wemm #  define USE_VSYSLOG	0
1183299c2f1SGregory Neil Shapiro # endif /* defined(__hpux) */
1193299c2f1SGregory Neil Shapiro 
1203299c2f1SGregory Neil Shapiro # ifdef DGUX
1213299c2f1SGregory Neil Shapiro #  define HASSNPRINTF	1
1223299c2f1SGregory Neil Shapiro #  define USE_LOCKF	1
1233299c2f1SGregory Neil Shapiro #  define USE_VSYSLOG	0
1243299c2f1SGregory Neil Shapiro # endif /* DGUX */
125c2aa98e2SPeter Wemm 
126c2aa98e2SPeter Wemm # if defined(_CRAY)
127c2aa98e2SPeter Wemm #  if !defined(MAXPATHLEN)
128c2aa98e2SPeter Wemm #   define MAXPATHLEN PATHSIZE
1293299c2f1SGregory Neil Shapiro #  endif /* !defined(MAXPATHLEN) */
130c2aa98e2SPeter Wemm #  define USE_VSYSLOG   0
131c2aa98e2SPeter Wemm #   define _PATH_MAILDIR	"/usr/spool/mail"
1323299c2f1SGregory Neil Shapiro # endif /* defined(_CRAY) */
133c2aa98e2SPeter Wemm 
134c2aa98e2SPeter Wemm # if defined(ultrix)
135c2aa98e2SPeter Wemm #  define USE_VSYSLOG	0
1363299c2f1SGregory Neil Shapiro # endif /* defined(ultrix) */
137c2aa98e2SPeter Wemm 
138c2aa98e2SPeter Wemm # if defined(__osf__)
139c2aa98e2SPeter Wemm #  define USE_VSYSLOG	0
1403299c2f1SGregory Neil Shapiro # endif /* defined(__osf__) */
141c2aa98e2SPeter Wemm 
14276b7bf71SPeter Wemm # if defined(NeXT) && !defined(__APPLE__)
143c2aa98e2SPeter Wemm #  include <libc.h>
144c2aa98e2SPeter Wemm #   define _PATH_MAILDIR	"/usr/spool/mail"
145c2aa98e2SPeter Wemm #  define S_IRUSR	S_IREAD
146c2aa98e2SPeter Wemm #  define S_IWUSR	S_IWRITE
1473299c2f1SGregory Neil Shapiro # endif /* defined(NeXT) && !defined(__APPLE__) */
148c2aa98e2SPeter Wemm 
149c2aa98e2SPeter Wemm # if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
150c2aa98e2SPeter Wemm #   include <paths.h>
1513299c2f1SGregory Neil Shapiro # endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
152c2aa98e2SPeter Wemm 
153c2aa98e2SPeter Wemm /*
154c2aa98e2SPeter Wemm  * If you don't have flock, you could try using lockf instead.
155c2aa98e2SPeter Wemm  */
156c2aa98e2SPeter Wemm 
157c2aa98e2SPeter Wemm # ifdef USE_LOCKF
158c2aa98e2SPeter Wemm #  define flock(a, b)	lockf(a, b, 0)
1593299c2f1SGregory Neil Shapiro #  ifdef LOCK_EX
1603299c2f1SGregory Neil Shapiro #   undef LOCK_EX
1613299c2f1SGregory Neil Shapiro #  endif /* LOCK_EX */
162c2aa98e2SPeter Wemm #  define LOCK_EX	F_LOCK
1633299c2f1SGregory Neil Shapiro # endif /* USE_LOCKF */
164c2aa98e2SPeter Wemm 
165c2aa98e2SPeter Wemm # ifndef USE_VSYSLOG
166c2aa98e2SPeter Wemm #  define USE_VSYSLOG	1
1673299c2f1SGregory Neil Shapiro # endif /* ! USE_VSYSLOG */
168c2aa98e2SPeter Wemm 
169c2aa98e2SPeter Wemm # ifndef LOCK_EX
170c2aa98e2SPeter Wemm #  include <sys/file.h>
1713299c2f1SGregory Neil Shapiro # endif /* ! LOCK_EX */
172c2aa98e2SPeter Wemm 
173c2aa98e2SPeter Wemm # if defined(BSD4_4) || defined(__GLIBC__)
1743299c2f1SGregory Neil Shapiro #   include <paths.h>
1753299c2f1SGregory Neil Shapiro #  define _PATH_LOCTMP	"/var/tmp/local.XXXXXX"
1763299c2f1SGregory Neil Shapiro # endif /* defined(BSD4_4) || defined(__GLIBC__) */
177c2aa98e2SPeter Wemm 
178c2aa98e2SPeter Wemm # ifdef BSD4_4
179c2aa98e2SPeter Wemm #  define HAS_ST_GEN	1
1803299c2f1SGregory Neil Shapiro # else /* BSD4_4 */
181c2aa98e2SPeter Wemm #  ifndef _BSD_VA_LIST_
182c2aa98e2SPeter Wemm #   define _BSD_VA_LIST_	va_list
1833299c2f1SGregory Neil Shapiro #  endif /* ! _BSD_VA_LIST_ */
1843299c2f1SGregory Neil Shapiro # endif /* BSD4_4 */
185c2aa98e2SPeter Wemm 
186c2aa98e2SPeter Wemm # if defined(BSD4_4) || defined(linux)
187c2aa98e2SPeter Wemm #  define HASSNPRINTF	1
1883299c2f1SGregory Neil Shapiro # else /* defined(BSD4_4) || defined(linux) */
189c2aa98e2SPeter Wemm #  ifndef ultrix
190c2aa98e2SPeter Wemm extern FILE	*fdopen __P((int, const char *));
1913299c2f1SGregory Neil Shapiro #  endif /* ! ultrix */
1923299c2f1SGregory Neil Shapiro # endif /* defined(BSD4_4) || defined(linux) */
1933299c2f1SGregory Neil Shapiro 
1943299c2f1SGregory Neil Shapiro # if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
1953299c2f1SGregory Neil Shapiro #  define CONTENTLENGTH	1	/* Needs the Content-Length header */
1963299c2f1SGregory Neil Shapiro # endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
197c2aa98e2SPeter Wemm 
198c2aa98e2SPeter Wemm # if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
199c2aa98e2SPeter Wemm #  define HASSNPRINTF	1		/* has snprintf starting in 2.6 */
2003299c2f1SGregory Neil Shapiro # endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
2013299c2f1SGregory Neil Shapiro 
2023299c2f1SGregory Neil Shapiro # ifdef HPUX11
203d995d2baSGregory Neil Shapiro #  define HASSNPRINTF	1		/* has snprintf starting in 11.X */
2043299c2f1SGregory Neil Shapiro # endif /* HPUX11 */
2053299c2f1SGregory Neil Shapiro 
2063299c2f1SGregory Neil Shapiro # if _AIX4 >= 40300
2073299c2f1SGregory Neil Shapiro #  define HASSNPRINTF	1		/* has snprintf starting in 4.3 */
2083299c2f1SGregory Neil Shapiro # endif /* _AIX4 >= 40300 */
209c2aa98e2SPeter Wemm 
210c2aa98e2SPeter Wemm # if !HASSNPRINTF
211c2aa98e2SPeter Wemm extern int	snprintf __P((char *, size_t, const char *, ...));
212c2aa98e2SPeter Wemm #  ifndef _CRAY
213c2aa98e2SPeter Wemm extern int	vsnprintf __P((char *, size_t, const char *, ...));
2143299c2f1SGregory Neil Shapiro #  endif /* ! _CRAY */
2153299c2f1SGregory Neil Shapiro # endif /* !HASSNPRINTF */
216c2aa98e2SPeter Wemm 
217c2aa98e2SPeter Wemm /*
2183299c2f1SGregory Neil Shapiro **  If you don't have setreuid, and you have saved uids, and you have
2193299c2f1SGregory Neil Shapiro **  a seteuid() call that doesn't try to emulate using setuid(), then
2203299c2f1SGregory Neil Shapiro **  you can try defining USE_SETEUID.
221c2aa98e2SPeter Wemm */
222c2aa98e2SPeter Wemm # ifdef USE_SETEUID
223c2aa98e2SPeter Wemm #  define setreuid(r, e)		seteuid(e)
2243299c2f1SGregory Neil Shapiro # endif /* USE_SETEUID */
225c2aa98e2SPeter Wemm 
226c2aa98e2SPeter Wemm /*
2273299c2f1SGregory Neil Shapiro **  And of course on hpux you have setresuid()
228c2aa98e2SPeter Wemm */
229c2aa98e2SPeter Wemm # ifdef USE_SETRESUID
230c2aa98e2SPeter Wemm #  define setreuid(r, e)		setresuid(-1, e, -1)
2313299c2f1SGregory Neil Shapiro # endif /* USE_SETRESUID */
232c2aa98e2SPeter Wemm 
233c2aa98e2SPeter Wemm # ifndef _PATH_LOCTMP
2343299c2f1SGregory Neil Shapiro #  define _PATH_LOCTMP	"/var/tmp/local.XXXXXX"
2353299c2f1SGregory Neil Shapiro # endif /* ! _PATH_LOCTMP */
236c2aa98e2SPeter Wemm #  ifndef _PATH_MAILDIR
237c2aa98e2SPeter Wemm #   define _PATH_MAILDIR	"/var/spool/mail"
2383299c2f1SGregory Neil Shapiro #  endif /* ! _PATH_MAILDIR */
239c2aa98e2SPeter Wemm 
240c2aa98e2SPeter Wemm # ifndef S_ISREG
241c2aa98e2SPeter Wemm #  define S_ISREG(mode)	(((mode) & _S_IFMT) == S_IFREG)
2423299c2f1SGregory Neil Shapiro # endif /* ! S_ISREG */
2433299c2f1SGregory Neil Shapiro 
2443299c2f1SGregory Neil Shapiro # ifdef MAILLOCK
2453299c2f1SGregory Neil Shapiro #  include <maillock.h>
2463299c2f1SGregory Neil Shapiro # endif /* MAILLOCK */
2473299c2f1SGregory Neil Shapiro 
248d995d2baSGregory Neil Shapiro # define U_UID pw->pw_uid
249d995d2baSGregory Neil Shapiro # define U_GID pw->pw_gid
250d995d2baSGregory Neil Shapiro 
2513299c2f1SGregory Neil Shapiro #ifndef INADDRSZ
2523299c2f1SGregory Neil Shapiro # define INADDRSZ	4		/* size of an IPv4 address in bytes */
2533299c2f1SGregory Neil Shapiro #endif /* ! INADDRSZ */
254c2aa98e2SPeter Wemm 
25576b7bf71SPeter Wemm #ifndef MAILER_DAEMON
25676b7bf71SPeter Wemm # define MAILER_DAEMON	"MAILER-DAEMON"
2573299c2f1SGregory Neil Shapiro #endif /* ! MAILER_DAEMON */
25876b7bf71SPeter Wemm 
2593299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
2603299c2f1SGregory Neil Shapiro char	ContentHdr[40] = "Content-Length: ";
2613299c2f1SGregory Neil Shapiro off_t	HeaderLength;
2623299c2f1SGregory Neil Shapiro off_t	BodyLength;
2633299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
264c2aa98e2SPeter Wemm 
2653299c2f1SGregory Neil Shapiro bool	EightBitMime = TRUE;		/* advertise 8BITMIME in LMTP */
2663299c2f1SGregory Neil Shapiro int	ExitVal = EX_OK;		/* sysexits.h error value. */
2673299c2f1SGregory Neil Shapiro bool	LMTPMode = FALSE;
2683299c2f1SGregory Neil Shapiro bool	bouncequota = FALSE;		/* permanent error when over quota */
2693299c2f1SGregory Neil Shapiro bool	nobiff = FALSE;
2703299c2f1SGregory Neil Shapiro bool	nofsync = FALSE;
2713299c2f1SGregory Neil Shapiro 
2723299c2f1SGregory Neil Shapiro void	deliver __P((int, char *, bool));
2733299c2f1SGregory Neil Shapiro int	e_to_sys __P((int));
274c2aa98e2SPeter Wemm void	notifybiff __P((char *));
275c2aa98e2SPeter Wemm int	store __P((char *, int));
276c2aa98e2SPeter Wemm void	usage __P((void));
277c2aa98e2SPeter Wemm void	vwarn __P((const char *, _BSD_VA_LIST_));
2783299c2f1SGregory Neil Shapiro int	lockmbox __P((char *));
279c2aa98e2SPeter Wemm void	unlockmbox __P((void));
280c2aa98e2SPeter Wemm void	mailerr __P((const char *, const char *, ...));
2813299c2f1SGregory Neil Shapiro 
282c2aa98e2SPeter Wemm 
283c2aa98e2SPeter Wemm int
284c2aa98e2SPeter Wemm main(argc, argv)
285c2aa98e2SPeter Wemm 	int argc;
286c2aa98e2SPeter Wemm 	char *argv[];
287c2aa98e2SPeter Wemm {
288c2aa98e2SPeter Wemm 	struct passwd *pw;
2893299c2f1SGregory Neil Shapiro 	int ch, fd;
290c2aa98e2SPeter Wemm 	uid_t uid;
291c2aa98e2SPeter Wemm 	char *from;
292c2aa98e2SPeter Wemm 	extern char *optarg;
293c2aa98e2SPeter Wemm 	extern int optind;
2943299c2f1SGregory Neil Shapiro 	extern void dolmtp __P((bool));
2953299c2f1SGregory Neil Shapiro 
296c2aa98e2SPeter Wemm 
297c2aa98e2SPeter Wemm 	/* make sure we have some open file descriptors */
298c2aa98e2SPeter Wemm 	for (fd = 10; fd < 30; fd++)
299c2aa98e2SPeter Wemm 		(void) close(fd);
300c2aa98e2SPeter Wemm 
301c2aa98e2SPeter Wemm 	/* use a reasonable umask */
302c2aa98e2SPeter Wemm 	(void) umask(0077);
303c2aa98e2SPeter Wemm 
304c2aa98e2SPeter Wemm # ifdef LOG_MAIL
305c2aa98e2SPeter Wemm 	openlog("mail.local", 0, LOG_MAIL);
3063299c2f1SGregory Neil Shapiro # else /* LOG_MAIL */
307c2aa98e2SPeter Wemm 	openlog("mail.local", 0);
3083299c2f1SGregory Neil Shapiro # endif /* LOG_MAIL */
309c2aa98e2SPeter Wemm 
310c2aa98e2SPeter Wemm 	from = NULL;
3113299c2f1SGregory Neil Shapiro 	while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1)
3123299c2f1SGregory Neil Shapiro 	{
3133299c2f1SGregory Neil Shapiro 		switch(ch)
3143299c2f1SGregory Neil Shapiro 		{
3153299c2f1SGregory Neil Shapiro 		  case '7':		/* Do not advertise 8BITMIME */
3163299c2f1SGregory Neil Shapiro 			EightBitMime = FALSE;
317d615a192SPeter Wemm 			break;
3183299c2f1SGregory Neil Shapiro 
3193299c2f1SGregory Neil Shapiro 		  case 'B':
3203299c2f1SGregory Neil Shapiro 			nobiff = TRUE;
3213299c2f1SGregory Neil Shapiro 			break;
3223299c2f1SGregory Neil Shapiro 
3233299c2f1SGregory Neil Shapiro 		  case 'b':		/* bounce mail when over quota. */
3243299c2f1SGregory Neil Shapiro 			bouncequota = TRUE;
3253299c2f1SGregory Neil Shapiro 			break;
3263299c2f1SGregory Neil Shapiro 
327c2aa98e2SPeter Wemm 		  case 'd':		/* Backward compatible. */
328c2aa98e2SPeter Wemm 			break;
3293299c2f1SGregory Neil Shapiro 
330c2aa98e2SPeter Wemm 		  case 'f':
331c2aa98e2SPeter Wemm 		  case 'r':		/* Backward compatible. */
3323299c2f1SGregory Neil Shapiro 			if (from != NULL)
3333299c2f1SGregory Neil Shapiro 			{
33476b7bf71SPeter Wemm 				mailerr(NULL, "multiple -f options");
335c2aa98e2SPeter Wemm 				usage();
336c2aa98e2SPeter Wemm 			}
337c2aa98e2SPeter Wemm 			from = optarg;
338c2aa98e2SPeter Wemm 			break;
3393299c2f1SGregory Neil Shapiro 
340c2aa98e2SPeter Wemm 		  case 'l':
3413299c2f1SGregory Neil Shapiro 			LMTPMode = TRUE;
342c2aa98e2SPeter Wemm 			break;
3433299c2f1SGregory Neil Shapiro 
344d615a192SPeter Wemm 		  case 's':
34505b73c60SPeter Wemm 			nofsync++;
346d615a192SPeter Wemm 			break;
3473299c2f1SGregory Neil Shapiro 
348c2aa98e2SPeter Wemm 		  case '?':
349c2aa98e2SPeter Wemm 		  default:
350c2aa98e2SPeter Wemm 			usage();
351c2aa98e2SPeter Wemm 		}
3523299c2f1SGregory Neil Shapiro 	}
353c2aa98e2SPeter Wemm 	argc -= optind;
354c2aa98e2SPeter Wemm 	argv += optind;
355c2aa98e2SPeter Wemm 
3563299c2f1SGregory Neil Shapiro 	/* initialize biff structures */
3573299c2f1SGregory Neil Shapiro 	if (!nobiff)
3583299c2f1SGregory Neil Shapiro 		notifybiff(NULL);
359c2aa98e2SPeter Wemm 
3603299c2f1SGregory Neil Shapiro 	if (LMTPMode)
3613299c2f1SGregory Neil Shapiro 		dolmtp(bouncequota);
3623299c2f1SGregory Neil Shapiro 
3633299c2f1SGregory Neil Shapiro 	if (*argv == '\0')
364c2aa98e2SPeter Wemm 		usage();
365c2aa98e2SPeter Wemm 
366c2aa98e2SPeter Wemm 	/*
3673299c2f1SGregory Neil Shapiro 	**  If from not specified, use the name from getlogin() if the
3683299c2f1SGregory Neil Shapiro 	**  uid matches, otherwise, use the name from the password file
3693299c2f1SGregory Neil Shapiro 	**  corresponding to the uid.
370c2aa98e2SPeter Wemm 	*/
371c2aa98e2SPeter Wemm 	uid = getuid();
3723299c2f1SGregory Neil Shapiro 
3733299c2f1SGregory Neil Shapiro 	if (from == NULL && ((from = getlogin()) == NULL ||
3743299c2f1SGregory Neil Shapiro 			     (pw = getpwnam(from)) == NULL ||
3753299c2f1SGregory Neil Shapiro 			     pw->pw_uid != uid))
3763299c2f1SGregory Neil Shapiro 		from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
377c2aa98e2SPeter Wemm 
378c2aa98e2SPeter Wemm 	/*
3793299c2f1SGregory Neil Shapiro 	**  There is no way to distinguish the error status of one delivery
3803299c2f1SGregory Neil Shapiro 	**  from the rest of the deliveries.  So, if we failed hard on one
3813299c2f1SGregory Neil Shapiro 	**  or more deliveries, but had no failures on any of the others, we
3823299c2f1SGregory Neil Shapiro 	**  return a hard failure.  If we failed temporarily on one or more
3833299c2f1SGregory Neil Shapiro 	**  deliveries, we return a temporary failure regardless of the other
3843299c2f1SGregory Neil Shapiro 	**  failures.  This results in the delivery being reattempted later
3853299c2f1SGregory Neil Shapiro 	**  at the expense of repeated failures and multiple deliveries.
386c2aa98e2SPeter Wemm 	*/
387c2aa98e2SPeter Wemm 	for (fd = store(from, 0); *argv; ++argv)
3883299c2f1SGregory Neil Shapiro 		deliver(fd, *argv, bouncequota);
3893299c2f1SGregory Neil Shapiro 	exit(ExitVal);
3903299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
3913299c2f1SGregory Neil Shapiro 	return ExitVal;
392c2aa98e2SPeter Wemm }
393c2aa98e2SPeter Wemm 
394c2aa98e2SPeter Wemm char *
3953299c2f1SGregory Neil Shapiro parseaddr(s, rcpt)
396c2aa98e2SPeter Wemm 	char *s;
3973299c2f1SGregory Neil Shapiro 	bool rcpt;
398c2aa98e2SPeter Wemm {
399c2aa98e2SPeter Wemm 	char *p;
4003299c2f1SGregory Neil Shapiro 	int l;
401c2aa98e2SPeter Wemm 
402c2aa98e2SPeter Wemm 	if (*s++ != '<')
403c2aa98e2SPeter Wemm 		return NULL;
404c2aa98e2SPeter Wemm 
405c2aa98e2SPeter Wemm 	p = s;
406c2aa98e2SPeter Wemm 
407c2aa98e2SPeter Wemm 	/* at-domain-list */
4083299c2f1SGregory Neil Shapiro 	while (*p == '@')
4093299c2f1SGregory Neil Shapiro 	{
410c2aa98e2SPeter Wemm 		p++;
4113299c2f1SGregory Neil Shapiro 		while (*p != ',' && *p != ':' && *p != '\0')
412c2aa98e2SPeter Wemm 			p++;
4133299c2f1SGregory Neil Shapiro 		if (*p == '\0')
414c2aa98e2SPeter Wemm 			return NULL;
4153299c2f1SGregory Neil Shapiro 
4163299c2f1SGregory Neil Shapiro 		/* Skip over , or : */
417c2aa98e2SPeter Wemm 		p++;
418c2aa98e2SPeter Wemm 	}
419c2aa98e2SPeter Wemm 
42076b7bf71SPeter Wemm 	s = p;
42176b7bf71SPeter Wemm 
422c2aa98e2SPeter Wemm 	/* local-part */
4233299c2f1SGregory Neil Shapiro 	while (*p != '\0' && *p != '@' && *p != '>')
4243299c2f1SGregory Neil Shapiro 	{
4253299c2f1SGregory Neil Shapiro 		if (*p == '\\')
4263299c2f1SGregory Neil Shapiro 		{
4273299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
4283299c2f1SGregory Neil Shapiro 				return NULL;
4293299c2f1SGregory Neil Shapiro 		}
4303299c2f1SGregory Neil Shapiro 		else if (*p == '\"')
4313299c2f1SGregory Neil Shapiro 		{
432c2aa98e2SPeter Wemm 			p++;
4333299c2f1SGregory Neil Shapiro 			while (*p != '\0' && *p != '\"')
4343299c2f1SGregory Neil Shapiro 			{
4353299c2f1SGregory Neil Shapiro 				if (*p == '\\')
4363299c2f1SGregory Neil Shapiro 				{
4373299c2f1SGregory Neil Shapiro 					if (*++p == '\0')
438c2aa98e2SPeter Wemm 						return NULL;
439c2aa98e2SPeter Wemm 				}
440c2aa98e2SPeter Wemm 				p++;
441c2aa98e2SPeter Wemm 			}
4423299c2f1SGregory Neil Shapiro 			if (*p == '\0' || *(p + 1) == '\0')
443c2aa98e2SPeter Wemm 				return NULL;
444c2aa98e2SPeter Wemm 		}
4453299c2f1SGregory Neil Shapiro 		/* +detail ? */
4463299c2f1SGregory Neil Shapiro 		if (*p == '+' && rcpt)
4473299c2f1SGregory Neil Shapiro 			*p = '\0';
448c2aa98e2SPeter Wemm 		p++;
449c2aa98e2SPeter Wemm 	}
450c2aa98e2SPeter Wemm 
451c2aa98e2SPeter Wemm 	/* @domain */
4523299c2f1SGregory Neil Shapiro 	if (*p == '@')
45376b7bf71SPeter Wemm 	{
4543299c2f1SGregory Neil Shapiro 		if (rcpt)
4553299c2f1SGregory Neil Shapiro 			*p++ = '\0';
4563299c2f1SGregory Neil Shapiro 		while (*p != '\0' && *p != '>')
4573299c2f1SGregory Neil Shapiro 			p++;
45876b7bf71SPeter Wemm 	}
459c2aa98e2SPeter Wemm 
4603299c2f1SGregory Neil Shapiro 	if (*p != '>')
4613299c2f1SGregory Neil Shapiro 		return NULL;
4623299c2f1SGregory Neil Shapiro 	else
4633299c2f1SGregory Neil Shapiro 		*p = '\0';
4643299c2f1SGregory Neil Shapiro 	p++;
4653299c2f1SGregory Neil Shapiro 
4663299c2f1SGregory Neil Shapiro 	if (*p != '\0' && *p != ' ')
4673299c2f1SGregory Neil Shapiro 		return NULL;
4683299c2f1SGregory Neil Shapiro 
4693299c2f1SGregory Neil Shapiro 	if (*s == '\0')
4703299c2f1SGregory Neil Shapiro 		s = MAILER_DAEMON;
4713299c2f1SGregory Neil Shapiro 
4723299c2f1SGregory Neil Shapiro 	l = strlen(s) + 1;
4733299c2f1SGregory Neil Shapiro 	p = malloc(l);
4743299c2f1SGregory Neil Shapiro 	if (p == NULL)
4753299c2f1SGregory Neil Shapiro 	{
476c2aa98e2SPeter Wemm 		printf("421 4.3.0 memory exhausted\r\n");
477c2aa98e2SPeter Wemm 		exit(EX_TEMPFAIL);
478c2aa98e2SPeter Wemm 	}
479c2aa98e2SPeter Wemm 
4803299c2f1SGregory Neil Shapiro 	(void) strlcpy(p, s, l);
481c2aa98e2SPeter Wemm 	return p;
482c2aa98e2SPeter Wemm }
483c2aa98e2SPeter Wemm 
484c2aa98e2SPeter Wemm char *
485c2aa98e2SPeter Wemm process_recipient(addr)
486c2aa98e2SPeter Wemm 	char *addr;
487c2aa98e2SPeter Wemm {
4883299c2f1SGregory Neil Shapiro 	if (getpwnam(addr) == NULL)
489c2aa98e2SPeter Wemm 		return "550 5.1.1 user unknown";
490c2aa98e2SPeter Wemm 	return NULL;
491c2aa98e2SPeter Wemm }
492c2aa98e2SPeter Wemm 
493c2aa98e2SPeter Wemm #define RCPT_GROW	30
494c2aa98e2SPeter Wemm 
495c2aa98e2SPeter Wemm void
4963299c2f1SGregory Neil Shapiro dolmtp(bouncequota)
4973299c2f1SGregory Neil Shapiro 	bool bouncequota;
498c2aa98e2SPeter Wemm {
499c2aa98e2SPeter Wemm 	char *return_path = NULL;
500c2aa98e2SPeter Wemm 	char **rcpt_addr = NULL;
501c2aa98e2SPeter Wemm 	int rcpt_num = 0;
502c2aa98e2SPeter Wemm 	int rcpt_alloc = 0;
5033299c2f1SGregory Neil Shapiro 	bool gotlhlo = FALSE;
504c2aa98e2SPeter Wemm 	char *err;
505c2aa98e2SPeter Wemm 	int msgfd;
506c2aa98e2SPeter Wemm 	char *p;
507c2aa98e2SPeter Wemm 	int i;
5083299c2f1SGregory Neil Shapiro 	char myhostname[1024];
5093299c2f1SGregory Neil Shapiro 	char buf[4096];
510c2aa98e2SPeter Wemm 
5113299c2f1SGregory Neil Shapiro 	(void) gethostname(myhostname, sizeof myhostname - 1);
512c2aa98e2SPeter Wemm 
513c2aa98e2SPeter Wemm 	printf("220 %s LMTP ready\r\n", myhostname);
5143299c2f1SGregory Neil Shapiro 	for (;;)
5153299c2f1SGregory Neil Shapiro 	{
5163299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
5173299c2f1SGregory Neil Shapiro 		if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
518c2aa98e2SPeter Wemm 			exit(EX_OK);
519c2aa98e2SPeter Wemm 		p = buf + strlen(buf) - 1;
520c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\n')
521c2aa98e2SPeter Wemm 			*p-- = '\0';
522c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\r')
523c2aa98e2SPeter Wemm 			*p-- = '\0';
524c2aa98e2SPeter Wemm 
5253299c2f1SGregory Neil Shapiro 		switch (buf[0])
5263299c2f1SGregory Neil Shapiro 		{
527c2aa98e2SPeter Wemm 		  case 'd':
528c2aa98e2SPeter Wemm 		  case 'D':
5293299c2f1SGregory Neil Shapiro 			if (strcasecmp(buf, "data") == 0)
5303299c2f1SGregory Neil Shapiro 			{
5313299c2f1SGregory Neil Shapiro 				if (rcpt_num == 0)
5323299c2f1SGregory Neil Shapiro 				{
533c2aa98e2SPeter Wemm 					printf("503 5.5.1 No recipients\r\n");
534c2aa98e2SPeter Wemm 					continue;
535c2aa98e2SPeter Wemm 				}
536c2aa98e2SPeter Wemm 				msgfd = store(return_path, rcpt_num);
537c2aa98e2SPeter Wemm 				if (msgfd == -1)
538c2aa98e2SPeter Wemm 					continue;
539c2aa98e2SPeter Wemm 
5403299c2f1SGregory Neil Shapiro 				for (i = 0; i < rcpt_num; i++)
5413299c2f1SGregory Neil Shapiro 				{
542c2aa98e2SPeter Wemm 					p = strchr(rcpt_addr[i], '+');
543c2aa98e2SPeter Wemm 					if (p != NULL)
544c2aa98e2SPeter Wemm 						*p++ = '\0';
545d995d2baSGregory Neil Shapiro 					deliver(msgfd, rcpt_addr[i],
546d995d2baSGregory Neil Shapiro 						bouncequota);
547c2aa98e2SPeter Wemm 				}
5483299c2f1SGregory Neil Shapiro 				(void) close(msgfd);
549c2aa98e2SPeter Wemm 				goto rset;
550c2aa98e2SPeter Wemm 			}
551c2aa98e2SPeter Wemm 			goto syntaxerr;
5523299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5533299c2f1SGregory Neil Shapiro 			break;
554c2aa98e2SPeter Wemm 
555c2aa98e2SPeter Wemm 		  case 'l':
556c2aa98e2SPeter Wemm 		  case 'L':
5573299c2f1SGregory Neil Shapiro 			if (strncasecmp(buf, "lhlo ", 5) == 0)
5583299c2f1SGregory Neil Shapiro 			{
5593299c2f1SGregory Neil Shapiro 				/* check for duplicate per RFC 1651 4.2 */
5603299c2f1SGregory Neil Shapiro 				if (gotlhlo)
5613299c2f1SGregory Neil Shapiro 				{
5623299c2f1SGregory Neil Shapiro 					printf("503 %s Duplicate LHLO\r\n",
563c2aa98e2SPeter Wemm 					       myhostname);
564c2aa98e2SPeter Wemm 					continue;
565c2aa98e2SPeter Wemm 				}
5663299c2f1SGregory Neil Shapiro 				gotlhlo = TRUE;
5673299c2f1SGregory Neil Shapiro 				printf("250-%s\r\n", myhostname);
5683299c2f1SGregory Neil Shapiro 				if (EightBitMime)
5693299c2f1SGregory Neil Shapiro 					printf("250-8BITMIME\r\n");
5703299c2f1SGregory Neil Shapiro 				printf("250-ENHANCEDSTATUSCODES\r\n");
5713299c2f1SGregory Neil Shapiro 				printf("250 PIPELINING\r\n");
5723299c2f1SGregory Neil Shapiro 				continue;
5733299c2f1SGregory Neil Shapiro 			}
574c2aa98e2SPeter Wemm 			goto syntaxerr;
5753299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5763299c2f1SGregory Neil Shapiro 			break;
577c2aa98e2SPeter Wemm 
578c2aa98e2SPeter Wemm 		  case 'm':
579c2aa98e2SPeter Wemm 		  case 'M':
5803299c2f1SGregory Neil Shapiro 			if (strncasecmp(buf, "mail ", 5) == 0)
5813299c2f1SGregory Neil Shapiro 			{
5823299c2f1SGregory Neil Shapiro 				if (return_path != NULL)
5833299c2f1SGregory Neil Shapiro 				{
584c2aa98e2SPeter Wemm 					printf("503 5.5.1 Nested MAIL command\r\n");
585c2aa98e2SPeter Wemm 					continue;
586c2aa98e2SPeter Wemm 				}
587c2aa98e2SPeter Wemm 				if (strncasecmp(buf+5, "from:", 5) != 0 ||
5883299c2f1SGregory Neil Shapiro 				    ((return_path = parseaddr(buf + 10,
5893299c2f1SGregory Neil Shapiro 							      FALSE)) == NULL))
5903299c2f1SGregory Neil Shapiro 				{
591c2aa98e2SPeter Wemm 					printf("501 5.5.4 Syntax error in parameters\r\n");
592c2aa98e2SPeter Wemm 					continue;
593c2aa98e2SPeter Wemm 				}
594c2aa98e2SPeter Wemm 				printf("250 2.5.0 ok\r\n");
595c2aa98e2SPeter Wemm 				continue;
596c2aa98e2SPeter Wemm 			}
597c2aa98e2SPeter Wemm 			goto syntaxerr;
5983299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
5993299c2f1SGregory Neil Shapiro 			break;
600c2aa98e2SPeter Wemm 
601c2aa98e2SPeter Wemm 		  case 'n':
602c2aa98e2SPeter Wemm 		  case 'N':
6033299c2f1SGregory Neil Shapiro 			if (strcasecmp(buf, "noop") == 0)
6043299c2f1SGregory Neil Shapiro 			{
605c2aa98e2SPeter Wemm 				printf("250 2.0.0 ok\r\n");
606c2aa98e2SPeter Wemm 				continue;
607c2aa98e2SPeter Wemm 			}
608c2aa98e2SPeter Wemm 			goto syntaxerr;
6093299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6103299c2f1SGregory Neil Shapiro 			break;
611c2aa98e2SPeter Wemm 
612c2aa98e2SPeter Wemm 		  case 'q':
613c2aa98e2SPeter Wemm 		  case 'Q':
6143299c2f1SGregory Neil Shapiro 			if (strcasecmp(buf, "quit") == 0)
6153299c2f1SGregory Neil Shapiro 			{
616c2aa98e2SPeter Wemm 				printf("221 2.0.0 bye\r\n");
617c2aa98e2SPeter Wemm 				exit(EX_OK);
618c2aa98e2SPeter Wemm 			}
619c2aa98e2SPeter Wemm 			goto syntaxerr;
6203299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6213299c2f1SGregory Neil Shapiro 			break;
622c2aa98e2SPeter Wemm 
623c2aa98e2SPeter Wemm 		  case 'r':
624c2aa98e2SPeter Wemm 		  case 'R':
6253299c2f1SGregory Neil Shapiro 			if (strncasecmp(buf, "rcpt ", 5) == 0)
6263299c2f1SGregory Neil Shapiro 			{
6273299c2f1SGregory Neil Shapiro 				if (return_path == NULL)
6283299c2f1SGregory Neil Shapiro 				{
629c2aa98e2SPeter Wemm 					printf("503 5.5.1 Need MAIL command\r\n");
630c2aa98e2SPeter Wemm 					continue;
631c2aa98e2SPeter Wemm 				}
6323299c2f1SGregory Neil Shapiro 				if (rcpt_num >= rcpt_alloc)
6333299c2f1SGregory Neil Shapiro 				{
634c2aa98e2SPeter Wemm 					rcpt_alloc += RCPT_GROW;
635c2aa98e2SPeter Wemm 					rcpt_addr = (char **)
6363299c2f1SGregory Neil Shapiro 						REALLOC((char *) rcpt_addr,
6373299c2f1SGregory Neil Shapiro 							rcpt_alloc *
6383299c2f1SGregory Neil Shapiro 							sizeof(char **));
6393299c2f1SGregory Neil Shapiro 					if (rcpt_addr == NULL)
6403299c2f1SGregory Neil Shapiro 					{
641c2aa98e2SPeter Wemm 						printf("421 4.3.0 memory exhausted\r\n");
642c2aa98e2SPeter Wemm 						exit(EX_TEMPFAIL);
643c2aa98e2SPeter Wemm 					}
644c2aa98e2SPeter Wemm 				}
645c2aa98e2SPeter Wemm 				if (strncasecmp(buf + 5, "to:", 3) != 0 ||
6463299c2f1SGregory Neil Shapiro 				    ((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
6473299c2f1SGregory Neil Shapiro 								      TRUE)) == NULL))
6483299c2f1SGregory Neil Shapiro 				{
649c2aa98e2SPeter Wemm 					printf("501 5.5.4 Syntax error in parameters\r\n");
650c2aa98e2SPeter Wemm 					continue;
651c2aa98e2SPeter Wemm 				}
6523299c2f1SGregory Neil Shapiro 				if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL)
6533299c2f1SGregory Neil Shapiro 				{
654c2aa98e2SPeter Wemm 					printf("%s\r\n", err);
655c2aa98e2SPeter Wemm 					continue;
656c2aa98e2SPeter Wemm 				}
657c2aa98e2SPeter Wemm 				rcpt_num++;
658c2aa98e2SPeter Wemm 				printf("250 2.1.5 ok\r\n");
659c2aa98e2SPeter Wemm 				continue;
660c2aa98e2SPeter Wemm 			}
6613299c2f1SGregory Neil Shapiro 			else if (strcasecmp(buf, "rset") == 0)
6623299c2f1SGregory Neil Shapiro 			{
663c2aa98e2SPeter Wemm 				printf("250 2.0.0 ok\r\n");
664c2aa98e2SPeter Wemm 
665c2aa98e2SPeter Wemm rset:
6663299c2f1SGregory Neil Shapiro 				while (rcpt_num)
667c2aa98e2SPeter Wemm 					free(rcpt_addr[--rcpt_num]);
668c2aa98e2SPeter Wemm 				if (return_path != NULL)
669c2aa98e2SPeter Wemm 					free(return_path);
670c2aa98e2SPeter Wemm 				return_path = NULL;
671c2aa98e2SPeter Wemm 				continue;
672c2aa98e2SPeter Wemm 			}
673c2aa98e2SPeter Wemm 			goto syntaxerr;
6743299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6753299c2f1SGregory Neil Shapiro 			break;
676c2aa98e2SPeter Wemm 
677c2aa98e2SPeter Wemm 		  case 'v':
678c2aa98e2SPeter Wemm 		  case 'V':
6793299c2f1SGregory Neil Shapiro 			if (strncasecmp(buf, "vrfy ", 5) == 0)
6803299c2f1SGregory Neil Shapiro 			{
681c2aa98e2SPeter Wemm 				printf("252 2.3.3 try RCPT to attempt delivery\r\n");
682c2aa98e2SPeter Wemm 				continue;
683c2aa98e2SPeter Wemm 			}
684c2aa98e2SPeter Wemm 			goto syntaxerr;
6853299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6863299c2f1SGregory Neil Shapiro 			break;
687c2aa98e2SPeter Wemm 
688c2aa98e2SPeter Wemm 		  default:
689c2aa98e2SPeter Wemm   syntaxerr:
690c2aa98e2SPeter Wemm 			printf("500 5.5.2 Syntax error\r\n");
691c2aa98e2SPeter Wemm 			continue;
6923299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6933299c2f1SGregory Neil Shapiro 			break;
694c2aa98e2SPeter Wemm 		}
695c2aa98e2SPeter Wemm 	}
696c2aa98e2SPeter Wemm }
697c2aa98e2SPeter Wemm 
698c2aa98e2SPeter Wemm int
699c2aa98e2SPeter Wemm store(from, lmtprcpts)
700c2aa98e2SPeter Wemm 	char *from;
701c2aa98e2SPeter Wemm 	int lmtprcpts;
702c2aa98e2SPeter Wemm {
70376b7bf71SPeter Wemm 	FILE *fp = NULL;
704c2aa98e2SPeter Wemm 	time_t tval;
7053299c2f1SGregory Neil Shapiro 	bool eline;
7063299c2f1SGregory Neil Shapiro 	bool fullline = TRUE;	/* current line is terminated */
7073299c2f1SGregory Neil Shapiro 	bool prevfl;		/* previous line was terminated */
708c2aa98e2SPeter Wemm 	char line[2048];
7093299c2f1SGregory Neil Shapiro 	int fd;
710c2aa98e2SPeter Wemm 	char tmpbuf[sizeof _PATH_LOCTMP + 1];
711c2aa98e2SPeter Wemm 
7123299c2f1SGregory Neil Shapiro 	(void) umask(0077);
7133299c2f1SGregory Neil Shapiro 	(void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
7143299c2f1SGregory Neil Shapiro 	if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL)
7153299c2f1SGregory Neil Shapiro 	{
7163299c2f1SGregory Neil Shapiro 		if (lmtprcpts)
7173299c2f1SGregory Neil Shapiro 		{
718c2aa98e2SPeter Wemm 			printf("451 4.3.0 unable to open temporary file\r\n");
719c2aa98e2SPeter Wemm 			return -1;
7203299c2f1SGregory Neil Shapiro 		}
7213299c2f1SGregory Neil Shapiro 		else
7223299c2f1SGregory Neil Shapiro 		{
72376b7bf71SPeter Wemm 			mailerr("451 4.3.0", "unable to open temporary file");
7243299c2f1SGregory Neil Shapiro 			exit(ExitVal);
725c2aa98e2SPeter Wemm 		}
726c2aa98e2SPeter Wemm 	}
727c2aa98e2SPeter Wemm 	(void) unlink(tmpbuf);
728c2aa98e2SPeter Wemm 
7293299c2f1SGregory Neil Shapiro 	if (LMTPMode)
7303299c2f1SGregory Neil Shapiro 	{
731c2aa98e2SPeter Wemm 		printf("354 go ahead\r\n");
7323299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
733c2aa98e2SPeter Wemm 	}
734c2aa98e2SPeter Wemm 
735c2aa98e2SPeter Wemm 	(void) time(&tval);
736c2aa98e2SPeter Wemm 	(void) fprintf(fp, "From %s %s", from, ctime(&tval));
737c2aa98e2SPeter Wemm 
7383299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
7393299c2f1SGregory Neil Shapiro 	HeaderLength = 0;
7403299c2f1SGregory Neil Shapiro 	BodyLength = -1;
7413299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
7423299c2f1SGregory Neil Shapiro 
743c2aa98e2SPeter Wemm 	line[0] = '\0';
7443299c2f1SGregory Neil Shapiro 	eline = TRUE;
7453299c2f1SGregory Neil Shapiro 	while (fgets(line, sizeof(line), stdin) != (char *)NULL)
7463299c2f1SGregory Neil Shapiro 	{
7473299c2f1SGregory Neil Shapiro 		size_t line_len = 0;
7483299c2f1SGregory Neil Shapiro 		int peek;
74976b7bf71SPeter Wemm 
7503299c2f1SGregory Neil Shapiro 		prevfl = fullline;	/* preserve state of previous line */
7513299c2f1SGregory Neil Shapiro 		while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
7523299c2f1SGregory Neil Shapiro 			line_len++;
7533299c2f1SGregory Neil Shapiro 		line_len++;
75476b7bf71SPeter Wemm 
7553299c2f1SGregory Neil Shapiro 		/* Check for dot-stuffing */
7563299c2f1SGregory Neil Shapiro 		if (prevfl && lmtprcpts && line[0] == '.')
7573299c2f1SGregory Neil Shapiro 		{
7583299c2f1SGregory Neil Shapiro 			if (line[1] == '\n' ||
7593299c2f1SGregory Neil Shapiro 			    (line[1] == '\r' && line[2] == '\n'))
760c2aa98e2SPeter Wemm 				goto lmtpdot;
7613299c2f1SGregory Neil Shapiro 			memcpy(line, line + 1, line_len);
7623299c2f1SGregory Neil Shapiro 			line_len--;
763c2aa98e2SPeter Wemm 		}
7643299c2f1SGregory Neil Shapiro 
7653299c2f1SGregory Neil Shapiro 		/* Check to see if we have the full line from fgets() */
7663299c2f1SGregory Neil Shapiro 		fullline = FALSE;
7673299c2f1SGregory Neil Shapiro 		if (line_len > 0)
7683299c2f1SGregory Neil Shapiro 		{
7693299c2f1SGregory Neil Shapiro 			if (line[line_len - 1] == '\n')
7703299c2f1SGregory Neil Shapiro 			{
7713299c2f1SGregory Neil Shapiro 				if (line_len >= 2 &&
7723299c2f1SGregory Neil Shapiro 				    line[line_len - 2] == '\r')
7733299c2f1SGregory Neil Shapiro 				{
7743299c2f1SGregory Neil Shapiro 					line[line_len - 2] = '\n';
7753299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\0';
7763299c2f1SGregory Neil Shapiro 					line_len--;
7773299c2f1SGregory Neil Shapiro 				}
7783299c2f1SGregory Neil Shapiro 				fullline = TRUE;
7793299c2f1SGregory Neil Shapiro 			}
7803299c2f1SGregory Neil Shapiro 			else if (line[line_len - 1] == '\r')
7813299c2f1SGregory Neil Shapiro 			{
7823299c2f1SGregory Neil Shapiro 				/* Did we just miss the CRLF? */
7833299c2f1SGregory Neil Shapiro 				peek = fgetc(stdin);
7843299c2f1SGregory Neil Shapiro 				if (peek == '\n')
7853299c2f1SGregory Neil Shapiro 				{
7863299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\n';
7873299c2f1SGregory Neil Shapiro 					fullline = TRUE;
7883299c2f1SGregory Neil Shapiro 				}
7893299c2f1SGregory Neil Shapiro 				else
7903299c2f1SGregory Neil Shapiro 					(void) ungetc(peek, stdin);
7913299c2f1SGregory Neil Shapiro 			}
7923299c2f1SGregory Neil Shapiro 		}
7933299c2f1SGregory Neil Shapiro 		else
7943299c2f1SGregory Neil Shapiro 			fullline = TRUE;
7953299c2f1SGregory Neil Shapiro 
7963299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
7973299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n' && HeaderLength == 0)
7983299c2f1SGregory Neil Shapiro 		{
7993299c2f1SGregory Neil Shapiro 			eline = FALSE;
8003299c2f1SGregory Neil Shapiro 			HeaderLength = ftell(fp);
8013299c2f1SGregory Neil Shapiro 			if (HeaderLength <= 0)
8023299c2f1SGregory Neil Shapiro 			{
8033299c2f1SGregory Neil Shapiro 				/*
8043299c2f1SGregory Neil Shapiro 				**  shouldn't happen, unless ftell() is
8053299c2f1SGregory Neil Shapiro 				**  badly broken
8063299c2f1SGregory Neil Shapiro 				*/
8073299c2f1SGregory Neil Shapiro 
8083299c2f1SGregory Neil Shapiro 				HeaderLength = -1;
8093299c2f1SGregory Neil Shapiro 			}
8103299c2f1SGregory Neil Shapiro 		}
8113299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
8123299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n')
8133299c2f1SGregory Neil Shapiro 			eline = TRUE;
8143299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
8153299c2f1SGregory Neil Shapiro 		else
8163299c2f1SGregory Neil Shapiro 		{
817c2aa98e2SPeter Wemm 			if (eline && line[0] == 'F' &&
818c2aa98e2SPeter Wemm 			    !memcmp(line, "From ", 5))
819c2aa98e2SPeter Wemm 				(void) putc('>', fp);
8203299c2f1SGregory Neil Shapiro 			eline = FALSE;
8213299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
8223299c2f1SGregory Neil Shapiro 			/* discard existing "Content-Length:" headers */
8233299c2f1SGregory Neil Shapiro 			if (prevfl && HeaderLength == 0 &&
8243299c2f1SGregory Neil Shapiro 			    (line[0] == 'C' || line[0] == 'c') &&
8253299c2f1SGregory Neil Shapiro 			    strncasecmp(line, ContentHdr, 15) == 0)
8263299c2f1SGregory Neil Shapiro 			{
8273299c2f1SGregory Neil Shapiro 				/*
8283299c2f1SGregory Neil Shapiro 				**  be paranoid: clear the line
8293299c2f1SGregory Neil Shapiro 				**  so no "wrong matches" may occur later
8303299c2f1SGregory Neil Shapiro 				*/
8313299c2f1SGregory Neil Shapiro 				line[0] = '\0';
8323299c2f1SGregory Neil Shapiro 				continue;
833c2aa98e2SPeter Wemm 			}
8343299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
8353299c2f1SGregory Neil Shapiro 
8363299c2f1SGregory Neil Shapiro 		}
8373299c2f1SGregory Neil Shapiro 		(void) fwrite(line, sizeof(char), line_len, fp);
8383299c2f1SGregory Neil Shapiro 		if (ferror(fp))
8393299c2f1SGregory Neil Shapiro 		{
8403299c2f1SGregory Neil Shapiro 			if (lmtprcpts)
8413299c2f1SGregory Neil Shapiro 			{
8423299c2f1SGregory Neil Shapiro 				while (lmtprcpts--)
843c2aa98e2SPeter Wemm 					printf("451 4.3.0 temporary file write error\r\n");
8443299c2f1SGregory Neil Shapiro 				(void) fclose(fp);
845c2aa98e2SPeter Wemm 				return -1;
8463299c2f1SGregory Neil Shapiro 			}
8473299c2f1SGregory Neil Shapiro 			else
8483299c2f1SGregory Neil Shapiro 			{
84976b7bf71SPeter Wemm 				mailerr("451 4.3.0",
85076b7bf71SPeter Wemm 					"temporary file write error");
8513299c2f1SGregory Neil Shapiro 				(void) fclose(fp);
8523299c2f1SGregory Neil Shapiro 				exit(ExitVal);
853c2aa98e2SPeter Wemm 			}
854c2aa98e2SPeter Wemm 		}
855c2aa98e2SPeter Wemm 	}
856c2aa98e2SPeter Wemm 
8573299c2f1SGregory Neil Shapiro 	if (lmtprcpts)
8583299c2f1SGregory Neil Shapiro 	{
859c2aa98e2SPeter Wemm 		/* Got a premature EOF -- toss message and exit */
860c2aa98e2SPeter Wemm 		exit(EX_OK);
861c2aa98e2SPeter Wemm 	}
862c2aa98e2SPeter Wemm 
863c2aa98e2SPeter Wemm 	/* If message not newline terminated, need an extra. */
864c2aa98e2SPeter Wemm 	if (strchr(line, '\n') == NULL)
865c2aa98e2SPeter Wemm 		(void) putc('\n', fp);
866c2aa98e2SPeter Wemm 
867c2aa98e2SPeter Wemm   lmtpdot:
868c2aa98e2SPeter Wemm 
8693299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
8703299c2f1SGregory Neil Shapiro 	BodyLength = ftell(fp);
8713299c2f1SGregory Neil Shapiro 	if (HeaderLength == 0 && BodyLength > 0)	/* empty body */
8723299c2f1SGregory Neil Shapiro 	{
8733299c2f1SGregory Neil Shapiro 		HeaderLength = BodyLength;
8743299c2f1SGregory Neil Shapiro 		BodyLength = 0;
8753299c2f1SGregory Neil Shapiro 	}
8763299c2f1SGregory Neil Shapiro 	else
8773299c2f1SGregory Neil Shapiro 		BodyLength = BodyLength - HeaderLength - 1 ;
8783299c2f1SGregory Neil Shapiro 
8793299c2f1SGregory Neil Shapiro 	if (HeaderLength > 0 && BodyLength >= 0)
8803299c2f1SGregory Neil Shapiro 	{
8813299c2f1SGregory Neil Shapiro 		extern char *quad_to_string();
8823299c2f1SGregory Neil Shapiro 
8833299c2f1SGregory Neil Shapiro 		if (sizeof BodyLength > sizeof(long))
8843299c2f1SGregory Neil Shapiro 			snprintf(line, sizeof line, "%s\n",
8853299c2f1SGregory Neil Shapiro 				 quad_to_string(BodyLength));
8863299c2f1SGregory Neil Shapiro 		else
887d995d2baSGregory Neil Shapiro 			snprintf(line, sizeof line, "%ld\n",
888d995d2baSGregory Neil Shapiro 				 (long) BodyLength);
8893299c2f1SGregory Neil Shapiro 		strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16);
8903299c2f1SGregory Neil Shapiro 	}
8913299c2f1SGregory Neil Shapiro 	else
8923299c2f1SGregory Neil Shapiro 		BodyLength = -1;	/* Something is wrong here */
8933299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
8943299c2f1SGregory Neil Shapiro 
895c2aa98e2SPeter Wemm 	/* Output a newline; note, empty messages are allowed. */
896c2aa98e2SPeter Wemm 	(void) putc('\n', fp);
897c2aa98e2SPeter Wemm 
8983299c2f1SGregory Neil Shapiro 	if (fflush(fp) == EOF || ferror(fp) != 0)
8993299c2f1SGregory Neil Shapiro 	{
9003299c2f1SGregory Neil Shapiro 		if (lmtprcpts)
9013299c2f1SGregory Neil Shapiro 		{
9023299c2f1SGregory Neil Shapiro 			while (lmtprcpts--)
903c2aa98e2SPeter Wemm 				printf("451 4.3.0 temporary file write error\r\n");
9043299c2f1SGregory Neil Shapiro 			(void) fclose(fp);
905c2aa98e2SPeter Wemm 			return -1;
9063299c2f1SGregory Neil Shapiro 		}
9073299c2f1SGregory Neil Shapiro 		else
9083299c2f1SGregory Neil Shapiro 		{
90976b7bf71SPeter Wemm 			mailerr("451 4.3.0", "temporary file write error");
9103299c2f1SGregory Neil Shapiro 			(void) fclose(fp);
9113299c2f1SGregory Neil Shapiro 			exit(ExitVal);
912c2aa98e2SPeter Wemm 		}
913c2aa98e2SPeter Wemm 	}
9143299c2f1SGregory Neil Shapiro 	return fd;
915c2aa98e2SPeter Wemm }
916c2aa98e2SPeter Wemm 
917c2aa98e2SPeter Wemm void
9183299c2f1SGregory Neil Shapiro deliver(fd, name, bouncequota)
919c2aa98e2SPeter Wemm 	int fd;
920c2aa98e2SPeter Wemm 	char *name;
9213299c2f1SGregory Neil Shapiro 	bool bouncequota;
922c2aa98e2SPeter Wemm {
9233299c2f1SGregory Neil Shapiro 	struct stat fsb;
9243299c2f1SGregory Neil Shapiro 	struct stat sb;
925c2aa98e2SPeter Wemm 	struct passwd *pw;
9263299c2f1SGregory Neil Shapiro 	char path[MAXPATHLEN];
9273299c2f1SGregory Neil Shapiro 	int mbfd, nr = 0, nw, off;
928c2aa98e2SPeter Wemm 	char *p;
929c2aa98e2SPeter Wemm 	off_t curoff;
9303299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
9313299c2f1SGregory Neil Shapiro 	off_t headerbytes;
9323299c2f1SGregory Neil Shapiro 	int readamount;
9333299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
9343299c2f1SGregory Neil Shapiro 	char biffmsg[100], buf[8*1024];
935c2aa98e2SPeter Wemm 	extern char *quad_to_string();
936c2aa98e2SPeter Wemm 
9373299c2f1SGregory Neil Shapiro 
938c2aa98e2SPeter Wemm 	/*
9393299c2f1SGregory Neil Shapiro 	**  Disallow delivery to unknown names -- special mailboxes can be
9403299c2f1SGregory Neil Shapiro 	**  handled in the sendmail aliases file.
941c2aa98e2SPeter Wemm 	*/
9423299c2f1SGregory Neil Shapiro 	if ((pw = getpwnam(name)) == NULL)
9433299c2f1SGregory Neil Shapiro 	{
9443299c2f1SGregory Neil Shapiro 		if (ExitVal != EX_TEMPFAIL)
9453299c2f1SGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
9463299c2f1SGregory Neil Shapiro 		if (LMTPMode)
9473299c2f1SGregory Neil Shapiro 		{
9483299c2f1SGregory Neil Shapiro 			if (ExitVal == EX_TEMPFAIL)
949d995d2baSGregory Neil Shapiro 				printf("451 4.3.0 cannot lookup name: %s\r\n",
950d995d2baSGregory Neil Shapiro 				       name);
9513299c2f1SGregory Neil Shapiro 			else
952c2aa98e2SPeter Wemm 				printf("550 5.1.1 unknown name: %s\r\n", name);
953c2aa98e2SPeter Wemm 		}
9543299c2f1SGregory Neil Shapiro 		else
9553299c2f1SGregory Neil Shapiro 		{
95676b7bf71SPeter Wemm 			char *errcode = NULL;
95776b7bf71SPeter Wemm 
9583299c2f1SGregory Neil Shapiro 			if (ExitVal == EX_TEMPFAIL)
95976b7bf71SPeter Wemm 				errcode = "451 4.3.0";
96076b7bf71SPeter Wemm 			else
96176b7bf71SPeter Wemm 				errcode = "550 5.1.1";
96276b7bf71SPeter Wemm 			mailerr(errcode, "unknown name: %s", name);
963c2aa98e2SPeter Wemm 		}
964c2aa98e2SPeter Wemm 		return;
965c2aa98e2SPeter Wemm 	}
966c2aa98e2SPeter Wemm 	endpwent();
967c2aa98e2SPeter Wemm 
968c2aa98e2SPeter Wemm 	/*
9693299c2f1SGregory Neil Shapiro 	**  Keep name reasonably short to avoid buffer overruns.
9703299c2f1SGregory Neil Shapiro 	**	This isn't necessary on BSD because of the proper
9713299c2f1SGregory Neil Shapiro 	**	definition of snprintf(), but it can cause problems
9723299c2f1SGregory Neil Shapiro 	**	on other systems.
9733299c2f1SGregory Neil Shapiro 	**  Also, clear out any bogus characters.
974c2aa98e2SPeter Wemm 	*/
975c2aa98e2SPeter Wemm 
976c2aa98e2SPeter Wemm 	if (strlen(name) > 40)
977c2aa98e2SPeter Wemm 		name[40] = '\0';
978c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
979c2aa98e2SPeter Wemm 	{
980c2aa98e2SPeter Wemm 		if (!isascii(*p))
981c2aa98e2SPeter Wemm 			*p &= 0x7f;
982c2aa98e2SPeter Wemm 		else if (!isprint(*p))
983c2aa98e2SPeter Wemm 			*p = '.';
984c2aa98e2SPeter Wemm 	}
985c2aa98e2SPeter Wemm 
9863299c2f1SGregory Neil Shapiro 
987c2aa98e2SPeter Wemm 	(void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
988c2aa98e2SPeter Wemm 
9893299c2f1SGregory Neil Shapiro 
990c2aa98e2SPeter Wemm 	/*
9913299c2f1SGregory Neil Shapiro 	**  If the mailbox is linked or a symlink, fail.  There's an obvious
9923299c2f1SGregory Neil Shapiro 	**  race here, that the file was replaced with a symbolic link after
9933299c2f1SGregory Neil Shapiro 	**  the lstat returned, but before the open.  We attempt to detect
9943299c2f1SGregory Neil Shapiro 	**  this by comparing the original stat information and information
9953299c2f1SGregory Neil Shapiro 	**  returned by an fstat of the file descriptor returned by the open.
9963299c2f1SGregory Neil Shapiro 	**
9973299c2f1SGregory Neil Shapiro 	**  NB: this is a symptom of a larger problem, that the mail spooling
9983299c2f1SGregory Neil Shapiro 	**  directory is writeable by the wrong users.  If that directory is
9993299c2f1SGregory Neil Shapiro 	**  writeable, system security is compromised for other reasons, and
10003299c2f1SGregory Neil Shapiro 	**  it cannot be fixed here.
10013299c2f1SGregory Neil Shapiro 	**
10023299c2f1SGregory Neil Shapiro 	**  If we created the mailbox, set the owner/group.  If that fails,
10033299c2f1SGregory Neil Shapiro 	**  just return.  Another process may have already opened it, so we
10043299c2f1SGregory Neil Shapiro 	**  can't unlink it.  Historically, binmail set the owner/group at
10053299c2f1SGregory Neil Shapiro 	**  each mail delivery.  We no longer do this, assuming that if the
10063299c2f1SGregory Neil Shapiro 	**  ownership or permissions were changed there was a reason.
10073299c2f1SGregory Neil Shapiro 	**
10083299c2f1SGregory Neil Shapiro 	**  XXX
10093299c2f1SGregory Neil Shapiro 	**  open(2) should support flock'ing the file.
1010c2aa98e2SPeter Wemm 	*/
10113299c2f1SGregory Neil Shapiro 
1012c2aa98e2SPeter Wemm tryagain:
10133299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
10143299c2f1SGregory Neil Shapiro 	p = name;
10153299c2f1SGregory Neil Shapiro #else /* MAILLOCK */
10163299c2f1SGregory Neil Shapiro 	p = path;
10173299c2f1SGregory Neil Shapiro #endif /* MAILLOCK */
10183299c2f1SGregory Neil Shapiro 	if ((off = lockmbox(p)) != 0)
10193299c2f1SGregory Neil Shapiro 	{
10203299c2f1SGregory Neil Shapiro 		if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
10213299c2f1SGregory Neil Shapiro 		{
10223299c2f1SGregory Neil Shapiro 			ExitVal = EX_TEMPFAIL;
10233299c2f1SGregory Neil Shapiro 			mailerr("451 4.3.0",
10243299c2f1SGregory Neil Shapiro 				"lockmailbox %s failed; error code %d %s",
10253299c2f1SGregory Neil Shapiro 				p, off, errno > 0 ? errstring(errno) : "");
10263299c2f1SGregory Neil Shapiro 		}
10273299c2f1SGregory Neil Shapiro 		else
10283299c2f1SGregory Neil Shapiro 		{
10293299c2f1SGregory Neil Shapiro 			mailerr("551 5.3.0",
10303299c2f1SGregory Neil Shapiro 				"lockmailbox %s failed; error code %d %s",
10313299c2f1SGregory Neil Shapiro 				p, off, errno > 0 ? errstring(errno) : "");
10323299c2f1SGregory Neil Shapiro 		}
10333299c2f1SGregory Neil Shapiro 		return;
10343299c2f1SGregory Neil Shapiro 	}
10353299c2f1SGregory Neil Shapiro 
1036c2aa98e2SPeter Wemm 	if (lstat(path, &sb) < 0)
1037c2aa98e2SPeter Wemm 	{
10383299c2f1SGregory Neil Shapiro 		int save_errno;
10393299c2f1SGregory Neil Shapiro 		int mode = S_IRUSR|S_IWUSR;
1040d995d2baSGregory Neil Shapiro 		gid_t gid = U_GID;
10413299c2f1SGregory Neil Shapiro 
10423299c2f1SGregory Neil Shapiro #ifdef MAILGID
10433299c2f1SGregory Neil Shapiro 		(void) umask(0007);
10443299c2f1SGregory Neil Shapiro 		gid = MAILGID;
10453299c2f1SGregory Neil Shapiro 		mode |= S_IRGRP|S_IWGRP;
10463299c2f1SGregory Neil Shapiro #endif /* MAILGID */
10473299c2f1SGregory Neil Shapiro 
1048d995d2baSGregory Neil Shapiro 		mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE,
1049d995d2baSGregory Neil Shapiro 			    mode);
10503299c2f1SGregory Neil Shapiro 		save_errno = errno;
10513299c2f1SGregory Neil Shapiro 
10523299c2f1SGregory Neil Shapiro 		if (lstat(path, &sb) < 0)
10533299c2f1SGregory Neil Shapiro 		{
10543299c2f1SGregory Neil Shapiro 			ExitVal = EX_CANTCREAT;
105576b7bf71SPeter Wemm 			mailerr("550 5.2.0",
105676b7bf71SPeter Wemm 				"%s: lstat: file changed after open", path);
1057c2aa98e2SPeter Wemm 			goto err1;
1058c2aa98e2SPeter Wemm 		}
10593299c2f1SGregory Neil Shapiro 		if (mbfd == -1)
10603299c2f1SGregory Neil Shapiro 		{
10613299c2f1SGregory Neil Shapiro 			if (save_errno == EEXIST)
1062c2aa98e2SPeter Wemm 				goto tryagain;
1063d995d2baSGregory Neil Shapiro 
1064d995d2baSGregory Neil Shapiro 			/* open failed, don't try again */
1065d995d2baSGregory Neil Shapiro 			mailerr("450 4.2.0", "%s: %s", path,
1066d995d2baSGregory Neil Shapiro 				errstring(save_errno));
1067d995d2baSGregory Neil Shapiro 			goto err0;
10683299c2f1SGregory Neil Shapiro 		}
1069d995d2baSGregory Neil Shapiro 		else if (fchown(mbfd, U_UID, gid) < 0)
10703299c2f1SGregory Neil Shapiro 		{
1071c2aa98e2SPeter Wemm 			mailerr("451 4.3.0", "chown %u.%u: %s",
1072d995d2baSGregory Neil Shapiro 				U_UID, gid, name);
1073c2aa98e2SPeter Wemm 			goto err1;
1074c2aa98e2SPeter Wemm 		}
1075d995d2baSGregory Neil Shapiro 		else
1076d995d2baSGregory Neil Shapiro 		{
1077d995d2baSGregory Neil Shapiro 			/*
1078d995d2baSGregory Neil Shapiro 			**  open() was successful, now close it so can
1079d995d2baSGregory Neil Shapiro 			**  be opened as the right owner again.
1080d995d2baSGregory Neil Shapiro 			**  Paranoia: reset mbdf since the file descriptor
1081d995d2baSGregory Neil Shapiro 			**  is no longer valid; better safe than sorry.
1082d995d2baSGregory Neil Shapiro 			*/
1083d995d2baSGregory Neil Shapiro 
1084d995d2baSGregory Neil Shapiro 			sb.st_uid = U_UID;
1085d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
1086d995d2baSGregory Neil Shapiro 			mbfd = -1;
1087d995d2baSGregory Neil Shapiro 		}
10883299c2f1SGregory Neil Shapiro 	}
10893299c2f1SGregory Neil Shapiro 	else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode))
10903299c2f1SGregory Neil Shapiro 	{
1091c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: irregular file", path);
1092c2aa98e2SPeter Wemm 		goto err0;
10933299c2f1SGregory Neil Shapiro 	}
1094d995d2baSGregory Neil Shapiro 	else if (sb.st_uid != U_UID)
10953299c2f1SGregory Neil Shapiro 	{
10963299c2f1SGregory Neil Shapiro 		ExitVal = EX_CANTCREAT;
1097c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: wrong ownership (%d)",
1098c2aa98e2SPeter Wemm 			path, sb.st_uid);
1099c2aa98e2SPeter Wemm 		goto err0;
1100c2aa98e2SPeter Wemm 	}
1101c2aa98e2SPeter Wemm 
1102d995d2baSGregory Neil Shapiro 	/* change UID for quota checks */
1103d995d2baSGregory Neil Shapiro 	if (setreuid(0, U_UID) < 0)
1104d995d2baSGregory Neil Shapiro 	{
1105d995d2baSGregory Neil Shapiro 		mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
1106d995d2baSGregory Neil Shapiro 			U_UID, errstring(errno), getuid(), geteuid());
1107d995d2baSGregory Neil Shapiro 		goto err1;
1108d995d2baSGregory Neil Shapiro 	}
1109d995d2baSGregory Neil Shapiro #ifdef DEBUG
1110d995d2baSGregory Neil Shapiro 	fprintf(stderr, "new euid = %d\n", geteuid());
1111d995d2baSGregory Neil Shapiro #endif /* DEBUG */
1112d995d2baSGregory Neil Shapiro 	mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0);
1113d995d2baSGregory Neil Shapiro 	if (mbfd < 0)
11143299c2f1SGregory Neil Shapiro 	{
11153299c2f1SGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
1116c2aa98e2SPeter Wemm 		goto err0;
11173299c2f1SGregory Neil Shapiro 	}
11183299c2f1SGregory Neil Shapiro 	else if (fstat(mbfd, &fsb) < 0 ||
1119c2aa98e2SPeter Wemm 		 fsb.st_nlink != 1 ||
1120c2aa98e2SPeter Wemm 		 sb.st_nlink != 1 ||
1121c2aa98e2SPeter Wemm 		 !S_ISREG(fsb.st_mode) ||
1122c2aa98e2SPeter Wemm 		 sb.st_dev != fsb.st_dev ||
1123c2aa98e2SPeter Wemm 		 sb.st_ino != fsb.st_ino ||
1124c2aa98e2SPeter Wemm # if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
1125c2aa98e2SPeter Wemm 		 sb.st_gen != fsb.st_gen ||
11263299c2f1SGregory Neil Shapiro # endif /* HAS_ST_GEN && 0 */
11273299c2f1SGregory Neil Shapiro 		 sb.st_uid != fsb.st_uid)
11283299c2f1SGregory Neil Shapiro 	{
11293299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
113076b7bf71SPeter Wemm 		mailerr("550 5.2.0", "%s: fstat: file changed after open",
113176b7bf71SPeter Wemm 			path);
1132c2aa98e2SPeter Wemm 		goto err1;
1133c2aa98e2SPeter Wemm 	}
1134c2aa98e2SPeter Wemm 
11353299c2f1SGregory Neil Shapiro 
1136c2aa98e2SPeter Wemm 	/* Wait until we can get a lock on the file. */
11373299c2f1SGregory Neil Shapiro 	if (flock(mbfd, LOCK_EX) < 0)
11383299c2f1SGregory Neil Shapiro 	{
11393299c2f1SGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
1140c2aa98e2SPeter Wemm 		goto err1;
1141c2aa98e2SPeter Wemm 	}
1142c2aa98e2SPeter Wemm 
11433299c2f1SGregory Neil Shapiro 	if (!nobiff)
11443299c2f1SGregory Neil Shapiro 	{
1145c2aa98e2SPeter Wemm 		/* Get the starting offset of the new message for biff. */
1146c2aa98e2SPeter Wemm 		curoff = lseek(mbfd, (off_t)0, SEEK_END);
1147c2aa98e2SPeter Wemm 		if (sizeof curoff > sizeof(long))
1148c2aa98e2SPeter Wemm 			(void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
1149c2aa98e2SPeter Wemm 					name, quad_to_string(curoff));
1150c2aa98e2SPeter Wemm 		else
1151c2aa98e2SPeter Wemm 			(void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
1152d995d2baSGregory Neil Shapiro 					name, (long) curoff);
1153d615a192SPeter Wemm 	}
1154c2aa98e2SPeter Wemm 
1155c2aa98e2SPeter Wemm 	/* Copy the message into the file. */
11563299c2f1SGregory Neil Shapiro 	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
11573299c2f1SGregory Neil Shapiro 	{
1158c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "temporary file: %s",
11593299c2f1SGregory Neil Shapiro 			errstring(errno));
1160c2aa98e2SPeter Wemm 		goto err1;
1161c2aa98e2SPeter Wemm 	}
1162c2aa98e2SPeter Wemm #ifdef DEBUG
1163d995d2baSGregory Neil Shapiro 	fprintf(stderr, "before writing: euid = %d\n", geteuid());
11643299c2f1SGregory Neil Shapiro #endif /* DEBUG */
11653299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
11663299c2f1SGregory Neil Shapiro 	headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
11673299c2f1SGregory Neil Shapiro 	for (;;)
11683299c2f1SGregory Neil Shapiro 	{
11693299c2f1SGregory Neil Shapiro 		if (headerbytes == 0)
11703299c2f1SGregory Neil Shapiro 		{
11713299c2f1SGregory Neil Shapiro 			snprintf(buf, sizeof buf, "%s", ContentHdr);
11723299c2f1SGregory Neil Shapiro 			nr = strlen(buf);
11733299c2f1SGregory Neil Shapiro 			headerbytes = -1;
11743299c2f1SGregory Neil Shapiro 			readamount = 0;
11753299c2f1SGregory Neil Shapiro 		}
11763299c2f1SGregory Neil Shapiro 		else if (headerbytes > sizeof(buf) || headerbytes < 0)
11773299c2f1SGregory Neil Shapiro 			readamount = sizeof(buf);
11783299c2f1SGregory Neil Shapiro 		else
11793299c2f1SGregory Neil Shapiro 			readamount = headerbytes;
11803299c2f1SGregory Neil Shapiro 		if (readamount != 0)
11813299c2f1SGregory Neil Shapiro 			nr = read(fd, buf, readamount);
11823299c2f1SGregory Neil Shapiro 		if (nr <= 0)
11833299c2f1SGregory Neil Shapiro 			break;
11843299c2f1SGregory Neil Shapiro 		if (headerbytes > 0)
11853299c2f1SGregory Neil Shapiro 			headerbytes -= nr ;
11863299c2f1SGregory Neil Shapiro 
11873299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
1188c2aa98e2SPeter Wemm 	while ((nr = read(fd, buf, sizeof(buf))) > 0)
11893299c2f1SGregory Neil Shapiro 	{
11903299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
1191c2aa98e2SPeter Wemm 		for (off = 0; off < nr; off += nw)
11923299c2f1SGregory Neil Shapiro 		{
11933299c2f1SGregory Neil Shapiro 			if ((nw = write(mbfd, buf + off, nr - off)) < 0)
11943299c2f1SGregory Neil Shapiro 			{
11953299c2f1SGregory Neil Shapiro #ifdef EDQUOT
11963299c2f1SGregory Neil Shapiro 				if (errno == EDQUOT && bouncequota)
11973299c2f1SGregory Neil Shapiro 					mailerr("552 5.2.2", "%s: %s",
11983299c2f1SGregory Neil Shapiro 						path, errstring(errno));
11993299c2f1SGregory Neil Shapiro 				else
12003299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
1201c2aa98e2SPeter Wemm 				mailerr("450 4.2.0", "%s: %s",
12023299c2f1SGregory Neil Shapiro 					path, errstring(errno));
1203c2aa98e2SPeter Wemm 				goto err3;
1204c2aa98e2SPeter Wemm 			}
12053299c2f1SGregory Neil Shapiro 		}
12063299c2f1SGregory Neil Shapiro 	}
12073299c2f1SGregory Neil Shapiro 	if (nr < 0)
12083299c2f1SGregory Neil Shapiro 	{
1209c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "temporary file: %s",
12103299c2f1SGregory Neil Shapiro 			errstring(errno));
1211c2aa98e2SPeter Wemm 		goto err3;
1212c2aa98e2SPeter Wemm 	}
1213c2aa98e2SPeter Wemm 
1214c2aa98e2SPeter Wemm 	/* Flush to disk, don't wait for update. */
12153299c2f1SGregory Neil Shapiro 	if (!nofsync && fsync(mbfd) < 0)
12163299c2f1SGregory Neil Shapiro 	{
12173299c2f1SGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
1218c2aa98e2SPeter Wemm err3:
12193299c2f1SGregory Neil Shapiro 		if (setreuid(0, 0) < 0)
12203299c2f1SGregory Neil Shapiro 		{
122176b7bf71SPeter Wemm #if 0
122276b7bf71SPeter Wemm 			/* already printed an error above for this recipient */
12233299c2f1SGregory Neil Shapiro 			(void) e_to_sys(errno);
1224c2aa98e2SPeter Wemm 			mailerr("450 4.2.0", "setreuid(0, 0): %s",
12253299c2f1SGregory Neil Shapiro 				errstring(errno));
12263299c2f1SGregory Neil Shapiro #endif /* 0 */
1227c2aa98e2SPeter Wemm 		}
1228c2aa98e2SPeter Wemm #ifdef DEBUG
12293299c2f1SGregory Neil Shapiro 		fprintf(stderr, "reset euid = %d\n", geteuid());
12303299c2f1SGregory Neil Shapiro #endif /* DEBUG */
1231c2aa98e2SPeter Wemm 		(void) ftruncate(mbfd, curoff);
1232d995d2baSGregory Neil Shapiro err1:		if (mbfd >= 0)
1233d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
1234c2aa98e2SPeter Wemm err0:		unlockmbox();
1235c2aa98e2SPeter Wemm 		return;
1236c2aa98e2SPeter Wemm 	}
1237c2aa98e2SPeter Wemm 
1238c2aa98e2SPeter Wemm 	/* Close and check -- NFS doesn't write until the close. */
12393299c2f1SGregory Neil Shapiro 	if (close(mbfd))
12403299c2f1SGregory Neil Shapiro 	{
12413299c2f1SGregory Neil Shapiro #ifdef EDQUOT
12423299c2f1SGregory Neil Shapiro 		if (errno == EDQUOT && bouncequota)
12433299c2f1SGregory Neil Shapiro 			mailerr("552 5.2.2", "%s: %s", path, errstring(errno));
12443299c2f1SGregory Neil Shapiro 		else
12453299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
12463299c2f1SGregory Neil Shapiro 		mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
12473299c2f1SGregory Neil Shapiro 		(void) truncate(path, curoff);
12483299c2f1SGregory Neil Shapiro 	}
12493299c2f1SGregory Neil Shapiro 	else if (!nobiff)
1250c2aa98e2SPeter Wemm 		notifybiff(biffmsg);
1251c2aa98e2SPeter Wemm 
12523299c2f1SGregory Neil Shapiro 	if (setreuid(0, 0) < 0)
12533299c2f1SGregory Neil Shapiro 	{
1254c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "setreuid(0, 0): %s",
12553299c2f1SGregory Neil Shapiro 			errstring(errno));
1256c2aa98e2SPeter Wemm 		goto err0;
1257c2aa98e2SPeter Wemm 	}
1258c2aa98e2SPeter Wemm #ifdef DEBUG
12593299c2f1SGregory Neil Shapiro 	fprintf(stderr, "reset euid = %d\n", geteuid());
12603299c2f1SGregory Neil Shapiro #endif /* DEBUG */
1261c2aa98e2SPeter Wemm 	unlockmbox();
12623299c2f1SGregory Neil Shapiro 	if (LMTPMode)
1263c2aa98e2SPeter Wemm 		printf("250 2.1.5 %s OK\r\n", name);
1264c2aa98e2SPeter Wemm }
1265c2aa98e2SPeter Wemm 
1266c2aa98e2SPeter Wemm /*
12673299c2f1SGregory Neil Shapiro **  user.lock files are necessary for compatibility with other
12683299c2f1SGregory Neil Shapiro **  systems, e.g., when the mail spool file is NFS exported.
12693299c2f1SGregory Neil Shapiro **  Alas, mailbox locking is more than just a local matter.
12703299c2f1SGregory Neil Shapiro **  EPA 11/94.
1271c2aa98e2SPeter Wemm */
1272c2aa98e2SPeter Wemm 
12733299c2f1SGregory Neil Shapiro bool	Locked = FALSE;
12743299c2f1SGregory Neil Shapiro 
12753299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
12763299c2f1SGregory Neil Shapiro int
12773299c2f1SGregory Neil Shapiro lockmbox(name)
12783299c2f1SGregory Neil Shapiro 	char *name;
12793299c2f1SGregory Neil Shapiro {
1280d995d2baSGregory Neil Shapiro 	int r = 0;
12813299c2f1SGregory Neil Shapiro 
12823299c2f1SGregory Neil Shapiro 	if (Locked)
12833299c2f1SGregory Neil Shapiro 		return 0;
12843299c2f1SGregory Neil Shapiro 	if ((r = maillock(name, 15)) == L_SUCCESS)
12853299c2f1SGregory Neil Shapiro 	{
12863299c2f1SGregory Neil Shapiro 		Locked = TRUE;
12873299c2f1SGregory Neil Shapiro 		return 0;
12883299c2f1SGregory Neil Shapiro 	}
12893299c2f1SGregory Neil Shapiro 	switch (r)
12903299c2f1SGregory Neil Shapiro 	{
12913299c2f1SGregory Neil Shapiro 	  case L_TMPLOCK:	/* Can't create tmp file */
12923299c2f1SGregory Neil Shapiro 	  case L_TMPWRITE:	/* Can't write pid into lockfile */
12933299c2f1SGregory Neil Shapiro 	  case L_MAXTRYS:	/* Failed after retrycnt attempts */
12943299c2f1SGregory Neil Shapiro 		errno = 0;
12953299c2f1SGregory Neil Shapiro 		r = EX_TEMPFAIL;
12963299c2f1SGregory Neil Shapiro 		break;
12973299c2f1SGregory Neil Shapiro 	  case L_ERROR:		/* Check errno for reason */
12983299c2f1SGregory Neil Shapiro 		r = errno;
12993299c2f1SGregory Neil Shapiro 		break;
13003299c2f1SGregory Neil Shapiro 	  default:		/* other permanent errors */
13013299c2f1SGregory Neil Shapiro 		errno = 0;
13023299c2f1SGregory Neil Shapiro 		r = EX_UNAVAILABLE;
13033299c2f1SGregory Neil Shapiro 		break;
13043299c2f1SGregory Neil Shapiro 	}
13053299c2f1SGregory Neil Shapiro 	return r;
13063299c2f1SGregory Neil Shapiro }
1307c2aa98e2SPeter Wemm 
1308c2aa98e2SPeter Wemm void
13093299c2f1SGregory Neil Shapiro unlockmbox()
13103299c2f1SGregory Neil Shapiro {
13113299c2f1SGregory Neil Shapiro 	if (Locked)
13123299c2f1SGregory Neil Shapiro 		mailunlock();
13133299c2f1SGregory Neil Shapiro 	Locked = FALSE;
13143299c2f1SGregory Neil Shapiro }
13153299c2f1SGregory Neil Shapiro #else /* MAILLOCK */
13163299c2f1SGregory Neil Shapiro 
13173299c2f1SGregory Neil Shapiro char	LockName[MAXPATHLEN];
13183299c2f1SGregory Neil Shapiro 
13193299c2f1SGregory Neil Shapiro int
1320c2aa98e2SPeter Wemm lockmbox(path)
1321c2aa98e2SPeter Wemm 	char *path;
1322c2aa98e2SPeter Wemm {
1323c2aa98e2SPeter Wemm 	int statfailed = 0;
13243299c2f1SGregory Neil Shapiro 	time_t start;
1325c2aa98e2SPeter Wemm 
13263299c2f1SGregory Neil Shapiro 	if (Locked)
13273299c2f1SGregory Neil Shapiro 		return 0;
13283299c2f1SGregory Neil Shapiro 	if (strlen(path) + 6 > sizeof LockName)
13293299c2f1SGregory Neil Shapiro 		return EX_SOFTWARE;
13303299c2f1SGregory Neil Shapiro 	(void) snprintf(LockName, sizeof LockName, "%s.lock", path);
13313299c2f1SGregory Neil Shapiro 	(void) time(&start);
13323299c2f1SGregory Neil Shapiro 	for (; ; sleep(5))
13333299c2f1SGregory Neil Shapiro 	{
1334c2aa98e2SPeter Wemm 		int fd;
1335c2aa98e2SPeter Wemm 		struct stat st;
1336c2aa98e2SPeter Wemm 		time_t now;
1337c2aa98e2SPeter Wemm 
13383299c2f1SGregory Neil Shapiro 		/* global timeout */
13393299c2f1SGregory Neil Shapiro 		(void) time(&now);
13403299c2f1SGregory Neil Shapiro 		if (now > start + LOCKTO_GLOB)
13413299c2f1SGregory Neil Shapiro 		{
13423299c2f1SGregory Neil Shapiro 			errno = 0;
13433299c2f1SGregory Neil Shapiro 			return EX_TEMPFAIL;
1344c2aa98e2SPeter Wemm 		}
13453299c2f1SGregory Neil Shapiro 		fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, 0);
13463299c2f1SGregory Neil Shapiro 		if (fd >= 0)
13473299c2f1SGregory Neil Shapiro 		{
13483299c2f1SGregory Neil Shapiro 			/* defeat lock checking programs which test pid */
13493299c2f1SGregory Neil Shapiro 			(void) write(fd, "0", 2);
13503299c2f1SGregory Neil Shapiro 			Locked = TRUE;
13513299c2f1SGregory Neil Shapiro 			(void) close(fd);
13523299c2f1SGregory Neil Shapiro 			return 0;
13533299c2f1SGregory Neil Shapiro 		}
13543299c2f1SGregory Neil Shapiro 		if (stat(LockName, &st) < 0)
13553299c2f1SGregory Neil Shapiro 		{
1356c2aa98e2SPeter Wemm 			if (statfailed++ > 5)
13573299c2f1SGregory Neil Shapiro 			{
13583299c2f1SGregory Neil Shapiro 				errno = 0;
13593299c2f1SGregory Neil Shapiro 				return EX_TEMPFAIL;
13603299c2f1SGregory Neil Shapiro 			}
1361c2aa98e2SPeter Wemm 			continue;
1362c2aa98e2SPeter Wemm 		}
1363c2aa98e2SPeter Wemm 		statfailed = 0;
13643299c2f1SGregory Neil Shapiro 		(void) time(&now);
13653299c2f1SGregory Neil Shapiro 		if (now < st.st_ctime + LOCKTO_RM)
1366c2aa98e2SPeter Wemm 			continue;
13673299c2f1SGregory Neil Shapiro 
13683299c2f1SGregory Neil Shapiro 		/* try to remove stale lockfile */
13693299c2f1SGregory Neil Shapiro 		if (unlink(LockName) < 0)
13703299c2f1SGregory Neil Shapiro 			return errno;
1371c2aa98e2SPeter Wemm 	}
1372c2aa98e2SPeter Wemm }
1373c2aa98e2SPeter Wemm 
1374c2aa98e2SPeter Wemm void
1375c2aa98e2SPeter Wemm unlockmbox()
1376c2aa98e2SPeter Wemm {
13773299c2f1SGregory Neil Shapiro 	if (!Locked)
1378c2aa98e2SPeter Wemm 		return;
13793299c2f1SGregory Neil Shapiro 	(void) unlink(LockName);
13803299c2f1SGregory Neil Shapiro 	Locked = FALSE;
1381c2aa98e2SPeter Wemm }
13823299c2f1SGregory Neil Shapiro #endif /* MAILLOCK */
1383c2aa98e2SPeter Wemm 
1384c2aa98e2SPeter Wemm void
1385c2aa98e2SPeter Wemm notifybiff(msg)
1386c2aa98e2SPeter Wemm 	char *msg;
1387c2aa98e2SPeter Wemm {
13883299c2f1SGregory Neil Shapiro 	static bool initialized = FALSE;
1389c2aa98e2SPeter Wemm 	static int f = -1;
1390c2aa98e2SPeter Wemm 	struct hostent *hp;
1391c2aa98e2SPeter Wemm 	struct servent *sp;
1392c2aa98e2SPeter Wemm 	int len;
13933299c2f1SGregory Neil Shapiro 	static struct sockaddr_in addr;
1394c2aa98e2SPeter Wemm 
13953299c2f1SGregory Neil Shapiro 	if (!initialized)
13963299c2f1SGregory Neil Shapiro 	{
13973299c2f1SGregory Neil Shapiro 		initialized = TRUE;
13983299c2f1SGregory Neil Shapiro 
1399c2aa98e2SPeter Wemm 		/* Be silent if biff service not available. */
14003299c2f1SGregory Neil Shapiro 		if ((sp = getservbyname("biff", "udp")) == NULL ||
14013299c2f1SGregory Neil Shapiro 		    (hp = gethostbyname("localhost")) == NULL ||
14023299c2f1SGregory Neil Shapiro 		    hp->h_length != INADDRSZ)
1403c2aa98e2SPeter Wemm 			return;
14043299c2f1SGregory Neil Shapiro 
1405c2aa98e2SPeter Wemm 		addr.sin_family = hp->h_addrtype;
14063299c2f1SGregory Neil Shapiro 		memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ);
1407c2aa98e2SPeter Wemm 		addr.sin_port = sp->s_port;
1408c2aa98e2SPeter Wemm 	}
14093299c2f1SGregory Neil Shapiro 
14103299c2f1SGregory Neil Shapiro 	/* No message, just return */
14113299c2f1SGregory Neil Shapiro 	if (msg == NULL)
1412c2aa98e2SPeter Wemm 		return;
14133299c2f1SGregory Neil Shapiro 
14143299c2f1SGregory Neil Shapiro 	/* Couldn't initialize addr struct */
14153299c2f1SGregory Neil Shapiro 	if (addr.sin_family == AF_UNSPEC)
14163299c2f1SGregory Neil Shapiro 		return;
14173299c2f1SGregory Neil Shapiro 
14183299c2f1SGregory Neil Shapiro 	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
14193299c2f1SGregory Neil Shapiro 		return;
1420c2aa98e2SPeter Wemm 	len = strlen(msg) + 1;
142176b7bf71SPeter Wemm 	(void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr));
1422c2aa98e2SPeter Wemm }
1423c2aa98e2SPeter Wemm 
1424c2aa98e2SPeter Wemm void
1425c2aa98e2SPeter Wemm usage()
1426c2aa98e2SPeter Wemm {
14273299c2f1SGregory Neil Shapiro 	ExitVal = EX_USAGE;
1428d995d2baSGregory Neil Shapiro 	mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-l] [-f from] user ...");
14293299c2f1SGregory Neil Shapiro 	exit(ExitVal);
1430c2aa98e2SPeter Wemm }
1431c2aa98e2SPeter Wemm 
1432c2aa98e2SPeter Wemm void
1433c2aa98e2SPeter Wemm #ifdef __STDC__
1434c2aa98e2SPeter Wemm mailerr(const char *hdr, const char *fmt, ...)
14353299c2f1SGregory Neil Shapiro #else /* __STDC__ */
1436c2aa98e2SPeter Wemm mailerr(hdr, fmt, va_alist)
1437c2aa98e2SPeter Wemm 	const char *hdr;
1438c2aa98e2SPeter Wemm 	const char *fmt;
1439c2aa98e2SPeter Wemm 	va_dcl
14403299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
1441c2aa98e2SPeter Wemm {
1442c2aa98e2SPeter Wemm 	va_list ap;
1443c2aa98e2SPeter Wemm 
1444c2aa98e2SPeter Wemm #ifdef __STDC__
1445c2aa98e2SPeter Wemm 	va_start(ap, fmt);
14463299c2f1SGregory Neil Shapiro #else /* __STDC__ */
1447c2aa98e2SPeter Wemm 	va_start(ap);
14483299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
14493299c2f1SGregory Neil Shapiro 	if (LMTPMode)
1450c2aa98e2SPeter Wemm 	{
145176b7bf71SPeter Wemm 		if (hdr != NULL)
1452c2aa98e2SPeter Wemm 			printf("%s ", hdr);
14533299c2f1SGregory Neil Shapiro 		(void) vprintf(fmt, ap);
14543299c2f1SGregory Neil Shapiro 		(void) printf("\r\n");
1455c2aa98e2SPeter Wemm 	}
1456c2aa98e2SPeter Wemm 	else
1457c2aa98e2SPeter Wemm 	{
14583299c2f1SGregory Neil Shapiro 		(void) e_to_sys(errno);
1459c2aa98e2SPeter Wemm 		vwarn(fmt, ap);
1460c2aa98e2SPeter Wemm 	}
1461c2aa98e2SPeter Wemm }
1462c2aa98e2SPeter Wemm 
1463c2aa98e2SPeter Wemm void
1464c2aa98e2SPeter Wemm vwarn(fmt, ap)
1465c2aa98e2SPeter Wemm 	const char *fmt;
1466c2aa98e2SPeter Wemm 	_BSD_VA_LIST_ ap;
1467c2aa98e2SPeter Wemm {
1468c2aa98e2SPeter Wemm 	/*
14693299c2f1SGregory Neil Shapiro 	**  Log the message to stderr.
14703299c2f1SGregory Neil Shapiro 	**
14713299c2f1SGregory Neil Shapiro 	**  Don't use LOG_PERROR as an openlog() flag to do this,
14723299c2f1SGregory Neil Shapiro 	**  it's not portable enough.
1473c2aa98e2SPeter Wemm 	*/
14743299c2f1SGregory Neil Shapiro 
14753299c2f1SGregory Neil Shapiro 	if (ExitVal != EX_USAGE)
1476c2aa98e2SPeter Wemm 		(void) fprintf(stderr, "mail.local: ");
1477c2aa98e2SPeter Wemm 	(void) vfprintf(stderr, fmt, ap);
1478c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "\n");
1479c2aa98e2SPeter Wemm 
1480c2aa98e2SPeter Wemm #if USE_VSYSLOG
1481c2aa98e2SPeter Wemm 	/* Log the message to syslog. */
1482c2aa98e2SPeter Wemm 	vsyslog(LOG_ERR, fmt, ap);
14833299c2f1SGregory Neil Shapiro #else /* USE_VSYSLOG */
1484c2aa98e2SPeter Wemm 	{
1485c2aa98e2SPeter Wemm 		char fmtbuf[10240];
1486c2aa98e2SPeter Wemm 
1487c2aa98e2SPeter Wemm 		(void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap);
1488c2aa98e2SPeter Wemm 		syslog(LOG_ERR, "%s", fmtbuf);
1489c2aa98e2SPeter Wemm 	}
14903299c2f1SGregory Neil Shapiro #endif /* USE_VSYSLOG */
1491c2aa98e2SPeter Wemm }
1492c2aa98e2SPeter Wemm 
1493c2aa98e2SPeter Wemm /*
1494c2aa98e2SPeter Wemm  * e_to_sys --
1495c2aa98e2SPeter Wemm  *	Guess which errno's are temporary.  Gag me.
1496c2aa98e2SPeter Wemm  */
14973299c2f1SGregory Neil Shapiro int
1498c2aa98e2SPeter Wemm e_to_sys(num)
1499c2aa98e2SPeter Wemm 	int num;
1500c2aa98e2SPeter Wemm {
1501c2aa98e2SPeter Wemm 	/* Temporary failures override hard errors. */
15023299c2f1SGregory Neil Shapiro 	if (ExitVal == EX_TEMPFAIL)
15033299c2f1SGregory Neil Shapiro 		return ExitVal;
1504c2aa98e2SPeter Wemm 
15053299c2f1SGregory Neil Shapiro 	switch (num)		/* Hopefully temporary errors. */
15063299c2f1SGregory Neil Shapiro 	{
1507c2aa98e2SPeter Wemm #ifdef EDQUOT
1508c2aa98e2SPeter Wemm 	  case EDQUOT:		/* Disc quota exceeded */
15093299c2f1SGregory Neil Shapiro 		if (bouncequota)
15103299c2f1SGregory Neil Shapiro 		{
15113299c2f1SGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
15123299c2f1SGregory Neil Shapiro 			break;
15133299c2f1SGregory Neil Shapiro 		}
15143299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
15153299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
15163299c2f1SGregory Neil Shapiro #ifdef EAGAIN
15173299c2f1SGregory Neil Shapiro 	  case EAGAIN:		/* Resource temporarily unavailable */
15183299c2f1SGregory Neil Shapiro #endif /* EAGAIN */
1519c2aa98e2SPeter Wemm #ifdef EBUSY
1520c2aa98e2SPeter Wemm 	  case EBUSY:		/* Device busy */
15213299c2f1SGregory Neil Shapiro #endif /* EBUSY */
1522c2aa98e2SPeter Wemm #ifdef EPROCLIM
1523c2aa98e2SPeter Wemm 	  case EPROCLIM:	/* Too many processes */
15243299c2f1SGregory Neil Shapiro #endif /* EPROCLIM */
1525c2aa98e2SPeter Wemm #ifdef EUSERS
1526c2aa98e2SPeter Wemm 	  case EUSERS:		/* Too many users */
15273299c2f1SGregory Neil Shapiro #endif /* EUSERS */
1528c2aa98e2SPeter Wemm #ifdef ECONNABORTED
1529c2aa98e2SPeter Wemm 	  case ECONNABORTED:	/* Software caused connection abort */
15303299c2f1SGregory Neil Shapiro #endif /* ECONNABORTED */
1531c2aa98e2SPeter Wemm #ifdef ECONNREFUSED
1532c2aa98e2SPeter Wemm 	  case ECONNREFUSED:	/* Connection refused */
15333299c2f1SGregory Neil Shapiro #endif /* ECONNREFUSED */
1534c2aa98e2SPeter Wemm #ifdef ECONNRESET
1535c2aa98e2SPeter Wemm 	  case ECONNRESET:	/* Connection reset by peer */
15363299c2f1SGregory Neil Shapiro #endif /* ECONNRESET */
1537c2aa98e2SPeter Wemm #ifdef EDEADLK
1538c2aa98e2SPeter Wemm 	  case EDEADLK:		/* Resource deadlock avoided */
15393299c2f1SGregory Neil Shapiro #endif /* EDEADLK */
1540c2aa98e2SPeter Wemm #ifdef EFBIG
1541c2aa98e2SPeter Wemm 	  case EFBIG:		/* File too large */
15423299c2f1SGregory Neil Shapiro #endif /* EFBIG */
1543c2aa98e2SPeter Wemm #ifdef EHOSTDOWN
1544c2aa98e2SPeter Wemm 	  case EHOSTDOWN:	/* Host is down */
15453299c2f1SGregory Neil Shapiro #endif /* EHOSTDOWN */
1546c2aa98e2SPeter Wemm #ifdef EHOSTUNREACH
1547c2aa98e2SPeter Wemm 	  case EHOSTUNREACH:	/* No route to host */
15483299c2f1SGregory Neil Shapiro #endif /* EHOSTUNREACH */
1549c2aa98e2SPeter Wemm #ifdef EMFILE
1550c2aa98e2SPeter Wemm 	  case EMFILE:		/* Too many open files */
15513299c2f1SGregory Neil Shapiro #endif /* EMFILE */
1552c2aa98e2SPeter Wemm #ifdef ENETDOWN
1553c2aa98e2SPeter Wemm 	  case ENETDOWN:	/* Network is down */
15543299c2f1SGregory Neil Shapiro #endif /* ENETDOWN */
1555c2aa98e2SPeter Wemm #ifdef ENETRESET
1556c2aa98e2SPeter Wemm 	  case ENETRESET:	/* Network dropped connection on reset */
15573299c2f1SGregory Neil Shapiro #endif /* ENETRESET */
1558c2aa98e2SPeter Wemm #ifdef ENETUNREACH
1559c2aa98e2SPeter Wemm 	  case ENETUNREACH:	/* Network is unreachable */
15603299c2f1SGregory Neil Shapiro #endif /* ENETUNREACH */
1561c2aa98e2SPeter Wemm #ifdef ENFILE
1562c2aa98e2SPeter Wemm 	  case ENFILE:		/* Too many open files in system */
15633299c2f1SGregory Neil Shapiro #endif /* ENFILE */
1564c2aa98e2SPeter Wemm #ifdef ENOBUFS
1565c2aa98e2SPeter Wemm 	  case ENOBUFS:		/* No buffer space available */
15663299c2f1SGregory Neil Shapiro #endif /* ENOBUFS */
1567c2aa98e2SPeter Wemm #ifdef ENOMEM
1568c2aa98e2SPeter Wemm 	  case ENOMEM:		/* Cannot allocate memory */
15693299c2f1SGregory Neil Shapiro #endif /* ENOMEM */
1570c2aa98e2SPeter Wemm #ifdef ENOSPC
1571c2aa98e2SPeter Wemm 	  case ENOSPC:		/* No space left on device */
15723299c2f1SGregory Neil Shapiro #endif /* ENOSPC */
1573c2aa98e2SPeter Wemm #ifdef EROFS
1574c2aa98e2SPeter Wemm 	  case EROFS:		/* Read-only file system */
15753299c2f1SGregory Neil Shapiro #endif /* EROFS */
1576c2aa98e2SPeter Wemm #ifdef ESTALE
1577c2aa98e2SPeter Wemm 	  case ESTALE:		/* Stale NFS file handle */
15783299c2f1SGregory Neil Shapiro #endif /* ESTALE */
1579c2aa98e2SPeter Wemm #ifdef ETIMEDOUT
1580c2aa98e2SPeter Wemm 	  case ETIMEDOUT:	/* Connection timed out */
15813299c2f1SGregory Neil Shapiro #endif /* ETIMEDOUT */
1582c2aa98e2SPeter Wemm #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
1583c2aa98e2SPeter Wemm 	  case EWOULDBLOCK:	/* Operation would block. */
15843299c2f1SGregory Neil Shapiro #endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */
15853299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
1586c2aa98e2SPeter Wemm 		break;
15873299c2f1SGregory Neil Shapiro 
1588c2aa98e2SPeter Wemm 	  default:
15893299c2f1SGregory Neil Shapiro 		ExitVal = EX_UNAVAILABLE;
1590c2aa98e2SPeter Wemm 		break;
1591c2aa98e2SPeter Wemm 	}
15923299c2f1SGregory Neil Shapiro 	return ExitVal;
1593c2aa98e2SPeter Wemm }
1594c2aa98e2SPeter Wemm 
1595c2aa98e2SPeter Wemm #if defined(ultrix) || defined(_CRAY)
1596c2aa98e2SPeter Wemm /*
1597c2aa98e2SPeter Wemm  * Copyright (c) 1987, 1993
1598c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
1599c2aa98e2SPeter Wemm  *
1600c2aa98e2SPeter Wemm  * Redistribution and use in source and binary forms, with or without
1601c2aa98e2SPeter Wemm  * modification, are permitted provided that the following conditions
1602c2aa98e2SPeter Wemm  * are met:
1603c2aa98e2SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1604c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1605c2aa98e2SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1606c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1607c2aa98e2SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1608c2aa98e2SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
1609c2aa98e2SPeter Wemm  *    must display the following acknowledgement:
1610c2aa98e2SPeter Wemm  *	This product includes software developed by the University of
1611c2aa98e2SPeter Wemm  *	California, Berkeley and its contributors.
1612c2aa98e2SPeter Wemm  * 4. Neither the name of the University nor the names of its contributors
1613c2aa98e2SPeter Wemm  *    may be used to endorse or promote products derived from this software
1614c2aa98e2SPeter Wemm  *    without specific prior written permission.
1615c2aa98e2SPeter Wemm  *
1616c2aa98e2SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1617c2aa98e2SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1618c2aa98e2SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1619c2aa98e2SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1620c2aa98e2SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1621c2aa98e2SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1622c2aa98e2SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1623c2aa98e2SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1624c2aa98e2SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1625c2aa98e2SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1626c2aa98e2SPeter Wemm  * SUCH DAMAGE.
1627c2aa98e2SPeter Wemm  */
1628c2aa98e2SPeter Wemm 
1629c2aa98e2SPeter Wemm # if defined(LIBC_SCCS) && !defined(lint)
1630c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
16313299c2f1SGregory Neil Shapiro # endif /* defined(LIBC_SCCS) && !defined(lint) */
1632c2aa98e2SPeter Wemm 
1633c2aa98e2SPeter Wemm # include <sys/types.h>
1634c2aa98e2SPeter Wemm # include <sys/stat.h>
1635c2aa98e2SPeter Wemm # include <fcntl.h>
1636c2aa98e2SPeter Wemm # include <errno.h>
1637c2aa98e2SPeter Wemm # include <stdio.h>
1638c2aa98e2SPeter Wemm # include <ctype.h>
1639c2aa98e2SPeter Wemm 
1640c2aa98e2SPeter Wemm static int _gettemp();
1641c2aa98e2SPeter Wemm 
1642c2aa98e2SPeter Wemm mkstemp(path)
1643c2aa98e2SPeter Wemm 	char *path;
1644c2aa98e2SPeter Wemm {
1645c2aa98e2SPeter Wemm 	int fd;
1646c2aa98e2SPeter Wemm 
1647c2aa98e2SPeter Wemm 	return (_gettemp(path, &fd) ? fd : -1);
1648c2aa98e2SPeter Wemm }
1649c2aa98e2SPeter Wemm 
16503299c2f1SGregory Neil Shapiro # if 0
1651c2aa98e2SPeter Wemm char *
1652c2aa98e2SPeter Wemm mktemp(path)
1653c2aa98e2SPeter Wemm 	char *path;
1654c2aa98e2SPeter Wemm {
1655c2aa98e2SPeter Wemm 	return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
1656c2aa98e2SPeter Wemm }
16573299c2f1SGregory Neil Shapiro # endif /* 0 */
1658c2aa98e2SPeter Wemm 
1659c2aa98e2SPeter Wemm static
1660c2aa98e2SPeter Wemm _gettemp(path, doopen)
1661c2aa98e2SPeter Wemm 	char *path;
1662c2aa98e2SPeter Wemm 	register int *doopen;
1663c2aa98e2SPeter Wemm {
1664c2aa98e2SPeter Wemm 	extern int errno;
1665c2aa98e2SPeter Wemm 	register char *start, *trv;
1666c2aa98e2SPeter Wemm 	struct stat sbuf;
1667c2aa98e2SPeter Wemm 	u_int pid;
1668c2aa98e2SPeter Wemm 
1669c2aa98e2SPeter Wemm 	pid = getpid();
1670c2aa98e2SPeter Wemm 	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
16713299c2f1SGregory Neil Shapiro 	while (*--trv == 'X')
16723299c2f1SGregory Neil Shapiro 	{
1673c2aa98e2SPeter Wemm 		*trv = (pid % 10) + '0';
1674c2aa98e2SPeter Wemm 		pid /= 10;
1675c2aa98e2SPeter Wemm 	}
1676c2aa98e2SPeter Wemm 
1677c2aa98e2SPeter Wemm 	/*
1678c2aa98e2SPeter Wemm 	 * check the target directory; if you have six X's and it
1679c2aa98e2SPeter Wemm 	 * doesn't exist this runs for a *very* long time.
1680c2aa98e2SPeter Wemm 	 */
16813299c2f1SGregory Neil Shapiro 	for (start = trv + 1;; --trv)
16823299c2f1SGregory Neil Shapiro 	{
1683c2aa98e2SPeter Wemm 		if (trv <= path)
1684c2aa98e2SPeter Wemm 			break;
16853299c2f1SGregory Neil Shapiro 		if (*trv == '/')
16863299c2f1SGregory Neil Shapiro 		{
1687c2aa98e2SPeter Wemm 			*trv = '\0';
1688c2aa98e2SPeter Wemm 			if (stat(path, &sbuf) < 0)
1689c2aa98e2SPeter Wemm 				return(0);
16903299c2f1SGregory Neil Shapiro 			if (!S_ISDIR(sbuf.st_mode))
16913299c2f1SGregory Neil Shapiro 			{
1692c2aa98e2SPeter Wemm 				errno = ENOTDIR;
1693c2aa98e2SPeter Wemm 				return(0);
1694c2aa98e2SPeter Wemm 			}
1695c2aa98e2SPeter Wemm 			*trv = '/';
1696c2aa98e2SPeter Wemm 			break;
1697c2aa98e2SPeter Wemm 		}
1698c2aa98e2SPeter Wemm 	}
1699c2aa98e2SPeter Wemm 
17003299c2f1SGregory Neil Shapiro 	for (;;)
17013299c2f1SGregory Neil Shapiro 	{
17023299c2f1SGregory Neil Shapiro 		if (doopen)
17033299c2f1SGregory Neil Shapiro 		{
1704d995d2baSGregory Neil Shapiro 			if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR,
1705d995d2baSGregory Neil Shapiro 					    0600)) >= 0)
1706c2aa98e2SPeter Wemm 				return(1);
1707c2aa98e2SPeter Wemm 			if (errno != EEXIST)
1708c2aa98e2SPeter Wemm 				return(0);
1709c2aa98e2SPeter Wemm 		}
1710c2aa98e2SPeter Wemm 		else if (stat(path, &sbuf) < 0)
1711c2aa98e2SPeter Wemm 			return(errno == ENOENT ? 1 : 0);
1712c2aa98e2SPeter Wemm 
1713c2aa98e2SPeter Wemm 		/* tricky little algorithm for backward compatibility */
17143299c2f1SGregory Neil Shapiro 		for (trv = start;;)
17153299c2f1SGregory Neil Shapiro 		{
1716c2aa98e2SPeter Wemm 			if (!*trv)
1717c2aa98e2SPeter Wemm 				return(0);
1718c2aa98e2SPeter Wemm 			if (*trv == 'z')
1719c2aa98e2SPeter Wemm 				*trv++ = 'a';
17203299c2f1SGregory Neil Shapiro 			else
17213299c2f1SGregory Neil Shapiro 			{
1722c2aa98e2SPeter Wemm 				if (isascii(*trv) && isdigit(*trv))
1723c2aa98e2SPeter Wemm 					*trv = 'a';
1724c2aa98e2SPeter Wemm 				else
1725c2aa98e2SPeter Wemm 					++*trv;
1726c2aa98e2SPeter Wemm 				break;
1727c2aa98e2SPeter Wemm 			}
1728c2aa98e2SPeter Wemm 		}
1729c2aa98e2SPeter Wemm 	}
1730c2aa98e2SPeter Wemm 	/* NOTREACHED */
1731c2aa98e2SPeter Wemm }
17323299c2f1SGregory Neil Shapiro #endif /* defined(ultrix) || defined(_CRAY) */
1733