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