|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted provided ! 7: * that: (1) source distributions retain this entire copyright notice and ! 8: * comment, and (2) distributions including binaries display the following ! 9: * acknowledgement: ``This product includes software developed by the ! 10: * University of California, Berkeley and its contributors'' in the ! 11: * documentation or other materials provided with the distribution and in ! 12: * all advertising materials mentioning features or use of this software. ! 13: * Neither the name of the University nor the names of its contributors may ! 14: * be used to endorse or promote products derived from this software without ! 15: * specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: */ ! 20: ! 21: #ifndef lint ! 22: static char sccsid[] = "@(#)deliver.c 5.38 (Berkeley) 6/1/90"; ! 23: #endif /* not lint */ ! 24: ! 25: #include "sendmail.h" ! 26: #include <sys/signal.h> ! 27: #include <sys/stat.h> ! 28: #include <netdb.h> ! 29: #include <fcntl.h> ! 30: #include <errno.h> ! 31: #ifdef NAMED_BIND ! 32: #include <arpa/nameser.h> ! 33: #include <resolv.h> ! 34: #endif ! 35: ! 36: /* ! 37: ** DELIVER -- Deliver a message to a list of addresses. ! 38: ** ! 39: ** This routine delivers to everyone on the same host as the ! 40: ** user on the head of the list. It is clever about mailers ! 41: ** that don't handle multiple users. It is NOT guaranteed ! 42: ** that it will deliver to all these addresses however -- so ! 43: ** deliver should be called once for each address on the ! 44: ** list. ! 45: ** ! 46: ** Parameters: ! 47: ** e -- the envelope to deliver. ! 48: ** firstto -- head of the address list to deliver to. ! 49: ** ! 50: ** Returns: ! 51: ** zero -- successfully delivered. ! 52: ** else -- some failure, see ExitStat for more info. ! 53: ** ! 54: ** Side Effects: ! 55: ** The standard input is passed off to someone. ! 56: */ ! 57: ! 58: deliver(e, firstto) ! 59: register ENVELOPE *e; ! 60: ADDRESS *firstto; ! 61: { ! 62: char *host; /* host being sent to */ ! 63: char *user; /* user being sent to */ ! 64: char **pvp; ! 65: register char **mvp; ! 66: register char *p; ! 67: register MAILER *m; /* mailer for this recipient */ ! 68: ADDRESS *ctladdr; ! 69: register ADDRESS *to = firstto; ! 70: bool clever = FALSE; /* running user smtp to this mailer */ ! 71: ADDRESS *tochain = NULL; /* chain of users in this mailer call */ ! 72: int rcode; /* response code */ ! 73: char *pv[MAXPV+1]; ! 74: char tobuf[MAXLINE-50]; /* text line of to people */ ! 75: char buf[MAXNAME]; ! 76: char tfrombuf[MAXNAME]; /* translated from person */ ! 77: extern bool checkcompat(); ! 78: extern ADDRESS *getctladdr(); ! 79: extern char *remotename(); ! 80: ! 81: errno = 0; ! 82: if (bitset(QDONTSEND, to->q_flags)) ! 83: return (0); ! 84: ! 85: #ifdef NAMED_BIND ! 86: /* unless interactive, try twice, over a minute */ ! 87: if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { ! 88: _res.retrans = 30; ! 89: _res.retry = 2; ! 90: } ! 91: #endif ! 92: ! 93: m = to->q_mailer; ! 94: host = to->q_host; ! 95: ! 96: if (tTd(10, 1)) ! 97: printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", ! 98: m->m_mno, host, to->q_user); ! 99: ! 100: /* ! 101: ** If this mailer is expensive, and if we don't want to make ! 102: ** connections now, just mark these addresses and return. ! 103: ** This is useful if we want to batch connections to ! 104: ** reduce load. This will cause the messages to be ! 105: ** queued up, and a daemon will come along to send the ! 106: ** messages later. ! 107: ** This should be on a per-mailer basis. ! 108: */ ! 109: ! 110: if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && ! 111: !Verbose) ! 112: { ! 113: for (; to != NULL; to = to->q_next) ! 114: { ! 115: if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) ! 116: continue; ! 117: to->q_flags |= QQUEUEUP|QDONTSEND; ! 118: e->e_to = to->q_paddr; ! 119: message(Arpa_Info, "queued"); ! 120: if (LogLevel > 4) ! 121: logdelivery("queued"); ! 122: } ! 123: e->e_to = NULL; ! 124: return (0); ! 125: } ! 126: ! 127: /* ! 128: ** Do initial argv setup. ! 129: ** Insert the mailer name. Notice that $x expansion is ! 130: ** NOT done on the mailer name. Then, if the mailer has ! 131: ** a picky -f flag, we insert it as appropriate. This ! 132: ** code does not check for 'pv' overflow; this places a ! 133: ** manifest lower limit of 4 for MAXPV. ! 134: ** The from address rewrite is expected to make ! 135: ** the address relative to the other end. ! 136: */ ! 137: ! 138: /* rewrite from address, using rewriting rules */ ! 139: expand("\001f", buf, &buf[sizeof buf - 1], e); ! 140: (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); ! 141: ! 142: define('g', tfrombuf, e); /* translated sender address */ ! 143: define('h', host, e); /* to host */ ! 144: Errors = 0; ! 145: pvp = pv; ! 146: *pvp++ = m->m_argv[0]; ! 147: ! 148: /* insert -f or -r flag as appropriate */ ! 149: if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) ! 150: { ! 151: if (bitnset(M_FOPT, m->m_flags)) ! 152: *pvp++ = "-f"; ! 153: else ! 154: *pvp++ = "-r"; ! 155: expand("\001g", buf, &buf[sizeof buf - 1], e); ! 156: *pvp++ = newstr(buf); ! 157: } ! 158: ! 159: /* ! 160: ** Append the other fixed parts of the argv. These run ! 161: ** up to the first entry containing "$u". There can only ! 162: ** be one of these, and there are only a few more slots ! 163: ** in the pv after it. ! 164: */ ! 165: ! 166: for (mvp = m->m_argv; (p = *++mvp) != NULL; ) ! 167: { ! 168: while ((p = index(p, '\001')) != NULL) ! 169: if (*++p == 'u') ! 170: break; ! 171: if (p != NULL) ! 172: break; ! 173: ! 174: /* this entry is safe -- go ahead and process it */ ! 175: expand(*mvp, buf, &buf[sizeof buf - 1], e); ! 176: *pvp++ = newstr(buf); ! 177: if (pvp >= &pv[MAXPV - 3]) ! 178: { ! 179: syserr("Too many parameters to %s before $u", pv[0]); ! 180: return (-1); ! 181: } ! 182: } ! 183: ! 184: /* ! 185: ** If we have no substitution for the user name in the argument ! 186: ** list, we know that we must supply the names otherwise -- and ! 187: ** SMTP is the answer!! ! 188: */ ! 189: ! 190: if (*mvp == NULL) ! 191: { ! 192: /* running SMTP */ ! 193: # ifdef SMTP ! 194: clever = TRUE; ! 195: *pvp = NULL; ! 196: # else SMTP ! 197: /* oops! we don't implement SMTP */ ! 198: syserr("SMTP style mailer"); ! 199: return (EX_SOFTWARE); ! 200: # endif SMTP ! 201: } ! 202: ! 203: /* ! 204: ** At this point *mvp points to the argument with $u. We ! 205: ** run through our address list and append all the addresses ! 206: ** we can. If we run out of space, do not fret! We can ! 207: ** always send another copy later. ! 208: */ ! 209: ! 210: tobuf[0] = '\0'; ! 211: e->e_to = tobuf; ! 212: ctladdr = NULL; ! 213: for (; to != NULL; to = to->q_next) ! 214: { ! 215: /* avoid sending multiple recipients to dumb mailers */ ! 216: if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) ! 217: break; ! 218: ! 219: /* if already sent or not for this host, don't send */ ! 220: if (bitset(QDONTSEND, to->q_flags) || ! 221: strcmp(to->q_host, host) != 0 || ! 222: to->q_mailer != firstto->q_mailer) ! 223: continue; ! 224: ! 225: /* avoid overflowing tobuf */ ! 226: if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) ! 227: break; ! 228: ! 229: if (tTd(10, 1)) ! 230: { ! 231: printf("\nsend to "); ! 232: printaddr(to, FALSE); ! 233: } ! 234: ! 235: /* compute effective uid/gid when sending */ ! 236: if (to->q_mailer == ProgMailer) ! 237: ctladdr = getctladdr(to); ! 238: ! 239: user = to->q_user; ! 240: e->e_to = to->q_paddr; ! 241: to->q_flags |= QDONTSEND; ! 242: ! 243: /* ! 244: ** Check to see that these people are allowed to ! 245: ** talk to each other. ! 246: */ ! 247: ! 248: if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) ! 249: { ! 250: NoReturn = TRUE; ! 251: usrerr("Message is too large; %ld bytes max", m->m_maxsize); ! 252: giveresponse(EX_UNAVAILABLE, m, e); ! 253: continue; ! 254: } ! 255: if (!checkcompat(to)) ! 256: { ! 257: giveresponse(EX_UNAVAILABLE, m, e); ! 258: continue; ! 259: } ! 260: ! 261: /* ! 262: ** Strip quote bits from names if the mailer is dumb ! 263: ** about them. ! 264: */ ! 265: ! 266: if (bitnset(M_STRIPQ, m->m_flags)) ! 267: { ! 268: stripquotes(user, TRUE); ! 269: stripquotes(host, TRUE); ! 270: } ! 271: else ! 272: { ! 273: stripquotes(user, FALSE); ! 274: stripquotes(host, FALSE); ! 275: } ! 276: ! 277: /* hack attack -- delivermail compatibility */ ! 278: if (m == ProgMailer && *user == '|') ! 279: user++; ! 280: ! 281: /* ! 282: ** If an error message has already been given, don't ! 283: ** bother to send to this address. ! 284: ** ! 285: ** >>>>>>>>>> This clause assumes that the local mailer ! 286: ** >> NOTE >> cannot do any further aliasing; that ! 287: ** >>>>>>>>>> function is subsumed by sendmail. ! 288: */ ! 289: ! 290: if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) ! 291: continue; ! 292: ! 293: /* save statistics.... */ ! 294: markstats(e, to); ! 295: ! 296: /* ! 297: ** See if this user name is "special". ! 298: ** If the user name has a slash in it, assume that this ! 299: ** is a file -- send it off without further ado. Note ! 300: ** that this type of addresses is not processed along ! 301: ** with the others, so we fudge on the To person. ! 302: */ ! 303: ! 304: if (m == LocalMailer) ! 305: { ! 306: if (user[0] == '/') ! 307: { ! 308: rcode = mailfile(user, getctladdr(to)); ! 309: giveresponse(rcode, m, e); ! 310: continue; ! 311: } ! 312: } ! 313: ! 314: /* ! 315: ** Address is verified -- add this user to mailer ! 316: ** argv, and add it to the print list of recipients. ! 317: */ ! 318: ! 319: /* link together the chain of recipients */ ! 320: to->q_tchain = tochain; ! 321: tochain = to; ! 322: ! 323: /* create list of users for error messages */ ! 324: (void) strcat(tobuf, ","); ! 325: (void) strcat(tobuf, to->q_paddr); ! 326: define('u', user, e); /* to user */ ! 327: define('z', to->q_home, e); /* user's home */ ! 328: ! 329: /* ! 330: ** Expand out this user into argument list. ! 331: */ ! 332: ! 333: if (!clever) ! 334: { ! 335: expand(*mvp, buf, &buf[sizeof buf - 1], e); ! 336: *pvp++ = newstr(buf); ! 337: if (pvp >= &pv[MAXPV - 2]) ! 338: { ! 339: /* allow some space for trailing parms */ ! 340: break; ! 341: } ! 342: } ! 343: } ! 344: ! 345: /* see if any addresses still exist */ ! 346: if (tobuf[0] == '\0') ! 347: { ! 348: define('g', (char *) NULL, e); ! 349: return (0); ! 350: } ! 351: ! 352: /* print out messages as full list */ ! 353: e->e_to = tobuf + 1; ! 354: ! 355: /* ! 356: ** Fill out any parameters after the $u parameter. ! 357: */ ! 358: ! 359: while (!clever && *++mvp != NULL) ! 360: { ! 361: expand(*mvp, buf, &buf[sizeof buf - 1], e); ! 362: *pvp++ = newstr(buf); ! 363: if (pvp >= &pv[MAXPV]) ! 364: syserr("deliver: pv overflow after $u for %s", pv[0]); ! 365: } ! 366: *pvp++ = NULL; ! 367: ! 368: /* ! 369: ** Call the mailer. ! 370: ** The argument vector gets built, pipes ! 371: ** are created as necessary, and we fork & exec as ! 372: ** appropriate. ! 373: ** If we are running SMTP, we just need to clean up. ! 374: */ ! 375: ! 376: if (ctladdr == NULL) ! 377: ctladdr = &e->e_from; ! 378: #ifdef NAMED_BIND ! 379: _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ ! 380: #endif ! 381: #ifdef SMTP ! 382: if (clever) ! 383: { ! 384: rcode = EX_OK; ! 385: #ifdef NAMED_BIND ! 386: if (host[0] && host[0] != '[') ! 387: { ! 388: expand("\001w", buf, &buf[sizeof(buf) - 1], e); ! 389: Nmx = getmxrr(host, MxHosts, buf, &rcode); ! 390: } ! 391: else ! 392: #endif ! 393: { ! 394: Nmx = 1; ! 395: MxHosts[0] = host; ! 396: } ! 397: if (Nmx >= 0) ! 398: { ! 399: message(Arpa_Info, "Connecting to %s (%s)...", ! 400: MxHosts[0], m->m_name); ! 401: if ((rcode = smtpinit(m, pv)) == EX_OK) { ! 402: register char *t = tobuf; ! 403: register int i; ! 404: ! 405: /* send the recipient list */ ! 406: tobuf[0] = '\0'; ! 407: for (to = tochain; to; to = to->q_tchain) { ! 408: e->e_to = to->q_paddr; ! 409: if ((i = smtprcpt(to, m)) != EX_OK) { ! 410: markfailure(e, to, i); ! 411: giveresponse(i, m, e); ! 412: } ! 413: else { ! 414: *t++ = ','; ! 415: for (p = to->q_paddr; *p; *t++ = *p++); ! 416: } ! 417: } ! 418: ! 419: /* now send the data */ ! 420: if (tobuf[0] == '\0') ! 421: e->e_to = NULL; ! 422: else { ! 423: e->e_to = tobuf + 1; ! 424: rcode = smtpdata(m, e); ! 425: } ! 426: ! 427: /* now close the connection */ ! 428: smtpquit(m); ! 429: } ! 430: } ! 431: } ! 432: else ! 433: #endif /* SMTP */ ! 434: { ! 435: message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name); ! 436: rcode = sendoff(e, m, pv, ctladdr); ! 437: } ! 438: #ifdef NAMED_BIND ! 439: _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ ! 440: #endif ! 441: ! 442: /* ! 443: ** Do final status disposal. ! 444: ** We check for something in tobuf for the SMTP case. ! 445: ** If we got a temporary failure, arrange to queue the ! 446: ** addressees. ! 447: */ ! 448: ! 449: if (tobuf[0] != '\0') ! 450: giveresponse(rcode, m, e); ! 451: if (rcode != EX_OK) ! 452: for (to = tochain; to != NULL; to = to->q_tchain) ! 453: markfailure(e, to, rcode); ! 454: ! 455: errno = 0; ! 456: define('g', (char *) NULL, e); ! 457: return (rcode); ! 458: } ! 459: /* ! 460: ** MARKFAILURE -- mark a failure on a specific address. ! 461: ** ! 462: ** Parameters: ! 463: ** e -- the envelope we are sending. ! 464: ** q -- the address to mark. ! 465: ** rcode -- the code signifying the particular failure. ! 466: ** ! 467: ** Returns: ! 468: ** none. ! 469: ** ! 470: ** Side Effects: ! 471: ** marks the address (and possibly the envelope) with the ! 472: ** failure so that an error will be returned or ! 473: ** the message will be queued, as appropriate. ! 474: */ ! 475: ! 476: markfailure(e, q, rcode) ! 477: register ENVELOPE *e; ! 478: register ADDRESS *q; ! 479: int rcode; ! 480: { ! 481: if (rcode == EX_OK) ! 482: return; ! 483: else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) ! 484: q->q_flags |= QBADADDR; ! 485: else if (curtime() > e->e_ctime + TimeOut) ! 486: { ! 487: extern char *pintvl(); ! 488: char buf[MAXLINE]; ! 489: ! 490: if (!bitset(EF_TIMEOUT, e->e_flags)) ! 491: { ! 492: (void) sprintf(buf, "Cannot send message for %s", ! 493: pintvl(TimeOut, FALSE)); ! 494: if (e->e_message != NULL) ! 495: free(e->e_message); ! 496: e->e_message = newstr(buf); ! 497: message(Arpa_Info, buf); ! 498: } ! 499: q->q_flags |= QBADADDR; ! 500: e->e_flags |= EF_TIMEOUT; ! 501: } ! 502: else ! 503: q->q_flags |= QQUEUEUP; ! 504: } ! 505: /* ! 506: ** DOFORK -- do a fork, retrying a couple of times on failure. ! 507: ** ! 508: ** This MUST be a macro, since after a vfork we are running ! 509: ** two processes on the same stack!!! ! 510: ** ! 511: ** Parameters: ! 512: ** none. ! 513: ** ! 514: ** Returns: ! 515: ** From a macro??? You've got to be kidding! ! 516: ** ! 517: ** Side Effects: ! 518: ** Modifies the ==> LOCAL <== variable 'pid', leaving: ! 519: ** pid of child in parent, zero in child. ! 520: ** -1 on unrecoverable error. ! 521: ** ! 522: ** Notes: ! 523: ** I'm awfully sorry this looks so awful. That's ! 524: ** vfork for you..... ! 525: */ ! 526: ! 527: # define NFORKTRIES 5 ! 528: # ifdef VMUNIX ! 529: # define XFORK vfork ! 530: # else VMUNIX ! 531: # define XFORK fork ! 532: # endif VMUNIX ! 533: ! 534: # define DOFORK(fORKfN) \ ! 535: {\ ! 536: register int i;\ ! 537: \ ! 538: for (i = NFORKTRIES; --i >= 0; )\ ! 539: {\ ! 540: pid = fORKfN();\ ! 541: if (pid >= 0)\ ! 542: break;\ ! 543: if (i > 0)\ ! 544: sleep((unsigned) NFORKTRIES - i);\ ! 545: }\ ! 546: } ! 547: /* ! 548: ** DOFORK -- simple fork interface to DOFORK. ! 549: ** ! 550: ** Parameters: ! 551: ** none. ! 552: ** ! 553: ** Returns: ! 554: ** pid of child in parent. ! 555: ** zero in child. ! 556: ** -1 on error. ! 557: ** ! 558: ** Side Effects: ! 559: ** returns twice, once in parent and once in child. ! 560: */ ! 561: ! 562: dofork() ! 563: { ! 564: register int pid; ! 565: ! 566: DOFORK(fork); ! 567: return (pid); ! 568: } ! 569: /* ! 570: ** SENDOFF -- send off call to mailer & collect response. ! 571: ** ! 572: ** Parameters: ! 573: ** e -- the envelope to mail. ! 574: ** m -- mailer descriptor. ! 575: ** pvp -- parameter vector to send to it. ! 576: ** ctladdr -- an address pointer controlling the ! 577: ** user/groupid etc. of the mailer. ! 578: ** ! 579: ** Returns: ! 580: ** exit status of mailer. ! 581: ** ! 582: ** Side Effects: ! 583: ** none. ! 584: */ ! 585: static ! 586: sendoff(e, m, pvp, ctladdr) ! 587: register ENVELOPE *e; ! 588: MAILER *m; ! 589: char **pvp; ! 590: ADDRESS *ctladdr; ! 591: { ! 592: auto FILE *mfile; ! 593: auto FILE *rfile; ! 594: register int i; ! 595: int pid; ! 596: ! 597: /* ! 598: ** Create connection to mailer. ! 599: */ ! 600: ! 601: pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); ! 602: if (pid < 0) ! 603: return (-1); ! 604: ! 605: /* ! 606: ** Format and send message. ! 607: */ ! 608: ! 609: putfromline(mfile, m); ! 610: (*e->e_puthdr)(mfile, m, e); ! 611: putline("\n", mfile, m); ! 612: (*e->e_putbody)(mfile, m, e); ! 613: (void) fclose(mfile); ! 614: if (rfile != NULL) ! 615: (void) fclose(rfile); ! 616: ! 617: i = endmailer(pid, pvp[0]); ! 618: ! 619: /* arrange a return receipt if requested */ ! 620: if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) ! 621: { ! 622: e->e_flags |= EF_SENDRECEIPT; ! 623: /* do we want to send back more info? */ ! 624: } ! 625: ! 626: return (i); ! 627: } ! 628: /* ! 629: ** ENDMAILER -- Wait for mailer to terminate. ! 630: ** ! 631: ** We should never get fatal errors (e.g., segmentation ! 632: ** violation), so we report those specially. For other ! 633: ** errors, we choose a status message (into statmsg), ! 634: ** and if it represents an error, we print it. ! 635: ** ! 636: ** Parameters: ! 637: ** pid -- pid of mailer. ! 638: ** name -- name of mailer (for error messages). ! 639: ** ! 640: ** Returns: ! 641: ** exit code of mailer. ! 642: ** ! 643: ** Side Effects: ! 644: ** none. ! 645: */ ! 646: ! 647: endmailer(pid, name) ! 648: int pid; ! 649: char *name; ! 650: { ! 651: int st; ! 652: ! 653: /* in the IPC case there is nothing to wait for */ ! 654: if (pid == 0) ! 655: return (EX_OK); ! 656: ! 657: /* wait for the mailer process to die and collect status */ ! 658: st = waitfor(pid); ! 659: if (st == -1) ! 660: { ! 661: syserr("endmailer %s: wait", name); ! 662: return (EX_SOFTWARE); ! 663: } ! 664: ! 665: /* see if it died a horrid death */ ! 666: if ((st & 0377) != 0) ! 667: { ! 668: syserr("mailer %s died with signal %o", name, st); ! 669: ExitStat = EX_TEMPFAIL; ! 670: return (EX_TEMPFAIL); ! 671: } ! 672: ! 673: /* normal death -- return status */ ! 674: st = (st >> 8) & 0377; ! 675: return (st); ! 676: } ! 677: /* ! 678: ** OPENMAILER -- open connection to mailer. ! 679: ** ! 680: ** Parameters: ! 681: ** m -- mailer descriptor. ! 682: ** pvp -- parameter vector to pass to mailer. ! 683: ** ctladdr -- controlling address for user. ! 684: ** clever -- create a full duplex connection. ! 685: ** pmfile -- pointer to mfile (to mailer) connection. ! 686: ** prfile -- pointer to rfile (from mailer) connection. ! 687: ** ! 688: ** Returns: ! 689: ** pid of mailer ( > 0 ). ! 690: ** -1 on error. ! 691: ** zero on an IPC connection. ! 692: ** ! 693: ** Side Effects: ! 694: ** creates a mailer in a subprocess. ! 695: */ ! 696: ! 697: openmailer(m, pvp, ctladdr, clever, pmfile, prfile) ! 698: MAILER *m; ! 699: char **pvp; ! 700: ADDRESS *ctladdr; ! 701: bool clever; ! 702: FILE **pmfile; ! 703: FILE **prfile; ! 704: { ! 705: int pid; ! 706: int mpvect[2]; ! 707: int rpvect[2]; ! 708: FILE *mfile = NULL; ! 709: FILE *rfile = NULL; ! 710: extern FILE *fdopen(); ! 711: ! 712: if (tTd(11, 1)) ! 713: { ! 714: printf("openmailer:"); ! 715: printav(pvp); ! 716: } ! 717: errno = 0; ! 718: ! 719: CurHostName = m->m_mailer; ! 720: ! 721: /* ! 722: ** Deal with the special case of mail handled through an IPC ! 723: ** connection. ! 724: ** In this case we don't actually fork. We must be ! 725: ** running SMTP for this to work. We will return a ! 726: ** zero pid to indicate that we are running IPC. ! 727: ** We also handle a debug version that just talks to stdin/out. ! 728: */ ! 729: ! 730: /* check for Local Person Communication -- not for mortals!!! */ ! 731: if (strcmp(m->m_mailer, "[LPC]") == 0) ! 732: { ! 733: *pmfile = stdout; ! 734: *prfile = stdin; ! 735: return (0); ! 736: } ! 737: ! 738: if (strcmp(m->m_mailer, "[IPC]") == 0) ! 739: { ! 740: #ifdef HOSTINFO ! 741: register STAB *st; ! 742: extern STAB *stab(); ! 743: #endif HOSTINFO ! 744: #ifdef DAEMON ! 745: register int i, j; ! 746: register u_short port; ! 747: ! 748: CurHostName = pvp[1]; ! 749: if (!clever) ! 750: syserr("non-clever IPC"); ! 751: if (pvp[2] != NULL) ! 752: port = atoi(pvp[2]); ! 753: else ! 754: port = 0; ! 755: for (j = 0; j < Nmx; j++) ! 756: { ! 757: CurHostName = MxHosts[j]; ! 758: #ifdef HOSTINFO ! 759: /* see if we have already determined that this host is fried */ ! 760: st = stab(MxHosts[j], ST_HOST, ST_FIND); ! 761: if (st == NULL || st->s_host.ho_exitstat == EX_OK) { ! 762: if (j > 1) ! 763: message(Arpa_Info, ! 764: "Connecting to %s (%s)...", ! 765: MxHosts[j], m->m_name); ! 766: i = makeconnection(MxHosts[j], port, pmfile, prfile); ! 767: } ! 768: else ! 769: { ! 770: i = st->s_host.ho_exitstat; ! 771: errno = st->s_host.ho_errno; ! 772: } ! 773: #else HOSTINFO ! 774: i = makeconnection(MxHosts[j], port, pmfile, prfile); ! 775: #endif HOSTINFO ! 776: if (i != EX_OK) ! 777: { ! 778: #ifdef HOSTINFO ! 779: /* enter status of this host */ ! 780: if (st == NULL) ! 781: st = stab(MxHosts[j], ST_HOST, ST_ENTER); ! 782: st->s_host.ho_exitstat = i; ! 783: st->s_host.ho_errno = errno; ! 784: #endif HOSTINFO ! 785: ExitStat = i; ! 786: continue; ! 787: } ! 788: else ! 789: return (0); ! 790: } ! 791: return (-1); ! 792: #else DAEMON ! 793: syserr("openmailer: no IPC"); ! 794: return (-1); ! 795: #endif DAEMON ! 796: } ! 797: ! 798: /* create a pipe to shove the mail through */ ! 799: if (pipe(mpvect) < 0) ! 800: { ! 801: syserr("openmailer: pipe (to mailer)"); ! 802: return (-1); ! 803: } ! 804: ! 805: #ifdef SMTP ! 806: /* if this mailer speaks smtp, create a return pipe */ ! 807: if (clever && pipe(rpvect) < 0) ! 808: { ! 809: syserr("openmailer: pipe (from mailer)"); ! 810: (void) close(mpvect[0]); ! 811: (void) close(mpvect[1]); ! 812: return (-1); ! 813: } ! 814: #endif SMTP ! 815: ! 816: /* ! 817: ** Actually fork the mailer process. ! 818: ** DOFORK is clever about retrying. ! 819: ** ! 820: ** Dispose of SIGCHLD signal catchers that may be laying ! 821: ** around so that endmail will get it. ! 822: */ ! 823: ! 824: if (CurEnv->e_xfp != NULL) ! 825: (void) fflush(CurEnv->e_xfp); /* for debugging */ ! 826: (void) fflush(stdout); ! 827: # ifdef SIGCHLD ! 828: (void) signal(SIGCHLD, SIG_DFL); ! 829: # endif SIGCHLD ! 830: DOFORK(XFORK); ! 831: /* pid is set by DOFORK */ ! 832: if (pid < 0) ! 833: { ! 834: /* failure */ ! 835: syserr("openmailer: cannot fork"); ! 836: (void) close(mpvect[0]); ! 837: (void) close(mpvect[1]); ! 838: #ifdef SMTP ! 839: if (clever) ! 840: { ! 841: (void) close(rpvect[0]); ! 842: (void) close(rpvect[1]); ! 843: } ! 844: #endif SMTP ! 845: return (-1); ! 846: } ! 847: else if (pid == 0) ! 848: { ! 849: int i; ! 850: extern int DtableSize; ! 851: ! 852: /* child -- set up input & exec mailer */ ! 853: /* make diagnostic output be standard output */ ! 854: (void) signal(SIGINT, SIG_IGN); ! 855: (void) signal(SIGHUP, SIG_IGN); ! 856: (void) signal(SIGTERM, SIG_DFL); ! 857: ! 858: /* arrange to filter standard & diag output of command */ ! 859: if (clever) ! 860: { ! 861: (void) close(rpvect[0]); ! 862: (void) close(1); ! 863: (void) dup(rpvect[1]); ! 864: (void) close(rpvect[1]); ! 865: } ! 866: else if (OpMode == MD_SMTP || HoldErrs) ! 867: { ! 868: /* put mailer output in transcript */ ! 869: (void) close(1); ! 870: (void) dup(fileno(CurEnv->e_xfp)); ! 871: } ! 872: (void) close(2); ! 873: (void) dup(1); ! 874: ! 875: /* arrange to get standard input */ ! 876: (void) close(mpvect[1]); ! 877: (void) close(0); ! 878: if (dup(mpvect[0]) < 0) ! 879: { ! 880: syserr("Cannot dup to zero!"); ! 881: _exit(EX_OSERR); ! 882: } ! 883: (void) close(mpvect[0]); ! 884: if (!bitnset(M_RESTR, m->m_flags)) ! 885: { ! 886: if (ctladdr == NULL || ctladdr->q_uid == 0) ! 887: { ! 888: (void) setgid(DefGid); ! 889: (void) initgroups(DefUser, DefGid); ! 890: (void) setuid(DefUid); ! 891: } ! 892: else ! 893: { ! 894: (void) setgid(ctladdr->q_gid); ! 895: (void) initgroups(ctladdr->q_ruser? ! 896: ctladdr->q_ruser: ctladdr->q_user, ! 897: ctladdr->q_gid); ! 898: (void) setuid(ctladdr->q_uid); ! 899: } ! 900: } ! 901: ! 902: /* arrange for all the files to be closed */ ! 903: for (i = 3; i < DtableSize; i++) { ! 904: register int j; ! 905: if ((j = fcntl(i, F_GETFD, 0)) != -1) ! 906: (void)fcntl(i, F_SETFD, j|1); ! 907: } ! 908: ! 909: /* try to execute the mailer */ ! 910: execve(m->m_mailer, pvp, UserEnviron); ! 911: syserr("Cannot exec %s", m->m_mailer); ! 912: if (m == LocalMailer || errno == EIO || errno == EAGAIN || ! 913: errno == ENOMEM || errno == EPROCLIM) ! 914: _exit(EX_TEMPFAIL); ! 915: else ! 916: _exit(EX_UNAVAILABLE); ! 917: } ! 918: ! 919: /* ! 920: ** Set up return value. ! 921: */ ! 922: ! 923: (void) close(mpvect[0]); ! 924: mfile = fdopen(mpvect[1], "w"); ! 925: if (clever) ! 926: { ! 927: (void) close(rpvect[1]); ! 928: rfile = fdopen(rpvect[0], "r"); ! 929: } else ! 930: rfile = NULL; ! 931: ! 932: *pmfile = mfile; ! 933: *prfile = rfile; ! 934: ! 935: return (pid); ! 936: } ! 937: /* ! 938: ** GIVERESPONSE -- Interpret an error response from a mailer ! 939: ** ! 940: ** Parameters: ! 941: ** stat -- the status code from the mailer (high byte ! 942: ** only; core dumps must have been taken care of ! 943: ** already). ! 944: ** m -- the mailer descriptor for this mailer. ! 945: ** ! 946: ** Returns: ! 947: ** none. ! 948: ** ! 949: ** Side Effects: ! 950: ** Errors may be incremented. ! 951: ** ExitStat may be set. ! 952: */ ! 953: ! 954: giveresponse(stat, m, e) ! 955: int stat; ! 956: register MAILER *m; ! 957: ENVELOPE *e; ! 958: { ! 959: register char *statmsg; ! 960: extern char *SysExMsg[]; ! 961: register int i; ! 962: extern int N_SysEx; ! 963: #ifdef NAMED_BIND ! 964: extern int h_errno; ! 965: #endif ! 966: char buf[MAXLINE]; ! 967: ! 968: #ifdef lint ! 969: if (m == NULL) ! 970: return; ! 971: #endif lint ! 972: ! 973: /* ! 974: ** Compute status message from code. ! 975: */ ! 976: ! 977: i = stat - EX__BASE; ! 978: if (stat == 0) ! 979: statmsg = "250 Sent"; ! 980: else if (i < 0 || i > N_SysEx) ! 981: { ! 982: (void) sprintf(buf, "554 unknown mailer error %d", stat); ! 983: stat = EX_UNAVAILABLE; ! 984: statmsg = buf; ! 985: } ! 986: else if (stat == EX_TEMPFAIL) ! 987: { ! 988: (void) strcpy(buf, SysExMsg[i]); ! 989: #ifdef NAMED_BIND ! 990: if (h_errno == TRY_AGAIN) ! 991: { ! 992: extern char *errstring(); ! 993: ! 994: statmsg = errstring(h_errno+MAX_ERRNO); ! 995: } ! 996: else ! 997: #endif ! 998: { ! 999: if (errno != 0) ! 1000: { ! 1001: extern char *errstring(); ! 1002: ! 1003: statmsg = errstring(errno); ! 1004: } ! 1005: else ! 1006: { ! 1007: #ifdef SMTP ! 1008: extern char SmtpError[]; ! 1009: ! 1010: statmsg = SmtpError; ! 1011: #else SMTP ! 1012: statmsg = NULL; ! 1013: #endif SMTP ! 1014: } ! 1015: } ! 1016: if (statmsg != NULL && statmsg[0] != '\0') ! 1017: { ! 1018: (void) strcat(buf, ": "); ! 1019: (void) strcat(buf, statmsg); ! 1020: } ! 1021: statmsg = buf; ! 1022: } ! 1023: else ! 1024: { ! 1025: statmsg = SysExMsg[i]; ! 1026: } ! 1027: ! 1028: /* ! 1029: ** Print the message as appropriate ! 1030: */ ! 1031: ! 1032: if (stat == EX_OK || stat == EX_TEMPFAIL) ! 1033: message(Arpa_Info, &statmsg[4]); ! 1034: else ! 1035: { ! 1036: Errors++; ! 1037: usrerr(statmsg); ! 1038: } ! 1039: ! 1040: /* ! 1041: ** Final cleanup. ! 1042: ** Log a record of the transaction. Compute the new ! 1043: ** ExitStat -- if we already had an error, stick with ! 1044: ** that. ! 1045: */ ! 1046: ! 1047: if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) ! 1048: logdelivery(&statmsg[4]); ! 1049: ! 1050: if (stat != EX_TEMPFAIL) ! 1051: setstat(stat); ! 1052: if (stat != EX_OK) ! 1053: { ! 1054: if (e->e_message != NULL) ! 1055: free(e->e_message); ! 1056: e->e_message = newstr(&statmsg[4]); ! 1057: } ! 1058: errno = 0; ! 1059: #ifdef NAMED_BIND ! 1060: h_errno = 0; ! 1061: #endif ! 1062: } ! 1063: /* ! 1064: ** LOGDELIVERY -- log the delivery in the system log ! 1065: ** ! 1066: ** Parameters: ! 1067: ** stat -- the message to print for the status ! 1068: ** ! 1069: ** Returns: ! 1070: ** none ! 1071: ** ! 1072: ** Side Effects: ! 1073: ** none ! 1074: */ ! 1075: ! 1076: logdelivery(stat) ! 1077: char *stat; ! 1078: { ! 1079: extern char *pintvl(); ! 1080: ! 1081: # ifdef LOG ! 1082: syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, ! 1083: CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); ! 1084: # endif LOG ! 1085: } ! 1086: /* ! 1087: ** PUTFROMLINE -- output a UNIX-style from line (or whatever) ! 1088: ** ! 1089: ** This can be made an arbitrary message separator by changing $l ! 1090: ** ! 1091: ** One of the ugliest hacks seen by human eyes is contained herein: ! 1092: ** UUCP wants those stupid "remote from <host>" lines. Why oh why ! 1093: ** does a well-meaning programmer such as myself have to deal with ! 1094: ** this kind of antique garbage???? ! 1095: ** ! 1096: ** Parameters: ! 1097: ** fp -- the file to output to. ! 1098: ** m -- the mailer describing this entry. ! 1099: ** ! 1100: ** Returns: ! 1101: ** none ! 1102: ** ! 1103: ** Side Effects: ! 1104: ** outputs some text to fp. ! 1105: */ ! 1106: ! 1107: putfromline(fp, m) ! 1108: register FILE *fp; ! 1109: register MAILER *m; ! 1110: { ! 1111: char *template = "\001l\n"; ! 1112: char buf[MAXLINE]; ! 1113: ! 1114: if (bitnset(M_NHDR, m->m_flags)) ! 1115: return; ! 1116: ! 1117: # ifdef UGLYUUCP ! 1118: if (bitnset(M_UGLYUUCP, m->m_flags)) ! 1119: { ! 1120: char *bang; ! 1121: char xbuf[MAXLINE]; ! 1122: ! 1123: expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); ! 1124: bang = index(buf, '!'); ! 1125: if (bang == NULL) ! 1126: syserr("No ! in UUCP! (%s)", buf); ! 1127: else ! 1128: { ! 1129: *bang++ = '\0'; ! 1130: (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); ! 1131: template = xbuf; ! 1132: } ! 1133: } ! 1134: # endif UGLYUUCP ! 1135: expand(template, buf, &buf[sizeof buf - 1], CurEnv); ! 1136: putline(buf, fp, m); ! 1137: } ! 1138: /* ! 1139: ** PUTBODY -- put the body of a message. ! 1140: ** ! 1141: ** Parameters: ! 1142: ** fp -- file to output onto. ! 1143: ** m -- a mailer descriptor to control output format. ! 1144: ** e -- the envelope to put out. ! 1145: ** ! 1146: ** Returns: ! 1147: ** none. ! 1148: ** ! 1149: ** Side Effects: ! 1150: ** The message is written onto fp. ! 1151: */ ! 1152: ! 1153: putbody(fp, m, e) ! 1154: FILE *fp; ! 1155: MAILER *m; ! 1156: register ENVELOPE *e; ! 1157: { ! 1158: char buf[MAXLINE]; ! 1159: ! 1160: /* ! 1161: ** Output the body of the message ! 1162: */ ! 1163: ! 1164: if (e->e_dfp == NULL) ! 1165: { ! 1166: if (e->e_df != NULL) ! 1167: { ! 1168: e->e_dfp = fopen(e->e_df, "r"); ! 1169: if (e->e_dfp == NULL) ! 1170: syserr("putbody: Cannot open %s for %s from %s", ! 1171: e->e_df, e->e_to, e->e_from); ! 1172: } ! 1173: else ! 1174: putline("<<< No Message Collected >>>", fp, m); ! 1175: } ! 1176: if (e->e_dfp != NULL) ! 1177: { ! 1178: rewind(e->e_dfp); ! 1179: while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) ! 1180: { ! 1181: if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && ! 1182: strncmp(buf, "From ", 5) == 0) ! 1183: (void) putc('>', fp); ! 1184: putline(buf, fp, m); ! 1185: } ! 1186: ! 1187: if (ferror(e->e_dfp)) ! 1188: { ! 1189: syserr("putbody: read error"); ! 1190: ExitStat = EX_IOERR; ! 1191: } ! 1192: } ! 1193: ! 1194: (void) fflush(fp); ! 1195: if (ferror(fp) && errno != EPIPE) ! 1196: { ! 1197: syserr("putbody: write error"); ! 1198: ExitStat = EX_IOERR; ! 1199: } ! 1200: errno = 0; ! 1201: } ! 1202: /* ! 1203: ** MAILFILE -- Send a message to a file. ! 1204: ** ! 1205: ** If the file has the setuid/setgid bits set, but NO execute ! 1206: ** bits, sendmail will try to become the owner of that file ! 1207: ** rather than the real user. Obviously, this only works if ! 1208: ** sendmail runs as root. ! 1209: ** ! 1210: ** This could be done as a subordinate mailer, except that it ! 1211: ** is used implicitly to save messages in ~/dead.letter. We ! 1212: ** view this as being sufficiently important as to include it ! 1213: ** here. For example, if the system is dying, we shouldn't have ! 1214: ** to create another process plus some pipes to save the message. ! 1215: ** ! 1216: ** Parameters: ! 1217: ** filename -- the name of the file to send to. ! 1218: ** ctladdr -- the controlling address header -- includes ! 1219: ** the userid/groupid to be when sending. ! 1220: ** ! 1221: ** Returns: ! 1222: ** The exit code associated with the operation. ! 1223: ** ! 1224: ** Side Effects: ! 1225: ** none. ! 1226: */ ! 1227: ! 1228: mailfile(filename, ctladdr) ! 1229: char *filename; ! 1230: ADDRESS *ctladdr; ! 1231: { ! 1232: register FILE *f; ! 1233: register int pid; ! 1234: ENVELOPE *e = CurEnv; ! 1235: ! 1236: /* ! 1237: ** Fork so we can change permissions here. ! 1238: ** Note that we MUST use fork, not vfork, because of ! 1239: ** the complications of calling subroutines, etc. ! 1240: */ ! 1241: ! 1242: DOFORK(fork); ! 1243: ! 1244: if (pid < 0) ! 1245: return (EX_OSERR); ! 1246: else if (pid == 0) ! 1247: { ! 1248: /* child -- actually write to file */ ! 1249: struct stat stb; ! 1250: ! 1251: (void) signal(SIGINT, SIG_DFL); ! 1252: (void) signal(SIGHUP, SIG_DFL); ! 1253: (void) signal(SIGTERM, SIG_DFL); ! 1254: (void) umask(OldUmask); ! 1255: if (stat(filename, &stb) < 0) ! 1256: { ! 1257: errno = 0; ! 1258: stb.st_mode = 0666; ! 1259: } ! 1260: if (bitset(0111, stb.st_mode)) ! 1261: exit(EX_CANTCREAT); ! 1262: if (ctladdr == NULL) ! 1263: ctladdr = &e->e_from; ! 1264: /* we have to open the dfile BEFORE setuid */ ! 1265: if (e->e_dfp == NULL && e->e_df != NULL) ! 1266: { ! 1267: e->e_dfp = fopen(e->e_df, "r"); ! 1268: if (e->e_dfp == NULL) { ! 1269: syserr("mailfile: Cannot open %s for %s from %s", ! 1270: e->e_df, e->e_to, e->e_from); ! 1271: } ! 1272: } ! 1273: ! 1274: if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) ! 1275: { ! 1276: if (ctladdr->q_uid == 0) { ! 1277: (void) setgid(DefGid); ! 1278: (void) initgroups(DefUser, DefGid); ! 1279: } else { ! 1280: (void) setgid(ctladdr->q_gid); ! 1281: (void) initgroups(ctladdr->q_ruser? ! 1282: ctladdr->q_ruser: ctladdr->q_user, ! 1283: ctladdr->q_gid); ! 1284: } ! 1285: } ! 1286: if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) ! 1287: { ! 1288: if (ctladdr->q_uid == 0) ! 1289: (void) setuid(DefUid); ! 1290: else ! 1291: (void) setuid(ctladdr->q_uid); ! 1292: } ! 1293: f = dfopen(filename, "a"); ! 1294: if (f == NULL) ! 1295: exit(EX_CANTCREAT); ! 1296: ! 1297: putfromline(f, ProgMailer); ! 1298: (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); ! 1299: putline("\n", f, ProgMailer); ! 1300: (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); ! 1301: putline("\n", f, ProgMailer); ! 1302: (void) fclose(f); ! 1303: (void) fflush(stdout); ! 1304: ! 1305: /* reset ISUID & ISGID bits for paranoid systems */ ! 1306: (void) chmod(filename, (int) stb.st_mode); ! 1307: exit(EX_OK); ! 1308: /*NOTREACHED*/ ! 1309: } ! 1310: else ! 1311: { ! 1312: /* parent -- wait for exit status */ ! 1313: int st; ! 1314: ! 1315: st = waitfor(pid); ! 1316: if ((st & 0377) != 0) ! 1317: return (EX_UNAVAILABLE); ! 1318: else ! 1319: return ((st >> 8) & 0377); ! 1320: /*NOTREACHED*/ ! 1321: } ! 1322: } ! 1323: /* ! 1324: ** SENDALL -- actually send all the messages. ! 1325: ** ! 1326: ** Parameters: ! 1327: ** e -- the envelope to send. ! 1328: ** mode -- the delivery mode to use. If SM_DEFAULT, use ! 1329: ** the current SendMode. ! 1330: ** ! 1331: ** Returns: ! 1332: ** none. ! 1333: ** ! 1334: ** Side Effects: ! 1335: ** Scans the send lists and sends everything it finds. ! 1336: ** Delivers any appropriate error messages. ! 1337: ** If we are running in a non-interactive mode, takes the ! 1338: ** appropriate action. ! 1339: */ ! 1340: ! 1341: sendall(e, mode) ! 1342: ENVELOPE *e; ! 1343: char mode; ! 1344: { ! 1345: register ADDRESS *q; ! 1346: bool oldverbose; ! 1347: int pid; ! 1348: FILE *lockfp = NULL, *queueup(); ! 1349: ! 1350: /* determine actual delivery mode */ ! 1351: if (mode == SM_DEFAULT) ! 1352: { ! 1353: extern bool shouldqueue(); ! 1354: ! 1355: if (shouldqueue(e->e_msgpriority)) ! 1356: mode = SM_QUEUE; ! 1357: else ! 1358: mode = SendMode; ! 1359: } ! 1360: ! 1361: if (tTd(13, 1)) ! 1362: { ! 1363: printf("\nSENDALL: mode %c, sendqueue:\n", mode); ! 1364: printaddr(e->e_sendqueue, TRUE); ! 1365: } ! 1366: ! 1367: /* ! 1368: ** Do any preprocessing necessary for the mode we are running. ! 1369: ** Check to make sure the hop count is reasonable. ! 1370: ** Delete sends to the sender in mailing lists. ! 1371: */ ! 1372: ! 1373: CurEnv = e; ! 1374: ! 1375: if (e->e_hopcount > MAXHOP) ! 1376: { ! 1377: errno = 0; ! 1378: syserr("sendall: too many hops %d (%d max): from %s, to %s", ! 1379: e->e_hopcount, MAXHOP, e->e_from, e->e_to); ! 1380: return; ! 1381: } ! 1382: ! 1383: if (!MeToo) ! 1384: { ! 1385: extern ADDRESS *recipient(); ! 1386: ! 1387: e->e_from.q_flags |= QDONTSEND; ! 1388: (void) recipient(&e->e_from, &e->e_sendqueue); ! 1389: } ! 1390: ! 1391: # ifdef QUEUE ! 1392: if ((mode == SM_QUEUE || mode == SM_FORK || ! 1393: (mode != SM_VERIFY && SuperSafe)) && ! 1394: !bitset(EF_INQUEUE, e->e_flags)) ! 1395: lockfp = queueup(e, TRUE, mode == SM_QUEUE); ! 1396: #endif QUEUE ! 1397: ! 1398: oldverbose = Verbose; ! 1399: switch (mode) ! 1400: { ! 1401: case SM_VERIFY: ! 1402: Verbose = TRUE; ! 1403: break; ! 1404: ! 1405: case SM_QUEUE: ! 1406: e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; ! 1407: return; ! 1408: ! 1409: case SM_FORK: ! 1410: if (e->e_xfp != NULL) ! 1411: (void) fflush(e->e_xfp); ! 1412: pid = fork(); ! 1413: if (pid < 0) ! 1414: { ! 1415: mode = SM_DELIVER; ! 1416: break; ! 1417: } ! 1418: else if (pid > 0) ! 1419: { ! 1420: /* be sure we leave the temp files to our child */ ! 1421: e->e_id = e->e_df = NULL; ! 1422: if (lockfp != NULL) ! 1423: (void) fclose(lockfp); ! 1424: return; ! 1425: } ! 1426: ! 1427: /* double fork to avoid zombies */ ! 1428: if (fork() > 0) ! 1429: exit(EX_OK); ! 1430: ! 1431: /* be sure we are immune from the terminal */ ! 1432: disconnect(FALSE); ! 1433: ! 1434: break; ! 1435: } ! 1436: ! 1437: /* ! 1438: ** Run through the list and send everything. ! 1439: */ ! 1440: ! 1441: for (q = e->e_sendqueue; q != NULL; q = q->q_next) ! 1442: { ! 1443: if (mode == SM_VERIFY) ! 1444: { ! 1445: e->e_to = q->q_paddr; ! 1446: if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) ! 1447: message(Arpa_Info, "deliverable"); ! 1448: } ! 1449: else ! 1450: (void) deliver(e, q); ! 1451: } ! 1452: Verbose = oldverbose; ! 1453: ! 1454: /* ! 1455: ** Now run through and check for errors. ! 1456: */ ! 1457: ! 1458: if (mode == SM_VERIFY) { ! 1459: if (lockfp != NULL) ! 1460: (void) fclose(lockfp); ! 1461: return; ! 1462: } ! 1463: ! 1464: for (q = e->e_sendqueue; q != NULL; q = q->q_next) ! 1465: { ! 1466: register ADDRESS *qq; ! 1467: ! 1468: if (tTd(13, 3)) ! 1469: { ! 1470: printf("Checking "); ! 1471: printaddr(q, FALSE); ! 1472: } ! 1473: ! 1474: /* only send errors if the message failed */ ! 1475: if (!bitset(QBADADDR, q->q_flags)) ! 1476: continue; ! 1477: ! 1478: /* we have an address that failed -- find the parent */ ! 1479: for (qq = q; qq != NULL; qq = qq->q_alias) ! 1480: { ! 1481: char obuf[MAXNAME + 6]; ! 1482: extern char *aliaslookup(); ! 1483: ! 1484: /* we can only have owners for local addresses */ ! 1485: if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) ! 1486: continue; ! 1487: ! 1488: /* see if the owner list exists */ ! 1489: (void) strcpy(obuf, "owner-"); ! 1490: if (strncmp(qq->q_user, "owner-", 6) == 0) ! 1491: (void) strcat(obuf, "owner"); ! 1492: else ! 1493: (void) strcat(obuf, qq->q_user); ! 1494: makelower(obuf); ! 1495: if (aliaslookup(obuf) == NULL) ! 1496: continue; ! 1497: ! 1498: if (tTd(13, 4)) ! 1499: printf("Errors to %s\n", obuf); ! 1500: ! 1501: /* owner list exists -- add it to the error queue */ ! 1502: sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); ! 1503: ErrorMode = EM_MAIL; ! 1504: break; ! 1505: } ! 1506: ! 1507: /* if we did not find an owner, send to the sender */ ! 1508: if (qq == NULL && bitset(QBADADDR, q->q_flags)) ! 1509: sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); ! 1510: } ! 1511: ! 1512: /* this removes the lock on the file */ ! 1513: if (lockfp != NULL) ! 1514: (void) fclose(lockfp); ! 1515: ! 1516: if (mode == SM_FORK) ! 1517: finis(); ! 1518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.