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