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