1 # include <stdio.h> 2 # include <pwd.h> 3 # include <signal.h> 4 # include <ctype.h> 5 # include <errno.h> 6 # include "sendmail.h" 7 # ifdef LOG 8 # include <syslog.h> 9 # endif LOG 10 11 static char SccsId[] = "@(#)deliver.c 3.21 08/18/81"; 12 13 /* 14 ** DELIVER -- Deliver a message to a particular address. 15 ** 16 ** Parameters: 17 ** to -- the address to deliver the message to. 18 ** editfcn -- if non-NULL, we want to call this function 19 ** to output the letter (instead of just out- 20 ** putting it raw). 21 ** 22 ** Returns: 23 ** zero -- successfully delivered. 24 ** else -- some failure, see ExitStat for more info. 25 ** 26 ** Side Effects: 27 ** The standard input is passed off to someone. 28 */ 29 30 deliver(to, editfcn) 31 ADDRESS *to; 32 int (*editfcn)(); 33 { 34 char *host; 35 char *user; 36 char **pvp; 37 register char **mvp; 38 register char *p; 39 register struct mailer *m; 40 register int i; 41 extern putmessage(); 42 extern bool checkcompat(); 43 char *pv[MAXPV+1]; 44 char tobuf[MAXLINE]; 45 char buf[MAXNAME]; 46 bool firstone; 47 48 if (bitset(QDONTSEND, to->q_flags)) 49 return (0); 50 51 # ifdef DEBUG 52 if (Debug) 53 printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 54 to->q_mailer, to->q_host, to->q_user); 55 # endif DEBUG 56 57 /* 58 ** Do initial argv setup. 59 ** Insert the mailer name. Notice that $x expansion is 60 ** NOT done on the mailer name. Then, if the mailer has 61 ** a picky -f flag, we insert it as appropriate. This 62 ** code does not check for 'pv' overflow; this places a 63 ** manifest lower limit of 4 for MAXPV. 64 */ 65 66 m = Mailer[to->q_mailer]; 67 host = to->q_host; 68 define('g', m->m_from); /* translated from address */ 69 define('h', host); /* to host */ 70 Errors = 0; 71 errno = 0; 72 pvp = pv; 73 *pvp++ = m->m_argv[0]; 74 75 /* insert -f or -r flag as appropriate */ 76 if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 77 { 78 if (bitset(M_FOPT, m->m_flags)) 79 *pvp++ = "-f"; 80 else 81 *pvp++ = "-r"; 82 (void) expand("$g", buf, &buf[sizeof buf - 1]); 83 *pvp++ = newstr(buf); 84 } 85 86 /* 87 ** Append the other fixed parts of the argv. These run 88 ** up to the first entry containing "$u". There can only 89 ** be one of these, and there are only a few more slots 90 ** in the pv after it. 91 */ 92 93 for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 94 { 95 while ((p = index(p, '$')) != NULL) 96 if (*++p == 'u') 97 break; 98 if (p != NULL) 99 break; 100 101 /* this entry is safe -- go ahead and process it */ 102 (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 103 *pvp++ = newstr(buf); 104 if (pvp >= &pv[MAXPV - 3]) 105 { 106 syserr("Too many parameters to %s before $u", pv[0]); 107 return (-1); 108 } 109 } 110 if (*mvp == NULL) 111 syserr("No $u in mailer argv for %s", pv[0]); 112 113 /* 114 ** At this point *mvp points to the argument with $u. We 115 ** run through our address list and append all the addresses 116 ** we can. If we run out of space, do not fret! We can 117 ** always send another copy later. 118 */ 119 120 tobuf[0] = '\0'; 121 firstone = TRUE; 122 To = tobuf; 123 for (; to != NULL; to = to->q_next) 124 { 125 /* avoid sending multiple recipients to dumb mailers */ 126 if (!firstone && !bitset(M_MUSER, m->m_flags)) 127 break; 128 129 /* if already sent or not for this host, don't send */ 130 if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0) 131 continue; 132 user = to->q_user; 133 To = to->q_paddr; 134 to->q_flags |= QDONTSEND; 135 firstone = FALSE; 136 137 # ifdef DEBUG 138 if (Debug) 139 printf(" send to `%s'\n", user); 140 # endif DEBUG 141 142 /* 143 ** Check to see that these people are allowed to 144 ** talk to each other. 145 */ 146 147 if (!checkcompat(to)) 148 { 149 giveresponse(EX_UNAVAILABLE, TRUE, m); 150 continue; 151 } 152 153 /* 154 ** Strip quote bits from names if the mailer is dumb 155 ** about them. 156 */ 157 158 if (bitset(M_STRIPQ, m->m_flags)) 159 { 160 stripquotes(user, TRUE); 161 stripquotes(host, TRUE); 162 } 163 else 164 { 165 stripquotes(user, FALSE); 166 stripquotes(host, FALSE); 167 } 168 169 /* 170 ** See if this user name is "special". 171 ** If the user name has a slash in it, assume that this 172 ** is a file -- send it off without further ado. 173 ** Note that this means that editfcn's will not 174 ** be applied to the message. Also note that 175 ** this type of addresses is not processed along 176 ** with the others, so we fudge on the To person. 177 */ 178 179 if (m == Mailer[M_LOCAL]) 180 { 181 if (index(user, '/') != NULL) 182 { 183 i = mailfile(user); 184 giveresponse(i, TRUE, m); 185 continue; 186 } 187 } 188 189 /* 190 ** See if the user exists. 191 ** Strictly, this is only needed to print a pretty 192 ** error message. 193 ** 194 ** >>>>>>>>>> This clause assumes that the local mailer 195 ** >> NOTE >> cannot do any further aliasing; that 196 ** >>>>>>>>>> function is subsumed by sendmail. 197 */ 198 199 if (bitset(QBADADDR, to->q_flags)) 200 { 201 giveresponse(EX_NOUSER, TRUE, m); 202 continue; 203 } 204 205 /* create list of users for error messages */ 206 if (tobuf[0] != '\0') 207 (void) strcat(tobuf, ","); 208 (void) strcat(tobuf, to->q_paddr); 209 define('u', user); /* to user */ 210 define('z', to->q_home); /* user's home */ 211 212 /* expand out this user */ 213 (void) expand(user, buf, &buf[sizeof buf - 1]); 214 *pvp++ = newstr(buf); 215 if (pvp >= &pv[MAXPV - 2]) 216 { 217 /* allow some space for trailing parms */ 218 break; 219 } 220 } 221 222 /* see if any addresses still exist */ 223 if (tobuf[0] == '\0') 224 return (0); 225 226 /* print out messages as full list */ 227 To = tobuf; 228 229 /* 230 ** Fill out any parameters after the $u parameter. 231 */ 232 233 while (*++mvp != NULL) 234 { 235 (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 236 *pvp++ = newstr(buf); 237 if (pvp >= &pv[MAXPV]) 238 syserr("deliver: pv overflow after $u for %s", pv[0]); 239 } 240 *pvp++ = NULL; 241 242 /* 243 ** Call the mailer. 244 ** The argument vector gets built, pipes 245 ** are created as necessary, and we fork & exec as 246 ** appropriate. 247 ** 248 ** Notice the tacky hack to handle private mailers. 249 */ 250 251 if (editfcn == NULL) 252 editfcn = putmessage; 253 i = sendoff(m, pv, editfcn); 254 255 return (i); 256 } 257 /* 258 ** SENDOFF -- send off call to mailer & collect response. 259 ** 260 ** Parameters: 261 ** m -- mailer descriptor. 262 ** pvp -- parameter vector to send to it. 263 ** editfcn -- function to pipe it through. 264 ** 265 ** Returns: 266 ** exit status of mailer. 267 ** 268 ** Side Effects: 269 ** none. 270 */ 271 272 #define NFORKTRIES 5 273 274 sendoff(m, pvp, editfcn) 275 struct mailer *m; 276 char **pvp; 277 int (*editfcn)(); 278 { 279 auto int st; 280 register int i; 281 int pid; 282 int pvect[2]; 283 FILE *mfile; 284 extern putmessage(); 285 extern FILE *fdopen(); 286 287 # ifdef DEBUG 288 if (Debug) 289 { 290 printf("Sendoff:\n"); 291 printav(pvp); 292 } 293 # endif DEBUG 294 295 /* create a pipe to shove the mail through */ 296 if (pipe(pvect) < 0) 297 { 298 syserr("pipe"); 299 return (-1); 300 } 301 for (i = NFORKTRIES; i-- > 0; ) 302 { 303 # ifdef VFORK 304 pid = vfork(); 305 # else 306 pid = fork(); 307 # endif 308 if (pid >= 0) 309 break; 310 sleep((unsigned) NFORKTRIES - i); 311 } 312 if (pid < 0) 313 { 314 syserr("Cannot fork"); 315 (void) close(pvect[0]); 316 (void) close(pvect[1]); 317 return (-1); 318 } 319 else if (pid == 0) 320 { 321 /* child -- set up input & exec mailer */ 322 /* make diagnostic output be standard output */ 323 (void) close(2); 324 (void) dup(1); 325 (void) signal(SIGINT, SIG_IGN); 326 (void) close(0); 327 if (dup(pvect[0]) < 0) 328 { 329 syserr("Cannot dup to zero!"); 330 _exit(EX_OSERR); 331 } 332 (void) close(pvect[0]); 333 (void) close(pvect[1]); 334 if (!bitset(M_RESTR, m->m_flags)) 335 (void) setuid(getuid()); 336 # ifndef VFORK 337 /* 338 ** We have to be careful with vfork - we can't mung up the 339 ** memory but we don't want the mailer to inherit any extra 340 ** open files. Chances are the mailer won't 341 ** care about an extra file, but then again you never know. 342 ** Actually, we would like to close(fileno(pwf)), but it's 343 ** declared static so we can't. But if we fclose(pwf), which 344 ** is what endpwent does, it closes it in the parent too and 345 ** the next getpwnam will be slower. If you have a weird 346 ** mailer that chokes on the extra file you should do the 347 ** endpwent(). 348 ** 349 ** Similar comments apply to log. However, openlog is 350 ** clever enough to set the FIOCLEX mode on the file, 351 ** so it will be closed automatically on the exec. 352 */ 353 354 endpwent(); 355 # ifdef LOG 356 closelog(); 357 # endif LOG 358 # endif VFORK 359 execv(m->m_mailer, pvp); 360 /* syserr fails because log is closed */ 361 /* syserr("Cannot exec %s", m->m_mailer); */ 362 printf("Cannot exec %s\n", m->m_mailer); 363 (void) fflush(stdout); 364 _exit(EX_UNAVAILABLE); 365 } 366 367 /* write out message to mailer */ 368 (void) close(pvect[0]); 369 (void) signal(SIGPIPE, SIG_IGN); 370 mfile = fdopen(pvect[1], "w"); 371 if (editfcn == NULL) 372 editfcn = putmessage; 373 (*editfcn)(mfile, m); 374 (void) fclose(mfile); 375 376 /* 377 ** Wait for child to die and report status. 378 ** We should never get fatal errors (e.g., segmentation 379 ** violation), so we report those specially. For other 380 ** errors, we choose a status message (into statmsg), 381 ** and if it represents an error, we print it. 382 */ 383 384 while ((i = wait(&st)) > 0 && i != pid) 385 continue; 386 if (i < 0) 387 { 388 syserr("wait"); 389 return (-1); 390 } 391 if ((st & 0377) != 0) 392 { 393 syserr("%s: stat %o", pvp[0], st); 394 ExitStat = EX_UNAVAILABLE; 395 return (-1); 396 } 397 i = (st >> 8) & 0377; 398 giveresponse(i, TRUE, m); 399 return (i); 400 } 401 /* 402 ** GIVERESPONSE -- Interpret an error response from a mailer 403 ** 404 ** Parameters: 405 ** stat -- the status code from the mailer (high byte 406 ** only; core dumps must have been taken care of 407 ** already). 408 ** force -- if set, force an error message output, even 409 ** if the mailer seems to like to print its own 410 ** messages. 411 ** m -- the mailer descriptor for this mailer. 412 ** 413 ** Returns: 414 ** none. 415 ** 416 ** Side Effects: 417 ** Errors may be incremented. 418 ** ExitStat may be set. 419 ** 420 ** Called By: 421 ** deliver 422 */ 423 424 giveresponse(stat, force, m) 425 int stat; 426 int force; 427 register struct mailer *m; 428 { 429 register char *statmsg; 430 extern char *SysExMsg[]; 431 register int i; 432 extern int N_SysEx; 433 extern long MsgSize; 434 char buf[30]; 435 436 i = stat - EX__BASE; 437 if (i < 0 || i > N_SysEx) 438 statmsg = NULL; 439 else 440 statmsg = SysExMsg[i]; 441 if (stat == 0) 442 { 443 statmsg = "ok"; 444 if (Verbose) 445 message("050", "ok"); 446 } 447 else 448 { 449 Errors++; 450 if (statmsg == NULL && m->m_badstat != 0) 451 { 452 stat = m->m_badstat; 453 i = stat - EX__BASE; 454 # ifdef DEBUG 455 if (i < 0 || i >= N_SysEx) 456 syserr("Bad m_badstat %d", stat); 457 else 458 # endif DEBUG 459 statmsg = SysExMsg[i]; 460 } 461 if (statmsg == NULL) 462 usrerr("unknown mailer response %d", stat); 463 else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 464 usrerr("%s", statmsg); 465 } 466 467 /* 468 ** Final cleanup. 469 ** Log a record of the transaction. Compute the new 470 ** ExitStat -- if we already had an error, stick with 471 ** that. 472 */ 473 474 if (statmsg == NULL) 475 { 476 (void) sprintf(buf, "error %d", stat); 477 statmsg = buf; 478 } 479 480 # ifdef LOG 481 syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 482 # endif LOG 483 setstat(stat); 484 } 485 /* 486 ** PUTMESSAGE -- output a message to the final mailer. 487 ** 488 ** This routine takes care of recreating the header from the 489 ** in-core copy, etc. 490 ** 491 ** Parameters: 492 ** fp -- file to output onto. 493 ** m -- a mailer descriptor. 494 ** 495 ** Returns: 496 ** none. 497 ** 498 ** Side Effects: 499 ** The message is written onto fp. 500 */ 501 502 putmessage(fp, m) 503 FILE *fp; 504 struct mailer *m; 505 { 506 char buf[BUFSIZ]; 507 register int i; 508 HDR *h; 509 register char *p; 510 extern char *arpadate(); 511 bool anyheader = FALSE; 512 extern char *capitalize(); 513 514 /* output "From" line unless supressed */ 515 if (!bitset(M_NHDR, m->m_flags)) 516 fprintf(fp, "%s\n", FromLine); 517 518 /* output all header lines */ 519 for (h = Header; h != NULL; h = h->h_link) 520 { 521 if (bitset(H_DELETE, h->h_flags)) 522 continue; 523 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 524 continue; 525 if (bitset(H_DEFAULT, h->h_flags)) 526 { 527 (void) expand(h->h_value, buf, &buf[sizeof buf]); 528 p = buf; 529 } 530 else 531 p = h->h_value; 532 if (*p == '\0') 533 continue; 534 fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 535 h->h_flags |= H_USED; 536 anyheader = TRUE; 537 } 538 539 if (anyheader) 540 fprintf(fp, "\n"); 541 542 /* output the body of the message */ 543 rewind(stdin); 544 while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, stdin)) > 0) 545 (void) fwrite(buf, 1, i, fp); 546 547 if (ferror(fp) && errno != EPIPE) 548 { 549 syserr("putmessage: write error"); 550 setstat(EX_IOERR); 551 } 552 errno = 0; 553 } 554 /* 555 ** SENDTO -- Designate a send list. 556 ** 557 ** The parameter is a comma-separated list of people to send to. 558 ** This routine arranges to send to all of them. 559 ** 560 ** Parameters: 561 ** list -- the send list. 562 ** copyf -- the copy flag; passed to parse. 563 ** 564 ** Returns: 565 ** none 566 ** 567 ** Side Effects: 568 ** none. 569 */ 570 571 # define MAXRCRSN 10 572 573 sendto(list, copyf) 574 char *list; 575 int copyf; 576 { 577 register char *p; 578 register char *q; 579 register char c; 580 ADDRESS *a; 581 bool more; 582 583 /* more keeps track of what the previous delimiter was */ 584 more = TRUE; 585 for (p = list; more; ) 586 { 587 /* find the end of this address */ 588 while (*p == ' ' || *p == '\t') 589 p++; 590 q = p; 591 while ((c = *p++) != '\0' && c != ',' && c != '\n') 592 continue; 593 more = c != '\0'; 594 *--p = '\0'; 595 if (more) 596 p++; 597 598 /* parse the address */ 599 if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 600 continue; 601 602 /* arrange to send to this person */ 603 recipient(a); 604 } 605 To = NULL; 606 } 607 /* 608 ** RECIPIENT -- Designate a message recipient 609 ** 610 ** Saves the named person for future mailing. 611 ** 612 ** Parameters: 613 ** a -- the (preparsed) address header for the recipient. 614 ** 615 ** Returns: 616 ** none. 617 ** 618 ** Side Effects: 619 ** none. 620 */ 621 622 recipient(a) 623 register ADDRESS *a; 624 { 625 register ADDRESS *q; 626 register struct mailer *m; 627 char buf[MAXNAME]; 628 629 To = a->q_paddr; 630 m = Mailer[a->q_mailer]; 631 errno = 0; 632 # ifdef DEBUG 633 if (Debug) 634 printf("recipient(%s)\n", To); 635 # endif DEBUG 636 637 /* break aliasing loops */ 638 if (AliasLevel > MAXRCRSN) 639 { 640 usrerr("aliasing/forwarding loop broken"); 641 return; 642 } 643 644 /* 645 ** Do sickly crude mapping for program mailing, etc. 646 */ 647 648 if (a->q_mailer == M_LOCAL) 649 { 650 if (a->q_user[0] == '|') 651 { 652 a->q_mailer = M_PROG; 653 m = Mailer[M_PROG]; 654 a->q_user++; 655 } 656 } 657 658 /* 659 ** Look up this person in the recipient list. If they 660 ** are there already, return, otherwise continue. 661 ** If the list is empty, just add it. 662 */ 663 664 if (m->m_sendq == NULL) 665 { 666 m->m_sendq = a; 667 } 668 else 669 { 670 ADDRESS *pq; 671 672 for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next) 673 { 674 if (!ForceMail && sameaddr(q, a, FALSE)) 675 { 676 # ifdef DEBUG 677 if (Debug) 678 printf("(%s in sendq)\n", a->q_paddr); 679 # endif DEBUG 680 if (Verbose && !bitset(QDONTSEND, a->q_flags)) 681 message("050", "duplicate supressed"); 682 return; 683 } 684 } 685 686 /* add address on list */ 687 q = pq; 688 q->q_next = a; 689 } 690 a->q_next = NULL; 691 692 /* 693 ** Alias the name and handle :include: specs. 694 */ 695 696 if (a->q_mailer == M_LOCAL) 697 { 698 if (strncmp(a->q_user, ":include:", 9) == 0) 699 { 700 a->q_flags |= QDONTSEND; 701 include(&a->q_user[9]); 702 } 703 else 704 alias(a); 705 } 706 707 /* 708 ** If the user is local and still being sent, verify that 709 ** the address is good. If it is, try to forward. 710 ** If the address is already good, we have a forwarding 711 ** loop. This can be broken by just sending directly to 712 ** the user (which is probably correct anyway). 713 */ 714 715 if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == M_LOCAL && 716 a->q_home == NULL) 717 { 718 register struct passwd *pw; 719 extern struct passwd *getpwnam(); 720 char buf[MAXNAME]; 721 722 strcpy(buf, a->q_user); 723 stripquotes(buf, TRUE); 724 pw = getpwnam(buf); 725 if (pw == NULL) 726 a->q_flags |= QBADADDR; 727 else 728 { 729 a->q_home = newstr(pw->pw_dir); 730 if (strcmp(buf, a->q_user) == 0) 731 forward(a); 732 } 733 } 734 } 735 /* 736 ** INCLUDE -- handle :include: specification. 737 ** 738 ** Parameters: 739 ** fname -- filename to include. 740 ** 741 ** Returns: 742 ** none. 743 ** 744 ** Side Effects: 745 ** reads the :include: file and sends to everyone 746 ** listed in that file. 747 */ 748 749 include(fname) 750 char *fname; 751 { 752 char buf[MAXLINE]; 753 register FILE *fp; 754 755 if (Verbose) 756 message("050", "Including file %s", fname); 757 fp = fopen(fname, "r"); 758 if (fp == NULL) 759 { 760 usrerr("Cannot open %s", fname); 761 return; 762 } 763 764 /* read the file -- each line is a comma-separated list. */ 765 while (fgets(buf, sizeof buf, fp) != NULL) 766 { 767 register char *p = index(buf, '\n'); 768 769 if (p != NULL) 770 *p = '\0'; 771 if (buf[0] == '\0') 772 continue; 773 To = fname; 774 if (Verbose) 775 message("050", " >> %s", buf); 776 sendto(buf, 1); 777 } 778 779 fclose(fp); 780 } 781 /* 782 ** MAILFILE -- Send a message to a file. 783 ** 784 ** Parameters: 785 ** filename -- the name of the file to send to. 786 ** 787 ** Returns: 788 ** The exit code associated with the operation. 789 ** 790 ** Side Effects: 791 ** none. 792 ** 793 ** Called By: 794 ** deliver 795 */ 796 797 mailfile(filename) 798 char *filename; 799 { 800 register FILE *f; 801 802 f = fopen(filename, "a"); 803 if (f == NULL) 804 return (EX_CANTCREAT); 805 806 putmessage(f, Mailer[1]); 807 fputs("\n", f); 808 (void) fclose(f); 809 return (EX_OK); 810 } 811