|
|
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.