1 # include <signal.h>
2 # include <errno.h>
3 # include "sendmail.h"
4 # include <sys/stat.h>
5 # ifdef LOG
6 # include <syslog.h>
7 # endif LOG
8 
9 static char SccsId[] = "@(#)deliver.c	3.50	10/26/81";
10 
11 /*
12 **  DELIVER -- Deliver a message to a list of addresses.
13 **
14 **	This routine delivers to everyone on the same host as the
15 **	user on the head of the list.  It is clever about mailers
16 **	that don't handle multiple users.  It is NOT guaranteed
17 **	that it will deliver to all these addresses however -- so
18 **	deliver should be called once for each address on the
19 **	list.
20 **
21 **	Parameters:
22 **		firstto -- head of the address list to deliver to.
23 **		editfcn -- if non-NULL, we want to call this function
24 **			to output the letter (instead of just out-
25 **			putting it raw).
26 **
27 **	Returns:
28 **		zero -- successfully delivered.
29 **		else -- some failure, see ExitStat for more info.
30 **
31 **	Side Effects:
32 **		The standard input is passed off to someone.
33 */
34 
35 deliver(firstto, editfcn)
36 	ADDRESS *firstto;
37 	int (*editfcn)();
38 {
39 	char *host;			/* host being sent to */
40 	char *user;			/* user being sent to */
41 	char **pvp;
42 	register char **mvp;
43 	register char *p;
44 	register struct mailer *m;	/* mailer for this recipient */
45 	register int i;
46 	extern putmessage();
47 	extern bool checkcompat();
48 	char *pv[MAXPV+1];
49 	char tobuf[MAXLINE];		/* text line of to people */
50 	char buf[MAXNAME];
51 	ADDRESS *ctladdr;
52 	extern ADDRESS *getctladdr();
53 	char tfrombuf[MAXNAME];		/* translated from person */
54 	extern char **prescan();
55 	register ADDRESS *to = firstto;
56 
57 	errno = 0;
58 	if (!ForceMail && bitset(QDONTSEND, to->q_flags))
59 		return (0);
60 
61 # ifdef DEBUG
62 	if (Debug)
63 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
64 			to->q_mailer->m_mno, to->q_host, to->q_user);
65 # endif DEBUG
66 
67 	/*
68 	**  Do initial argv setup.
69 	**	Insert the mailer name.  Notice that $x expansion is
70 	**	NOT done on the mailer name.  Then, if the mailer has
71 	**	a picky -f flag, we insert it as appropriate.  This
72 	**	code does not check for 'pv' overflow; this places a
73 	**	manifest lower limit of 4 for MAXPV.
74 	*/
75 
76 	m = to->q_mailer;
77 	host = to->q_host;
78 
79 	/* rewrite from address, using rewriting rules */
80 	(void) expand(m->m_from, buf, &buf[sizeof buf - 1]);
81 	mvp = prescan(buf, '\0');
82 	if (mvp == NULL)
83 	{
84 		syserr("bad mailer from translate \"%s\"", buf);
85 		return (EX_SOFTWARE);
86 	}
87 	rewrite(mvp, 2);
88 	cataddr(mvp, tfrombuf, sizeof tfrombuf);
89 
90 	define('g', tfrombuf);		/* translated sender address */
91 	define('h', host);		/* to host */
92 	Errors = 0;
93 	pvp = pv;
94 	*pvp++ = m->m_argv[0];
95 
96 	/* insert -f or -r flag as appropriate */
97 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
98 	{
99 		if (bitset(M_FOPT, m->m_flags))
100 			*pvp++ = "-f";
101 		else
102 			*pvp++ = "-r";
103 		(void) expand("$g", buf, &buf[sizeof buf - 1]);
104 		*pvp++ = newstr(buf);
105 	}
106 
107 	/*
108 	**  Append the other fixed parts of the argv.  These run
109 	**  up to the first entry containing "$u".  There can only
110 	**  be one of these, and there are only a few more slots
111 	**  in the pv after it.
112 	*/
113 
114 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
115 	{
116 		while ((p = index(p, '$')) != NULL)
117 			if (*++p == 'u')
118 				break;
119 		if (p != NULL)
120 			break;
121 
122 		/* this entry is safe -- go ahead and process it */
123 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
124 		*pvp++ = newstr(buf);
125 		if (pvp >= &pv[MAXPV - 3])
126 		{
127 			syserr("Too many parameters to %s before $u", pv[0]);
128 			return (-1);
129 		}
130 	}
131 	if (*mvp == NULL)
132 		syserr("No $u in mailer argv for %s", pv[0]);
133 
134 	/*
135 	**  At this point *mvp points to the argument with $u.  We
136 	**  run through our address list and append all the addresses
137 	**  we can.  If we run out of space, do not fret!  We can
138 	**  always send another copy later.
139 	*/
140 
141 	tobuf[0] = '\0';
142 	To = tobuf;
143 	ctladdr = NULL;
144 	for (; to != NULL; to = to->q_next)
145 	{
146 		/* avoid sending multiple recipients to dumb mailers */
147 		if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags))
148 			break;
149 
150 		/* if already sent or not for this host, don't send */
151 		if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) ||
152 		    strcmp(to->q_host, host) != 0)
153 			continue;
154 
155 		/* compute effective uid/gid when sending */
156 		if (to->q_mailer == ProgMailer)
157 			ctladdr = getctladdr(to);
158 
159 		user = to->q_user;
160 		To = to->q_paddr;
161 		to->q_flags |= QDONTSEND;
162 # ifdef DEBUG
163 		if (Debug)
164 			printf("   send to `%s'\n", user);
165 # endif DEBUG
166 
167 		/*
168 		**  Check to see that these people are allowed to
169 		**  talk to each other.
170 		*/
171 
172 		if (!checkcompat(to))
173 		{
174 			giveresponse(EX_UNAVAILABLE, TRUE, m);
175 			continue;
176 		}
177 
178 		/*
179 		**  Strip quote bits from names if the mailer is dumb
180 		**	about them.
181 		*/
182 
183 		if (bitset(M_STRIPQ, m->m_flags))
184 		{
185 			stripquotes(user, TRUE);
186 			stripquotes(host, TRUE);
187 		}
188 		else
189 		{
190 			stripquotes(user, FALSE);
191 			stripquotes(host, FALSE);
192 		}
193 
194 		/*
195 		**  If an error message has already been given, don't
196 		**	bother to send to this address.
197 		**
198 		**	>>>>>>>>>> This clause assumes that the local mailer
199 		**	>> NOTE >> cannot do any further aliasing; that
200 		**	>>>>>>>>>> function is subsumed by sendmail.
201 		*/
202 
203 		if (bitset(QBADADDR, to->q_flags))
204 			continue;
205 
206 		/* save statistics.... */
207 		Stat.stat_nt[to->q_mailer->m_mno]++;
208 		Stat.stat_bt[to->q_mailer->m_mno] += kbytes(MsgSize);
209 
210 		/*
211 		**  See if this user name is "special".
212 		**	If the user name has a slash in it, assume that this
213 		**	is a file -- send it off without further ado.
214 		**	Note that this means that editfcn's will not
215 		**	be applied to the message.  Also note that
216 		**	this type of addresses is not processed along
217 		**	with the others, so we fudge on the To person.
218 		*/
219 
220 		if (m == LocalMailer)
221 		{
222 			if (index(user, '/') != NULL)
223 			{
224 				i = mailfile(user, getctladdr(to));
225 				giveresponse(i, TRUE, m);
226 				continue;
227 			}
228 		}
229 
230 		/*
231 		**  Address is verified -- add this user to mailer
232 		**  argv, and add it to the print list of recipients.
233 		*/
234 
235 		/* create list of users for error messages */
236 		if (tobuf[0] != '\0')
237 			(void) strcat(tobuf, ",");
238 		(void) strcat(tobuf, to->q_paddr);
239 		define('u', user);		/* to user */
240 		define('z', to->q_home);	/* user's home */
241 
242 		/* expand out this user */
243 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
244 		*pvp++ = newstr(buf);
245 		if (pvp >= &pv[MAXPV - 2])
246 		{
247 			/* allow some space for trailing parms */
248 			break;
249 		}
250 	}
251 
252 	/* see if any addresses still exist */
253 	if (tobuf[0] == '\0')
254 		return (0);
255 
256 	/* print out messages as full list */
257 	To = tobuf;
258 
259 	/*
260 	**  Fill out any parameters after the $u parameter.
261 	*/
262 
263 	while (*++mvp != NULL)
264 	{
265 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
266 		*pvp++ = newstr(buf);
267 		if (pvp >= &pv[MAXPV])
268 			syserr("deliver: pv overflow after $u for %s", pv[0]);
269 	}
270 	*pvp++ = NULL;
271 
272 	/*
273 	**  Call the mailer.
274 	**	The argument vector gets built, pipes
275 	**	are created as necessary, and we fork & exec as
276 	**	appropriate.
277 	*/
278 
279 	if (editfcn == NULL)
280 		editfcn = putmessage;
281 	if (ctladdr == NULL)
282 		ctladdr = &From;
283 	i = sendoff(m, pv, editfcn, ctladdr);
284 
285 	/*
286 	**  If we got a temporary failure, arrange to queue the
287 	**  addressees.
288 	*/
289 
290 	if (i == EX_TEMPFAIL)
291 	{
292 		QueueUp = TRUE;
293 		for (to = firstto; to != NULL; to = to->q_next)
294 		{
295 			if (bitset(QBADADDR, to->q_flags))
296 				continue;
297 			to->q_flags |= QQUEUEUP;
298 		}
299 	}
300 
301 	errno = 0;
302 	return (i);
303 }
304 /*
305 **  DOFORK -- do a fork, retrying a couple of times on failure.
306 **
307 **	This MUST be a macro, since after a vfork we are running
308 **	two processes on the same stack!!!
309 **
310 **	Parameters:
311 **		none.
312 **
313 **	Returns:
314 **		From a macro???  You've got to be kidding!
315 **
316 **	Side Effects:
317 **		Modifies the ==> LOCAL <== variable 'pid', leaving:
318 **			pid of child in parent, zero in child.
319 **			-1 on unrecoverable error.
320 **
321 **	Notes:
322 **		I'm awfully sorry this looks so awful.  That's
323 **		vfork for you.....
324 */
325 
326 # define NFORKTRIES	5
327 # ifdef VFORK
328 # define XFORK	vfork
329 # else VFORK
330 # define XFORK	fork
331 # endif VFORK
332 
333 # define DOFORK(fORKfN) \
334 {\
335 	register int i;\
336 \
337 	for (i = NFORKTRIES; i-- > 0; )\
338 	{\
339 		pid = fORKfN();\
340 		if (pid >= 0)\
341 			break;\
342 		sleep((unsigned) NFORKTRIES - i);\
343 	}\
344 }
345 /*
346 **  SENDOFF -- send off call to mailer & collect response.
347 **
348 **	Parameters:
349 **		m -- mailer descriptor.
350 **		pvp -- parameter vector to send to it.
351 **		editfcn -- function to pipe it through.
352 **		ctladdr -- an address pointer controlling the
353 **			user/groupid etc. of the mailer.
354 **
355 **	Returns:
356 **		exit status of mailer.
357 **
358 **	Side Effects:
359 **		none.
360 */
361 
362 sendoff(m, pvp, editfcn, ctladdr)
363 	struct mailer *m;
364 	char **pvp;
365 	int (*editfcn)();
366 	ADDRESS *ctladdr;
367 {
368 	auto int st;
369 	register int i;
370 	int pid;
371 	int pvect[2];
372 	FILE *mfile;
373 	extern putmessage();
374 	extern FILE *fdopen();
375 
376 # ifdef DEBUG
377 	if (Debug)
378 	{
379 		printf("Sendoff:\n");
380 		printav(pvp);
381 	}
382 # endif DEBUG
383 	errno = 0;
384 
385 	/* create a pipe to shove the mail through */
386 	if (pipe(pvect) < 0)
387 	{
388 		syserr("pipe");
389 		return (-1);
390 	}
391 	DOFORK(XFORK);
392 	/* pid is set by DOFORK */
393 	if (pid < 0)
394 	{
395 		syserr("Cannot fork");
396 		(void) close(pvect[0]);
397 		(void) close(pvect[1]);
398 		return (-1);
399 	}
400 	else if (pid == 0)
401 	{
402 		/* child -- set up input & exec mailer */
403 		/* make diagnostic output be standard output */
404 		(void) signal(SIGINT, SIG_IGN);
405 		(void) signal(SIGHUP, SIG_IGN);
406 		(void) signal(SIGTERM, SIG_DFL);
407 		(void) close(2);
408 		(void) dup(1);
409 		(void) close(0);
410 		if (dup(pvect[0]) < 0)
411 		{
412 			syserr("Cannot dup to zero!");
413 			_exit(EX_OSERR);
414 		}
415 		(void) close(pvect[0]);
416 		(void) close(pvect[1]);
417 		if (!bitset(M_RESTR, m->m_flags))
418 		{
419 			if (ctladdr->q_uid == 0)
420 			{
421 				extern int DefUid, DefGid;
422 
423 				(void) setgid(DefGid);
424 				(void) setuid(DefUid);
425 			}
426 			else
427 			{
428 				(void) setgid(ctladdr->q_gid);
429 				(void) setuid(ctladdr->q_uid);
430 			}
431 		}
432 # ifndef VFORK
433 		/*
434 		**  We have to be careful with vfork - we can't mung up the
435 		**  memory but we don't want the mailer to inherit any extra
436 		**  open files.  Chances are the mailer won't
437 		**  care about an extra file, but then again you never know.
438 		**  Actually, we would like to close(fileno(pwf)), but it's
439 		**  declared static so we can't.  But if we fclose(pwf), which
440 		**  is what endpwent does, it closes it in the parent too and
441 		**  the next getpwnam will be slower.  If you have a weird
442 		**  mailer that chokes on the extra file you should do the
443 		**  endpwent().
444 		**
445 		**  Similar comments apply to log.  However, openlog is
446 		**  clever enough to set the FIOCLEX mode on the file,
447 		**  so it will be closed automatically on the exec.
448 		*/
449 
450 		endpwent();
451 # ifdef LOG
452 		closelog();
453 # endif LOG
454 # endif VFORK
455 		execv(m->m_mailer, pvp);
456 		/* syserr fails because log is closed */
457 		/* syserr("Cannot exec %s", m->m_mailer); */
458 		printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno);
459 		(void) fflush(stdout);
460 		_exit(EX_UNAVAILABLE);
461 	}
462 
463 	/* write out message to mailer */
464 	(void) close(pvect[0]);
465 	(void) signal(SIGPIPE, SIG_IGN);
466 	mfile = fdopen(pvect[1], "w");
467 	if (editfcn == NULL)
468 		editfcn = putmessage;
469 	(*editfcn)(mfile, m);
470 	(void) fclose(mfile);
471 
472 	/*
473 	**  Wait for child to die and report status.
474 	**	We should never get fatal errors (e.g., segmentation
475 	**	violation), so we report those specially.  For other
476 	**	errors, we choose a status message (into statmsg),
477 	**	and if it represents an error, we print it.
478 	*/
479 
480 	while ((i = wait(&st)) > 0 && i != pid)
481 		continue;
482 	if (i < 0)
483 	{
484 		syserr("wait");
485 		return (-1);
486 	}
487 	if ((st & 0377) != 0)
488 	{
489 		syserr("%s: stat %o", pvp[0], st);
490 		ExitStat = EX_UNAVAILABLE;
491 		return (-1);
492 	}
493 	i = (st >> 8) & 0377;
494 	giveresponse(i, TRUE, m);
495 	return (i);
496 }
497 /*
498 **  GIVERESPONSE -- Interpret an error response from a mailer
499 **
500 **	Parameters:
501 **		stat -- the status code from the mailer (high byte
502 **			only; core dumps must have been taken care of
503 **			already).
504 **		force -- if set, force an error message output, even
505 **			if the mailer seems to like to print its own
506 **			messages.
507 **		m -- the mailer descriptor for this mailer.
508 **
509 **	Returns:
510 **		none.
511 **
512 **	Side Effects:
513 **		Errors may be incremented.
514 **		ExitStat may be set.
515 */
516 
517 giveresponse(stat, force, m)
518 	int stat;
519 	int force;
520 	register struct mailer *m;
521 {
522 	register char *statmsg;
523 	extern char *SysExMsg[];
524 	register int i;
525 	extern int N_SysEx;
526 	char buf[30];
527 
528 	/*
529 	**  Compute status message from code.
530 	*/
531 
532 	i = stat - EX__BASE;
533 	if (i < 0 || i > N_SysEx)
534 		statmsg = NULL;
535 	else
536 		statmsg = SysExMsg[i];
537 	if (stat == 0)
538 	{
539 		if (bitset(M_LOCAL, m->m_flags))
540 			statmsg = "delivered";
541 		else
542 			statmsg = "queued";
543 		if (Verbose)
544 			message(Arpa_Info, statmsg);
545 	}
546 	else if (stat == EX_TEMPFAIL)
547 	{
548 		if (Verbose)
549 			message(Arpa_Info, "transmission deferred");
550 	}
551 	else
552 	{
553 		Errors++;
554 		if (statmsg == NULL && m->m_badstat != 0)
555 		{
556 			stat = m->m_badstat;
557 			i = stat - EX__BASE;
558 # ifdef DEBUG
559 			if (i < 0 || i >= N_SysEx)
560 				syserr("Bad m_badstat %d", stat);
561 			else
562 # endif DEBUG
563 			statmsg = SysExMsg[i];
564 		}
565 		if (statmsg == NULL)
566 			usrerr("unknown mailer response %d", stat);
567 		else if (force || !bitset(M_QUIET, m->m_flags) || Verbose)
568 			usrerr("%s", statmsg);
569 	}
570 
571 	/*
572 	**  Final cleanup.
573 	**	Log a record of the transaction.  Compute the new
574 	**	ExitStat -- if we already had an error, stick with
575 	**	that.
576 	*/
577 
578 	if (statmsg == NULL)
579 	{
580 		(void) sprintf(buf, "error %d", stat);
581 		statmsg = buf;
582 	}
583 
584 # ifdef LOG
585 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
586 # endif LOG
587 	if (stat != EX_TEMPFAIL)
588 		setstat(stat);
589 }
590 /*
591 **  PUTMESSAGE -- output a message to the final mailer.
592 **
593 **	This routine takes care of recreating the header from the
594 **	in-core copy, etc.
595 **
596 **	Parameters:
597 **		fp -- file to output onto.
598 **		m -- a mailer descriptor.
599 **
600 **	Returns:
601 **		none.
602 **
603 **	Side Effects:
604 **		The message is written onto fp.
605 */
606 
607 putmessage(fp, m)
608 	FILE *fp;
609 	struct mailer *m;
610 {
611 	char buf[BUFSIZ];
612 	register int i;
613 	register HDR *h;
614 	extern char *arpadate();
615 	bool anyheader = FALSE;
616 	extern char *capitalize();
617 	extern char *hvalue();
618 	extern bool samefrom();
619 	char *of_line;
620 
621 	/*
622 	**  Output "From" line unless supressed
623 	*/
624 
625 	if (!bitset(M_NHDR, m->m_flags))
626 	{
627 		(void) expand("$l", buf, &buf[sizeof buf - 1]);
628 		fprintf(fp, "%s\n", buf);
629 	}
630 
631 	/*
632 	**  Output all header lines
633 	*/
634 
635 	of_line = hvalue("original-from");
636 	for (h = Header; h != NULL; h = h->h_link)
637 	{
638 		register char *p;
639 		char *origfrom = OrigFrom;
640 		bool nooutput;
641 
642 		nooutput = FALSE;
643 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags))
644 		{
645 			p = ")><(";		/* can't happen (I hope) */
646 			nooutput = TRUE;
647 		}
648 
649 		/* use From: line from message if generated is the same */
650 		if (strcmp(h->h_field, "from") == 0 && origfrom != NULL &&
651 		    strcmp(m->m_from, "$f") == 0 && of_line == NULL)
652 		{
653 			p = origfrom;
654 			origfrom = NULL;
655 		}
656 		else if (bitset(H_DEFAULT, h->h_flags))
657 		{
658 			(void) expand(h->h_value, buf, &buf[sizeof buf]);
659 			p = buf;
660 		}
661 		else
662 			p = h->h_value;
663 		if (p == NULL || *p == '\0')
664 			continue;
665 
666 		/* hack, hack -- output Original-From field if different */
667 		if (strcmp(h->h_field, "from") == 0 && origfrom != NULL)
668 		{
669 			/* output new Original-From line if needed */
670 			if (of_line == NULL && !samefrom(p, origfrom))
671 			{
672 				fprintf(fp, "Original-From: %s\n", origfrom);
673 				anyheader = TRUE;
674 			}
675 			if (of_line != NULL && !nooutput && samefrom(p, of_line))
676 			{
677 				/* delete Original-From: line if redundant */
678 				p = of_line;
679 				of_line = NULL;
680 			}
681 		}
682 		else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL)
683 			nooutput = TRUE;
684 
685 		/* finally, output the header line */
686 		if (!nooutput)
687 		{
688 			fprintf(fp, "%s: %s\n", capitalize(h->h_field), p);
689 			h->h_flags |= H_USED;
690 			anyheader = TRUE;
691 		}
692 	}
693 	if (anyheader)
694 		fprintf(fp, "\n");
695 
696 	/*
697 	**  Output the body of the message
698 	*/
699 
700 	if (TempFile != NULL)
701 	{
702 		rewind(TempFile);
703 		while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, TempFile)) > 0)
704 			(void) fwrite(buf, 1, i, fp);
705 
706 		if (ferror(TempFile))
707 		{
708 			syserr("putmessage: read error");
709 			setstat(EX_IOERR);
710 		}
711 	}
712 
713 	(void) fflush(fp);
714 	if (ferror(fp) && errno != EPIPE)
715 	{
716 		syserr("putmessage: write error");
717 		setstat(EX_IOERR);
718 	}
719 	errno = 0;
720 }
721 /*
722 **  SAMEFROM -- tell if two text addresses represent the same from address.
723 **
724 **	Parameters:
725 **		ifrom -- internally generated form of from address.
726 **		efrom -- external form of from address.
727 **
728 **	Returns:
729 **		TRUE -- if they convey the same info.
730 **		FALSE -- if any information has been lost.
731 **
732 **	Side Effects:
733 **		none.
734 */
735 
736 bool
737 samefrom(ifrom, efrom)
738 	char *ifrom;
739 	char *efrom;
740 {
741 	register char *p;
742 	char buf[MAXNAME + 4];
743 
744 # ifdef DEBUG
745 	if (Debug > 7)
746 		printf("samefrom(%s,%s)-->", ifrom, efrom);
747 # endif DEBUG
748 	if (strcmp(ifrom, efrom) == 0)
749 		goto success;
750 	p = index(ifrom, '@');
751 	if (p == NULL)
752 		goto failure;
753 	*p = '\0';
754 	strcpy(buf, ifrom);
755 	strcat(buf, " at ");
756 	*p++ = '@';
757 	strcat(buf, p);
758 	if (strcmp(buf, efrom) == 0)
759 		goto success;
760 
761   failure:
762 # ifdef DEBUG
763 	if (Debug > 7)
764 		printf("FALSE\n");
765 # endif DEBUG
766 	return (FALSE);
767 
768   success:
769 # ifdef DEBUG
770 	if (Debug > 7)
771 		printf("TRUE\n");
772 # endif DEBUG
773 	return (TRUE);
774 }
775 /*
776 **  MAILFILE -- Send a message to a file.
777 **
778 **	If the file has the setuid/setgid bits set, but NO execute
779 **	bits, sendmail will try to become the owner of that file
780 **	rather than the real user.  Obviously, this only works if
781 **	sendmail runs as root.
782 **
783 **	Parameters:
784 **		filename -- the name of the file to send to.
785 **		ctladdr -- the controlling address header -- includes
786 **			the userid/groupid to be when sending.
787 **
788 **	Returns:
789 **		The exit code associated with the operation.
790 **
791 **	Side Effects:
792 **		none.
793 */
794 
795 mailfile(filename, ctladdr)
796 	char *filename;
797 	ADDRESS *ctladdr;
798 {
799 	register FILE *f;
800 	register int pid;
801 
802 	/*
803 	**  Fork so we can change permissions here.
804 	**	Note that we MUST use fork, not vfork, because of
805 	**	the complications of calling subroutines, etc.
806 	*/
807 
808 	DOFORK(fork);
809 
810 	if (pid < 0)
811 		return (EX_OSERR);
812 	else if (pid == 0)
813 	{
814 		/* child -- actually write to file */
815 		struct stat stb;
816 		extern int DefUid, DefGid;
817 
818 		(void) signal(SIGINT, SIG_DFL);
819 		(void) signal(SIGHUP, SIG_DFL);
820 		(void) signal(SIGTERM, SIG_DFL);
821 		umask(OldUmask);
822 		if (stat(filename, &stb) < 0)
823 			stb.st_mode = 0666;
824 		if (bitset(0111, stb.st_mode))
825 			exit(EX_CANTCREAT);
826 		if (ctladdr == NULL)
827 			ctladdr = &From;
828 		if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0)
829 		{
830 			if (ctladdr->q_uid == 0)
831 				(void) setgid(DefGid);
832 			else
833 				(void) setgid(ctladdr->q_gid);
834 		}
835 		if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0)
836 		{
837 			if (ctladdr->q_uid == 0)
838 				(void) setuid(DefUid);
839 			else
840 				(void) setuid(ctladdr->q_uid);
841 		}
842 		f = fopen(filename, "a");
843 		if (f == NULL)
844 			exit(EX_CANTCREAT);
845 
846 		putmessage(f, Mailer[1]);
847 		fputs("\n", f);
848 		(void) fclose(f);
849 		(void) fflush(stdout);
850 
851 		/* reset ISUID & ISGID bits */
852 		(void) chmod(filename, (int) stb.st_mode);
853 		exit(EX_OK);
854 		/*NOTREACHED*/
855 	}
856 	else
857 	{
858 		/* parent -- wait for exit status */
859 		register int i;
860 		auto int stat;
861 
862 		while ((i = wait(&stat)) != pid)
863 		{
864 			if (i < 0)
865 			{
866 				stat = EX_OSERR << 8;
867 				break;
868 			}
869 		}
870 		if ((stat & 0377) != 0)
871 			stat = EX_UNAVAILABLE << 8;
872 		return ((stat >> 8) & 0377);
873 	}
874 }
875 /*
876 **  SENDALL -- actually send all the messages.
877 **
878 **	Parameters:
879 **		verifyonly -- if set, only give verification messages.
880 **
881 **	Returns:
882 **		none.
883 **
884 **	Side Effects:
885 **		Scans the send lists and sends everything it finds.
886 */
887 
888 sendall(verifyonly)
889 	bool verifyonly;
890 {
891 	register int i;
892 	typedef int (*fnptr)();
893 
894 	for (i = 0; Mailer[i] != NULL; i++)
895 	{
896 		ADDRESS *q;
897 
898 		for (q = Mailer[i]->m_sendq; q != NULL; q = q->q_next)
899 		{
900 			if (verifyonly)
901 			{
902 				To = q->q_paddr;
903 				if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
904 				{
905 					if (bitset(M_LOCAL, q->q_mailer->m_flags))
906 						message(Arpa_Info, "deliverable");
907 					else
908 						message(Arpa_Info, "queueable");
909 				}
910 			}
911 			else
912 				(void) deliver(q, (fnptr) NULL);
913 		}
914 	}
915 }
916