1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)recipient.c 6.10 (Berkeley) 02/18/93"; 11 #endif /* not lint */ 12 13 # include <sys/types.h> 14 # include <sys/stat.h> 15 # include <fcntl.h> 16 # include <pwd.h> 17 # include "sendmail.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, e) 44 char *list; 45 ADDRESS *ctladdr; 46 ADDRESS **sendq; 47 register ENVELOPE *e; 48 { 49 register char *p; 50 register ADDRESS *al; /* list of addresses to send to */ 51 bool firstone; /* set on first address sent */ 52 bool selfref; /* set if this list includes ctladdr */ 53 char delimiter; /* the address delimiter */ 54 55 if (tTd(25, 1)) 56 { 57 printf("sendto: %s\n ctladdr=", list); 58 printaddr(ctladdr, FALSE); 59 } 60 61 /* heuristic to determine old versus new style addresses */ 62 if (ctladdr == NULL && 63 (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 64 strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 65 e->e_flags &= ~EF_OLDSTYLE; 66 delimiter = ' '; 67 if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 68 delimiter = ','; 69 70 firstone = TRUE; 71 selfref = FALSE; 72 al = NULL; 73 74 for (p = list; *p != '\0'; ) 75 { 76 register ADDRESS *a; 77 extern char *DelimChar; /* defined in prescan */ 78 79 /* parse the address */ 80 while ((isascii(*p) && isspace(*p)) || *p == ',') 81 p++; 82 a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter, e); 83 p = DelimChar; 84 if (a == NULL) 85 continue; 86 a->q_next = al; 87 a->q_alias = ctladdr; 88 89 /* see if this should be marked as a primary address */ 90 if (ctladdr == NULL || 91 (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 92 a->q_flags |= QPRIMARY; 93 94 if (ctladdr != NULL && sameaddr(ctladdr, a)) 95 selfref = TRUE; 96 al = a; 97 firstone = FALSE; 98 } 99 100 /* if this alias doesn't include itself, delete ctladdr */ 101 if (!selfref && ctladdr != NULL) 102 { 103 if (tTd(25, 5)) 104 { 105 printf("sendtolist: QDONTSEND "); 106 printaddr(ctladdr, FALSE); 107 } 108 ctladdr->q_flags |= QDONTSEND; 109 } 110 111 /* arrange to send to everyone on the local send list */ 112 while (al != NULL) 113 { 114 register ADDRESS *a = al; 115 extern ADDRESS *recipient(); 116 117 al = a->q_next; 118 a = recipient(a, sendq, e); 119 120 /* arrange to inherit full name */ 121 if (a->q_fullname == NULL && ctladdr != NULL) 122 a->q_fullname = ctladdr->q_fullname; 123 } 124 125 e->e_to = NULL; 126 } 127 /* 128 ** RECIPIENT -- Designate a message recipient 129 ** 130 ** Saves the named person for future mailing. 131 ** 132 ** Parameters: 133 ** a -- the (preparsed) address header for the recipient. 134 ** sendq -- a pointer to the head of a queue to put the 135 ** recipient in. Duplicate supression is done 136 ** in this queue. 137 ** e -- the current envelope. 138 ** 139 ** Returns: 140 ** The actual address in the queue. This will be "a" if 141 ** the address is not a duplicate, else the original address. 142 ** 143 ** Side Effects: 144 ** none. 145 */ 146 147 extern ADDRESS *getctladdr(); 148 extern char *RcptLogFile; 149 150 ADDRESS * 151 recipient(a, sendq, e) 152 register ADDRESS *a; 153 register ADDRESS **sendq; 154 register ENVELOPE *e; 155 { 156 register ADDRESS *q; 157 ADDRESS **pq; 158 register struct mailer *m; 159 register char *p; 160 bool quoted = FALSE; /* set if the addr has a quote bit */ 161 int findusercount = 0; 162 char buf[MAXNAME]; /* unquoted image of the user name */ 163 extern bool safefile(); 164 165 e->e_to = a->q_paddr; 166 m = a->q_mailer; 167 errno = 0; 168 if (tTd(26, 1)) 169 { 170 printf("\nrecipient: "); 171 printaddr(a, FALSE); 172 } 173 174 /* break aliasing loops */ 175 if (AliasLevel > MAXRCRSN) 176 { 177 usrerr("aliasing/forwarding loop broken"); 178 return (a); 179 } 180 181 /* 182 ** Finish setting up address structure. 183 */ 184 185 /* set the queue timeout */ 186 a->q_timeout = TimeOut; 187 188 /* map user & host to lower case if requested on non-aliases */ 189 if (a->q_alias == NULL) 190 loweraddr(a); 191 192 /* get unquoted user for file, program or user.name check */ 193 (void) strcpy(buf, a->q_user); 194 for (p = buf; *p != '\0' && !quoted; p++) 195 { 196 if (*p == '\\') 197 quoted = TRUE; 198 } 199 stripquotes(buf); 200 201 /* check for direct mailing to restricted mailers */ 202 if (a->q_alias == NULL && m == ProgMailer) 203 { 204 a->q_flags |= QDONTSEND|QBADADDR; 205 usrerr("Cannot mail directly to programs", m->m_name); 206 } 207 208 /* 209 ** Look up this person in the recipient list. 210 ** If they are there already, return, otherwise continue. 211 ** If the list is empty, just add it. Notice the cute 212 ** hack to make from addresses suppress things correctly: 213 ** the QDONTSEND bit will be set in the send list. 214 ** [Please note: the emphasis is on "hack."] 215 */ 216 217 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 218 { 219 if (!ForceMail && sameaddr(q, a)) 220 { 221 if (tTd(26, 1)) 222 { 223 printf("%s in sendq: ", a->q_paddr); 224 printaddr(q, FALSE); 225 } 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 238 if (a->q_alias == NULL && RcptLogFile != NULL && 239 !bitset(QDONTSEND, a->q_flags)) 240 { 241 static int RcptLogFd = -1; 242 243 /* 244 ** Log the incoming recipient name before aliasing, 245 ** expanding, forwarding, rewriting, and all that jazz. 246 ** We'll use this to track down out-of-date aliases, 247 ** host names, and so forth. 248 */ 249 250 if (RcptLogFd < 0) 251 { 252 /* try to open the log file */ 253 RcptLogFd = open(RcptLogFile, O_WRONLY|O_APPEND|O_CREAT, 0666); 254 if (RcptLogFd >= 0) 255 (void) fcntl(RcptLogFd, F_SETFD, 1); 256 } 257 if (RcptLogFd >= 0) 258 { 259 int l = strlen(a->q_paddr); 260 261 a->q_paddr[l] = '\n'; 262 if (write(RcptLogFd, a->q_paddr, l + 1) < 0) 263 { 264 (void) close(RcptLogFd); 265 RcptLogFd = -1; 266 } 267 a->q_paddr[l] = '\0'; 268 } 269 } 270 271 /* 272 ** Alias the name and handle special mailer types. 273 */ 274 275 trylocaluser: 276 if (tTd(29, 7)) 277 printf("at trylocaluser %s\n", a->q_user); 278 279 if (bitset(QDONTSEND, a->q_flags)) 280 return (a); 281 282 if (m == InclMailer) 283 { 284 a->q_flags |= QDONTSEND; 285 if (a->q_alias == NULL) 286 { 287 a->q_flags |= QBADADDR; 288 usrerr("Cannot mail directly to :include:s"); 289 } 290 else 291 { 292 message(Arpa_Info, "including file %s", a->q_user); 293 (void) include(a->q_user, FALSE, a, sendq, e); 294 } 295 } 296 else if (m == FileMailer) 297 { 298 struct stat stb; 299 extern bool writable(); 300 301 p = strrchr(buf, '/'); 302 /* check if writable or creatable */ 303 if (a->q_alias == NULL && !QueueRun) 304 { 305 a->q_flags |= QDONTSEND|QBADADDR; 306 usrerr("Cannot mail directly to files"); 307 } 308 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 309 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 310 { 311 a->q_flags |= QBADADDR; 312 giveresponse(EX_CANTCREAT, m, e); 313 } 314 } 315 316 if (m != LocalMailer) 317 { 318 if (!bitset(QDONTSEND, a->q_flags)) 319 e->e_nrcpts++; 320 return (a); 321 } 322 323 /* try aliasing */ 324 alias(a, sendq, e); 325 326 # ifdef USERDB 327 /* if not aliased, look it up in the user database */ 328 if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags)) 329 { 330 extern int udbexpand(); 331 332 if (udbexpand(a, sendq, e) == EX_TEMPFAIL) 333 { 334 a->q_flags |= QQUEUEUP; 335 if (e->e_message == NULL) 336 e->e_message = newstr("Deferred: user database error"); 337 # ifdef LOG 338 if (LogLevel > 8) 339 syslog(LOG_INFO, "%s: deferred: udbexpand", 340 e->e_id); 341 # endif 342 message(Arpa_Info, "queued (user database error)"); 343 e->e_nrcpts++; 344 return (a); 345 } 346 } 347 # endif 348 349 /* if it was an alias or a UDB expansion, just return now */ 350 if (bitset(QDONTSEND, a->q_flags)) 351 return (a); 352 353 /* 354 ** If we have a level two config file, then pass the name through 355 ** Ruleset 5 before sending it off. Ruleset 5 has the right 356 ** to send rewrite it to another mailer. This gives us a hook 357 ** after local aliasing has been done. 358 */ 359 360 if (tTd(29, 5)) 361 { 362 printf("recipient: testing local? cl=%d, rr5=%x\n\t", 363 ConfigLevel, RewriteRules[5]); 364 printaddr(a, FALSE); 365 } 366 if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 && 367 RewriteRules[5] != NULL) 368 { 369 maplocaluser(a, sendq, e); 370 } 371 372 /* 373 ** If it didn't get rewritten to another mailer, go ahead 374 ** and deliver it. 375 */ 376 377 if (!bitset(QDONTSEND, a->q_flags)) 378 { 379 auto bool fuzzy; 380 register struct passwd *pw; 381 extern struct passwd *finduser(); 382 383 /* warning -- finduser may trash buf */ 384 pw = finduser(buf, &fuzzy); 385 if (pw == NULL) 386 { 387 a->q_flags |= QBADADDR; 388 giveresponse(EX_NOUSER, m, e); 389 } 390 else 391 { 392 char nbuf[MAXNAME]; 393 394 if (fuzzy) 395 { 396 /* name was a fuzzy match */ 397 a->q_user = newstr(pw->pw_name); 398 if (findusercount++ > 3) 399 { 400 usrerr("aliasing/forwarding loop for %s broken", 401 pw->pw_name); 402 return (a); 403 } 404 405 /* see if it aliases */ 406 (void) strcpy(buf, pw->pw_name); 407 goto trylocaluser; 408 } 409 a->q_home = newstr(pw->pw_dir); 410 a->q_uid = pw->pw_uid; 411 a->q_gid = pw->pw_gid; 412 a->q_flags |= QGOODUID; 413 buildfname(pw->pw_gecos, pw->pw_name, nbuf); 414 if (nbuf[0] != '\0') 415 a->q_fullname = newstr(nbuf); 416 if (!quoted) 417 forward(a, sendq, e); 418 } 419 } 420 if (!bitset(QDONTSEND, a->q_flags)) 421 e->e_nrcpts++; 422 return (a); 423 } 424 /* 425 ** FINDUSER -- find the password entry for a user. 426 ** 427 ** This looks a lot like getpwnam, except that it may want to 428 ** do some fancier pattern matching in /etc/passwd. 429 ** 430 ** This routine contains most of the time of many sendmail runs. 431 ** It deserves to be optimized. 432 ** 433 ** Parameters: 434 ** name -- the name to match against. 435 ** fuzzyp -- an outarg that is set to TRUE if this entry 436 ** was found using the fuzzy matching algorithm; 437 ** set to FALSE otherwise. 438 ** 439 ** Returns: 440 ** A pointer to a pw struct. 441 ** NULL if name is unknown or ambiguous. 442 ** 443 ** Side Effects: 444 ** may modify name. 445 */ 446 447 struct passwd * 448 finduser(name, fuzzyp) 449 char *name; 450 bool *fuzzyp; 451 { 452 register struct passwd *pw; 453 register char *p; 454 extern struct passwd *getpwent(); 455 extern struct passwd *getpwnam(); 456 457 if (tTd(29, 4)) 458 printf("finduser(%s): ", name); 459 460 /* map upper => lower case */ 461 for (p = name; *p != '\0'; p++) 462 { 463 if (isascii(*p) && isupper(*p)) 464 *p = tolower(*p); 465 } 466 *fuzzyp = FALSE; 467 468 /* look up this login name using fast path */ 469 if ((pw = getpwnam(name)) != NULL) 470 { 471 if (tTd(29, 4)) 472 printf("found (non-fuzzy)\n"); 473 return (pw); 474 } 475 476 #ifdef MATCHGECOS 477 /* see if fuzzy matching allowed */ 478 if (!MatchGecos) 479 { 480 if (tTd(29, 4)) 481 printf("not found (fuzzy disabled)\n"); 482 return NULL; 483 } 484 485 /* search for a matching full name instead */ 486 for (p = name; *p != '\0'; p++) 487 { 488 if (*p == (SpaceSub & 0177) || *p == '_') 489 *p = ' '; 490 } 491 (void) setpwent(); 492 while ((pw = getpwent()) != NULL) 493 { 494 char buf[MAXNAME]; 495 496 buildfname(pw->pw_gecos, pw->pw_name, buf); 497 if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 498 { 499 if (tTd(29, 4)) 500 printf("fuzzy matches %s\n", pw->pw_name); 501 message(Arpa_Info, "sending to login name %s", pw->pw_name); 502 *fuzzyp = TRUE; 503 return (pw); 504 } 505 } 506 #endif 507 if (tTd(29, 4)) 508 printf("no fuzzy match found\n"); 509 return (NULL); 510 } 511 /* 512 ** WRITABLE -- predicate returning if the file is writable. 513 ** 514 ** This routine must duplicate the algorithm in sys/fio.c. 515 ** Unfortunately, we cannot use the access call since we 516 ** won't necessarily be the real uid when we try to 517 ** actually open the file. 518 ** 519 ** Notice that ANY file with ANY execute bit is automatically 520 ** not writable. This is also enforced by mailfile. 521 ** 522 ** Parameters: 523 ** s -- pointer to a stat struct for the file. 524 ** 525 ** Returns: 526 ** TRUE -- if we will be able to write this file. 527 ** FALSE -- if we cannot write this file. 528 ** 529 ** Side Effects: 530 ** none. 531 */ 532 533 bool 534 writable(s) 535 register struct stat *s; 536 { 537 uid_t euid; 538 gid_t egid; 539 int bits; 540 541 if (bitset(0111, s->st_mode)) 542 return (FALSE); 543 euid = getruid(); 544 egid = getrgid(); 545 if (geteuid() == 0) 546 { 547 if (bitset(S_ISUID, s->st_mode)) 548 euid = s->st_uid; 549 if (bitset(S_ISGID, s->st_mode)) 550 egid = s->st_gid; 551 } 552 553 if (euid == 0) 554 return (TRUE); 555 bits = S_IWRITE; 556 if (euid != s->st_uid) 557 { 558 bits >>= 3; 559 if (egid != s->st_gid) 560 bits >>= 3; 561 } 562 return ((s->st_mode & bits) != 0); 563 } 564 /* 565 ** INCLUDE -- handle :include: specification. 566 ** 567 ** Parameters: 568 ** fname -- filename to include. 569 ** forwarding -- if TRUE, we are reading a .forward file. 570 ** if FALSE, it's a :include: file. 571 ** ctladdr -- address template to use to fill in these 572 ** addresses -- effective user/group id are 573 ** the important things. 574 ** sendq -- a pointer to the head of the send queue 575 ** to put these addresses in. 576 ** 577 ** Returns: 578 ** open error status 579 ** 580 ** Side Effects: 581 ** reads the :include: file and sends to everyone 582 ** listed in that file. 583 */ 584 585 static jmp_buf CtxIncludeTimeout; 586 587 int 588 include(fname, forwarding, ctladdr, sendq, e) 589 char *fname; 590 bool forwarding; 591 ADDRESS *ctladdr; 592 ADDRESS **sendq; 593 ENVELOPE *e; 594 { 595 register FILE *fp; 596 char *oldto = e->e_to; 597 char *oldfilename = FileName; 598 int oldlinenumber = LineNumber; 599 register EVENT *ev = NULL; 600 char buf[MAXLINE]; 601 static int includetimeout(); 602 603 if (tTd(27, 2)) 604 printf("include(%s)\n", fname); 605 606 /* 607 ** If home directory is remote mounted but server is down, 608 ** this can hang or give errors; use a timeout to avoid this 609 */ 610 611 if (setjmp(CtxIncludeTimeout) != 0) 612 { 613 ctladdr->q_flags |= QQUEUEUP|QDONTSEND; 614 errno = 0; 615 usrerr("451 open timeout on %s", fname); 616 return ETIMEDOUT; 617 } 618 ev = setevent((time_t) 60, includetimeout, 0); 619 620 /* if forwarding, the input file must be marked safe */ 621 if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD)) 622 { 623 /* don't use this .forward file */ 624 clrevent(ev); 625 if (tTd(27, 4)) 626 printf("include: not safe (uid=%d)\n", ctladdr->q_uid); 627 return EPERM; 628 } 629 630 fp = fopen(fname, "r"); 631 if (fp == NULL) 632 { 633 int ret = errno; 634 635 usrerr("Cannot open %s", fname); 636 return ret; 637 } 638 639 if (getctladdr(ctladdr) == NULL) 640 { 641 struct stat st; 642 643 if (fstat(fileno(fp), &st) < 0) 644 syserr("Cannot fstat %s!", fname); 645 ctladdr->q_uid = st.st_uid; 646 ctladdr->q_gid = st.st_gid; 647 ctladdr->q_flags |= QGOODUID; 648 } 649 650 clrevent(ev); 651 652 /* read the file -- each line is a comma-separated list. */ 653 FileName = fname; 654 LineNumber = 0; 655 while (fgets(buf, sizeof buf, fp) != NULL) 656 { 657 register char *p = strchr(buf, '\n'); 658 659 LineNumber++; 660 if (p != NULL) 661 *p = '\0'; 662 if (buf[0] == '#' || buf[0] == '\0') 663 continue; 664 e->e_to = NULL; 665 message(Arpa_Info, "%s to %s", 666 forwarding ? "forwarding" : "sending", buf); 667 #ifdef LOG 668 if (forwarding && LogLevel > 9) 669 syslog(LOG_INFO, "%s: forward %s => %s", 670 e->e_id, oldto, buf); 671 #endif 672 673 AliasLevel++; 674 sendtolist(buf, ctladdr, sendq, e); 675 AliasLevel--; 676 } 677 678 (void) fclose(fp); 679 FileName = oldfilename; 680 LineNumber = oldlinenumber; 681 return 0; 682 } 683 684 static 685 includetimeout() 686 { 687 longjmp(CtxIncludeTimeout, 1); 688 } 689 /* 690 ** SENDTOARGV -- send to an argument vector. 691 ** 692 ** Parameters: 693 ** argv -- argument vector to send to. 694 ** 695 ** Returns: 696 ** none. 697 ** 698 ** Side Effects: 699 ** puts all addresses on the argument vector onto the 700 ** send queue. 701 */ 702 703 sendtoargv(argv, e) 704 register char **argv; 705 register ENVELOPE *e; 706 { 707 register char *p; 708 709 while ((p = *argv++) != NULL) 710 { 711 if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at")) 712 { 713 char nbuf[MAXNAME]; 714 715 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 716 usrerr("address overflow"); 717 else 718 { 719 (void) strcpy(nbuf, p); 720 (void) strcat(nbuf, "@"); 721 (void) strcat(nbuf, argv[1]); 722 p = newstr(nbuf); 723 argv += 2; 724 } 725 } 726 sendtolist(p, (ADDRESS *) NULL, &e->e_sendqueue, e); 727 } 728 } 729 /* 730 ** GETCTLADDR -- get controlling address from an address header. 731 ** 732 ** If none, get one corresponding to the effective userid. 733 ** 734 ** Parameters: 735 ** a -- the address to find the controller of. 736 ** 737 ** Returns: 738 ** the controlling address. 739 ** 740 ** Side Effects: 741 ** none. 742 */ 743 744 ADDRESS * 745 getctladdr(a) 746 register ADDRESS *a; 747 { 748 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 749 a = a->q_alias; 750 return (a); 751 } 752