1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)envelope.c	8.42 (Berkeley) 11/04/94";
11 #endif /* not lint */
12 
13 #include "sendmail.h"
14 #include <pwd.h>
15 
16 /*
17 **  NEWENVELOPE -- allocate a new envelope
18 **
19 **	Supports inheritance.
20 **
21 **	Parameters:
22 **		e -- the new envelope to fill in.
23 **		parent -- the envelope to be the parent of e.
24 **
25 **	Returns:
26 **		e.
27 **
28 **	Side Effects:
29 **		none.
30 */
31 
32 ENVELOPE *
33 newenvelope(e, parent)
34 	register ENVELOPE *e;
35 	register ENVELOPE *parent;
36 {
37 	extern putheader(), putbody();
38 	extern ENVELOPE BlankEnvelope;
39 
40 	if (e == parent && e->e_parent != NULL)
41 		parent = e->e_parent;
42 	clearenvelope(e, TRUE);
43 	if (e == CurEnv)
44 		bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
45 	else
46 		bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
47 	e->e_parent = parent;
48 	e->e_ctime = curtime();
49 	if (parent != NULL)
50 		e->e_msgpriority = parent->e_msgsize;
51 	e->e_puthdr = putheader;
52 	e->e_putbody = putbody;
53 	if (CurEnv->e_xfp != NULL)
54 		(void) fflush(CurEnv->e_xfp);
55 
56 	return (e);
57 }
58 /*
59 **  DROPENVELOPE -- deallocate an envelope.
60 **
61 **	Parameters:
62 **		e -- the envelope to deallocate.
63 **
64 **	Returns:
65 **		none.
66 **
67 **	Side Effects:
68 **		housekeeping necessary to dispose of an envelope.
69 **		Unlocks this queue file.
70 */
71 
72 void
73 dropenvelope(e)
74 	register ENVELOPE *e;
75 {
76 	bool queueit = FALSE;
77 	bool failure_return = FALSE;
78 	bool success_return = FALSE;
79 	register ADDRESS *q;
80 	char *id = e->e_id;
81 	bool return_no, return_yes;
82 	char buf[MAXLINE];
83 
84 	if (tTd(50, 1))
85 	{
86 		printf("dropenvelope %x: id=", e);
87 		xputs(e->e_id);
88 		printf(", flags=0x%x\n", e->e_flags);
89 		if (tTd(50, 10))
90 		{
91 			printf("sendq=");
92 			printaddr(e->e_sendqueue, TRUE);
93 		}
94 	}
95 
96 	/* we must have an id to remove disk files */
97 	if (id == NULL)
98 		return;
99 
100 #ifdef LOG
101 	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
102 		logsender(e, NULL);
103 	if (LogLevel > 84)
104 		syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d",
105 				  id, e->e_flags, getpid());
106 #endif /* LOG */
107 	e->e_flags &= ~EF_LOGSENDER;
108 
109 	/* post statistics */
110 	poststats(StatFile);
111 
112 	/*
113 	**  Extract state information from dregs of send list.
114 	*/
115 
116 	e->e_flags &= ~EF_QUEUERUN;
117 	return_no = return_yes = FALSE;
118 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
119 	{
120 		if (bitset(QQUEUEUP, q->q_flags))
121 			queueit = TRUE;
122 
123 		/* see if a notification is needed */
124 		if (bitset(QBADADDR, q->q_flags) &&
125 		    bitset(QPINGONFAILURE, q->q_flags))
126 		{
127 			failure_return = TRUE;
128 			if (q->q_owner == NULL &&
129 			    strcmp(e->e_from.q_paddr, "<>") != 0)
130 				(void) sendtolist(e->e_from.q_paddr, NULL,
131 						  &e->e_errorqueue, e);
132 		}
133 		else if (bitset(QSENT, q->q_flags) &&
134 		    bitnset(M_LOCALMAILER, q->q_mailer->m_flags) &&
135 		    bitset(QPINGONSUCCESS, q->q_flags))
136 		{
137 			success_return = TRUE;
138 		}
139 		else
140 			continue;
141 
142 		/* common code for error returns and return receipts */
143 
144 		/* test for returning the body */
145 		if (!bitset(QHASRETPARAM, q->q_flags))
146 		{
147 			if (!bitset(EF_NORETURN, e->e_flags))
148 				return_yes = TRUE;
149 		}
150 		else if (bitset(QNOBODYRETURN, q->q_flags))
151 			return_no = TRUE;
152 		else
153 			return_yes = TRUE;
154 	}
155 	if (return_no && !return_yes)
156 		e->e_flags |= EF_NORETURN;
157 
158 	/*
159 	**  See if the message timed out.
160 	*/
161 
162 	if (!queueit)
163 		/* nothing to do */ ;
164 	else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
165 	{
166 		(void) sprintf(buf, "Cannot send message for %s",
167 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
168 		if (e->e_message != NULL)
169 			free(e->e_message);
170 		e->e_message = newstr(buf);
171 		message(buf);
172 		e->e_flags |= EF_CLRQUEUE;
173 		failure_return = TRUE;
174 		fprintf(e->e_xfp, "Message could not be delivered for %s\n",
175 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
176 		fprintf(e->e_xfp, "Message will be deleted from queue\n");
177 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
178 		{
179 			if (bitset(QQUEUEUP, q->q_flags))
180 				q->q_flags |= QBADADDR;
181 		}
182 	}
183 	else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
184 	    curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
185 	{
186 		if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
187 		    e->e_class >= 0 &&
188 		    strcmp(e->e_from.q_paddr, "<>") != 0 &&
189 		    strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
190 		    (strlen(e->e_from.q_paddr) <= 8 ||
191 		     strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
192 		{
193 			(void) sprintf(buf,
194 				"Warning: cannot send message for %s",
195 				pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
196 			if (e->e_message != NULL)
197 				free(e->e_message);
198 			e->e_message = newstr(buf);
199 			message(buf);
200 			e->e_flags |= EF_WARNING;
201 			failure_return = TRUE;
202 		}
203 		fprintf(e->e_xfp,
204 			"Warning: message still undelivered after %s\n",
205 			pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
206 		fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
207 			pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
208 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
209 		{
210 			if (bitset(QQUEUEUP, q->q_flags))
211 				q->q_flags |= QREPORT;
212 		}
213 	}
214 
215 	if (tTd(50, 2))
216 		printf("failure_return=%d success_return=%d queueit=%d\n",
217 			failure_return, success_return, queueit);
218 
219 	/*
220 	**  Send back return receipts as requested.
221 	*/
222 
223 /*
224 	if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)
225 	    && !bitset(PRIV_NORECEIPTS, PrivacyFlags))
226 */
227 	if (e->e_receiptto == NULL)
228 		e->e_receiptto = e->e_from.q_paddr;
229 	if (success_return && strcmp(e->e_receiptto, "<>") != 0)
230 	{
231 		auto ADDRESS *rlist = NULL;
232 
233 		e->e_flags |= EF_SENDRECEIPT;
234 		(void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e);
235 		(void) returntosender("Return receipt", rlist, FALSE, e);
236 	}
237 	e->e_flags &= ~EF_SENDRECEIPT;
238 
239 	/*
240 	**  Arrange to send error messages if there are fatal errors.
241 	*/
242 
243 	if (failure_return && e->e_errormode != EM_QUIET)
244 		savemail(e);
245 
246 	/*
247 	**  Arrange to send warning messages to postmaster as requested.
248 	*/
249 
250 	if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL &&
251 	    !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0)
252 	{
253 		auto ADDRESS *rlist = NULL;
254 
255 		(void) sendtolist(PostMasterCopy, NULLADDR, &rlist, e);
256 		(void) returntosender(e->e_message, rlist, FALSE, e);
257 	}
258 
259 	/*
260 	**  Instantiate or deinstantiate the queue.
261 	*/
262 
263 	if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
264 	    bitset(EF_CLRQUEUE, e->e_flags))
265 	{
266 		if (tTd(50, 1))
267 			printf("\n===== Dropping [dq]f%s (queueit=%d, e_flags=%x) =====\n\n",
268 				e->e_id, queueit, e->e_flags);
269 		if (e->e_df != NULL)
270 			xunlink(e->e_df);
271 		xunlink(queuename(e, 'q'));
272 
273 #ifdef LOG
274 		if (LogLevel > 10)
275 			syslog(LOG_INFO, "%s: done", id);
276 #endif
277 	}
278 	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
279 	{
280 #ifdef QUEUE
281 		queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE);
282 #else /* QUEUE */
283 		syserr("554 dropenvelope: queueup");
284 #endif /* QUEUE */
285 	}
286 
287 	/* now unlock the job */
288 	closexscript(e);
289 	unlockqueue(e);
290 
291 	/* make sure that this envelope is marked unused */
292 	if (e->e_dfp != NULL)
293 		(void) xfclose(e->e_dfp, "dropenvelope", e->e_df);
294 	e->e_dfp = NULL;
295 	e->e_id = e->e_df = NULL;
296 }
297 /*
298 **  CLEARENVELOPE -- clear an envelope without unlocking
299 **
300 **	This is normally used by a child process to get a clean
301 **	envelope without disturbing the parent.
302 **
303 **	Parameters:
304 **		e -- the envelope to clear.
305 **		fullclear - if set, the current envelope is total
306 **			garbage and should be ignored; otherwise,
307 **			release any resources it may indicate.
308 **
309 **	Returns:
310 **		none.
311 **
312 **	Side Effects:
313 **		Closes files associated with the envelope.
314 **		Marks the envelope as unallocated.
315 */
316 
317 void
318 clearenvelope(e, fullclear)
319 	register ENVELOPE *e;
320 	bool fullclear;
321 {
322 	register HDR *bh;
323 	register HDR **nhp;
324 	extern ENVELOPE BlankEnvelope;
325 
326 	if (!fullclear)
327 	{
328 		/* clear out any file information */
329 		if (e->e_xfp != NULL)
330 			(void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
331 		if (e->e_dfp != NULL)
332 			(void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df);
333 		e->e_xfp = e->e_dfp = NULL;
334 	}
335 
336 	/* now clear out the data */
337 	STRUCTCOPY(BlankEnvelope, *e);
338 	if (Verbose)
339 		e->e_sendmode = SM_DELIVER;
340 	bh = BlankEnvelope.e_header;
341 	nhp = &e->e_header;
342 	while (bh != NULL)
343 	{
344 		*nhp = (HDR *) xalloc(sizeof *bh);
345 		bcopy((char *) bh, (char *) *nhp, sizeof *bh);
346 		bh = bh->h_link;
347 		nhp = &(*nhp)->h_link;
348 	}
349 }
350 /*
351 **  INITSYS -- initialize instantiation of system
352 **
353 **	In Daemon mode, this is done in the child.
354 **
355 **	Parameters:
356 **		none.
357 **
358 **	Returns:
359 **		none.
360 **
361 **	Side Effects:
362 **		Initializes the system macros, some global variables,
363 **		etc.  In particular, the current time in various
364 **		forms is set.
365 */
366 
367 void
368 initsys(e)
369 	register ENVELOPE *e;
370 {
371 	char cbuf[5];				/* holds hop count */
372 	char pbuf[10];				/* holds pid */
373 #ifdef TTYNAME
374 	static char ybuf[60];			/* holds tty id */
375 	register char *p;
376 #endif /* TTYNAME */
377 	extern char *ttyname();
378 	extern void settime();
379 	extern char Version[];
380 
381 	/*
382 	**  Give this envelope a reality.
383 	**	I.e., an id, a transcript, and a creation time.
384 	*/
385 
386 	openxscript(e);
387 	e->e_ctime = curtime();
388 
389 	/*
390 	**  Set OutChannel to something useful if stdout isn't it.
391 	**	This arranges that any extra stuff the mailer produces
392 	**	gets sent back to the user on error (because it is
393 	**	tucked away in the transcript).
394 	*/
395 
396 	if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
397 	    e->e_xfp != NULL)
398 		OutChannel = e->e_xfp;
399 
400 	/*
401 	**  Set up some basic system macros.
402 	*/
403 
404 	/* process id */
405 	(void) sprintf(pbuf, "%d", getpid());
406 	define('p', newstr(pbuf), e);
407 
408 	/* hop count */
409 	(void) sprintf(cbuf, "%d", e->e_hopcount);
410 	define('c', newstr(cbuf), e);
411 
412 	/* time as integer, unix time, arpa time */
413 	settime(e);
414 
415 #ifdef TTYNAME
416 	/* tty name */
417 	if (macvalue('y', e) == NULL)
418 	{
419 		p = ttyname(2);
420 		if (p != NULL)
421 		{
422 			if (strrchr(p, '/') != NULL)
423 				p = strrchr(p, '/') + 1;
424 			(void) strcpy(ybuf, p);
425 			define('y', ybuf, e);
426 		}
427 	}
428 #endif /* TTYNAME */
429 }
430 /*
431 **  SETTIME -- set the current time.
432 **
433 **	Parameters:
434 **		none.
435 **
436 **	Returns:
437 **		none.
438 **
439 **	Side Effects:
440 **		Sets the various time macros -- $a, $b, $d, $t.
441 */
442 
443 void
444 settime(e)
445 	register ENVELOPE *e;
446 {
447 	register char *p;
448 	auto time_t now;
449 	char tbuf[20];				/* holds "current" time */
450 	char dbuf[30];				/* holds ctime(tbuf) */
451 	register struct tm *tm;
452 	extern char *arpadate();
453 	extern struct tm *gmtime();
454 
455 	now = curtime();
456 	tm = gmtime(&now);
457 	(void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
458 			tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
459 	define('t', newstr(tbuf), e);
460 	(void) strcpy(dbuf, ctime(&now));
461 	p = strchr(dbuf, '\n');
462 	if (p != NULL)
463 		*p = '\0';
464 	define('d', newstr(dbuf), e);
465 	p = arpadate(dbuf);
466 	p = newstr(p);
467 	if (macvalue('a', e) == NULL)
468 		define('a', p, e);
469 	define('b', p, e);
470 }
471 /*
472 **  OPENXSCRIPT -- Open transcript file
473 **
474 **	Creates a transcript file for possible eventual mailing or
475 **	sending back.
476 **
477 **	Parameters:
478 **		e -- the envelope to create the transcript in/for.
479 **
480 **	Returns:
481 **		none
482 **
483 **	Side Effects:
484 **		Creates the transcript file.
485 */
486 
487 #ifndef O_APPEND
488 #define O_APPEND	0
489 #endif
490 
491 void
492 openxscript(e)
493 	register ENVELOPE *e;
494 {
495 	register char *p;
496 	int fd;
497 
498 	if (e->e_xfp != NULL)
499 		return;
500 	p = queuename(e, 'x');
501 	fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644);
502 	if (fd < 0)
503 	{
504 		syserr("Can't create transcript file %s", p);
505 		fd = open("/dev/null", O_WRONLY, 0644);
506 		if (fd < 0)
507 			syserr("!Can't open /dev/null");
508 	}
509 	e->e_xfp = fdopen(fd, "w");
510 	if (e->e_xfp == NULL)
511 	{
512 		syserr("!Can't create transcript stream %s", p);
513 	}
514 	if (tTd(46, 9))
515 	{
516 		printf("openxscript(%s):\n  ", p);
517 		dumpfd(fileno(e->e_xfp), TRUE, FALSE);
518 	}
519 }
520 /*
521 **  CLOSEXSCRIPT -- close the transcript file.
522 **
523 **	Parameters:
524 **		e -- the envelope containing the transcript to close.
525 **
526 **	Returns:
527 **		none.
528 **
529 **	Side Effects:
530 **		none.
531 */
532 
533 void
534 closexscript(e)
535 	register ENVELOPE *e;
536 {
537 	if (e->e_xfp == NULL)
538 		return;
539 	(void) xfclose(e->e_xfp, "closexscript", e->e_id);
540 	e->e_xfp = NULL;
541 }
542 /*
543 **  SETSENDER -- set the person who this message is from
544 **
545 **	Under certain circumstances allow the user to say who
546 **	s/he is (using -f or -r).  These are:
547 **	1.  The user's uid is zero (root).
548 **	2.  The user's login name is in an approved list (typically
549 **	    from a network server).
550 **	3.  The address the user is trying to claim has a
551 **	    "!" character in it (since #2 doesn't do it for
552 **	    us if we are dialing out for UUCP).
553 **	A better check to replace #3 would be if the
554 **	effective uid is "UUCP" -- this would require me
555 **	to rewrite getpwent to "grab" uucp as it went by,
556 **	make getname more nasty, do another passwd file
557 **	scan, or compile the UID of "UUCP" into the code,
558 **	all of which are reprehensible.
559 **
560 **	Assuming all of these fail, we figure out something
561 **	ourselves.
562 **
563 **	Parameters:
564 **		from -- the person we would like to believe this message
565 **			is from, as specified on the command line.
566 **		e -- the envelope in which we would like the sender set.
567 **		delimptr -- if non-NULL, set to the location of the
568 **			trailing delimiter.
569 **		internal -- set if this address is coming from an internal
570 **			source such as an owner alias.
571 **
572 **	Returns:
573 **		none.
574 **
575 **	Side Effects:
576 **		sets sendmail's notion of who the from person is.
577 */
578 
579 void
580 setsender(from, e, delimptr, internal)
581 	char *from;
582 	register ENVELOPE *e;
583 	char **delimptr;
584 	bool internal;
585 {
586 	register char **pvp;
587 	char *realname = NULL;
588 	register struct passwd *pw;
589 	char delimchar;
590 	char *bp;
591 	char buf[MAXNAME + 2];
592 	char pvpbuf[PSBUFSIZE];
593 	extern struct passwd *getpwnam();
594 	extern char *FullName;
595 
596 	if (tTd(45, 1))
597 		printf("setsender(%s)\n", from == NULL ? "" : from);
598 
599 	/*
600 	**  Figure out the real user executing us.
601 	**	Username can return errno != 0 on non-errors.
602 	*/
603 
604 	if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
605 	    OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
606 		realname = from;
607 	if (realname == NULL || realname[0] == '\0')
608 		realname = username();
609 
610 	if (ConfigLevel < 2)
611 		SuprErrs = TRUE;
612 
613 	delimchar = internal ? '\0' : ' ';
614 	e->e_from.q_flags = QBADADDR;
615 	if (from == NULL ||
616 	    parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
617 		      delimchar, delimptr, e) == NULL ||
618 	    bitset(QBADADDR, e->e_from.q_flags) ||
619 	    e->e_from.q_mailer == ProgMailer ||
620 	    e->e_from.q_mailer == FileMailer ||
621 	    e->e_from.q_mailer == InclMailer)
622 	{
623 		/* log garbage addresses for traceback */
624 # ifdef LOG
625 		if (from != NULL && LogLevel > 2)
626 		{
627 			char *p;
628 			char ebuf[MAXNAME * 2 + 2];
629 
630 			p = macvalue('_', e);
631 			if (p == NULL)
632 			{
633 				char *host = RealHostName;
634 				if (host == NULL)
635 					host = MyHostName;
636 				(void) sprintf(ebuf, "%s@%s", realname, host);
637 				p = ebuf;
638 			}
639 			syslog(LOG_NOTICE,
640 				"setsender: %s: invalid or unparseable, received from %s",
641 				shortenstring(from, 83), p);
642 		}
643 # endif /* LOG */
644 		if (from != NULL)
645 		{
646 			if (!bitset(QBADADDR, e->e_from.q_flags))
647 			{
648 				/* it was a bogus mailer in the from addr */
649 				usrerr("553 Invalid sender address");
650 			}
651 			SuprErrs = TRUE;
652 		}
653 		if (from == realname ||
654 		    parseaddr(from = newstr(realname), &e->e_from,
655 			      RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
656 		{
657 			char nbuf[100];
658 
659 			SuprErrs = TRUE;
660 			expand("\201n", nbuf, &nbuf[sizeof nbuf], e);
661 			if (parseaddr(from = newstr(nbuf), &e->e_from,
662 				      RF_COPYALL, ' ', NULL, e) == NULL &&
663 			    parseaddr(from = "postmaster", &e->e_from,
664 			    	      RF_COPYALL, ' ', NULL, e) == NULL)
665 				syserr("553 setsender: can't even parse postmaster!");
666 		}
667 	}
668 	else
669 		FromFlag = TRUE;
670 	e->e_from.q_flags |= QDONTSEND;
671 	if (tTd(45, 5))
672 	{
673 		printf("setsender: QDONTSEND ");
674 		printaddr(&e->e_from, FALSE);
675 	}
676 	SuprErrs = FALSE;
677 
678 # ifdef USERDB
679 	if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
680 	{
681 		register char *p;
682 		extern char *udbsender();
683 
684 		p = udbsender(e->e_from.q_user);
685 		if (p != NULL)
686 			from = p;
687 	}
688 # endif /* USERDB */
689 
690 	if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
691 	{
692 		if (!internal)
693 		{
694 			/* if the user already given fullname don't redefine */
695 			if (FullName == NULL)
696 				FullName = macvalue('x', e);
697 			if (FullName != NULL && FullName[0] == '\0')
698 				FullName = NULL;
699 		}
700 
701 		if ((pw = getpwnam(e->e_from.q_user)) != NULL)
702 		{
703 			/*
704 			**  Process passwd file entry.
705 			*/
706 
707 			/* extract home directory */
708 			if (strcmp(pw->pw_dir, "/") == 0)
709 				e->e_from.q_home = newstr("");
710 			else
711 				e->e_from.q_home = newstr(pw->pw_dir);
712 			define('z', e->e_from.q_home, e);
713 
714 			/* extract user and group id */
715 			e->e_from.q_uid = pw->pw_uid;
716 			e->e_from.q_gid = pw->pw_gid;
717 			e->e_from.q_flags |= QGOODUID;
718 
719 			/* extract full name from passwd file */
720 			if (FullName == NULL && pw->pw_gecos != NULL &&
721 			    strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
722 			    !internal)
723 			{
724 				buildfname(pw->pw_gecos, e->e_from.q_user, buf);
725 				if (buf[0] != '\0')
726 					FullName = newstr(buf);
727 			}
728 		}
729 		if (FullName != NULL && !internal)
730 			define('x', FullName, e);
731 	}
732 	else if (!internal && OpMode != MD_DAEMON)
733 	{
734 		if (e->e_from.q_home == NULL)
735 		{
736 			e->e_from.q_home = getenv("HOME");
737 			if (e->e_from.q_home != NULL &&
738 			    strcmp(e->e_from.q_home, "/") == 0)
739 				e->e_from.q_home++;
740 		}
741 		e->e_from.q_uid = RealUid;
742 		e->e_from.q_gid = RealGid;
743 		e->e_from.q_flags |= QGOODUID;
744 	}
745 
746 	/*
747 	**  Rewrite the from person to dispose of possible implicit
748 	**	links in the net.
749 	*/
750 
751 	pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL);
752 	if (pvp == NULL)
753 	{
754 		/* don't need to give error -- prescan did that already */
755 # ifdef LOG
756 		if (LogLevel > 2)
757 			syslog(LOG_NOTICE, "cannot prescan from (%s)", from);
758 # endif
759 		finis();
760 	}
761 /*
762 	(void) rewrite(pvp, 3, 0, e);
763 	(void) rewrite(pvp, 1, 0, e);
764 	(void) rewrite(pvp, 4, 0, e);
765 */
766 	bp = buf + 1;
767 	cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
768 	if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
769 	{
770 		/* heuristic: route-addr: add angle brackets */
771 		strcat(bp, ">");
772 		*--bp = '<';
773 	}
774 	e->e_sender = newstr(bp);
775 	define('f', e->e_sender, e);
776 
777 	/* save the domain spec if this mailer wants it */
778 	if (e->e_from.q_mailer != NULL &&
779 	    bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
780 	{
781 		extern char **copyplist();
782 
783 		while (*pvp != NULL && strcmp(*pvp, "@") != 0)
784 			pvp++;
785 		if (*pvp != NULL)
786 			e->e_fromdomain = copyplist(pvp, TRUE);
787 	}
788 }
789