1 /*
2 **  Sendmail
3 **  Copyright (c) 1983  Eric P. Allman
4 **  Berkeley, California
5 **
6 **  Copyright (c) 1983 Regents of the University of California.
7 **  All rights reserved.  The Berkeley software License Agreement
8 **  specifies the terms and conditions for redistribution.
9 */
10 
11 #ifndef lint
12 static char	SccsId[] = "@(#)envelope.c	5.4 (Berkeley) 09/19/85";
13 #endif not lint
14 
15 #include <pwd.h>
16 #include <sys/time.h>
17 #include "sendmail.h"
18 #include <sys/stat.h>
19 
20 /*
21 **  NEWENVELOPE -- allocate a new envelope
22 **
23 **	Supports inheritance.
24 **
25 **	Parameters:
26 **		e -- the new envelope to fill in.
27 **
28 **	Returns:
29 **		e.
30 **
31 **	Side Effects:
32 **		none.
33 */
34 
35 ENVELOPE *
36 newenvelope(e)
37 	register ENVELOPE *e;
38 {
39 	register HDR *bh;
40 	register HDR **nhp;
41 	register ENVELOPE *parent;
42 	extern putheader(), putbody();
43 	extern ENVELOPE BlankEnvelope;
44 
45 	parent = CurEnv;
46 	if (e == CurEnv)
47 		parent = e->e_parent;
48 	bzero((char *) e, sizeof *e);
49 	if (e == CurEnv)
50 		bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
51 	else
52 		bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
53 	e->e_parent = parent;
54 	e->e_ctime = curtime();
55 	e->e_puthdr = putheader;
56 	e->e_putbody = putbody;
57 	bh = BlankEnvelope.e_header;
58 	nhp = &e->e_header;
59 	while (bh != NULL)
60 	{
61 		*nhp = (HDR *) xalloc(sizeof *bh);
62 		bcopy((char *) bh, (char *) *nhp, sizeof *bh);
63 		bh = bh->h_link;
64 		nhp = &(*nhp)->h_link;
65 	}
66 	if (CurEnv->e_xfp != NULL)
67 		(void) fflush(CurEnv->e_xfp);
68 
69 	return (e);
70 }
71 /*
72 **  DROPENVELOPE -- deallocate an envelope.
73 **
74 **	Parameters:
75 **		e -- the envelope to deallocate.
76 **
77 **	Returns:
78 **		none.
79 **
80 **	Side Effects:
81 **		housekeeping necessary to dispose of an envelope.
82 **		Unlocks this queue file.
83 */
84 
85 dropenvelope(e)
86 	register ENVELOPE *e;
87 {
88 	bool queueit = FALSE;
89 	register ADDRESS *q;
90 
91 #ifdef DEBUG
92 	if (tTd(50, 1))
93 	{
94 		printf("dropenvelope %x id=", e);
95 		xputs(e->e_id);
96 		printf(" flags=%o\n", e->e_flags);
97 	}
98 #endif DEBUG
99 #ifdef LOG
100 	if (LogLevel > 10)
101 		syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d",
102 				  e->e_id == NULL ? "(none)" : e->e_id,
103 				  e->e_flags, getpid());
104 #endif LOG
105 
106 	/* we must have an id to remove disk files */
107 	if (e->e_id == NULL)
108 		return;
109 
110 	/*
111 	**  Extract state information from dregs of send list.
112 	*/
113 
114 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
115 	{
116 		if (bitset(QQUEUEUP, q->q_flags))
117 			queueit = TRUE;
118 	}
119 
120 	/*
121 	**  Send back return receipts as requested.
122 	*/
123 
124 	if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags))
125 	{
126 		auto ADDRESS *rlist = NULL;
127 
128 		sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist);
129 		(void) returntosender("Return receipt", rlist, FALSE);
130 	}
131 
132 	/*
133 	**  Arrange to send error messages if there are fatal errors.
134 	*/
135 
136 	if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET)
137 		savemail(e);
138 
139 	/*
140 	**  Instantiate or deinstantiate the queue.
141 	*/
142 
143 	if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) ||
144 	    bitset(EF_CLRQUEUE, e->e_flags))
145 	{
146 		if (e->e_df != NULL)
147 			xunlink(e->e_df);
148 		xunlink(queuename(e, 'q'));
149 	}
150 	else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
151 	{
152 #ifdef QUEUE
153 		queueup(e, FALSE, FALSE);
154 #else QUEUE
155 		syserr("dropenvelope: queueup");
156 #endif QUEUE
157 	}
158 
159 	/* now unlock the job */
160 	closexscript(e);
161 	unlockqueue(e);
162 
163 	/* make sure that this envelope is marked unused */
164 	e->e_id = e->e_df = NULL;
165 	if (e->e_dfp != NULL)
166 		(void) fclose(e->e_dfp);
167 	e->e_dfp = NULL;
168 }
169 /*
170 **  CLEARENVELOPE -- clear an envelope without unlocking
171 **
172 **	This is normally used by a child process to get a clean
173 **	envelope without disturbing the parent.
174 **
175 **	Parameters:
176 **		e -- the envelope to clear.
177 **
178 **	Returns:
179 **		none.
180 **
181 **	Side Effects:
182 **		Closes files associated with the envelope.
183 **		Marks the envelope as unallocated.
184 */
185 
186 clearenvelope(e)
187 	register ENVELOPE *e;
188 {
189 	/* clear out any file information */
190 	if (e->e_xfp != NULL)
191 		(void) fclose(e->e_xfp);
192 	if (e->e_dfp != NULL)
193 		(void) fclose(e->e_dfp);
194 	e->e_xfp = e->e_dfp = NULL;
195 
196 	/* now expunge names of objects */
197 	e->e_df = e->e_id = NULL;
198 
199 	/* and the flags which are now meaningless */
200 	e->e_flags = 0;
201 }
202 /*
203 **  INITSYS -- initialize instantiation of system
204 **
205 **	In Daemon mode, this is done in the child.
206 **
207 **	Parameters:
208 **		none.
209 **
210 **	Returns:
211 **		none.
212 **
213 **	Side Effects:
214 **		Initializes the system macros, some global variables,
215 **		etc.  In particular, the current time in various
216 **		forms is set.
217 */
218 
219 initsys()
220 {
221 	static char cbuf[5];			/* holds hop count */
222 	static char pbuf[10];			/* holds pid */
223 #ifdef TTYNAME
224 	static char ybuf[10];			/* holds tty id */
225 	register char *p;
226 #endif TTYNAME
227 	extern char *ttyname();
228 	extern char *macvalue();
229 	extern char Version[];
230 
231 	/*
232 	**  Give this envelope a reality.
233 	**	I.e., an id, a transcript, and a creation time.
234 	*/
235 
236 	openxscript(CurEnv);
237 	CurEnv->e_ctime = curtime();
238 
239 	/*
240 	**  Set OutChannel to something useful if stdout isn't it.
241 	**	This arranges that any extra stuff the mailer produces
242 	**	gets sent back to the user on error (because it is
243 	**	tucked away in the transcript).
244 	*/
245 
246 	if (OpMode == MD_DAEMON && QueueRun)
247 		OutChannel = CurEnv->e_xfp;
248 
249 	/*
250 	**  Set up some basic system macros.
251 	*/
252 
253 	/* process id */
254 	(void) sprintf(pbuf, "%d", getpid());
255 	define('p', pbuf, CurEnv);
256 
257 	/* hop count */
258 	(void) sprintf(cbuf, "%d", CurEnv->e_hopcount);
259 	define('c', cbuf, CurEnv);
260 
261 	/* time as integer, unix time, arpa time */
262 	settime();
263 
264 #ifdef TTYNAME
265 	/* tty name */
266 	if (macvalue('y', CurEnv) == NULL)
267 	{
268 		p = ttyname(2);
269 		if (p != NULL)
270 		{
271 			if (rindex(p, '/') != NULL)
272 				p = rindex(p, '/') + 1;
273 			(void) strcpy(ybuf, p);
274 			define('y', ybuf, CurEnv);
275 		}
276 	}
277 #endif TTYNAME
278 }
279 /*
280 **  SETTIME -- set the current time.
281 **
282 **	Parameters:
283 **		none.
284 **
285 **	Returns:
286 **		none.
287 **
288 **	Side Effects:
289 **		Sets the various time macros -- $a, $b, $d, $t.
290 */
291 
292 settime()
293 {
294 	register char *p;
295 	auto time_t now;
296 	static char tbuf[20];			/* holds "current" time */
297 	static char dbuf[30];			/* holds ctime(tbuf) */
298 	register struct tm *tm;
299 	extern char *arpadate();
300 	extern struct tm *gmtime();
301 	extern char *macvalue();
302 
303 	now = curtime();
304 	tm = gmtime(&now);
305 	(void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1,
306 			tm->tm_mday, tm->tm_hour, tm->tm_min);
307 	define('t', tbuf, CurEnv);
308 	(void) strcpy(dbuf, ctime(&now));
309 	*index(dbuf, '\n') = '\0';
310 	if (macvalue('d', CurEnv) == NULL)
311 		define('d', dbuf, CurEnv);
312 	p = newstr(arpadate(dbuf));
313 	if (macvalue('a', CurEnv) == NULL)
314 		define('a', p, CurEnv);
315 	define('b', p, CurEnv);
316 }
317 /*
318 **  OPENXSCRIPT -- Open transcript file
319 **
320 **	Creates a transcript file for possible eventual mailing or
321 **	sending back.
322 **
323 **	Parameters:
324 **		e -- the envelope to create the transcript in/for.
325 **
326 **	Returns:
327 **		none
328 **
329 **	Side Effects:
330 **		Creates the transcript file.
331 */
332 
333 openxscript(e)
334 	register ENVELOPE *e;
335 {
336 	register char *p;
337 
338 # ifdef LOG
339 	if (LogLevel > 19)
340 		syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)");
341 # endif LOG
342 	if (e->e_xfp != NULL)
343 		return;
344 	p = queuename(e, 'x');
345 	e->e_xfp = fopen(p, "w");
346 	if (e->e_xfp == NULL)
347 		syserr("Can't create %s", p);
348 	else
349 		(void) chmod(p, 0644);
350 }
351 /*
352 **  CLOSEXSCRIPT -- close the transcript file.
353 **
354 **	Parameters:
355 **		e -- the envelope containing the transcript to close.
356 **
357 **	Returns:
358 **		none.
359 **
360 **	Side Effects:
361 **		none.
362 */
363 
364 closexscript(e)
365 	register ENVELOPE *e;
366 {
367 	if (e->e_xfp == NULL)
368 		return;
369 	(void) fclose(e->e_xfp);
370 	e->e_xfp = NULL;
371 }
372 /*
373 **  SETSENDER -- set the person who this message is from
374 **
375 **	Under certain circumstances allow the user to say who
376 **	s/he is (using -f or -r).  These are:
377 **	1.  The user's uid is zero (root).
378 **	2.  The user's login name is in an approved list (typically
379 **	    from a network server).
380 **	3.  The address the user is trying to claim has a
381 **	    "!" character in it (since #2 doesn't do it for
382 **	    us if we are dialing out for UUCP).
383 **	A better check to replace #3 would be if the
384 **	effective uid is "UUCP" -- this would require me
385 **	to rewrite getpwent to "grab" uucp as it went by,
386 **	make getname more nasty, do another passwd file
387 **	scan, or compile the UID of "UUCP" into the code,
388 **	all of which are reprehensible.
389 **
390 **	Assuming all of these fail, we figure out something
391 **	ourselves.
392 **
393 **	Parameters:
394 **		from -- the person we would like to believe this message
395 **			is from, as specified on the command line.
396 **
397 **	Returns:
398 **		none.
399 **
400 **	Side Effects:
401 **		sets sendmail's notion of who the from person is.
402 */
403 
404 setsender(from)
405 	char *from;
406 {
407 	register char **pvp;
408 	char *realname = NULL;
409 	register struct passwd *pw;
410 	char buf[MAXNAME];
411 	char pvpbuf[PSBUFSIZE];
412 	extern struct passwd *getpwnam();
413 	extern char *macvalue();
414 	extern char **prescan();
415 	extern bool safefile();
416 	extern char *FullName;
417 
418 # ifdef DEBUG
419 	if (tTd(45, 1))
420 		printf("setsender(%s)\n", from == NULL ? "" : from);
421 # endif DEBUG
422 
423 	/*
424 	**  Figure out the real user executing us.
425 	**	Username can return errno != 0 on non-errors.
426 	*/
427 
428 	if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
429 		realname = from;
430 	if (realname == NULL || realname[0] == '\0')
431 	{
432 		extern char *username();
433 
434 		realname = username();
435 	}
436 
437 	/*
438 	**  Determine if this real person is allowed to alias themselves.
439 	*/
440 
441 	if (from != NULL)
442 	{
443 		extern bool trusteduser();
444 
445 		if (!trusteduser(realname) &&
446 # ifdef DEBUG
447 		    (!tTd(1, 9) || getuid() != geteuid()) &&
448 # endif DEBUG
449 		    index(from, '!') == NULL && getuid() != 0)
450 		{
451 			/* network sends -r regardless (why why why?) */
452 			/* syserr("%s, you cannot use the -f flag", realname); */
453 			from = NULL;
454 		}
455 	}
456 
457 	SuprErrs = TRUE;
458 	if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL)
459 	{
460 		/* log garbage addresses for traceback */
461 		if (from != NULL)
462 		{
463 # ifdef LOG
464 			if (LogLevel >= 1)
465 				syslog(LOG_ERR, "Unparseable user %s wants to be %s",
466 						realname, from);
467 # endif LOG
468 		}
469 		from = newstr(realname);
470 		if (parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL &&
471 		    parseaddr("postmaster", &CurEnv->e_from, 1, '\0') == NULL)
472 		{
473 			syserr("setsender: can't even parse postmaster!");
474 		}
475 	}
476 	else
477 		FromFlag = TRUE;
478 	CurEnv->e_from.q_flags |= QDONTSEND;
479 	loweraddr(&CurEnv->e_from);
480 	SuprErrs = FALSE;
481 
482 	if (CurEnv->e_from.q_mailer == LocalMailer &&
483 	    (pw = getpwnam(CurEnv->e_from.q_user)) != NULL)
484 	{
485 		/*
486 		**  Process passwd file entry.
487 		*/
488 
489 
490 		/* extract home directory */
491 		CurEnv->e_from.q_home = newstr(pw->pw_dir);
492 		define('z', CurEnv->e_from.q_home, CurEnv);
493 
494 		/* extract user and group id */
495 		CurEnv->e_from.q_uid = pw->pw_uid;
496 		CurEnv->e_from.q_gid = pw->pw_gid;
497 
498 		/* if the user has given fullname already, don't redefine */
499 		if (FullName == NULL)
500 			FullName = macvalue('x', CurEnv);
501 		if (FullName != NULL && FullName[0] == '\0')
502 			FullName = NULL;
503 
504 		/* extract full name from passwd file */
505 		if (FullName == NULL && pw->pw_gecos != NULL &&
506 		    strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0)
507 		{
508 			buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf);
509 			if (buf[0] != '\0')
510 				FullName = newstr(buf);
511 		}
512 		if (FullName != NULL)
513 			define('x', FullName, CurEnv);
514 	}
515 	else
516 	{
517 #ifndef V6
518 		if (CurEnv->e_from.q_home == NULL)
519 			CurEnv->e_from.q_home = getenv("HOME");
520 #endif V6
521 		CurEnv->e_from.q_uid = getuid();
522 		CurEnv->e_from.q_gid = getgid();
523 	}
524 
525 	if (CurEnv->e_from.q_uid != 0)
526 	{
527 		DefUid = CurEnv->e_from.q_uid;
528 		DefGid = CurEnv->e_from.q_gid;
529 	}
530 
531 	/*
532 	**  Rewrite the from person to dispose of possible implicit
533 	**	links in the net.
534 	*/
535 
536 	pvp = prescan(from, '\0', pvpbuf);
537 	if (pvp == NULL)
538 	{
539 		syserr("cannot prescan from (%s)", from);
540 		finis();
541 	}
542 	rewrite(pvp, 3);
543 	rewrite(pvp, 1);
544 	rewrite(pvp, 4);
545 	cataddr(pvp, buf, sizeof buf);
546 	define('f', newstr(buf), CurEnv);
547 
548 	/* save the domain spec if this mailer wants it */
549 	if (CurEnv->e_from.q_mailer != NULL &&
550 	    bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags))
551 	{
552 		extern char **copyplist();
553 
554 		while (*pvp != NULL && strcmp(*pvp, "@") != 0)
555 			pvp++;
556 		if (*pvp != NULL)
557 			CurEnv->e_fromdomain = copyplist(pvp, TRUE);
558 	}
559 }
560 /*
561 **  TRUSTEDUSER -- tell us if this user is to be trusted.
562 **
563 **	Parameters:
564 **		user -- the user to be checked.
565 **
566 **	Returns:
567 **		TRUE if the user is in an approved list.
568 **		FALSE otherwise.
569 **
570 **	Side Effects:
571 **		none.
572 */
573 
574 bool
575 trusteduser(user)
576 	char *user;
577 {
578 	register char **ulist;
579 	extern char *TrustedUsers[];
580 
581 	for (ulist = TrustedUsers; *ulist != NULL; ulist++)
582 		if (strcmp(*ulist, user) == 0)
583 			return (TRUE);
584 	return (FALSE);
585 }
586