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