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