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