1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)recipient.c	5.28 (Berkeley) 05/29/92";
11 #endif /* not lint */
12 
13 # include <sys/types.h>
14 # include <sys/stat.h>
15 # include <sys/file.h>
16 # include <pwd.h>
17 # include "sendmail.h"
18 
19 /*
20 **  SENDTOLIST -- Designate a send list.
21 **
22 **	The parameter is a comma-separated list of people to send to.
23 **	This routine arranges to send to all of them.
24 **
25 **	Parameters:
26 **		list -- the send list.
27 **		ctladdr -- the address template for the person to
28 **			send to -- effective uid/gid are important.
29 **			This is typically the alias that caused this
30 **			expansion.
31 **		sendq -- a pointer to the head of a queue to put
32 **			these people into.
33 **
34 **	Returns:
35 **		none
36 **
37 **	Side Effects:
38 **		none.
39 */
40 
41 # define MAXRCRSN	10
42 
43 sendtolist(list, ctladdr, sendq)
44 	char *list;
45 	ADDRESS *ctladdr;
46 	ADDRESS **sendq;
47 {
48 	register char *p;
49 	register ADDRESS *al;	/* list of addresses to send to */
50 	bool firstone;		/* set on first address sent */
51 	bool selfref;		/* set if this list includes ctladdr */
52 	char delimiter;		/* the address delimiter */
53 
54 	if (tTd(25, 1))
55 	{
56 		printf("sendto: %s\n   ctladdr=", list);
57 		printaddr(ctladdr, FALSE);
58 	}
59 
60 	/* heuristic to determine old versus new style addresses */
61 	if (ctladdr == NULL &&
62 	    (index(list, ',') != NULL || index(list, ';') != NULL ||
63 	     index(list, '<') != NULL || index(list, '(') != NULL))
64 		CurEnv->e_flags &= ~EF_OLDSTYLE;
65 	delimiter = ' ';
66 	if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
67 		delimiter = ',';
68 
69 	firstone = TRUE;
70 	selfref = FALSE;
71 	al = NULL;
72 
73 	for (p = list; *p != '\0'; )
74 	{
75 		register ADDRESS *a;
76 		extern char *DelimChar;		/* defined in prescan */
77 
78 		/* parse the address */
79 		while (isspace(*p) || *p == ',')
80 			p++;
81 		a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
82 		p = DelimChar;
83 		if (a == NULL)
84 			continue;
85 		a->q_next = al;
86 		a->q_alias = ctladdr;
87 
88 		/* see if this should be marked as a primary address */
89 		if (ctladdr == NULL ||
90 		    (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
91 			a->q_flags |= QPRIMARY;
92 
93 		/* put on send queue or suppress self-reference */
94 		if (ctladdr != NULL && sameaddr(ctladdr, a))
95 			selfref = TRUE;
96 		else
97 			al = a;
98 		firstone = FALSE;
99 	}
100 
101 	/* if this alias doesn't include itself, delete ctladdr */
102 	if (!selfref && ctladdr != NULL)
103 		ctladdr->q_flags |= QDONTSEND;
104 
105 	/* arrange to send to everyone on the local send list */
106 	while (al != NULL)
107 	{
108 		register ADDRESS *a = al;
109 		extern ADDRESS *recipient();
110 
111 		al = a->q_next;
112 		setctladdr(a);
113 		a = recipient(a, sendq);
114 
115 		/* arrange to inherit full name */
116 		if (a->q_fullname == NULL && ctladdr != NULL)
117 			a->q_fullname = ctladdr->q_fullname;
118 	}
119 
120 	CurEnv->e_to = NULL;
121 }
122 /*
123 **  RECIPIENT -- Designate a message recipient
124 **
125 **	Saves the named person for future mailing.
126 **
127 **	Parameters:
128 **		a -- the (preparsed) address header for the recipient.
129 **		sendq -- a pointer to the head of a queue to put the
130 **			recipient in.  Duplicate supression is done
131 **			in this queue.
132 **
133 **	Returns:
134 **		The actual address in the queue.  This will be "a" if
135 **		the address is not a duplicate, else the original address.
136 **
137 **	Side Effects:
138 **		none.
139 */
140 
141 extern ADDRESS *getctladdr();
142 extern char	*RcptLogFile;
143 
144 ADDRESS *
145 recipient(a, sendq)
146 	register ADDRESS *a;
147 	register ADDRESS **sendq;
148 {
149 	register ADDRESS *q;
150 	ADDRESS **pq;
151 	register struct mailer *m;
152 	register char *p;
153 	bool quoted = FALSE;		/* set if the addr has a quote bit */
154 	int findusercount = 0;
155 	char buf[MAXNAME];		/* unquoted image of the user name */
156 	extern bool safefile();
157 
158 	CurEnv->e_to = a->q_paddr;
159 	m = a->q_mailer;
160 	errno = 0;
161 	if (tTd(26, 1))
162 	{
163 		printf("\nrecipient: ");
164 		printaddr(a, FALSE);
165 	}
166 
167 	/* break aliasing loops */
168 	if (AliasLevel > MAXRCRSN)
169 	{
170 		usrerr("aliasing/forwarding loop broken");
171 		return (a);
172 	}
173 
174 	/*
175 	**  Finish setting up address structure.
176 	*/
177 
178 	/* set the queue timeout */
179 	a->q_timeout = TimeOut;
180 
181 	/* map user & host to lower case if requested on non-aliases */
182 	if (a->q_alias == NULL)
183 		loweraddr(a);
184 
185 	/* get unquoted user for file, program or user.name check */
186 	(void) strcpy(buf, a->q_user);
187 	for (p = buf; *p != '\0' && !quoted; p++)
188 	{
189 		if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
190 			quoted = TRUE;
191 	}
192 	stripquotes(buf, TRUE);
193 
194 	/* do sickly crude mapping for program mailing, etc. */
195 	if (m == LocalMailer && buf[0] == '|')
196 	{
197 		a->q_mailer = m = ProgMailer;
198 		a->q_user++;
199 		if (a->q_alias == NULL && !QueueRun && !ForceMail)
200 		{
201 			a->q_flags |= QDONTSEND|QBADADDR;
202 			usrerr("Cannot mail directly to programs");
203 		}
204 	}
205 
206 	/*
207 	**  Look up this person in the recipient list.
208 	**	If they are there already, return, otherwise continue.
209 	**	If the list is empty, just add it.  Notice the cute
210 	**	hack to make from addresses suppress things correctly:
211 	**	the QDONTSEND bit will be set in the send list.
212 	**	[Please note: the emphasis is on "hack."]
213 	*/
214 
215 	for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
216 	{
217 		if (!ForceMail && sameaddr(q, a))
218 		{
219 			if (tTd(26, 1))
220 			{
221 				printf("%s in sendq: ", a->q_paddr);
222 				printaddr(q, FALSE);
223 			}
224 			if (!bitset(QDONTSEND, a->q_flags))
225 				message(Arpa_Info, "duplicate suppressed");
226 			if (!bitset(QPRIMARY, q->q_flags))
227 				q->q_flags |= a->q_flags;
228 			return (q);
229 		}
230 	}
231 
232 	/* add address on list */
233 	*pq = a;
234 	a->q_next = NULL;
235 	CurEnv->e_nrcpts++;
236 
237 	if (a->q_alias == NULL && RcptLogFile != NULL &&
238 	    !bitset(QDONTSEND, a->q_flags))
239 	{
240 		static int RcptLogFd = -1;
241 
242 		/*
243 		**  Log the incoming recipient name before aliasing,
244 		**  expanding, forwarding, rewriting, and all that jazz.
245 		**  We'll use this to track down out-of-date aliases,
246 		**  host names, and so forth.
247 		*/
248 
249 		if (RcptLogFd < 0)
250 		{
251 			/* try to open the log file */
252 			RcptLogFd = open(RcptLogFile, O_WRONLY|O_APPEND|O_CREAT, 0666);
253 			if (RcptLogFd >= 0)
254 				(void) fcntl(RcptLogFd, F_SETFD, 1);
255 		}
256 		if (RcptLogFd >= 0)
257 		{
258 			int l = strlen(a->q_paddr);
259 
260 			a->q_paddr[l] = '\n';
261 			if (write(RcptLogFd, a->q_paddr, l + 1) < 0)
262 			{
263 				(void) close(RcptLogFd);
264 				RcptLogFd = -1;
265 			}
266 			a->q_paddr[l] = '\0';
267 		}
268 	}
269 
270 	/*
271 	**  Alias the name and handle :include: specs.
272 	*/
273 
274   trylocaluser:
275 	if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
276 	{
277 		if (strncmp(a->q_user, ":include:", 9) == 0)
278 		{
279 			a->q_flags |= QDONTSEND;
280 			if (a->q_alias == NULL && !QueueRun && !ForceMail)
281 			{
282 				a->q_flags |= QBADADDR;
283 				usrerr("Cannot mail directly to :include:s");
284 			}
285 			else
286 			{
287 				message(Arpa_Info, "including file %s", &a->q_user[9]);
288 				include(&a->q_user[9], FALSE, a, sendq);
289 			}
290 		}
291 		else
292 		{
293 			/* try aliasing */
294 			alias(a, sendq);
295 
296 # ifdef USERDB
297 			/* if not aliased, look it up in the user database */
298 			if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags))
299 			{
300 				extern int udbexpand();
301 
302 				if (udbexpand(a, sendq) == EX_TEMPFAIL)
303 				{
304 					a->q_flags |= QQUEUEUP;
305 					if (CurEnv->e_message == NULL)
306 						CurEnv->e_message = newstr("Deferred: user database error");
307 # ifdef LOG
308 					if (LogLevel > 3)
309 						syslog(LOG_INFO, "%s: deferred: udbexpand",
310 							CurEnv->e_id);
311 # endif
312 					message(Arpa_Info, "queued (user database error)");
313 					return (a);
314 				}
315 			}
316 # endif
317 		}
318 	}
319 
320 	/*
321 	**  If the user is local and still being sent, verify that
322 	**  the address is good.  If it is, try to forward.
323 	**  If the address is already good, we have a forwarding
324 	**  loop.  This can be broken by just sending directly to
325 	**  the user (which is probably correct anyway).
326 	*/
327 
328 	if (bitset(QDONTSEND, a->q_flags) || m != LocalMailer)
329 		return (a);
330 
331 	/* see if this is to a file */
332 	if (buf[0] == '/')
333 	{
334 		struct stat stb;
335 		extern bool writable();
336 
337 		p = rindex(buf, '/');
338 		/* check if writable or creatable */
339 		if (a->q_alias == NULL && !QueueRun && !ForceMail)
340 		{
341 			a->q_flags |= QDONTSEND|QBADADDR;
342 			usrerr("Cannot mail directly to files");
343 		}
344 		else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
345 		    (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
346 		{
347 			a->q_flags |= QBADADDR;
348 			giveresponse(EX_CANTCREAT, m, CurEnv);
349 		}
350 		return (a);
351 	}
352 
353 	/*
354 	**  If we have a level two config file, then pass the name through
355 	**  Ruleset 5 before sending it off.  Ruleset 5 has the right
356 	**  to send rewrite it to another mailer.  This gives us a hook
357 	**  after local aliasing has been done.
358 	*/
359 
360 	if (tTd(29, 5))
361 	{
362 		printf("recipient: testing local?  cl=%d, rr5=%x\n\t",
363 			ConfigLevel, RewriteRules[5]);
364 		printaddr(a, FALSE);
365 	}
366 	if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 &&
367 	    RewriteRules[5] != NULL)
368 	{
369 		maplocaluser(a, sendq);
370 	}
371 
372 	/*
373 	**  If it didn't get rewritten to another mailer, go ahead
374 	**  and deliver it.
375 	*/
376 
377 	if (!bitset(QDONTSEND, a->q_flags))
378 	{
379 		register struct passwd *pw;
380 		extern struct passwd *finduser();
381 
382 		/* warning -- finduser may trash buf */
383 		pw = finduser(buf);
384 		if (pw == NULL)
385 		{
386 			a->q_flags |= QBADADDR;
387 			giveresponse(EX_NOUSER, m, CurEnv);
388 		}
389 		else
390 		{
391 			char nbuf[MAXNAME];
392 
393 			if (strcmp(a->q_user, pw->pw_name) != 0)
394 			{
395 				/* name was a fuzzy match */
396 				a->q_user = newstr(pw->pw_name);
397 				if (findusercount++ > 3)
398 				{
399 					usrerr("aliasing/forwarding loop for %s broken",
400 						pw->pw_name);
401 					return (a);
402 				}
403 
404 				/* see if it aliases */
405 				(void) strcpy(buf, pw->pw_name);
406 				goto trylocaluser;
407 			}
408 			a->q_home = newstr(pw->pw_dir);
409 			a->q_uid = pw->pw_uid;
410 			a->q_gid = pw->pw_gid;
411 			a->q_flags |= QGOODUID;
412 			buildfname(pw->pw_gecos, pw->pw_name, nbuf);
413 			if (nbuf[0] != '\0')
414 				a->q_fullname = newstr(nbuf);
415 			if (!quoted)
416 				forward(a, sendq);
417 		}
418 	}
419 	return (a);
420 }
421 /*
422 **  FINDUSER -- find the password entry for a user.
423 **
424 **	This looks a lot like getpwnam, except that it may want to
425 **	do some fancier pattern matching in /etc/passwd.
426 **
427 **	This routine contains most of the time of many sendmail runs.
428 **	It deserves to be optimized.
429 **
430 **	Parameters:
431 **		name -- the name to match against.
432 **
433 **	Returns:
434 **		A pointer to a pw struct.
435 **		NULL if name is unknown or ambiguous.
436 **
437 **	Side Effects:
438 **		may modify name.
439 */
440 
441 struct passwd *
442 finduser(name)
443 	char *name;
444 {
445 	register struct passwd *pw;
446 	register char *p;
447 	extern struct passwd *getpwent();
448 	extern struct passwd *getpwnam();
449 
450 	/* map upper => lower case */
451 	for (p = name; *p != '\0'; p++)
452 	{
453 		if (isascii(*p) && isupper(*p))
454 			*p = tolower(*p);
455 	}
456 
457 	/* look up this login name using fast path */
458 	if ((pw = getpwnam(name)) != NULL)
459 		return (pw);
460 
461 #ifdef MATCHGECOS
462 	/* see if fuzzy matching allowed */
463 	if (!MatchGecos)
464 		return NULL;
465 
466 	/* search for a matching full name instead */
467 	for (p = name; *p != '\0'; p++)
468 	{
469 		if (*p == (SpaceSub & 0177) || *p == '_')
470 			*p = ' ';
471 	}
472 	(void) setpwent();
473 	while ((pw = getpwent()) != NULL)
474 	{
475 		char buf[MAXNAME];
476 
477 		buildfname(pw->pw_gecos, pw->pw_name, buf);
478 		if (index(buf, ' ') != NULL && !strcasecmp(buf, name))
479 		{
480 			message(Arpa_Info, "sending to login name %s", pw->pw_name);
481 			return (pw);
482 		}
483 	}
484 #endif
485 	return (NULL);
486 }
487 /*
488 **  WRITABLE -- predicate returning if the file is writable.
489 **
490 **	This routine must duplicate the algorithm in sys/fio.c.
491 **	Unfortunately, we cannot use the access call since we
492 **	won't necessarily be the real uid when we try to
493 **	actually open the file.
494 **
495 **	Notice that ANY file with ANY execute bit is automatically
496 **	not writable.  This is also enforced by mailfile.
497 **
498 **	Parameters:
499 **		s -- pointer to a stat struct for the file.
500 **
501 **	Returns:
502 **		TRUE -- if we will be able to write this file.
503 **		FALSE -- if we cannot write this file.
504 **
505 **	Side Effects:
506 **		none.
507 */
508 
509 bool
510 writable(s)
511 	register struct stat *s;
512 {
513 	int euid, egid;
514 	int bits;
515 
516 	if (bitset(0111, s->st_mode))
517 		return (FALSE);
518 	euid = getruid();
519 	egid = getrgid();
520 	if (geteuid() == 0)
521 	{
522 		if (bitset(S_ISUID, s->st_mode))
523 			euid = s->st_uid;
524 		if (bitset(S_ISGID, s->st_mode))
525 			egid = s->st_gid;
526 	}
527 
528 	if (euid == 0)
529 		return (TRUE);
530 	bits = S_IWRITE;
531 	if (euid != s->st_uid)
532 	{
533 		bits >>= 3;
534 		if (egid != s->st_gid)
535 			bits >>= 3;
536 	}
537 	return ((s->st_mode & bits) != 0);
538 }
539 /*
540 **  INCLUDE -- handle :include: specification.
541 **
542 **	Parameters:
543 **		fname -- filename to include.
544 **		forwarding -- if TRUE, we are reading a .forward file.
545 **			if FALSE, it's a :include: file.
546 **		ctladdr -- address template to use to fill in these
547 **			addresses -- effective user/group id are
548 **			the important things.
549 **		sendq -- a pointer to the head of the send queue
550 **			to put these addresses in.
551 **
552 **	Returns:
553 **		none.
554 **
555 **	Side Effects:
556 **		reads the :include: file and sends to everyone
557 **		listed in that file.
558 */
559 
560 static jmp_buf	CtxIncludeTimeout;
561 
562 include(fname, forwarding, ctladdr, sendq)
563 	char *fname;
564 	bool forwarding;
565 	ADDRESS *ctladdr;
566 	ADDRESS **sendq;
567 {
568 	register FILE *fp;
569 	char *oldto = CurEnv->e_to;
570 	char *oldfilename = FileName;
571 	int oldlinenumber = LineNumber;
572 	register EVENT *ev = NULL;
573 	char buf[MAXLINE];
574 	static int includetimeout();
575 
576 	/*
577 	**  If home directory is remote mounted but server is down,
578 	**  this can hang or give errors; use a timeout to avoid this
579 	*/
580 
581 	if (setjmp(CtxIncludeTimeout) != 0)
582 	{
583 		ctladdr->q_flags |= QQUEUEUP|QDONTSEND;
584 		errno = 0;
585 		usrerr("451 open timeout on %s", fname);
586 		return;
587 	}
588 	ev = setevent((time_t) 60, includetimeout, 0);
589 
590 	/* if forwarding, the input file must be marked safe */
591 	if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD))
592 	{
593 		/* don't use this .forward file */
594 		clrevent(ev);
595 		return;
596 	}
597 
598 	fp = fopen(fname, "r");
599 	if (fp == NULL)
600 	{
601 		usrerr("Cannot open %s", fname);
602 		return;
603 	}
604 
605 	if (getctladdr(ctladdr) == NULL)
606 	{
607 		struct stat st;
608 
609 		if (fstat(fileno(fp), &st) < 0)
610 			syserr("Cannot fstat %s!", fname);
611 		ctladdr->q_uid = st.st_uid;
612 		ctladdr->q_gid = st.st_gid;
613 		ctladdr->q_flags |= QGOODUID;
614 	}
615 
616 	clrevent(ev);
617 
618 	/* read the file -- each line is a comma-separated list. */
619 	FileName = fname;
620 	LineNumber = 0;
621 	while (fgets(buf, sizeof buf, fp) != NULL)
622 	{
623 		register char *p = index(buf, '\n');
624 
625 		LineNumber++;
626 		if (p != NULL)
627 			*p = '\0';
628 		if (buf[0] == '\0' || buf[0] == '#')
629 			continue;
630 		CurEnv->e_to = oldto;
631 		message(Arpa_Info, "%s to %s",
632 			forwarding ? "forwarding" : "sending", buf);
633 		AliasLevel++;
634 		sendtolist(buf, ctladdr, sendq);
635 		AliasLevel--;
636 	}
637 
638 	(void) fclose(fp);
639 	FileName = oldfilename;
640 	LineNumber = oldlinenumber;
641 }
642 
643 static
644 includetimeout()
645 {
646 	longjmp(CtxIncludeTimeout, 1);
647 }
648 /*
649 **  SENDTOARGV -- send to an argument vector.
650 **
651 **	Parameters:
652 **		argv -- argument vector to send to.
653 **
654 **	Returns:
655 **		none.
656 **
657 **	Side Effects:
658 **		puts all addresses on the argument vector onto the
659 **			send queue.
660 */
661 
662 sendtoargv(argv)
663 	register char **argv;
664 {
665 	register char *p;
666 
667 	while ((p = *argv++) != NULL)
668 	{
669 		if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
670 		{
671 			char nbuf[MAXNAME];
672 
673 			if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
674 				usrerr("address overflow");
675 			else
676 			{
677 				(void) strcpy(nbuf, p);
678 				(void) strcat(nbuf, "@");
679 				(void) strcat(nbuf, argv[1]);
680 				p = newstr(nbuf);
681 				argv += 2;
682 			}
683 		}
684 		sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
685 	}
686 }
687 /*
688 **  GETCTLADDR -- get controlling address from an address header.
689 **
690 **	If none, get one corresponding to the effective userid.
691 **
692 **	Parameters:
693 **		a -- the address to find the controller of.
694 **
695 **	Returns:
696 **		the controlling address.
697 **
698 **	Side Effects:
699 **		none.
700 */
701 
702 ADDRESS *
703 getctladdr(a)
704 	register ADDRESS *a;
705 {
706 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
707 		a = a->q_alias;
708 	return (a);
709 }
710