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: }