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.5 (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 
195 	/* now clear out the data */
196 	bzero((char *) e, sizeof *e);
197 }
198 /*
199 **  INITSYS -- initialize instantiation of system
200 **
201 **	In Daemon mode, this is done in the child.
202 **
203 **	Parameters:
204 **		none.
205 **
206 **	Returns:
207 **		none.
208 **
209 **	Side Effects:
210 **		Initializes the system macros, some global variables,
211 **		etc.  In particular, the current time in various
212 **		forms is set.
213 */
214 
215 initsys()
216 {
217 	static char cbuf[5];			/* holds hop count */
218 	static char pbuf[10];			/* holds pid */
219 #ifdef TTYNAME
220 	static char ybuf[10];			/* holds tty id */
221 	register char *p;
222 #endif TTYNAME
223 	extern char *ttyname();
224 	extern char *macvalue();
225 	extern char Version[];
226 
227 	/*
228 	**  Give this envelope a reality.
229 	**	I.e., an id, a transcript, and a creation time.
230 	*/
231 
232 	openxscript(CurEnv);
233 	CurEnv->e_ctime = curtime();
234 
235 	/*
236 	**  Set OutChannel to something useful if stdout isn't it.
237 	**	This arranges that any extra stuff the mailer produces
238 	**	gets sent back to the user on error (because it is
239 	**	tucked away in the transcript).
240 	*/
241 
242 	if (OpMode == MD_DAEMON && QueueRun)
243 		OutChannel = CurEnv->e_xfp;
244 
245 	/*
246 	**  Set up some basic system macros.
247 	*/
248 
249 	/* process id */
250 	(void) sprintf(pbuf, "%d", getpid());
251 	define('p', pbuf, CurEnv);
252 
253 	/* hop count */
254 	(void) sprintf(cbuf, "%d", CurEnv->e_hopcount);
255 	define('c', cbuf, CurEnv);
256 
257 	/* time as integer, unix time, arpa time */
258 	settime();
259 
260 #ifdef TTYNAME
261 	/* tty name */
262 	if (macvalue('y', CurEnv) == NULL)
263 	{
264 		p = ttyname(2);
265 		if (p != NULL)
266 		{
267 			if (rindex(p, '/') != NULL)
268 				p = rindex(p, '/') + 1;
269 			(void) strcpy(ybuf, p);
270 			define('y', ybuf, CurEnv);
271 		}
272 	}
273 #endif TTYNAME
274 }
275 /*
276 **  SETTIME -- set the current time.
277 **
278 **	Parameters:
279 **		none.
280 **
281 **	Returns:
282 **		none.
283 **
284 **	Side Effects:
285 **		Sets the various time macros -- $a, $b, $d, $t.
286 */
287 
288 settime()
289 {
290 	register char *p;
291 	auto time_t now;
292 	static char tbuf[20];			/* holds "current" time */
293 	static char dbuf[30];			/* holds ctime(tbuf) */
294 	register struct tm *tm;
295 	extern char *arpadate();
296 	extern struct tm *gmtime();
297 	extern char *macvalue();
298 
299 	now = curtime();
300 	tm = gmtime(&now);
301 	(void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1,
302 			tm->tm_mday, tm->tm_hour, tm->tm_min);
303 	define('t', tbuf, CurEnv);
304 	(void) strcpy(dbuf, ctime(&now));
305 	*index(dbuf, '\n') = '\0';
306 	if (macvalue('d', CurEnv) == NULL)
307 		define('d', dbuf, CurEnv);
308 	p = newstr(arpadate(dbuf));
309 	if (macvalue('a', CurEnv) == NULL)
310 		define('a', p, CurEnv);
311 	define('b', p, CurEnv);
312 }
313 /*
314 **  OPENXSCRIPT -- Open transcript file
315 **
316 **	Creates a transcript file for possible eventual mailing or
317 **	sending back.
318 **
319 **	Parameters:
320 **		e -- the envelope to create the transcript in/for.
321 **
322 **	Returns:
323 **		none
324 **
325 **	Side Effects:
326 **		Creates the transcript file.
327 */
328 
329 openxscript(e)
330 	register ENVELOPE *e;
331 {
332 	register char *p;
333 
334 # ifdef LOG
335 	if (LogLevel > 19)
336 		syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)");
337 # endif LOG
338 	if (e->e_xfp != NULL)
339 		return;
340 	p = queuename(e, 'x');
341 	e->e_xfp = fopen(p, "w");
342 	if (e->e_xfp == NULL)
343 		syserr("Can't create %s", p);
344 	else
345 		(void) chmod(p, 0644);
346 }
347 /*
348 **  CLOSEXSCRIPT -- close the transcript file.
349 **
350 **	Parameters:
351 **		e -- the envelope containing the transcript to close.
352 **
353 **	Returns:
354 **		none.
355 **
356 **	Side Effects:
357 **		none.
358 */
359 
360 closexscript(e)
361 	register ENVELOPE *e;
362 {
363 	if (e->e_xfp == NULL)
364 		return;
365 	(void) fclose(e->e_xfp);
366 	e->e_xfp = NULL;
367 }
368 /*
369 **  SETSENDER -- set the person who this message is from
370 **
371 **	Under certain circumstances allow the user to say who
372 **	s/he is (using -f or -r).  These are:
373 **	1.  The user's uid is zero (root).
374 **	2.  The user's login name is in an approved list (typically
375 **	    from a network server).
376 **	3.  The address the user is trying to claim has a
377 **	    "!" character in it (since #2 doesn't do it for
378 **	    us if we are dialing out for UUCP).
379 **	A better check to replace #3 would be if the
380 **	effective uid is "UUCP" -- this would require me
381 **	to rewrite getpwent to "grab" uucp as it went by,
382 **	make getname more nasty, do another passwd file
383 **	scan, or compile the UID of "UUCP" into the code,
384 **	all of which are reprehensible.
385 **
386 **	Assuming all of these fail, we figure out something
387 **	ourselves.
388 **
389 **	Parameters:
390 **		from -- the person we would like to believe this message
391 **			is from, as specified on the command line.
392 **
393 **	Returns:
394 **		none.
395 **
396 **	Side Effects:
397 **		sets sendmail's notion of who the from person is.
398 */
399 
400 setsender(from)
401 	char *from;
402 {
403 	register char **pvp;
404 	char *realname = NULL;
405 	register struct passwd *pw;
406 	char buf[MAXNAME];
407 	char pvpbuf[PSBUFSIZE];
408 	extern struct passwd *getpwnam();
409 	extern char *macvalue();
410 	extern char **prescan();
411 	extern bool safefile();
412 	extern char *FullName;
413 
414 # ifdef DEBUG
415 	if (tTd(45, 1))
416 		printf("setsender(%s)\n", from == NULL ? "" : from);
417 # endif DEBUG
418 
419 	/*
420 	**  Figure out the real user executing us.
421 	**	Username can return errno != 0 on non-errors.
422 	*/
423 
424 	if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
425 		realname = from;
426 	if (realname == NULL || realname[0] == '\0')
427 	{
428 		extern char *username();
429 
430 		realname = username();
431 	}
432 
433 	/*
434 	**  Determine if this real person is allowed to alias themselves.
435 	*/
436 
437 	if (from != NULL)
438 	{
439 		extern bool trusteduser();
440 
441 		if (!trusteduser(realname) &&
442 # ifdef DEBUG
443 		    (!tTd(1, 9) || getuid() != geteuid()) &&
444 # endif DEBUG
445 		    index(from, '!') == NULL && getuid() != 0)
446 		{
447 			/* network sends -r regardless (why why why?) */
448 			/* syserr("%s, you cannot use the -f flag", realname); */
449 			from = NULL;
450 		}
451 	}
452 
453 	SuprErrs = TRUE;
454 	if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL)
455 	{
456 		/* log garbage addresses for traceback */
457 		if (from != NULL)
458 		{
459 # ifdef LOG
460 			if (LogLevel >= 1)
461 				syslog(LOG_ERR, "Unparseable user %s wants to be %s",
462 						realname, from);
463 # endif LOG
464 		}
465 		from = newstr(realname);
466 		if (parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL &&
467 		    parseaddr("postmaster", &CurEnv->e_from, 1, '\0') == NULL)
468 		{
469 			syserr("setsender: can't even parse postmaster!");
470 		}
471 	}
472 	else
473 		FromFlag = TRUE;
474 	CurEnv->e_from.q_flags |= QDONTSEND;
475 	loweraddr(&CurEnv->e_from);
476 	SuprErrs = FALSE;
477 
478 	if (CurEnv->e_from.q_mailer == LocalMailer &&
479 	    (pw = getpwnam(CurEnv->e_from.q_user)) != NULL)
480 	{
481 		/*
482 		**  Process passwd file entry.
483 		*/
484 
485 
486 		/* extract home directory */
487 		CurEnv->e_from.q_home = newstr(pw->pw_dir);
488 		define('z', CurEnv->e_from.q_home, CurEnv);
489 
490 		/* extract user and group id */
491 		CurEnv->e_from.q_uid = pw->pw_uid;
492 		CurEnv->e_from.q_gid = pw->pw_gid;
493 
494 		/* if the user has given fullname already, don't redefine */
495 		if (FullName == NULL)
496 			FullName = macvalue('x', CurEnv);
497 		if (FullName != NULL && FullName[0] == '\0')
498 			FullName = NULL;
499 
500 		/* extract full name from passwd file */
501 		if (FullName == NULL && pw->pw_gecos != NULL &&
502 		    strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0)
503 		{
504 			buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf);
505 			if (buf[0] != '\0')
506 				FullName = newstr(buf);
507 		}
508 		if (FullName != NULL)
509 			define('x', FullName, CurEnv);
510 	}
511 	else
512 	{
513 #ifndef V6
514 		if (CurEnv->e_from.q_home == NULL)
515 			CurEnv->e_from.q_home = getenv("HOME");
516 #endif V6
517 		CurEnv->e_from.q_uid = getuid();
518 		CurEnv->e_from.q_gid = getgid();
519 	}
520 
521 	if (CurEnv->e_from.q_uid != 0)
522 	{
523 		DefUid = CurEnv->e_from.q_uid;
524 		DefGid = CurEnv->e_from.q_gid;
525 	}
526 
527 	/*
528 	**  Rewrite the from person to dispose of possible implicit
529 	**	links in the net.
530 	*/
531 
532 	pvp = prescan(from, '\0', pvpbuf);
533 	if (pvp == NULL)
534 	{
535 		syserr("cannot prescan from (%s)", from);
536 		finis();
537 	}
538 	rewrite(pvp, 3);
539 	rewrite(pvp, 1);
540 	rewrite(pvp, 4);
541 	cataddr(pvp, buf, sizeof buf);
542 	define('f', newstr(buf), CurEnv);
543 
544 	/* save the domain spec if this mailer wants it */
545 	if (CurEnv->e_from.q_mailer != NULL &&
546 	    bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags))
547 	{
548 		extern char **copyplist();
549 
550 		while (*pvp != NULL && strcmp(*pvp, "@") != 0)
551 			pvp++;
552 		if (*pvp != NULL)
553 			CurEnv->e_fromdomain = copyplist(pvp, TRUE);
554 	}
555 }
556 /*
557 **  TRUSTEDUSER -- tell us if this user is to be trusted.
558 **
559 **	Parameters:
560 **		user -- the user to be checked.
561 **
562 **	Returns:
563 **		TRUE if the user is in an approved list.
564 **		FALSE otherwise.
565 **
566 **	Side Effects:
567 **		none.
568 */
569 
570 bool
571 trusteduser(user)
572 	char *user;
573 {
574 	register char **ulist;
575 	extern char *TrustedUsers[];
576 
577 	for (ulist = TrustedUsers; *ulist != NULL; ulist++)
578 		if (strcmp(*ulist, user) == 0)
579 			return (TRUE);
580 	return (FALSE);
581 }
582