1 # include <stdio.h>
2 # include <pwd.h>
3 # include <signal.h>
4 # include <ctype.h>
5 # include "postbox.h"
6 # ifdef LOG
7 # include <syslog.h>
8 # endif LOG
9 
10 static char SccsId[] = "@(#)deliver.c	3.6	03/11/81";
11 
12 /*
13 **  DELIVER -- Deliver a message to a particular address.
14 **
15 **	Algorithm:
16 **		Compute receiving network (i.e., mailer), host, & user.
17 **		If local, see if this is really a program name.
18 **		Build argument for the mailer.
19 **		Create pipe through edit fcn if appropriate.
20 **		Fork.
21 **			Child: call mailer
22 **		Parent: call editfcn if specified.
23 **		Wait for mailer to finish.
24 **		Interpret exit status.
25 **
26 **	Parameters:
27 **		to -- the address to deliver the message to.
28 **		editfcn -- if non-NULL, we want to call this function
29 **			to output the letter (instead of just out-
30 **			putting it raw).
31 **
32 **	Returns:
33 **		zero -- successfully delivered.
34 **		else -- some failure, see ExitStat for more info.
35 **
36 **	Side Effects:
37 **		The standard input is passed off to someone.
38 **
39 **	WARNING:
40 **		The standard input is shared amongst all children,
41 **		including the file pointer.  It is critical that the
42 **		parent waits for the child to finish before forking
43 **		another child.
44 */
45 
46 deliver(to, editfcn)
47 	ADDRESS *to;
48 	int (*editfcn)();
49 {
50 	register struct mailer *m;
51 	char *host;
52 	char *user;
53 	extern struct passwd *getpwnam();
54 	char **pvp;
55 	extern char **buildargv();
56 	auto int st;
57 	register int i;
58 	register char *p;
59 	int pid;
60 	int pvect[2];
61 	extern FILE *fdopen();
62 	extern int errno;
63 	FILE *mfile;
64 	extern putmessage();
65 	extern pipesig();
66 	extern char *index();
67 	extern bool checkcompat();
68 
69 	/*
70 	**  Compute receiving mailer, host, and to addreses.
71 	**	Do some initialization first.  To is the to address
72 	**	for error messages.
73 	**	Also, define the standard per-address macros.
74 	*/
75 
76 	To = to->q_paddr;
77 	m = Mailer[to->q_mailer];
78 	user = to->q_user;
79 	host = to->q_host;
80 	Errors = 0;
81 	errno = 0;
82 	define('u', user);		/* to user */
83 	define('h', host);		/* to host */
84 	define('g', m->m_from);		/* translated from address */
85 # ifdef DEBUG
86 	if (Debug)
87 		printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
88 # endif DEBUG
89 
90 	/*
91 	**  Check to see that these people are allowed to talk to each other.
92 	*/
93 
94 	if (!checkcompat(to))
95 		return(giveresponse(EX_UNAVAILABLE, TRUE, m));
96 
97 	/*
98 	**  Remove quote bits from user/host.
99 	*/
100 
101 	for (p = user; (*p++ &= 0177) != '\0'; )
102 		continue;
103 	if (host != NULL)
104 		for (p = host; (*p++ &= 0177) != '\0'; )
105 			continue;
106 
107 	/*
108 	**  Strip quote bits from names if the mailer wants it.
109 	*/
110 
111 	if (bitset(M_STRIPQ, m->m_flags))
112 	{
113 		stripquotes(user);
114 		stripquotes(host);
115 	}
116 
117 	/*
118 	**  See if this user name is "special".
119 	**	If the user is a program, diddle with the mailer spec.
120 	**	If the user name has a slash in it, assume that this
121 	**		is a file -- send it off without further ado.
122 	**		Note that this means that editfcn's will not
123 	**		be applied to the message.
124 	*/
125 
126 	if (m == Mailer[0])
127 	{
128 		if (*user == '|')
129 		{
130 			user++;
131 			m = Mailer[1];
132 		}
133 		else
134 		{
135 			if (index(user, '/') != NULL)
136 			{
137 				i = mailfile(user);
138 				giveresponse(i, TRUE, m);
139 				return (i);
140 			}
141 		}
142 	}
143 
144 	/*
145 	**  See if the user exists.
146 	**	Strictly, this is only needed to print a pretty
147 	**	error message.
148 	**
149 	**	>>>>>>>>>> This clause assumes that the local mailer
150 	**	>> NOTE >> cannot do any further aliasing; that
151 	**	>>>>>>>>>> function is subsumed by postbox.
152 	*/
153 
154 	if (m == Mailer[0])
155 	{
156 		if (getpwnam(user) == NULL)
157 		{
158 			giveresponse(EX_NOUSER, TRUE, m);
159 			return (EX_NOUSER);
160 		}
161 	}
162 
163 	/*
164 	**  Call the mailer.
165 	**	The argument vector gets built, pipes
166 	**	are created as necessary, and we fork & exec as
167 	**	appropriate.
168 	*/
169 
170 	pvp = buildargv(m, host, user, From.q_paddr);
171 	if (pvp == NULL)
172 	{
173 		usrerr("name too long");
174 		return (-1);
175 	}
176 	rewind(stdin);
177 
178 	/* create a pipe to shove the mail through */
179 	if (pipe(pvect) < 0)
180 	{
181 		syserr("pipe");
182 		return (-1);
183 	}
184 # ifdef VFORK
185 	pid = vfork();
186 # else
187 	pid = fork();
188 # endif
189 	if (pid < 0)
190 	{
191 		syserr("Cannot fork");
192 		close(pvect[0]);
193 		close(pvect[1]);
194 		return (-1);
195 	}
196 	else if (pid == 0)
197 	{
198 		/* child -- set up input & exec mailer */
199 		/* make diagnostic output be standard output */
200 		close(2);
201 		dup(1);
202 		signal(SIGINT, SIG_IGN);
203 		close(0);
204 		if (dup(pvect[0]) < 0)
205 		{
206 			syserr("Cannot dup to zero!");
207 			_exit(EX_OSERR);
208 		}
209 		close(pvect[0]);
210 		close(pvect[1]);
211 		if (!bitset(M_RESTR, m->m_flags))
212 			setuid(getuid());
213 # ifndef VFORK
214 		/*
215 		**  We have to be careful with vfork - we can't mung up the
216 		**  memory but we don't want the mailer to inherit any extra
217 		**  open files.  Chances are the mailer won't
218 		**  care about an extra file, but then again you never know.
219 		**  Actually, we would like to close(fileno(pwf)), but it's
220 		**  declared static so we can't.  But if we fclose(pwf), which
221 		**  is what endpwent does, it closes it in the parent too and
222 		**  the next getpwnam will be slower.  If you have a weird
223 		**  mailer that chokes on the extra file you should do the
224 		**  endpwent().
225 		**
226 		**  Similar comments apply to log.  However, openlog is
227 		**  clever enough to set the FIOCLEX mode on the file,
228 		**  so it will be closed automatically on the exec.
229 		*/
230 
231 		endpwent();
232 # ifdef LOG
233 		closelog();
234 # endif LOG
235 # endif VFORK
236 		execv(m->m_mailer, pvp);
237 		/* syserr fails because log is closed */
238 		/* syserr("Cannot exec %s", m->m_mailer); */
239 		printf("Cannot exec %s\n", m->m_mailer);
240 		fflush(stdout);
241 		_exit(EX_UNAVAILABLE);
242 	}
243 
244 	/* write out message to mailer */
245 	close(pvect[0]);
246 	signal(SIGPIPE, pipesig);
247 	mfile = fdopen(pvect[1], "w");
248 	if (editfcn == NULL)
249 		editfcn = putmessage;
250 	(*editfcn)(mfile, m);
251 	fclose(mfile);
252 
253 	/*
254 	**  Wait for child to die and report status.
255 	**	We should never get fatal errors (e.g., segmentation
256 	**	violation), so we report those specially.  For other
257 	**	errors, we choose a status message (into statmsg),
258 	**	and if it represents an error, we print it.
259 	*/
260 
261 	while ((i = wait(&st)) > 0 && i != pid)
262 		continue;
263 	if (i < 0)
264 	{
265 		syserr("wait");
266 		return (-1);
267 	}
268 	if ((st & 0377) != 0)
269 	{
270 		syserr("%s: stat %o", pvp[0], st);
271 		ExitStat = EX_UNAVAILABLE;
272 		return (-1);
273 	}
274 	i = (st >> 8) & 0377;
275 	giveresponse(i, TRUE, m);
276 	return (i);
277 }
278 /*
279 **  GIVERESPONSE -- Interpret an error response from a mailer
280 **
281 **	Parameters:
282 **		stat -- the status code from the mailer (high byte
283 **			only; core dumps must have been taken care of
284 **			already).
285 **		force -- if set, force an error message output, even
286 **			if the mailer seems to like to print its own
287 **			messages.
288 **		m -- the mailer descriptor for this mailer.
289 **
290 **	Returns:
291 **		stat.
292 **
293 **	Side Effects:
294 **		Errors may be incremented.
295 **		ExitStat may be set.
296 **
297 **	Called By:
298 **		deliver
299 */
300 
301 giveresponse(stat, force, m)
302 	int stat;
303 	int force;
304 	register struct mailer *m;
305 {
306 	register char *statmsg;
307 	extern char *SysExMsg[];
308 	register int i;
309 	extern int N_SysEx;
310 	extern long MsgSize;
311 	char buf[30];
312 	extern char *sprintf();
313 
314 	i = stat - EX__BASE;
315 	if (i < 0 || i > N_SysEx)
316 		statmsg = NULL;
317 	else
318 		statmsg = SysExMsg[i];
319 	if (stat == 0)
320 		statmsg = "ok";
321 	else
322 	{
323 		Errors++;
324 		if (statmsg == NULL && m->m_badstat != 0)
325 		{
326 			stat = m->m_badstat;
327 			i = stat - EX__BASE;
328 # ifdef DEBUG
329 			if (i < 0 || i >= N_SysEx)
330 				syserr("Bad m_badstat %d", stat);
331 			else
332 # endif DEBUG
333 			statmsg = SysExMsg[i];
334 		}
335 		if (statmsg == NULL)
336 			usrerr("unknown mailer response %d", stat);
337 		else if (force || !bitset(M_QUIET, m->m_flags))
338 			usrerr("%s", statmsg);
339 	}
340 
341 	/*
342 	**  Final cleanup.
343 	**	Log a record of the transaction.  Compute the new
344 	**	ExitStat -- if we already had an error, stick with
345 	**	that.
346 	*/
347 
348 	if (statmsg == NULL)
349 	{
350 		sprintf(buf, "error %d", stat);
351 		statmsg = buf;
352 	}
353 
354 # ifdef LOG
355 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
356 # endif LOG
357 	setstat(stat);
358 	return (stat);
359 }
360 /*
361 **  PUTMESSAGE -- output a message to the final mailer.
362 **
363 **	This routine takes care of recreating the header from the
364 **	in-core copy, etc.
365 **
366 **	Parameters:
367 **		fp -- file to output onto.
368 **		m -- a mailer descriptor.
369 **
370 **	Returns:
371 **		none.
372 **
373 **	Side Effects:
374 **		The message is written onto fp.
375 */
376 
377 putmessage(fp, m)
378 	FILE *fp;
379 	struct mailer *m;
380 {
381 	char buf[BUFSIZ];
382 	register int i;
383 	HDR *h;
384 	register char *p;
385 	extern char *arpadate();
386 	extern char *hvalue();
387 	bool anyheader = FALSE;
388 	extern char *expand();
389 	extern char *capitalize();
390 
391 	/* output "From" line unless supressed */
392 	if (!bitset(M_NHDR, m->m_flags))
393 		fprintf(fp, "%s\n", FromLine);
394 
395 	/* clear all "used" bits */
396 	for (h = Header; h != NULL; h = h->h_link)
397 		h->h_flags &= ~H_USED;
398 
399 	/* output date if needed by mailer */
400 	p = hvalue("date");
401 	if (bitset(M_NEEDDATE, m->m_flags) && p == NULL)
402 		p = arpadate(Date);
403 	if (p != NULL)
404 	{
405 		fprintf(fp, "Date: %s\n", p);
406 		anyheader = TRUE;
407 	}
408 
409 	/* output from line if needed by mailer */
410 	p = hvalue("from");
411 	if (bitset(M_NEEDFROM, m->m_flags) && p == NULL)
412 	{
413 		extern char *FullName;
414 
415 		expand("$g", buf, &buf[sizeof buf - 1]);
416 		if (FullName != NULL)
417 			fprintf(fp, "From: %s <%s>\n", FullName, buf);
418 		else
419 			fprintf(fp, "From: %s\n", buf);
420 		anyheader = TRUE;
421 	}
422 	else if (p != NULL)
423 	{
424 		fprintf(fp, "From: %s\n", p);
425 		anyheader = TRUE;
426 	}
427 
428 	/* output message-id field if needed */
429 	p = hvalue("message-id");
430 	if (bitset(M_MSGID, m->m_flags) && p == NULL)
431 		p = MsgId;
432 	if (p != NULL)
433 	{
434 		fprintf(fp, "Message-Id: %s\n", p);
435 		anyheader = TRUE;
436 	}
437 
438 	/* output any other header lines */
439 	for (h = Header; h != NULL; h = h->h_link)
440 	{
441 		if (bitset(H_USED, h->h_flags))
442 			continue;
443 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), h->h_value);
444 		h->h_flags |= H_USED;
445 		anyheader = TRUE;
446 	}
447 
448 	if (anyheader)
449 		fprintf(fp, "\n");
450 
451 	/* output the body of the message */
452 	while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0)
453 		fwrite(buf, 1, i, fp);
454 
455 	if (ferror(fp))
456 	{
457 		syserr("putmessage: write error");
458 		setstat(EX_IOERR);
459 	}
460 }
461 /*
462 **  PIPESIG -- Handle broken pipe signals
463 **
464 **	This just logs an error.
465 **
466 **	Parameters:
467 **		none
468 **
469 **	Returns:
470 **		none
471 **
472 **	Side Effects:
473 **		logs an error message.
474 */
475 
476 pipesig()
477 {
478 	syserr("Broken pipe");
479 	signal(SIGPIPE, SIG_IGN);
480 }
481 /*
482 **  SENDTO -- Designate a send list.
483 **
484 **	The parameter is a comma-separated list of people to send to.
485 **	This routine arranges to send to all of them.
486 **
487 **	Parameters:
488 **		list -- the send list.
489 **		copyf -- the copy flag; passed to parse.
490 **
491 **	Returns:
492 **		none
493 **
494 **	Side Effects:
495 **		none.
496 **
497 **	Called By:
498 **		main
499 **		alias
500 */
501 
502 sendto(list, copyf)
503 	char *list;
504 	int copyf;
505 {
506 	register char *p;
507 	register char *q;
508 	register char c;
509 	ADDRESS *a;
510 	extern ADDRESS *parse();
511 	bool more;
512 
513 	/* more keeps track of what the previous delimiter was */
514 	more = TRUE;
515 	for (p = list; more; )
516 	{
517 		/* find the end of this address */
518 		q = p;
519 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
520 			continue;
521 		more = c != '\0';
522 		*--p = '\0';
523 		if (more)
524 			p++;
525 
526 		/* parse the address */
527 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
528 			continue;
529 
530 		/* arrange to send to this person */
531 		recipient(a);
532 	}
533 	To = NULL;
534 }
535 /*
536 **  RECIPIENT -- Designate a message recipient
537 **
538 **	Saves the named person for future mailing.
539 **
540 **	Parameters:
541 **		a -- the (preparsed) address header for the recipient.
542 **
543 **	Returns:
544 **		none.
545 **
546 **	Side Effects:
547 **		none.
548 **
549 **	Called By:
550 **		sendto
551 **		main
552 */
553 
554 recipient(a)
555 	register ADDRESS *a;
556 {
557 	register ADDRESS *q;
558 	register struct mailer *m;
559 	extern bool forward();
560 	extern int errno;
561 	extern bool sameaddr();
562 
563 	To = a->q_paddr;
564 	m = Mailer[a->q_mailer];
565 	errno = 0;
566 # ifdef DEBUG
567 	if (Debug)
568 		printf("recipient(%s)\n", To);
569 # endif DEBUG
570 
571 	/*
572 	**  Do sickly crude mapping for program mailing, etc.
573 	*/
574 
575 	if (a->q_mailer == 0 && a->q_user[0] == '|')
576 	{
577 		a->q_mailer = 1;
578 		m++;
579 		a->q_user++;
580 	}
581 
582 	/*
583 	**  Look up this person in the recipient list.  If they
584 	**  are there already, return, otherwise continue.
585 	**  If the list is empty, just add it.
586 	*/
587 
588 	if (m->m_sendq == NULL)
589 	{
590 		m->m_sendq = a;
591 	}
592 	else
593 	{
594 		ADDRESS *pq;
595 
596 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
597 		{
598 			if (!ForceMail && sameaddr(q, a, FALSE))
599 			{
600 # ifdef DEBUG
601 				if (Debug)
602 					printf("(%s in sendq)\n", a->q_paddr);
603 # endif DEBUG
604 				return;
605 			}
606 		}
607 
608 		/* add address on list */
609 		q = pq;
610 		q->q_next = NULL;
611 	}
612 	a->q_next = NULL;
613 
614 	/*
615 	**  See if the user wants hir mail forwarded.
616 	**	`Forward' must do the forwarding recursively.
617 	*/
618 
619 	if (m == Mailer[0] && !NoAlias && forward(a))
620 		setbit(QDONTSEND, a->q_flags);
621 
622 	return;
623 }
624 /*
625 **  BUILDARGV -- Build an argument vector for a mail server.
626 **
627 **	Using a template defined in config.c, an argv is built.
628 **	The format of the template is already a vector.  The
629 **	items of this vector are copied, unless a dollar sign
630 **	is encountered.  In this case, the next character
631 **	specifies something else to copy in.  These can be
632 **	any macros.  System defined macros are:
633 **		$f	The from address.
634 **		$h	The host.
635 **		$u	The user.
636 **		$c	The hop count.
637 **	among others.
638 **	The vector is built in a local buffer.  A pointer to
639 **	the static argv is returned.
640 **
641 **	Parameters:
642 **		m -- a pointer to the mailer descriptor.
643 **		host -- the host name to send to.
644 **		user -- the user name to send to.
645 **		from -- the person this mail is from.
646 **
647 **	Returns:
648 **		A pointer to an argv.
649 **
650 **	Side Effects:
651 **		none
652 **
653 **	WARNING:
654 **		Since the argv is staticly allocated, any subsequent
655 **		calls will clobber the old argv.
656 **
657 **	Called By:
658 **		deliver
659 */
660 
661 char **
662 buildargv(m, host, user, from)
663 	struct mailer *m;
664 	char *host;
665 	char *user;
666 	char *from;
667 {
668 	register char *p;
669 	static char *pv[MAXPV+1];
670 	char **pvp;
671 	char **mvp;
672 	static char buf[512];
673 	extern char *expand();
674 	extern char *newstr();
675 
676 	/*
677 	**  Do initial argv setup.
678 	**	Insert the mailer name.  Notice that $x expansion is
679 	**	NOT done on the mailer name.  Then, if the mailer has
680 	**	a picky -f flag, we insert it as appropriate.  This
681 	**	code does not check for 'pv' overflow; this places a
682 	**	manifest lower limit of 4 for MAXPV.
683 	*/
684 
685 	pvp = pv;
686 	*pvp++ = m->m_argv[0];
687 
688 	/* insert -f or -r flag as appropriate */
689 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
690 	{
691 		if (bitset(M_FOPT, m->m_flags))
692 			*pvp++ = "-f";
693 		else
694 			*pvp++ = "-r";
695 		expand(from, buf, &buf[sizeof buf - 1]);
696 		*pvp++ = newstr(buf);
697 	}
698 
699 	/*
700 	**  Build the rest of argv.
701 	**	For each prototype parameter, the prototype is
702 	**	scanned character at a time.  Buffer overflow is
703 	**	checked.
704 	*/
705 
706 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
707 	{
708 		if (pvp >= &pv[MAXPV])
709 		{
710 			syserr("Too many parameters to %s", pv[0]);
711 			return (NULL);
712 		}
713 		expand(p, buf, &buf[sizeof buf - 1]);
714 		*pvp++ = newstr(buf);
715 	}
716 	*pvp = NULL;
717 
718 # ifdef DEBUG
719 	if (Debug)
720 	{
721 		printf("Interpolated argv is:\n");
722 		for (mvp = pv; *mvp != NULL; mvp++)
723 			printf("\t%s\n", *mvp);
724 	}
725 # endif DEBUG
726 
727 	return (pv);
728 }
729 /*
730 **  MAILFILE -- Send a message to a file.
731 **
732 **	Parameters:
733 **		filename -- the name of the file to send to.
734 **
735 **	Returns:
736 **		The exit code associated with the operation.
737 **
738 **	Side Effects:
739 **		none.
740 **
741 **	Called By:
742 **		deliver
743 */
744 
745 mailfile(filename)
746 	char *filename;
747 {
748 	register FILE *f;
749 
750 	f = fopen(filename, "a");
751 	if (f == NULL)
752 		return (EX_CANTCREAT);
753 
754 	putmessage(f, Mailer[1]);
755 	fputs("\n", f);
756 	fclose(f);
757 	return (EX_OK);
758 }
759