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[] = "@(#)recipient.c	5.15 (Berkeley) 02/27/89";
21 #endif /* not lint */
22 
23 # include <sys/types.h>
24 # include <sys/stat.h>
25 # include <pwd.h>
26 # include "sendmail.h"
27 
28 /*
29 **  SENDTOLIST -- Designate a send list.
30 **
31 **	The parameter is a comma-separated list of people to send to.
32 **	This routine arranges to send to all of them.
33 **
34 **	Parameters:
35 **		list -- the send list.
36 **		ctladdr -- the address template for the person to
37 **			send to -- effective uid/gid are important.
38 **			This is typically the alias that caused this
39 **			expansion.
40 **		sendq -- a pointer to the head of a queue to put
41 **			these people into.
42 **
43 **	Returns:
44 **		none
45 **
46 **	Side Effects:
47 **		none.
48 */
49 
50 # define MAXRCRSN	10
51 
52 sendtolist(list, ctladdr, sendq)
53 	char *list;
54 	ADDRESS *ctladdr;
55 	ADDRESS **sendq;
56 {
57 	register char *p;
58 	register ADDRESS *al;	/* list of addresses to send to */
59 	bool firstone;		/* set on first address sent */
60 	bool selfref;		/* set if this list includes ctladdr */
61 	char delimiter;		/* the address delimiter */
62 
63 	if (tTd(25, 1))
64 	{
65 		printf("sendto: %s\n   ctladdr=", list);
66 		printaddr(ctladdr, FALSE);
67 	}
68 
69 	/* heuristic to determine old versus new style addresses */
70 	if (ctladdr == NULL &&
71 	    (index(list, ',') != NULL || index(list, ';') != NULL ||
72 	     index(list, '<') != NULL || index(list, '(') != NULL))
73 		CurEnv->e_flags &= ~EF_OLDSTYLE;
74 	delimiter = ' ';
75 	if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
76 		delimiter = ',';
77 
78 	firstone = TRUE;
79 	selfref = FALSE;
80 	al = NULL;
81 
82 	for (p = list; *p != '\0'; )
83 	{
84 		register ADDRESS *a;
85 		extern char *DelimChar;		/* defined in prescan */
86 
87 		/* parse the address */
88 		while (isspace(*p) || *p == ',')
89 			p++;
90 		a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
91 		p = DelimChar;
92 		if (a == NULL)
93 			continue;
94 		a->q_next = al;
95 		a->q_alias = ctladdr;
96 
97 		/* see if this should be marked as a primary address */
98 		if (ctladdr == NULL ||
99 		    (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
100 			a->q_flags |= QPRIMARY;
101 
102 		/* put on send queue or suppress self-reference */
103 		if (ctladdr != NULL && sameaddr(ctladdr, a))
104 			selfref = TRUE;
105 		else
106 			al = a;
107 		firstone = FALSE;
108 	}
109 
110 	/* if this alias doesn't include itself, delete ctladdr */
111 	if (!selfref && ctladdr != NULL)
112 		ctladdr->q_flags |= QDONTSEND;
113 
114 	/* arrange to send to everyone on the local send list */
115 	while (al != NULL)
116 	{
117 		register ADDRESS *a = al;
118 		extern ADDRESS *recipient();
119 
120 		al = a->q_next;
121 		a = recipient(a, sendq);
122 
123 		/* arrange to inherit full name */
124 		if (a->q_fullname == NULL && ctladdr != NULL)
125 			a->q_fullname = ctladdr->q_fullname;
126 	}
127 
128 	CurEnv->e_to = NULL;
129 }
130 /*
131 **  RECIPIENT -- Designate a message recipient
132 **
133 **	Saves the named person for future mailing.
134 **
135 **	Parameters:
136 **		a -- the (preparsed) address header for the recipient.
137 **		sendq -- a pointer to the head of a queue to put the
138 **			recipient in.  Duplicate supression is done
139 **			in this queue.
140 **
141 **	Returns:
142 **		The actual address in the queue.  This will be "a" if
143 **		the address is not a duplicate, else the original address.
144 **
145 **	Side Effects:
146 **		none.
147 */
148 
149 ADDRESS *
150 recipient(a, sendq)
151 	register ADDRESS *a;
152 	register ADDRESS **sendq;
153 {
154 	register ADDRESS *q;
155 	ADDRESS **pq;
156 	register struct mailer *m;
157 	register char *p;
158 	bool quoted = FALSE;		/* set if the addr has a quote bit */
159 	char buf[MAXNAME];		/* unquoted image of the user name */
160 	extern ADDRESS *getctladdr();
161 	extern bool safefile();
162 
163 	CurEnv->e_to = a->q_paddr;
164 	m = a->q_mailer;
165 	errno = 0;
166 	if (tTd(26, 1))
167 	{
168 		printf("\nrecipient: ");
169 		printaddr(a, FALSE);
170 	}
171 
172 	/* break aliasing loops */
173 	if (AliasLevel > MAXRCRSN)
174 	{
175 		usrerr("aliasing/forwarding loop broken");
176 		return (a);
177 	}
178 
179 	/*
180 	**  Finish setting up address structure.
181 	*/
182 
183 	/* set the queue timeout */
184 	a->q_timeout = TimeOut;
185 
186 	/* map user & host to lower case if requested on non-aliases */
187 	if (a->q_alias == NULL)
188 		loweraddr(a);
189 
190 	/* get unquoted user for file, program or user.name check */
191 	(void) strcpy(buf, a->q_user);
192 	for (p = buf; *p != '\0' && !quoted; p++)
193 	{
194 		if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
195 			quoted = TRUE;
196 	}
197 	stripquotes(buf, TRUE);
198 
199 	/* do sickly crude mapping for program mailing, etc. */
200 	if (m == LocalMailer && buf[0] == '|')
201 	{
202 		a->q_mailer = m = ProgMailer;
203 		a->q_user++;
204 		if (a->q_alias == NULL && !QueueRun && !ForceMail)
205 		{
206 			a->q_flags |= QDONTSEND|QBADADDR;
207 			usrerr("Cannot mail directly to programs");
208 		}
209 	}
210 
211 	/*
212 	**  Look up this person in the recipient list.
213 	**	If they are there already, return, otherwise continue.
214 	**	If the list is empty, just add it.  Notice the cute
215 	**	hack to make from addresses suppress things correctly:
216 	**	the QDONTSEND bit will be set in the send list.
217 	**	[Please note: the emphasis is on "hack."]
218 	*/
219 
220 	for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
221 	{
222 		if (!ForceMail && sameaddr(q, a))
223 		{
224 			if (tTd(26, 1))
225 			{
226 				printf("%s in sendq: ", a->q_paddr);
227 				printaddr(q, FALSE);
228 			}
229 			if (!bitset(QDONTSEND, a->q_flags))
230 				message(Arpa_Info, "duplicate suppressed");
231 			if (!bitset(QPRIMARY, q->q_flags))
232 				q->q_flags |= a->q_flags;
233 			return (q);
234 		}
235 	}
236 
237 	/* add address on list */
238 	*pq = a;
239 	a->q_next = NULL;
240 	CurEnv->e_nrcpts++;
241 
242 	/*
243 	**  Alias the name and handle :include: specs.
244 	*/
245 
246 	if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
247 	{
248 		if (strncmp(a->q_user, ":include:", 9) == 0)
249 		{
250 			a->q_flags |= QDONTSEND;
251 			if (a->q_alias == NULL && !QueueRun && !ForceMail)
252 			{
253 				a->q_flags |= QBADADDR;
254 				usrerr("Cannot mail directly to :include:s");
255 			}
256 			else
257 			{
258 				message(Arpa_Info, "including file %s", &a->q_user[9]);
259 				include(&a->q_user[9], " sending", a, sendq);
260 			}
261 		}
262 		else
263 			alias(a, sendq);
264 	}
265 
266 	/*
267 	**  If the user is local and still being sent, verify that
268 	**  the address is good.  If it is, try to forward.
269 	**  If the address is already good, we have a forwarding
270 	**  loop.  This can be broken by just sending directly to
271 	**  the user (which is probably correct anyway).
272 	*/
273 
274 	if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
275 	{
276 		struct stat stb;
277 		extern bool writable();
278 
279 		/* see if this is to a file */
280 		if (buf[0] == '/')
281 		{
282 			p = rindex(buf, '/');
283 			/* check if writable or creatable */
284 			if (a->q_alias == NULL && !QueueRun && !ForceMail)
285 			{
286 				a->q_flags |= QDONTSEND|QBADADDR;
287 				usrerr("Cannot mail directly to files");
288 			}
289 			else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
290 			    (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
291 			{
292 				a->q_flags |= QBADADDR;
293 				giveresponse(EX_CANTCREAT, m, CurEnv);
294 			}
295 		}
296 		else
297 		{
298 			register struct passwd *pw;
299 			extern struct passwd *finduser();
300 
301 			/* warning -- finduser may trash buf */
302 			pw = finduser(buf);
303 			if (pw == NULL)
304 			{
305 				a->q_flags |= QBADADDR;
306 				giveresponse(EX_NOUSER, m, CurEnv);
307 			}
308 			else
309 			{
310 				char nbuf[MAXNAME];
311 
312 				if (strcmp(a->q_user, pw->pw_name) != 0)
313 				{
314 					a->q_user = newstr(pw->pw_name);
315 					(void) strcpy(buf, pw->pw_name);
316 				}
317 				a->q_home = newstr(pw->pw_dir);
318 				a->q_uid = pw->pw_uid;
319 				a->q_gid = pw->pw_gid;
320 				a->q_flags |= QGOODUID;
321 				buildfname(pw->pw_gecos, pw->pw_name, nbuf);
322 				if (nbuf[0] != '\0')
323 					a->q_fullname = newstr(nbuf);
324 				if (!quoted)
325 					forward(a, sendq);
326 			}
327 		}
328 	}
329 	return (a);
330 }
331 /*
332 **  FINDUSER -- find the password entry for a user.
333 **
334 **	This looks a lot like getpwnam, except that it may want to
335 **	do some fancier pattern matching in /etc/passwd.
336 **
337 **	This routine contains most of the time of many sendmail runs.
338 **	It deserves to be optimized.
339 **
340 **	Parameters:
341 **		name -- the name to match against.
342 **
343 **	Returns:
344 **		A pointer to a pw struct.
345 **		NULL if name is unknown or ambiguous.
346 **
347 **	Side Effects:
348 **		may modify name.
349 */
350 
351 struct passwd *
352 finduser(name)
353 	char *name;
354 {
355 	register struct passwd *pw;
356 	register char *p;
357 	extern struct passwd *getpwent();
358 	extern struct passwd *getpwnam();
359 
360 	/* map upper => lower case */
361 	for (p = name; *p != '\0'; p++)
362 	{
363 		if (isascii(*p) && isupper(*p))
364 			*p = tolower(*p);
365 	}
366 
367 	/* look up this login name using fast path */
368 	if ((pw = getpwnam(name)) != NULL)
369 		return (pw);
370 
371 	/* search for a matching full name instead */
372 	for (p = name; *p != '\0'; p++)
373 	{
374 		if (*p == (SpaceSub & 0177) || *p == '_')
375 			*p = ' ';
376 	}
377 	(void) setpwent();
378 	while ((pw = getpwent()) != NULL)
379 	{
380 		char buf[MAXNAME];
381 
382 		buildfname(pw->pw_gecos, pw->pw_name, buf);
383 		if (index(buf, ' ') != NULL && !strcasecmp(buf, name))
384 		{
385 			message(Arpa_Info, "sending to login name %s", pw->pw_name);
386 			return (pw);
387 		}
388 	}
389 	return (NULL);
390 }
391 /*
392 **  WRITABLE -- predicate returning if the file is writable.
393 **
394 **	This routine must duplicate the algorithm in sys/fio.c.
395 **	Unfortunately, we cannot use the access call since we
396 **	won't necessarily be the real uid when we try to
397 **	actually open the file.
398 **
399 **	Notice that ANY file with ANY execute bit is automatically
400 **	not writable.  This is also enforced by mailfile.
401 **
402 **	Parameters:
403 **		s -- pointer to a stat struct for the file.
404 **
405 **	Returns:
406 **		TRUE -- if we will be able to write this file.
407 **		FALSE -- if we cannot write this file.
408 **
409 **	Side Effects:
410 **		none.
411 */
412 
413 bool
414 writable(s)
415 	register struct stat *s;
416 {
417 	int euid, egid;
418 	int bits;
419 
420 	if (bitset(0111, s->st_mode))
421 		return (FALSE);
422 	euid = getruid();
423 	egid = getrgid();
424 	if (geteuid() == 0)
425 	{
426 		if (bitset(S_ISUID, s->st_mode))
427 			euid = s->st_uid;
428 		if (bitset(S_ISGID, s->st_mode))
429 			egid = s->st_gid;
430 	}
431 
432 	if (euid == 0)
433 		return (TRUE);
434 	bits = S_IWRITE;
435 	if (euid != s->st_uid)
436 	{
437 		bits >>= 3;
438 		if (egid != s->st_gid)
439 			bits >>= 3;
440 	}
441 	return ((s->st_mode & bits) != 0);
442 }
443 /*
444 **  INCLUDE -- handle :include: specification.
445 **
446 **	Parameters:
447 **		fname -- filename to include.
448 **		msg -- message to print in verbose mode.
449 **		ctladdr -- address template to use to fill in these
450 **			addresses -- effective user/group id are
451 **			the important things.
452 **		sendq -- a pointer to the head of the send queue
453 **			to put these addresses in.
454 **
455 **	Returns:
456 **		none.
457 **
458 **	Side Effects:
459 **		reads the :include: file and sends to everyone
460 **		listed in that file.
461 */
462 
463 include(fname, msg, ctladdr, sendq)
464 	char *fname;
465 	char *msg;
466 	ADDRESS *ctladdr;
467 	ADDRESS **sendq;
468 {
469 	char buf[MAXLINE];
470 	register FILE *fp;
471 	char *oldto = CurEnv->e_to;
472 	char *oldfilename = FileName;
473 	int oldlinenumber = LineNumber;
474 
475 	fp = fopen(fname, "r");
476 	if (fp == NULL)
477 	{
478 		usrerr("Cannot open %s", fname);
479 		return;
480 	}
481 	if (getctladdr(ctladdr) == NULL)
482 	{
483 		struct stat st;
484 
485 		if (fstat(fileno(fp), &st) < 0)
486 			syserr("Cannot fstat %s!", fname);
487 		ctladdr->q_uid = st.st_uid;
488 		ctladdr->q_gid = st.st_gid;
489 		ctladdr->q_flags |= QGOODUID;
490 	}
491 
492 	/* read the file -- each line is a comma-separated list. */
493 	FileName = fname;
494 	LineNumber = 0;
495 	while (fgets(buf, sizeof buf, fp) != NULL)
496 	{
497 		register char *p = index(buf, '\n');
498 
499 		if (p != NULL)
500 			*p = '\0';
501 		if (buf[0] == '\0')
502 			continue;
503 		CurEnv->e_to = oldto;
504 		message(Arpa_Info, "%s to %s", msg, buf);
505 		AliasLevel++;
506 		sendtolist(buf, ctladdr, sendq);
507 		AliasLevel--;
508 	}
509 
510 	(void) fclose(fp);
511 	FileName = oldfilename;
512 	LineNumber = oldlinenumber;
513 }
514 /*
515 **  SENDTOARGV -- send to an argument vector.
516 **
517 **	Parameters:
518 **		argv -- argument vector to send to.
519 **
520 **	Returns:
521 **		none.
522 **
523 **	Side Effects:
524 **		puts all addresses on the argument vector onto the
525 **			send queue.
526 */
527 
528 sendtoargv(argv)
529 	register char **argv;
530 {
531 	register char *p;
532 
533 	while ((p = *argv++) != NULL)
534 	{
535 		if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
536 		{
537 			char nbuf[MAXNAME];
538 
539 			if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
540 				usrerr("address overflow");
541 			else
542 			{
543 				(void) strcpy(nbuf, p);
544 				(void) strcat(nbuf, "@");
545 				(void) strcat(nbuf, argv[1]);
546 				p = newstr(nbuf);
547 				argv += 2;
548 			}
549 		}
550 		sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
551 	}
552 }
553 /*
554 **  GETCTLADDR -- get controlling address from an address header.
555 **
556 **	If none, get one corresponding to the effective userid.
557 **
558 **	Parameters:
559 **		a -- the address to find the controller of.
560 **
561 **	Returns:
562 **		the controlling address.
563 **
564 **	Side Effects:
565 **		none.
566 */
567 
568 ADDRESS *
569 getctladdr(a)
570 	register ADDRESS *a;
571 {
572 	while (a != NULL && !bitset(QGOODUID, a->q_flags))
573 		a = a->q_alias;
574 	return (a);
575 }
576