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