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