xref: /freebsd/contrib/sendmail/mail.local/mail.local.c (revision 76b7bf71351ebb789c5591a4e300e2c6bfa59b99)
176b7bf71SPeter Wemm /*
2c2aa98e2SPeter Wemm  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3c2aa98e2SPeter Wemm  * Copyright (c) 1990, 1993, 1994
4c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
5c2aa98e2SPeter Wemm  *
6c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
7c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
8c2aa98e2SPeter Wemm  * the sendmail distribution.
9c2aa98e2SPeter Wemm  *
10c2aa98e2SPeter Wemm  */
11c2aa98e2SPeter Wemm 
12c2aa98e2SPeter Wemm #ifndef lint
13c2aa98e2SPeter Wemm static char copyright[] =
14c2aa98e2SPeter Wemm "@(#) Copyright (c) 1990, 1993, 1994\n\
15c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
16c2aa98e2SPeter Wemm #endif /* not lint */
17c2aa98e2SPeter Wemm 
18c2aa98e2SPeter Wemm #ifndef lint
1976b7bf71SPeter Wemm static char sccsid[] = "@(#)mail.local.c	8.83 (Berkeley) 12/17/1998";
20c2aa98e2SPeter Wemm #endif /* not lint */
21c2aa98e2SPeter Wemm 
22c2aa98e2SPeter Wemm /*
23c2aa98e2SPeter Wemm  * This is not intended to work on System V derived systems
24c2aa98e2SPeter Wemm  * such as Solaris or HP-UX, since they use a totally different
25c2aa98e2SPeter Wemm  * approach to mailboxes (essentially, they have a setgid program
26c2aa98e2SPeter Wemm  * rather than setuid, and they rely on the ability to "give away"
27c2aa98e2SPeter Wemm  * files to do their work).  IT IS NOT A BUG that this doesn't
28c2aa98e2SPeter Wemm  * work on such architectures.
29c2aa98e2SPeter Wemm  */
30c2aa98e2SPeter Wemm 
31c2aa98e2SPeter Wemm #include <sys/param.h>
32c2aa98e2SPeter Wemm #include <sys/stat.h>
33c2aa98e2SPeter Wemm #include <sys/socket.h>
34c2aa98e2SPeter Wemm #include <sys/file.h>
35c2aa98e2SPeter Wemm 
36c2aa98e2SPeter Wemm #include <netinet/in.h>
37c2aa98e2SPeter Wemm 
38c2aa98e2SPeter Wemm #include <errno.h>
39c2aa98e2SPeter Wemm #include <fcntl.h>
40c2aa98e2SPeter Wemm #include <netdb.h>
41c2aa98e2SPeter Wemm #include <pwd.h>
42c2aa98e2SPeter Wemm #include <stdio.h>
43c2aa98e2SPeter Wemm #include <stdlib.h>
44c2aa98e2SPeter Wemm #include <string.h>
45c2aa98e2SPeter Wemm #include <syslog.h>
46c2aa98e2SPeter Wemm #include <time.h>
47c2aa98e2SPeter Wemm #include <unistd.h>
48c2aa98e2SPeter Wemm #ifdef EX_OK
49c2aa98e2SPeter Wemm # undef EX_OK		/* unistd.h may have another use for this */
50c2aa98e2SPeter Wemm #endif
51c2aa98e2SPeter Wemm #include <sysexits.h>
52c2aa98e2SPeter Wemm #include <ctype.h>
53c2aa98e2SPeter Wemm 
54c2aa98e2SPeter Wemm #ifdef __STDC__
55c2aa98e2SPeter Wemm #include <stdarg.h>
56c2aa98e2SPeter Wemm #else
57c2aa98e2SPeter Wemm #include <varargs.h>
58c2aa98e2SPeter Wemm #endif
59c2aa98e2SPeter Wemm 
60c2aa98e2SPeter Wemm #if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
61c2aa98e2SPeter Wemm # define USE_LOCKF	1
62c2aa98e2SPeter Wemm # define USE_SETEUID	1
63c2aa98e2SPeter Wemm # define _PATH_MAILDIR	"/var/mail"
64c2aa98e2SPeter Wemm #endif
65c2aa98e2SPeter Wemm 
66c2aa98e2SPeter Wemm #if (defined(sun) && !defined(__svr4__)) && !defined(__SVR4)
67c2aa98e2SPeter Wemm # ifdef __dead
68c2aa98e2SPeter Wemm #  undef __dead
69c2aa98e2SPeter Wemm #  define __dead
70c2aa98e2SPeter Wemm # endif
71c2aa98e2SPeter Wemm #endif
72c2aa98e2SPeter Wemm 
73c2aa98e2SPeter Wemm #if defined(_AIX)
74c2aa98e2SPeter Wemm # define USE_LOCKF	1
75c2aa98e2SPeter Wemm # define USE_SETEUID	1
76c2aa98e2SPeter Wemm # define USE_VSYSLOG	0
77c2aa98e2SPeter Wemm #endif
78c2aa98e2SPeter Wemm 
79c2aa98e2SPeter Wemm #if defined(__hpux)
80c2aa98e2SPeter Wemm # define USE_LOCKF	1
81c2aa98e2SPeter Wemm # define USE_SETRESUID	1
82c2aa98e2SPeter Wemm # define USE_VSYSLOG	0
83c2aa98e2SPeter Wemm # ifdef __dead
84c2aa98e2SPeter Wemm #  undef __dead
85c2aa98e2SPeter Wemm #  define __dead
86c2aa98e2SPeter Wemm # endif
87c2aa98e2SPeter Wemm #endif
88c2aa98e2SPeter Wemm 
89c2aa98e2SPeter Wemm #if defined(_CRAY)
90c2aa98e2SPeter Wemm # if !defined(MAXPATHLEN)
91c2aa98e2SPeter Wemm #  define MAXPATHLEN PATHSIZE
92c2aa98e2SPeter Wemm # endif
93c2aa98e2SPeter Wemm # define USE_VSYSLOG   0
94c2aa98e2SPeter Wemm # define _PATH_MAILDIR	"/usr/spool/mail"
95c2aa98e2SPeter Wemm #endif
96c2aa98e2SPeter Wemm 
97c2aa98e2SPeter Wemm #if defined(ultrix)
98c2aa98e2SPeter Wemm # define USE_VSYSLOG	0
99c2aa98e2SPeter Wemm #endif
100c2aa98e2SPeter Wemm 
101c2aa98e2SPeter Wemm #if defined(__osf__)
102c2aa98e2SPeter Wemm # define USE_VSYSLOG	0
103c2aa98e2SPeter Wemm #endif
104c2aa98e2SPeter Wemm 
10576b7bf71SPeter Wemm #if defined(NeXT) && !defined(__APPLE__)
106c2aa98e2SPeter Wemm # include <libc.h>
107c2aa98e2SPeter Wemm # define _PATH_MAILDIR	"/usr/spool/mail"
108c2aa98e2SPeter Wemm # define __dead		/* empty */
109c2aa98e2SPeter Wemm # define S_IRUSR	S_IREAD
110c2aa98e2SPeter Wemm # define S_IWUSR	S_IWRITE
111c2aa98e2SPeter Wemm #endif
112c2aa98e2SPeter Wemm 
113c2aa98e2SPeter Wemm #if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
114c2aa98e2SPeter Wemm # include <paths.h>
115c2aa98e2SPeter Wemm # define HASSTRERROR	1	/* has strerror(3) */
116c2aa98e2SPeter Wemm #endif
117c2aa98e2SPeter Wemm 
118c2aa98e2SPeter Wemm /*
119c2aa98e2SPeter Wemm  * If you don't have flock, you could try using lockf instead.
120c2aa98e2SPeter Wemm  */
121c2aa98e2SPeter Wemm 
122c2aa98e2SPeter Wemm #ifdef USE_LOCKF
123c2aa98e2SPeter Wemm # define flock(a, b)	lockf(a, b, 0)
124c2aa98e2SPeter Wemm # define LOCK_EX	F_LOCK
125c2aa98e2SPeter Wemm #endif
126c2aa98e2SPeter Wemm 
127c2aa98e2SPeter Wemm #ifndef USE_VSYSLOG
128c2aa98e2SPeter Wemm # define USE_VSYSLOG	1
129c2aa98e2SPeter Wemm #endif
130c2aa98e2SPeter Wemm 
131c2aa98e2SPeter Wemm #ifndef LOCK_EX
132c2aa98e2SPeter Wemm # include <sys/file.h>
133c2aa98e2SPeter Wemm #endif
134c2aa98e2SPeter Wemm 
135c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(__GLIBC__)
136c2aa98e2SPeter Wemm # include "pathnames.h"
137c2aa98e2SPeter Wemm #endif
138c2aa98e2SPeter Wemm 
139c2aa98e2SPeter Wemm #ifndef __P
140c2aa98e2SPeter Wemm # ifdef __STDC__
141c2aa98e2SPeter Wemm #  define __P(protos)	protos
142c2aa98e2SPeter Wemm # else
143c2aa98e2SPeter Wemm #  define __P(protos)	()
144c2aa98e2SPeter Wemm #  define const
145c2aa98e2SPeter Wemm # endif
146c2aa98e2SPeter Wemm #endif
147c2aa98e2SPeter Wemm #ifndef __dead
148c2aa98e2SPeter Wemm # if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__)
149c2aa98e2SPeter Wemm #  define __dead	__volatile
150c2aa98e2SPeter Wemm # else
151c2aa98e2SPeter Wemm #  define __dead
152c2aa98e2SPeter Wemm # endif
153c2aa98e2SPeter Wemm #endif
154c2aa98e2SPeter Wemm 
155c2aa98e2SPeter Wemm #ifdef BSD4_4
156c2aa98e2SPeter Wemm # define HAS_ST_GEN	1
157c2aa98e2SPeter Wemm #else
158c2aa98e2SPeter Wemm # ifndef _BSD_VA_LIST_
159c2aa98e2SPeter Wemm #  define _BSD_VA_LIST_	va_list
160c2aa98e2SPeter Wemm # endif
161c2aa98e2SPeter Wemm #endif
162c2aa98e2SPeter Wemm 
163c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(linux)
164c2aa98e2SPeter Wemm # define HASSNPRINTF	1
165c2aa98e2SPeter Wemm #else
166c2aa98e2SPeter Wemm # ifndef ultrix
167c2aa98e2SPeter Wemm extern FILE	*fdopen __P((int, const char *));
168c2aa98e2SPeter Wemm # endif
169c2aa98e2SPeter Wemm #endif
170c2aa98e2SPeter Wemm 
171c2aa98e2SPeter Wemm #if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
172c2aa98e2SPeter Wemm # define HASSNPRINTF	1		/* has snprintf starting in 2.6 */
173c2aa98e2SPeter Wemm #endif
174c2aa98e2SPeter Wemm 
175c2aa98e2SPeter Wemm #if !HASSNPRINTF
176c2aa98e2SPeter Wemm extern int	snprintf __P((char *, size_t, const char *, ...));
177c2aa98e2SPeter Wemm # ifndef _CRAY
178c2aa98e2SPeter Wemm extern int	vsnprintf __P((char *, size_t, const char *, ...));
179c2aa98e2SPeter Wemm # endif
180c2aa98e2SPeter Wemm #endif
181c2aa98e2SPeter Wemm 
182c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__)
183c2aa98e2SPeter Wemm # ifndef HASSTRERROR
184c2aa98e2SPeter Wemm #  define HASSTRERROR	1
185c2aa98e2SPeter Wemm # endif
186c2aa98e2SPeter Wemm #endif
187c2aa98e2SPeter Wemm 
188c2aa98e2SPeter Wemm #if !HASSTRERROR
189c2aa98e2SPeter Wemm extern char	*strerror __P((int));
190c2aa98e2SPeter Wemm #endif
191c2aa98e2SPeter Wemm 
192c2aa98e2SPeter Wemm /*
193c2aa98e2SPeter Wemm  * If you don't have setreuid, and you have saved uids, and you have
194c2aa98e2SPeter Wemm  * a seteuid() call that doesn't try to emulate using setuid(), then
195c2aa98e2SPeter Wemm  * you can try defining USE_SETEUID.
196c2aa98e2SPeter Wemm  */
197c2aa98e2SPeter Wemm #ifdef USE_SETEUID
198c2aa98e2SPeter Wemm # define setreuid(r, e)		seteuid(e)
199c2aa98e2SPeter Wemm #endif
200c2aa98e2SPeter Wemm 
201c2aa98e2SPeter Wemm /*
202c2aa98e2SPeter Wemm  * And of course on hpux you have setresuid()
203c2aa98e2SPeter Wemm  */
204c2aa98e2SPeter Wemm #ifdef USE_SETRESUID
205c2aa98e2SPeter Wemm # define setreuid(r, e)		setresuid(-1, e, -1)
206c2aa98e2SPeter Wemm #endif
207c2aa98e2SPeter Wemm 
208c2aa98e2SPeter Wemm #ifndef _PATH_LOCTMP
209c2aa98e2SPeter Wemm # define _PATH_LOCTMP	"/tmp/local.XXXXXX"
210c2aa98e2SPeter Wemm #endif
211c2aa98e2SPeter Wemm #ifndef _PATH_MAILDIR
212c2aa98e2SPeter Wemm # define _PATH_MAILDIR	"/var/spool/mail"
213c2aa98e2SPeter Wemm #endif
214c2aa98e2SPeter Wemm 
215c2aa98e2SPeter Wemm #ifndef S_ISREG
216c2aa98e2SPeter Wemm # define S_ISREG(mode)	(((mode) & _S_IFMT) == S_IFREG)
217c2aa98e2SPeter Wemm #endif
218c2aa98e2SPeter Wemm 
21976b7bf71SPeter Wemm #ifndef MAILER_DAEMON
22076b7bf71SPeter Wemm # define MAILER_DAEMON	"MAILER-DAEMON"
22176b7bf71SPeter Wemm #endif
22276b7bf71SPeter Wemm 
223c2aa98e2SPeter Wemm int	eval = EX_OK;			/* sysexits.h error value. */
224c2aa98e2SPeter Wemm int	lmtpmode = 0;
225c2aa98e2SPeter Wemm u_char	tTdvect[100];
226c2aa98e2SPeter Wemm 
227d615a192SPeter Wemm void		deliver __P((int, char *, int, int));
228c2aa98e2SPeter Wemm void		e_to_sys __P((int));
229c2aa98e2SPeter Wemm void		notifybiff __P((char *));
230c2aa98e2SPeter Wemm int		store __P((char *, int));
231c2aa98e2SPeter Wemm void		usage __P((void));
232c2aa98e2SPeter Wemm void		vwarn __P((const char *, _BSD_VA_LIST_));
233c2aa98e2SPeter Wemm void		lockmbox __P((char *));
234c2aa98e2SPeter Wemm void		unlockmbox __P((void));
235c2aa98e2SPeter Wemm void		mailerr __P((const char *, const char *, ...));
236d615a192SPeter Wemm void		dolmtp __P((int, int));
237c2aa98e2SPeter Wemm 
238c2aa98e2SPeter Wemm int
239c2aa98e2SPeter Wemm main(argc, argv)
240c2aa98e2SPeter Wemm 	int argc;
241c2aa98e2SPeter Wemm 	char *argv[];
242c2aa98e2SPeter Wemm {
243c2aa98e2SPeter Wemm 	struct passwd *pw;
24405b73c60SPeter Wemm 	int ch, fd, nobiff, nofsync;
245c2aa98e2SPeter Wemm 	uid_t uid;
246c2aa98e2SPeter Wemm 	char *from;
247c2aa98e2SPeter Wemm 	extern char *optarg;
248c2aa98e2SPeter Wemm 	extern int optind;
249c2aa98e2SPeter Wemm 
250c2aa98e2SPeter Wemm 	/* make sure we have some open file descriptors */
251c2aa98e2SPeter Wemm 	for (fd = 10; fd < 30; fd++)
252c2aa98e2SPeter Wemm 		(void) close(fd);
253c2aa98e2SPeter Wemm 
254c2aa98e2SPeter Wemm 	/* use a reasonable umask */
255c2aa98e2SPeter Wemm 	(void) umask(0077);
256c2aa98e2SPeter Wemm 
257c2aa98e2SPeter Wemm #ifdef LOG_MAIL
258c2aa98e2SPeter Wemm 	openlog("mail.local", 0, LOG_MAIL);
259c2aa98e2SPeter Wemm #else
260c2aa98e2SPeter Wemm 	openlog("mail.local", 0);
261c2aa98e2SPeter Wemm #endif
262c2aa98e2SPeter Wemm 
263c2aa98e2SPeter Wemm 	from = NULL;
264d615a192SPeter Wemm 	nobiff = 0;
26505b73c60SPeter Wemm 	nofsync = 0;
266d615a192SPeter Wemm 	while ((ch = getopt(argc, argv, "bdf:r:ls")) != -1)
267c2aa98e2SPeter Wemm 		switch(ch) {
268d615a192SPeter Wemm 		case 'b':
269d615a192SPeter Wemm 			nobiff++;
270d615a192SPeter Wemm 			break;
271c2aa98e2SPeter Wemm 		case 'd':		/* Backward compatible. */
272c2aa98e2SPeter Wemm 			break;
273c2aa98e2SPeter Wemm 		case 'f':
274c2aa98e2SPeter Wemm 		case 'r':		/* Backward compatible. */
275c2aa98e2SPeter Wemm 			if (from != NULL) {
27676b7bf71SPeter Wemm 				mailerr(NULL, "multiple -f options");
277c2aa98e2SPeter Wemm 				usage();
278c2aa98e2SPeter Wemm 			}
279c2aa98e2SPeter Wemm 			from = optarg;
280c2aa98e2SPeter Wemm 			break;
281c2aa98e2SPeter Wemm 		case 'l':
282c2aa98e2SPeter Wemm 			lmtpmode++;
283c2aa98e2SPeter Wemm 			break;
284d615a192SPeter Wemm 		case 's':
28505b73c60SPeter Wemm 			nofsync++;
286d615a192SPeter Wemm 			break;
287c2aa98e2SPeter Wemm 		case '?':
288c2aa98e2SPeter Wemm 		default:
289c2aa98e2SPeter Wemm 			usage();
290c2aa98e2SPeter Wemm 		}
291c2aa98e2SPeter Wemm 	argc -= optind;
292c2aa98e2SPeter Wemm 	argv += optind;
293c2aa98e2SPeter Wemm 
294c2aa98e2SPeter Wemm 	if (lmtpmode)
29505b73c60SPeter Wemm 		dolmtp(nobiff, nofsync);
296c2aa98e2SPeter Wemm 
297c2aa98e2SPeter Wemm 	if (!*argv)
298c2aa98e2SPeter Wemm 		usage();
299c2aa98e2SPeter Wemm 
300c2aa98e2SPeter Wemm 	/*
301c2aa98e2SPeter Wemm 	 * If from not specified, use the name from getlogin() if the
302c2aa98e2SPeter Wemm 	 * uid matches, otherwise, use the name from the password file
303c2aa98e2SPeter Wemm 	 * corresponding to the uid.
304c2aa98e2SPeter Wemm 	 */
305c2aa98e2SPeter Wemm 	uid = getuid();
306c2aa98e2SPeter Wemm 	if (!from && (!(from = getlogin()) ||
307c2aa98e2SPeter Wemm 	    !(pw = getpwnam(from)) || pw->pw_uid != uid))
308c2aa98e2SPeter Wemm 		from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
309c2aa98e2SPeter Wemm 
310c2aa98e2SPeter Wemm 	/*
311c2aa98e2SPeter Wemm 	 * There is no way to distinguish the error status of one delivery
312c2aa98e2SPeter Wemm 	 * from the rest of the deliveries.  So, if we failed hard on one
313c2aa98e2SPeter Wemm 	 * or more deliveries, but had no failures on any of the others, we
314c2aa98e2SPeter Wemm 	 * return a hard failure.  If we failed temporarily on one or more
315c2aa98e2SPeter Wemm 	 * deliveries, we return a temporary failure regardless of the other
316c2aa98e2SPeter Wemm 	 * failures.  This results in the delivery being reattempted later
317c2aa98e2SPeter Wemm 	 * at the expense of repeated failures and multiple deliveries.
318c2aa98e2SPeter Wemm 	 */
319c2aa98e2SPeter Wemm 	for (fd = store(from, 0); *argv; ++argv)
32005b73c60SPeter Wemm 		deliver(fd, *argv, nobiff, nofsync);
321c2aa98e2SPeter Wemm 	exit(eval);
322c2aa98e2SPeter Wemm }
323c2aa98e2SPeter Wemm 
324c2aa98e2SPeter Wemm char *
325c2aa98e2SPeter Wemm parseaddr(s)
326c2aa98e2SPeter Wemm 	char *s;
327c2aa98e2SPeter Wemm {
328c2aa98e2SPeter Wemm 	char *p;
329c2aa98e2SPeter Wemm 	int len;
330c2aa98e2SPeter Wemm 
331c2aa98e2SPeter Wemm 	if (*s++ != '<')
332c2aa98e2SPeter Wemm 		return NULL;
333c2aa98e2SPeter Wemm 
334c2aa98e2SPeter Wemm 	p = s;
335c2aa98e2SPeter Wemm 
336c2aa98e2SPeter Wemm 	/* at-domain-list */
337c2aa98e2SPeter Wemm 	while (*p == '@') {
338c2aa98e2SPeter Wemm 		p++;
339c2aa98e2SPeter Wemm 		if (*p == '[') {
340c2aa98e2SPeter Wemm 			p++;
341c2aa98e2SPeter Wemm 			while (isascii(*p) &&
342c2aa98e2SPeter Wemm 			       (isalnum(*p) || *p == '.' ||
343c2aa98e2SPeter Wemm 				*p == '-' || *p == ':'))
344c2aa98e2SPeter Wemm 				p++;
345c2aa98e2SPeter Wemm 			if (*p++ != ']')
346c2aa98e2SPeter Wemm 				return NULL;
347c2aa98e2SPeter Wemm 		} else {
348c2aa98e2SPeter Wemm 			while ((isascii(*p) && isalnum(*p)) ||
34976b7bf71SPeter Wemm 			       strchr(".-_", *p))
350c2aa98e2SPeter Wemm 				p++;
351c2aa98e2SPeter Wemm 		}
352c2aa98e2SPeter Wemm 		if (*p == ',' && p[1] == '@')
353c2aa98e2SPeter Wemm 			p++;
354c2aa98e2SPeter Wemm 		else if (*p == ':' && p[1] != '@')
355c2aa98e2SPeter Wemm 			p++;
356c2aa98e2SPeter Wemm 		else
357c2aa98e2SPeter Wemm 			return NULL;
358c2aa98e2SPeter Wemm 	}
359c2aa98e2SPeter Wemm 
36076b7bf71SPeter Wemm 	s = p;
36176b7bf71SPeter Wemm 
362c2aa98e2SPeter Wemm 	/* local-part */
363c2aa98e2SPeter Wemm 	if (*p == '\"') {
364c2aa98e2SPeter Wemm 		p++;
365c2aa98e2SPeter Wemm 		while (*p && *p != '\"') {
366c2aa98e2SPeter Wemm 			if (*p == '\\') {
367c2aa98e2SPeter Wemm 				if (!*++p)
368c2aa98e2SPeter Wemm 					return NULL;
369c2aa98e2SPeter Wemm 			}
370c2aa98e2SPeter Wemm 			p++;
371c2aa98e2SPeter Wemm 		}
372c2aa98e2SPeter Wemm 		if (!*p++)
373c2aa98e2SPeter Wemm 			return NULL;
374c2aa98e2SPeter Wemm 	} else {
375c2aa98e2SPeter Wemm 		while (*p && *p != '@' && *p != '>') {
376c2aa98e2SPeter Wemm 			if (*p == '\\') {
377c2aa98e2SPeter Wemm 				if (!*++p)
378c2aa98e2SPeter Wemm 					return NULL;
379c2aa98e2SPeter Wemm 			} else {
380c2aa98e2SPeter Wemm 			if (*p <= ' ' || (*p & 128) ||
381c2aa98e2SPeter Wemm 			    strchr("<>()[]\\,;:\"", *p))
382c2aa98e2SPeter Wemm 				return NULL;
383c2aa98e2SPeter Wemm 			}
384c2aa98e2SPeter Wemm 			p++;
385c2aa98e2SPeter Wemm 		}
386c2aa98e2SPeter Wemm 	}
387c2aa98e2SPeter Wemm 
388c2aa98e2SPeter Wemm 	/* @domain */
389c2aa98e2SPeter Wemm 	if (*p == '@') {
390c2aa98e2SPeter Wemm 		p++;
391c2aa98e2SPeter Wemm 		if (*p == '[') {
392c2aa98e2SPeter Wemm 			p++;
393c2aa98e2SPeter Wemm 			while (isascii(*p) &&
394c2aa98e2SPeter Wemm 			       (isalnum(*p) || *p == '.' ||
395c2aa98e2SPeter Wemm 				*p == '-' || *p == ':'))
396c2aa98e2SPeter Wemm 				p++;
397c2aa98e2SPeter Wemm 			if (*p++ != ']')
398c2aa98e2SPeter Wemm 				return NULL;
399c2aa98e2SPeter Wemm 		} else {
400c2aa98e2SPeter Wemm 			while ((isascii(*p) && isalnum(*p)) ||
40176b7bf71SPeter Wemm 			       strchr(".-_", *p))
402c2aa98e2SPeter Wemm 				p++;
403c2aa98e2SPeter Wemm 		}
404c2aa98e2SPeter Wemm 	}
405c2aa98e2SPeter Wemm 
406c2aa98e2SPeter Wemm 	if (*p++ != '>')
407c2aa98e2SPeter Wemm 		return NULL;
408c2aa98e2SPeter Wemm 	if (*p && *p != ' ')
409c2aa98e2SPeter Wemm 		return NULL;
410c2aa98e2SPeter Wemm 	len = p - s - 1;
41176b7bf71SPeter Wemm 	if (*s == '\0' || len <= 0)
41276b7bf71SPeter Wemm 	{
41376b7bf71SPeter Wemm 		s = MAILER_DAEMON;
41476b7bf71SPeter Wemm 		len = strlen(s);
41576b7bf71SPeter Wemm 	}
416c2aa98e2SPeter Wemm 
417c2aa98e2SPeter Wemm 	p = malloc(len + 1);
418c2aa98e2SPeter Wemm 	if (p == NULL) {
419c2aa98e2SPeter Wemm 		printf("421 4.3.0 memory exhausted\r\n");
420c2aa98e2SPeter Wemm 		exit(EX_TEMPFAIL);
421c2aa98e2SPeter Wemm 	}
422c2aa98e2SPeter Wemm 
423c2aa98e2SPeter Wemm 	strncpy(p, s, len);
424c2aa98e2SPeter Wemm 	p[len] = '\0';
425c2aa98e2SPeter Wemm 	return p;
426c2aa98e2SPeter Wemm }
427c2aa98e2SPeter Wemm 
428c2aa98e2SPeter Wemm char *
429c2aa98e2SPeter Wemm process_recipient(addr)
430c2aa98e2SPeter Wemm 	char *addr;
431c2aa98e2SPeter Wemm {
432c2aa98e2SPeter Wemm 	if (getpwnam(addr) == NULL) {
433c2aa98e2SPeter Wemm 		return "550 5.1.1 user unknown";
434c2aa98e2SPeter Wemm 	}
435c2aa98e2SPeter Wemm 
436c2aa98e2SPeter Wemm 	return NULL;
437c2aa98e2SPeter Wemm }
438c2aa98e2SPeter Wemm 
439c2aa98e2SPeter Wemm 
440c2aa98e2SPeter Wemm #define RCPT_GROW	30
441c2aa98e2SPeter Wemm 
442c2aa98e2SPeter Wemm void
44305b73c60SPeter Wemm dolmtp(nobiff, nofsync)
44405b73c60SPeter Wemm 	int nobiff, nofsync;
445c2aa98e2SPeter Wemm {
446c2aa98e2SPeter Wemm 	char *return_path = NULL;
447c2aa98e2SPeter Wemm 	char **rcpt_addr = NULL;
448c2aa98e2SPeter Wemm 	int rcpt_num = 0;
449c2aa98e2SPeter Wemm 	int rcpt_alloc = 0;
450c2aa98e2SPeter Wemm 	char myhostname[1024];
451c2aa98e2SPeter Wemm 	char buf[4096];
452c2aa98e2SPeter Wemm 	char *err;
453c2aa98e2SPeter Wemm 	int msgfd;
454c2aa98e2SPeter Wemm 	char *p;
455c2aa98e2SPeter Wemm 	int i;
456c2aa98e2SPeter Wemm 
457c2aa98e2SPeter Wemm 	gethostname(myhostname, sizeof myhostname - 1);
458c2aa98e2SPeter Wemm 
459c2aa98e2SPeter Wemm 	printf("220 %s LMTP ready\r\n", myhostname);
460c2aa98e2SPeter Wemm 	for (;;) {
461c2aa98e2SPeter Wemm 		fflush(stdout);
462c2aa98e2SPeter Wemm 		if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
463c2aa98e2SPeter Wemm 			exit(EX_OK);
464c2aa98e2SPeter Wemm 		}
465c2aa98e2SPeter Wemm 		p = buf + strlen(buf) - 1;
466c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\n')
467c2aa98e2SPeter Wemm 			*p-- = '\0';
468c2aa98e2SPeter Wemm 		if (p >= buf && *p == '\r')
469c2aa98e2SPeter Wemm 			*p-- = '\0';
470c2aa98e2SPeter Wemm 
471c2aa98e2SPeter Wemm 		switch (buf[0]) {
472c2aa98e2SPeter Wemm 
473c2aa98e2SPeter Wemm 		case 'd':
474c2aa98e2SPeter Wemm 		case 'D':
475c2aa98e2SPeter Wemm 			if (strcasecmp(buf, "data") == 0) {
476c2aa98e2SPeter Wemm 				if (rcpt_num == 0) {
477c2aa98e2SPeter Wemm 					printf("503 5.5.1 No recipients\r\n");
478c2aa98e2SPeter Wemm 					continue;
479c2aa98e2SPeter Wemm 				}
480c2aa98e2SPeter Wemm 				msgfd = store(return_path, rcpt_num);
481c2aa98e2SPeter Wemm 				if (msgfd == -1)
482c2aa98e2SPeter Wemm 					continue;
483c2aa98e2SPeter Wemm 
484c2aa98e2SPeter Wemm 				for (i = 0; i < rcpt_num; i++) {
485c2aa98e2SPeter Wemm 					p = strchr(rcpt_addr[i], '+');
486c2aa98e2SPeter Wemm 					if (p != NULL)
487c2aa98e2SPeter Wemm 						*p++ = '\0';
488d615a192SPeter Wemm 					deliver(msgfd, rcpt_addr[i], nobiff,
48905b73c60SPeter Wemm 					    nofsync);
490c2aa98e2SPeter Wemm 				}
491c2aa98e2SPeter Wemm 				close(msgfd);
492c2aa98e2SPeter Wemm 				goto rset;
493c2aa98e2SPeter Wemm 			}
494c2aa98e2SPeter Wemm 			goto syntaxerr;
495c2aa98e2SPeter Wemm 
496c2aa98e2SPeter Wemm 		case 'l':
497c2aa98e2SPeter Wemm 		case 'L':
498c2aa98e2SPeter Wemm 			if (strncasecmp(buf, "lhlo ", 5) == 0) {
499c2aa98e2SPeter Wemm 				printf("250-%s\r\n250-8BITMIME\r\n250-ENHANCEDSTATUSCODES\r\n250 PIPELINING\r\n",
500c2aa98e2SPeter Wemm 					   myhostname);
501c2aa98e2SPeter Wemm 				continue;
502c2aa98e2SPeter Wemm 			}
503c2aa98e2SPeter Wemm 			goto syntaxerr;
504c2aa98e2SPeter Wemm 
505c2aa98e2SPeter Wemm 		case 'm':
506c2aa98e2SPeter Wemm 		case 'M':
507c2aa98e2SPeter Wemm 			if (strncasecmp(buf, "mail ", 5) == 0) {
508c2aa98e2SPeter Wemm 				if (return_path != NULL) {
509c2aa98e2SPeter Wemm 					printf("503 5.5.1 Nested MAIL command\r\n");
510c2aa98e2SPeter Wemm 					continue;
511c2aa98e2SPeter Wemm 				}
512c2aa98e2SPeter Wemm 				if (strncasecmp(buf+5, "from:", 5) != 0 ||
513c2aa98e2SPeter Wemm 				    ((return_path = parseaddr(buf+10)) == NULL)) {
514c2aa98e2SPeter Wemm 					printf("501 5.5.4 Syntax error in parameters\r\n");
515c2aa98e2SPeter Wemm 					continue;
516c2aa98e2SPeter Wemm 				}
517c2aa98e2SPeter Wemm 				printf("250 2.5.0 ok\r\n");
518c2aa98e2SPeter Wemm 				continue;
519c2aa98e2SPeter Wemm 			}
520c2aa98e2SPeter Wemm 			goto syntaxerr;
521c2aa98e2SPeter Wemm 
522c2aa98e2SPeter Wemm 		case 'n':
523c2aa98e2SPeter Wemm 		case 'N':
524c2aa98e2SPeter Wemm 			if (strcasecmp(buf, "noop") == 0) {
525c2aa98e2SPeter Wemm 				printf("250 2.0.0 ok\r\n");
526c2aa98e2SPeter Wemm 				continue;
527c2aa98e2SPeter Wemm 			}
528c2aa98e2SPeter Wemm 			goto syntaxerr;
529c2aa98e2SPeter Wemm 
530c2aa98e2SPeter Wemm 		case 'q':
531c2aa98e2SPeter Wemm 		case 'Q':
532c2aa98e2SPeter Wemm 			if (strcasecmp(buf, "quit") == 0) {
533c2aa98e2SPeter Wemm 				printf("221 2.0.0 bye\r\n");
534c2aa98e2SPeter Wemm 				exit(EX_OK);
535c2aa98e2SPeter Wemm 			}
536c2aa98e2SPeter Wemm 			goto syntaxerr;
537c2aa98e2SPeter Wemm 
538c2aa98e2SPeter Wemm 		case 'r':
539c2aa98e2SPeter Wemm 		case 'R':
540c2aa98e2SPeter Wemm 			if (strncasecmp(buf, "rcpt ", 5) == 0) {
541c2aa98e2SPeter Wemm 				if (return_path == NULL) {
542c2aa98e2SPeter Wemm 					printf("503 5.5.1 Need MAIL command\r\n");
543c2aa98e2SPeter Wemm 					continue;
544c2aa98e2SPeter Wemm 				}
545c2aa98e2SPeter Wemm 				if (rcpt_num >= rcpt_alloc) {
546c2aa98e2SPeter Wemm 					rcpt_alloc += RCPT_GROW;
547c2aa98e2SPeter Wemm 					rcpt_addr = (char **)
548c2aa98e2SPeter Wemm 						realloc((char *)rcpt_addr,
549c2aa98e2SPeter Wemm 							rcpt_alloc * sizeof(char **));
550c2aa98e2SPeter Wemm 					if (rcpt_addr == NULL) {
551c2aa98e2SPeter Wemm 						printf("421 4.3.0 memory exhausted\r\n");
552c2aa98e2SPeter Wemm 						exit(EX_TEMPFAIL);
553c2aa98e2SPeter Wemm 					}
554c2aa98e2SPeter Wemm 				}
555c2aa98e2SPeter Wemm 				if (strncasecmp(buf+5, "to:", 3) != 0 ||
556c2aa98e2SPeter Wemm 				    ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) {
557c2aa98e2SPeter Wemm 					printf("501 5.5.4 Syntax error in parameters\r\n");
558c2aa98e2SPeter Wemm 					continue;
559c2aa98e2SPeter Wemm 				}
560c2aa98e2SPeter Wemm 				if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) {
561c2aa98e2SPeter Wemm 					printf("%s\r\n", err);
562c2aa98e2SPeter Wemm 					continue;
563c2aa98e2SPeter Wemm 				}
564c2aa98e2SPeter Wemm 				rcpt_num++;
565c2aa98e2SPeter Wemm 				printf("250 2.1.5 ok\r\n");
566c2aa98e2SPeter Wemm 				continue;
567c2aa98e2SPeter Wemm 			}
568c2aa98e2SPeter Wemm 			else if (strcasecmp(buf, "rset") == 0) {
569c2aa98e2SPeter Wemm 				printf("250 2.0.0 ok\r\n");
570c2aa98e2SPeter Wemm 
571c2aa98e2SPeter Wemm   rset:
572c2aa98e2SPeter Wemm 				while (rcpt_num) {
573c2aa98e2SPeter Wemm 					free(rcpt_addr[--rcpt_num]);
574c2aa98e2SPeter Wemm 				}
575c2aa98e2SPeter Wemm 				if (return_path != NULL)
576c2aa98e2SPeter Wemm 					free(return_path);
577c2aa98e2SPeter Wemm 				return_path = NULL;
578c2aa98e2SPeter Wemm 				continue;
579c2aa98e2SPeter Wemm 			}
580c2aa98e2SPeter Wemm 			goto syntaxerr;
581c2aa98e2SPeter Wemm 
582c2aa98e2SPeter Wemm 		case 'v':
583c2aa98e2SPeter Wemm 		case 'V':
584c2aa98e2SPeter Wemm 			if (strncasecmp(buf, "vrfy ", 5) == 0) {
585c2aa98e2SPeter Wemm 				printf("252 2.3.3 try RCPT to attempt delivery\r\n");
586c2aa98e2SPeter Wemm 				continue;
587c2aa98e2SPeter Wemm 			}
588c2aa98e2SPeter Wemm 			goto syntaxerr;
589c2aa98e2SPeter Wemm 
590c2aa98e2SPeter Wemm 		default:
591c2aa98e2SPeter Wemm   syntaxerr:
592c2aa98e2SPeter Wemm 			printf("500 5.5.2 Syntax error\r\n");
593c2aa98e2SPeter Wemm 			continue;
594c2aa98e2SPeter Wemm 		}
595c2aa98e2SPeter Wemm 	}
596c2aa98e2SPeter Wemm }
597c2aa98e2SPeter Wemm 
598c2aa98e2SPeter Wemm int
599c2aa98e2SPeter Wemm store(from, lmtprcpts)
600c2aa98e2SPeter Wemm 	char *from;
601c2aa98e2SPeter Wemm 	int lmtprcpts;
602c2aa98e2SPeter Wemm {
60376b7bf71SPeter Wemm 	FILE *fp = NULL;
604c2aa98e2SPeter Wemm 	time_t tval;
605c2aa98e2SPeter Wemm 	int fd, eline;
606c2aa98e2SPeter Wemm 	char line[2048];
607c2aa98e2SPeter Wemm 	char tmpbuf[sizeof _PATH_LOCTMP + 1];
608c2aa98e2SPeter Wemm 
609c2aa98e2SPeter Wemm 	strcpy(tmpbuf, _PATH_LOCTMP);
610c2aa98e2SPeter Wemm 	if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
611c2aa98e2SPeter Wemm 		if (lmtprcpts) {
612c2aa98e2SPeter Wemm 			printf("451 4.3.0 unable to open temporary file\r\n");
613c2aa98e2SPeter Wemm 			return -1;
614c2aa98e2SPeter Wemm 		} else {
61576b7bf71SPeter Wemm 			mailerr("451 4.3.0", "unable to open temporary file");
61676b7bf71SPeter Wemm 			exit(eval);
617c2aa98e2SPeter Wemm 		}
618c2aa98e2SPeter Wemm 	}
619c2aa98e2SPeter Wemm 	(void)unlink(tmpbuf);
620c2aa98e2SPeter Wemm 
621c2aa98e2SPeter Wemm 	if (lmtpmode) {
622c2aa98e2SPeter Wemm 		printf("354 go ahead\r\n");
623c2aa98e2SPeter Wemm 		fflush(stdout);
624c2aa98e2SPeter Wemm 	}
625c2aa98e2SPeter Wemm 
626c2aa98e2SPeter Wemm 	(void)time(&tval);
627c2aa98e2SPeter Wemm 	(void)fprintf(fp, "From %s %s", from, ctime(&tval));
628c2aa98e2SPeter Wemm 
629c2aa98e2SPeter Wemm 	line[0] = '\0';
630c2aa98e2SPeter Wemm 	for (eline = 1; fgets(line, sizeof(line), stdin);) {
63176b7bf71SPeter Wemm 		size_t line_len = strlen(line);
63276b7bf71SPeter Wemm 
63376b7bf71SPeter Wemm 		if (line_len >= 2 &&
63476b7bf71SPeter Wemm 		    line[line_len - 2] == '\r' &&
63576b7bf71SPeter Wemm 		    line[line_len - 1] == '\n') {
63676b7bf71SPeter Wemm 			strcpy(line + line_len - 2, "\n");
637c2aa98e2SPeter Wemm 		}
638c2aa98e2SPeter Wemm 		if (lmtprcpts && line[0] == '.') {
63976b7bf71SPeter Wemm 			char *src = line + 1, *dest = line;
64076b7bf71SPeter Wemm 
641c2aa98e2SPeter Wemm 			if (line[1] == '\n')
642c2aa98e2SPeter Wemm 				goto lmtpdot;
64376b7bf71SPeter Wemm 			while (*src != '\0')
64476b7bf71SPeter Wemm 				*dest++ = *src++;
64576b7bf71SPeter Wemm 			*dest = '\0';
646c2aa98e2SPeter Wemm 		}
647c2aa98e2SPeter Wemm 		if (line[0] == '\n')
648c2aa98e2SPeter Wemm 			eline = 1;
649c2aa98e2SPeter Wemm 		else {
650c2aa98e2SPeter Wemm 			if (eline && line[0] == 'F' &&
651c2aa98e2SPeter Wemm 			    !memcmp(line, "From ", 5))
652c2aa98e2SPeter Wemm 				(void)putc('>', fp);
653c2aa98e2SPeter Wemm 			eline = 0;
654c2aa98e2SPeter Wemm 		}
655c2aa98e2SPeter Wemm 		(void)fprintf(fp, "%s", line);
656c2aa98e2SPeter Wemm 		if (ferror(fp)) {
657c2aa98e2SPeter Wemm 			if (lmtprcpts) {
658c2aa98e2SPeter Wemm 				while (lmtprcpts--) {
659c2aa98e2SPeter Wemm 					printf("451 4.3.0 temporary file write error\r\n");
660c2aa98e2SPeter Wemm 				}
661c2aa98e2SPeter Wemm 				fclose(fp);
662c2aa98e2SPeter Wemm 				return -1;
663c2aa98e2SPeter Wemm 			} else {
66476b7bf71SPeter Wemm 				mailerr("451 4.3.0",
66576b7bf71SPeter Wemm 					"temporary file write error");
66676b7bf71SPeter Wemm 				fclose(fp);
66776b7bf71SPeter Wemm 				exit(eval);
668c2aa98e2SPeter Wemm 			}
669c2aa98e2SPeter Wemm 		}
670c2aa98e2SPeter Wemm 	}
671c2aa98e2SPeter Wemm 
672c2aa98e2SPeter Wemm 	if (lmtprcpts) {
673c2aa98e2SPeter Wemm 		/* Got a premature EOF -- toss message and exit */
674c2aa98e2SPeter Wemm 		exit(EX_OK);
675c2aa98e2SPeter Wemm 	}
676c2aa98e2SPeter Wemm 
677c2aa98e2SPeter Wemm 	/* If message not newline terminated, need an extra. */
678c2aa98e2SPeter Wemm 	if (strchr(line, '\n') == NULL)
679c2aa98e2SPeter Wemm 		(void)putc('\n', fp);
680c2aa98e2SPeter Wemm 
681c2aa98e2SPeter Wemm   lmtpdot:
682c2aa98e2SPeter Wemm 
683c2aa98e2SPeter Wemm 	/* Output a newline; note, empty messages are allowed. */
684c2aa98e2SPeter Wemm 	(void)putc('\n', fp);
685c2aa98e2SPeter Wemm 
686c2aa98e2SPeter Wemm 	if (fflush(fp) == EOF || ferror(fp)) {
687c2aa98e2SPeter Wemm 		if (lmtprcpts) {
688c2aa98e2SPeter Wemm 			while (lmtprcpts--) {
689c2aa98e2SPeter Wemm 				printf("451 4.3.0 temporary file write error\r\n");
690c2aa98e2SPeter Wemm 			}
691c2aa98e2SPeter Wemm 			fclose(fp);
692c2aa98e2SPeter Wemm 			return -1;
693c2aa98e2SPeter Wemm 		} else {
69476b7bf71SPeter Wemm 			mailerr("451 4.3.0", "temporary file write error");
69576b7bf71SPeter Wemm 			fclose(fp);
69676b7bf71SPeter Wemm 			exit(eval);
697c2aa98e2SPeter Wemm 		}
698c2aa98e2SPeter Wemm 	}
699c2aa98e2SPeter Wemm 	return (fd);
700c2aa98e2SPeter Wemm }
701c2aa98e2SPeter Wemm 
702c2aa98e2SPeter Wemm void
70305b73c60SPeter Wemm deliver(fd, name, nobiff, nofsync)
704c2aa98e2SPeter Wemm 	int fd;
705c2aa98e2SPeter Wemm 	char *name;
70605b73c60SPeter Wemm 	int nobiff, nofsync;
707c2aa98e2SPeter Wemm {
708c2aa98e2SPeter Wemm 	struct stat fsb, sb;
709c2aa98e2SPeter Wemm 	struct passwd *pw;
710c2aa98e2SPeter Wemm 	int mbfd, nr, nw, off;
711c2aa98e2SPeter Wemm 	char *p;
712c2aa98e2SPeter Wemm 	char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
713c2aa98e2SPeter Wemm 	off_t curoff;
714c2aa98e2SPeter Wemm 	extern char *quad_to_string();
715c2aa98e2SPeter Wemm 
716c2aa98e2SPeter Wemm 	/*
717c2aa98e2SPeter Wemm 	 * Disallow delivery to unknown names -- special mailboxes can be
718c2aa98e2SPeter Wemm 	 * handled in the sendmail aliases file.
719c2aa98e2SPeter Wemm 	 */
720c2aa98e2SPeter Wemm 	if ((pw = getpwnam(name)) == NULL) {
721c2aa98e2SPeter Wemm 		if (eval != EX_TEMPFAIL)
722c2aa98e2SPeter Wemm 			eval = EX_UNAVAILABLE;
723c2aa98e2SPeter Wemm 		if (lmtpmode) {
724c2aa98e2SPeter Wemm 			if (eval == EX_TEMPFAIL) {
725c2aa98e2SPeter Wemm 				printf("451 4.3.0 cannot lookup name: %s\r\n", name);
726c2aa98e2SPeter Wemm 			} else {
727c2aa98e2SPeter Wemm 				printf("550 5.1.1 unknown name: %s\r\n", name);
728c2aa98e2SPeter Wemm 			}
729c2aa98e2SPeter Wemm 		}
730c2aa98e2SPeter Wemm 		else {
73176b7bf71SPeter Wemm 			char *errcode = NULL;
73276b7bf71SPeter Wemm 
73376b7bf71SPeter Wemm 			if (eval == EX_TEMPFAIL)
73476b7bf71SPeter Wemm 				errcode = "451 4.3.0";
73576b7bf71SPeter Wemm 			else
73676b7bf71SPeter Wemm 				errcode = "550 5.1.1";
73776b7bf71SPeter Wemm 			mailerr(errcode, "unknown name: %s", name);
738c2aa98e2SPeter Wemm 		}
739c2aa98e2SPeter Wemm 		return;
740c2aa98e2SPeter Wemm 	}
741c2aa98e2SPeter Wemm 	endpwent();
742c2aa98e2SPeter Wemm 
743c2aa98e2SPeter Wemm 	/*
744c2aa98e2SPeter Wemm 	 * Keep name reasonably short to avoid buffer overruns.
745c2aa98e2SPeter Wemm 	 *	This isn't necessary on BSD because of the proper
746c2aa98e2SPeter Wemm 	 *	definition of snprintf(), but it can cause problems
747c2aa98e2SPeter Wemm 	 *	on other systems.
748c2aa98e2SPeter Wemm 	 * Also, clear out any bogus characters.
749c2aa98e2SPeter Wemm 	 */
750c2aa98e2SPeter Wemm 
751c2aa98e2SPeter Wemm 	if (strlen(name) > 40)
752c2aa98e2SPeter Wemm 		name[40] = '\0';
753c2aa98e2SPeter Wemm 	for (p = name; *p != '\0'; p++)
754c2aa98e2SPeter Wemm 	{
755c2aa98e2SPeter Wemm 		if (!isascii(*p))
756c2aa98e2SPeter Wemm 			*p &= 0x7f;
757c2aa98e2SPeter Wemm 		else if (!isprint(*p))
758c2aa98e2SPeter Wemm 			*p = '.';
759c2aa98e2SPeter Wemm 	}
760c2aa98e2SPeter Wemm 
761c2aa98e2SPeter Wemm 	(void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
762c2aa98e2SPeter Wemm 
763c2aa98e2SPeter Wemm 	/*
764c2aa98e2SPeter Wemm 	 * If the mailbox is linked or a symlink, fail.  There's an obvious
765c2aa98e2SPeter Wemm 	 * race here, that the file was replaced with a symbolic link after
766c2aa98e2SPeter Wemm 	 * the lstat returned, but before the open.  We attempt to detect
767c2aa98e2SPeter Wemm 	 * this by comparing the original stat information and information
768c2aa98e2SPeter Wemm 	 * returned by an fstat of the file descriptor returned by the open.
769c2aa98e2SPeter Wemm 	 *
770c2aa98e2SPeter Wemm 	 * NB: this is a symptom of a larger problem, that the mail spooling
771c2aa98e2SPeter Wemm 	 * directory is writeable by the wrong users.  If that directory is
772c2aa98e2SPeter Wemm 	 * writeable, system security is compromised for other reasons, and
773c2aa98e2SPeter Wemm 	 * it cannot be fixed here.
774c2aa98e2SPeter Wemm 	 *
775c2aa98e2SPeter Wemm 	 * If we created the mailbox, set the owner/group.  If that fails,
776c2aa98e2SPeter Wemm 	 * just return.  Another process may have already opened it, so we
777c2aa98e2SPeter Wemm 	 * can't unlink it.  Historically, binmail set the owner/group at
778c2aa98e2SPeter Wemm 	 * each mail delivery.  We no longer do this, assuming that if the
779c2aa98e2SPeter Wemm 	 * ownership or permissions were changed there was a reason.
780c2aa98e2SPeter Wemm 	 *
781c2aa98e2SPeter Wemm 	 * XXX
782c2aa98e2SPeter Wemm 	 * open(2) should support flock'ing the file.
783c2aa98e2SPeter Wemm 	 */
784c2aa98e2SPeter Wemm tryagain:
785c2aa98e2SPeter Wemm 	lockmbox(path);
786c2aa98e2SPeter Wemm 	if (lstat(path, &sb) < 0) {
787c2aa98e2SPeter Wemm 		mbfd = open(path,
788c2aa98e2SPeter Wemm 			O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
789c2aa98e2SPeter Wemm 		if (lstat(path, &sb) < 0)
790c2aa98e2SPeter Wemm 		{
791c2aa98e2SPeter Wemm 			eval = EX_CANTCREAT;
79276b7bf71SPeter Wemm 			mailerr("550 5.2.0",
79376b7bf71SPeter Wemm 				"%s: lstat: file changed after open", path);
794c2aa98e2SPeter Wemm 			goto err1;
795c2aa98e2SPeter Wemm 		}
796c2aa98e2SPeter Wemm 		else
797c2aa98e2SPeter Wemm 			sb.st_uid = pw->pw_uid;
798c2aa98e2SPeter Wemm 		if (mbfd == -1) {
799c2aa98e2SPeter Wemm 			if (errno == EEXIST)
800c2aa98e2SPeter Wemm 				goto tryagain;
801c2aa98e2SPeter Wemm 		} else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) {
802c2aa98e2SPeter Wemm 			mailerr("451 4.3.0", "chown %u.%u: %s",
803c2aa98e2SPeter Wemm 				pw->pw_uid, pw->pw_gid, name);
804c2aa98e2SPeter Wemm 			goto err1;
805c2aa98e2SPeter Wemm 		}
806c2aa98e2SPeter Wemm 	} else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
807c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: irregular file", path);
808c2aa98e2SPeter Wemm 		goto err0;
809c2aa98e2SPeter Wemm 	} else if (sb.st_uid != pw->pw_uid) {
810c2aa98e2SPeter Wemm 		eval = EX_CANTCREAT;
811c2aa98e2SPeter Wemm 		mailerr("550 5.2.0", "%s: wrong ownership (%d)",
812c2aa98e2SPeter Wemm 				path, sb.st_uid);
813c2aa98e2SPeter Wemm 		goto err0;
814c2aa98e2SPeter Wemm 	} else {
815c2aa98e2SPeter Wemm 		mbfd = open(path, O_APPEND|O_WRONLY, 0);
816c2aa98e2SPeter Wemm 	}
817c2aa98e2SPeter Wemm 
818c2aa98e2SPeter Wemm 	if (mbfd == -1) {
819c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
820c2aa98e2SPeter Wemm 		goto err0;
821c2aa98e2SPeter Wemm 	} else if (fstat(mbfd, &fsb) < 0 ||
822c2aa98e2SPeter Wemm 	    fsb.st_nlink != 1 ||
823c2aa98e2SPeter Wemm 	    sb.st_nlink != 1 ||
824c2aa98e2SPeter Wemm 	    !S_ISREG(fsb.st_mode) ||
825c2aa98e2SPeter Wemm 	    sb.st_dev != fsb.st_dev ||
826c2aa98e2SPeter Wemm 	    sb.st_ino != fsb.st_ino ||
827c2aa98e2SPeter Wemm #if HAS_ST_GEN && 0		/* AFS returns random values for st_gen */
828c2aa98e2SPeter Wemm 	    sb.st_gen != fsb.st_gen ||
829c2aa98e2SPeter Wemm #endif
830c2aa98e2SPeter Wemm 	    sb.st_uid != fsb.st_uid) {
831c2aa98e2SPeter Wemm 		eval = EX_TEMPFAIL;
83276b7bf71SPeter Wemm 		mailerr("550 5.2.0", "%s: fstat: file changed after open",
83376b7bf71SPeter Wemm 			path);
834c2aa98e2SPeter Wemm 		goto err1;
835c2aa98e2SPeter Wemm 	}
836c2aa98e2SPeter Wemm 
837c2aa98e2SPeter Wemm 	/* Wait until we can get a lock on the file. */
838c2aa98e2SPeter Wemm 	if (flock(mbfd, LOCK_EX)) {
839c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
840c2aa98e2SPeter Wemm 		goto err1;
841c2aa98e2SPeter Wemm 	}
842c2aa98e2SPeter Wemm 
843d615a192SPeter Wemm 	if (!nobiff) {
844c2aa98e2SPeter Wemm 		/* Get the starting offset of the new message for biff. */
845c2aa98e2SPeter Wemm 		curoff = lseek(mbfd, (off_t)0, SEEK_END);
846c2aa98e2SPeter Wemm 		if (sizeof curoff > sizeof(long))
847c2aa98e2SPeter Wemm 			(void)snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
848c2aa98e2SPeter Wemm 				       name, quad_to_string(curoff));
849c2aa98e2SPeter Wemm 		else
850c2aa98e2SPeter Wemm 			(void)snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
851c2aa98e2SPeter Wemm 				       name, curoff);
852d615a192SPeter Wemm 	}
853c2aa98e2SPeter Wemm 
854c2aa98e2SPeter Wemm 	/* Copy the message into the file. */
855c2aa98e2SPeter Wemm 	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
856c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "temporary file: %s",
857c2aa98e2SPeter Wemm 			strerror(errno));
858c2aa98e2SPeter Wemm 		goto err1;
859c2aa98e2SPeter Wemm 	}
860c2aa98e2SPeter Wemm 	if (setreuid(0, pw->pw_uid) < 0) {
861c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
862c2aa98e2SPeter Wemm 		     pw->pw_uid, strerror(errno), getuid(), geteuid());
863c2aa98e2SPeter Wemm 		goto err1;
864c2aa98e2SPeter Wemm 	}
865c2aa98e2SPeter Wemm #ifdef DEBUG
866c2aa98e2SPeter Wemm 	printf("new euid = %d\n", geteuid());
867c2aa98e2SPeter Wemm #endif
868c2aa98e2SPeter Wemm 	while ((nr = read(fd, buf, sizeof(buf))) > 0)
869c2aa98e2SPeter Wemm 		for (off = 0; off < nr; off += nw)
870c2aa98e2SPeter Wemm 			if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
871c2aa98e2SPeter Wemm 				mailerr("450 4.2.0", "%s: %s",
872c2aa98e2SPeter Wemm 					path, strerror(errno));
873c2aa98e2SPeter Wemm 				goto err3;
874c2aa98e2SPeter Wemm 			}
875c2aa98e2SPeter Wemm 	if (nr < 0) {
876c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "temporary file: %s",
877c2aa98e2SPeter Wemm 			strerror(errno));
878c2aa98e2SPeter Wemm 		goto err3;
879c2aa98e2SPeter Wemm 	}
880c2aa98e2SPeter Wemm 
881c2aa98e2SPeter Wemm 	/* Flush to disk, don't wait for update. */
88205b73c60SPeter Wemm 	if (!nofsync && fsync(mbfd)) {
883c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
884c2aa98e2SPeter Wemm err3:
885c2aa98e2SPeter Wemm 		if (setreuid(0, 0) < 0) {
88676b7bf71SPeter Wemm #if 0
88776b7bf71SPeter Wemm 			/* already printed an error above for this recipient */
888c2aa98e2SPeter Wemm 			e_to_sys(errno);
889c2aa98e2SPeter Wemm 			mailerr("450 4.2.0", "setreuid(0, 0): %s",
890c2aa98e2SPeter Wemm 				strerror(errno));
89176b7bf71SPeter Wemm #endif
892c2aa98e2SPeter Wemm 		}
893c2aa98e2SPeter Wemm #ifdef DEBUG
894c2aa98e2SPeter Wemm 		printf("reset euid = %d\n", geteuid());
895c2aa98e2SPeter Wemm #endif
896c2aa98e2SPeter Wemm 		(void)ftruncate(mbfd, curoff);
897c2aa98e2SPeter Wemm err1:		(void)close(mbfd);
898c2aa98e2SPeter Wemm err0:		unlockmbox();
899c2aa98e2SPeter Wemm 		return;
900c2aa98e2SPeter Wemm 	}
901c2aa98e2SPeter Wemm 
902c2aa98e2SPeter Wemm 	/* Close and check -- NFS doesn't write until the close. */
903c2aa98e2SPeter Wemm 	if (close(mbfd)) {
904c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
905c2aa98e2SPeter Wemm 		truncate(path, curoff);
906d615a192SPeter Wemm 	} else if (!nobiff)
907c2aa98e2SPeter Wemm 		notifybiff(biffmsg);
908c2aa98e2SPeter Wemm 
909c2aa98e2SPeter Wemm 	if (setreuid(0, 0) < 0) {
910c2aa98e2SPeter Wemm 		mailerr("450 4.2.0", "setreuid(0, 0): %s",
911c2aa98e2SPeter Wemm 			strerror(errno));
912c2aa98e2SPeter Wemm 		goto err0;
913c2aa98e2SPeter Wemm 	}
914c2aa98e2SPeter Wemm #ifdef DEBUG
915c2aa98e2SPeter Wemm 	printf("reset euid = %d\n", geteuid());
916c2aa98e2SPeter Wemm #endif
917c2aa98e2SPeter Wemm 	unlockmbox();
918c2aa98e2SPeter Wemm 	if (lmtpmode) {
919c2aa98e2SPeter Wemm 		printf("250 2.1.5 %s OK\r\n", name);
920c2aa98e2SPeter Wemm 	}
921c2aa98e2SPeter Wemm }
922c2aa98e2SPeter Wemm 
923c2aa98e2SPeter Wemm /*
924c2aa98e2SPeter Wemm  * user.lock files are necessary for compatibility with other
925c2aa98e2SPeter Wemm  * systems, e.g., when the mail spool file is NFS exported.
926c2aa98e2SPeter Wemm  * Alas, mailbox locking is more than just a local matter.
927c2aa98e2SPeter Wemm  * EPA 11/94.
928c2aa98e2SPeter Wemm  */
929c2aa98e2SPeter Wemm 
930c2aa98e2SPeter Wemm char	lockname[MAXPATHLEN];
931c2aa98e2SPeter Wemm int	locked = 0;
932c2aa98e2SPeter Wemm 
933c2aa98e2SPeter Wemm void
934c2aa98e2SPeter Wemm lockmbox(path)
935c2aa98e2SPeter Wemm 	char *path;
936c2aa98e2SPeter Wemm {
937c2aa98e2SPeter Wemm 	int statfailed = 0;
938c2aa98e2SPeter Wemm 
939c2aa98e2SPeter Wemm 	if (locked)
940c2aa98e2SPeter Wemm 		return;
941c2aa98e2SPeter Wemm 	if (strlen(path) + 6 > sizeof lockname)
942c2aa98e2SPeter Wemm 		return;
943c2aa98e2SPeter Wemm 	snprintf(lockname, sizeof lockname, "%s.lock", path);
944c2aa98e2SPeter Wemm 	for (;; sleep(5)) {
945c2aa98e2SPeter Wemm 		int fd;
946c2aa98e2SPeter Wemm 		struct stat st;
947c2aa98e2SPeter Wemm 		time_t now;
948c2aa98e2SPeter Wemm 
949c2aa98e2SPeter Wemm 		fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0);
950c2aa98e2SPeter Wemm 		if (fd >= 0) {
951c2aa98e2SPeter Wemm 			/* defeat lock checking programs which test pid */
952c2aa98e2SPeter Wemm 			write(fd, "0", 2);
953c2aa98e2SPeter Wemm 			locked = 1;
954c2aa98e2SPeter Wemm 			close(fd);
955c2aa98e2SPeter Wemm 			return;
956c2aa98e2SPeter Wemm 		}
957c2aa98e2SPeter Wemm 		if (stat(lockname, &st) < 0) {
958c2aa98e2SPeter Wemm 			if (statfailed++ > 5)
959c2aa98e2SPeter Wemm 				return;
960c2aa98e2SPeter Wemm 			continue;
961c2aa98e2SPeter Wemm 		}
962c2aa98e2SPeter Wemm 		statfailed = 0;
963c2aa98e2SPeter Wemm 		time(&now);
964c2aa98e2SPeter Wemm 		if (now < st.st_ctime + 300)
965c2aa98e2SPeter Wemm 			continue;
966c2aa98e2SPeter Wemm 		unlink(lockname);
967c2aa98e2SPeter Wemm 	}
968c2aa98e2SPeter Wemm }
969c2aa98e2SPeter Wemm 
970c2aa98e2SPeter Wemm void
971c2aa98e2SPeter Wemm unlockmbox()
972c2aa98e2SPeter Wemm {
973c2aa98e2SPeter Wemm 	if (!locked)
974c2aa98e2SPeter Wemm 		return;
975c2aa98e2SPeter Wemm 	unlink(lockname);
976c2aa98e2SPeter Wemm 	locked = 0;
977c2aa98e2SPeter Wemm }
978c2aa98e2SPeter Wemm 
979c2aa98e2SPeter Wemm void
980c2aa98e2SPeter Wemm notifybiff(msg)
981c2aa98e2SPeter Wemm 	char *msg;
982c2aa98e2SPeter Wemm {
983c2aa98e2SPeter Wemm 	static struct sockaddr_in addr;
984c2aa98e2SPeter Wemm 	static int f = -1;
985c2aa98e2SPeter Wemm 	struct hostent *hp;
986c2aa98e2SPeter Wemm 	struct servent *sp;
987c2aa98e2SPeter Wemm 	int len;
988c2aa98e2SPeter Wemm 
989c2aa98e2SPeter Wemm 	if (addr.sin_family == 0) {
990c2aa98e2SPeter Wemm 		/* Be silent if biff service not available. */
991c2aa98e2SPeter Wemm 		if ((sp = getservbyname("biff", "udp")) == NULL)
992c2aa98e2SPeter Wemm 			return;
993c2aa98e2SPeter Wemm 		if ((hp = gethostbyname("localhost")) == NULL) {
994c2aa98e2SPeter Wemm 			return;
995c2aa98e2SPeter Wemm 		}
996c2aa98e2SPeter Wemm 		addr.sin_family = hp->h_addrtype;
997c2aa98e2SPeter Wemm 		memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
998c2aa98e2SPeter Wemm 		addr.sin_port = sp->s_port;
999c2aa98e2SPeter Wemm 	}
1000c2aa98e2SPeter Wemm 	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
1001c2aa98e2SPeter Wemm 		return;
1002c2aa98e2SPeter Wemm 	}
1003c2aa98e2SPeter Wemm 	len = strlen(msg) + 1;
100476b7bf71SPeter Wemm 	(void) sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr));
1005c2aa98e2SPeter Wemm }
1006c2aa98e2SPeter Wemm 
1007c2aa98e2SPeter Wemm void
1008c2aa98e2SPeter Wemm usage()
1009c2aa98e2SPeter Wemm {
1010c2aa98e2SPeter Wemm 	eval = EX_USAGE;
101176b7bf71SPeter Wemm 	mailerr(NULL, "usage: mail.local [-b] [-l] [-f from] [-s] user ...");
101276b7bf71SPeter Wemm 	exit(eval);
1013c2aa98e2SPeter Wemm }
1014c2aa98e2SPeter Wemm 
1015c2aa98e2SPeter Wemm void
1016c2aa98e2SPeter Wemm #ifdef __STDC__
1017c2aa98e2SPeter Wemm mailerr(const char *hdr, const char *fmt, ...)
1018c2aa98e2SPeter Wemm #else
1019c2aa98e2SPeter Wemm mailerr(hdr, fmt, va_alist)
1020c2aa98e2SPeter Wemm 	const char *hdr;
1021c2aa98e2SPeter Wemm 	const char *fmt;
1022c2aa98e2SPeter Wemm 	va_dcl
1023c2aa98e2SPeter Wemm #endif
1024c2aa98e2SPeter Wemm {
1025c2aa98e2SPeter Wemm 	va_list ap;
1026c2aa98e2SPeter Wemm 
1027c2aa98e2SPeter Wemm #ifdef __STDC__
1028c2aa98e2SPeter Wemm 	va_start(ap, fmt);
1029c2aa98e2SPeter Wemm #else
1030c2aa98e2SPeter Wemm 	va_start(ap);
1031c2aa98e2SPeter Wemm #endif
1032c2aa98e2SPeter Wemm 	if (lmtpmode)
1033c2aa98e2SPeter Wemm 	{
103476b7bf71SPeter Wemm 		if (hdr != NULL)
1035c2aa98e2SPeter Wemm 			printf("%s ", hdr);
1036c2aa98e2SPeter Wemm 		vprintf(fmt, ap);
1037c2aa98e2SPeter Wemm 		printf("\r\n");
1038c2aa98e2SPeter Wemm 	}
1039c2aa98e2SPeter Wemm 	else
1040c2aa98e2SPeter Wemm 	{
1041c2aa98e2SPeter Wemm 		e_to_sys(errno);
1042c2aa98e2SPeter Wemm 		vwarn(fmt, ap);
1043c2aa98e2SPeter Wemm 	}
1044c2aa98e2SPeter Wemm }
1045c2aa98e2SPeter Wemm 
1046c2aa98e2SPeter Wemm void
1047c2aa98e2SPeter Wemm vwarn(fmt, ap)
1048c2aa98e2SPeter Wemm 	const char *fmt;
1049c2aa98e2SPeter Wemm 	_BSD_VA_LIST_ ap;
1050c2aa98e2SPeter Wemm {
1051c2aa98e2SPeter Wemm 	/*
1052c2aa98e2SPeter Wemm 	 * Log the message to stderr.
1053c2aa98e2SPeter Wemm 	 *
1054c2aa98e2SPeter Wemm 	 * Don't use LOG_PERROR as an openlog() flag to do this,
1055c2aa98e2SPeter Wemm 	 * it's not portable enough.
1056c2aa98e2SPeter Wemm 	 */
1057c2aa98e2SPeter Wemm 	if (eval != EX_USAGE)
1058c2aa98e2SPeter Wemm 		(void)fprintf(stderr, "mail.local: ");
1059c2aa98e2SPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
1060c2aa98e2SPeter Wemm 	(void)fprintf(stderr, "\n");
1061c2aa98e2SPeter Wemm 
1062c2aa98e2SPeter Wemm #if USE_VSYSLOG
1063c2aa98e2SPeter Wemm 	/* Log the message to syslog. */
1064c2aa98e2SPeter Wemm 	vsyslog(LOG_ERR, fmt, ap);
1065c2aa98e2SPeter Wemm #else
1066c2aa98e2SPeter Wemm 	{
1067c2aa98e2SPeter Wemm 		char fmtbuf[10240];
1068c2aa98e2SPeter Wemm 
1069c2aa98e2SPeter Wemm 		(void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap);
1070c2aa98e2SPeter Wemm 		syslog(LOG_ERR, "%s", fmtbuf);
1071c2aa98e2SPeter Wemm 	}
1072c2aa98e2SPeter Wemm #endif
1073c2aa98e2SPeter Wemm }
1074c2aa98e2SPeter Wemm 
1075c2aa98e2SPeter Wemm /*
1076c2aa98e2SPeter Wemm  * e_to_sys --
1077c2aa98e2SPeter Wemm  *	Guess which errno's are temporary.  Gag me.
1078c2aa98e2SPeter Wemm  */
1079c2aa98e2SPeter Wemm void
1080c2aa98e2SPeter Wemm e_to_sys(num)
1081c2aa98e2SPeter Wemm 	int num;
1082c2aa98e2SPeter Wemm {
1083c2aa98e2SPeter Wemm 	/* Temporary failures override hard errors. */
1084c2aa98e2SPeter Wemm 	if (eval == EX_TEMPFAIL)
1085c2aa98e2SPeter Wemm 		return;
1086c2aa98e2SPeter Wemm 
1087c2aa98e2SPeter Wemm 	switch(num) {		/* Hopefully temporary errors. */
1088c2aa98e2SPeter Wemm #ifdef EAGAIN
1089c2aa98e2SPeter Wemm 	case EAGAIN:		/* Resource temporarily unavailable */
1090c2aa98e2SPeter Wemm #endif
1091c2aa98e2SPeter Wemm #ifdef EDQUOT
1092c2aa98e2SPeter Wemm 	case EDQUOT:		/* Disc quota exceeded */
1093c2aa98e2SPeter Wemm #endif
1094c2aa98e2SPeter Wemm #ifdef EBUSY
1095c2aa98e2SPeter Wemm 	case EBUSY:		/* Device busy */
1096c2aa98e2SPeter Wemm #endif
1097c2aa98e2SPeter Wemm #ifdef EPROCLIM
1098c2aa98e2SPeter Wemm 	case EPROCLIM:		/* Too many processes */
1099c2aa98e2SPeter Wemm #endif
1100c2aa98e2SPeter Wemm #ifdef EUSERS
1101c2aa98e2SPeter Wemm 	case EUSERS:		/* Too many users */
1102c2aa98e2SPeter Wemm #endif
1103c2aa98e2SPeter Wemm #ifdef ECONNABORTED
1104c2aa98e2SPeter Wemm 	case ECONNABORTED:	/* Software caused connection abort */
1105c2aa98e2SPeter Wemm #endif
1106c2aa98e2SPeter Wemm #ifdef ECONNREFUSED
1107c2aa98e2SPeter Wemm 	case ECONNREFUSED:	/* Connection refused */
1108c2aa98e2SPeter Wemm #endif
1109c2aa98e2SPeter Wemm #ifdef ECONNRESET
1110c2aa98e2SPeter Wemm 	case ECONNRESET:	/* Connection reset by peer */
1111c2aa98e2SPeter Wemm #endif
1112c2aa98e2SPeter Wemm #ifdef EDEADLK
1113c2aa98e2SPeter Wemm 	case EDEADLK:		/* Resource deadlock avoided */
1114c2aa98e2SPeter Wemm #endif
1115c2aa98e2SPeter Wemm #ifdef EFBIG
1116c2aa98e2SPeter Wemm 	case EFBIG:		/* File too large */
1117c2aa98e2SPeter Wemm #endif
1118c2aa98e2SPeter Wemm #ifdef EHOSTDOWN
1119c2aa98e2SPeter Wemm 	case EHOSTDOWN:		/* Host is down */
1120c2aa98e2SPeter Wemm #endif
1121c2aa98e2SPeter Wemm #ifdef EHOSTUNREACH
1122c2aa98e2SPeter Wemm 	case EHOSTUNREACH:	/* No route to host */
1123c2aa98e2SPeter Wemm #endif
1124c2aa98e2SPeter Wemm #ifdef EMFILE
1125c2aa98e2SPeter Wemm 	case EMFILE:		/* Too many open files */
1126c2aa98e2SPeter Wemm #endif
1127c2aa98e2SPeter Wemm #ifdef ENETDOWN
1128c2aa98e2SPeter Wemm 	case ENETDOWN:		/* Network is down */
1129c2aa98e2SPeter Wemm #endif
1130c2aa98e2SPeter Wemm #ifdef ENETRESET
1131c2aa98e2SPeter Wemm 	case ENETRESET:		/* Network dropped connection on reset */
1132c2aa98e2SPeter Wemm #endif
1133c2aa98e2SPeter Wemm #ifdef ENETUNREACH
1134c2aa98e2SPeter Wemm 	case ENETUNREACH:	/* Network is unreachable */
1135c2aa98e2SPeter Wemm #endif
1136c2aa98e2SPeter Wemm #ifdef ENFILE
1137c2aa98e2SPeter Wemm 	case ENFILE:		/* Too many open files in system */
1138c2aa98e2SPeter Wemm #endif
1139c2aa98e2SPeter Wemm #ifdef ENOBUFS
1140c2aa98e2SPeter Wemm 	case ENOBUFS:		/* No buffer space available */
1141c2aa98e2SPeter Wemm #endif
1142c2aa98e2SPeter Wemm #ifdef ENOMEM
1143c2aa98e2SPeter Wemm 	case ENOMEM:		/* Cannot allocate memory */
1144c2aa98e2SPeter Wemm #endif
1145c2aa98e2SPeter Wemm #ifdef ENOSPC
1146c2aa98e2SPeter Wemm 	case ENOSPC:		/* No space left on device */
1147c2aa98e2SPeter Wemm #endif
1148c2aa98e2SPeter Wemm #ifdef EROFS
1149c2aa98e2SPeter Wemm 	case EROFS:		/* Read-only file system */
1150c2aa98e2SPeter Wemm #endif
1151c2aa98e2SPeter Wemm #ifdef ESTALE
1152c2aa98e2SPeter Wemm 	case ESTALE:		/* Stale NFS file handle */
1153c2aa98e2SPeter Wemm #endif
1154c2aa98e2SPeter Wemm #ifdef ETIMEDOUT
1155c2aa98e2SPeter Wemm 	case ETIMEDOUT:		/* Connection timed out */
1156c2aa98e2SPeter Wemm #endif
1157c2aa98e2SPeter Wemm #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
1158c2aa98e2SPeter Wemm 	case EWOULDBLOCK:	/* Operation would block. */
1159c2aa98e2SPeter Wemm #endif
1160c2aa98e2SPeter Wemm 		eval = EX_TEMPFAIL;
1161c2aa98e2SPeter Wemm 		break;
1162c2aa98e2SPeter Wemm 	default:
1163c2aa98e2SPeter Wemm 		eval = EX_UNAVAILABLE;
1164c2aa98e2SPeter Wemm 		break;
1165c2aa98e2SPeter Wemm 	}
1166c2aa98e2SPeter Wemm }
1167c2aa98e2SPeter Wemm 
1168c2aa98e2SPeter Wemm #if !HASSTRERROR
1169c2aa98e2SPeter Wemm 
1170c2aa98e2SPeter Wemm char *
1171c2aa98e2SPeter Wemm strerror(eno)
1172c2aa98e2SPeter Wemm 	int eno;
1173c2aa98e2SPeter Wemm {
1174c2aa98e2SPeter Wemm 	extern int sys_nerr;
1175c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
1176c2aa98e2SPeter Wemm 	static char ebuf[60];
1177c2aa98e2SPeter Wemm 
1178c2aa98e2SPeter Wemm 	if (eno >= 0 && eno < sys_nerr)
1179c2aa98e2SPeter Wemm 		return sys_errlist[eno];
1180c2aa98e2SPeter Wemm 	(void) sprintf(ebuf, "Error %d", eno);
1181c2aa98e2SPeter Wemm 	return ebuf;
1182c2aa98e2SPeter Wemm }
1183c2aa98e2SPeter Wemm 
1184c2aa98e2SPeter Wemm #endif /* !HASSTRERROR */
1185c2aa98e2SPeter Wemm 
1186c2aa98e2SPeter Wemm #if defined(ultrix) || defined(_CRAY)
1187c2aa98e2SPeter Wemm 
1188c2aa98e2SPeter Wemm /*
1189c2aa98e2SPeter Wemm  * Copyright (c) 1987, 1993
1190c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
1191c2aa98e2SPeter Wemm  *
1192c2aa98e2SPeter Wemm  * Redistribution and use in source and binary forms, with or without
1193c2aa98e2SPeter Wemm  * modification, are permitted provided that the following conditions
1194c2aa98e2SPeter Wemm  * are met:
1195c2aa98e2SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1196c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1197c2aa98e2SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1198c2aa98e2SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1199c2aa98e2SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1200c2aa98e2SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
1201c2aa98e2SPeter Wemm  *    must display the following acknowledgement:
1202c2aa98e2SPeter Wemm  *	This product includes software developed by the University of
1203c2aa98e2SPeter Wemm  *	California, Berkeley and its contributors.
1204c2aa98e2SPeter Wemm  * 4. Neither the name of the University nor the names of its contributors
1205c2aa98e2SPeter Wemm  *    may be used to endorse or promote products derived from this software
1206c2aa98e2SPeter Wemm  *    without specific prior written permission.
1207c2aa98e2SPeter Wemm  *
1208c2aa98e2SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1209c2aa98e2SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1210c2aa98e2SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1211c2aa98e2SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1212c2aa98e2SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1213c2aa98e2SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1214c2aa98e2SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1215c2aa98e2SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1216c2aa98e2SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1217c2aa98e2SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1218c2aa98e2SPeter Wemm  * SUCH DAMAGE.
1219c2aa98e2SPeter Wemm  */
1220c2aa98e2SPeter Wemm 
1221c2aa98e2SPeter Wemm #if defined(LIBC_SCCS) && !defined(lint)
1222c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
1223c2aa98e2SPeter Wemm #endif /* LIBC_SCCS and not lint */
1224c2aa98e2SPeter Wemm 
1225c2aa98e2SPeter Wemm #include <sys/types.h>
1226c2aa98e2SPeter Wemm #include <sys/stat.h>
1227c2aa98e2SPeter Wemm #include <fcntl.h>
1228c2aa98e2SPeter Wemm #include <errno.h>
1229c2aa98e2SPeter Wemm #include <stdio.h>
1230c2aa98e2SPeter Wemm #include <ctype.h>
1231c2aa98e2SPeter Wemm 
1232c2aa98e2SPeter Wemm static int _gettemp();
1233c2aa98e2SPeter Wemm 
1234c2aa98e2SPeter Wemm mkstemp(path)
1235c2aa98e2SPeter Wemm 	char *path;
1236c2aa98e2SPeter Wemm {
1237c2aa98e2SPeter Wemm 	int fd;
1238c2aa98e2SPeter Wemm 
1239c2aa98e2SPeter Wemm 	return (_gettemp(path, &fd) ? fd : -1);
1240c2aa98e2SPeter Wemm }
1241c2aa98e2SPeter Wemm 
1242c2aa98e2SPeter Wemm /*
1243c2aa98e2SPeter Wemm char *
1244c2aa98e2SPeter Wemm mktemp(path)
1245c2aa98e2SPeter Wemm 	char *path;
1246c2aa98e2SPeter Wemm {
1247c2aa98e2SPeter Wemm 	return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
1248c2aa98e2SPeter Wemm }
1249c2aa98e2SPeter Wemm */
1250c2aa98e2SPeter Wemm 
1251c2aa98e2SPeter Wemm static
1252c2aa98e2SPeter Wemm _gettemp(path, doopen)
1253c2aa98e2SPeter Wemm 	char *path;
1254c2aa98e2SPeter Wemm 	register int *doopen;
1255c2aa98e2SPeter Wemm {
1256c2aa98e2SPeter Wemm 	extern int errno;
1257c2aa98e2SPeter Wemm 	register char *start, *trv;
1258c2aa98e2SPeter Wemm 	struct stat sbuf;
1259c2aa98e2SPeter Wemm 	u_int pid;
1260c2aa98e2SPeter Wemm 
1261c2aa98e2SPeter Wemm 	pid = getpid();
1262c2aa98e2SPeter Wemm 	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
1263c2aa98e2SPeter Wemm 	while (*--trv == 'X') {
1264c2aa98e2SPeter Wemm 		*trv = (pid % 10) + '0';
1265c2aa98e2SPeter Wemm 		pid /= 10;
1266c2aa98e2SPeter Wemm 	}
1267c2aa98e2SPeter Wemm 
1268c2aa98e2SPeter Wemm 	/*
1269c2aa98e2SPeter Wemm 	 * check the target directory; if you have six X's and it
1270c2aa98e2SPeter Wemm 	 * doesn't exist this runs for a *very* long time.
1271c2aa98e2SPeter Wemm 	 */
1272c2aa98e2SPeter Wemm 	for (start = trv + 1;; --trv) {
1273c2aa98e2SPeter Wemm 		if (trv <= path)
1274c2aa98e2SPeter Wemm 			break;
1275c2aa98e2SPeter Wemm 		if (*trv == '/') {
1276c2aa98e2SPeter Wemm 			*trv = '\0';
1277c2aa98e2SPeter Wemm 			if (stat(path, &sbuf) < 0)
1278c2aa98e2SPeter Wemm 				return(0);
1279c2aa98e2SPeter Wemm 			if (!S_ISDIR(sbuf.st_mode)) {
1280c2aa98e2SPeter Wemm 				errno = ENOTDIR;
1281c2aa98e2SPeter Wemm 				return(0);
1282c2aa98e2SPeter Wemm 			}
1283c2aa98e2SPeter Wemm 			*trv = '/';
1284c2aa98e2SPeter Wemm 			break;
1285c2aa98e2SPeter Wemm 		}
1286c2aa98e2SPeter Wemm 	}
1287c2aa98e2SPeter Wemm 
1288c2aa98e2SPeter Wemm 	for (;;) {
1289c2aa98e2SPeter Wemm 		if (doopen) {
1290c2aa98e2SPeter Wemm 			if ((*doopen =
1291c2aa98e2SPeter Wemm 			    open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
1292c2aa98e2SPeter Wemm 				return(1);
1293c2aa98e2SPeter Wemm 			if (errno != EEXIST)
1294c2aa98e2SPeter Wemm 				return(0);
1295c2aa98e2SPeter Wemm 		}
1296c2aa98e2SPeter Wemm 		else if (stat(path, &sbuf) < 0)
1297c2aa98e2SPeter Wemm 			return(errno == ENOENT ? 1 : 0);
1298c2aa98e2SPeter Wemm 
1299c2aa98e2SPeter Wemm 		/* tricky little algorithm for backward compatibility */
1300c2aa98e2SPeter Wemm 		for (trv = start;;) {
1301c2aa98e2SPeter Wemm 			if (!*trv)
1302c2aa98e2SPeter Wemm 				return(0);
1303c2aa98e2SPeter Wemm 			if (*trv == 'z')
1304c2aa98e2SPeter Wemm 				*trv++ = 'a';
1305c2aa98e2SPeter Wemm 			else {
1306c2aa98e2SPeter Wemm 				if (isascii(*trv) && isdigit(*trv))
1307c2aa98e2SPeter Wemm 					*trv = 'a';
1308c2aa98e2SPeter Wemm 				else
1309c2aa98e2SPeter Wemm 					++*trv;
1310c2aa98e2SPeter Wemm 				break;
1311c2aa98e2SPeter Wemm 			}
1312c2aa98e2SPeter Wemm 		}
1313c2aa98e2SPeter Wemm 	}
1314c2aa98e2SPeter Wemm 	/*NOTREACHED*/
1315c2aa98e2SPeter Wemm }
1316c2aa98e2SPeter Wemm 
1317c2aa98e2SPeter Wemm #endif /* ultrix */
1318