1*955eb5e1SGarrett D'Amore /*
2*955eb5e1SGarrett D'Amore * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
3*955eb5e1SGarrett D'Amore * Copyright (c) 1990, 1993, 1994
4*955eb5e1SGarrett D'Amore * The Regents of the University of California. All rights reserved.
5*955eb5e1SGarrett D'Amore *
6*955eb5e1SGarrett D'Amore * By using this file, you agree to the terms and conditions set
7*955eb5e1SGarrett D'Amore * forth in the LICENSE file which can be found at the top level
8*955eb5e1SGarrett D'Amore * of the sendmail distribution.
9*955eb5e1SGarrett D'Amore */
10*955eb5e1SGarrett D'Amore
11*955eb5e1SGarrett D'Amore /*
12*955eb5e1SGarrett D'Amore * Copyright 1994-2007 Sun Microsystems, Inc. All rights reserved.
13*955eb5e1SGarrett D'Amore * Use is subject to license terms.
14*955eb5e1SGarrett D'Amore */
15*955eb5e1SGarrett D'Amore
16*955eb5e1SGarrett D'Amore #ifndef lint
17*955eb5e1SGarrett D'Amore static char copyright[] =
18*955eb5e1SGarrett D'Amore "@(#) Copyright (c) 1990, 1993, 1994\n\
19*955eb5e1SGarrett D'Amore The Regents of the University of California. All rights reserved.\n";
20*955eb5e1SGarrett D'Amore #endif /* not lint */
21*955eb5e1SGarrett D'Amore
22*955eb5e1SGarrett D'Amore #ifndef lint
23*955eb5e1SGarrett D'Amore static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/98";
24*955eb5e1SGarrett D'Amore static char sccsi2[] = "%W% (Sun) %G%";
25*955eb5e1SGarrett D'Amore #endif /* not lint */
26*955eb5e1SGarrett D'Amore
27*955eb5e1SGarrett D'Amore #include <sys/param.h>
28*955eb5e1SGarrett D'Amore #include <sys/stat.h>
29*955eb5e1SGarrett D'Amore #include <sys/socket.h>
30*955eb5e1SGarrett D'Amore #include <sys/file.h>
31*955eb5e1SGarrett D'Amore
32*955eb5e1SGarrett D'Amore #include <netinet/in.h>
33*955eb5e1SGarrett D'Amore
34*955eb5e1SGarrett D'Amore #include <errno.h>
35*955eb5e1SGarrett D'Amore #include <fcntl.h>
36*955eb5e1SGarrett D'Amore #include <netdb.h>
37*955eb5e1SGarrett D'Amore #include <pwd.h>
38*955eb5e1SGarrett D'Amore #include <stdio.h>
39*955eb5e1SGarrett D'Amore #include <stdlib.h>
40*955eb5e1SGarrett D'Amore #include <signal.h>
41*955eb5e1SGarrett D'Amore #include <ctype.h>
42*955eb5e1SGarrett D'Amore #include <string.h>
43*955eb5e1SGarrett D'Amore #include <sysexits.h>
44*955eb5e1SGarrett D'Amore #include <time.h>
45*955eb5e1SGarrett D'Amore #include <unistd.h>
46*955eb5e1SGarrett D'Amore #include <maillock.h>
47*955eb5e1SGarrett D'Amore #include <grp.h>
48*955eb5e1SGarrett D'Amore
49*955eb5e1SGarrett D'Amore #ifdef __STDC__
50*955eb5e1SGarrett D'Amore #include <stdarg.h>
51*955eb5e1SGarrett D'Amore #else
52*955eb5e1SGarrett D'Amore #include <varargs.h>
53*955eb5e1SGarrett D'Amore #endif
54*955eb5e1SGarrett D'Amore
55*955eb5e1SGarrett D'Amore #include <syslog.h>
56*955eb5e1SGarrett D'Amore
57*955eb5e1SGarrett D'Amore #include <sysexits.h>
58*955eb5e1SGarrett D'Amore #include <ctype.h>
59*955eb5e1SGarrett D'Amore
60*955eb5e1SGarrett D'Amore #include <sm/conf.h>
61*955eb5e1SGarrett D'Amore #include <sendmail/pathnames.h>
62*955eb5e1SGarrett D'Amore
63*955eb5e1SGarrett D'Amore /*
64*955eb5e1SGarrett D'Amore ** If you don't have flock, you could try using lockf instead.
65*955eb5e1SGarrett D'Amore */
66*955eb5e1SGarrett D'Amore
67*955eb5e1SGarrett D'Amore #ifdef LDA_USE_LOCKF
68*955eb5e1SGarrett D'Amore # define flock(a, b) lockf(a, b, 0)
69*955eb5e1SGarrett D'Amore # ifdef LOCK_EX
70*955eb5e1SGarrett D'Amore # undef LOCK_EX
71*955eb5e1SGarrett D'Amore # endif /* LOCK_EX */
72*955eb5e1SGarrett D'Amore # define LOCK_EX F_LOCK
73*955eb5e1SGarrett D'Amore #endif /* LDA_USE_LOCKF */
74*955eb5e1SGarrett D'Amore
75*955eb5e1SGarrett D'Amore #ifndef LOCK_EX
76*955eb5e1SGarrett D'Amore # include <sys/file.h>
77*955eb5e1SGarrett D'Amore #endif /* ! LOCK_EX */
78*955eb5e1SGarrett D'Amore
79*955eb5e1SGarrett D'Amore #ifndef MAILER_DAEMON
80*955eb5e1SGarrett D'Amore # define MAILER_DAEMON "MAILER-DAEMON"
81*955eb5e1SGarrett D'Amore #endif
82*955eb5e1SGarrett D'Amore
83*955eb5e1SGarrett D'Amore typedef int bool;
84*955eb5e1SGarrett D'Amore
85*955eb5e1SGarrett D'Amore #define FALSE 0
86*955eb5e1SGarrett D'Amore #define TRUE 1
87*955eb5e1SGarrett D'Amore
88*955eb5e1SGarrett D'Amore bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */
89*955eb5e1SGarrett D'Amore static int eval = EX_OK; /* sysexits.h error value. */
90*955eb5e1SGarrett D'Amore static int lmtpmode = 0;
91*955eb5e1SGarrett D'Amore bool bouncequota = FALSE; /* permanent error when over quota */
92*955eb5e1SGarrett D'Amore
93*955eb5e1SGarrett D'Amore #define _PATH_MAILDIR "/var/mail"
94*955eb5e1SGarrett D'Amore #define _PATH_LOCTMP "/tmp/local.XXXXXX"
95*955eb5e1SGarrett D'Amore #define _PATH_LOCHTMP "/tmp/lochd.XXXXXX"
96*955eb5e1SGarrett D'Amore #define FALSE 0
97*955eb5e1SGarrett D'Amore #define TRUE 1
98*955eb5e1SGarrett D'Amore #define MAXLINE 2048
99*955eb5e1SGarrett D'Amore
100*955eb5e1SGarrett D'Amore static void deliver(int, int, char *, bool);
101*955eb5e1SGarrett D'Amore static void e_to_sys(int);
102*955eb5e1SGarrett D'Amore static void err(const char *fmt, ...);
103*955eb5e1SGarrett D'Amore static void notifybiff(char *);
104*955eb5e1SGarrett D'Amore static void store(char *, int);
105*955eb5e1SGarrett D'Amore static void usage(void);
106*955eb5e1SGarrett D'Amore static void vwarn();
107*955eb5e1SGarrett D'Amore static void warn(const char *fmt, ...);
108*955eb5e1SGarrett D'Amore static void mailerr(const char *, const char *, ...);
109*955eb5e1SGarrett D'Amore static void sigterm_handler();
110*955eb5e1SGarrett D'Amore
111*955eb5e1SGarrett D'Amore static char unix_from_line[MAXLINE];
112*955eb5e1SGarrett D'Amore static int ulen;
113*955eb5e1SGarrett D'Amore static int content_length;
114*955eb5e1SGarrett D'Amore static int bfd, hfd; /* temp file */
115*955eb5e1SGarrett D'Amore static uid_t src_uid, targ_uid, saved_uid;
116*955eb5e1SGarrett D'Amore static int sigterm_caught;
117*955eb5e1SGarrett D'Amore
118*955eb5e1SGarrett D'Amore int
main(argc,argv)119*955eb5e1SGarrett D'Amore main(argc, argv)
120*955eb5e1SGarrett D'Amore int argc;
121*955eb5e1SGarrett D'Amore char *argv[];
122*955eb5e1SGarrett D'Amore {
123*955eb5e1SGarrett D'Amore struct passwd *pw;
124*955eb5e1SGarrett D'Amore int ch;
125*955eb5e1SGarrett D'Amore uid_t uid;
126*955eb5e1SGarrett D'Amore char *from;
127*955eb5e1SGarrett D'Amore struct group *grpptr;
128*955eb5e1SGarrett D'Amore void dolmtp();
129*955eb5e1SGarrett D'Amore
130*955eb5e1SGarrett D'Amore openlog("mail.local", 0, LOG_MAIL);
131*955eb5e1SGarrett D'Amore
132*955eb5e1SGarrett D'Amore from = NULL;
133*955eb5e1SGarrett D'Amore pw = NULL;
134*955eb5e1SGarrett D'Amore sigterm_caught = FALSE;
135*955eb5e1SGarrett D'Amore
136*955eb5e1SGarrett D'Amore (void) sigset(SIGTERM, sigterm_handler);
137*955eb5e1SGarrett D'Amore
138*955eb5e1SGarrett D'Amore while ((ch = getopt(argc, argv, "7bdf:r:l")) != EOF)
139*955eb5e1SGarrett D'Amore switch (ch) {
140*955eb5e1SGarrett D'Amore case '7': /* Do not advertise 8BITMIME */
141*955eb5e1SGarrett D'Amore EightBitMime = FALSE;
142*955eb5e1SGarrett D'Amore break;
143*955eb5e1SGarrett D'Amore
144*955eb5e1SGarrett D'Amore case 'b': /* bounce mail when over quota. */
145*955eb5e1SGarrett D'Amore bouncequota = TRUE;
146*955eb5e1SGarrett D'Amore break;
147*955eb5e1SGarrett D'Amore
148*955eb5e1SGarrett D'Amore case 'd': /* Backward compatible. */
149*955eb5e1SGarrett D'Amore break;
150*955eb5e1SGarrett D'Amore case 'f':
151*955eb5e1SGarrett D'Amore case 'r': /* Backward compatible. */
152*955eb5e1SGarrett D'Amore if (from != NULL) {
153*955eb5e1SGarrett D'Amore warn("multiple -f options");
154*955eb5e1SGarrett D'Amore usage();
155*955eb5e1SGarrett D'Amore }
156*955eb5e1SGarrett D'Amore from = optarg;
157*955eb5e1SGarrett D'Amore break;
158*955eb5e1SGarrett D'Amore case 'l':
159*955eb5e1SGarrett D'Amore lmtpmode++;
160*955eb5e1SGarrett D'Amore break;
161*955eb5e1SGarrett D'Amore case '?':
162*955eb5e1SGarrett D'Amore default:
163*955eb5e1SGarrett D'Amore usage();
164*955eb5e1SGarrett D'Amore }
165*955eb5e1SGarrett D'Amore argc -= optind;
166*955eb5e1SGarrett D'Amore argv += optind;
167*955eb5e1SGarrett D'Amore
168*955eb5e1SGarrett D'Amore notifybiff(NULL); /* initialize biff structures */
169*955eb5e1SGarrett D'Amore
170*955eb5e1SGarrett D'Amore /*
171*955eb5e1SGarrett D'Amore * We expect sendmail will invoke us with saved id 0
172*955eb5e1SGarrett D'Amore * We then do setgid and setuid defore delivery
173*955eb5e1SGarrett D'Amore * setgid to mail group
174*955eb5e1SGarrett D'Amore */
175*955eb5e1SGarrett D'Amore if ((grpptr = getgrnam("mail")) != NULL)
176*955eb5e1SGarrett D'Amore (void) setgid(grpptr->gr_gid);
177*955eb5e1SGarrett D'Amore saved_uid = geteuid();
178*955eb5e1SGarrett D'Amore
179*955eb5e1SGarrett D'Amore if (lmtpmode) {
180*955eb5e1SGarrett D'Amore if (saved_uid != 0) {
181*955eb5e1SGarrett D'Amore warn("only super-user can use -l option");
182*955eb5e1SGarrett D'Amore exit(EX_CANTCREAT);
183*955eb5e1SGarrett D'Amore }
184*955eb5e1SGarrett D'Amore dolmtp(bouncequota);
185*955eb5e1SGarrett D'Amore }
186*955eb5e1SGarrett D'Amore
187*955eb5e1SGarrett D'Amore if (!*argv)
188*955eb5e1SGarrett D'Amore usage();
189*955eb5e1SGarrett D'Amore
190*955eb5e1SGarrett D'Amore /*
191*955eb5e1SGarrett D'Amore * If from not specified, use the name from getlogin() if the
192*955eb5e1SGarrett D'Amore * uid matches, otherwise, use the name from the password file
193*955eb5e1SGarrett D'Amore * corresponding to the uid.
194*955eb5e1SGarrett D'Amore */
195*955eb5e1SGarrett D'Amore uid = getuid();
196*955eb5e1SGarrett D'Amore if (!from && (!(from = getlogin()) ||
197*955eb5e1SGarrett D'Amore !(pw = getpwnam(from)) || pw->pw_uid != uid))
198*955eb5e1SGarrett D'Amore from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
199*955eb5e1SGarrett D'Amore src_uid = pw ? pw->pw_uid : uid;
200*955eb5e1SGarrett D'Amore
201*955eb5e1SGarrett D'Amore /*
202*955eb5e1SGarrett D'Amore * There is no way to distinguish the error status of one delivery
203*955eb5e1SGarrett D'Amore * from the rest of the deliveries. So, if we failed hard on one
204*955eb5e1SGarrett D'Amore * or more deliveries, but had no failures on any of the others, we
205*955eb5e1SGarrett D'Amore * return a hard failure. If we failed temporarily on one or more
206*955eb5e1SGarrett D'Amore * deliveries, we return a temporary failure regardless of the other
207*955eb5e1SGarrett D'Amore * failures. This results in the delivery being reattempted later
208*955eb5e1SGarrett D'Amore * at the expense of repeated failures and multiple deliveries.
209*955eb5e1SGarrett D'Amore */
210*955eb5e1SGarrett D'Amore
211*955eb5e1SGarrett D'Amore for (store(from, 0); *argv; ++argv)
212*955eb5e1SGarrett D'Amore deliver(hfd, bfd, *argv, bouncequota);
213*955eb5e1SGarrett D'Amore return (eval);
214*955eb5e1SGarrett D'Amore }
215*955eb5e1SGarrett D'Amore
216*955eb5e1SGarrett D'Amore void
sigterm_handler()217*955eb5e1SGarrett D'Amore sigterm_handler()
218*955eb5e1SGarrett D'Amore {
219*955eb5e1SGarrett D'Amore sigterm_caught = TRUE;
220*955eb5e1SGarrett D'Amore (void) sigignore(SIGTERM);
221*955eb5e1SGarrett D'Amore }
222*955eb5e1SGarrett D'Amore
223*955eb5e1SGarrett D'Amore char *
parseaddr(s)224*955eb5e1SGarrett D'Amore parseaddr(s)
225*955eb5e1SGarrett D'Amore char *s;
226*955eb5e1SGarrett D'Amore {
227*955eb5e1SGarrett D'Amore char *p;
228*955eb5e1SGarrett D'Amore int len;
229*955eb5e1SGarrett D'Amore
230*955eb5e1SGarrett D'Amore if (*s++ != '<')
231*955eb5e1SGarrett D'Amore return NULL;
232*955eb5e1SGarrett D'Amore
233*955eb5e1SGarrett D'Amore p = s;
234*955eb5e1SGarrett D'Amore
235*955eb5e1SGarrett D'Amore /* at-domain-list */
236*955eb5e1SGarrett D'Amore while (*p == '@') {
237*955eb5e1SGarrett D'Amore p++;
238*955eb5e1SGarrett D'Amore if (*p == '[') {
239*955eb5e1SGarrett D'Amore p++;
240*955eb5e1SGarrett D'Amore while (isascii(*p) &&
241*955eb5e1SGarrett D'Amore (isalnum(*p) || *p == '.' ||
242*955eb5e1SGarrett D'Amore *p == '-' || *p == ':'))
243*955eb5e1SGarrett D'Amore p++;
244*955eb5e1SGarrett D'Amore if (*p++ != ']')
245*955eb5e1SGarrett D'Amore return NULL;
246*955eb5e1SGarrett D'Amore } else {
247*955eb5e1SGarrett D'Amore while ((isascii(*p) && isalnum(*p)) ||
248*955eb5e1SGarrett D'Amore strchr(".-_", *p))
249*955eb5e1SGarrett D'Amore p++;
250*955eb5e1SGarrett D'Amore }
251*955eb5e1SGarrett D'Amore if (*p == ',' && p[1] == '@')
252*955eb5e1SGarrett D'Amore p++;
253*955eb5e1SGarrett D'Amore else if (*p == ':' && p[1] != '@')
254*955eb5e1SGarrett D'Amore p++;
255*955eb5e1SGarrett D'Amore else
256*955eb5e1SGarrett D'Amore return NULL;
257*955eb5e1SGarrett D'Amore }
258*955eb5e1SGarrett D'Amore
259*955eb5e1SGarrett D'Amore s = p;
260*955eb5e1SGarrett D'Amore
261*955eb5e1SGarrett D'Amore /* local-part */
262*955eb5e1SGarrett D'Amore if (*p == '\"') {
263*955eb5e1SGarrett D'Amore p++;
264*955eb5e1SGarrett D'Amore while (*p && *p != '\"') {
265*955eb5e1SGarrett D'Amore if (*p == '\\') {
266*955eb5e1SGarrett D'Amore if (!*++p)
267*955eb5e1SGarrett D'Amore return NULL;
268*955eb5e1SGarrett D'Amore }
269*955eb5e1SGarrett D'Amore p++;
270*955eb5e1SGarrett D'Amore }
271*955eb5e1SGarrett D'Amore if (!*p++)
272*955eb5e1SGarrett D'Amore return NULL;
273*955eb5e1SGarrett D'Amore } else {
274*955eb5e1SGarrett D'Amore while (*p && *p != '@' && *p != '>') {
275*955eb5e1SGarrett D'Amore if (*p == '\\') {
276*955eb5e1SGarrett D'Amore if (!*++p)
277*955eb5e1SGarrett D'Amore return NULL;
278*955eb5e1SGarrett D'Amore } else {
279*955eb5e1SGarrett D'Amore if (*p <= ' ' || (*p & 128) ||
280*955eb5e1SGarrett D'Amore strchr("<>()[]\\,;:\"", *p))
281*955eb5e1SGarrett D'Amore return NULL;
282*955eb5e1SGarrett D'Amore }
283*955eb5e1SGarrett D'Amore p++;
284*955eb5e1SGarrett D'Amore }
285*955eb5e1SGarrett D'Amore }
286*955eb5e1SGarrett D'Amore
287*955eb5e1SGarrett D'Amore /* @domain */
288*955eb5e1SGarrett D'Amore if (*p == '@') {
289*955eb5e1SGarrett D'Amore p++;
290*955eb5e1SGarrett D'Amore if (*p == '[') {
291*955eb5e1SGarrett D'Amore p++;
292*955eb5e1SGarrett D'Amore while (isascii(*p) &&
293*955eb5e1SGarrett D'Amore (isalnum(*p) || *p == '.' ||
294*955eb5e1SGarrett D'Amore *p == '-' || *p == ':'))
295*955eb5e1SGarrett D'Amore p++;
296*955eb5e1SGarrett D'Amore if (*p++ != ']')
297*955eb5e1SGarrett D'Amore return NULL;
298*955eb5e1SGarrett D'Amore } else {
299*955eb5e1SGarrett D'Amore while ((isascii(*p) && isalnum(*p)) ||
300*955eb5e1SGarrett D'Amore strchr(".-_", *p))
301*955eb5e1SGarrett D'Amore p++;
302*955eb5e1SGarrett D'Amore }
303*955eb5e1SGarrett D'Amore }
304*955eb5e1SGarrett D'Amore
305*955eb5e1SGarrett D'Amore if (*p++ != '>')
306*955eb5e1SGarrett D'Amore return NULL;
307*955eb5e1SGarrett D'Amore if (*p && *p != ' ')
308*955eb5e1SGarrett D'Amore return NULL;
309*955eb5e1SGarrett D'Amore len = p - s - 1;
310*955eb5e1SGarrett D'Amore
311*955eb5e1SGarrett D'Amore if (*s == '\0' || len <= 0)
312*955eb5e1SGarrett D'Amore {
313*955eb5e1SGarrett D'Amore s = MAILER_DAEMON;
314*955eb5e1SGarrett D'Amore len = strlen(s);
315*955eb5e1SGarrett D'Amore }
316*955eb5e1SGarrett D'Amore
317*955eb5e1SGarrett D'Amore p = malloc(len + 1);
318*955eb5e1SGarrett D'Amore if (p == NULL) {
319*955eb5e1SGarrett D'Amore printf("421 4.3.0 memory exhausted\r\n");
320*955eb5e1SGarrett D'Amore exit(EX_TEMPFAIL);
321*955eb5e1SGarrett D'Amore }
322*955eb5e1SGarrett D'Amore
323*955eb5e1SGarrett D'Amore strncpy(p, s, len);
324*955eb5e1SGarrett D'Amore p[len] = '\0';
325*955eb5e1SGarrett D'Amore return p;
326*955eb5e1SGarrett D'Amore }
327*955eb5e1SGarrett D'Amore
328*955eb5e1SGarrett D'Amore char *
process_recipient(addr)329*955eb5e1SGarrett D'Amore process_recipient(addr)
330*955eb5e1SGarrett D'Amore char *addr;
331*955eb5e1SGarrett D'Amore {
332*955eb5e1SGarrett D'Amore if (getpwnam(addr) == NULL) {
333*955eb5e1SGarrett D'Amore return "550 5.1.1 user unknown";
334*955eb5e1SGarrett D'Amore }
335*955eb5e1SGarrett D'Amore
336*955eb5e1SGarrett D'Amore return NULL;
337*955eb5e1SGarrett D'Amore }
338*955eb5e1SGarrett D'Amore
339*955eb5e1SGarrett D'Amore #define RCPT_GROW 30
340*955eb5e1SGarrett D'Amore
341*955eb5e1SGarrett D'Amore void
dolmtp(bouncequota)342*955eb5e1SGarrett D'Amore dolmtp(bouncequota)
343*955eb5e1SGarrett D'Amore bool bouncequota;
344*955eb5e1SGarrett D'Amore {
345*955eb5e1SGarrett D'Amore char *return_path = NULL;
346*955eb5e1SGarrett D'Amore char **rcpt_addr = NULL;
347*955eb5e1SGarrett D'Amore int rcpt_num = 0;
348*955eb5e1SGarrett D'Amore int rcpt_alloc = 0;
349*955eb5e1SGarrett D'Amore bool gotlhlo = FALSE;
350*955eb5e1SGarrett D'Amore char myhostname[MAXHOSTNAMELEN];
351*955eb5e1SGarrett D'Amore char buf[4096];
352*955eb5e1SGarrett D'Amore char *err;
353*955eb5e1SGarrett D'Amore char *p;
354*955eb5e1SGarrett D'Amore int i;
355*955eb5e1SGarrett D'Amore
356*955eb5e1SGarrett D'Amore gethostname(myhostname, sizeof myhostname - 1);
357*955eb5e1SGarrett D'Amore
358*955eb5e1SGarrett D'Amore printf("220 %s LMTP ready\r\n", myhostname);
359*955eb5e1SGarrett D'Amore for (;;) {
360*955eb5e1SGarrett D'Amore if (sigterm_caught) {
361*955eb5e1SGarrett D'Amore for (; rcpt_num > 0; rcpt_num--)
362*955eb5e1SGarrett D'Amore printf("451 4.3.0 shutting down\r\n");
363*955eb5e1SGarrett D'Amore exit(EX_OK);
364*955eb5e1SGarrett D'Amore }
365*955eb5e1SGarrett D'Amore fflush(stdout);
366*955eb5e1SGarrett D'Amore if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
367*955eb5e1SGarrett D'Amore exit(EX_OK);
368*955eb5e1SGarrett D'Amore }
369*955eb5e1SGarrett D'Amore p = buf + strlen(buf) - 1;
370*955eb5e1SGarrett D'Amore if (p >= buf && *p == '\n')
371*955eb5e1SGarrett D'Amore *p-- = '\0';
372*955eb5e1SGarrett D'Amore if (p >= buf && *p == '\r')
373*955eb5e1SGarrett D'Amore *p-- = '\0';
374*955eb5e1SGarrett D'Amore
375*955eb5e1SGarrett D'Amore switch (buf[0]) {
376*955eb5e1SGarrett D'Amore
377*955eb5e1SGarrett D'Amore case 'd':
378*955eb5e1SGarrett D'Amore case 'D':
379*955eb5e1SGarrett D'Amore if (strcasecmp(buf, "data") == 0) {
380*955eb5e1SGarrett D'Amore if (rcpt_num == 0) {
381*955eb5e1SGarrett D'Amore printf("503 5.5.1 No recipients\r\n");
382*955eb5e1SGarrett D'Amore continue;
383*955eb5e1SGarrett D'Amore }
384*955eb5e1SGarrett D'Amore store(return_path, rcpt_num);
385*955eb5e1SGarrett D'Amore if (bfd == -1 || hfd == -1)
386*955eb5e1SGarrett D'Amore continue;
387*955eb5e1SGarrett D'Amore
388*955eb5e1SGarrett D'Amore for (i = 0; i < rcpt_num; i++) {
389*955eb5e1SGarrett D'Amore p = strchr(rcpt_addr[i], '+');
390*955eb5e1SGarrett D'Amore if (p != NULL)
391*955eb5e1SGarrett D'Amore *p++ = '\0';
392*955eb5e1SGarrett D'Amore deliver(hfd, bfd, rcpt_addr[i],
393*955eb5e1SGarrett D'Amore bouncequota);
394*955eb5e1SGarrett D'Amore }
395*955eb5e1SGarrett D'Amore close(bfd);
396*955eb5e1SGarrett D'Amore close(hfd);
397*955eb5e1SGarrett D'Amore goto rset;
398*955eb5e1SGarrett D'Amore }
399*955eb5e1SGarrett D'Amore goto syntaxerr;
400*955eb5e1SGarrett D'Amore /* NOTREACHED */
401*955eb5e1SGarrett D'Amore break;
402*955eb5e1SGarrett D'Amore
403*955eb5e1SGarrett D'Amore case 'l':
404*955eb5e1SGarrett D'Amore case 'L':
405*955eb5e1SGarrett D'Amore if (strncasecmp(buf, "lhlo ", 5) == 0)
406*955eb5e1SGarrett D'Amore {
407*955eb5e1SGarrett D'Amore /* check for duplicate per RFC 1651 4.2 */
408*955eb5e1SGarrett D'Amore if (gotlhlo)
409*955eb5e1SGarrett D'Amore {
410*955eb5e1SGarrett D'Amore printf("503 %s Duplicate LHLO\r\n",
411*955eb5e1SGarrett D'Amore myhostname);
412*955eb5e1SGarrett D'Amore continue;
413*955eb5e1SGarrett D'Amore }
414*955eb5e1SGarrett D'Amore gotlhlo = TRUE;
415*955eb5e1SGarrett D'Amore printf("250-%s\r\n", myhostname);
416*955eb5e1SGarrett D'Amore if (EightBitMime)
417*955eb5e1SGarrett D'Amore printf("250-8BITMIME\r\n");
418*955eb5e1SGarrett D'Amore printf("250-ENHANCEDSTATUSCODES\r\n");
419*955eb5e1SGarrett D'Amore printf("250 PIPELINING\r\n");
420*955eb5e1SGarrett D'Amore continue;
421*955eb5e1SGarrett D'Amore }
422*955eb5e1SGarrett D'Amore goto syntaxerr;
423*955eb5e1SGarrett D'Amore /* NOTREACHED */
424*955eb5e1SGarrett D'Amore break;
425*955eb5e1SGarrett D'Amore
426*955eb5e1SGarrett D'Amore case 'm':
427*955eb5e1SGarrett D'Amore case 'M':
428*955eb5e1SGarrett D'Amore if (strncasecmp(buf, "mail ", 5) == 0) {
429*955eb5e1SGarrett D'Amore if (return_path != NULL) {
430*955eb5e1SGarrett D'Amore printf("503 5.5.1 Nested MAIL command\r\n");
431*955eb5e1SGarrett D'Amore continue;
432*955eb5e1SGarrett D'Amore }
433*955eb5e1SGarrett D'Amore if (strncasecmp(buf+5, "from:", 5) != 0 ||
434*955eb5e1SGarrett D'Amore ((return_path = parseaddr(buf+10)) == NULL)) {
435*955eb5e1SGarrett D'Amore printf("501 5.5.4 Syntax error in parameters\r\n");
436*955eb5e1SGarrett D'Amore continue;
437*955eb5e1SGarrett D'Amore }
438*955eb5e1SGarrett D'Amore printf("250 2.5.0 ok\r\n");
439*955eb5e1SGarrett D'Amore continue;
440*955eb5e1SGarrett D'Amore }
441*955eb5e1SGarrett D'Amore goto syntaxerr;
442*955eb5e1SGarrett D'Amore
443*955eb5e1SGarrett D'Amore case 'n':
444*955eb5e1SGarrett D'Amore case 'N':
445*955eb5e1SGarrett D'Amore if (strcasecmp(buf, "noop") == 0) {
446*955eb5e1SGarrett D'Amore printf("250 2.0.0 ok\r\n");
447*955eb5e1SGarrett D'Amore continue;
448*955eb5e1SGarrett D'Amore }
449*955eb5e1SGarrett D'Amore goto syntaxerr;
450*955eb5e1SGarrett D'Amore
451*955eb5e1SGarrett D'Amore case 'q':
452*955eb5e1SGarrett D'Amore case 'Q':
453*955eb5e1SGarrett D'Amore if (strcasecmp(buf, "quit") == 0) {
454*955eb5e1SGarrett D'Amore printf("221 2.0.0 bye\r\n");
455*955eb5e1SGarrett D'Amore exit(EX_OK);
456*955eb5e1SGarrett D'Amore }
457*955eb5e1SGarrett D'Amore goto syntaxerr;
458*955eb5e1SGarrett D'Amore
459*955eb5e1SGarrett D'Amore case 'r':
460*955eb5e1SGarrett D'Amore case 'R':
461*955eb5e1SGarrett D'Amore if (strncasecmp(buf, "rcpt ", 5) == 0) {
462*955eb5e1SGarrett D'Amore if (return_path == NULL) {
463*955eb5e1SGarrett D'Amore printf("503 5.5.1 Need MAIL command\r\n");
464*955eb5e1SGarrett D'Amore continue;
465*955eb5e1SGarrett D'Amore }
466*955eb5e1SGarrett D'Amore if (rcpt_num >= rcpt_alloc) {
467*955eb5e1SGarrett D'Amore rcpt_alloc += RCPT_GROW;
468*955eb5e1SGarrett D'Amore rcpt_addr = (char **)
469*955eb5e1SGarrett D'Amore realloc((char *)rcpt_addr,
470*955eb5e1SGarrett D'Amore rcpt_alloc * sizeof(char **));
471*955eb5e1SGarrett D'Amore if (rcpt_addr == NULL) {
472*955eb5e1SGarrett D'Amore printf("421 4.3.0 memory exhausted\r\n");
473*955eb5e1SGarrett D'Amore exit(EX_TEMPFAIL);
474*955eb5e1SGarrett D'Amore }
475*955eb5e1SGarrett D'Amore }
476*955eb5e1SGarrett D'Amore if (strncasecmp(buf+5, "to:", 3) != 0 ||
477*955eb5e1SGarrett D'Amore ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) {
478*955eb5e1SGarrett D'Amore printf("501 5.5.4 Syntax error in parameters\r\n");
479*955eb5e1SGarrett D'Amore continue;
480*955eb5e1SGarrett D'Amore }
481*955eb5e1SGarrett D'Amore if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) {
482*955eb5e1SGarrett D'Amore printf("%s\r\n", err);
483*955eb5e1SGarrett D'Amore continue;
484*955eb5e1SGarrett D'Amore }
485*955eb5e1SGarrett D'Amore rcpt_num++;
486*955eb5e1SGarrett D'Amore printf("250 2.1.5 ok\r\n");
487*955eb5e1SGarrett D'Amore continue;
488*955eb5e1SGarrett D'Amore }
489*955eb5e1SGarrett D'Amore else if (strcasecmp(buf, "rset") == 0) {
490*955eb5e1SGarrett D'Amore printf("250 2.0.0 ok\r\n");
491*955eb5e1SGarrett D'Amore
492*955eb5e1SGarrett D'Amore rset:
493*955eb5e1SGarrett D'Amore while (rcpt_num > 0) {
494*955eb5e1SGarrett D'Amore free(rcpt_addr[--rcpt_num]);
495*955eb5e1SGarrett D'Amore }
496*955eb5e1SGarrett D'Amore if (return_path != NULL)
497*955eb5e1SGarrett D'Amore free(return_path);
498*955eb5e1SGarrett D'Amore return_path = NULL;
499*955eb5e1SGarrett D'Amore continue;
500*955eb5e1SGarrett D'Amore }
501*955eb5e1SGarrett D'Amore goto syntaxerr;
502*955eb5e1SGarrett D'Amore
503*955eb5e1SGarrett D'Amore case 'v':
504*955eb5e1SGarrett D'Amore case 'V':
505*955eb5e1SGarrett D'Amore if (strncasecmp(buf, "vrfy ", 5) == 0) {
506*955eb5e1SGarrett D'Amore printf("252 2.3.3 try RCPT to attempt delivery\r\n");
507*955eb5e1SGarrett D'Amore continue;
508*955eb5e1SGarrett D'Amore }
509*955eb5e1SGarrett D'Amore goto syntaxerr;
510*955eb5e1SGarrett D'Amore
511*955eb5e1SGarrett D'Amore default:
512*955eb5e1SGarrett D'Amore syntaxerr:
513*955eb5e1SGarrett D'Amore printf("500 5.5.2 Syntax error\r\n");
514*955eb5e1SGarrett D'Amore continue;
515*955eb5e1SGarrett D'Amore }
516*955eb5e1SGarrett D'Amore }
517*955eb5e1SGarrett D'Amore }
518*955eb5e1SGarrett D'Amore
519*955eb5e1SGarrett D'Amore static void
store(from,lmtprcpts)520*955eb5e1SGarrett D'Amore store(from, lmtprcpts)
521*955eb5e1SGarrett D'Amore char *from;
522*955eb5e1SGarrett D'Amore int lmtprcpts;
523*955eb5e1SGarrett D'Amore {
524*955eb5e1SGarrett D'Amore FILE *fp = NULL;
525*955eb5e1SGarrett D'Amore time_t tval;
526*955eb5e1SGarrett D'Amore bool fullline = TRUE; /* current line is terminated */
527*955eb5e1SGarrett D'Amore bool prevfl; /* previous line was terminated */
528*955eb5e1SGarrett D'Amore char line[MAXLINE];
529*955eb5e1SGarrett D'Amore FILE *bfp, *hfp;
530*955eb5e1SGarrett D'Amore char *btn, *htn;
531*955eb5e1SGarrett D'Amore int in_header_section;
532*955eb5e1SGarrett D'Amore int newfd;
533*955eb5e1SGarrett D'Amore
534*955eb5e1SGarrett D'Amore bfd = -1;
535*955eb5e1SGarrett D'Amore hfd = -1;
536*955eb5e1SGarrett D'Amore btn = strdup(_PATH_LOCTMP);
537*955eb5e1SGarrett D'Amore if ((bfd = mkstemp(btn)) == -1 || (bfp = fdopen(bfd, "w+")) == NULL) {
538*955eb5e1SGarrett D'Amore if (bfd != -1)
539*955eb5e1SGarrett D'Amore (void) close(bfd);
540*955eb5e1SGarrett D'Amore if (lmtprcpts) {
541*955eb5e1SGarrett D'Amore printf("451 4.3.0 unable to open temporary file\r\n");
542*955eb5e1SGarrett D'Amore return;
543*955eb5e1SGarrett D'Amore } else {
544*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "unable to open temporary file");
545*955eb5e1SGarrett D'Amore exit(eval);
546*955eb5e1SGarrett D'Amore }
547*955eb5e1SGarrett D'Amore }
548*955eb5e1SGarrett D'Amore (void) unlink(btn);
549*955eb5e1SGarrett D'Amore free(btn);
550*955eb5e1SGarrett D'Amore
551*955eb5e1SGarrett D'Amore if (lmtpmode) {
552*955eb5e1SGarrett D'Amore printf("354 go ahead\r\n");
553*955eb5e1SGarrett D'Amore fflush(stdout);
554*955eb5e1SGarrett D'Amore }
555*955eb5e1SGarrett D'Amore
556*955eb5e1SGarrett D'Amore htn = strdup(_PATH_LOCHTMP);
557*955eb5e1SGarrett D'Amore if ((hfd = mkstemp(htn)) == -1 || (hfp = fdopen(hfd, "w+")) == NULL) {
558*955eb5e1SGarrett D'Amore if (hfd != -1)
559*955eb5e1SGarrett D'Amore (void) close(hfd);
560*955eb5e1SGarrett D'Amore e_to_sys(errno);
561*955eb5e1SGarrett D'Amore err("unable to open temporary file");
562*955eb5e1SGarrett D'Amore }
563*955eb5e1SGarrett D'Amore (void) unlink(htn);
564*955eb5e1SGarrett D'Amore free(htn);
565*955eb5e1SGarrett D'Amore
566*955eb5e1SGarrett D'Amore in_header_section = TRUE;
567*955eb5e1SGarrett D'Amore content_length = 0;
568*955eb5e1SGarrett D'Amore fp = hfp;
569*955eb5e1SGarrett D'Amore
570*955eb5e1SGarrett D'Amore line[0] = '\0';
571*955eb5e1SGarrett D'Amore while (fgets(line, sizeof(line), stdin) != (char *)NULL)
572*955eb5e1SGarrett D'Amore {
573*955eb5e1SGarrett D'Amore size_t line_len = 0;
574*955eb5e1SGarrett D'Amore int peek;
575*955eb5e1SGarrett D'Amore
576*955eb5e1SGarrett D'Amore prevfl = fullline; /* preserve state of previous line */
577*955eb5e1SGarrett D'Amore while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
578*955eb5e1SGarrett D'Amore line_len++;
579*955eb5e1SGarrett D'Amore line_len++;
580*955eb5e1SGarrett D'Amore
581*955eb5e1SGarrett D'Amore /* Check for dot-stuffing */
582*955eb5e1SGarrett D'Amore if (prevfl && lmtprcpts && line[0] == '.')
583*955eb5e1SGarrett D'Amore {
584*955eb5e1SGarrett D'Amore if (line[1] == '\n' ||
585*955eb5e1SGarrett D'Amore (line[1] == '\r' && line[2] == '\n'))
586*955eb5e1SGarrett D'Amore goto lmtpdot;
587*955eb5e1SGarrett D'Amore memcpy(line, line + 1, line_len);
588*955eb5e1SGarrett D'Amore line_len--;
589*955eb5e1SGarrett D'Amore }
590*955eb5e1SGarrett D'Amore
591*955eb5e1SGarrett D'Amore /* Check to see if we have the full line from fgets() */
592*955eb5e1SGarrett D'Amore fullline = FALSE;
593*955eb5e1SGarrett D'Amore if (line_len > 0)
594*955eb5e1SGarrett D'Amore {
595*955eb5e1SGarrett D'Amore if (line[line_len - 1] == '\n')
596*955eb5e1SGarrett D'Amore {
597*955eb5e1SGarrett D'Amore if (line_len >= 2 &&
598*955eb5e1SGarrett D'Amore line[line_len - 2] == '\r')
599*955eb5e1SGarrett D'Amore {
600*955eb5e1SGarrett D'Amore line[line_len - 2] = '\n';
601*955eb5e1SGarrett D'Amore line[line_len - 1] = '\0';
602*955eb5e1SGarrett D'Amore line_len--;
603*955eb5e1SGarrett D'Amore }
604*955eb5e1SGarrett D'Amore fullline = TRUE;
605*955eb5e1SGarrett D'Amore }
606*955eb5e1SGarrett D'Amore else if (line[line_len - 1] == '\r')
607*955eb5e1SGarrett D'Amore {
608*955eb5e1SGarrett D'Amore /* Did we just miss the CRLF? */
609*955eb5e1SGarrett D'Amore peek = fgetc(stdin);
610*955eb5e1SGarrett D'Amore if (peek == '\n')
611*955eb5e1SGarrett D'Amore {
612*955eb5e1SGarrett D'Amore line[line_len - 1] = '\n';
613*955eb5e1SGarrett D'Amore fullline = TRUE;
614*955eb5e1SGarrett D'Amore }
615*955eb5e1SGarrett D'Amore else
616*955eb5e1SGarrett D'Amore (void) ungetc(peek, stdin);
617*955eb5e1SGarrett D'Amore }
618*955eb5e1SGarrett D'Amore }
619*955eb5e1SGarrett D'Amore else
620*955eb5e1SGarrett D'Amore fullline = TRUE;
621*955eb5e1SGarrett D'Amore
622*955eb5e1SGarrett D'Amore if (prevfl && line[0] == '\n' && in_header_section) {
623*955eb5e1SGarrett D'Amore in_header_section = FALSE;
624*955eb5e1SGarrett D'Amore if (fflush(fp) == EOF || ferror(fp)) {
625*955eb5e1SGarrett D'Amore if (lmtprcpts) {
626*955eb5e1SGarrett D'Amore while (lmtprcpts--)
627*955eb5e1SGarrett D'Amore printf("451 4.3.0 temporary file write error\r\n");
628*955eb5e1SGarrett D'Amore fclose(fp);
629*955eb5e1SGarrett D'Amore return;
630*955eb5e1SGarrett D'Amore } else {
631*955eb5e1SGarrett D'Amore mailerr("451 4.3.0",
632*955eb5e1SGarrett D'Amore "temporary file write error");
633*955eb5e1SGarrett D'Amore fclose(fp);
634*955eb5e1SGarrett D'Amore exit(eval);
635*955eb5e1SGarrett D'Amore }
636*955eb5e1SGarrett D'Amore }
637*955eb5e1SGarrett D'Amore fp = bfp;
638*955eb5e1SGarrett D'Amore continue;
639*955eb5e1SGarrett D'Amore }
640*955eb5e1SGarrett D'Amore
641*955eb5e1SGarrett D'Amore if (in_header_section) {
642*955eb5e1SGarrett D'Amore if (strncasecmp("Content-Length:", line, 15) == 0) {
643*955eb5e1SGarrett D'Amore continue; /* skip this header */
644*955eb5e1SGarrett D'Amore }
645*955eb5e1SGarrett D'Amore } else
646*955eb5e1SGarrett D'Amore content_length += strlen(line);
647*955eb5e1SGarrett D'Amore (void) fwrite(line, sizeof(char), line_len, fp);
648*955eb5e1SGarrett D'Amore if (ferror(fp)) {
649*955eb5e1SGarrett D'Amore if (lmtprcpts) {
650*955eb5e1SGarrett D'Amore while (lmtprcpts--)
651*955eb5e1SGarrett D'Amore printf("451 4.3.0 temporary file write error\r\n");
652*955eb5e1SGarrett D'Amore fclose(fp);
653*955eb5e1SGarrett D'Amore return;
654*955eb5e1SGarrett D'Amore } else {
655*955eb5e1SGarrett D'Amore mailerr("451 4.3.0",
656*955eb5e1SGarrett D'Amore "temporary file write error");
657*955eb5e1SGarrett D'Amore fclose(fp);
658*955eb5e1SGarrett D'Amore exit(eval);
659*955eb5e1SGarrett D'Amore }
660*955eb5e1SGarrett D'Amore }
661*955eb5e1SGarrett D'Amore }
662*955eb5e1SGarrett D'Amore if (sigterm_caught) {
663*955eb5e1SGarrett D'Amore if (lmtprcpts)
664*955eb5e1SGarrett D'Amore while (lmtprcpts--)
665*955eb5e1SGarrett D'Amore printf("451 4.3.0 shutting down\r\n");
666*955eb5e1SGarrett D'Amore else
667*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
668*955eb5e1SGarrett D'Amore fclose(fp);
669*955eb5e1SGarrett D'Amore exit(eval);
670*955eb5e1SGarrett D'Amore }
671*955eb5e1SGarrett D'Amore
672*955eb5e1SGarrett D'Amore if (lmtprcpts) {
673*955eb5e1SGarrett D'Amore /* Got a premature EOF -- toss message and exit */
674*955eb5e1SGarrett D'Amore exit(EX_OK);
675*955eb5e1SGarrett D'Amore }
676*955eb5e1SGarrett D'Amore
677*955eb5e1SGarrett D'Amore /* If message not newline terminated, need an extra. */
678*955eb5e1SGarrett D'Amore if (!strchr(line, '\n')) {
679*955eb5e1SGarrett D'Amore (void) putc('\n', fp);
680*955eb5e1SGarrett D'Amore content_length++;
681*955eb5e1SGarrett D'Amore }
682*955eb5e1SGarrett D'Amore
683*955eb5e1SGarrett D'Amore lmtpdot:
684*955eb5e1SGarrett D'Amore
685*955eb5e1SGarrett D'Amore /* Output a newline; note, empty messages are allowed. */
686*955eb5e1SGarrett D'Amore (void) putc('\n', fp);
687*955eb5e1SGarrett D'Amore
688*955eb5e1SGarrett D'Amore if (fflush(fp) == EOF || ferror(fp)) {
689*955eb5e1SGarrett D'Amore if (lmtprcpts) {
690*955eb5e1SGarrett D'Amore while (lmtprcpts--) {
691*955eb5e1SGarrett D'Amore printf("451 4.3.0 temporary file write error\r\n");
692*955eb5e1SGarrett D'Amore }
693*955eb5e1SGarrett D'Amore fclose(fp);
694*955eb5e1SGarrett D'Amore return;
695*955eb5e1SGarrett D'Amore } else {
696*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "temporary file write error");
697*955eb5e1SGarrett D'Amore fclose(fp);
698*955eb5e1SGarrett D'Amore exit(eval);
699*955eb5e1SGarrett D'Amore }
700*955eb5e1SGarrett D'Amore }
701*955eb5e1SGarrett D'Amore
702*955eb5e1SGarrett D'Amore if ((newfd = dup(bfd)) >= 0) {
703*955eb5e1SGarrett D'Amore fclose(bfp);
704*955eb5e1SGarrett D'Amore bfd = newfd;
705*955eb5e1SGarrett D'Amore }
706*955eb5e1SGarrett D'Amore if ((newfd = dup(hfd)) >= 0) {
707*955eb5e1SGarrett D'Amore fclose(hfp);
708*955eb5e1SGarrett D'Amore hfd = newfd;
709*955eb5e1SGarrett D'Amore }
710*955eb5e1SGarrett D'Amore (void) time(&tval);
711*955eb5e1SGarrett D'Amore (void) snprintf(unix_from_line, sizeof (unix_from_line), "From %s %s",
712*955eb5e1SGarrett D'Amore from, ctime(&tval));
713*955eb5e1SGarrett D'Amore ulen = strlen(unix_from_line);
714*955eb5e1SGarrett D'Amore }
715*955eb5e1SGarrett D'Amore
716*955eb5e1SGarrett D'Amore static void
handle_error(err_num,bouncequota,path)717*955eb5e1SGarrett D'Amore handle_error(err_num, bouncequota, path)
718*955eb5e1SGarrett D'Amore int err_num;
719*955eb5e1SGarrett D'Amore bool bouncequota;
720*955eb5e1SGarrett D'Amore char *path;
721*955eb5e1SGarrett D'Amore {
722*955eb5e1SGarrett D'Amore #ifdef EDQUOT
723*955eb5e1SGarrett D'Amore if (err_num == EDQUOT && bouncequota) {
724*955eb5e1SGarrett D'Amore mailerr("552 5.2.2", "%s: %s", path, sm_errstring(err_num));
725*955eb5e1SGarrett D'Amore } else
726*955eb5e1SGarrett D'Amore #endif /* EDQUOT */
727*955eb5e1SGarrett D'Amore mailerr("450 4.2.0", "%s: %s", path, sm_errstring(err_num));
728*955eb5e1SGarrett D'Amore }
729*955eb5e1SGarrett D'Amore
730*955eb5e1SGarrett D'Amore static void
deliver(hfd,bfd,name,bouncequota)731*955eb5e1SGarrett D'Amore deliver(hfd, bfd, name, bouncequota)
732*955eb5e1SGarrett D'Amore int hfd;
733*955eb5e1SGarrett D'Amore int bfd;
734*955eb5e1SGarrett D'Amore char *name;
735*955eb5e1SGarrett D'Amore bool bouncequota;
736*955eb5e1SGarrett D'Amore {
737*955eb5e1SGarrett D'Amore struct stat fsb, sb;
738*955eb5e1SGarrett D'Amore int mbfd = -1, nr, nw = 0, off;
739*955eb5e1SGarrett D'Amore char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
740*955eb5e1SGarrett D'Amore off_t curoff, cursize;
741*955eb5e1SGarrett D'Amore int len;
742*955eb5e1SGarrett D'Amore struct passwd *pw = NULL;
743*955eb5e1SGarrett D'Amore
744*955eb5e1SGarrett D'Amore /*
745*955eb5e1SGarrett D'Amore * Disallow delivery to unknown names -- special mailboxes
746*955eb5e1SGarrett D'Amore * can be handled in the sendmail aliases file.
747*955eb5e1SGarrett D'Amore */
748*955eb5e1SGarrett D'Amore if ((pw = getpwnam(name)) == NULL) {
749*955eb5e1SGarrett D'Amore eval = EX_TEMPFAIL;
750*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "cannot lookup name: %s", name);
751*955eb5e1SGarrett D'Amore return;
752*955eb5e1SGarrett D'Amore }
753*955eb5e1SGarrett D'Amore endpwent();
754*955eb5e1SGarrett D'Amore
755*955eb5e1SGarrett D'Amore if (sigterm_caught) {
756*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
757*955eb5e1SGarrett D'Amore return;
758*955eb5e1SGarrett D'Amore }
759*955eb5e1SGarrett D'Amore
760*955eb5e1SGarrett D'Amore /* mailbox may be NFS mounted, seteuid to user */
761*955eb5e1SGarrett D'Amore targ_uid = pw->pw_uid;
762*955eb5e1SGarrett D'Amore (void) seteuid(targ_uid);
763*955eb5e1SGarrett D'Amore
764*955eb5e1SGarrett D'Amore if ((saved_uid != 0) && (src_uid != targ_uid)) {
765*955eb5e1SGarrett D'Amore /*
766*955eb5e1SGarrett D'Amore * If saved_uid == 0 (root), anything is OK; this is
767*955eb5e1SGarrett D'Amore * as it should be. But to prevent a random user from
768*955eb5e1SGarrett D'Amore * calling "mail.local foo" in an attempt to hijack
769*955eb5e1SGarrett D'Amore * foo's mail-box, make sure src_uid == targ_uid o/w.
770*955eb5e1SGarrett D'Amore */
771*955eb5e1SGarrett D'Amore warn("%s: wrong owner (is %d, should be %d)",
772*955eb5e1SGarrett D'Amore name, src_uid, targ_uid);
773*955eb5e1SGarrett D'Amore eval = EX_CANTCREAT;
774*955eb5e1SGarrett D'Amore return;
775*955eb5e1SGarrett D'Amore }
776*955eb5e1SGarrett D'Amore
777*955eb5e1SGarrett D'Amore path[0] = '\0';
778*955eb5e1SGarrett D'Amore (void) snprintf(path, sizeof (path), "%s/%s", _PATH_MAILDIR, name);
779*955eb5e1SGarrett D'Amore
780*955eb5e1SGarrett D'Amore /*
781*955eb5e1SGarrett D'Amore * If the mailbox is linked or a symlink, fail. There's an obvious
782*955eb5e1SGarrett D'Amore * race here, that the file was replaced with a symbolic link after
783*955eb5e1SGarrett D'Amore * the lstat returned, but before the open. We attempt to detect
784*955eb5e1SGarrett D'Amore * this by comparing the original stat information and information
785*955eb5e1SGarrett D'Amore * returned by an fstat of the file descriptor returned by the open.
786*955eb5e1SGarrett D'Amore *
787*955eb5e1SGarrett D'Amore * NB: this is a symptom of a larger problem, that the mail spooling
788*955eb5e1SGarrett D'Amore * directory is writeable by the wrong users. If that directory is
789*955eb5e1SGarrett D'Amore * writeable, system security is compromised for other reasons, and
790*955eb5e1SGarrett D'Amore * it cannot be fixed here.
791*955eb5e1SGarrett D'Amore *
792*955eb5e1SGarrett D'Amore * If we created the mailbox, set the owner/group. If that fails,
793*955eb5e1SGarrett D'Amore * just return. Another process may have already opened it, so we
794*955eb5e1SGarrett D'Amore * can't unlink it. Historically, binmail set the owner/group at
795*955eb5e1SGarrett D'Amore * each mail delivery. We no longer do this, assuming that if the
796*955eb5e1SGarrett D'Amore * ownership or permissions were changed there was a reason.
797*955eb5e1SGarrett D'Amore *
798*955eb5e1SGarrett D'Amore * XXX
799*955eb5e1SGarrett D'Amore * open(2) should support flock'ing the file.
800*955eb5e1SGarrett D'Amore */
801*955eb5e1SGarrett D'Amore tryagain:
802*955eb5e1SGarrett D'Amore /* should check lock status, but... maillock return no value */
803*955eb5e1SGarrett D'Amore maillock(name, 10);
804*955eb5e1SGarrett D'Amore
805*955eb5e1SGarrett D'Amore if (sigterm_caught) {
806*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
807*955eb5e1SGarrett D'Amore goto err0;
808*955eb5e1SGarrett D'Amore }
809*955eb5e1SGarrett D'Amore
810*955eb5e1SGarrett D'Amore if (lstat(path, &sb)) {
811*955eb5e1SGarrett D'Amore mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY,
812*955eb5e1SGarrett D'Amore S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
813*955eb5e1SGarrett D'Amore if (mbfd != -1)
814*955eb5e1SGarrett D'Amore (void) fchmod(mbfd, 0660);
815*955eb5e1SGarrett D'Amore
816*955eb5e1SGarrett D'Amore
817*955eb5e1SGarrett D'Amore if (mbfd == -1) {
818*955eb5e1SGarrett D'Amore if (errno == EEXIST) {
819*955eb5e1SGarrett D'Amore mailunlock();
820*955eb5e1SGarrett D'Amore goto tryagain;
821*955eb5e1SGarrett D'Amore }
822*955eb5e1SGarrett D'Amore }
823*955eb5e1SGarrett D'Amore } else if (sb.st_nlink != 1) {
824*955eb5e1SGarrett D'Amore mailerr("550 5.2.0", "%s: too many links", path);
825*955eb5e1SGarrett D'Amore goto err0;
826*955eb5e1SGarrett D'Amore } else if (!S_ISREG(sb.st_mode)) {
827*955eb5e1SGarrett D'Amore mailerr("550 5.2.0", "%s: irregular file", path);
828*955eb5e1SGarrett D'Amore goto err0;
829*955eb5e1SGarrett D'Amore } else {
830*955eb5e1SGarrett D'Amore mbfd = open(path, O_APPEND|O_WRONLY, 0);
831*955eb5e1SGarrett D'Amore if (mbfd != -1 &&
832*955eb5e1SGarrett D'Amore (fstat(mbfd, &fsb) || fsb.st_nlink != 1 ||
833*955eb5e1SGarrett D'Amore S_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
834*955eb5e1SGarrett D'Amore sb.st_ino != fsb.st_ino)) {
835*955eb5e1SGarrett D'Amore eval = EX_TEMPFAIL;
836*955eb5e1SGarrett D'Amore mailerr("550 5.2.0",
837*955eb5e1SGarrett D'Amore "%s: fstat: file changed after open", path);
838*955eb5e1SGarrett D'Amore goto err1;
839*955eb5e1SGarrett D'Amore }
840*955eb5e1SGarrett D'Amore }
841*955eb5e1SGarrett D'Amore
842*955eb5e1SGarrett D'Amore if (mbfd == -1) {
843*955eb5e1SGarrett D'Amore mailerr("450 4.2.0", "%s: %s", path, strerror(errno));
844*955eb5e1SGarrett D'Amore goto err0;
845*955eb5e1SGarrett D'Amore }
846*955eb5e1SGarrett D'Amore
847*955eb5e1SGarrett D'Amore if (sigterm_caught) {
848*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
849*955eb5e1SGarrett D'Amore goto err0;
850*955eb5e1SGarrett D'Amore }
851*955eb5e1SGarrett D'Amore
852*955eb5e1SGarrett D'Amore /* Get the starting offset of the new message for biff. */
853*955eb5e1SGarrett D'Amore curoff = lseek(mbfd, (off_t)0, SEEK_END);
854*955eb5e1SGarrett D'Amore (void) snprintf(biffmsg, sizeof (biffmsg), "%s@%ld\n", name, curoff);
855*955eb5e1SGarrett D'Amore
856*955eb5e1SGarrett D'Amore /* Copy the message into the file. */
857*955eb5e1SGarrett D'Amore if (lseek(hfd, (off_t)0, SEEK_SET) == (off_t)-1) {
858*955eb5e1SGarrett D'Amore mailerr("450 4.2.0", "temporary file: %s", strerror(errno));
859*955eb5e1SGarrett D'Amore goto err1;
860*955eb5e1SGarrett D'Amore }
861*955eb5e1SGarrett D'Amore /* Copy the message into the file. */
862*955eb5e1SGarrett D'Amore if (lseek(bfd, (off_t)0, SEEK_SET) == (off_t)-1) {
863*955eb5e1SGarrett D'Amore mailerr("450 4.2.0", "temporary file: %s", strerror(errno));
864*955eb5e1SGarrett D'Amore goto err1;
865*955eb5e1SGarrett D'Amore }
866*955eb5e1SGarrett D'Amore if ((write(mbfd, unix_from_line, ulen)) != ulen) {
867*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
868*955eb5e1SGarrett D'Amore goto err2;
869*955eb5e1SGarrett D'Amore }
870*955eb5e1SGarrett D'Amore
871*955eb5e1SGarrett D'Amore if (sigterm_caught) {
872*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
873*955eb5e1SGarrett D'Amore goto err2;
874*955eb5e1SGarrett D'Amore }
875*955eb5e1SGarrett D'Amore
876*955eb5e1SGarrett D'Amore while ((nr = read(hfd, buf, sizeof (buf))) > 0)
877*955eb5e1SGarrett D'Amore for (off = 0; off < nr; nr -= nw, off += nw)
878*955eb5e1SGarrett D'Amore if ((nw = write(mbfd, buf + off, nr)) < 0)
879*955eb5e1SGarrett D'Amore {
880*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
881*955eb5e1SGarrett D'Amore goto err2;
882*955eb5e1SGarrett D'Amore }
883*955eb5e1SGarrett D'Amore if (nr < 0) {
884*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
885*955eb5e1SGarrett D'Amore goto err2;
886*955eb5e1SGarrett D'Amore }
887*955eb5e1SGarrett D'Amore
888*955eb5e1SGarrett D'Amore if (sigterm_caught) {
889*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
890*955eb5e1SGarrett D'Amore goto err2;
891*955eb5e1SGarrett D'Amore }
892*955eb5e1SGarrett D'Amore
893*955eb5e1SGarrett D'Amore (void) snprintf(buf, sizeof (buf), "Content-Length: %d\n\n",
894*955eb5e1SGarrett D'Amore content_length);
895*955eb5e1SGarrett D'Amore len = strlen(buf);
896*955eb5e1SGarrett D'Amore if (write(mbfd, buf, len) != len) {
897*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
898*955eb5e1SGarrett D'Amore goto err2;
899*955eb5e1SGarrett D'Amore }
900*955eb5e1SGarrett D'Amore
901*955eb5e1SGarrett D'Amore if (sigterm_caught) {
902*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
903*955eb5e1SGarrett D'Amore goto err2;
904*955eb5e1SGarrett D'Amore }
905*955eb5e1SGarrett D'Amore
906*955eb5e1SGarrett D'Amore while ((nr = read(bfd, buf, sizeof (buf))) > 0) {
907*955eb5e1SGarrett D'Amore for (off = 0; off < nr; nr -= nw, off += nw)
908*955eb5e1SGarrett D'Amore if ((nw = write(mbfd, buf + off, nr)) < 0) {
909*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
910*955eb5e1SGarrett D'Amore goto err2;
911*955eb5e1SGarrett D'Amore }
912*955eb5e1SGarrett D'Amore if (sigterm_caught) {
913*955eb5e1SGarrett D'Amore mailerr("451 4.3.0", "shutting down");
914*955eb5e1SGarrett D'Amore goto err2;
915*955eb5e1SGarrett D'Amore }
916*955eb5e1SGarrett D'Amore }
917*955eb5e1SGarrett D'Amore if (nr < 0) {
918*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
919*955eb5e1SGarrett D'Amore goto err2;
920*955eb5e1SGarrett D'Amore }
921*955eb5e1SGarrett D'Amore
922*955eb5e1SGarrett D'Amore /* Flush to disk, don't wait for update. */
923*955eb5e1SGarrett D'Amore if (fsync(mbfd)) {
924*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
925*955eb5e1SGarrett D'Amore err2: if (mbfd >= 0)
926*955eb5e1SGarrett D'Amore (void)ftruncate(mbfd, curoff);
927*955eb5e1SGarrett D'Amore err1: (void)close(mbfd);
928*955eb5e1SGarrett D'Amore err0: mailunlock();
929*955eb5e1SGarrett D'Amore (void)seteuid(saved_uid);
930*955eb5e1SGarrett D'Amore return;
931*955eb5e1SGarrett D'Amore }
932*955eb5e1SGarrett D'Amore
933*955eb5e1SGarrett D'Amore /*
934*955eb5e1SGarrett D'Amore ** Save the current size so if the close() fails below
935*955eb5e1SGarrett D'Amore ** we can make sure no other process has changed the mailbox
936*955eb5e1SGarrett D'Amore ** between the failed close and the re-open()/re-lock().
937*955eb5e1SGarrett D'Amore ** If something else has changed the size, we shouldn't
938*955eb5e1SGarrett D'Amore ** try to truncate it as we may do more harm then good
939*955eb5e1SGarrett D'Amore ** (e.g., truncate a later message delivery).
940*955eb5e1SGarrett D'Amore */
941*955eb5e1SGarrett D'Amore
942*955eb5e1SGarrett D'Amore if (fstat(mbfd, &sb) < 0)
943*955eb5e1SGarrett D'Amore cursize = 0;
944*955eb5e1SGarrett D'Amore else
945*955eb5e1SGarrett D'Amore cursize = sb.st_size;
946*955eb5e1SGarrett D'Amore
947*955eb5e1SGarrett D'Amore /* Close and check -- NFS doesn't write until the close. */
948*955eb5e1SGarrett D'Amore if (close(mbfd))
949*955eb5e1SGarrett D'Amore {
950*955eb5e1SGarrett D'Amore handle_error(errno, bouncequota, path);
951*955eb5e1SGarrett D'Amore mbfd = open(path, O_WRONLY, 0);
952*955eb5e1SGarrett D'Amore if (mbfd < 0 ||
953*955eb5e1SGarrett D'Amore cursize == 0
954*955eb5e1SGarrett D'Amore || flock(mbfd, LOCK_EX) < 0 ||
955*955eb5e1SGarrett D'Amore fstat(mbfd, &sb) < 0 ||
956*955eb5e1SGarrett D'Amore sb.st_size != cursize ||
957*955eb5e1SGarrett D'Amore sb.st_nlink != 1 ||
958*955eb5e1SGarrett D'Amore !S_ISREG(sb.st_mode) ||
959*955eb5e1SGarrett D'Amore sb.st_dev != fsb.st_dev ||
960*955eb5e1SGarrett D'Amore sb.st_ino != fsb.st_ino ||
961*955eb5e1SGarrett D'Amore sb.st_uid != fsb.st_uid)
962*955eb5e1SGarrett D'Amore {
963*955eb5e1SGarrett D'Amore /* Don't use a bogus file */
964*955eb5e1SGarrett D'Amore if (mbfd >= 0)
965*955eb5e1SGarrett D'Amore {
966*955eb5e1SGarrett D'Amore (void) close(mbfd);
967*955eb5e1SGarrett D'Amore mbfd = -1;
968*955eb5e1SGarrett D'Amore }
969*955eb5e1SGarrett D'Amore }
970*955eb5e1SGarrett D'Amore
971*955eb5e1SGarrett D'Amore /* Attempt to truncate back to pre-write size */
972*955eb5e1SGarrett D'Amore goto err2;
973*955eb5e1SGarrett D'Amore } else
974*955eb5e1SGarrett D'Amore notifybiff(biffmsg);
975*955eb5e1SGarrett D'Amore
976*955eb5e1SGarrett D'Amore mailunlock();
977*955eb5e1SGarrett D'Amore
978*955eb5e1SGarrett D'Amore (void)seteuid(saved_uid);
979*955eb5e1SGarrett D'Amore
980*955eb5e1SGarrett D'Amore if (lmtpmode) {
981*955eb5e1SGarrett D'Amore printf("250 2.1.5 %s OK\r\n", name);
982*955eb5e1SGarrett D'Amore }
983*955eb5e1SGarrett D'Amore }
984*955eb5e1SGarrett D'Amore
985*955eb5e1SGarrett D'Amore static void
notifybiff(msg)986*955eb5e1SGarrett D'Amore notifybiff(msg)
987*955eb5e1SGarrett D'Amore char *msg;
988*955eb5e1SGarrett D'Amore {
989*955eb5e1SGarrett D'Amore static struct sockaddr_in addr;
990*955eb5e1SGarrett D'Amore static int f = -1;
991*955eb5e1SGarrett D'Amore struct hostent *hp;
992*955eb5e1SGarrett D'Amore struct servent *sp;
993*955eb5e1SGarrett D'Amore int len;
994*955eb5e1SGarrett D'Amore
995*955eb5e1SGarrett D'Amore if (msg == NULL) {
996*955eb5e1SGarrett D'Amore /* Be silent if biff service not available. */
997*955eb5e1SGarrett D'Amore if ((sp = getservbyname("biff", "udp")) == NULL)
998*955eb5e1SGarrett D'Amore return;
999*955eb5e1SGarrett D'Amore if ((hp = gethostbyname("localhost")) == NULL) {
1000*955eb5e1SGarrett D'Amore warn("localhost: %s", strerror(errno));
1001*955eb5e1SGarrett D'Amore return;
1002*955eb5e1SGarrett D'Amore }
1003*955eb5e1SGarrett D'Amore addr.sin_family = hp->h_addrtype;
1004*955eb5e1SGarrett D'Amore (void) memmove(&addr.sin_addr, hp->h_addr, hp->h_length);
1005*955eb5e1SGarrett D'Amore addr.sin_port = sp->s_port;
1006*955eb5e1SGarrett D'Amore return;
1007*955eb5e1SGarrett D'Amore }
1008*955eb5e1SGarrett D'Amore
1009*955eb5e1SGarrett D'Amore if (addr.sin_family == 0)
1010*955eb5e1SGarrett D'Amore return; /* did not initialize */
1011*955eb5e1SGarrett D'Amore
1012*955eb5e1SGarrett D'Amore if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
1013*955eb5e1SGarrett D'Amore warn("socket: %s", strerror(errno));
1014*955eb5e1SGarrett D'Amore return;
1015*955eb5e1SGarrett D'Amore }
1016*955eb5e1SGarrett D'Amore len = strlen(msg) + 1;
1017*955eb5e1SGarrett D'Amore if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof (addr))
1018*955eb5e1SGarrett D'Amore != len)
1019*955eb5e1SGarrett D'Amore warn("sendto biff: %s", strerror(errno));
1020*955eb5e1SGarrett D'Amore }
1021*955eb5e1SGarrett D'Amore
1022*955eb5e1SGarrett D'Amore static void
usage()1023*955eb5e1SGarrett D'Amore usage()
1024*955eb5e1SGarrett D'Amore {
1025*955eb5e1SGarrett D'Amore eval = EX_USAGE;
1026*955eb5e1SGarrett D'Amore err("usage: mail.local [-l] [-f from] user ...");
1027*955eb5e1SGarrett D'Amore }
1028*955eb5e1SGarrett D'Amore
1029*955eb5e1SGarrett D'Amore static void
1030*955eb5e1SGarrett D'Amore /*VARARGS2*/
1031*955eb5e1SGarrett D'Amore #ifdef __STDC__
mailerr(const char * hdr,const char * fmt,...)1032*955eb5e1SGarrett D'Amore mailerr(const char *hdr, const char *fmt, ...)
1033*955eb5e1SGarrett D'Amore #else
1034*955eb5e1SGarrett D'Amore mailerr(hdr, fmt, va_alist)
1035*955eb5e1SGarrett D'Amore const char *hdr;
1036*955eb5e1SGarrett D'Amore const char *fmt;
1037*955eb5e1SGarrett D'Amore va_dcl
1038*955eb5e1SGarrett D'Amore #endif
1039*955eb5e1SGarrett D'Amore {
1040*955eb5e1SGarrett D'Amore va_list ap;
1041*955eb5e1SGarrett D'Amore
1042*955eb5e1SGarrett D'Amore #ifdef __STDC__
1043*955eb5e1SGarrett D'Amore va_start(ap, fmt);
1044*955eb5e1SGarrett D'Amore #else
1045*955eb5e1SGarrett D'Amore va_start(ap);
1046*955eb5e1SGarrett D'Amore #endif
1047*955eb5e1SGarrett D'Amore if (lmtpmode)
1048*955eb5e1SGarrett D'Amore {
1049*955eb5e1SGarrett D'Amore if (hdr != NULL)
1050*955eb5e1SGarrett D'Amore printf("%s ", hdr);
1051*955eb5e1SGarrett D'Amore vprintf(fmt, ap);
1052*955eb5e1SGarrett D'Amore printf("\r\n");
1053*955eb5e1SGarrett D'Amore }
1054*955eb5e1SGarrett D'Amore else
1055*955eb5e1SGarrett D'Amore {
1056*955eb5e1SGarrett D'Amore e_to_sys(errno);
1057*955eb5e1SGarrett D'Amore vwarn(fmt, ap);
1058*955eb5e1SGarrett D'Amore }
1059*955eb5e1SGarrett D'Amore }
1060*955eb5e1SGarrett D'Amore
1061*955eb5e1SGarrett D'Amore static void
1062*955eb5e1SGarrett D'Amore /*VARARGS1*/
1063*955eb5e1SGarrett D'Amore #ifdef __STDC__
err(const char * fmt,...)1064*955eb5e1SGarrett D'Amore err(const char *fmt, ...)
1065*955eb5e1SGarrett D'Amore #else
1066*955eb5e1SGarrett D'Amore err(fmt, va_alist)
1067*955eb5e1SGarrett D'Amore const char *fmt;
1068*955eb5e1SGarrett D'Amore va_dcl
1069*955eb5e1SGarrett D'Amore #endif
1070*955eb5e1SGarrett D'Amore {
1071*955eb5e1SGarrett D'Amore va_list ap;
1072*955eb5e1SGarrett D'Amore
1073*955eb5e1SGarrett D'Amore #ifdef __STDC__
1074*955eb5e1SGarrett D'Amore va_start(ap, fmt);
1075*955eb5e1SGarrett D'Amore #else
1076*955eb5e1SGarrett D'Amore va_start(ap);
1077*955eb5e1SGarrett D'Amore #endif
1078*955eb5e1SGarrett D'Amore vwarn(fmt, ap);
1079*955eb5e1SGarrett D'Amore va_end(ap);
1080*955eb5e1SGarrett D'Amore
1081*955eb5e1SGarrett D'Amore exit(eval);
1082*955eb5e1SGarrett D'Amore }
1083*955eb5e1SGarrett D'Amore
1084*955eb5e1SGarrett D'Amore static void
1085*955eb5e1SGarrett D'Amore /*VARARGS1*/
1086*955eb5e1SGarrett D'Amore #ifdef __STDC__
warn(const char * fmt,...)1087*955eb5e1SGarrett D'Amore warn(const char *fmt, ...)
1088*955eb5e1SGarrett D'Amore #else
1089*955eb5e1SGarrett D'Amore warn(fmt, va_alist)
1090*955eb5e1SGarrett D'Amore const char *fmt;
1091*955eb5e1SGarrett D'Amore va_dcl
1092*955eb5e1SGarrett D'Amore #endif
1093*955eb5e1SGarrett D'Amore {
1094*955eb5e1SGarrett D'Amore va_list ap;
1095*955eb5e1SGarrett D'Amore
1096*955eb5e1SGarrett D'Amore #ifdef __STDC__
1097*955eb5e1SGarrett D'Amore va_start(ap, fmt);
1098*955eb5e1SGarrett D'Amore #else
1099*955eb5e1SGarrett D'Amore va_start(ap);
1100*955eb5e1SGarrett D'Amore #endif
1101*955eb5e1SGarrett D'Amore vwarn(fmt, ap);
1102*955eb5e1SGarrett D'Amore va_end(ap);
1103*955eb5e1SGarrett D'Amore }
1104*955eb5e1SGarrett D'Amore
1105*955eb5e1SGarrett D'Amore static void
vwarn(fmt,ap)1106*955eb5e1SGarrett D'Amore vwarn(fmt, ap)
1107*955eb5e1SGarrett D'Amore const char *fmt;
1108*955eb5e1SGarrett D'Amore va_list ap;
1109*955eb5e1SGarrett D'Amore {
1110*955eb5e1SGarrett D'Amore /*
1111*955eb5e1SGarrett D'Amore * Log the message to stderr.
1112*955eb5e1SGarrett D'Amore *
1113*955eb5e1SGarrett D'Amore * Don't use LOG_PERROR as an openlog() flag to do this,
1114*955eb5e1SGarrett D'Amore * it's not portable enough.
1115*955eb5e1SGarrett D'Amore */
1116*955eb5e1SGarrett D'Amore if (eval != EX_USAGE)
1117*955eb5e1SGarrett D'Amore (void) fprintf(stderr, "mail.local: ");
1118*955eb5e1SGarrett D'Amore (void) vfprintf(stderr, fmt, ap);
1119*955eb5e1SGarrett D'Amore (void) fprintf(stderr, "\n");
1120*955eb5e1SGarrett D'Amore
1121*955eb5e1SGarrett D'Amore /* Log the message to syslog. */
1122*955eb5e1SGarrett D'Amore vsyslog(LOG_ERR, fmt, ap);
1123*955eb5e1SGarrett D'Amore }
1124*955eb5e1SGarrett D'Amore
1125*955eb5e1SGarrett D'Amore /*
1126*955eb5e1SGarrett D'Amore * e_to_sys --
1127*955eb5e1SGarrett D'Amore * Guess which errno's are temporary. Gag me.
1128*955eb5e1SGarrett D'Amore */
1129*955eb5e1SGarrett D'Amore static void
e_to_sys(num)1130*955eb5e1SGarrett D'Amore e_to_sys(num)
1131*955eb5e1SGarrett D'Amore int num;
1132*955eb5e1SGarrett D'Amore {
1133*955eb5e1SGarrett D'Amore /* Temporary failures override hard errors. */
1134*955eb5e1SGarrett D'Amore if (eval == EX_TEMPFAIL)
1135*955eb5e1SGarrett D'Amore return;
1136*955eb5e1SGarrett D'Amore
1137*955eb5e1SGarrett D'Amore switch (num) /* Hopefully temporary errors. */
1138*955eb5e1SGarrett D'Amore {
1139*955eb5e1SGarrett D'Amore #ifdef EDQUOT
1140*955eb5e1SGarrett D'Amore case EDQUOT: /* Disc quota exceeded */
1141*955eb5e1SGarrett D'Amore if (bouncequota)
1142*955eb5e1SGarrett D'Amore {
1143*955eb5e1SGarrett D'Amore eval = EX_UNAVAILABLE;
1144*955eb5e1SGarrett D'Amore break;
1145*955eb5e1SGarrett D'Amore }
1146*955eb5e1SGarrett D'Amore #endif /* EDQUOT */
1147*955eb5e1SGarrett D'Amore #ifdef EAGAIN
1148*955eb5e1SGarrett D'Amore /* FALLTHROUGH */
1149*955eb5e1SGarrett D'Amore case EAGAIN: /* Resource temporarily unavailable */
1150*955eb5e1SGarrett D'Amore #endif
1151*955eb5e1SGarrett D'Amore #ifdef EBUSY
1152*955eb5e1SGarrett D'Amore case EBUSY: /* Device busy */
1153*955eb5e1SGarrett D'Amore #endif
1154*955eb5e1SGarrett D'Amore #ifdef EPROCLIM
1155*955eb5e1SGarrett D'Amore case EPROCLIM: /* Too many processes */
1156*955eb5e1SGarrett D'Amore #endif
1157*955eb5e1SGarrett D'Amore #ifdef EUSERS
1158*955eb5e1SGarrett D'Amore case EUSERS: /* Too many users */
1159*955eb5e1SGarrett D'Amore #endif
1160*955eb5e1SGarrett D'Amore #ifdef ECONNABORTED
1161*955eb5e1SGarrett D'Amore case ECONNABORTED: /* Software caused connection abort */
1162*955eb5e1SGarrett D'Amore #endif
1163*955eb5e1SGarrett D'Amore #ifdef ECONNREFUSED
1164*955eb5e1SGarrett D'Amore case ECONNREFUSED: /* Connection refused */
1165*955eb5e1SGarrett D'Amore #endif
1166*955eb5e1SGarrett D'Amore #ifdef ECONNRESET
1167*955eb5e1SGarrett D'Amore case ECONNRESET: /* Connection reset by peer */
1168*955eb5e1SGarrett D'Amore #endif
1169*955eb5e1SGarrett D'Amore #ifdef EDEADLK
1170*955eb5e1SGarrett D'Amore case EDEADLK: /* Resource deadlock avoided */
1171*955eb5e1SGarrett D'Amore #endif
1172*955eb5e1SGarrett D'Amore #ifdef EFBIG
1173*955eb5e1SGarrett D'Amore case EFBIG: /* File too large */
1174*955eb5e1SGarrett D'Amore #endif
1175*955eb5e1SGarrett D'Amore #ifdef EHOSTDOWN
1176*955eb5e1SGarrett D'Amore case EHOSTDOWN: /* Host is down */
1177*955eb5e1SGarrett D'Amore #endif
1178*955eb5e1SGarrett D'Amore #ifdef EHOSTUNREACH
1179*955eb5e1SGarrett D'Amore case EHOSTUNREACH: /* No route to host */
1180*955eb5e1SGarrett D'Amore #endif
1181*955eb5e1SGarrett D'Amore #ifdef EMFILE
1182*955eb5e1SGarrett D'Amore case EMFILE: /* Too many open files */
1183*955eb5e1SGarrett D'Amore #endif
1184*955eb5e1SGarrett D'Amore #ifdef ENETDOWN
1185*955eb5e1SGarrett D'Amore case ENETDOWN: /* Network is down */
1186*955eb5e1SGarrett D'Amore #endif
1187*955eb5e1SGarrett D'Amore #ifdef ENETRESET
1188*955eb5e1SGarrett D'Amore case ENETRESET: /* Network dropped connection on reset */
1189*955eb5e1SGarrett D'Amore #endif
1190*955eb5e1SGarrett D'Amore #ifdef ENETUNREACH
1191*955eb5e1SGarrett D'Amore case ENETUNREACH: /* Network is unreachable */
1192*955eb5e1SGarrett D'Amore #endif
1193*955eb5e1SGarrett D'Amore #ifdef ENFILE
1194*955eb5e1SGarrett D'Amore case ENFILE: /* Too many open files in system */
1195*955eb5e1SGarrett D'Amore #endif
1196*955eb5e1SGarrett D'Amore #ifdef ENOBUFS
1197*955eb5e1SGarrett D'Amore case ENOBUFS: /* No buffer space available */
1198*955eb5e1SGarrett D'Amore #endif
1199*955eb5e1SGarrett D'Amore #ifdef ENOMEM
1200*955eb5e1SGarrett D'Amore case ENOMEM: /* Cannot allocate memory */
1201*955eb5e1SGarrett D'Amore #endif
1202*955eb5e1SGarrett D'Amore #ifdef ENOSPC
1203*955eb5e1SGarrett D'Amore case ENOSPC: /* No space left on device */
1204*955eb5e1SGarrett D'Amore #endif
1205*955eb5e1SGarrett D'Amore #ifdef EROFS
1206*955eb5e1SGarrett D'Amore case EROFS: /* Read-only file system */
1207*955eb5e1SGarrett D'Amore #endif
1208*955eb5e1SGarrett D'Amore #ifdef ESTALE
1209*955eb5e1SGarrett D'Amore case ESTALE: /* Stale NFS file handle */
1210*955eb5e1SGarrett D'Amore #endif
1211*955eb5e1SGarrett D'Amore #ifdef ETIMEDOUT
1212*955eb5e1SGarrett D'Amore case ETIMEDOUT: /* Connection timed out */
1213*955eb5e1SGarrett D'Amore #endif
1214*955eb5e1SGarrett D'Amore #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1215*955eb5e1SGarrett D'Amore case EWOULDBLOCK: /* Operation would block. */
1216*955eb5e1SGarrett D'Amore #endif
1217*955eb5e1SGarrett D'Amore eval = EX_TEMPFAIL;
1218*955eb5e1SGarrett D'Amore break;
1219*955eb5e1SGarrett D'Amore default:
1220*955eb5e1SGarrett D'Amore eval = EX_UNAVAILABLE;
1221*955eb5e1SGarrett D'Amore break;
1222*955eb5e1SGarrett D'Amore }
1223*955eb5e1SGarrett D'Amore }
1224