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 5.37 (Berkeley) 11/14/92"; 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 /* do sickly crude mapping for program mailing, etc. */ 196 if (m == LocalMailer && buf[0] == '|') 197 { 198 a->q_mailer = m = ProgMailer; 199 a->q_user++; 200 if (a->q_alias == NULL && !ForceMail) 201 { 202 a->q_flags |= QDONTSEND|QBADADDR; 203 usrerr("Cannot mail directly to programs"); 204 } 205 } 206 207 /* 208 ** Look up this person in the recipient list. 209 ** If they are there already, return, otherwise continue. 210 ** If the list is empty, just add it. Notice the cute 211 ** hack to make from addresses suppress things correctly: 212 ** the QDONTSEND bit will be set in the send list. 213 ** [Please note: the emphasis is on "hack."] 214 */ 215 216 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 217 { 218 if (!ForceMail && sameaddr(q, a)) 219 { 220 if (tTd(26, 1)) 221 { 222 printf("%s in sendq: ", a->q_paddr); 223 printaddr(q, FALSE); 224 } 225 if (!bitset(QDONTSEND, a->q_flags)) 226 message(Arpa_Info, "duplicate suppressed"); 227 if (!bitset(QPRIMARY, q->q_flags)) 228 q->q_flags |= a->q_flags; 229 return (q); 230 } 231 } 232 233 /* add address on list */ 234 *pq = a; 235 a->q_next = NULL; 236 e->e_nrcpts++; 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 :include: specs. 273 */ 274 275 trylocaluser: 276 if (tTd(29, 7)) 277 printf("at trylocaluser %s\n", a->q_user); 278 279 if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags)) 280 { 281 if (strncmp(a->q_user, ":include:", 9) == 0) 282 { 283 a->q_flags |= QDONTSEND; 284 if (a->q_alias == NULL && !ForceMail) 285 { 286 a->q_flags |= QBADADDR; 287 usrerr("Cannot mail directly to :include:s"); 288 } 289 else 290 { 291 message(Arpa_Info, "including file %s", &a->q_user[9]); 292 include(&a->q_user[9], FALSE, a, sendq, e); 293 } 294 } 295 else 296 { 297 /* try aliasing */ 298 alias(a, sendq, e); 299 300 # ifdef USERDB 301 /* if not aliased, look it up in the user database */ 302 if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags)) 303 { 304 extern int udbexpand(); 305 306 if (udbexpand(a, sendq, e) == EX_TEMPFAIL) 307 { 308 a->q_flags |= QQUEUEUP; 309 if (e->e_message == NULL) 310 e->e_message = newstr("Deferred: user database error"); 311 # ifdef LOG 312 if (LogLevel > 3) 313 syslog(LOG_INFO, "%s: deferred: udbexpand", 314 e->e_id); 315 # endif 316 message(Arpa_Info, "queued (user database error)"); 317 return (a); 318 } 319 } 320 # endif 321 } 322 } 323 324 /* 325 ** If the user is local and still being sent, verify that 326 ** the address is good. If it is, try to forward. 327 ** If the address is already good, we have a forwarding 328 ** loop. This can be broken by just sending directly to 329 ** the user (which is probably correct anyway). 330 */ 331 332 if (bitset(QDONTSEND, a->q_flags) || m != LocalMailer) 333 return (a); 334 335 /* see if this is to a file */ 336 if (buf[0] == '/') 337 { 338 struct stat stb; 339 extern bool writable(); 340 341 p = strrchr(buf, '/'); 342 /* check if writable or creatable */ 343 if (a->q_alias == NULL && !QueueRun && !ForceMail) 344 { 345 a->q_flags |= QDONTSEND|QBADADDR; 346 usrerr("Cannot mail directly to files"); 347 } 348 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 349 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 350 { 351 a->q_flags |= QBADADDR; 352 giveresponse(EX_CANTCREAT, m, e); 353 } 354 return (a); 355 } 356 357 /* 358 ** If we have a level two config file, then pass the name through 359 ** Ruleset 5 before sending it off. Ruleset 5 has the right 360 ** to send rewrite it to another mailer. This gives us a hook 361 ** after local aliasing has been done. 362 */ 363 364 if (tTd(29, 5)) 365 { 366 printf("recipient: testing local? cl=%d, rr5=%x\n\t", 367 ConfigLevel, RewriteRules[5]); 368 printaddr(a, FALSE); 369 } 370 if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 && 371 RewriteRules[5] != NULL) 372 { 373 maplocaluser(a, sendq, e); 374 } 375 376 /* 377 ** If it didn't get rewritten to another mailer, go ahead 378 ** and deliver it. 379 */ 380 381 if (!bitset(QDONTSEND, a->q_flags)) 382 { 383 auto bool fuzzy; 384 register struct passwd *pw; 385 extern struct passwd *finduser(); 386 387 /* warning -- finduser may trash buf */ 388 pw = finduser(buf, &fuzzy); 389 if (pw == NULL) 390 { 391 a->q_flags |= QBADADDR; 392 giveresponse(EX_NOUSER, m, e); 393 } 394 else 395 { 396 char nbuf[MAXNAME]; 397 398 if (fuzzy) 399 { 400 /* name was a fuzzy match */ 401 a->q_user = newstr(pw->pw_name); 402 if (findusercount++ > 3) 403 { 404 usrerr("aliasing/forwarding loop for %s broken", 405 pw->pw_name); 406 return (a); 407 } 408 409 /* see if it aliases */ 410 (void) strcpy(buf, pw->pw_name); 411 goto trylocaluser; 412 } 413 a->q_home = newstr(pw->pw_dir); 414 a->q_uid = pw->pw_uid; 415 a->q_gid = pw->pw_gid; 416 a->q_flags |= QGOODUID; 417 buildfname(pw->pw_gecos, pw->pw_name, nbuf); 418 if (nbuf[0] != '\0') 419 a->q_fullname = newstr(nbuf); 420 if (!quoted) 421 forward(a, sendq, e); 422 } 423 } 424 return (a); 425 } 426 /* 427 ** FINDUSER -- find the password entry for a user. 428 ** 429 ** This looks a lot like getpwnam, except that it may want to 430 ** do some fancier pattern matching in /etc/passwd. 431 ** 432 ** This routine contains most of the time of many sendmail runs. 433 ** It deserves to be optimized. 434 ** 435 ** Parameters: 436 ** name -- the name to match against. 437 ** fuzzyp -- an outarg that is set to TRUE if this entry 438 ** was found using the fuzzy matching algorithm; 439 ** set to FALSE otherwise. 440 ** 441 ** Returns: 442 ** A pointer to a pw struct. 443 ** NULL if name is unknown or ambiguous. 444 ** 445 ** Side Effects: 446 ** may modify name. 447 */ 448 449 struct passwd * 450 finduser(name, fuzzyp) 451 char *name; 452 bool *fuzzyp; 453 { 454 register struct passwd *pw; 455 register char *p; 456 extern struct passwd *getpwent(); 457 extern struct passwd *getpwnam(); 458 459 if (tTd(29, 4)) 460 printf("finduser(%s): ", name); 461 462 /* map upper => lower case */ 463 for (p = name; *p != '\0'; p++) 464 { 465 if (isascii(*p) && isupper(*p)) 466 *p = tolower(*p); 467 } 468 *fuzzyp = FALSE; 469 470 /* look up this login name using fast path */ 471 if ((pw = getpwnam(name)) != NULL) 472 { 473 if (tTd(29, 4)) 474 printf("found (non-fuzzy)\n"); 475 return (pw); 476 } 477 478 #ifdef MATCHGECOS 479 /* see if fuzzy matching allowed */ 480 if (!MatchGecos) 481 { 482 if (tTd(29, 4)) 483 printf("not found (fuzzy disabled)\n"); 484 return NULL; 485 } 486 487 /* search for a matching full name instead */ 488 for (p = name; *p != '\0'; p++) 489 { 490 if (*p == (SpaceSub & 0177) || *p == '_') 491 *p = ' '; 492 } 493 (void) setpwent(); 494 while ((pw = getpwent()) != NULL) 495 { 496 char buf[MAXNAME]; 497 498 buildfname(pw->pw_gecos, pw->pw_name, buf); 499 if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 500 { 501 if (tTd(29, 4)) 502 printf("fuzzy matches %s\n", pw->pw_name); 503 message(Arpa_Info, "sending to login name %s", pw->pw_name); 504 *fuzzyp = TRUE; 505 return (pw); 506 } 507 } 508 #endif 509 if (tTd(29, 4)) 510 printf("no fuzzy match found\n"); 511 return (NULL); 512 } 513 /* 514 ** WRITABLE -- predicate returning if the file is writable. 515 ** 516 ** This routine must duplicate the algorithm in sys/fio.c. 517 ** Unfortunately, we cannot use the access call since we 518 ** won't necessarily be the real uid when we try to 519 ** actually open the file. 520 ** 521 ** Notice that ANY file with ANY execute bit is automatically 522 ** not writable. This is also enforced by mailfile. 523 ** 524 ** Parameters: 525 ** s -- pointer to a stat struct for the file. 526 ** 527 ** Returns: 528 ** TRUE -- if we will be able to write this file. 529 ** FALSE -- if we cannot write this file. 530 ** 531 ** Side Effects: 532 ** none. 533 */ 534 535 bool 536 writable(s) 537 register struct stat *s; 538 { 539 uid_t euid; 540 gid_t egid; 541 int bits; 542 543 if (bitset(0111, s->st_mode)) 544 return (FALSE); 545 euid = getruid(); 546 egid = getrgid(); 547 if (geteuid() == 0) 548 { 549 if (bitset(S_ISUID, s->st_mode)) 550 euid = s->st_uid; 551 if (bitset(S_ISGID, s->st_mode)) 552 egid = s->st_gid; 553 } 554 555 if (euid == 0) 556 return (TRUE); 557 bits = S_IWRITE; 558 if (euid != s->st_uid) 559 { 560 bits >>= 3; 561 if (egid != s->st_gid) 562 bits >>= 3; 563 } 564 return ((s->st_mode & bits) != 0); 565 } 566 /* 567 ** INCLUDE -- handle :include: specification. 568 ** 569 ** Parameters: 570 ** fname -- filename to include. 571 ** forwarding -- if TRUE, we are reading a .forward file. 572 ** if FALSE, it's a :include: file. 573 ** ctladdr -- address template to use to fill in these 574 ** addresses -- effective user/group id are 575 ** the important things. 576 ** sendq -- a pointer to the head of the send queue 577 ** to put these addresses in. 578 ** 579 ** Returns: 580 ** none. 581 ** 582 ** Side Effects: 583 ** reads the :include: file and sends to everyone 584 ** listed in that file. 585 */ 586 587 static jmp_buf CtxIncludeTimeout; 588 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 /* 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; 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 return; 624 } 625 626 fp = fopen(fname, "r"); 627 if (fp == NULL) 628 { 629 usrerr("Cannot open %s", fname); 630 return; 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 e->e_to = oldto; 657 message(Arpa_Info, "%s to %s", 658 forwarding ? "forwarding" : "sending", buf); 659 AliasLevel++; 660 sendtolist(buf, ctladdr, sendq, e); 661 AliasLevel--; 662 } 663 664 (void) fclose(fp); 665 FileName = oldfilename; 666 LineNumber = oldlinenumber; 667 } 668 669 static 670 includetimeout() 671 { 672 longjmp(CtxIncludeTimeout, 1); 673 } 674 /* 675 ** SENDTOARGV -- send to an argument vector. 676 ** 677 ** Parameters: 678 ** argv -- argument vector to send to. 679 ** 680 ** Returns: 681 ** none. 682 ** 683 ** Side Effects: 684 ** puts all addresses on the argument vector onto the 685 ** send queue. 686 */ 687 688 sendtoargv(argv, e) 689 register char **argv; 690 register ENVELOPE *e; 691 { 692 register char *p; 693 694 while ((p = *argv++) != NULL) 695 { 696 if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at")) 697 { 698 char nbuf[MAXNAME]; 699 700 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 701 usrerr("address overflow"); 702 else 703 { 704 (void) strcpy(nbuf, p); 705 (void) strcat(nbuf, "@"); 706 (void) strcat(nbuf, argv[1]); 707 p = newstr(nbuf); 708 argv += 2; 709 } 710 } 711 sendtolist(p, (ADDRESS *) NULL, &e->e_sendqueue, e); 712 } 713 } 714 /* 715 ** GETCTLADDR -- get controlling address from an address header. 716 ** 717 ** If none, get one corresponding to the effective userid. 718 ** 719 ** Parameters: 720 ** a -- the address to find the controller of. 721 ** 722 ** Returns: 723 ** the controlling address. 724 ** 725 ** Side Effects: 726 ** none. 727 */ 728 729 ADDRESS * 730 getctladdr(a) 731 register ADDRESS *a; 732 { 733 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 734 a = a->q_alias; 735 return (a); 736 } 737