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