xref: /freebsd/contrib/sendmail/rmail/rmail.c (revision d995d2ba6b346ad29395c43f83421c01a446d2ae)
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
22d995d2baSGregory Neil Shapiro static char id[] = "@(#)$Id: rmail.c,v 8.39.4.8 2000/09/16 22:20:25 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 
94d995d2baSGregory Neil Shapiro #if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11)
95c2aa98e2SPeter Wemm # define HASSNPRINTF	1
96d995d2baSGregory Neil Shapiro #endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11) */
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;
156d995d2baSGregory Neil Shapiro 	char **args, 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 
315d995d2baSGregory Neil Shapiro 
316d995d2baSGregory Neil Shapiro 	/* Allocate args (with room for sendmail args as well as recipients */
317d995d2baSGregory Neil Shapiro 	args = (char **)xalloc(sizeof(*args) * (10 + argc));
318d995d2baSGregory Neil Shapiro 
319c2aa98e2SPeter Wemm 	i = 0;
320c2aa98e2SPeter Wemm 	args[i++] = _PATH_SENDMAIL;	/* Build sendmail's argument list. */
321d995d2baSGregory Neil Shapiro 	args[i++] = "-G";		/* relay submission */
322c2aa98e2SPeter Wemm 	args[i++] = "-oee";		/* No errors, just status. */
323829be59cSPeter Wemm #ifdef QUEUE_ONLY
324c2aa98e2SPeter Wemm 	args[i++] = "-odq";		/* Queue it, don't try to deliver. */
325829be59cSPeter Wemm #else
326829be59cSPeter Wemm 	args[i++] = "-odi";		/* Deliver in foreground. */
327829be59cSPeter Wemm #endif
328c2aa98e2SPeter Wemm 	args[i++] = "-oi";		/* Ignore '.' on a line by itself. */
329c2aa98e2SPeter Wemm 
330c2aa98e2SPeter Wemm 	/* set from system and protocol used */
331c2aa98e2SPeter Wemm 	if (from_sys == NULL)
3323299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s", domain);
333c2aa98e2SPeter Wemm 	else if (strchr(from_sys, '.') == NULL)
3343299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s:%s.%s",
335c2aa98e2SPeter Wemm 			domain, from_sys, domain);
336c2aa98e2SPeter Wemm 	else
3373299c2f1SGregory Neil Shapiro 		snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
338c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
339c2aa98e2SPeter Wemm 
340c2aa98e2SPeter Wemm 	/* Set name of ``from'' person. */
3413299c2f1SGregory Neil Shapiro 	snprintf(buf, sizeof(buf), "-f%s%s",
342c2aa98e2SPeter Wemm 		 from_path ? from_path : "", from_user);
343c2aa98e2SPeter Wemm 	args[i++] = newstr(buf);
344c2aa98e2SPeter Wemm 
345c2aa98e2SPeter Wemm 	/*
3463299c2f1SGregory Neil Shapiro 	**  Don't copy arguments beginning with - as they will be
3473299c2f1SGregory Neil Shapiro 	**  passed to sendmail and could be interpreted as flags.
3483299c2f1SGregory Neil Shapiro 	**  To prevent confusion of sendmail wrap < and > around
3493299c2f1SGregory Neil Shapiro 	**  the address (helps to pass addrs like @gw1,@gw2:aa@bb)
350c2aa98e2SPeter Wemm 	*/
3513299c2f1SGregory Neil Shapiro 
352d995d2baSGregory Neil Shapiro 	while (*argv != NULL)
3533299c2f1SGregory Neil Shapiro 	{
354c2aa98e2SPeter Wemm 		if (**argv == '-')
355c2aa98e2SPeter Wemm 			err(EX_USAGE, "dash precedes argument: %s", *argv);
3563299c2f1SGregory Neil Shapiro 
357c2aa98e2SPeter Wemm 		if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
358c2aa98e2SPeter Wemm 			args[i++] = *argv;
3593299c2f1SGregory Neil Shapiro 		else
3603299c2f1SGregory Neil Shapiro 		{
3613299c2f1SGregory Neil Shapiro 			len = strlen(*argv) + 3;
3623299c2f1SGregory Neil Shapiro 			if ((args[i] = malloc(len)) == NULL)
363c2aa98e2SPeter Wemm 				err(EX_TEMPFAIL, "Cannot malloc");
3643299c2f1SGregory Neil Shapiro 			snprintf(args[i++], len, "<%s>", *argv);
365c2aa98e2SPeter Wemm 		}
366c2aa98e2SPeter Wemm 		argv++;
367d995d2baSGregory Neil Shapiro 		argc--;
368d995d2baSGregory Neil Shapiro 
369d995d2baSGregory Neil Shapiro 		/* Paranoia check, argc used for args[] bound */
370d995d2baSGregory Neil Shapiro 		if (argc < 0)
371d995d2baSGregory Neil Shapiro 			err(EX_SOFTWARE, "Argument count mismatch");
372c2aa98e2SPeter Wemm 	}
373d995d2baSGregory Neil Shapiro 	args[i] = NULL;
374c2aa98e2SPeter Wemm 
3753299c2f1SGregory Neil Shapiro 	if (debug)
3763299c2f1SGregory Neil Shapiro 	{
3773299c2f1SGregory Neil Shapiro 		fprintf(stderr, "Sendmail arguments:\n");
378d995d2baSGregory Neil Shapiro 		for (i = 0; args[i] != NULL; i++)
3793299c2f1SGregory Neil Shapiro 			fprintf(stderr, "\t%s\n", args[i]);
380c2aa98e2SPeter Wemm 	}
381c2aa98e2SPeter Wemm 
382c2aa98e2SPeter Wemm 	/*
3833299c2f1SGregory Neil Shapiro 	**  If called with a regular file as standard input, seek to the right
3843299c2f1SGregory Neil Shapiro 	**  position in the file and just exec sendmail.  Could probably skip
3853299c2f1SGregory Neil Shapiro 	**  skip the stat, but it's not unreasonable to believe that a failed
3863299c2f1SGregory Neil Shapiro 	**  seek will cause future reads to fail.
387c2aa98e2SPeter Wemm 	*/
3883299c2f1SGregory Neil Shapiro 
3893299c2f1SGregory Neil Shapiro 	if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode))
3903299c2f1SGregory Neil Shapiro 	{
391c2aa98e2SPeter Wemm 		if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
392c2aa98e2SPeter Wemm 			err(EX_TEMPFAIL, "stdin seek");
3933299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
394c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
395c2aa98e2SPeter Wemm 	}
396c2aa98e2SPeter Wemm 
397c2aa98e2SPeter Wemm 	if (pipe(pdes) < 0)
398c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
399c2aa98e2SPeter Wemm 
4003299c2f1SGregory Neil Shapiro 	switch (pid = FORK())
4013299c2f1SGregory Neil Shapiro 	{
402c2aa98e2SPeter Wemm 	  case -1:				/* Err. */
403c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
4043299c2f1SGregory Neil Shapiro 		/* NOTREACHED */
4053299c2f1SGregory Neil Shapiro 
406c2aa98e2SPeter Wemm 	  case 0:				/* Child. */
4073299c2f1SGregory Neil Shapiro 		if (pdes[0] != STDIN_FILENO)
4083299c2f1SGregory Neil Shapiro 		{
409c2aa98e2SPeter Wemm 			(void) dup2(pdes[0], STDIN_FILENO);
410c2aa98e2SPeter Wemm 			(void) close(pdes[0]);
411c2aa98e2SPeter Wemm 		}
412c2aa98e2SPeter Wemm 		(void) close(pdes[1]);
4133299c2f1SGregory Neil Shapiro 		(void) execv(_PATH_SENDMAIL, args);
414c2aa98e2SPeter Wemm 		_exit(127);
415c2aa98e2SPeter Wemm 		/* NOTREACHED */
416c2aa98e2SPeter Wemm 	}
417c2aa98e2SPeter Wemm 
418c2aa98e2SPeter Wemm 	if ((fp = fdopen(pdes[1], "w")) == NULL)
419c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
420c2aa98e2SPeter Wemm 	(void) close(pdes[0]);
421c2aa98e2SPeter Wemm 
422c2aa98e2SPeter Wemm 	/* Copy the file down the pipe. */
4233299c2f1SGregory Neil Shapiro 	do
4243299c2f1SGregory Neil Shapiro 	{
425c2aa98e2SPeter Wemm 		(void) fprintf(fp, "%s", lbuf);
426c2aa98e2SPeter Wemm 	} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
427c2aa98e2SPeter Wemm 
428c2aa98e2SPeter Wemm 	if (ferror(stdin))
4293299c2f1SGregory Neil Shapiro 		err(EX_TEMPFAIL, "stdin: %s", errstring(errno));
430c2aa98e2SPeter Wemm 
431c2aa98e2SPeter Wemm 	if (fclose(fp))
432c2aa98e2SPeter Wemm 		err(EX_OSERR, NULL);
433c2aa98e2SPeter Wemm 
434c2aa98e2SPeter Wemm 	if ((waitpid(pid, &status, 0)) == -1)
435c2aa98e2SPeter Wemm 		err(EX_OSERR, "%s", _PATH_SENDMAIL);
436c2aa98e2SPeter Wemm 
437c2aa98e2SPeter Wemm 	if (!WIFEXITED(status))
4383299c2f1SGregory Neil Shapiro 		err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL);
439c2aa98e2SPeter Wemm 
440c2aa98e2SPeter Wemm 	if (WEXITSTATUS(status))
441c2aa98e2SPeter Wemm 		err(status, "%s: terminated with %d (non-zero) status",
442c2aa98e2SPeter Wemm 		    _PATH_SENDMAIL, WEXITSTATUS(status));
443c2aa98e2SPeter Wemm 	exit(EX_OK);
4443299c2f1SGregory Neil Shapiro 	/* NOTREACHED */
4453299c2f1SGregory Neil Shapiro 	return EX_OK;
446c2aa98e2SPeter Wemm }
447c2aa98e2SPeter Wemm 
4483299c2f1SGregory Neil Shapiro static void
449c2aa98e2SPeter Wemm usage()
450c2aa98e2SPeter Wemm {
451c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
452c2aa98e2SPeter Wemm 	exit(EX_USAGE);
453c2aa98e2SPeter Wemm }
454c2aa98e2SPeter Wemm 
455c2aa98e2SPeter Wemm #ifdef __STDC__
456c2aa98e2SPeter Wemm # include <stdarg.h>
4573299c2f1SGregory Neil Shapiro #else /* __STDC__ */
458c2aa98e2SPeter Wemm # include <varargs.h>
4593299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
460c2aa98e2SPeter Wemm 
4613299c2f1SGregory Neil Shapiro static void
462c2aa98e2SPeter Wemm #ifdef __STDC__
463c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...)
4643299c2f1SGregory Neil Shapiro #else /* __STDC__ */
465c2aa98e2SPeter Wemm err(eval, fmt, va_alist)
466c2aa98e2SPeter Wemm 	int eval;
467c2aa98e2SPeter Wemm 	const char *fmt;
468c2aa98e2SPeter Wemm 	va_dcl
4693299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
470c2aa98e2SPeter Wemm {
471c2aa98e2SPeter Wemm 	va_list ap;
4723299c2f1SGregory Neil Shapiro #ifdef __STDC__
473c2aa98e2SPeter Wemm 	va_start(ap, fmt);
4743299c2f1SGregory Neil Shapiro #else /* __STDC__ */
475c2aa98e2SPeter Wemm 	va_start(ap);
4763299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
477c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "rmail: ");
478c2aa98e2SPeter Wemm 	(void) vfprintf(stderr, fmt, ap);
479c2aa98e2SPeter Wemm 	va_end(ap);
480c2aa98e2SPeter Wemm 	(void) fprintf(stderr, "\n");
481c2aa98e2SPeter Wemm 	exit(eval);
482c2aa98e2SPeter Wemm }
483