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