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