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