xref: /freebsd/contrib/sendmail/rmail/rmail.c (revision 3299c2f1)
1c2aa98e2SPeter Wemm /*
23299c2f1SGregory Neil Shapiro  * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
5c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
6c2aa98e2SPeter Wemm  *
7c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
8c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
9c2aa98e2SPeter Wemm  * the sendmail distribution.
10c2aa98e2SPeter Wemm  *
11c2aa98e2SPeter Wemm  */
12c2aa98e2SPeter Wemm 
13c2aa98e2SPeter Wemm #ifndef lint
14c2aa98e2SPeter Wemm static char copyright[] =
153299c2f1SGregory Neil Shapiro "@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
163299c2f1SGregory Neil Shapiro 	All rights reserved.\n\
173299c2f1SGregory Neil Shapiro      Copyright (c) 1988, 1993\n\
18c2aa98e2SPeter Wemm 	The Regents of the University of California.  All rights reserved.\n";
193299c2f1SGregory Neil Shapiro #endif /* ! lint */
20c2aa98e2SPeter Wemm 
21c2aa98e2SPeter Wemm #ifndef lint
223299c2f1SGregory Neil Shapiro static char id[] = "@(#)$Id: rmail.c,v 8.39.4.5 2000/07/18 05:55:29 gshapiro Exp $";
233299c2f1SGregory Neil Shapiro #endif /* ! lint */
243299c2f1SGregory Neil Shapiro 
253299c2f1SGregory Neil Shapiro /* $FreeBSD$ */
26c2aa98e2SPeter Wemm 
27c2aa98e2SPeter Wemm /*
28c2aa98e2SPeter Wemm  * RMAIL -- UUCP mail server.
29c2aa98e2SPeter Wemm  *
30c2aa98e2SPeter Wemm  * This program reads the >From ... remote from ... lines that UUCP is so
31c2aa98e2SPeter Wemm  * fond of and turns them into something reasonable.  It then execs sendmail
32c2aa98e2SPeter Wemm  * with various options built from these lines.
33c2aa98e2SPeter Wemm  *
34c2aa98e2SPeter Wemm  * The expected syntax is:
35c2aa98e2SPeter Wemm  *
36c2aa98e2SPeter Wemm  *	 <user> := [-a-z0-9]+
37c2aa98e2SPeter Wemm  *	 <date> := ctime format
38c2aa98e2SPeter Wemm  *	 <site> := [-a-z0-9!]+
39c2aa98e2SPeter Wemm  * <blank line> := "^\n$"
40c2aa98e2SPeter Wemm  *	 <from> := "From" <space> <user> <space> <date>
41c2aa98e2SPeter Wemm  *		  [<space> "remote from" <space> <site>]
42c2aa98e2SPeter Wemm  *    <forward> := ">" <from>
43c2aa98e2SPeter Wemm  *	    msg := <from> <forward>* <blank-line> <body>
44c2aa98e2SPeter Wemm  *
45c2aa98e2SPeter Wemm  * The output of rmail(8) compresses the <forward> lines into a single
46c2aa98e2SPeter Wemm  * from path.
47c2aa98e2SPeter Wemm  *
48c2aa98e2SPeter Wemm  * The err(3) routine is included here deliberately to make this code
49c2aa98e2SPeter Wemm  * a bit more portable.
50c2aa98e2SPeter Wemm  */
513299c2f1SGregory Neil Shapiro 
523299c2f1SGregory Neil Shapiro #include <sys/types.h>
53c2aa98e2SPeter Wemm #include <sys/param.h>
54c2aa98e2SPeter Wemm #include <sys/stat.h>
55c2aa98e2SPeter Wemm #include <sys/wait.h>
56c2aa98e2SPeter Wemm 
57c2aa98e2SPeter Wemm #include <ctype.h>
58c2aa98e2SPeter Wemm #include <fcntl.h>
59c2aa98e2SPeter Wemm #ifdef BSD4_4
60c2aa98e2SPeter Wemm # define FORK vfork
61c2aa98e2SPeter Wemm # include <paths.h>
623299c2f1SGregory Neil Shapiro #else /* BSD4_4 */
63c2aa98e2SPeter Wemm # define FORK fork
64c2aa98e2SPeter Wemm # ifndef _PATH_SENDMAIL
65c2aa98e2SPeter Wemm #  define _PATH_SENDMAIL "/usr/lib/sendmail"
663299c2f1SGregory Neil Shapiro # endif /* ! _PATH_SENDMAIL */
673299c2f1SGregory Neil Shapiro #endif /* BSD4_4 */
68c2aa98e2SPeter Wemm #include <stdio.h>
69c2aa98e2SPeter Wemm #include <stdlib.h>
70c2aa98e2SPeter Wemm #include <string.h>
71c2aa98e2SPeter Wemm #include <unistd.h>
72c2aa98e2SPeter Wemm #ifdef EX_OK
73c2aa98e2SPeter Wemm # undef EX_OK		/* unistd.h may have another use for this */
743299c2f1SGregory Neil Shapiro #endif /* EX_OK */
75c2aa98e2SPeter Wemm #include <sysexits.h>
76c2aa98e2SPeter Wemm 
77c2aa98e2SPeter Wemm #ifndef MAX
78c2aa98e2SPeter Wemm # define MAX(a, b)	((a) < (b) ? (b) : (a))
793299c2f1SGregory Neil Shapiro #endif /* ! MAX */
80c2aa98e2SPeter Wemm 
81c2aa98e2SPeter Wemm #ifndef __P
82c2aa98e2SPeter Wemm # ifdef __STDC__
83c2aa98e2SPeter Wemm #  define __P(protos)	protos
843299c2f1SGregory Neil Shapiro # else /* __STDC__ */
85c2aa98e2SPeter Wemm #  define __P(protos)	()
86c2aa98e2SPeter Wemm #  define const
873299c2f1SGregory Neil Shapiro # endif /* __STDC__ */
883299c2f1SGregory Neil Shapiro #endif /* ! __P */
89c2aa98e2SPeter Wemm 
903299c2f1SGregory Neil Shapiro #ifndef STDIN_FILENO
913299c2f1SGregory Neil Shapiro # define STDIN_FILENO	0
923299c2f1SGregory Neil Shapiro #endif /* ! STDIN_FILENO */
933299c2f1SGregory Neil Shapiro 
943299c2f1SGregory Neil Shapiro #if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300
95c2aa98e2SPeter Wemm # define HASSNPRINTF	1
963299c2f1SGregory Neil Shapiro #endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 */
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm #if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
99c2aa98e2SPeter Wemm # define memmove(d, s, l)	(bcopy((s), (d), (l)))
1003299c2f1SGregory Neil Shapiro #endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm #if !HASSNPRINTF
103c2aa98e2SPeter Wemm extern int	snprintf __P((char *, size_t, const char *, ...));
104c2aa98e2SPeter Wemm #endif /* !HASSNPRINTF */
105c2aa98e2SPeter Wemm 
1063299c2f1SGregory Neil Shapiro #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
1073299c2f1SGregory Neil Shapiro # ifndef HASSTRERROR
1083299c2f1SGregory Neil Shapiro #  define HASSTRERROR	1
1093299c2f1SGregory Neil Shapiro # endif /* ! HASSTRERROR */
1103299c2f1SGregory Neil Shapiro #endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
1113299c2f1SGregory Neil Shapiro 	  defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
112c2aa98e2SPeter Wemm 
1133299c2f1SGregory Neil Shapiro #if defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__)
1143299c2f1SGregory Neil Shapiro # undef WIFEXITED
1153299c2f1SGregory Neil Shapiro # undef WEXITSTATUS
1163299c2f1SGregory Neil Shapiro # define WIFEXITED(st)		(((st) & 0377) == 0)
1173299c2f1SGregory Neil Shapiro # define WEXITSTATUS(st)	(((st) >> 8) & 0377)
1183299c2f1SGregory Neil Shapiro #endif /* defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__) */
1193299c2f1SGregory Neil Shapiro 
1203299c2f1SGregory Neil Shapiro 
1213299c2f1SGregory Neil Shapiro #include "sendmail/errstring.h"
1223299c2f1SGregory Neil Shapiro 
1233299c2f1SGregory Neil Shapiro static void err __P((int, const char *, ...));
1243299c2f1SGregory Neil Shapiro static void usage __P((void));
1253299c2f1SGregory Neil Shapiro static char *xalloc __P((int));
126c2aa98e2SPeter Wemm 
127c2aa98e2SPeter Wemm #define newstr(s)	strcpy(xalloc(strlen(s) + 1), s)
128c2aa98e2SPeter Wemm 
1293299c2f1SGregory Neil Shapiro static char *
130c2aa98e2SPeter Wemm xalloc(sz)
131c2aa98e2SPeter Wemm 	register int sz;
132c2aa98e2SPeter Wemm {
133c2aa98e2SPeter Wemm 	register char *p;
134c2aa98e2SPeter Wemm 
135c2aa98e2SPeter Wemm 	/* some systems can't handle size zero mallocs */
136c2aa98e2SPeter Wemm 	if (sz <= 0)
137c2aa98e2SPeter Wemm 		sz = 1;
138c2aa98e2SPeter Wemm 
139c2aa98e2SPeter Wemm 	p = malloc((unsigned) sz);
140c2aa98e2SPeter Wemm 	if (p == NULL)
141c2aa98e2SPeter Wemm 		err(EX_TEMPFAIL, "out of memory");
142c2aa98e2SPeter Wemm 	return (p);
143c2aa98e2SPeter Wemm }
144c2aa98e2SPeter Wemm 
145c2aa98e2SPeter Wemm int
146c2aa98e2SPeter Wemm main(argc, argv)
147c2aa98e2SPeter Wemm 	int argc;
148c2aa98e2SPeter Wemm 	char *argv[];
149c2aa98e2SPeter Wemm {
1503299c2f1SGregory Neil Shapiro 	int ch, debug, i, pdes[2], pid, status;
15176b7bf71SPeter Wemm 	size_t fplen = 0, fptlen = 0, len;
152c2aa98e2SPeter Wemm 	off_t offset;
1533299c2f1SGregory Neil Shapiro 	FILE *fp;
15476b7bf71SPeter Wemm 	char *addrp = NULL, *domain, *p, *t;
155c2aa98e2SPeter Wemm 	char *from_path, *from_sys, *from_user;
156c2aa98e2SPeter Wemm 	char *args[100], buf[2048], lbuf[2048];
1573299c2f1SGregory Neil Shapiro 	struct stat sb;
1583299c2f1SGregory Neil Shapiro 	extern char *optarg;
1593299c2f1SGregory Neil Shapiro 	extern int optind;
160c2aa98e2SPeter Wemm 
161c2aa98e2SPeter Wemm 	debug = 0;
162c2aa98e2SPeter Wemm 	domain = "UUCP";		/* Default "domain". */
163b2ee1660SPeter Wemm 	while ((ch = getopt(argc, argv, "D:T")) != -1)
1643299c2f1SGregory Neil Shapiro 	{
1653299c2f1SGregory Neil Shapiro 		switch (ch)
1663299c2f1SGregory Neil Shapiro 		{
167c2aa98e2SPeter Wemm 		  case 'T':
168c2aa98e2SPeter Wemm 			debug = 1;
169c2aa98e2SPeter Wemm 			break;
1703299c2f1SGregory Neil Shapiro 
171c2aa98e2SPeter Wemm 		  case 'D':
172c2aa98e2SPeter Wemm 			domain = optarg;
173c2aa98e2SPeter Wemm 			break;
1743299c2f1SGregory Neil Shapiro 
175c2aa98e2SPeter Wemm 		  case '?':
176c2aa98e2SPeter Wemm 		  default:
177c2aa98e2SPeter Wemm 			usage();
178c2aa98e2SPeter Wemm 		}
1793299c2f1SGregory Neil Shapiro 	}
1803299c2f1SGregory Neil Shapiro 
181c2aa98e2SPeter Wemm 	argc -= optind;
182c2aa98e2SPeter Wemm 	argv += optind;
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	if (argc < 1)
185c2aa98e2SPeter Wemm 		usage();
186c2aa98e2SPeter Wemm 
187c2aa98e2SPeter Wemm 	from_path = from_sys = from_user = NULL;
1883299c2f1SGregory Neil Shapiro 	for (offset = 0; ; )
1893299c2f1SGregory Neil Shapiro 	{
190c2aa98e2SPeter Wemm 		/* Get and nul-terminate the line. */
191c2aa98e2SPeter Wemm 		if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
192c2aa98e2SPeter Wemm 			exit(EX_DATAERR);
193c2aa98e2SPeter Wemm 		if ((p = strchr(lbuf, '\n')) == NULL)
194c2aa98e2SPeter Wemm 			err(EX_DATAERR, "line too long");
195c2aa98e2SPeter Wemm 		*p = '\0';
196c2aa98e2SPeter Wemm 
197c2aa98e2SPeter Wemm 		/* Parse lines until reach a non-"From" line. */
198c2aa98e2SPeter Wemm 		if (!strncmp(lbuf, "From ", 5))
199c2aa98e2SPeter Wemm 			addrp = lbuf + 5;
200c2aa98e2SPeter Wemm 		else if (!strncmp(lbuf, ">From ", 6))
201c2aa98e2SPeter Wemm 			addrp = lbuf + 6;
202c2aa98e2SPeter Wemm 		else if (offset == 0)
203c2aa98e2SPeter Wemm 			err(EX_DATAERR,
204c2aa98e2SPeter Wemm 			    "missing or empty From line: %s", lbuf);
2053299c2f1SGregory Neil Shapiro 		else
2063299c2f1SGregory Neil Shapiro 		{
207c2aa98e2SPeter Wemm 			*p = '\n';
208c2aa98e2SPeter Wemm 			break;
209c2aa98e2SPeter Wemm 		}
210c2aa98e2SPeter Wemm 
2113299c2f1SGregory Neil Shapiro 		if (addrp == NULL || *addrp == '\0')
212c2aa98e2SPeter Wemm 			err(EX_DATAERR, "corrupted From line: %s", lbuf);
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 		/* Use the "remote from" if it exists. */
215c2aa98e2SPeter Wemm 		for (p = addrp; (p = strchr(p + 1, 'r')) != NULL; )
2163299c2f1SGregory Neil Shapiro 		{
2173299c2f1SGregory Neil Shapiro 			if (!strncmp(p, "remote from ", 12))
2183299c2f1SGregory Neil Shapiro 			{
2193299c2f1SGregory Neil Shapiro 				for (t = p += 12; *t != '\0'; ++t)
2203299c2f1SGregory Neil Shapiro 				{
2213299c2f1SGregory Neil Shapiro 					if (isascii(*t) && isspace(*t))
2223299c2f1SGregory Neil Shapiro 						break;
2233299c2f1SGregory Neil Shapiro 				}
224c2aa98e2SPeter Wemm 				*t = '\0';
225c2aa98e2SPeter Wemm 				if (debug)
2263299c2f1SGregory Neil Shapiro 					fprintf(stderr, "remote from: %s\n", p);
227c2aa98e2SPeter Wemm 				break;
228c2aa98e2SPeter Wemm 			}
2293299c2f1SGregory Neil Shapiro 		}
230c2aa98e2SPeter Wemm 
231c2aa98e2SPeter Wemm 		/* Else use the string up to the last bang. */
2323299c2f1SGregory Neil Shapiro 		if (p == NULL)
2333299c2f1SGregory Neil Shapiro 		{
234c2aa98e2SPeter Wemm 			if (*addrp == '!')
2353299c2f1SGregory Neil Shapiro 				err(EX_DATAERR, "bang starts address: %s",
2363299c2f1SGregory Neil Shapiro 				    addrp);
2373299c2f1SGregory Neil Shapiro 			else if ((t = strrchr(addrp, '!')) != NULL)
2383299c2f1SGregory Neil Shapiro 			{
239c2aa98e2SPeter Wemm 				*t = '\0';
240c2aa98e2SPeter Wemm 				p = addrp;
241c2aa98e2SPeter Wemm 				addrp = t + 1;
242c2aa98e2SPeter Wemm 				if (*addrp == '\0')
243c2aa98e2SPeter Wemm 					err(EX_DATAERR,
244c2aa98e2SPeter Wemm 					    "corrupted From line: %s", lbuf);
245c2aa98e2SPeter Wemm 				if (debug)
2463299c2f1SGregory Neil Shapiro 					fprintf(stderr, "bang: %s\n", p);
247c2aa98e2SPeter Wemm 			}
248c2aa98e2SPeter Wemm 		}
2493299c2f1SGregory Neil Shapiro 
250c2aa98e2SPeter Wemm 		/* 'p' now points to any system string from this line. */
2513299c2f1SGregory Neil Shapiro 		if (p != NULL)
2523299c2f1SGregory Neil Shapiro 		{
253c2aa98e2SPeter Wemm 			/* Nul terminate it as necessary. */
2543299c2f1SGregory Neil Shapiro 			for (t = p; *t != '\0'; ++t)
2553299c2f1SGregory Neil Shapiro 			{
2563299c2f1SGregory Neil Shapiro 				if (isascii(*t) && isspace(*t))
2573299c2f1SGregory Neil Shapiro 					break;
2583299c2f1SGregory Neil Shapiro 			}
259c2aa98e2SPeter Wemm 			*t = '\0';
260c2aa98e2SPeter Wemm 
261c2aa98e2SPeter Wemm 			/* If the first system, copy to the from_sys string. */
2623299c2f1SGregory Neil Shapiro 			if (from_sys == NULL)
2633299c2f1SGregory Neil Shapiro 			{
264c2aa98e2SPeter Wemm 				from_sys = newstr(p);
265c2aa98e2SPeter Wemm 				if (debug)
2663299c2f1SGregory Neil Shapiro 					fprintf(stderr, "from_sys: %s\n",
2673299c2f1SGregory Neil Shapiro 						from_sys);
268c2aa98e2SPeter Wemm 			}
269c2aa98e2SPeter Wemm 
270c2aa98e2SPeter Wemm 			/* Concatenate to the path string. */
271c2aa98e2SPeter Wemm 			len = t - p;
2723299c2f1SGregory Neil Shapiro 			if (from_path == NULL)
2733299c2f1SGregory Neil Shapiro 			{
274c2aa98e2SPeter Wemm 				fplen = 0;
275c2aa98e2SPeter Wemm 				if ((from_path = malloc(fptlen = 256)) == NULL)
276c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
277c2aa98e2SPeter Wemm 			}
2783299c2f1SGregory Neil Shapiro 			if (fplen + len + 2 > fptlen)
2793299c2f1SGregory Neil Shapiro 			{
280c2aa98e2SPeter Wemm 				fptlen += MAX(fplen + len + 2, 256);
2813299c2f1SGregory Neil Shapiro 				if ((from_path = realloc(from_path,
2823299c2f1SGregory Neil Shapiro 							 fptlen)) == NULL)
283c2aa98e2SPeter Wemm 					err(EX_TEMPFAIL, NULL);
284c2aa98e2SPeter Wemm 			}
285c2aa98e2SPeter Wemm 			memmove(from_path + fplen, p, len);
286c2aa98e2SPeter Wemm 			fplen += len;
287c2aa98e2SPeter Wemm 			from_path[fplen++] = '!';
288c2aa98e2SPeter Wemm 			from_path[fplen] = '\0';
289c2aa98e2SPeter Wemm 		}
290c2aa98e2SPeter Wemm 
291c2aa98e2SPeter Wemm 		/* Save off from user's address; the last one wins. */
2923299c2f1SGregory Neil Shapiro 		for (p = addrp; *p != '\0'; ++p)
2933299c2f1SGregory Neil Shapiro 		{
2943299c2f1SGregory Neil Shapiro 			if (isascii(*p) && isspace(*p))
2953299c2f1SGregory Neil Shapiro 				break;
2963299c2f1SGregory Neil Shapiro 		}
297c2aa98e2SPeter Wemm 		*p = '\0';
298c2aa98e2SPeter Wemm 		if (*addrp == '\0')
299c2aa98e2SPeter Wemm 			addrp = "<>";
300c2aa98e2SPeter Wemm 		if (from_user != NULL)
301c2aa98e2SPeter Wemm 			free(from_user);
302c2aa98e2SPeter Wemm 		from_user = newstr(addrp);
303c2aa98e2SPeter Wemm 
3043299c2f1SGregory Neil Shapiro 		if (debug)
3053299c2f1SGregory Neil Shapiro 		{
306c2aa98e2SPeter Wemm 			if (from_path != NULL)
3073299c2f1SGregory Neil Shapiro 				fprintf(stderr, "from_path: %s\n", from_path);
3083299c2f1SGregory Neil Shapiro 			fprintf(stderr, "from_user: %s\n", from_user);
309c2aa98e2SPeter Wemm 		}
310c2aa98e2SPeter Wemm 
311c2aa98e2SPeter Wemm 		if (offset != -1)
312c2aa98e2SPeter Wemm 			offset = (off_t)ftell(stdin);
313c2aa98e2SPeter Wemm 	}
314c2aa98e2SPeter Wemm 
315c2aa98e2SPeter Wemm 	i = 0;
316c2aa98e2SPeter Wemm 	args[i++] = _PATH_SENDMAIL;	/* Build sendmail's argument list. */
317c2aa98e2SPeter Wemm 	args[i++] = "-oee";		/* No errors, just status. */
318829be59cSPeter Wemm #ifdef QUEUE_ONLY
319c2aa98e2SPeter Wemm 	args[i++] = "-odq";		/* Queue it, don't try to deliver. */
320829be59cSPeter Wemm #else
321829be59cSPeter Wemm 	args[i++] = "-odi";		/* Deliver in foreground. */
322829be59cSPeter Wemm #endif
323c2aa98e2SPeter Wemm 	args[i++] = "-oi";		/* Ignore '.' on a line by itself. */
324c2aa98e2SPeter Wemm 
325c2aa98e2SPeter Wemm 	/* set from system and protocol used */
326c2aa98e2SPeter Wemm 	if (from_sys == NULL)
3273299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s", domain);
328c2aa98e2SPeter Wemm 	else if (strchr(from_sys, '.') == NULL)
3293299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s:%s.%s",
330c2aa98e2SPeter Wemm 			domain, from_sys, domain);
331c2aa98e2SPeter Wemm 	else
3323299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
333c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
334c2aa98e2SPeter Wemm 
335c2aa98e2SPeter Wemm 	/* Set name of ``from'' person. */
3363299c2f1SGregory Neil Shapiro 	snprintf(buf, sizeof(buf), "-f%s%s",
337c2aa98e2SPeter Wemm 		 from_path ? from_path : "", from_user);
338c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
339c2aa98e2SPeter Wemm 
340c2aa98e2SPeter Wemm 	/*
3413299c2f1SGregory Neil Shapiro 	**  Don't copy arguments beginning with - as they will be
3423299c2f1SGregory Neil Shapiro 	**  passed to sendmail and could be interpreted as flags.
3433299c2f1SGregory Neil Shapiro 	**  To prevent confusion of sendmail wrap < and > around
3443299c2f1SGregory Neil Shapiro 	**  the address (helps to pass addrs like @gw1,@gw2:aa@bb)
345c2aa98e2SPeter Wemm 	*/
3463299c2f1SGregory Neil Shapiro 
3473299c2f1SGregory Neil Shapiro 	while (*argv)
3483299c2f1SGregory Neil Shapiro 	{
349c2aa98e2SPeter Wemm 		if (**argv == '-')
350c2aa98e2SPeter Wemm 			err(EX_USAGE, "dash precedes argument: %s", *argv);
3513299c2f1SGregory Neil Shapiro 
352c2aa98e2SPeter Wemm 		if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
353c2aa98e2SPeter Wemm 			args[i++] = *argv;
3543299c2f1SGregory Neil Shapiro 		else
3553299c2f1SGregory Neil Shapiro 		{
3563299c2f1SGregory Neil Shapiro 			len = strlen(*argv) + 3;
3573299c2f1SGregory Neil Shapiro 			if ((args[i] = malloc(len)) == NULL)
358c2aa98e2SPeter Wemm 				err(EX_TEMPFAIL, "Cannot malloc");
3593299c2f1SGregory Neil Shapiro 			snprintf(args[i++], len, "<%s>", *argv);
360c2aa98e2SPeter Wemm 		}
361c2aa98e2SPeter Wemm 		argv++;
362c2aa98e2SPeter Wemm 	}
363c2aa98e2SPeter Wemm 	args[i] = 0;
364c2aa98e2SPeter Wemm 
3653299c2f1SGregory Neil Shapiro 	if (debug)
3663299c2f1SGregory Neil Shapiro 	{
3673299c2f1SGregory Neil Shapiro 		fprintf(stderr, "Sendmail arguments:\n");
368c2aa98e2SPeter Wemm 		for (i = 0; args[i]; i++)
3693299c2f1SGregory Neil Shapiro 			fprintf(stderr, "\t%s\n", args[i]);
370c2aa98e2SPeter Wemm 	}
371c2aa98e2SPeter Wemm 
372c2aa98e2SPeter Wemm 	/*
3733299c2f1SGregory Neil Shapiro 	**  If called with a regular file as standard input, seek to the right
3743299c2f1SGregory Neil Shapiro 	**  position in the file and just exec sendmail.  Could probably skip
3753299c2f1SGregory Neil Shapiro 	**  skip the stat, but it's not unreasonable to believe that a failed
3763299c2f1SGregory Neil Shapiro 	**  seek will cause future reads to fail.
377c2aa98e2SPeter Wemm 	*/
3783299c2f1SGregory Neil Shapiro 
3793299c2f1SGregory Neil Shapiro 	if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode))
3803299c2f1SGregory Neil Shapiro 	{
381c2aa98e2SPeter Wemm 		if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
382c2aa98e2SPeter Wemm 			err(EX_TEMPFAIL, "stdin seek");
3833299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
384c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
385c2aa98e2SPeter Wemm 	}
386c2aa98e2SPeter Wemm 
387c2aa98e2SPeter Wemm 	if (pipe(pdes) < 0)
388c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
389c2aa98e2SPeter Wemm 
3903299c2f1SGregory Neil Shapiro 	switch (pid = FORK())
3913299c2f1SGregory Neil Shapiro 	{
392c2aa98e2SPeter Wemm 	  case -1:				/* Err. */
393c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
3943299c2f1SGregory Neil Shapiro 		/* NOTREACHED */
3953299c2f1SGregory Neil Shapiro 
396c2aa98e2SPeter Wemm 	  case 0:				/* Child. */
3973299c2f1SGregory Neil Shapiro 		if (pdes[0] != STDIN_FILENO)
3983299c2f1SGregory Neil Shapiro 		{
399c2aa98e2SPeter Wemm 			(void) dup2(pdes[0], STDIN_FILENO);
400c2aa98e2SPeter Wemm 			(void) close(pdes[0]);
401c2aa98e2SPeter Wemm 		}
402c2aa98e2SPeter Wemm 		(void) close(pdes[1]);
4033299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
404c2aa98e2SPeter Wemm 		_exit(127);
405c2aa98e2SPeter Wemm 		/* NOTREACHED */
406c2aa98e2SPeter Wemm 	}
407c2aa98e2SPeter Wemm 
408c2aa98e2SPeter Wemm 	if ((fp = fdopen(pdes[1], "w")) == NULL)
409c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
410c2aa98e2SPeter Wemm 	(void) close(pdes[0]);
411c2aa98e2SPeter Wemm 
412c2aa98e2SPeter Wemm 	/* Copy the file down the pipe. */
4133299c2f1SGregory Neil Shapiro 	do
4143299c2f1SGregory Neil Shapiro 	{
415c2aa98e2SPeter Wemm 		(void) fprintf(fp, "%s", lbuf);
416c2aa98e2SPeter Wemm 	} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
417c2aa98e2SPeter Wemm 
418c2aa98e2SPeter Wemm 	if (ferror(stdin))
4193299c2f1SGregory Neil Shapiro 		err(EX_TEMPFAIL, "stdin: %s", errstring(errno));
420c2aa98e2SPeter Wemm 
421c2aa98e2SPeter Wemm 	if (fclose(fp))
422c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
423c2aa98e2SPeter Wemm 
424c2aa98e2SPeter Wemm 	if ((waitpid(pid, &status, 0)) == -1)
425c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
426c2aa98e2SPeter Wemm 
427c2aa98e2SPeter Wemm 	if (!WIFEXITED(status))
4283299c2f1SGregory Neil Shapiro 		err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL);
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm 	if (WEXITSTATUS(status))
431c2aa98e2SPeter Wemm 		err(status, "%s: terminated with %d (non-zero) status",
432c2aa98e2SPeter Wemm 		    _PATH_SENDMAIL, WEXITSTATUS(status));
433c2aa98e2SPeter Wemm 	exit(EX_OK);
4343299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
4353299c2f1SGregory Neil Shapiro 	return EX_OK;
436c2aa98e2SPeter Wemm }
437c2aa98e2SPeter Wemm 
4383299c2f1SGregory Neil Shapiro static void
439c2aa98e2SPeter Wemm usage()
440c2aa98e2SPeter Wemm {
441c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
442c2aa98e2SPeter Wemm 	exit(EX_USAGE);
443c2aa98e2SPeter Wemm }
444c2aa98e2SPeter Wemm 
445c2aa98e2SPeter Wemm #ifdef __STDC__
446c2aa98e2SPeter Wemm # include <stdarg.h>
4473299c2f1SGregory Neil Shapiro #else /* __STDC__ */
448c2aa98e2SPeter Wemm # include <varargs.h>
4493299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
450c2aa98e2SPeter Wemm 
4513299c2f1SGregory Neil Shapiro static void
452c2aa98e2SPeter Wemm #ifdef __STDC__
453c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...)
4543299c2f1SGregory Neil Shapiro #else /* __STDC__ */
455c2aa98e2SPeter Wemm err(eval, fmt, va_alist)
456c2aa98e2SPeter Wemm 	int eval;
457c2aa98e2SPeter Wemm 	const char *fmt;
458c2aa98e2SPeter Wemm 	va_dcl
4593299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
460c2aa98e2SPeter Wemm {
461c2aa98e2SPeter Wemm 	va_list ap;
4623299c2f1SGregory Neil Shapiro #ifdef __STDC__
463c2aa98e2SPeter Wemm 	va_start(ap, fmt);
4643299c2f1SGregory Neil Shapiro #else /* __STDC__ */
465c2aa98e2SPeter Wemm 	va_start(ap);
4663299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
467c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "rmail: ");
468c2aa98e2SPeter Wemm 	(void) vfprintf(stderr, fmt, ap);
469c2aa98e2SPeter Wemm 	va_end(ap);
470c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "\n");
471c2aa98e2SPeter Wemm 	exit(eval);
472c2aa98e2SPeter Wemm }
473