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