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