xref: /freebsd/contrib/sendmail/mail.local/mail.local.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
176b7bf71SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004 Proofpoint, 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,
185dd76dd0SGregory Neil Shapiro "@(#) Copyright (c) 1998-2004 Proofpoint, 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 
234313cc83SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: mail.local.c,v 8.257 2013-11-22 20:51:51 ca Exp $")
2412ed1c7cSGregory Neil Shapiro 
2512ed1c7cSGregory Neil Shapiro #include <stdlib.h>
262fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
2712ed1c7cSGregory Neil Shapiro #include <sm/errstring.h>
2812ed1c7cSGregory Neil Shapiro #include <sm/io.h>
2912ed1c7cSGregory Neil Shapiro #include <sm/limits.h>
3012ed1c7cSGregory Neil Shapiro #include <unistd.h>
317660b554SGregory Neil Shapiro #define LOCKFILE_PMODE 0
3212ed1c7cSGregory Neil Shapiro #include <sm/mbdb.h>
3312ed1c7cSGregory Neil Shapiro #include <sm/sysexits.h>
343299c2f1SGregory Neil Shapiro 
35bfb62e91SGregory Neil Shapiro #ifndef HASHSPOOL
36bfb62e91SGregory Neil Shapiro # define HASHSPOOL	0
375b0945b5SGregory Neil Shapiro #endif
38bfb62e91SGregory Neil Shapiro #ifndef HASHSPOOLMD5
39bfb62e91SGregory Neil Shapiro # define HASHSPOOLMD5	0
405b0945b5SGregory Neil Shapiro #endif
41bfb62e91SGregory Neil Shapiro 
42c2aa98e2SPeter Wemm /*
433299c2f1SGregory Neil Shapiro **  This is not intended to work on System V derived systems
443299c2f1SGregory Neil Shapiro **  such as Solaris or HP-UX, since they use a totally different
4512ed1c7cSGregory Neil Shapiro **  approach to mailboxes (essentially, they have a set-group-ID program
4612ed1c7cSGregory Neil Shapiro **  rather than set-user-ID, and they rely on the ability to "give away"
473299c2f1SGregory Neil Shapiro **  files to do their work).  IT IS NOT A BUG that this doesn't
483299c2f1SGregory Neil Shapiro **  work on such architectures.
49c2aa98e2SPeter Wemm */
50c2aa98e2SPeter Wemm 
513299c2f1SGregory Neil Shapiro 
5212ed1c7cSGregory Neil Shapiro #include <stdio.h>
5312ed1c7cSGregory Neil Shapiro #include <errno.h>
5412ed1c7cSGregory Neil Shapiro #include <fcntl.h>
5512ed1c7cSGregory Neil Shapiro #include <sys/types.h>
5612ed1c7cSGregory Neil Shapiro #include <sys/stat.h>
5712ed1c7cSGregory Neil Shapiro #include <time.h>
5812ed1c7cSGregory Neil Shapiro #include <stdlib.h>
5912ed1c7cSGregory Neil Shapiro # include <sys/socket.h>
6012ed1c7cSGregory Neil Shapiro # include <sys/file.h>
6112ed1c7cSGregory Neil Shapiro # include <netinet/in.h>
6212ed1c7cSGregory Neil Shapiro # include <arpa/nameser.h>
6312ed1c7cSGregory Neil Shapiro # include <netdb.h>
6412ed1c7cSGregory Neil Shapiro # include <pwd.h>
6512ed1c7cSGregory Neil Shapiro 
6612ed1c7cSGregory Neil Shapiro #include <sm/string.h>
6712ed1c7cSGregory Neil Shapiro #include <syslog.h>
6812ed1c7cSGregory Neil Shapiro #include <ctype.h>
6912ed1c7cSGregory Neil Shapiro 
7012ed1c7cSGregory Neil Shapiro #include <sm/conf.h>
7112ed1c7cSGregory Neil Shapiro #include <sendmail/pathnames.h>
7212ed1c7cSGregory Neil Shapiro 
73bfb62e91SGregory Neil Shapiro #if HASHSPOOL
74bfb62e91SGregory Neil Shapiro # define HASH_NONE	0
75bfb62e91SGregory Neil Shapiro # define HASH_USER	1
76bfb62e91SGregory Neil Shapiro # if HASHSPOOLMD5
77bfb62e91SGregory Neil Shapiro #  define HASH_MD5	2
78bfb62e91SGregory Neil Shapiro #  include <openssl/md5.h>
795b0945b5SGregory Neil Shapiro # endif
80bfb62e91SGregory Neil Shapiro #endif /* HASHSPOOL */
81bfb62e91SGregory Neil Shapiro 
82e3793f76SGregory Neil Shapiro #if _FFR_SPOOL_PATH
83e3793f76SGregory Neil Shapiro 	/*
84e3793f76SGregory Neil Shapiro 	**  Override path to mail store at run time (using -p).
85e3793f76SGregory Neil Shapiro 	**  From: Eugene Grosbein of Svyaz Service JSC
86e3793f76SGregory Neil Shapiro 	**  See: http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/114195
87e3793f76SGregory Neil Shapiro 	**  NOTE: Update man page before adding this to a release.
88e3793f76SGregory Neil Shapiro 	*/
89e3793f76SGregory Neil Shapiro #endif /* _FFR_SPOOL_PATH */
90e3793f76SGregory Neil Shapiro 
9112ed1c7cSGregory Neil Shapiro 
923299c2f1SGregory Neil Shapiro #ifndef LOCKTO_RM
933299c2f1SGregory Neil Shapiro # define LOCKTO_RM	300	/* timeout for stale lockfile removal */
945b0945b5SGregory Neil Shapiro #endif
953299c2f1SGregory Neil Shapiro #ifndef LOCKTO_GLOB
963299c2f1SGregory Neil Shapiro # define LOCKTO_GLOB	400	/* global timeout for lockfile creation */
975b0945b5SGregory Neil Shapiro #endif
983299c2f1SGregory Neil Shapiro 
993299c2f1SGregory Neil Shapiro /* define a realloc() which works for NULL pointers */
1003299c2f1SGregory Neil Shapiro #define REALLOC(ptr, size)	(((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm /*
10312ed1c7cSGregory Neil Shapiro **  If you don't have flock, you could try using lockf instead.
104c2aa98e2SPeter Wemm */
105c2aa98e2SPeter Wemm 
10612ed1c7cSGregory Neil Shapiro #ifdef LDA_USE_LOCKF
107c2aa98e2SPeter Wemm # define flock(a, b)	lockf(a, b, 0)
1083299c2f1SGregory Neil Shapiro # ifdef LOCK_EX
1093299c2f1SGregory Neil Shapiro #  undef LOCK_EX
1105b0945b5SGregory Neil Shapiro # endif
111c2aa98e2SPeter Wemm # define LOCK_EX	F_LOCK
11212ed1c7cSGregory Neil Shapiro #endif /* LDA_USE_LOCKF */
113c2aa98e2SPeter Wemm 
114c2aa98e2SPeter Wemm #ifndef LOCK_EX
115c2aa98e2SPeter Wemm # include <sys/file.h>
1165b0945b5SGregory Neil Shapiro #endif
117c2aa98e2SPeter Wemm 
118c2aa98e2SPeter Wemm /*
1193299c2f1SGregory Neil Shapiro **  If you don't have setreuid, and you have saved uids, and you have
1203299c2f1SGregory Neil Shapiro **  a seteuid() call that doesn't try to emulate using setuid(), then
12112ed1c7cSGregory Neil Shapiro **  you can try defining LDA_USE_SETEUID.
122c2aa98e2SPeter Wemm */
123b4662009SGregory Neil Shapiro 
12412ed1c7cSGregory Neil Shapiro #ifdef LDA_USE_SETEUID
125c2aa98e2SPeter Wemm # define setreuid(r, e)		seteuid(e)
1265b0945b5SGregory Neil Shapiro #endif
127c2aa98e2SPeter Wemm 
12812ed1c7cSGregory Neil Shapiro #ifdef LDA_CONTENTLENGTH
12912ed1c7cSGregory Neil Shapiro # define CONTENTLENGTH	1
1305b0945b5SGregory Neil Shapiro #endif
131d995d2baSGregory Neil Shapiro 
1323299c2f1SGregory Neil Shapiro #ifndef INADDRSZ
1333299c2f1SGregory Neil Shapiro # define INADDRSZ	4		/* size of an IPv4 address in bytes */
1345b0945b5SGregory Neil Shapiro #endif
135c2aa98e2SPeter Wemm 
13612ed1c7cSGregory Neil Shapiro #ifdef MAILLOCK
13712ed1c7cSGregory Neil Shapiro # include <maillock.h>
1385b0945b5SGregory Neil Shapiro #endif
13912ed1c7cSGregory Neil Shapiro 
14076b7bf71SPeter Wemm #ifndef MAILER_DAEMON
14176b7bf71SPeter Wemm # define MAILER_DAEMON	"MAILER-DAEMON"
1425b0945b5SGregory Neil Shapiro #endif
14376b7bf71SPeter Wemm 
1443299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
1453299c2f1SGregory Neil Shapiro char	ContentHdr[40] = "Content-Length: ";
1463299c2f1SGregory Neil Shapiro off_t	HeaderLength;
1473299c2f1SGregory Neil Shapiro off_t	BodyLength;
1485b0945b5SGregory Neil Shapiro #endif
149c2aa98e2SPeter Wemm 
15012ed1c7cSGregory Neil Shapiro bool	EightBitMime = true;		/* advertise 8BITMIME in LMTP */
1512fb4f839SGregory Neil Shapiro #if USE_EAI
1522fb4f839SGregory Neil Shapiro bool	EAI = true;			/* advertise SMTPUTF8 in LMTP */
1532fb4f839SGregory Neil Shapiro #endif
154b4662009SGregory Neil Shapiro char	ErrBuf[10240];			/* error buffer */
1553299c2f1SGregory Neil Shapiro int	ExitVal = EX_OK;		/* sysexits.h error value. */
15612ed1c7cSGregory Neil Shapiro bool	nobiff = false;
15712ed1c7cSGregory Neil Shapiro bool	nofsync = false;
15812ed1c7cSGregory Neil Shapiro bool	HoldErrs = false;		/* Hold errors in ErrBuf */
15912ed1c7cSGregory Neil Shapiro bool	LMTPMode = false;
16012ed1c7cSGregory Neil Shapiro bool	BounceQuota = false;		/* permanent error when over quota */
161684b2a5fSGregory Neil Shapiro bool	CloseMBDB = false;
16212ed1c7cSGregory Neil Shapiro char	*HomeMailFile = NULL;		/* store mail in homedir */
1633299c2f1SGregory Neil Shapiro 
164bfb62e91SGregory Neil Shapiro #if HASHSPOOL
165bfb62e91SGregory Neil Shapiro int	HashType = HASH_NONE;
166bfb62e91SGregory Neil Shapiro int	HashDepth = 0;
167bfb62e91SGregory Neil Shapiro bool	StripRcptDomain = true;
1685b0945b5SGregory Neil Shapiro #else
169bfb62e91SGregory Neil Shapiro # define StripRcptDomain true
1705b0945b5SGregory Neil Shapiro #endif
171bfb62e91SGregory Neil Shapiro char	SpoolPath[MAXPATHLEN];
172bfb62e91SGregory Neil Shapiro 
173684b2a5fSGregory Neil Shapiro char	*parseaddr __P((char *, bool));
174684b2a5fSGregory Neil Shapiro char	*process_recipient __P((char *));
175684b2a5fSGregory Neil Shapiro void	dolmtp __P((void));
176b4662009SGregory Neil Shapiro void	deliver __P((int, char *));
1773299c2f1SGregory Neil Shapiro int	e_to_sys __P((int));
178c2aa98e2SPeter Wemm void	notifybiff __P((char *));
17912ed1c7cSGregory Neil Shapiro int	store __P((char *, bool *));
180c2aa98e2SPeter Wemm void	usage __P((void));
1813299c2f1SGregory Neil Shapiro int	lockmbox __P((char *));
182c2aa98e2SPeter Wemm void	unlockmbox __P((void));
183c2aa98e2SPeter Wemm void	mailerr __P((const char *, const char *, ...));
184b4662009SGregory Neil Shapiro void	flush_error __P((void));
185bfb62e91SGregory Neil Shapiro #if HASHSPOOL
186bfb62e91SGregory Neil Shapiro const char	*hashname __P((char *));
1875b0945b5SGregory Neil Shapiro #endif
1883299c2f1SGregory Neil Shapiro 
189c2aa98e2SPeter Wemm 
190951742c4SGregory Neil Shapiro static void sm_exit __P((int));
191951742c4SGregory Neil Shapiro 
192684b2a5fSGregory Neil Shapiro static void
sm_exit(status)193684b2a5fSGregory Neil Shapiro sm_exit(status)
194684b2a5fSGregory Neil Shapiro 	int status;
195684b2a5fSGregory Neil Shapiro {
196684b2a5fSGregory Neil Shapiro 	if (CloseMBDB)
197684b2a5fSGregory Neil Shapiro 	{
198684b2a5fSGregory Neil Shapiro 		sm_mbdb_terminate();
199684b2a5fSGregory Neil Shapiro 		CloseMBDB = false;	/* not really necessary, but ... */
200684b2a5fSGregory Neil Shapiro 	}
201684b2a5fSGregory Neil Shapiro 	exit(status);
202684b2a5fSGregory Neil Shapiro }
203684b2a5fSGregory Neil Shapiro 
204c2aa98e2SPeter Wemm int
main(argc,argv)205c2aa98e2SPeter Wemm main(argc, argv)
206c2aa98e2SPeter Wemm 	int argc;
207c2aa98e2SPeter Wemm 	char *argv[];
208c2aa98e2SPeter Wemm {
209c2aa98e2SPeter Wemm 	struct passwd *pw;
2103299c2f1SGregory Neil Shapiro 	int ch, fd;
211c2aa98e2SPeter Wemm 	uid_t uid;
212c2aa98e2SPeter Wemm 	char *from;
21312ed1c7cSGregory Neil Shapiro 	char *mbdbname = "pw";
21412ed1c7cSGregory Neil Shapiro 	int err;
215c2aa98e2SPeter Wemm 	extern char *optarg;
216c2aa98e2SPeter Wemm 	extern int optind;
2173299c2f1SGregory Neil Shapiro 
218c2aa98e2SPeter Wemm 
219c2aa98e2SPeter Wemm 	/* make sure we have some open file descriptors */
220c2aa98e2SPeter Wemm 	for (fd = 10; fd < 30; fd++)
221c2aa98e2SPeter Wemm 		(void) close(fd);
222c2aa98e2SPeter Wemm 
223c2aa98e2SPeter Wemm 	/* use a reasonable umask */
224c2aa98e2SPeter Wemm 	(void) umask(0077);
225c2aa98e2SPeter Wemm 
226c2aa98e2SPeter Wemm #ifdef LOG_MAIL
227c2aa98e2SPeter Wemm 	openlog("mail.local", 0, LOG_MAIL);
2285b0945b5SGregory Neil Shapiro #else
229c2aa98e2SPeter Wemm 	openlog("mail.local", 0);
2305b0945b5SGregory Neil Shapiro #endif
231c2aa98e2SPeter Wemm 
232c2aa98e2SPeter Wemm 	from = NULL;
233684b2a5fSGregory Neil Shapiro 
234684b2a5fSGregory Neil Shapiro 	/* XXX can this be converted to a compile time check? */
235bfb62e91SGregory Neil Shapiro 	if (sm_strlcpy(SpoolPath, _PATH_MAILDIR, sizeof(SpoolPath)) >=
236bfb62e91SGregory Neil Shapiro 	    sizeof(SpoolPath))
237bfb62e91SGregory Neil Shapiro 	{
238bfb62e91SGregory Neil Shapiro 		mailerr("421", "Configuration error: _PATH_MAILDIR too large");
239684b2a5fSGregory Neil Shapiro 		sm_exit(EX_CONFIG);
240bfb62e91SGregory Neil Shapiro 	}
2412fb4f839SGregory Neil Shapiro 
2422fb4f839SGregory Neil Shapiro 	/* HACK: add U to all options - this should be only for USE_EAI */
243bfb62e91SGregory Neil Shapiro #if HASHSPOOL
2442fb4f839SGregory Neil Shapiro 	while ((ch = getopt(argc, argv, "7BbdD:f:h:r:lH:p:nsUV")) != -1)
245bfb62e91SGregory Neil Shapiro #else /* HASHSPOOL */
246e3793f76SGregory Neil Shapiro # if _FFR_SPOOL_PATH
2472fb4f839SGregory Neil Shapiro 	while ((ch = getopt(argc, argv, "7BbdD:f:h:r:lp:sUV")) != -1)
2485b0945b5SGregory Neil Shapiro # else
2492fb4f839SGregory Neil Shapiro 	while ((ch = getopt(argc, argv, "7BbdD:f:h:r:lsUV")) != -1)
2505b0945b5SGregory Neil Shapiro # endif
251bfb62e91SGregory Neil Shapiro #endif /* HASHSPOOL */
2523299c2f1SGregory Neil Shapiro 	{
2533299c2f1SGregory Neil Shapiro 		switch(ch)
2543299c2f1SGregory Neil Shapiro 		{
2553299c2f1SGregory Neil Shapiro 		  case '7':		/* Do not advertise 8BITMIME */
25612ed1c7cSGregory Neil Shapiro 			EightBitMime = false;
257d615a192SPeter Wemm 			break;
2583299c2f1SGregory Neil Shapiro 
2593299c2f1SGregory Neil Shapiro 		  case 'B':
26039e37e72SGregory Neil Shapiro 			nobiff = true;
2613299c2f1SGregory Neil Shapiro 			break;
2623299c2f1SGregory Neil Shapiro 
2633299c2f1SGregory Neil Shapiro 		  case 'b':		/* bounce mail when over quota. */
26412ed1c7cSGregory Neil Shapiro 			BounceQuota = true;
2653299c2f1SGregory Neil Shapiro 			break;
2663299c2f1SGregory Neil Shapiro 
267c2aa98e2SPeter Wemm 		  case 'd':		/* Backward compatible. */
268c2aa98e2SPeter Wemm 			break;
2693299c2f1SGregory Neil Shapiro 
27012ed1c7cSGregory Neil Shapiro 		  case 'D':		/* mailbox database type */
27112ed1c7cSGregory Neil Shapiro 			mbdbname = optarg;
27212ed1c7cSGregory Neil Shapiro 			break;
27312ed1c7cSGregory Neil Shapiro 
274c2aa98e2SPeter Wemm 		  case 'f':
275c2aa98e2SPeter Wemm 		  case 'r':		/* Backward compatible. */
2763299c2f1SGregory Neil Shapiro 			if (from != NULL)
2773299c2f1SGregory Neil Shapiro 			{
278b4662009SGregory Neil Shapiro 				mailerr(NULL, "Multiple -f options");
279c2aa98e2SPeter Wemm 				usage();
280c2aa98e2SPeter Wemm 			}
281c2aa98e2SPeter Wemm 			from = optarg;
282c2aa98e2SPeter Wemm 			break;
2833299c2f1SGregory Neil Shapiro 
28412ed1c7cSGregory Neil Shapiro 		  case 'h':
28512ed1c7cSGregory Neil Shapiro 			if (optarg != NULL || *optarg != '\0')
28612ed1c7cSGregory Neil Shapiro 				HomeMailFile = optarg;
28712ed1c7cSGregory Neil Shapiro 			else
28812ed1c7cSGregory Neil Shapiro 			{
28912ed1c7cSGregory Neil Shapiro 				mailerr(NULL, "-h: missing filename");
29012ed1c7cSGregory Neil Shapiro 				usage();
29112ed1c7cSGregory Neil Shapiro 			}
29212ed1c7cSGregory Neil Shapiro 			break;
29312ed1c7cSGregory Neil Shapiro 
294c2aa98e2SPeter Wemm 		  case 'l':
29512ed1c7cSGregory Neil Shapiro 			LMTPMode = true;
296c2aa98e2SPeter Wemm 			break;
2973299c2f1SGregory Neil Shapiro 
298d615a192SPeter Wemm 		  case 's':
29905b73c60SPeter Wemm 			nofsync++;
300d615a192SPeter Wemm 			break;
3013299c2f1SGregory Neil Shapiro 
302bfb62e91SGregory Neil Shapiro #if HASHSPOOL
303bfb62e91SGregory Neil Shapiro 		  case 'H':
304bfb62e91SGregory Neil Shapiro 			if (optarg == NULL || *optarg == '\0')
305bfb62e91SGregory Neil Shapiro 			{
306bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-H: missing hashinfo");
307bfb62e91SGregory Neil Shapiro 				usage();
308bfb62e91SGregory Neil Shapiro 			}
309bfb62e91SGregory Neil Shapiro 			switch(optarg[0])
310bfb62e91SGregory Neil Shapiro 			{
311bfb62e91SGregory Neil Shapiro 			  case 'u':
312bfb62e91SGregory Neil Shapiro 				HashType = HASH_USER;
313bfb62e91SGregory Neil Shapiro 				break;
314bfb62e91SGregory Neil Shapiro 
315bfb62e91SGregory Neil Shapiro # if HASHSPOOLMD5
316bfb62e91SGregory Neil Shapiro 			  case 'm':
317bfb62e91SGregory Neil Shapiro 				HashType = HASH_MD5;
318bfb62e91SGregory Neil Shapiro 				break;
3195b0945b5SGregory Neil Shapiro # endif
320bfb62e91SGregory Neil Shapiro 
321bfb62e91SGregory Neil Shapiro 			  default:
322bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-H: unknown hash type");
323bfb62e91SGregory Neil Shapiro 				usage();
324bfb62e91SGregory Neil Shapiro 			}
325bfb62e91SGregory Neil Shapiro 			if (optarg[1] == '\0')
326bfb62e91SGregory Neil Shapiro 			{
327bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-H: invalid hash depth");
328bfb62e91SGregory Neil Shapiro 				usage();
329bfb62e91SGregory Neil Shapiro 			}
330bfb62e91SGregory Neil Shapiro 			HashDepth = atoi(&optarg[1]);
331bfb62e91SGregory Neil Shapiro 			if ((HashDepth <= 0) || ((HashDepth * 2) >= MAXPATHLEN))
332bfb62e91SGregory Neil Shapiro 			{
333bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-H: invalid hash depth");
334bfb62e91SGregory Neil Shapiro 				usage();
335bfb62e91SGregory Neil Shapiro 			}
336bfb62e91SGregory Neil Shapiro 			break;
337bfb62e91SGregory Neil Shapiro 
338e3793f76SGregory Neil Shapiro 		  case 'n':
339e3793f76SGregory Neil Shapiro 			StripRcptDomain = false;
340e3793f76SGregory Neil Shapiro 			break;
341e3793f76SGregory Neil Shapiro #endif /* HASHSPOOL */
342e3793f76SGregory Neil Shapiro 
343e3793f76SGregory Neil Shapiro #if HASHSPOOL || _FFR_SPOOL_PATH
344bfb62e91SGregory Neil Shapiro 		  case 'p':
345bfb62e91SGregory Neil Shapiro 			if (optarg == NULL || *optarg == '\0')
346bfb62e91SGregory Neil Shapiro 			{
347bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-p: missing spool path");
348bfb62e91SGregory Neil Shapiro 				usage();
349bfb62e91SGregory Neil Shapiro 			}
350bfb62e91SGregory Neil Shapiro 			if (sm_strlcpy(SpoolPath, optarg, sizeof(SpoolPath)) >=
351bfb62e91SGregory Neil Shapiro 			    sizeof(SpoolPath))
352bfb62e91SGregory Neil Shapiro 			{
353bfb62e91SGregory Neil Shapiro 				mailerr(NULL, "-p: invalid spool path");
354bfb62e91SGregory Neil Shapiro 				usage();
355bfb62e91SGregory Neil Shapiro 			}
356bfb62e91SGregory Neil Shapiro 			break;
357e3793f76SGregory Neil Shapiro #endif /* HASHSPOOL || _FFR_SPOOL_PATH */
358bfb62e91SGregory Neil Shapiro 
3592fb4f839SGregory Neil Shapiro #if USE_EAI
3602fb4f839SGregory Neil Shapiro 		  case 'U':
3612fb4f839SGregory Neil Shapiro 			EAI = false;
3622fb4f839SGregory Neil Shapiro 			break;
3632fb4f839SGregory Neil Shapiro #endif
3642fb4f839SGregory Neil Shapiro 		  case 'V':
3652fb4f839SGregory Neil Shapiro 			fprintf(stderr, "compiled with\n");
3662fb4f839SGregory Neil Shapiro #if MAIL_LOCAL_TEST
3672fb4f839SGregory Neil Shapiro 			fprintf(stderr, "MAIL_LOCAL_TEST\n");
3682fb4f839SGregory Neil Shapiro #endif
3692fb4f839SGregory Neil Shapiro #if USE_EAI
3702fb4f839SGregory Neil Shapiro 			/* test scripts should look for SMTPUTF8 */
3712fb4f839SGregory Neil Shapiro 			fprintf(stderr, "USE_EAI\n");
3722fb4f839SGregory Neil Shapiro #endif
3732fb4f839SGregory Neil Shapiro 			break;
3742fb4f839SGregory Neil Shapiro 
375c2aa98e2SPeter Wemm 		  case '?':
376c2aa98e2SPeter Wemm 		  default:
377c2aa98e2SPeter Wemm 			usage();
378c2aa98e2SPeter Wemm 		}
3793299c2f1SGregory Neil Shapiro 	}
380c2aa98e2SPeter Wemm 	argc -= optind;
381c2aa98e2SPeter Wemm 	argv += optind;
382c2aa98e2SPeter Wemm 
3833299c2f1SGregory Neil Shapiro 	/* initialize biff structures */
3843299c2f1SGregory Neil Shapiro 	if (!nobiff)
3853299c2f1SGregory Neil Shapiro 		notifybiff(NULL);
386c2aa98e2SPeter Wemm 
38712ed1c7cSGregory Neil Shapiro 	err = sm_mbdb_initialize(mbdbname);
38812ed1c7cSGregory Neil Shapiro 	if (err != EX_OK)
38912ed1c7cSGregory Neil Shapiro 	{
39012ed1c7cSGregory Neil Shapiro 		char *errcode = "521";
39112ed1c7cSGregory Neil Shapiro 
39212ed1c7cSGregory Neil Shapiro 		if (err == EX_TEMPFAIL)
39312ed1c7cSGregory Neil Shapiro 			errcode = "421";
39412ed1c7cSGregory Neil Shapiro 
39512ed1c7cSGregory Neil Shapiro 		mailerr(errcode, "Can not open mailbox database %s: %s",
39612ed1c7cSGregory Neil Shapiro 			mbdbname, sm_strexit(err));
397684b2a5fSGregory Neil Shapiro 		sm_exit(err);
39812ed1c7cSGregory Neil Shapiro 	}
399684b2a5fSGregory Neil Shapiro 	CloseMBDB = true;
40012ed1c7cSGregory Neil Shapiro 
4013299c2f1SGregory Neil Shapiro 	if (LMTPMode)
402b4662009SGregory Neil Shapiro 	{
403b4662009SGregory Neil Shapiro 		if (argc > 0)
404b4662009SGregory Neil Shapiro 		{
405b4662009SGregory Neil Shapiro 			mailerr("421", "Users should not be specified in command line if LMTP required");
406684b2a5fSGregory Neil Shapiro 			sm_exit(EX_TEMPFAIL);
407b4662009SGregory Neil Shapiro 		}
408b4662009SGregory Neil Shapiro 
409b4662009SGregory Neil Shapiro 		dolmtp();
410b4662009SGregory Neil Shapiro 		/* NOTREACHED */
411684b2a5fSGregory Neil Shapiro 		sm_exit(EX_OK);
412b4662009SGregory Neil Shapiro 	}
413b4662009SGregory Neil Shapiro 
414b4662009SGregory Neil Shapiro 	/* Non-LMTP from here on out */
415f1897613SBrooks Davis 	if (*argv == NULL)
416c2aa98e2SPeter Wemm 		usage();
417c2aa98e2SPeter Wemm 
418c2aa98e2SPeter Wemm 	/*
4193299c2f1SGregory Neil Shapiro 	**  If from not specified, use the name from getlogin() if the
4203299c2f1SGregory Neil Shapiro 	**  uid matches, otherwise, use the name from the password file
4213299c2f1SGregory Neil Shapiro 	**  corresponding to the uid.
422c2aa98e2SPeter Wemm 	*/
423b4662009SGregory Neil Shapiro 
424c2aa98e2SPeter Wemm 	uid = getuid();
4253299c2f1SGregory Neil Shapiro 	if (from == NULL && ((from = getlogin()) == NULL ||
4263299c2f1SGregory Neil Shapiro 			     (pw = getpwnam(from)) == NULL ||
4273299c2f1SGregory Neil Shapiro 			     pw->pw_uid != uid))
4283299c2f1SGregory Neil Shapiro 		from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm 	/*
4313299c2f1SGregory Neil Shapiro 	**  There is no way to distinguish the error status of one delivery
4323299c2f1SGregory Neil Shapiro 	**  from the rest of the deliveries.  So, if we failed hard on one
4333299c2f1SGregory Neil Shapiro 	**  or more deliveries, but had no failures on any of the others, we
4343299c2f1SGregory Neil Shapiro 	**  return a hard failure.  If we failed temporarily on one or more
4353299c2f1SGregory Neil Shapiro 	**  deliveries, we return a temporary failure regardless of the other
4363299c2f1SGregory Neil Shapiro 	**  failures.  This results in the delivery being reattempted later
4373299c2f1SGregory Neil Shapiro 	**  at the expense of repeated failures and multiple deliveries.
438c2aa98e2SPeter Wemm 	*/
439b4662009SGregory Neil Shapiro 
44012ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
44112ed1c7cSGregory Neil Shapiro 	fd = store(from, NULL);
44212ed1c7cSGregory Neil Shapiro 	HoldErrs = false;
443b4662009SGregory Neil Shapiro 	if (fd < 0)
444b4662009SGregory Neil Shapiro 	{
445b4662009SGregory Neil Shapiro 		flush_error();
446684b2a5fSGregory Neil Shapiro 		sm_exit(ExitVal);
447b4662009SGregory Neil Shapiro 	}
448b4662009SGregory Neil Shapiro 	for (; *argv != NULL; ++argv)
449b4662009SGregory Neil Shapiro 		deliver(fd, *argv);
450684b2a5fSGregory Neil Shapiro 	sm_exit(ExitVal);
4513299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
4523299c2f1SGregory Neil Shapiro 	return ExitVal;
453c2aa98e2SPeter Wemm }
454c2aa98e2SPeter Wemm 
455c2aa98e2SPeter Wemm char *
parseaddr(s,rcpt)4563299c2f1SGregory Neil Shapiro parseaddr(s, rcpt)
457c2aa98e2SPeter Wemm 	char *s;
4583299c2f1SGregory Neil Shapiro 	bool rcpt;
459c2aa98e2SPeter Wemm {
460c2aa98e2SPeter Wemm 	char *p;
4613299c2f1SGregory Neil Shapiro 	int l;
462c2aa98e2SPeter Wemm 
463c2aa98e2SPeter Wemm 	if (*s++ != '<')
464c2aa98e2SPeter Wemm 		return NULL;
465c2aa98e2SPeter Wemm 
466c2aa98e2SPeter Wemm 	p = s;
467c2aa98e2SPeter Wemm 
468c2aa98e2SPeter Wemm 	/* at-domain-list */
4693299c2f1SGregory Neil Shapiro 	while (*p == '@')
4703299c2f1SGregory Neil Shapiro 	{
471c2aa98e2SPeter Wemm 		p++;
4723299c2f1SGregory Neil Shapiro 		while (*p != ',' && *p != ':' && *p != '\0')
473c2aa98e2SPeter Wemm 			p++;
4743299c2f1SGregory Neil Shapiro 		if (*p == '\0')
475c2aa98e2SPeter Wemm 			return NULL;
4763299c2f1SGregory Neil Shapiro 
4773299c2f1SGregory Neil Shapiro 		/* Skip over , or : */
478c2aa98e2SPeter Wemm 		p++;
479c2aa98e2SPeter Wemm 	}
480c2aa98e2SPeter Wemm 
48176b7bf71SPeter Wemm 	s = p;
48276b7bf71SPeter Wemm 
483c2aa98e2SPeter Wemm 	/* local-part */
4843299c2f1SGregory Neil Shapiro 	while (*p != '\0' && *p != '@' && *p != '>')
4853299c2f1SGregory Neil Shapiro 	{
4863299c2f1SGregory Neil Shapiro 		if (*p == '\\')
4873299c2f1SGregory Neil Shapiro 		{
4883299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
4893299c2f1SGregory Neil Shapiro 				return NULL;
4903299c2f1SGregory Neil Shapiro 		}
4913299c2f1SGregory Neil Shapiro 		else if (*p == '\"')
4923299c2f1SGregory Neil Shapiro 		{
493c2aa98e2SPeter Wemm 			p++;
4943299c2f1SGregory Neil Shapiro 			while (*p != '\0' && *p != '\"')
4953299c2f1SGregory Neil Shapiro 			{
4963299c2f1SGregory Neil Shapiro 				if (*p == '\\')
4973299c2f1SGregory Neil Shapiro 				{
4983299c2f1SGregory Neil Shapiro 					if (*++p == '\0')
499c2aa98e2SPeter Wemm 						return NULL;
500c2aa98e2SPeter Wemm 				}
501c2aa98e2SPeter Wemm 				p++;
502c2aa98e2SPeter Wemm 			}
5033299c2f1SGregory Neil Shapiro 			if (*p == '\0' || *(p + 1) == '\0')
504c2aa98e2SPeter Wemm 				return NULL;
505c2aa98e2SPeter Wemm 		}
5063299c2f1SGregory Neil Shapiro 		/* +detail ? */
5073299c2f1SGregory Neil Shapiro 		if (*p == '+' && rcpt)
5083299c2f1SGregory Neil Shapiro 			*p = '\0';
509c2aa98e2SPeter Wemm 		p++;
510c2aa98e2SPeter Wemm 	}
511c2aa98e2SPeter Wemm 
512c2aa98e2SPeter Wemm 	/* @domain */
5133299c2f1SGregory Neil Shapiro 	if (*p == '@')
51476b7bf71SPeter Wemm 	{
5153299c2f1SGregory Neil Shapiro 		if (rcpt)
5163299c2f1SGregory Neil Shapiro 			*p++ = '\0';
5173299c2f1SGregory Neil Shapiro 		while (*p != '\0' && *p != '>')
5183299c2f1SGregory Neil Shapiro 			p++;
51976b7bf71SPeter Wemm 	}
520c2aa98e2SPeter Wemm 
5213299c2f1SGregory Neil Shapiro 	if (*p != '>')
5223299c2f1SGregory Neil Shapiro 		return NULL;
5233299c2f1SGregory Neil Shapiro 	else
5243299c2f1SGregory Neil Shapiro 		*p = '\0';
5253299c2f1SGregory Neil Shapiro 	p++;
5263299c2f1SGregory Neil Shapiro 
5273299c2f1SGregory Neil Shapiro 	if (*p != '\0' && *p != ' ')
5283299c2f1SGregory Neil Shapiro 		return NULL;
5293299c2f1SGregory Neil Shapiro 
5303299c2f1SGregory Neil Shapiro 	if (*s == '\0')
5313299c2f1SGregory Neil Shapiro 		s = MAILER_DAEMON;
5323299c2f1SGregory Neil Shapiro 
5333299c2f1SGregory Neil Shapiro 	l = strlen(s) + 1;
53412ed1c7cSGregory Neil Shapiro 	if (l < 0)
53512ed1c7cSGregory Neil Shapiro 		return NULL;
5363299c2f1SGregory Neil Shapiro 	p = malloc(l);
5373299c2f1SGregory Neil Shapiro 	if (p == NULL)
5383299c2f1SGregory Neil Shapiro 	{
539b4662009SGregory Neil Shapiro 		mailerr("421 4.3.0", "Memory exhausted");
540684b2a5fSGregory Neil Shapiro 		sm_exit(EX_TEMPFAIL);
541c2aa98e2SPeter Wemm 	}
542c2aa98e2SPeter Wemm 
54312ed1c7cSGregory Neil Shapiro 	(void) sm_strlcpy(p, s, l);
544c2aa98e2SPeter Wemm 	return p;
545c2aa98e2SPeter Wemm }
546c2aa98e2SPeter Wemm 
547c2aa98e2SPeter Wemm char *
process_recipient(addr)548c2aa98e2SPeter Wemm process_recipient(addr)
549c2aa98e2SPeter Wemm 	char *addr;
550c2aa98e2SPeter Wemm {
55112ed1c7cSGregory Neil Shapiro 	SM_MBDB_T user;
55212ed1c7cSGregory Neil Shapiro 
55312ed1c7cSGregory Neil Shapiro 	switch (sm_mbdb_lookup(addr, &user))
55412ed1c7cSGregory Neil Shapiro 	{
55512ed1c7cSGregory Neil Shapiro 	  case EX_OK:
556c2aa98e2SPeter Wemm 		return NULL;
55712ed1c7cSGregory Neil Shapiro 
55812ed1c7cSGregory Neil Shapiro 	  case EX_NOUSER:
55912ed1c7cSGregory Neil Shapiro 		return "550 5.1.1 User unknown";
56012ed1c7cSGregory Neil Shapiro 
56112ed1c7cSGregory Neil Shapiro 	  case EX_TEMPFAIL:
56212ed1c7cSGregory Neil Shapiro 		return "451 4.3.0 User database failure; retry later";
56312ed1c7cSGregory Neil Shapiro 
56412ed1c7cSGregory Neil Shapiro 	  default:
56512ed1c7cSGregory Neil Shapiro 		return "550 5.3.0 User database failure";
56612ed1c7cSGregory Neil Shapiro 	}
567c2aa98e2SPeter Wemm }
568c2aa98e2SPeter Wemm 
569c2aa98e2SPeter Wemm #define RCPT_GROW	30
570c2aa98e2SPeter Wemm 
571c2aa98e2SPeter Wemm void
dolmtp()572b4662009SGregory Neil Shapiro dolmtp()
573c2aa98e2SPeter Wemm {
574c2aa98e2SPeter Wemm 	char *return_path = NULL;
575c2aa98e2SPeter Wemm 	char **rcpt_addr = NULL;
576c2aa98e2SPeter Wemm 	int rcpt_num = 0;
577c2aa98e2SPeter Wemm 	int rcpt_alloc = 0;
57812ed1c7cSGregory Neil Shapiro 	bool gotlhlo = false;
579c2aa98e2SPeter Wemm 	char *err;
580c2aa98e2SPeter Wemm 	int msgfd;
581c2aa98e2SPeter Wemm 	char *p;
582c2aa98e2SPeter Wemm 	int i;
5833299c2f1SGregory Neil Shapiro 	char myhostname[1024];
5843299c2f1SGregory Neil Shapiro 	char buf[4096];
585c2aa98e2SPeter Wemm 
586b4662009SGregory Neil Shapiro 	memset(myhostname, '\0', sizeof myhostname);
5873299c2f1SGregory Neil Shapiro 	(void) gethostname(myhostname, sizeof myhostname - 1);
588b4662009SGregory Neil Shapiro 	if (myhostname[0] == '\0')
58912ed1c7cSGregory Neil Shapiro 		sm_strlcpy(myhostname, "localhost", sizeof myhostname);
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	printf("220 %s LMTP ready\r\n", myhostname);
5923299c2f1SGregory Neil Shapiro 	for (;;)
5933299c2f1SGregory Neil Shapiro 	{
5943299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
5953299c2f1SGregory Neil Shapiro 		if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
596684b2a5fSGregory Neil Shapiro 			sm_exit(EX_OK);
597c2aa98e2SPeter Wemm 		p = buf + strlen(buf) - 1;
598c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\n')
599c2aa98e2SPeter Wemm 			*p-- = '\0';
600c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\r')
601c2aa98e2SPeter Wemm 			*p-- = '\0';
602c2aa98e2SPeter Wemm 
6033299c2f1SGregory Neil Shapiro 		switch (buf[0])
6043299c2f1SGregory Neil Shapiro 		{
605c2aa98e2SPeter Wemm 		  case 'd':
606c2aa98e2SPeter Wemm 		  case 'D':
6072fb4f839SGregory Neil Shapiro 			if (SM_STRCASEEQ(buf, "data"))
6083299c2f1SGregory Neil Shapiro 			{
60912ed1c7cSGregory Neil Shapiro 				bool inbody = false;
610b4662009SGregory Neil Shapiro 
6113299c2f1SGregory Neil Shapiro 				if (rcpt_num == 0)
6123299c2f1SGregory Neil Shapiro 				{
613b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1", "No recipients");
614c2aa98e2SPeter Wemm 					continue;
615c2aa98e2SPeter Wemm 				}
61612ed1c7cSGregory Neil Shapiro 				HoldErrs = true;
61712ed1c7cSGregory Neil Shapiro 				msgfd = store(return_path, &inbody);
61812ed1c7cSGregory Neil Shapiro 				HoldErrs = false;
619b4662009SGregory Neil Shapiro 				if (msgfd < 0 && !inbody)
620b4662009SGregory Neil Shapiro 				{
621b4662009SGregory Neil Shapiro 					flush_error();
622c2aa98e2SPeter Wemm 					continue;
623b4662009SGregory Neil Shapiro 				}
624c2aa98e2SPeter Wemm 
6253299c2f1SGregory Neil Shapiro 				for (i = 0; i < rcpt_num; i++)
6263299c2f1SGregory Neil Shapiro 				{
627b4662009SGregory Neil Shapiro 					if (msgfd < 0)
628b4662009SGregory Neil Shapiro 					{
629b4662009SGregory Neil Shapiro 						/* print error for rcpt */
630b4662009SGregory Neil Shapiro 						flush_error();
631b4662009SGregory Neil Shapiro 						continue;
632b4662009SGregory Neil Shapiro 					}
633c2aa98e2SPeter Wemm 					p = strchr(rcpt_addr[i], '+');
634c2aa98e2SPeter Wemm 					if (p != NULL)
635b4662009SGregory Neil Shapiro 						*p = '\0';
636b4662009SGregory Neil Shapiro 					deliver(msgfd, rcpt_addr[i]);
637c2aa98e2SPeter Wemm 				}
638b4662009SGregory Neil Shapiro 				if (msgfd >= 0)
6393299c2f1SGregory Neil Shapiro 					(void) close(msgfd);
640c2aa98e2SPeter Wemm 				goto rset;
641c2aa98e2SPeter Wemm 			}
642c2aa98e2SPeter Wemm 			goto syntaxerr;
6433299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6443299c2f1SGregory Neil Shapiro 			break;
645c2aa98e2SPeter Wemm 
646c2aa98e2SPeter Wemm 		  case 'l':
647c2aa98e2SPeter Wemm 		  case 'L':
64812ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "lhlo ", 5) == 0)
6493299c2f1SGregory Neil Shapiro 			{
6503299c2f1SGregory Neil Shapiro 				/* check for duplicate per RFC 1651 4.2 */
6513299c2f1SGregory Neil Shapiro 				if (gotlhlo)
6523299c2f1SGregory Neil Shapiro 				{
653b4662009SGregory Neil Shapiro 					mailerr("503", "%s Duplicate LHLO",
654c2aa98e2SPeter Wemm 					       myhostname);
655c2aa98e2SPeter Wemm 					continue;
656c2aa98e2SPeter Wemm 				}
65712ed1c7cSGregory Neil Shapiro 				gotlhlo = true;
6583299c2f1SGregory Neil Shapiro 				printf("250-%s\r\n", myhostname);
6593299c2f1SGregory Neil Shapiro 				if (EightBitMime)
6603299c2f1SGregory Neil Shapiro 					printf("250-8BITMIME\r\n");
6612fb4f839SGregory Neil Shapiro #if USE_EAI
6622fb4f839SGregory Neil Shapiro 				if (EAI)
6632fb4f839SGregory Neil Shapiro 					printf("250-SMTPUTF8\r\n");
6642fb4f839SGregory Neil Shapiro #endif
6653299c2f1SGregory Neil Shapiro 				printf("250-ENHANCEDSTATUSCODES\r\n");
6663299c2f1SGregory Neil Shapiro 				printf("250 PIPELINING\r\n");
6673299c2f1SGregory Neil Shapiro 				continue;
6683299c2f1SGregory Neil Shapiro 			}
669c2aa98e2SPeter Wemm 			goto syntaxerr;
6703299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6713299c2f1SGregory Neil Shapiro 			break;
672c2aa98e2SPeter Wemm 
673c2aa98e2SPeter Wemm 		  case 'm':
674c2aa98e2SPeter Wemm 		  case 'M':
67512ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "mail ", 5) == 0)
6763299c2f1SGregory Neil Shapiro 			{
6773299c2f1SGregory Neil Shapiro 				if (return_path != NULL)
6783299c2f1SGregory Neil Shapiro 				{
679b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1",
680b4662009SGregory Neil Shapiro 						"Nested MAIL command");
681c2aa98e2SPeter Wemm 					continue;
682c2aa98e2SPeter Wemm 				}
68312ed1c7cSGregory Neil Shapiro 				if (sm_strncasecmp(buf + 5, "from:", 5) != 0 ||
6843299c2f1SGregory Neil Shapiro 				    ((return_path = parseaddr(buf + 10,
68512ed1c7cSGregory Neil Shapiro 							      false)) == NULL))
6863299c2f1SGregory Neil Shapiro 				{
687b4662009SGregory Neil Shapiro 					mailerr("501 5.5.4",
688b4662009SGregory Neil Shapiro 						"Syntax error in parameters");
689c2aa98e2SPeter Wemm 					continue;
690c2aa98e2SPeter Wemm 				}
691b4662009SGregory Neil Shapiro 				printf("250 2.5.0 Ok\r\n");
692c2aa98e2SPeter Wemm 				continue;
693c2aa98e2SPeter Wemm 			}
694c2aa98e2SPeter Wemm 			goto syntaxerr;
6953299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
6963299c2f1SGregory Neil Shapiro 			break;
697c2aa98e2SPeter Wemm 
698c2aa98e2SPeter Wemm 		  case 'n':
699c2aa98e2SPeter Wemm 		  case 'N':
7002fb4f839SGregory Neil Shapiro 			if (SM_STRCASEEQ(buf, "noop"))
7013299c2f1SGregory Neil Shapiro 			{
702b4662009SGregory Neil Shapiro 				printf("250 2.0.0 Ok\r\n");
703c2aa98e2SPeter Wemm 				continue;
704c2aa98e2SPeter Wemm 			}
705c2aa98e2SPeter Wemm 			goto syntaxerr;
7063299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
7073299c2f1SGregory Neil Shapiro 			break;
708c2aa98e2SPeter Wemm 
709c2aa98e2SPeter Wemm 		  case 'q':
710c2aa98e2SPeter Wemm 		  case 'Q':
7112fb4f839SGregory Neil Shapiro 			if (SM_STRCASEEQ(buf, "quit"))
7123299c2f1SGregory Neil Shapiro 			{
713b4662009SGregory Neil Shapiro 				printf("221 2.0.0 Bye\r\n");
714684b2a5fSGregory Neil Shapiro 				sm_exit(EX_OK);
715c2aa98e2SPeter Wemm 			}
716c2aa98e2SPeter Wemm 			goto syntaxerr;
7173299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
7183299c2f1SGregory Neil Shapiro 			break;
719c2aa98e2SPeter Wemm 
720c2aa98e2SPeter Wemm 		  case 'r':
721c2aa98e2SPeter Wemm 		  case 'R':
72212ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "rcpt ", 5) == 0)
7233299c2f1SGregory Neil Shapiro 			{
7243299c2f1SGregory Neil Shapiro 				if (return_path == NULL)
7253299c2f1SGregory Neil Shapiro 				{
726b4662009SGregory Neil Shapiro 					mailerr("503 5.5.1",
727b4662009SGregory Neil Shapiro 						"Need MAIL command");
728c2aa98e2SPeter Wemm 					continue;
729c2aa98e2SPeter Wemm 				}
7303299c2f1SGregory Neil Shapiro 				if (rcpt_num >= rcpt_alloc)
7313299c2f1SGregory Neil Shapiro 				{
732c2aa98e2SPeter Wemm 					rcpt_alloc += RCPT_GROW;
733c2aa98e2SPeter Wemm 					rcpt_addr = (char **)
7343299c2f1SGregory Neil Shapiro 						REALLOC((char *) rcpt_addr,
7353299c2f1SGregory Neil Shapiro 							rcpt_alloc *
7363299c2f1SGregory Neil Shapiro 							sizeof(char **));
7373299c2f1SGregory Neil Shapiro 					if (rcpt_addr == NULL)
7383299c2f1SGregory Neil Shapiro 					{
739b4662009SGregory Neil Shapiro 						mailerr("421 4.3.0",
740b4662009SGregory Neil Shapiro 							"Memory exhausted");
741684b2a5fSGregory Neil Shapiro 						sm_exit(EX_TEMPFAIL);
742c2aa98e2SPeter Wemm 					}
743c2aa98e2SPeter Wemm 				}
74412ed1c7cSGregory Neil Shapiro 				if (sm_strncasecmp(buf + 5, "to:", 3) != 0 ||
7453299c2f1SGregory Neil Shapiro 				    ((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
746bfb62e91SGregory Neil Shapiro 								      StripRcptDomain)) == NULL))
7473299c2f1SGregory Neil Shapiro 				{
748b4662009SGregory Neil Shapiro 					mailerr("501 5.5.4",
749b4662009SGregory Neil Shapiro 						"Syntax error in parameters");
750c2aa98e2SPeter Wemm 					continue;
751c2aa98e2SPeter Wemm 				}
752b4662009SGregory Neil Shapiro 				err = process_recipient(rcpt_addr[rcpt_num]);
753b4662009SGregory Neil Shapiro 				if (err != NULL)
7543299c2f1SGregory Neil Shapiro 				{
755b4662009SGregory Neil Shapiro 					mailerr(NULL, "%s", err);
756c2aa98e2SPeter Wemm 					continue;
757c2aa98e2SPeter Wemm 				}
758c2aa98e2SPeter Wemm 				rcpt_num++;
759b4662009SGregory Neil Shapiro 				printf("250 2.1.5 Ok\r\n");
760c2aa98e2SPeter Wemm 				continue;
761c2aa98e2SPeter Wemm 			}
7622fb4f839SGregory Neil Shapiro 			else if (SM_STRCASEEQ(buf, "rset"))
7633299c2f1SGregory Neil Shapiro 			{
764b4662009SGregory Neil Shapiro 				printf("250 2.0.0 Ok\r\n");
765c2aa98e2SPeter Wemm 
766c2aa98e2SPeter Wemm rset:
767c46d91b7SGregory Neil Shapiro 				while (rcpt_num > 0)
768c2aa98e2SPeter Wemm 					free(rcpt_addr[--rcpt_num]);
769c2aa98e2SPeter Wemm 				if (return_path != NULL)
770c2aa98e2SPeter Wemm 					free(return_path);
771c2aa98e2SPeter Wemm 				return_path = NULL;
772c2aa98e2SPeter Wemm 				continue;
773c2aa98e2SPeter Wemm 			}
774c2aa98e2SPeter Wemm 			goto syntaxerr;
7753299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
7763299c2f1SGregory Neil Shapiro 			break;
777c2aa98e2SPeter Wemm 
778c2aa98e2SPeter Wemm 		  case 'v':
779c2aa98e2SPeter Wemm 		  case 'V':
78012ed1c7cSGregory Neil Shapiro 			if (sm_strncasecmp(buf, "vrfy ", 5) == 0)
7813299c2f1SGregory Neil Shapiro 			{
782b4662009SGregory Neil Shapiro 				printf("252 2.3.3 Try RCPT to attempt delivery\r\n");
783c2aa98e2SPeter Wemm 				continue;
784c2aa98e2SPeter Wemm 			}
785c2aa98e2SPeter Wemm 			goto syntaxerr;
7863299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
7873299c2f1SGregory Neil Shapiro 			break;
788c2aa98e2SPeter Wemm 
789c2aa98e2SPeter Wemm 		  default:
790c2aa98e2SPeter Wemm   syntaxerr:
791b4662009SGregory Neil Shapiro 			mailerr("500 5.5.2", "Syntax error");
792c2aa98e2SPeter Wemm 			continue;
7933299c2f1SGregory Neil Shapiro 			/* NOTREACHED */
7943299c2f1SGregory Neil Shapiro 			break;
795c2aa98e2SPeter Wemm 		}
796c2aa98e2SPeter Wemm 	}
797c2aa98e2SPeter Wemm }
798c2aa98e2SPeter Wemm 
799c2aa98e2SPeter Wemm int
store(from,inbody)80012ed1c7cSGregory Neil Shapiro store(from, inbody)
801c2aa98e2SPeter Wemm 	char *from;
802b4662009SGregory Neil Shapiro 	bool *inbody;
803c2aa98e2SPeter Wemm {
80476b7bf71SPeter Wemm 	FILE *fp = NULL;
805c2aa98e2SPeter Wemm 	time_t tval;
80612ed1c7cSGregory Neil Shapiro 	bool eline;		/* previous line was empty */
80712ed1c7cSGregory Neil Shapiro 	bool fullline = true;	/* current line is terminated */
8083299c2f1SGregory Neil Shapiro 	bool prevfl;		/* previous line was terminated */
809c2aa98e2SPeter Wemm 	char line[2048];
8103299c2f1SGregory Neil Shapiro 	int fd;
811c2aa98e2SPeter Wemm 	char tmpbuf[sizeof _PATH_LOCTMP + 1];
812c2aa98e2SPeter Wemm 
813b4662009SGregory Neil Shapiro 	if (inbody != NULL)
81412ed1c7cSGregory Neil Shapiro 		*inbody = false;
815b4662009SGregory Neil Shapiro 
8163299c2f1SGregory Neil Shapiro 	(void) umask(0077);
81712ed1c7cSGregory Neil Shapiro 	(void) sm_strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
818b4662009SGregory Neil Shapiro 	if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL)
8193299c2f1SGregory Neil Shapiro 	{
8202ef40764SGregory Neil Shapiro 		if (fd >= 0)
8212ef40764SGregory Neil Shapiro 			(void) close(fd);
822b4662009SGregory Neil Shapiro 		mailerr("451 4.3.0", "Unable to open temporary file");
823c2aa98e2SPeter Wemm 		return -1;
8243299c2f1SGregory Neil Shapiro 	}
825c2aa98e2SPeter Wemm 	(void) unlink(tmpbuf);
826c2aa98e2SPeter Wemm 
8273299c2f1SGregory Neil Shapiro 	if (LMTPMode)
8283299c2f1SGregory Neil Shapiro 	{
829b4662009SGregory Neil Shapiro 		printf("354 Go ahead\r\n");
8303299c2f1SGregory Neil Shapiro 		(void) fflush(stdout);
831c2aa98e2SPeter Wemm 	}
832b4662009SGregory Neil Shapiro 	if (inbody != NULL)
83312ed1c7cSGregory Neil Shapiro 		*inbody = true;
834c2aa98e2SPeter Wemm 
835c2aa98e2SPeter Wemm 	(void) time(&tval);
836c2aa98e2SPeter Wemm 	(void) fprintf(fp, "From %s %s", from, ctime(&tval));
837c2aa98e2SPeter Wemm 
8383299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
8393299c2f1SGregory Neil Shapiro 	HeaderLength = 0;
8403299c2f1SGregory Neil Shapiro 	BodyLength = -1;
8415b0945b5SGregory Neil Shapiro #endif
8423299c2f1SGregory Neil Shapiro 
843c2aa98e2SPeter Wemm 	line[0] = '\0';
84412ed1c7cSGregory Neil Shapiro 	eline = true;
8453299c2f1SGregory Neil Shapiro 	while (fgets(line, sizeof(line), stdin) != (char *) NULL)
8463299c2f1SGregory Neil Shapiro 	{
8473299c2f1SGregory Neil Shapiro 		size_t line_len = 0;
8483299c2f1SGregory Neil Shapiro 		int peek;
84976b7bf71SPeter Wemm 
8503299c2f1SGregory Neil Shapiro 		prevfl = fullline;	/* preserve state of previous line */
8513299c2f1SGregory Neil Shapiro 		while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
8523299c2f1SGregory Neil Shapiro 			line_len++;
8533299c2f1SGregory Neil Shapiro 		line_len++;
85476b7bf71SPeter Wemm 
8553299c2f1SGregory Neil Shapiro 		/* Check for dot-stuffing */
856b4662009SGregory Neil Shapiro 		if (prevfl && LMTPMode && line[0] == '.')
8573299c2f1SGregory Neil Shapiro 		{
8583299c2f1SGregory Neil Shapiro 			if (line[1] == '\n' ||
8593299c2f1SGregory Neil Shapiro 			    (line[1] == '\r' && line[2] == '\n'))
860c2aa98e2SPeter Wemm 				goto lmtpdot;
8613299c2f1SGregory Neil Shapiro 			memcpy(line, line + 1, line_len);
8623299c2f1SGregory Neil Shapiro 			line_len--;
863c2aa98e2SPeter Wemm 		}
8643299c2f1SGregory Neil Shapiro 
8653299c2f1SGregory Neil Shapiro 		/* Check to see if we have the full line from fgets() */
86612ed1c7cSGregory Neil Shapiro 		fullline = false;
8673299c2f1SGregory Neil Shapiro 		if (line_len > 0)
8683299c2f1SGregory Neil Shapiro 		{
8693299c2f1SGregory Neil Shapiro 			if (line[line_len - 1] == '\n')
8703299c2f1SGregory Neil Shapiro 			{
8713299c2f1SGregory Neil Shapiro 				if (line_len >= 2 &&
8723299c2f1SGregory Neil Shapiro 				    line[line_len - 2] == '\r')
8733299c2f1SGregory Neil Shapiro 				{
8743299c2f1SGregory Neil Shapiro 					line[line_len - 2] = '\n';
8753299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\0';
8763299c2f1SGregory Neil Shapiro 					line_len--;
8773299c2f1SGregory Neil Shapiro 				}
87812ed1c7cSGregory Neil Shapiro 				fullline = true;
8793299c2f1SGregory Neil Shapiro 			}
8803299c2f1SGregory Neil Shapiro 			else if (line[line_len - 1] == '\r')
8813299c2f1SGregory Neil Shapiro 			{
8823299c2f1SGregory Neil Shapiro 				/* Did we just miss the CRLF? */
8833299c2f1SGregory Neil Shapiro 				peek = fgetc(stdin);
8843299c2f1SGregory Neil Shapiro 				if (peek == '\n')
8853299c2f1SGregory Neil Shapiro 				{
8863299c2f1SGregory Neil Shapiro 					line[line_len - 1] = '\n';
88712ed1c7cSGregory Neil Shapiro 					fullline = true;
8883299c2f1SGregory Neil Shapiro 				}
8893299c2f1SGregory Neil Shapiro 				else
8903299c2f1SGregory Neil Shapiro 					(void) ungetc(peek, stdin);
8913299c2f1SGregory Neil Shapiro 			}
8923299c2f1SGregory Neil Shapiro 		}
8933299c2f1SGregory Neil Shapiro 		else
89412ed1c7cSGregory Neil Shapiro 			fullline = true;
8953299c2f1SGregory Neil Shapiro 
8963299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
8973299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n' && HeaderLength == 0)
8983299c2f1SGregory Neil Shapiro 		{
89912ed1c7cSGregory Neil Shapiro 			eline = false;
900b4662009SGregory Neil Shapiro 			if (fp != NULL)
9013299c2f1SGregory Neil Shapiro 				HeaderLength = ftell(fp);
9023299c2f1SGregory Neil Shapiro 			if (HeaderLength <= 0)
9033299c2f1SGregory Neil Shapiro 			{
9043299c2f1SGregory Neil Shapiro 				/*
9053299c2f1SGregory Neil Shapiro 				**  shouldn't happen, unless ftell() is
9063299c2f1SGregory Neil Shapiro 				**  badly broken
9073299c2f1SGregory Neil Shapiro 				*/
9083299c2f1SGregory Neil Shapiro 
9093299c2f1SGregory Neil Shapiro 				HeaderLength = -1;
9103299c2f1SGregory Neil Shapiro 			}
9113299c2f1SGregory Neil Shapiro 		}
9123299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
9133299c2f1SGregory Neil Shapiro 		if (prevfl && line[0] == '\n')
91412ed1c7cSGregory Neil Shapiro 			eline = true;
9153299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
9163299c2f1SGregory Neil Shapiro 		else
9173299c2f1SGregory Neil Shapiro 		{
918c2aa98e2SPeter Wemm 			if (eline && line[0] == 'F' &&
919b4662009SGregory Neil Shapiro 			    fp != NULL &&
920c2aa98e2SPeter Wemm 			    !memcmp(line, "From ", 5))
921c2aa98e2SPeter Wemm 				(void) putc('>', fp);
92212ed1c7cSGregory Neil Shapiro 			eline = false;
9233299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
9243299c2f1SGregory Neil Shapiro 			/* discard existing "Content-Length:" headers */
9253299c2f1SGregory Neil Shapiro 			if (prevfl && HeaderLength == 0 &&
9263299c2f1SGregory Neil Shapiro 			    (line[0] == 'C' || line[0] == 'c') &&
92712ed1c7cSGregory Neil Shapiro 			    sm_strncasecmp(line, ContentHdr, 15) == 0)
9283299c2f1SGregory Neil Shapiro 			{
9293299c2f1SGregory Neil Shapiro 				/*
9303299c2f1SGregory Neil Shapiro 				**  be paranoid: clear the line
9313299c2f1SGregory Neil Shapiro 				**  so no "wrong matches" may occur later
9323299c2f1SGregory Neil Shapiro 				*/
9333299c2f1SGregory Neil Shapiro 				line[0] = '\0';
9343299c2f1SGregory Neil Shapiro 				continue;
935c2aa98e2SPeter Wemm 			}
9363299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
9373299c2f1SGregory Neil Shapiro 
9383299c2f1SGregory Neil Shapiro 		}
939b4662009SGregory Neil Shapiro 		if (fp != NULL)
940b4662009SGregory Neil Shapiro 		{
9413299c2f1SGregory Neil Shapiro 			(void) fwrite(line, sizeof(char), line_len, fp);
9423299c2f1SGregory Neil Shapiro 			if (ferror(fp))
9433299c2f1SGregory Neil Shapiro 			{
94476b7bf71SPeter Wemm 				mailerr("451 4.3.0",
945b4662009SGregory Neil Shapiro 					"Temporary file write error");
9463299c2f1SGregory Neil Shapiro 				(void) fclose(fp);
947b4662009SGregory Neil Shapiro 				fp = NULL;
948b4662009SGregory Neil Shapiro 				continue;
949c2aa98e2SPeter Wemm 			}
950c2aa98e2SPeter Wemm 		}
951c2aa98e2SPeter Wemm 	}
952c2aa98e2SPeter Wemm 
953b4662009SGregory Neil Shapiro 	/* check if an error occurred */
954b4662009SGregory Neil Shapiro 	if (fp == NULL)
955b4662009SGregory Neil Shapiro 		return -1;
956b4662009SGregory Neil Shapiro 
957b4662009SGregory Neil Shapiro 	if (LMTPMode)
9583299c2f1SGregory Neil Shapiro 	{
959c2aa98e2SPeter Wemm 		/* Got a premature EOF -- toss message and exit */
960684b2a5fSGregory Neil Shapiro 		sm_exit(EX_OK);
961c2aa98e2SPeter Wemm 	}
962c2aa98e2SPeter Wemm 
963c2aa98e2SPeter Wemm 	/* If message not newline terminated, need an extra. */
964b4662009SGregory Neil Shapiro 	if (fp != NULL && strchr(line, '\n') == NULL)
965c2aa98e2SPeter Wemm 		(void) putc('\n', fp);
966c2aa98e2SPeter Wemm 
967c2aa98e2SPeter Wemm   lmtpdot:
968c2aa98e2SPeter Wemm 
9693299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
970b4662009SGregory Neil Shapiro 	if (fp != NULL)
9713299c2f1SGregory Neil Shapiro 		BodyLength = ftell(fp);
9723299c2f1SGregory Neil Shapiro 	if (HeaderLength == 0 && BodyLength > 0)	/* empty body */
9733299c2f1SGregory Neil Shapiro 	{
9743299c2f1SGregory Neil Shapiro 		HeaderLength = BodyLength;
9753299c2f1SGregory Neil Shapiro 		BodyLength = 0;
9763299c2f1SGregory Neil Shapiro 	}
9773299c2f1SGregory Neil Shapiro 	else
9783299c2f1SGregory Neil Shapiro 		BodyLength = BodyLength - HeaderLength - 1 ;
9793299c2f1SGregory Neil Shapiro 
9803299c2f1SGregory Neil Shapiro 	if (HeaderLength > 0 && BodyLength >= 0)
9813299c2f1SGregory Neil Shapiro 	{
98212ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(line, sizeof line, "%lld\n",
98312ed1c7cSGregory Neil Shapiro 				   (LONGLONG_T) BodyLength);
98412ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(&ContentHdr[16], line,
98512ed1c7cSGregory Neil Shapiro 				  sizeof(ContentHdr) - 16);
9863299c2f1SGregory Neil Shapiro 	}
9873299c2f1SGregory Neil Shapiro 	else
9883299c2f1SGregory Neil Shapiro 		BodyLength = -1;	/* Something is wrong here */
9893299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
9903299c2f1SGregory Neil Shapiro 
991c2aa98e2SPeter Wemm 	/* Output a newline; note, empty messages are allowed. */
992b4662009SGregory Neil Shapiro 	if (fp != NULL)
993c2aa98e2SPeter Wemm 		(void) putc('\n', fp);
994c2aa98e2SPeter Wemm 
995b4662009SGregory Neil Shapiro 	if (fp == NULL || fflush(fp) == EOF || ferror(fp) != 0)
9963299c2f1SGregory Neil Shapiro 	{
9972fb4f839SGregory Neil Shapiro 		mailerr("451 4.3.0", "Temporary file flush error");
998b4662009SGregory Neil Shapiro 		if (fp != NULL)
9993299c2f1SGregory Neil Shapiro 			(void) fclose(fp);
1000c2aa98e2SPeter Wemm 		return -1;
10013299c2f1SGregory Neil Shapiro 	}
10023299c2f1SGregory Neil Shapiro 	return fd;
1003c2aa98e2SPeter Wemm }
1004c2aa98e2SPeter Wemm 
1005c2aa98e2SPeter Wemm void
deliver(fd,name)1006b4662009SGregory Neil Shapiro deliver(fd, name)
1007c2aa98e2SPeter Wemm 	int fd;
1008c2aa98e2SPeter Wemm 	char *name;
1009c2aa98e2SPeter Wemm {
10103299c2f1SGregory Neil Shapiro 	struct stat fsb;
10113299c2f1SGregory Neil Shapiro 	struct stat sb;
10123299c2f1SGregory Neil Shapiro 	char path[MAXPATHLEN];
1013c46d91b7SGregory Neil Shapiro 	int mbfd = -1, nr = 0, nw, off;
101412ed1c7cSGregory Neil Shapiro 	int exitval;
1015c2aa98e2SPeter Wemm 	char *p;
1016b4662009SGregory Neil Shapiro 	char *errcode;
10177660b554SGregory Neil Shapiro 	off_t curoff, cursize;
10183299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
10193299c2f1SGregory Neil Shapiro 	off_t headerbytes;
10203299c2f1SGregory Neil Shapiro 	int readamount;
10215b0945b5SGregory Neil Shapiro #endif
10223299c2f1SGregory Neil Shapiro 	char biffmsg[100], buf[8 * 1024];
102312ed1c7cSGregory Neil Shapiro 	SM_MBDB_T user;
10243299c2f1SGregory Neil Shapiro 
1025c2aa98e2SPeter Wemm 	/*
10263299c2f1SGregory Neil Shapiro 	**  Disallow delivery to unknown names -- special mailboxes can be
10273299c2f1SGregory Neil Shapiro 	**  handled in the sendmail aliases file.
1028c2aa98e2SPeter Wemm 	*/
1029b4662009SGregory Neil Shapiro 
103012ed1c7cSGregory Neil Shapiro 	exitval = sm_mbdb_lookup(name, &user);
103112ed1c7cSGregory Neil Shapiro 	switch (exitval)
10323299c2f1SGregory Neil Shapiro 	{
103312ed1c7cSGregory Neil Shapiro 	  case EX_OK:
103412ed1c7cSGregory Neil Shapiro 		break;
103512ed1c7cSGregory Neil Shapiro 
103612ed1c7cSGregory Neil Shapiro 	  case EX_NOUSER:
103712ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
103812ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: User unknown", name);
103912ed1c7cSGregory Neil Shapiro 		break;
104012ed1c7cSGregory Neil Shapiro 
104112ed1c7cSGregory Neil Shapiro 	  case EX_TEMPFAIL:
104212ed1c7cSGregory Neil Shapiro 		mailerr("451 4.3.0", "%s: User database failure; retry later",
104312ed1c7cSGregory Neil Shapiro 			name);
104412ed1c7cSGregory Neil Shapiro 		break;
104512ed1c7cSGregory Neil Shapiro 
104612ed1c7cSGregory Neil Shapiro 	  default:
104712ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
104812ed1c7cSGregory Neil Shapiro 		mailerr("550 5.3.0", "%s: User database failure", name);
104912ed1c7cSGregory Neil Shapiro 		break;
1050c2aa98e2SPeter Wemm 	}
105112ed1c7cSGregory Neil Shapiro 
105212ed1c7cSGregory Neil Shapiro 	if (exitval != EX_OK)
105312ed1c7cSGregory Neil Shapiro 	{
105412ed1c7cSGregory Neil Shapiro 		if (ExitVal != EX_TEMPFAIL)
105512ed1c7cSGregory Neil Shapiro 			ExitVal = exitval;
1056c2aa98e2SPeter Wemm 		return;
1057c2aa98e2SPeter Wemm 	}
105812ed1c7cSGregory Neil Shapiro 
1059c2aa98e2SPeter Wemm 	endpwent();
1060c2aa98e2SPeter Wemm 
1061c2aa98e2SPeter Wemm 	/*
10623299c2f1SGregory Neil Shapiro 	**  Keep name reasonably short to avoid buffer overruns.
10633299c2f1SGregory Neil Shapiro 	**	This isn't necessary on BSD because of the proper
10643299c2f1SGregory Neil Shapiro 	**	definition of snprintf(), but it can cause problems
10653299c2f1SGregory Neil Shapiro 	**	on other systems.
10663299c2f1SGregory Neil Shapiro 	**  Also, clear out any bogus characters.
1067c2aa98e2SPeter Wemm 	*/
1068c2aa98e2SPeter Wemm 
1069bfb62e91SGregory Neil Shapiro #if !HASHSPOOL
1070c2aa98e2SPeter Wemm 	if (strlen(name) > 40)
1071c2aa98e2SPeter Wemm 		name[40] = '\0';
1072c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
1073c2aa98e2SPeter Wemm 	{
1074c2aa98e2SPeter Wemm 		if (!isascii(*p))
1075c2aa98e2SPeter Wemm 			*p &= 0x7f;
1076c2aa98e2SPeter Wemm 		else if (!isprint(*p))
1077c2aa98e2SPeter Wemm 			*p = '.';
1078c2aa98e2SPeter Wemm 	}
1079bfb62e91SGregory Neil Shapiro #endif /* !HASHSPOOL */
1080c2aa98e2SPeter Wemm 
10813299c2f1SGregory Neil Shapiro 
108212ed1c7cSGregory Neil Shapiro 	if (HomeMailFile == NULL)
108312ed1c7cSGregory Neil Shapiro 	{
1084bfb62e91SGregory Neil Shapiro 		if (sm_strlcpyn(path, sizeof(path),
1085bfb62e91SGregory Neil Shapiro #if HASHSPOOL
1086bfb62e91SGregory Neil Shapiro 				4,
10875b0945b5SGregory Neil Shapiro #else
1088bfb62e91SGregory Neil Shapiro 				3,
10895b0945b5SGregory Neil Shapiro #endif
1090bfb62e91SGregory Neil Shapiro 				SpoolPath, "/",
1091bfb62e91SGregory Neil Shapiro #if HASHSPOOL
1092bfb62e91SGregory Neil Shapiro 				hashname(name),
10935b0945b5SGregory Neil Shapiro #endif
1094bfb62e91SGregory Neil Shapiro 				name) >= sizeof(path))
109512ed1c7cSGregory Neil Shapiro 		{
109612ed1c7cSGregory Neil Shapiro 			exitval = EX_UNAVAILABLE;
109712ed1c7cSGregory Neil Shapiro 			mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
109812ed1c7cSGregory Neil Shapiro 			return;
109912ed1c7cSGregory Neil Shapiro 		}
110012ed1c7cSGregory Neil Shapiro 	}
110112ed1c7cSGregory Neil Shapiro 	else if (*user.mbdb_homedir == '\0')
110212ed1c7cSGregory Neil Shapiro 	{
110312ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
110412ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: User missing home directory", name);
110512ed1c7cSGregory Neil Shapiro 		return;
110612ed1c7cSGregory Neil Shapiro 	}
110712ed1c7cSGregory Neil Shapiro 	else if (sm_snprintf(path, sizeof(path), "%s/%s",
110812ed1c7cSGregory Neil Shapiro 			     user.mbdb_homedir, HomeMailFile) >= sizeof(path))
110912ed1c7cSGregory Neil Shapiro 	{
111012ed1c7cSGregory Neil Shapiro 		exitval = EX_UNAVAILABLE;
111112ed1c7cSGregory Neil Shapiro 		mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
111212ed1c7cSGregory Neil Shapiro 		return;
111312ed1c7cSGregory Neil Shapiro 	}
1114c2aa98e2SPeter Wemm 
11153299c2f1SGregory Neil Shapiro 
1116c2aa98e2SPeter Wemm 	/*
11173299c2f1SGregory Neil Shapiro 	**  If the mailbox is linked or a symlink, fail.  There's an obvious
11183299c2f1SGregory Neil Shapiro 	**  race here, that the file was replaced with a symbolic link after
11193299c2f1SGregory Neil Shapiro 	**  the lstat returned, but before the open.  We attempt to detect
11203299c2f1SGregory Neil Shapiro 	**  this by comparing the original stat information and information
11213299c2f1SGregory Neil Shapiro 	**  returned by an fstat of the file descriptor returned by the open.
11223299c2f1SGregory Neil Shapiro 	**
11233299c2f1SGregory Neil Shapiro 	**  NB: this is a symptom of a larger problem, that the mail spooling
11243299c2f1SGregory Neil Shapiro 	**  directory is writeable by the wrong users.  If that directory is
11253299c2f1SGregory Neil Shapiro 	**  writeable, system security is compromised for other reasons, and
11263299c2f1SGregory Neil Shapiro 	**  it cannot be fixed here.
11273299c2f1SGregory Neil Shapiro 	**
11283299c2f1SGregory Neil Shapiro 	**  If we created the mailbox, set the owner/group.  If that fails,
11293299c2f1SGregory Neil Shapiro 	**  just return.  Another process may have already opened it, so we
11303299c2f1SGregory Neil Shapiro 	**  can't unlink it.  Historically, binmail set the owner/group at
11313299c2f1SGregory Neil Shapiro 	**  each mail delivery.  We no longer do this, assuming that if the
11323299c2f1SGregory Neil Shapiro 	**  ownership or permissions were changed there was a reason.
11333299c2f1SGregory Neil Shapiro 	**
11343299c2f1SGregory Neil Shapiro 	**  XXX
11353299c2f1SGregory Neil Shapiro 	**  open(2) should support flock'ing the file.
1136c2aa98e2SPeter Wemm 	*/
11373299c2f1SGregory Neil Shapiro 
1138c2aa98e2SPeter Wemm tryagain:
11393299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
11403299c2f1SGregory Neil Shapiro 	p = name;
11415b0945b5SGregory Neil Shapiro #else
11423299c2f1SGregory Neil Shapiro 	p = path;
11435b0945b5SGregory Neil Shapiro #endif
11443299c2f1SGregory Neil Shapiro 	if ((off = lockmbox(p)) != 0)
11453299c2f1SGregory Neil Shapiro 	{
11463299c2f1SGregory Neil Shapiro 		if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
11473299c2f1SGregory Neil Shapiro 		{
11483299c2f1SGregory Neil Shapiro 			ExitVal = EX_TEMPFAIL;
1149b4662009SGregory Neil Shapiro 			errcode = "451 4.3.0";
11503299c2f1SGregory Neil Shapiro 		}
11513299c2f1SGregory Neil Shapiro 		else
1152b4662009SGregory Neil Shapiro 			errcode = "551 5.3.0";
1153b4662009SGregory Neil Shapiro 
1154b4662009SGregory Neil Shapiro 		mailerr(errcode, "lockmailbox %s failed; error code %d %s",
115512ed1c7cSGregory Neil Shapiro 			p, off, errno > 0 ? sm_errstring(errno) : "");
11563299c2f1SGregory Neil Shapiro 		return;
11573299c2f1SGregory Neil Shapiro 	}
11583299c2f1SGregory Neil Shapiro 
1159c2aa98e2SPeter Wemm 	if (lstat(path, &sb) < 0)
1160c2aa98e2SPeter Wemm 	{
11613299c2f1SGregory Neil Shapiro 		int save_errno;
11623299c2f1SGregory Neil Shapiro 		int mode = S_IRUSR|S_IWUSR;
116312ed1c7cSGregory Neil Shapiro 		gid_t gid = user.mbdb_gid;
11643299c2f1SGregory Neil Shapiro 
11653299c2f1SGregory Neil Shapiro #ifdef MAILGID
11663299c2f1SGregory Neil Shapiro 		(void) umask(0007);
11673299c2f1SGregory Neil Shapiro 		gid = MAILGID;
11683299c2f1SGregory Neil Shapiro 		mode |= S_IRGRP|S_IWGRP;
11695b0945b5SGregory Neil Shapiro #endif
11703299c2f1SGregory Neil Shapiro 
11717660b554SGregory Neil Shapiro 		mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY,
1172d995d2baSGregory Neil Shapiro 			    mode);
11733299c2f1SGregory Neil Shapiro 		save_errno = errno;
11743299c2f1SGregory Neil Shapiro 
11753299c2f1SGregory Neil Shapiro 		if (lstat(path, &sb) < 0)
11763299c2f1SGregory Neil Shapiro 		{
11773299c2f1SGregory Neil Shapiro 			ExitVal = EX_CANTCREAT;
117876b7bf71SPeter Wemm 			mailerr("550 5.2.0",
117976b7bf71SPeter Wemm 				"%s: lstat: file changed after open", path);
1180c2aa98e2SPeter Wemm 			goto err1;
1181c2aa98e2SPeter Wemm 		}
1182b4662009SGregory Neil Shapiro 		if (mbfd < 0)
11833299c2f1SGregory Neil Shapiro 		{
11843299c2f1SGregory Neil Shapiro 			if (save_errno == EEXIST)
1185c2aa98e2SPeter Wemm 				goto tryagain;
1186d995d2baSGregory Neil Shapiro 
1187d995d2baSGregory Neil Shapiro 			/* open failed, don't try again */
11882fb4f839SGregory Neil Shapiro 			mailerr("450 4.2.0", "Create %s: %s", path,
118912ed1c7cSGregory Neil Shapiro 				sm_errstring(save_errno));
1190d995d2baSGregory Neil Shapiro 			goto err0;
11913299c2f1SGregory Neil Shapiro 		}
119212ed1c7cSGregory Neil Shapiro 		else if (fchown(mbfd, user.mbdb_uid, gid) < 0)
11933299c2f1SGregory Neil Shapiro 		{
1194c2aa98e2SPeter Wemm 			mailerr("451 4.3.0", "chown %u.%u: %s",
119512ed1c7cSGregory Neil Shapiro 				user.mbdb_uid, gid, name);
1196c2aa98e2SPeter Wemm 			goto err1;
1197c2aa98e2SPeter Wemm 		}
1198d995d2baSGregory Neil Shapiro 		else
1199d995d2baSGregory Neil Shapiro 		{
1200d995d2baSGregory Neil Shapiro 			/*
1201d995d2baSGregory Neil Shapiro 			**  open() was successful, now close it so can
1202d995d2baSGregory Neil Shapiro 			**  be opened as the right owner again.
1203d995d2baSGregory Neil Shapiro 			**  Paranoia: reset mbdf since the file descriptor
1204d995d2baSGregory Neil Shapiro 			**  is no longer valid; better safe than sorry.
1205d995d2baSGregory Neil Shapiro 			*/
1206d995d2baSGregory Neil Shapiro 
120712ed1c7cSGregory Neil Shapiro 			sb.st_uid = user.mbdb_uid;
1208d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
1209d995d2baSGregory Neil Shapiro 			mbfd = -1;
1210d995d2baSGregory Neil Shapiro 		}
12113299c2f1SGregory Neil Shapiro 	}
1212f9218d3dSGregory Neil Shapiro 	else if (sb.st_nlink != 1)
1213f9218d3dSGregory Neil Shapiro 	{
1214f9218d3dSGregory Neil Shapiro 		mailerr("550 5.2.0", "%s: too many links", path);
1215f9218d3dSGregory Neil Shapiro 		goto err0;
1216f9218d3dSGregory Neil Shapiro 	}
1217f9218d3dSGregory Neil Shapiro 	else if (!S_ISREG(sb.st_mode))
12183299c2f1SGregory Neil Shapiro 	{
1219c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: irregular file", path);
1220c2aa98e2SPeter Wemm 		goto err0;
12213299c2f1SGregory Neil Shapiro 	}
122212ed1c7cSGregory Neil Shapiro 	else if (sb.st_uid != user.mbdb_uid)
12233299c2f1SGregory Neil Shapiro 	{
12243299c2f1SGregory Neil Shapiro 		ExitVal = EX_CANTCREAT;
1225c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: wrong ownership (%d)",
122612ed1c7cSGregory Neil Shapiro 			path, (int) sb.st_uid);
1227c2aa98e2SPeter Wemm 		goto err0;
1228c2aa98e2SPeter Wemm 	}
1229c2aa98e2SPeter Wemm 
1230d995d2baSGregory Neil Shapiro 	/* change UID for quota checks */
12312fb4f839SGregory Neil Shapiro 	if (
12322fb4f839SGregory Neil Shapiro #if MAIL_LOCAL_TEST
12332fb4f839SGregory Neil Shapiro 	    (HomeMailFile == NULL || user.mbdb_uid != getuid()) &&
12342fb4f839SGregory Neil Shapiro #endif
12352fb4f839SGregory Neil Shapiro 	    setreuid(0, user.mbdb_uid) < 0)
1236d995d2baSGregory Neil Shapiro 	{
1237d995d2baSGregory Neil Shapiro 		mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
123812ed1c7cSGregory Neil Shapiro 			(int) user.mbdb_uid, sm_errstring(errno),
123912ed1c7cSGregory Neil Shapiro 			(int) getuid(), (int) geteuid());
1240d995d2baSGregory Neil Shapiro 		goto err1;
1241d995d2baSGregory Neil Shapiro 	}
1242d995d2baSGregory Neil Shapiro #ifdef DEBUG
124312ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "new euid = %d\n", (int) geteuid());
12445b0945b5SGregory Neil Shapiro #endif
12457660b554SGregory Neil Shapiro 	mbfd = open(path, O_APPEND|O_WRONLY, 0);
1246d995d2baSGregory Neil Shapiro 	if (mbfd < 0)
12473299c2f1SGregory Neil Shapiro 	{
12482fb4f839SGregory Neil Shapiro 		mailerr("450 4.2.0", "Append %s: %s", path, sm_errstring(errno));
1249c2aa98e2SPeter Wemm 		goto err0;
12503299c2f1SGregory Neil Shapiro 	}
12513299c2f1SGregory Neil Shapiro 	else if (fstat(mbfd, &fsb) < 0 ||
1252c2aa98e2SPeter Wemm 		 fsb.st_nlink != 1 ||
1253c2aa98e2SPeter Wemm 		 sb.st_nlink != 1 ||
1254c2aa98e2SPeter Wemm 		 !S_ISREG(fsb.st_mode) ||
1255c2aa98e2SPeter Wemm 		 sb.st_dev != fsb.st_dev ||
1256c2aa98e2SPeter Wemm 		 sb.st_ino != fsb.st_ino ||
1257c2aa98e2SPeter Wemm #if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
1258c2aa98e2SPeter Wemm 		 sb.st_gen != fsb.st_gen ||
12595b0945b5SGregory Neil Shapiro #endif
12603299c2f1SGregory Neil Shapiro 		 sb.st_uid != fsb.st_uid)
12613299c2f1SGregory Neil Shapiro 	{
12623299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
126376b7bf71SPeter Wemm 		mailerr("550 5.2.0", "%s: fstat: file changed after open",
126476b7bf71SPeter Wemm 			path);
1265c2aa98e2SPeter Wemm 		goto err1;
1266c2aa98e2SPeter Wemm 	}
1267c2aa98e2SPeter Wemm 
126812ed1c7cSGregory Neil Shapiro #if 0
126912ed1c7cSGregory Neil Shapiro 	/*
127012ed1c7cSGregory Neil Shapiro 	**  This code could be reused if we decide to add a
127112ed1c7cSGregory Neil Shapiro 	**  per-user quota field to the sm_mbdb interface.
127212ed1c7cSGregory Neil Shapiro 	*/
127312ed1c7cSGregory Neil Shapiro 
127412ed1c7cSGregory Neil Shapiro 	/*
127512ed1c7cSGregory Neil Shapiro 	**  Fail if the user has a quota specified, and delivery of this
127612ed1c7cSGregory Neil Shapiro 	**  message would exceed that quota.  We bounce such failures using
127712ed1c7cSGregory Neil Shapiro 	**  EX_UNAVAILABLE, unless there were internal problems, since
127812ed1c7cSGregory Neil Shapiro 	**  storing immense messages for later retries can cause queueing
127912ed1c7cSGregory Neil Shapiro 	**  issues.
128012ed1c7cSGregory Neil Shapiro 	*/
128112ed1c7cSGregory Neil Shapiro 
128212ed1c7cSGregory Neil Shapiro 	if (ui.quota > 0)
128312ed1c7cSGregory Neil Shapiro 	{
128412ed1c7cSGregory Neil Shapiro 		struct stat dsb;
128512ed1c7cSGregory Neil Shapiro 
128612ed1c7cSGregory Neil Shapiro 		if (fstat(fd, &dsb) < 0)
128712ed1c7cSGregory Neil Shapiro 		{
128812ed1c7cSGregory Neil Shapiro 			ExitVal = EX_TEMPFAIL;
128912ed1c7cSGregory Neil Shapiro 			mailerr("451 4.3.0",
129012ed1c7cSGregory Neil Shapiro 				"%s: fstat: can't stat temporary storage: %s",
129112ed1c7cSGregory Neil Shapiro 				ui.mailspool, sm_errstring(errno));
129212ed1c7cSGregory Neil Shapiro 			goto err1;
129312ed1c7cSGregory Neil Shapiro 		}
129412ed1c7cSGregory Neil Shapiro 
129512ed1c7cSGregory Neil Shapiro 		if (dsb.st_size + sb.st_size + 1 > ui.quota)
129612ed1c7cSGregory Neil Shapiro 		{
129712ed1c7cSGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
129812ed1c7cSGregory Neil Shapiro 			mailerr("551 5.2.2",
129912ed1c7cSGregory Neil Shapiro 				"%s: Mailbox full or quota exceeded",
130012ed1c7cSGregory Neil Shapiro 				ui.mailspool);
130112ed1c7cSGregory Neil Shapiro 			goto err1;
130212ed1c7cSGregory Neil Shapiro 		}
130312ed1c7cSGregory Neil Shapiro 	}
130412ed1c7cSGregory Neil Shapiro #endif /* 0 */
13053299c2f1SGregory Neil Shapiro 
1306c2aa98e2SPeter Wemm 	/* Wait until we can get a lock on the file. */
13073299c2f1SGregory Neil Shapiro 	if (flock(mbfd, LOCK_EX) < 0)
13083299c2f1SGregory Neil Shapiro 	{
13092fb4f839SGregory Neil Shapiro 		mailerr("450 4.2.0", "Lock %s: %s", path, sm_errstring(errno));
1310c2aa98e2SPeter Wemm 		goto err1;
1311c2aa98e2SPeter Wemm 	}
1312c2aa98e2SPeter Wemm 
131372936242SGregory Neil Shapiro 	/* Get the starting offset of the new message */
1314c2aa98e2SPeter Wemm 	curoff = lseek(mbfd, (off_t) 0, SEEK_END);
1315518536daSGregory Neil Shapiro 
1316518536daSGregory Neil Shapiro 	if (!nobiff)
1317518536daSGregory Neil Shapiro 	{
131812ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(biffmsg, sizeof(biffmsg), "%s@%lld\n",
131912ed1c7cSGregory Neil Shapiro 				   name, (LONGLONG_T) curoff);
1320d615a192SPeter Wemm 	}
1321c2aa98e2SPeter Wemm 
1322c2aa98e2SPeter Wemm 	/* Copy the message into the file. */
13233299c2f1SGregory Neil Shapiro 	if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1)
13243299c2f1SGregory Neil Shapiro 	{
13252fb4f839SGregory Neil Shapiro 		mailerr("450 4.2.0", "Temporary file seek error: %s",
132612ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1327c2aa98e2SPeter Wemm 		goto err1;
1328c2aa98e2SPeter Wemm 	}
1329c2aa98e2SPeter Wemm #ifdef DEBUG
133012ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "before writing: euid = %d\n", (int) geteuid());
13315b0945b5SGregory Neil Shapiro #endif
13323299c2f1SGregory Neil Shapiro #ifdef CONTENTLENGTH
13333299c2f1SGregory Neil Shapiro 	headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
13343299c2f1SGregory Neil Shapiro 	for (;;)
13353299c2f1SGregory Neil Shapiro 	{
13363299c2f1SGregory Neil Shapiro 		if (headerbytes == 0)
13373299c2f1SGregory Neil Shapiro 		{
133812ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof buf, "%s", ContentHdr);
13393299c2f1SGregory Neil Shapiro 			nr = strlen(buf);
13403299c2f1SGregory Neil Shapiro 			headerbytes = -1;
13413299c2f1SGregory Neil Shapiro 			readamount = 0;
13423299c2f1SGregory Neil Shapiro 		}
13433299c2f1SGregory Neil Shapiro 		else if (headerbytes > sizeof(buf) || headerbytes < 0)
13443299c2f1SGregory Neil Shapiro 			readamount = sizeof(buf);
13453299c2f1SGregory Neil Shapiro 		else
13463299c2f1SGregory Neil Shapiro 			readamount = headerbytes;
13473299c2f1SGregory Neil Shapiro 		if (readamount != 0)
13483299c2f1SGregory Neil Shapiro 			nr = read(fd, buf, readamount);
13493299c2f1SGregory Neil Shapiro 		if (nr <= 0)
13503299c2f1SGregory Neil Shapiro 			break;
13513299c2f1SGregory Neil Shapiro 		if (headerbytes > 0)
13523299c2f1SGregory Neil Shapiro 			headerbytes -= nr ;
13533299c2f1SGregory Neil Shapiro 
13543299c2f1SGregory Neil Shapiro #else /* CONTENTLENGTH */
1355c2aa98e2SPeter Wemm 	while ((nr = read(fd, buf, sizeof(buf))) > 0)
13563299c2f1SGregory Neil Shapiro 	{
13573299c2f1SGregory Neil Shapiro #endif /* CONTENTLENGTH */
1358c2aa98e2SPeter Wemm 		for (off = 0; off < nr; off += nw)
13593299c2f1SGregory Neil Shapiro 		{
13603299c2f1SGregory Neil Shapiro 			if ((nw = write(mbfd, buf + off, nr - off)) < 0)
13613299c2f1SGregory Neil Shapiro 			{
1362b4662009SGregory Neil Shapiro 				errcode = "450 4.2.0";
13633299c2f1SGregory Neil Shapiro #ifdef EDQUOT
1364b4662009SGregory Neil Shapiro 				if (errno == EDQUOT && BounceQuota)
1365b4662009SGregory Neil Shapiro 					errcode = "552 5.2.2";
13665b0945b5SGregory Neil Shapiro #endif
13672fb4f839SGregory Neil Shapiro 				mailerr(errcode, "Write %s: %s",
136812ed1c7cSGregory Neil Shapiro 					path, sm_errstring(errno));
1369c2aa98e2SPeter Wemm 				goto err3;
1370c2aa98e2SPeter Wemm 			}
13713299c2f1SGregory Neil Shapiro 		}
13723299c2f1SGregory Neil Shapiro 	}
13733299c2f1SGregory Neil Shapiro 	if (nr < 0)
13743299c2f1SGregory Neil Shapiro 	{
13752fb4f839SGregory Neil Shapiro 		mailerr("450 4.2.0", "Temporary file read error: %s",
137612ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1377c2aa98e2SPeter Wemm 		goto err3;
1378c2aa98e2SPeter Wemm 	}
1379c2aa98e2SPeter Wemm 
1380c2aa98e2SPeter Wemm 	/* Flush to disk, don't wait for update. */
13813299c2f1SGregory Neil Shapiro 	if (!nofsync && fsync(mbfd) < 0)
13823299c2f1SGregory Neil Shapiro 	{
13832fb4f839SGregory Neil Shapiro 		mailerr("450 4.2.0", "Sync %s: %s", path, sm_errstring(errno));
1384c2aa98e2SPeter Wemm err3:
1385c2aa98e2SPeter Wemm #ifdef DEBUG
138612ed1c7cSGregory Neil Shapiro 		fprintf(stderr, "reset euid = %d\n", (int) geteuid());
13875b0945b5SGregory Neil Shapiro #endif
13882ef40764SGregory Neil Shapiro 		if (mbfd >= 0)
1389c2aa98e2SPeter Wemm 			(void) ftruncate(mbfd, curoff);
1390d995d2baSGregory Neil Shapiro err1:		if (mbfd >= 0)
1391d995d2baSGregory Neil Shapiro 			(void) close(mbfd);
13922fb4f839SGregory Neil Shapiro err0:
13932fb4f839SGregory Neil Shapiro #if MAIL_LOCAL_TEST
13942fb4f839SGregory Neil Shapiro 		if (HomeMailFile == NULL || user.mbdb_uid != getuid())
13952fb4f839SGregory Neil Shapiro #endif
13962fb4f839SGregory Neil Shapiro 		(void) setreuid(0, 0);
13977660b554SGregory Neil Shapiro 		unlockmbox();
1398c2aa98e2SPeter Wemm 		return;
1399c2aa98e2SPeter Wemm 	}
1400c2aa98e2SPeter Wemm 
14017660b554SGregory Neil Shapiro 	/*
14027660b554SGregory Neil Shapiro 	**  Save the current size so if the close() fails below
14037660b554SGregory Neil Shapiro 	**  we can make sure no other process has changed the mailbox
14047660b554SGregory Neil Shapiro 	**  between the failed close and the re-open()/re-lock().
14057660b554SGregory Neil Shapiro 	**  If something else has changed the size, we shouldn't
14067660b554SGregory Neil Shapiro 	**  try to truncate it as we may do more harm then good
14077660b554SGregory Neil Shapiro 	**  (e.g., truncate a later message delivery).
14087660b554SGregory Neil Shapiro 	*/
14097660b554SGregory Neil Shapiro 
14107660b554SGregory Neil Shapiro 	if (fstat(mbfd, &sb) < 0)
14117660b554SGregory Neil Shapiro 		cursize = 0;
14127660b554SGregory Neil Shapiro 	else
14137660b554SGregory Neil Shapiro 		cursize = sb.st_size;
14147660b554SGregory Neil Shapiro 
14157660b554SGregory Neil Shapiro 
1416c2aa98e2SPeter Wemm 	/* Close and check -- NFS doesn't write until the close. */
14173299c2f1SGregory Neil Shapiro 	if (close(mbfd))
14183299c2f1SGregory Neil Shapiro 	{
1419b4662009SGregory Neil Shapiro 		errcode = "450 4.2.0";
14203299c2f1SGregory Neil Shapiro #ifdef EDQUOT
1421b4662009SGregory Neil Shapiro 		if (errno == EDQUOT && BounceQuota)
1422b4662009SGregory Neil Shapiro 			errcode = "552 5.2.2";
14235b0945b5SGregory Neil Shapiro #endif
14242fb4f839SGregory Neil Shapiro 		mailerr(errcode, "Close %s: %s", path, sm_errstring(errno));
14257660b554SGregory Neil Shapiro 		mbfd = open(path, O_WRONLY, 0);
14267660b554SGregory Neil Shapiro 		if (mbfd < 0 ||
14277660b554SGregory Neil Shapiro 		    cursize == 0
14287660b554SGregory Neil Shapiro 		    || flock(mbfd, LOCK_EX) < 0 ||
14297660b554SGregory Neil Shapiro 		    fstat(mbfd, &sb) < 0 ||
14307660b554SGregory Neil Shapiro 		    sb.st_size != cursize ||
14312ef40764SGregory Neil Shapiro 		    sb.st_nlink != 1 ||
14322ef40764SGregory Neil Shapiro 		    !S_ISREG(sb.st_mode) ||
14332ef40764SGregory Neil Shapiro 		    sb.st_dev != fsb.st_dev ||
14342ef40764SGregory Neil Shapiro 		    sb.st_ino != fsb.st_ino ||
14352ef40764SGregory Neil Shapiro #if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
14362ef40764SGregory Neil Shapiro 		    sb.st_gen != fsb.st_gen ||
14375b0945b5SGregory Neil Shapiro #endif
14382ef40764SGregory Neil Shapiro 		    sb.st_uid != fsb.st_uid
14392ef40764SGregory Neil Shapiro 		   )
14402ef40764SGregory Neil Shapiro 		{
14412ef40764SGregory Neil Shapiro 			/* Don't use a bogus file */
14422ef40764SGregory Neil Shapiro 			if (mbfd >= 0)
14432ef40764SGregory Neil Shapiro 			{
14442ef40764SGregory Neil Shapiro 				(void) close(mbfd);
14452ef40764SGregory Neil Shapiro 				mbfd = -1;
14462ef40764SGregory Neil Shapiro 			}
14472ef40764SGregory Neil Shapiro 		}
14482ef40764SGregory Neil Shapiro 
14492ef40764SGregory Neil Shapiro 		/* Attempt to truncate back to pre-write size */
14502ef40764SGregory Neil Shapiro 		goto err3;
14513299c2f1SGregory Neil Shapiro 	}
14523299c2f1SGregory Neil Shapiro 	else if (!nobiff)
1453c2aa98e2SPeter Wemm 		notifybiff(biffmsg);
1454c2aa98e2SPeter Wemm 
14552fb4f839SGregory Neil Shapiro 	if (
14562fb4f839SGregory Neil Shapiro #if MAIL_LOCAL_TEST
14572fb4f839SGregory Neil Shapiro 	    (HomeMailFile == NULL || user.mbdb_uid != getuid()) &&
14582fb4f839SGregory Neil Shapiro #endif
14592fb4f839SGregory Neil Shapiro 	    setreuid(0, 0) < 0)
14603299c2f1SGregory Neil Shapiro 	{
1461c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "setreuid(0, 0): %s",
146212ed1c7cSGregory Neil Shapiro 			sm_errstring(errno));
1463c2aa98e2SPeter Wemm 		goto err0;
1464c2aa98e2SPeter Wemm 	}
1465c2aa98e2SPeter Wemm #ifdef DEBUG
146612ed1c7cSGregory Neil Shapiro 	fprintf(stderr, "reset euid = %d\n", (int) geteuid());
14675b0945b5SGregory Neil Shapiro #endif
1468c2aa98e2SPeter Wemm 	unlockmbox();
14693299c2f1SGregory Neil Shapiro 	if (LMTPMode)
1470b4662009SGregory Neil Shapiro 		printf("250 2.1.5 %s Ok\r\n", name);
1471c2aa98e2SPeter Wemm }
1472c2aa98e2SPeter Wemm 
1473c2aa98e2SPeter Wemm /*
14743299c2f1SGregory Neil Shapiro **  user.lock files are necessary for compatibility with other
14753299c2f1SGregory Neil Shapiro **  systems, e.g., when the mail spool file is NFS exported.
14763299c2f1SGregory Neil Shapiro **  Alas, mailbox locking is more than just a local matter.
14773299c2f1SGregory Neil Shapiro **  EPA 11/94.
1478c2aa98e2SPeter Wemm */
1479c2aa98e2SPeter Wemm 
148012ed1c7cSGregory Neil Shapiro bool	Locked = false;
14813299c2f1SGregory Neil Shapiro 
14823299c2f1SGregory Neil Shapiro #ifdef MAILLOCK
14833299c2f1SGregory Neil Shapiro int
lockmbox(name)14843299c2f1SGregory Neil Shapiro lockmbox(name)
14853299c2f1SGregory Neil Shapiro 	char *name;
14863299c2f1SGregory Neil Shapiro {
1487d995d2baSGregory Neil Shapiro 	int r = 0;
14883299c2f1SGregory Neil Shapiro 
14893299c2f1SGregory Neil Shapiro 	if (Locked)
14903299c2f1SGregory Neil Shapiro 		return 0;
14913299c2f1SGregory Neil Shapiro 	if ((r = maillock(name, 15)) == L_SUCCESS)
14923299c2f1SGregory Neil Shapiro 	{
149312ed1c7cSGregory Neil Shapiro 		Locked = true;
14943299c2f1SGregory Neil Shapiro 		return 0;
14953299c2f1SGregory Neil Shapiro 	}
14963299c2f1SGregory Neil Shapiro 	switch (r)
14973299c2f1SGregory Neil Shapiro 	{
14983299c2f1SGregory Neil Shapiro 	  case L_TMPLOCK:	/* Can't create tmp file */
14993299c2f1SGregory Neil Shapiro 	  case L_TMPWRITE:	/* Can't write pid into lockfile */
15003299c2f1SGregory Neil Shapiro 	  case L_MAXTRYS:	/* Failed after retrycnt attempts */
15013299c2f1SGregory Neil Shapiro 		errno = 0;
15023299c2f1SGregory Neil Shapiro 		r = EX_TEMPFAIL;
15033299c2f1SGregory Neil Shapiro 		break;
15043299c2f1SGregory Neil Shapiro 	  case L_ERROR:		/* Check errno for reason */
15053299c2f1SGregory Neil Shapiro 		r = errno;
15063299c2f1SGregory Neil Shapiro 		break;
15073299c2f1SGregory Neil Shapiro 	  default:		/* other permanent errors */
15083299c2f1SGregory Neil Shapiro 		errno = 0;
15093299c2f1SGregory Neil Shapiro 		r = EX_UNAVAILABLE;
15103299c2f1SGregory Neil Shapiro 		break;
15113299c2f1SGregory Neil Shapiro 	}
15123299c2f1SGregory Neil Shapiro 	return r;
15133299c2f1SGregory Neil Shapiro }
1514c2aa98e2SPeter Wemm 
1515c2aa98e2SPeter Wemm void
unlockmbox()15163299c2f1SGregory Neil Shapiro unlockmbox()
15173299c2f1SGregory Neil Shapiro {
15183299c2f1SGregory Neil Shapiro 	if (Locked)
15193299c2f1SGregory Neil Shapiro 		mailunlock();
152012ed1c7cSGregory Neil Shapiro 	Locked = false;
15213299c2f1SGregory Neil Shapiro }
15223299c2f1SGregory Neil Shapiro #else /* MAILLOCK */
15233299c2f1SGregory Neil Shapiro 
15243299c2f1SGregory Neil Shapiro char	LockName[MAXPATHLEN];
15253299c2f1SGregory Neil Shapiro 
15263299c2f1SGregory Neil Shapiro int
lockmbox(path)1527c2aa98e2SPeter Wemm lockmbox(path)
1528c2aa98e2SPeter Wemm 	char *path;
1529c2aa98e2SPeter Wemm {
1530c2aa98e2SPeter Wemm 	int statfailed = 0;
15313299c2f1SGregory Neil Shapiro 	time_t start;
1532c2aa98e2SPeter Wemm 
15333299c2f1SGregory Neil Shapiro 	if (Locked)
15343299c2f1SGregory Neil Shapiro 		return 0;
15353299c2f1SGregory Neil Shapiro 	if (strlen(path) + 6 > sizeof LockName)
15363299c2f1SGregory Neil Shapiro 		return EX_SOFTWARE;
153712ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(LockName, sizeof LockName, "%s.lock", path);
15383299c2f1SGregory Neil Shapiro 	(void) time(&start);
15393299c2f1SGregory Neil Shapiro 	for (; ; sleep(5))
15403299c2f1SGregory Neil Shapiro 	{
1541c2aa98e2SPeter Wemm 		int fd;
1542c2aa98e2SPeter Wemm 		struct stat st;
1543c2aa98e2SPeter Wemm 		time_t now;
1544c2aa98e2SPeter Wemm 
15453299c2f1SGregory Neil Shapiro 		/* global timeout */
15463299c2f1SGregory Neil Shapiro 		(void) time(&now);
15473299c2f1SGregory Neil Shapiro 		if (now > start + LOCKTO_GLOB)
15483299c2f1SGregory Neil Shapiro 		{
15493299c2f1SGregory Neil Shapiro 			errno = 0;
15503299c2f1SGregory Neil Shapiro 			return EX_TEMPFAIL;
1551c2aa98e2SPeter Wemm 		}
15527660b554SGregory Neil Shapiro 		fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, LOCKFILE_PMODE);
15533299c2f1SGregory Neil Shapiro 		if (fd >= 0)
15543299c2f1SGregory Neil Shapiro 		{
15553299c2f1SGregory Neil Shapiro 			/* defeat lock checking programs which test pid */
15563299c2f1SGregory Neil Shapiro 			(void) write(fd, "0", 2);
155712ed1c7cSGregory Neil Shapiro 			Locked = true;
15583299c2f1SGregory Neil Shapiro 			(void) close(fd);
15593299c2f1SGregory Neil Shapiro 			return 0;
15603299c2f1SGregory Neil Shapiro 		}
15613299c2f1SGregory Neil Shapiro 		if (stat(LockName, &st) < 0)
15623299c2f1SGregory Neil Shapiro 		{
1563c2aa98e2SPeter Wemm 			if (statfailed++ > 5)
15643299c2f1SGregory Neil Shapiro 			{
15653299c2f1SGregory Neil Shapiro 				errno = 0;
15663299c2f1SGregory Neil Shapiro 				return EX_TEMPFAIL;
15673299c2f1SGregory Neil Shapiro 			}
1568c2aa98e2SPeter Wemm 			continue;
1569c2aa98e2SPeter Wemm 		}
1570c2aa98e2SPeter Wemm 		statfailed = 0;
15713299c2f1SGregory Neil Shapiro 		(void) time(&now);
15723299c2f1SGregory Neil Shapiro 		if (now < st.st_ctime + LOCKTO_RM)
1573c2aa98e2SPeter Wemm 			continue;
15743299c2f1SGregory Neil Shapiro 
15753299c2f1SGregory Neil Shapiro 		/* try to remove stale lockfile */
15763299c2f1SGregory Neil Shapiro 		if (unlink(LockName) < 0)
15773299c2f1SGregory Neil Shapiro 			return errno;
1578c2aa98e2SPeter Wemm 	}
1579c2aa98e2SPeter Wemm }
1580c2aa98e2SPeter Wemm 
1581c2aa98e2SPeter Wemm void
unlockmbox()1582c2aa98e2SPeter Wemm unlockmbox()
1583c2aa98e2SPeter Wemm {
15843299c2f1SGregory Neil Shapiro 	if (!Locked)
1585c2aa98e2SPeter Wemm 		return;
15863299c2f1SGregory Neil Shapiro 	(void) unlink(LockName);
158712ed1c7cSGregory Neil Shapiro 	Locked = false;
1588c2aa98e2SPeter Wemm }
15893299c2f1SGregory Neil Shapiro #endif /* MAILLOCK */
1590c2aa98e2SPeter Wemm 
1591c2aa98e2SPeter Wemm void
notifybiff(msg)1592c2aa98e2SPeter Wemm notifybiff(msg)
1593c2aa98e2SPeter Wemm 	char *msg;
1594c2aa98e2SPeter Wemm {
159512ed1c7cSGregory Neil Shapiro 	static bool initialized = false;
1596c2aa98e2SPeter Wemm 	static int f = -1;
1597c2aa98e2SPeter Wemm 	struct hostent *hp;
1598c2aa98e2SPeter Wemm 	struct servent *sp;
1599c2aa98e2SPeter Wemm 	int len;
16003299c2f1SGregory Neil Shapiro 	static struct sockaddr_in addr;
1601c2aa98e2SPeter Wemm 
16023299c2f1SGregory Neil Shapiro 	if (!initialized)
16033299c2f1SGregory Neil Shapiro 	{
160412ed1c7cSGregory Neil Shapiro 		initialized = true;
16053299c2f1SGregory Neil Shapiro 
1606c2aa98e2SPeter Wemm 		/* Be silent if biff service not available. */
16073299c2f1SGregory Neil Shapiro 		if ((sp = getservbyname("biff", "udp")) == NULL ||
16083299c2f1SGregory Neil Shapiro 		    (hp = gethostbyname("localhost")) == NULL ||
16093299c2f1SGregory Neil Shapiro 		    hp->h_length != INADDRSZ)
1610c2aa98e2SPeter Wemm 			return;
16113299c2f1SGregory Neil Shapiro 
1612c2aa98e2SPeter Wemm 		addr.sin_family = hp->h_addrtype;
16133299c2f1SGregory Neil Shapiro 		memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ);
1614c2aa98e2SPeter Wemm 		addr.sin_port = sp->s_port;
1615c2aa98e2SPeter Wemm 	}
16163299c2f1SGregory Neil Shapiro 
16173299c2f1SGregory Neil Shapiro 	/* No message, just return */
16183299c2f1SGregory Neil Shapiro 	if (msg == NULL)
1619c2aa98e2SPeter Wemm 		return;
16203299c2f1SGregory Neil Shapiro 
16213299c2f1SGregory Neil Shapiro 	/* Couldn't initialize addr struct */
16223299c2f1SGregory Neil Shapiro 	if (addr.sin_family == AF_UNSPEC)
16233299c2f1SGregory Neil Shapiro 		return;
16243299c2f1SGregory Neil Shapiro 
1625b4662009SGregory Neil Shapiro 	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
16263299c2f1SGregory Neil Shapiro 		return;
1627c2aa98e2SPeter Wemm 	len = strlen(msg) + 1;
162876b7bf71SPeter Wemm 	(void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr));
1629c2aa98e2SPeter Wemm }
1630c2aa98e2SPeter Wemm 
1631c2aa98e2SPeter Wemm void
usage()1632c2aa98e2SPeter Wemm usage()
1633c2aa98e2SPeter Wemm {
16343299c2f1SGregory Neil Shapiro 	ExitVal = EX_USAGE;
16352fb4f839SGregory Neil Shapiro 	/* XXX add U to options for USE_EAI */
1636e3793f76SGregory Neil Shapiro #if _FFR_SPOOL_PATH
1637e3793f76SGregory Neil Shapiro 	mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-d] [-l] [-s] [-f from|-r from] [-h filename] [-p path] user ...");
16385b0945b5SGregory Neil Shapiro #else
163912ed1c7cSGregory Neil Shapiro 	mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-d] [-l] [-s] [-f from|-r from] [-h filename] user ...");
16405b0945b5SGregory Neil Shapiro #endif
1641684b2a5fSGregory Neil Shapiro 	sm_exit(ExitVal);
1642c2aa98e2SPeter Wemm }
1643c2aa98e2SPeter Wemm 
1644c2aa98e2SPeter Wemm void
164512ed1c7cSGregory Neil Shapiro /*VARARGS2*/
1646c2aa98e2SPeter Wemm #ifdef __STDC__
mailerr(const char * hdr,const char * fmt,...)1647c2aa98e2SPeter Wemm mailerr(const char *hdr, const char *fmt, ...)
16483299c2f1SGregory Neil Shapiro #else /* __STDC__ */
1649c2aa98e2SPeter Wemm mailerr(hdr, fmt, va_alist)
1650c2aa98e2SPeter Wemm 	const char *hdr;
1651c2aa98e2SPeter Wemm 	const char *fmt;
1652c2aa98e2SPeter Wemm 	va_dcl
16533299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
1654c2aa98e2SPeter Wemm {
1655b4662009SGregory Neil Shapiro 	size_t len = 0;
165612ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
1657c2aa98e2SPeter Wemm 
1658b4662009SGregory Neil Shapiro 	(void) e_to_sys(errno);
1659b4662009SGregory Neil Shapiro 
166012ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
1661b4662009SGregory Neil Shapiro 
166212ed1c7cSGregory Neil Shapiro 	if (LMTPMode && hdr != NULL)
1663c2aa98e2SPeter Wemm 	{
166412ed1c7cSGregory Neil Shapiro 		sm_snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr);
1665b4662009SGregory Neil Shapiro 		len = strlen(ErrBuf);
1666c2aa98e2SPeter Wemm 	}
166712ed1c7cSGregory Neil Shapiro 	(void) sm_vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap);
166812ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
1669b4662009SGregory Neil Shapiro 
1670b4662009SGregory Neil Shapiro 	if (!HoldErrs)
1671b4662009SGregory Neil Shapiro 		flush_error();
1672b4662009SGregory Neil Shapiro 
1673b4662009SGregory Neil Shapiro 	/* Log the message to syslog. */
1674b4662009SGregory Neil Shapiro 	if (!LMTPMode)
1675b4662009SGregory Neil Shapiro 		syslog(LOG_ERR, "%s", ErrBuf);
1676b4662009SGregory Neil Shapiro }
1677c2aa98e2SPeter Wemm 
1678c2aa98e2SPeter Wemm void
flush_error()1679b4662009SGregory Neil Shapiro flush_error()
1680c2aa98e2SPeter Wemm {
1681b4662009SGregory Neil Shapiro 	if (LMTPMode)
1682b4662009SGregory Neil Shapiro 		printf("%s\r\n", ErrBuf);
1683b4662009SGregory Neil Shapiro 	else
1684b4662009SGregory Neil Shapiro 	{
16853299c2f1SGregory Neil Shapiro 		if (ExitVal != EX_USAGE)
1686c2aa98e2SPeter Wemm 			(void) fprintf(stderr, "mail.local: ");
1687b4662009SGregory Neil Shapiro 		fprintf(stderr, "%s\n", ErrBuf);
1688c2aa98e2SPeter Wemm 	}
1689c2aa98e2SPeter Wemm }
1690c2aa98e2SPeter Wemm 
1691bfb62e91SGregory Neil Shapiro #if HASHSPOOL
1692bfb62e91SGregory Neil Shapiro const char *
hashname(name)1693bfb62e91SGregory Neil Shapiro hashname(name)
1694bfb62e91SGregory Neil Shapiro 	char *name;
1695bfb62e91SGregory Neil Shapiro {
1696bfb62e91SGregory Neil Shapiro 	static char p[MAXPATHLEN];
1697bfb62e91SGregory Neil Shapiro 	int i;
1698bfb62e91SGregory Neil Shapiro 	int len;
1699bfb62e91SGregory Neil Shapiro 	char *str;
1700bfb62e91SGregory Neil Shapiro # if HASHSPOOLMD5
1701bfb62e91SGregory Neil Shapiro 	char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_";
1702bfb62e91SGregory Neil Shapiro 	MD5_CTX ctx;
1703bfb62e91SGregory Neil Shapiro 	unsigned char md5[18];
1704bfb62e91SGregory Neil Shapiro #  if MAXPATHLEN <= 24
1705*d39bd2c1SGregory Neil Shapiro #    error "MAXPATHLEN <= 24"
17065b0945b5SGregory Neil Shapiro #  endif
1707bfb62e91SGregory Neil Shapiro 	char b64[24];
1708bfb62e91SGregory Neil Shapiro 	MD5_LONG bits;
1709bfb62e91SGregory Neil Shapiro 	int j;
1710bfb62e91SGregory Neil Shapiro # endif /* HASHSPOOLMD5 */
1711bfb62e91SGregory Neil Shapiro 
1712bfb62e91SGregory Neil Shapiro 	if (HashType == HASH_NONE || HashDepth * 2 >= MAXPATHLEN)
1713bfb62e91SGregory Neil Shapiro 	{
1714bfb62e91SGregory Neil Shapiro 		p[0] = '\0';
1715bfb62e91SGregory Neil Shapiro 		return p;
1716bfb62e91SGregory Neil Shapiro 	}
1717bfb62e91SGregory Neil Shapiro 
1718bfb62e91SGregory Neil Shapiro 	switch(HashType)
1719bfb62e91SGregory Neil Shapiro 	{
1720bfb62e91SGregory Neil Shapiro 	  case HASH_USER:
1721bfb62e91SGregory Neil Shapiro 		str = name;
1722bfb62e91SGregory Neil Shapiro 		break;
1723bfb62e91SGregory Neil Shapiro 
1724bfb62e91SGregory Neil Shapiro # if HASHSPOOLMD5
1725bfb62e91SGregory Neil Shapiro 	  case HASH_MD5:
1726bfb62e91SGregory Neil Shapiro 		MD5_Init(&ctx);
1727bfb62e91SGregory Neil Shapiro 		MD5_Update(&ctx, name, strlen(name));
1728bfb62e91SGregory Neil Shapiro 		MD5_Final(md5, &ctx);
1729bfb62e91SGregory Neil Shapiro 		md5[16] = 0;
1730bfb62e91SGregory Neil Shapiro 		md5[17] = 0;
1731bfb62e91SGregory Neil Shapiro 
1732bfb62e91SGregory Neil Shapiro 		for (i = 0; i < 6; i++)
1733bfb62e91SGregory Neil Shapiro 		{
1734bfb62e91SGregory Neil Shapiro 			bits = (unsigned) md5[(3 * i)] << 16;
1735bfb62e91SGregory Neil Shapiro 			bits |= (unsigned) md5[(3 * i) + 1] << 8;
1736bfb62e91SGregory Neil Shapiro 			bits |= (unsigned) md5[(3 * i) + 2];
1737bfb62e91SGregory Neil Shapiro 
1738bfb62e91SGregory Neil Shapiro 			for (j = 3; j >= 0; j--)
1739bfb62e91SGregory Neil Shapiro 			{
1740bfb62e91SGregory Neil Shapiro 				b64[(4 * i) + j] = Base64[(bits & 0x3f)];
1741bfb62e91SGregory Neil Shapiro 				bits >>= 6;
1742bfb62e91SGregory Neil Shapiro 			}
1743bfb62e91SGregory Neil Shapiro 		}
1744bfb62e91SGregory Neil Shapiro 		b64[22] = '\0';
1745bfb62e91SGregory Neil Shapiro 		str = b64;
1746bfb62e91SGregory Neil Shapiro 		break;
1747bfb62e91SGregory Neil Shapiro # endif /* HASHSPOOLMD5 */
1748bfb62e91SGregory Neil Shapiro 	}
1749bfb62e91SGregory Neil Shapiro 
1750bfb62e91SGregory Neil Shapiro 	len = strlen(str);
1751bfb62e91SGregory Neil Shapiro 	for (i = 0; i < HashDepth; i++)
1752bfb62e91SGregory Neil Shapiro 	{
1753bfb62e91SGregory Neil Shapiro 		if (i < len)
1754bfb62e91SGregory Neil Shapiro 			p[i * 2] = str[i];
1755bfb62e91SGregory Neil Shapiro 		else
1756bfb62e91SGregory Neil Shapiro 			p[i * 2] = '_';
1757bfb62e91SGregory Neil Shapiro 		p[(i * 2) + 1] = '/';
1758bfb62e91SGregory Neil Shapiro 	}
1759bfb62e91SGregory Neil Shapiro 	p[HashDepth * 2] = '\0';
1760bfb62e91SGregory Neil Shapiro 	return p;
1761bfb62e91SGregory Neil Shapiro }
1762bfb62e91SGregory Neil Shapiro #endif /* HASHSPOOL */
1763bfb62e91SGregory Neil Shapiro 
1764c2aa98e2SPeter Wemm /*
1765c2aa98e2SPeter Wemm  * e_to_sys --
1766c2aa98e2SPeter Wemm  *	Guess which errno's are temporary.  Gag me.
1767c2aa98e2SPeter Wemm  */
1768b4662009SGregory Neil Shapiro 
17693299c2f1SGregory Neil Shapiro int
e_to_sys(num)1770c2aa98e2SPeter Wemm e_to_sys(num)
1771c2aa98e2SPeter Wemm 	int num;
1772c2aa98e2SPeter Wemm {
1773c2aa98e2SPeter Wemm 	/* Temporary failures override hard errors. */
17743299c2f1SGregory Neil Shapiro 	if (ExitVal == EX_TEMPFAIL)
17753299c2f1SGregory Neil Shapiro 		return ExitVal;
1776c2aa98e2SPeter Wemm 
17773299c2f1SGregory Neil Shapiro 	switch (num)		/* Hopefully temporary errors. */
17783299c2f1SGregory Neil Shapiro 	{
1779c2aa98e2SPeter Wemm #ifdef EDQUOT
1780c2aa98e2SPeter Wemm 	  case EDQUOT:		/* Disc quota exceeded */
1781b4662009SGregory Neil Shapiro 		if (BounceQuota)
17823299c2f1SGregory Neil Shapiro 		{
17833299c2f1SGregory Neil Shapiro 			ExitVal = EX_UNAVAILABLE;
17843299c2f1SGregory Neil Shapiro 			break;
17853299c2f1SGregory Neil Shapiro 		}
17863299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
17873299c2f1SGregory Neil Shapiro #endif /* EDQUOT */
17883299c2f1SGregory Neil Shapiro #ifdef EAGAIN
17893299c2f1SGregory Neil Shapiro 	  case EAGAIN:		/* Resource temporarily unavailable */
17905b0945b5SGregory Neil Shapiro #endif
1791c2aa98e2SPeter Wemm #ifdef EBUSY
1792c2aa98e2SPeter Wemm 	  case EBUSY:		/* Device busy */
17935b0945b5SGregory Neil Shapiro #endif
1794c2aa98e2SPeter Wemm #ifdef EPROCLIM
1795c2aa98e2SPeter Wemm 	  case EPROCLIM:	/* Too many processes */
17965b0945b5SGregory Neil Shapiro #endif
1797c2aa98e2SPeter Wemm #ifdef EUSERS
1798c2aa98e2SPeter Wemm 	  case EUSERS:		/* Too many users */
17995b0945b5SGregory Neil Shapiro #endif
1800c2aa98e2SPeter Wemm #ifdef ECONNABORTED
1801c2aa98e2SPeter Wemm 	  case ECONNABORTED:	/* Software caused connection abort */
18025b0945b5SGregory Neil Shapiro #endif
1803c2aa98e2SPeter Wemm #ifdef ECONNREFUSED
1804c2aa98e2SPeter Wemm 	  case ECONNREFUSED:	/* Connection refused */
18055b0945b5SGregory Neil Shapiro #endif
1806c2aa98e2SPeter Wemm #ifdef ECONNRESET
1807c2aa98e2SPeter Wemm 	  case ECONNRESET:	/* Connection reset by peer */
18085b0945b5SGregory Neil Shapiro #endif
1809c2aa98e2SPeter Wemm #ifdef EDEADLK
1810c2aa98e2SPeter Wemm 	  case EDEADLK:		/* Resource deadlock avoided */
18115b0945b5SGregory Neil Shapiro #endif
1812c2aa98e2SPeter Wemm #ifdef EFBIG
1813c2aa98e2SPeter Wemm 	  case EFBIG:		/* File too large */
18145b0945b5SGregory Neil Shapiro #endif
1815c2aa98e2SPeter Wemm #ifdef EHOSTDOWN
1816c2aa98e2SPeter Wemm 	  case EHOSTDOWN:	/* Host is down */
18175b0945b5SGregory Neil Shapiro #endif
1818c2aa98e2SPeter Wemm #ifdef EHOSTUNREACH
1819c2aa98e2SPeter Wemm 	  case EHOSTUNREACH:	/* No route to host */
18205b0945b5SGregory Neil Shapiro #endif
1821c2aa98e2SPeter Wemm #ifdef EMFILE
1822c2aa98e2SPeter Wemm 	  case EMFILE:		/* Too many open files */
18235b0945b5SGregory Neil Shapiro #endif
1824c2aa98e2SPeter Wemm #ifdef ENETDOWN
1825c2aa98e2SPeter Wemm 	  case ENETDOWN:	/* Network is down */
18265b0945b5SGregory Neil Shapiro #endif
1827c2aa98e2SPeter Wemm #ifdef ENETRESET
1828c2aa98e2SPeter Wemm 	  case ENETRESET:	/* Network dropped connection on reset */
18295b0945b5SGregory Neil Shapiro #endif
1830c2aa98e2SPeter Wemm #ifdef ENETUNREACH
1831c2aa98e2SPeter Wemm 	  case ENETUNREACH:	/* Network is unreachable */
18325b0945b5SGregory Neil Shapiro #endif
1833c2aa98e2SPeter Wemm #ifdef ENFILE
1834c2aa98e2SPeter Wemm 	  case ENFILE:		/* Too many open files in system */
18355b0945b5SGregory Neil Shapiro #endif
1836c2aa98e2SPeter Wemm #ifdef ENOBUFS
1837c2aa98e2SPeter Wemm 	  case ENOBUFS:		/* No buffer space available */
18385b0945b5SGregory Neil Shapiro #endif
1839c2aa98e2SPeter Wemm #ifdef ENOMEM
1840c2aa98e2SPeter Wemm 	  case ENOMEM:		/* Cannot allocate memory */
18415b0945b5SGregory Neil Shapiro #endif
1842c2aa98e2SPeter Wemm #ifdef ENOSPC
1843c2aa98e2SPeter Wemm 	  case ENOSPC:		/* No space left on device */
18445b0945b5SGregory Neil Shapiro #endif
1845c2aa98e2SPeter Wemm #ifdef EROFS
1846c2aa98e2SPeter Wemm 	  case EROFS:		/* Read-only file system */
18475b0945b5SGregory Neil Shapiro #endif
1848c2aa98e2SPeter Wemm #ifdef ESTALE
1849c2aa98e2SPeter Wemm 	  case ESTALE:		/* Stale NFS file handle */
18505b0945b5SGregory Neil Shapiro #endif
1851c2aa98e2SPeter Wemm #ifdef ETIMEDOUT
1852c2aa98e2SPeter Wemm 	  case ETIMEDOUT:	/* Connection timed out */
18535b0945b5SGregory Neil Shapiro #endif
1854c2aa98e2SPeter Wemm #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
1855c2aa98e2SPeter Wemm 	  case EWOULDBLOCK:	/* Operation would block. */
18565b0945b5SGregory Neil Shapiro #endif
18573299c2f1SGregory Neil Shapiro 		ExitVal = EX_TEMPFAIL;
1858c2aa98e2SPeter Wemm 		break;
18593299c2f1SGregory Neil Shapiro 
1860c2aa98e2SPeter Wemm 	  default:
18613299c2f1SGregory Neil Shapiro 		ExitVal = EX_UNAVAILABLE;
1862c2aa98e2SPeter Wemm 		break;
1863c2aa98e2SPeter Wemm 	}
18643299c2f1SGregory Neil Shapiro 	return ExitVal;
1865c2aa98e2SPeter Wemm }
1866c2aa98e2SPeter Wemm 
1867c2aa98e2SPeter Wemm #if defined(ultrix) || defined(_CRAY)
1868c2aa98e2SPeter Wemm /*
1869c2aa98e2SPeter Wemm  * Copyright (c) 1987, 1993
1870c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
1871c2aa98e2SPeter Wemm  *
1872c2aa98e2SPeter Wemm  * Redistribution and use in source and binary forms, with or without
1873c2aa98e2SPeter Wemm  * modification, are permitted provided that the following conditions
1874c2aa98e2SPeter Wemm  * are met:
1875c2aa98e2SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1876c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1877c2aa98e2SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1878c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1879c2aa98e2SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1880c2aa98e2SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
1881c2aa98e2SPeter Wemm  *    must display the following acknowledgement:
1882c2aa98e2SPeter Wemm  *	This product includes software developed by the University of
1883c2aa98e2SPeter Wemm  *	California, Berkeley and its contributors.
1884c2aa98e2SPeter Wemm  * 4. Neither the name of the University nor the names of its contributors
1885c2aa98e2SPeter Wemm  *    may be used to endorse or promote products derived from this software
1886c2aa98e2SPeter Wemm  *    without specific prior written permission.
1887c2aa98e2SPeter Wemm  *
1888c2aa98e2SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1889c2aa98e2SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1890c2aa98e2SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1891c2aa98e2SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1892c2aa98e2SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1893c2aa98e2SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1894c2aa98e2SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1895c2aa98e2SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1896c2aa98e2SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1897c2aa98e2SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1898c2aa98e2SPeter Wemm  * SUCH DAMAGE.
1899c2aa98e2SPeter Wemm  */
1900c2aa98e2SPeter Wemm 
1901c2aa98e2SPeter Wemm # if defined(LIBC_SCCS) && !defined(lint)
1902c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
19035b0945b5SGregory Neil Shapiro # endif
1904c2aa98e2SPeter Wemm 
1905c2aa98e2SPeter Wemm # include <sys/types.h>
1906c2aa98e2SPeter Wemm # include <sys/stat.h>
1907c2aa98e2SPeter Wemm # include <fcntl.h>
1908c2aa98e2SPeter Wemm # include <errno.h>
1909c2aa98e2SPeter Wemm # include <stdio.h>
1910c2aa98e2SPeter Wemm # include <ctype.h>
1911c2aa98e2SPeter Wemm 
1912c2aa98e2SPeter Wemm static int _gettemp();
1913c2aa98e2SPeter Wemm 
mkstemp(path)1914c2aa98e2SPeter Wemm mkstemp(path)
1915c2aa98e2SPeter Wemm 	char *path;
1916c2aa98e2SPeter Wemm {
1917c2aa98e2SPeter Wemm 	int fd;
1918c2aa98e2SPeter Wemm 
1919c2aa98e2SPeter Wemm 	return (_gettemp(path, &fd) ? fd : -1);
1920c2aa98e2SPeter Wemm }
1921c2aa98e2SPeter Wemm 
1922c2aa98e2SPeter Wemm static
_gettemp(path,doopen)1923c2aa98e2SPeter Wemm _gettemp(path, doopen)
1924c2aa98e2SPeter Wemm 	char *path;
1925c2aa98e2SPeter Wemm 	register int *doopen;
1926c2aa98e2SPeter Wemm {
1927c2aa98e2SPeter Wemm 	extern int errno;
1928c2aa98e2SPeter Wemm 	register char *start, *trv;
1929c2aa98e2SPeter Wemm 	struct stat sbuf;
193012ed1c7cSGregory Neil Shapiro 	unsigned int pid;
1931c2aa98e2SPeter Wemm 
1932c2aa98e2SPeter Wemm 	pid = getpid();
1933c2aa98e2SPeter Wemm 	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
19343299c2f1SGregory Neil Shapiro 	while (*--trv == 'X')
19353299c2f1SGregory Neil Shapiro 	{
1936c2aa98e2SPeter Wemm 		*trv = (pid % 10) + '0';
1937c2aa98e2SPeter Wemm 		pid /= 10;
1938c2aa98e2SPeter Wemm 	}
1939c2aa98e2SPeter Wemm 
1940c2aa98e2SPeter Wemm 	/*
1941c2aa98e2SPeter Wemm 	 * check the target directory; if you have six X's and it
1942c2aa98e2SPeter Wemm 	 * doesn't exist this runs for a *very* long time.
1943c2aa98e2SPeter Wemm 	 */
19443299c2f1SGregory Neil Shapiro 	for (start = trv + 1;; --trv)
19453299c2f1SGregory Neil Shapiro 	{
1946c2aa98e2SPeter Wemm 		if (trv <= path)
1947c2aa98e2SPeter Wemm 			break;
19483299c2f1SGregory Neil Shapiro 		if (*trv == '/')
19493299c2f1SGregory Neil Shapiro 		{
1950c2aa98e2SPeter Wemm 			*trv = '\0';
1951c2aa98e2SPeter Wemm 			if (stat(path, &sbuf) < 0)
1952c2aa98e2SPeter Wemm 				return(0);
19533299c2f1SGregory Neil Shapiro 			if (!S_ISDIR(sbuf.st_mode))
19543299c2f1SGregory Neil Shapiro 			{
1955c2aa98e2SPeter Wemm 				errno = ENOTDIR;
1956c2aa98e2SPeter Wemm 				return(0);
1957c2aa98e2SPeter Wemm 			}
1958c2aa98e2SPeter Wemm 			*trv = '/';
1959c2aa98e2SPeter Wemm 			break;
1960c2aa98e2SPeter Wemm 		}
1961c2aa98e2SPeter Wemm 	}
1962c2aa98e2SPeter Wemm 
19633299c2f1SGregory Neil Shapiro 	for (;;)
19643299c2f1SGregory Neil Shapiro 	{
19653299c2f1SGregory Neil Shapiro 		if (doopen)
19663299c2f1SGregory Neil Shapiro 		{
1967d995d2baSGregory Neil Shapiro 			if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR,
1968d995d2baSGregory Neil Shapiro 					    0600)) >= 0)
1969c2aa98e2SPeter Wemm 				return(1);
1970c2aa98e2SPeter Wemm 			if (errno != EEXIST)
1971c2aa98e2SPeter Wemm 				return(0);
1972c2aa98e2SPeter Wemm 		}
1973c2aa98e2SPeter Wemm 		else if (stat(path, &sbuf) < 0)
1974c2aa98e2SPeter Wemm 			return(errno == ENOENT ? 1 : 0);
1975c2aa98e2SPeter Wemm 
1976c2aa98e2SPeter Wemm 		/* tricky little algorithm for backward compatibility */
19773299c2f1SGregory Neil Shapiro 		for (trv = start;;)
19783299c2f1SGregory Neil Shapiro 		{
1979c2aa98e2SPeter Wemm 			if (!*trv)
1980c2aa98e2SPeter Wemm 				return(0);
1981c2aa98e2SPeter Wemm 			if (*trv == 'z')
1982c2aa98e2SPeter Wemm 				*trv++ = 'a';
19833299c2f1SGregory Neil Shapiro 			else
19843299c2f1SGregory Neil Shapiro 			{
1985c2aa98e2SPeter Wemm 				if (isascii(*trv) && isdigit(*trv))
1986c2aa98e2SPeter Wemm 					*trv = 'a';
1987c2aa98e2SPeter Wemm 				else
1988c2aa98e2SPeter Wemm 					++*trv;
1989c2aa98e2SPeter Wemm 				break;
1990c2aa98e2SPeter Wemm 			}
1991c2aa98e2SPeter Wemm 		}
1992c2aa98e2SPeter Wemm 	}
1993c2aa98e2SPeter Wemm 	/* NOTREACHED */
1994c2aa98e2SPeter Wemm }
19953299c2f1SGregory Neil Shapiro #endif /* defined(ultrix) || defined(_CRAY) */
1996