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