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