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