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