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