1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*10133Seric SCCSID(@(#)deliver.c 3.143 01/04/83); 7405Seric 8294Seric /* 94315Seric ** DELIVER -- Deliver a message to a list of addresses. 10294Seric ** 114315Seric ** This routine delivers to everyone on the same host as the 124315Seric ** user on the head of the list. It is clever about mailers 134315Seric ** that don't handle multiple users. It is NOT guaranteed 144315Seric ** that it will deliver to all these addresses however -- so 154315Seric ** deliver should be called once for each address on the 164315Seric ** list. 174315Seric ** 18294Seric ** Parameters: 199370Seric ** e -- the envelope to deliver. 204621Seric ** firstto -- head of the address list to deliver to. 21294Seric ** 22294Seric ** Returns: 23294Seric ** zero -- successfully delivered. 24294Seric ** else -- some failure, see ExitStat for more info. 25294Seric ** 26294Seric ** Side Effects: 27294Seric ** The standard input is passed off to someone. 28294Seric */ 29294Seric 309370Seric deliver(e, firstto) 319370Seric register ENVELOPE *e; 324621Seric ADDRESS *firstto; 33294Seric { 344452Seric char *host; /* host being sent to */ 354452Seric char *user; /* user being sent to */ 36294Seric char **pvp; 373233Seric register char **mvp; 383233Seric register char *p; 399370Seric register MAILER *m; /* mailer for this recipient */ 402968Seric extern bool checkcompat(); 413233Seric char *pv[MAXPV+1]; 428225Seric char tobuf[MAXLINE-50]; /* text line of to people */ 433233Seric char buf[MAXNAME]; 444397Seric ADDRESS *ctladdr; 454397Seric extern ADDRESS *getctladdr(); 464452Seric char tfrombuf[MAXNAME]; /* translated from person */ 474452Seric extern char **prescan(); 484621Seric register ADDRESS *to = firstto; 494863Seric bool clever = FALSE; /* running user smtp to this mailer */ 505032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 518003Seric register int rcode; /* response code */ 52294Seric 534488Seric errno = 0; 547052Seric if (bitset(QDONTSEND, to->q_flags)) 553233Seric return (0); 56294Seric 576974Seric m = to->q_mailer; 586974Seric host = to->q_host; 596974Seric 60294Seric # ifdef DEBUG 617672Seric if (tTd(10, 1)) 623233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 636974Seric m->m_mno, host, to->q_user); 64294Seric # endif DEBUG 65294Seric 66294Seric /* 675903Seric ** If this mailer is expensive, and if we don't want to make 685903Seric ** connections now, just mark these addresses and return. 695903Seric ** This is useful if we want to batch connections to 705903Seric ** reduce load. This will cause the messages to be 715903Seric ** queued up, and a daemon will come along to send the 725903Seric ** messages later. 735903Seric ** This should be on a per-mailer basis. 745903Seric */ 755903Seric 768428Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags) && 778428Seric !Verbose) 785903Seric { 795903Seric for (; to != NULL; to = to->q_next) 808431Seric { 818431Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 828431Seric continue; 838431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 849370Seric e->e_to = to->q_paddr; 858496Seric message(Arpa_Info, "queued"); 868496Seric if (LogLevel > 4) 878496Seric logdelivery("queued"); 888431Seric } 899370Seric e->e_to = NULL; 905903Seric return (0); 915903Seric } 925903Seric 935903Seric /* 943233Seric ** Do initial argv setup. 953233Seric ** Insert the mailer name. Notice that $x expansion is 963233Seric ** NOT done on the mailer name. Then, if the mailer has 973233Seric ** a picky -f flag, we insert it as appropriate. This 983233Seric ** code does not check for 'pv' overflow; this places a 993233Seric ** manifest lower limit of 4 for MAXPV. 1008062Seric ** The from address rewrite is expected to make 1018062Seric ** the address relative to the other end. 1022968Seric */ 1032968Seric 1044452Seric /* rewrite from address, using rewriting rules */ 1059370Seric expand("$f", buf, &buf[sizeof buf - 1], e); 1064452Seric mvp = prescan(buf, '\0'); 1079370Seric rewrite(mvp, 3); 1089370Seric rewrite(mvp, 1); 1098062Seric rewrite(mvp, m->m_s_rwset); 1104452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 1114452Seric 1129370Seric define('g', tfrombuf, e); /* translated sender address */ 1139370Seric define('h', host, e); /* to host */ 1143233Seric Errors = 0; 1153233Seric pvp = pv; 1163233Seric *pvp++ = m->m_argv[0]; 1172968Seric 1183233Seric /* insert -f or -r flag as appropriate */ 1193233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1203233Seric { 1213233Seric if (bitset(M_FOPT, m->m_flags)) 1223233Seric *pvp++ = "-f"; 1233233Seric else 1243233Seric *pvp++ = "-r"; 1259370Seric expand("$g", buf, &buf[sizeof buf - 1], e); 1263233Seric *pvp++ = newstr(buf); 1273233Seric } 128294Seric 129294Seric /* 1303233Seric ** Append the other fixed parts of the argv. These run 1313233Seric ** up to the first entry containing "$u". There can only 1323233Seric ** be one of these, and there are only a few more slots 1333233Seric ** in the pv after it. 134294Seric */ 135294Seric 1363233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 137294Seric { 1383233Seric while ((p = index(p, '$')) != NULL) 1393233Seric if (*++p == 'u') 1403233Seric break; 1413233Seric if (p != NULL) 1423233Seric break; 1433233Seric 1443233Seric /* this entry is safe -- go ahead and process it */ 1459370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1463233Seric *pvp++ = newstr(buf); 1473233Seric if (pvp >= &pv[MAXPV - 3]) 1483233Seric { 1493233Seric syserr("Too many parameters to %s before $u", pv[0]); 1503233Seric return (-1); 1513233Seric } 152294Seric } 1534863Seric 1546038Seric /* 1556038Seric ** If we have no substitution for the user name in the argument 1566038Seric ** list, we know that we must supply the names otherwise -- and 1576038Seric ** SMTP is the answer!! 1586038Seric */ 1596038Seric 1603233Seric if (*mvp == NULL) 1614863Seric { 1624863Seric /* running SMTP */ 1635179Seric # ifdef SMTP 1644863Seric clever = TRUE; 1654863Seric *pvp = NULL; 1665179Seric # else SMTP 1676038Seric /* oops! we don't implement SMTP */ 1685179Seric syserr("SMTP style mailer"); 1695179Seric return (EX_SOFTWARE); 1705179Seric # endif SMTP 1714863Seric } 172294Seric 173294Seric /* 1743233Seric ** At this point *mvp points to the argument with $u. We 1753233Seric ** run through our address list and append all the addresses 1763233Seric ** we can. If we run out of space, do not fret! We can 1773233Seric ** always send another copy later. 178294Seric */ 179294Seric 1803233Seric tobuf[0] = '\0'; 1819370Seric e->e_to = tobuf; 1824397Seric ctladdr = NULL; 1833233Seric for (; to != NULL; to = to->q_next) 184294Seric { 1853233Seric /* avoid sending multiple recipients to dumb mailers */ 1864382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1873233Seric break; 1883233Seric 1893233Seric /* if already sent or not for this host, don't send */ 1907052Seric if (bitset(QDONTSEND, to->q_flags) || 1917052Seric strcmp(to->q_host, host) != 0 || 1927052Seric to->q_mailer != firstto->q_mailer) 1933233Seric continue; 1944397Seric 1958225Seric /* avoid overflowing tobuf */ 1969370Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 1978225Seric break; 1988225Seric 1995032Seric # ifdef DEBUG 2007672Seric if (tTd(10, 1)) 2015032Seric { 2025032Seric printf("\nsend to "); 2035032Seric printaddr(to, FALSE); 2045032Seric } 2055032Seric # endif DEBUG 2065032Seric 2074397Seric /* compute effective uid/gid when sending */ 2084596Seric if (to->q_mailer == ProgMailer) 2094397Seric ctladdr = getctladdr(to); 2104397Seric 2113233Seric user = to->q_user; 2129370Seric e->e_to = to->q_paddr; 2133233Seric to->q_flags |= QDONTSEND; 2143233Seric 2153233Seric /* 2163233Seric ** Check to see that these people are allowed to 2173233Seric ** talk to each other. 2183233Seric */ 2193233Seric 2203233Seric if (!checkcompat(to)) 221294Seric { 22210105Seric giveresponse(EX_UNAVAILABLE, m, e); 2233233Seric continue; 224294Seric } 2253233Seric 2263233Seric /* 2274099Seric ** Strip quote bits from names if the mailer is dumb 2284099Seric ** about them. 2293233Seric */ 2303233Seric 2313233Seric if (bitset(M_STRIPQ, m->m_flags)) 232294Seric { 2334099Seric stripquotes(user, TRUE); 2344099Seric stripquotes(host, TRUE); 2353233Seric } 2364099Seric else 2374099Seric { 2384099Seric stripquotes(user, FALSE); 2394099Seric stripquotes(host, FALSE); 2404099Seric } 2413233Seric 2429206Seric /* hack attack -- delivermail compatibility */ 2439206Seric if (m == ProgMailer && *user == '|') 2449206Seric user++; 2459206Seric 2463233Seric /* 2474161Seric ** If an error message has already been given, don't 2484161Seric ** bother to send to this address. 2494161Seric ** 2504161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2514161Seric ** >> NOTE >> cannot do any further aliasing; that 2524161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2534161Seric */ 2544161Seric 2557293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2564161Seric continue; 2574161Seric 2584283Seric /* save statistics.... */ 2599370Seric markstats(e, to); 2604283Seric 2614161Seric /* 2623233Seric ** See if this user name is "special". 2633233Seric ** If the user name has a slash in it, assume that this 2646974Seric ** is a file -- send it off without further ado. Note 2656974Seric ** that this type of addresses is not processed along 2666974Seric ** with the others, so we fudge on the To person. 2673233Seric */ 2683233Seric 2694596Seric if (m == LocalMailer) 2703233Seric { 2715599Seric if (user[0] == '/') 272294Seric { 2738003Seric rcode = mailfile(user, getctladdr(to)); 27410105Seric giveresponse(rcode, m, e); 2753233Seric continue; 276294Seric } 277294Seric } 2783233Seric 2794315Seric /* 2804315Seric ** Address is verified -- add this user to mailer 2814315Seric ** argv, and add it to the print list of recipients. 2824315Seric */ 2834315Seric 2846059Seric /* link together the chain of recipients */ 2856272Seric to->q_tchain = tochain; 2866272Seric tochain = to; 2876059Seric 2883233Seric /* create list of users for error messages */ 2899388Seric (void) strcat(tobuf, ","); 2904082Seric (void) strcat(tobuf, to->q_paddr); 2919370Seric define('u', user, e); /* to user */ 2929370Seric define('z', to->q_home, e); /* user's home */ 2933233Seric 2944863Seric /* 2956059Seric ** Expand out this user into argument list. 2964863Seric */ 2974863Seric 2986059Seric if (!clever) 2993233Seric { 3009370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3014863Seric *pvp++ = newstr(buf); 3024863Seric if (pvp >= &pv[MAXPV - 2]) 3034863Seric { 3044863Seric /* allow some space for trailing parms */ 3054863Seric break; 3064863Seric } 3074863Seric } 308294Seric } 309294Seric 3104067Seric /* see if any addresses still exist */ 3114067Seric if (tobuf[0] == '\0') 3124863Seric { 3139370Seric define('g', (char *) NULL, e); 3144067Seric return (0); 3154863Seric } 3164067Seric 3173233Seric /* print out messages as full list */ 3189388Seric e->e_to = tobuf + 1; 3193233Seric 320294Seric /* 3213233Seric ** Fill out any parameters after the $u parameter. 322294Seric */ 323294Seric 3244863Seric while (!clever && *++mvp != NULL) 325294Seric { 3269370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3273233Seric *pvp++ = newstr(buf); 3283233Seric if (pvp >= &pv[MAXPV]) 3293233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 330294Seric } 3313233Seric *pvp++ = NULL; 332294Seric 333294Seric /* 334294Seric ** Call the mailer. 3352898Seric ** The argument vector gets built, pipes 336294Seric ** are created as necessary, and we fork & exec as 3372898Seric ** appropriate. 3384863Seric ** If we are running SMTP, we just need to clean up. 339294Seric */ 340294Seric 3419370Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 3429370Seric 3434397Seric if (ctladdr == NULL) 3449370Seric ctladdr = &e->e_from; 3455179Seric # ifdef SMTP 3464863Seric if (clever) 3474863Seric { 3489370Seric /* send the initial SMTP protocol */ 3499370Seric rcode = smtpinit(m, pv, (ADDRESS *) NULL); 3509370Seric 3519388Seric if (rcode == EX_OK) 3529370Seric { 3539388Seric /* send the recipient list */ 3549388Seric tobuf[0] = '\0'; 3559388Seric for (to = tochain; to != NULL; to = to->q_tchain) 3569388Seric { 3579388Seric int i; 3589370Seric 3599388Seric e->e_to = to->q_paddr; 3609370Seric i = smtprcpt(to); 3619388Seric if (i != EX_OK) 3629388Seric { 36310092Seric markfailure(e, to, i); 36410105Seric giveresponse(i, m, e); 3659388Seric } 3669388Seric else 3679388Seric { 3689388Seric strcat(tobuf, ","); 3699388Seric strcat(tobuf, to->q_paddr); 3709388Seric } 3719388Seric } 3729388Seric 3739388Seric /* now send the data */ 3749388Seric if (tobuf[0] == '\0') 3759388Seric e->e_to = NULL; 3769370Seric else 3779370Seric { 3789388Seric e->e_to = tobuf + 1; 3799388Seric rcode = smtpfinish(m, e); 3809370Seric } 3819388Seric 3829388Seric /* now close the connection */ 3839388Seric smtpquit(pv[0]); 3849370Seric } 3854863Seric } 3864863Seric else 3875179Seric # endif SMTP 38810064Seric rcode = sendoff(e, m, pv, ctladdr, FALSE); 3893233Seric 3904621Seric /* 3919388Seric ** Do final status disposal. 3929388Seric ** We check for something in tobuf for the SMTP case. 3939388Seric ** If we got a temporary failure, arrange to queue the 3949388Seric ** addressees. 3954621Seric */ 3964621Seric 3979388Seric if (tobuf[0] != '\0') 39810105Seric giveresponse(rcode, m, e); 3999388Seric if (rcode != EX_OK) 4004621Seric { 4015032Seric for (to = tochain; to != NULL; to = to->q_tchain) 40210092Seric markfailure(e, to, rcode); 4034621Seric } 4044621Seric 4054488Seric errno = 0; 4069370Seric define('g', (char *) NULL, e); 4078003Seric return (rcode); 4083233Seric } 4093233Seric /* 41010092Seric ** MARKFAILURE -- mark a failure on a specific address. 41110092Seric ** 41210092Seric ** Parameters: 41310092Seric ** e -- the envelope we are sending. 41410092Seric ** q -- the address to mark. 41510092Seric ** rcode -- the code signifying the particular failure. 41610092Seric ** 41710092Seric ** Returns: 41810092Seric ** none. 41910092Seric ** 42010092Seric ** Side Effects: 42110092Seric ** marks the address (and possibly the envelope) with the 42210092Seric ** failure so that an error will be returned or 42310092Seric ** the message will be queued, as appropriate. 42410092Seric */ 42510092Seric 42610092Seric markfailure(e, q, rcode) 42710092Seric register ENVELOPE *e; 42810092Seric register ADDRESS *q; 42910092Seric int rcode; 43010092Seric { 43110092Seric if (rcode == EX_OK) 43210092Seric return; 43310092Seric else if (rcode != EX_TEMPFAIL) 43410092Seric q->q_flags |= QBADADDR; 43510092Seric else if (curtime() > e->e_ctime + TimeOut) 43610092Seric { 43710092Seric extern char *pintvl(); 43810105Seric char buf[MAXLINE]; 43910092Seric 44010092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 44110105Seric { 44210105Seric (void) sprintf(buf, "Cannot send message for %s", 44310092Seric pintvl(TimeOut, FALSE)); 44410105Seric if (e->e_message != NULL) 44510105Seric free(e->e_message); 44610105Seric e->e_message = newstr(buf); 44710105Seric message(Arpa_Info, buf); 44810105Seric } 44910092Seric q->q_flags |= QBADADDR; 45010092Seric e->e_flags |= EF_TIMEOUT; 45110092Seric } 45210092Seric else 45310092Seric q->q_flags |= QQUEUEUP; 45410092Seric } 45510092Seric /* 4564214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4574214Seric ** 4584214Seric ** This MUST be a macro, since after a vfork we are running 4594214Seric ** two processes on the same stack!!! 4604214Seric ** 4614214Seric ** Parameters: 4624214Seric ** none. 4634214Seric ** 4644214Seric ** Returns: 4654214Seric ** From a macro??? You've got to be kidding! 4664214Seric ** 4674214Seric ** Side Effects: 4684214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4694214Seric ** pid of child in parent, zero in child. 4704214Seric ** -1 on unrecoverable error. 4714214Seric ** 4724214Seric ** Notes: 4734214Seric ** I'm awfully sorry this looks so awful. That's 4744214Seric ** vfork for you..... 4754214Seric */ 4764214Seric 4774214Seric # define NFORKTRIES 5 4789148Seric # ifdef VMUNIX 4794214Seric # define XFORK vfork 4809148Seric # else VMUNIX 4814214Seric # define XFORK fork 4829148Seric # endif VMUNIX 4834214Seric 4844214Seric # define DOFORK(fORKfN) \ 4854214Seric {\ 4864214Seric register int i;\ 4874214Seric \ 4884214Seric for (i = NFORKTRIES; i-- > 0; )\ 4894214Seric {\ 4904214Seric pid = fORKfN();\ 4914214Seric if (pid >= 0)\ 4924214Seric break;\ 4937003Seric sleep(NFORKTRIES - i);\ 4944214Seric }\ 4954214Seric } 4964214Seric /* 4974637Seric ** DOFORK -- simple fork interface to DOFORK. 4984637Seric ** 4994637Seric ** Parameters: 5004637Seric ** none. 5014637Seric ** 5024637Seric ** Returns: 5034637Seric ** pid of child in parent. 5044637Seric ** zero in child. 5054637Seric ** -1 on error. 5064637Seric ** 5074637Seric ** Side Effects: 5084637Seric ** returns twice, once in parent and once in child. 5094637Seric */ 5104637Seric 5114637Seric dofork() 5124637Seric { 5134637Seric register int pid; 5144637Seric 5154637Seric DOFORK(fork); 5164637Seric return (pid); 5174637Seric } 5184637Seric /* 5193233Seric ** SENDOFF -- send off call to mailer & collect response. 5203233Seric ** 5213233Seric ** Parameters: 5229370Seric ** e -- the envelope to mail. 5233233Seric ** m -- mailer descriptor. 5243233Seric ** pvp -- parameter vector to send to it. 5254397Seric ** ctladdr -- an address pointer controlling the 5264397Seric ** user/groupid etc. of the mailer. 52710064Seric ** crlf -- set if we want CRLF on the end of lines. 5283233Seric ** 5293233Seric ** Returns: 5303233Seric ** exit status of mailer. 5313233Seric ** 5323233Seric ** Side Effects: 5333233Seric ** none. 5343233Seric */ 5353233Seric 53610064Seric sendoff(e, m, pvp, ctladdr, crlf) 5379370Seric register ENVELOPE *e; 5389370Seric MAILER *m; 5393233Seric char **pvp; 5404397Seric ADDRESS *ctladdr; 54110064Seric bool crlf; 5423233Seric { 5434863Seric auto FILE *mfile; 5444863Seric auto FILE *rfile; 5453233Seric register int i; 5463233Seric int pid; 5474863Seric 5484863Seric /* 5494863Seric ** Create connection to mailer. 5504863Seric */ 5514863Seric 5524863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5534863Seric if (pid < 0) 5544863Seric return (-1); 5554863Seric 5564863Seric /* 5574863Seric ** Format and send message. 5584863Seric */ 5594863Seric 56010064Seric putfromline(mfile, m, crlf); 56110064Seric (*e->e_puthdr)(mfile, m, e, crlf); 5626974Seric fprintf(mfile, "\n"); 56310064Seric (*e->e_putbody)(mfile, m, FALSE, e, crlf); 5644863Seric (void) fclose(mfile); 5654863Seric 5664863Seric i = endmailer(pid, pvp[0]); 5675981Seric 5685981Seric /* arrange a return receipt if requested */ 5699370Seric if (e->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 5705981Seric { 5719370Seric e->e_flags |= EF_SENDRECEIPT; 5725981Seric /* do we want to send back more info? */ 5735981Seric } 5745981Seric 5754863Seric return (i); 5764863Seric } 5774863Seric /* 5784863Seric ** ENDMAILER -- Wait for mailer to terminate. 5794863Seric ** 5804863Seric ** We should never get fatal errors (e.g., segmentation 5814863Seric ** violation), so we report those specially. For other 5824863Seric ** errors, we choose a status message (into statmsg), 5834863Seric ** and if it represents an error, we print it. 5844863Seric ** 5854863Seric ** Parameters: 5864863Seric ** pid -- pid of mailer. 5874863Seric ** name -- name of mailer (for error messages). 5884863Seric ** 5894863Seric ** Returns: 5904863Seric ** exit code of mailer. 5914863Seric ** 5924863Seric ** Side Effects: 5934863Seric ** none. 5944863Seric */ 5954863Seric 5964863Seric endmailer(pid, name) 5974863Seric int pid; 5984863Seric char *name; 5994863Seric { 6009370Seric int st; 6014863Seric 6026038Seric /* in the IPC case there is nothing to wait for */ 6036038Seric if (pid == 0) 6046038Seric return (EX_OK); 6056038Seric 6066038Seric /* wait for the mailer process to die and collect status */ 6079370Seric st = waitfor(pid); 6089370Seric if (st == -1) 6098127Seric { 6109370Seric syserr("endmailer %s: wait", name); 6119370Seric return (EX_SOFTWARE); 6124863Seric } 6136038Seric 6146038Seric /* see if it died a horrid death */ 6154863Seric if ((st & 0377) != 0) 6164863Seric { 6179370Seric syserr("endmailer %s: stat %o", name, st); 6184863Seric ExitStat = EX_UNAVAILABLE; 6199370Seric return (EX_UNAVAILABLE); 6204863Seric } 6216038Seric 6226038Seric /* normal death -- return status */ 6239370Seric st = (st >> 8) & 0377; 6249370Seric return (st); 6254863Seric } 6264863Seric /* 6274863Seric ** OPENMAILER -- open connection to mailer. 6284863Seric ** 6294863Seric ** Parameters: 6304863Seric ** m -- mailer descriptor. 6314863Seric ** pvp -- parameter vector to pass to mailer. 6324863Seric ** ctladdr -- controlling address for user. 6334863Seric ** clever -- create a full duplex connection. 6344863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6354863Seric ** prfile -- pointer to rfile (from mailer) connection. 6364863Seric ** 6374863Seric ** Returns: 6386038Seric ** pid of mailer ( > 0 ). 6394863Seric ** -1 on error. 6406038Seric ** zero on an IPC connection. 6414863Seric ** 6424863Seric ** Side Effects: 6434863Seric ** creates a mailer in a subprocess. 6444863Seric */ 6454863Seric 6464863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6479370Seric MAILER *m; 6484863Seric char **pvp; 6494863Seric ADDRESS *ctladdr; 6504863Seric bool clever; 6514863Seric FILE **pmfile; 6524863Seric FILE **prfile; 6534863Seric { 6544863Seric int pid; 6554709Seric int mpvect[2]; 6564863Seric int rpvect[2]; 6573233Seric FILE *mfile; 6584863Seric FILE *rfile; 6593233Seric extern FILE *fdopen(); 6603233Seric 6613233Seric # ifdef DEBUG 6627672Seric if (tTd(11, 1)) 663294Seric { 6648178Seric printf("openmailer:"); 6653233Seric printav(pvp); 666294Seric } 6673233Seric # endif DEBUG 6684488Seric errno = 0; 6693233Seric 6706038Seric /* 6716038Seric ** Deal with the special case of mail handled through an IPC 6726038Seric ** connection. 6736038Seric ** In this case we don't actually fork. We must be 6746038Seric ** running SMTP for this to work. We will return a 6756038Seric ** zero pid to indicate that we are running IPC. 6766038Seric */ 6776038Seric 6786038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6796038Seric { 6809370Seric #ifdef DAEMON 6816038Seric register int i; 6827285Seric register u_short port; 6836038Seric 6846038Seric if (!clever) 6856038Seric syserr("non-clever IPC"); 6866632Seric if (pvp[2] != NULL) 6877285Seric port = atoi(pvp[2]); 6886632Seric else 6897285Seric port = 0; 6907285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 6916038Seric if (i != EX_OK) 6926047Seric { 6936047Seric ExitStat = i; 6946038Seric return (-1); 6956047Seric } 6966038Seric else 6976038Seric return (0); 6989370Seric #else DAEMON 6999370Seric syserr("openmailer: no IPC"); 7009370Seric return (-1); 7019370Seric #endif DAEMON 7026038Seric } 7036038Seric 7042898Seric /* create a pipe to shove the mail through */ 7054709Seric if (pipe(mpvect) < 0) 706294Seric { 7079370Seric syserr("openmailer: pipe (to mailer)"); 708294Seric return (-1); 709294Seric } 7104863Seric 7119370Seric #ifdef SMTP 7124863Seric /* if this mailer speaks smtp, create a return pipe */ 7134863Seric if (clever && pipe(rpvect) < 0) 7144863Seric { 7159370Seric syserr("openmailer: pipe (from mailer)"); 7164863Seric (void) close(mpvect[0]); 7174863Seric (void) close(mpvect[1]); 7184863Seric return (-1); 7194863Seric } 7209370Seric #endif SMTP 7214863Seric 7226038Seric /* 7236038Seric ** Actually fork the mailer process. 7246038Seric ** DOFORK is clever about retrying. 7256038Seric */ 7266038Seric 7279538Seric if (CurEnv->e_xfp != NULL) 7289538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7299370Seric (void) fflush(stdout); 7304214Seric DOFORK(XFORK); 7314327Seric /* pid is set by DOFORK */ 732294Seric if (pid < 0) 733294Seric { 7346038Seric /* failure */ 7359370Seric syserr("openmailer: cannot fork"); 7364709Seric (void) close(mpvect[0]); 7374709Seric (void) close(mpvect[1]); 7389370Seric #ifdef SMTP 7394863Seric if (clever) 7404863Seric { 7414863Seric (void) close(rpvect[0]); 7424863Seric (void) close(rpvect[1]); 7434863Seric } 7449370Seric #endif SMTP 745294Seric return (-1); 746294Seric } 747294Seric else if (pid == 0) 748294Seric { 749294Seric /* child -- set up input & exec mailer */ 7501621Seric /* make diagnostic output be standard output */ 7514477Seric (void) signal(SIGINT, SIG_IGN); 7524477Seric (void) signal(SIGHUP, SIG_IGN); 7534215Seric (void) signal(SIGTERM, SIG_DFL); 7544709Seric 7554709Seric /* arrange to filter standard & diag output of command */ 7564863Seric if (clever) 7574709Seric { 7584863Seric (void) close(rpvect[0]); 7594709Seric (void) close(1); 7604863Seric (void) dup(rpvect[1]); 7614863Seric (void) close(rpvect[1]); 7624863Seric } 7639275Seric else if (OpMode == MD_SMTP || HoldErrs) 7644863Seric { 7659370Seric /* put mailer output in transcript */ 7664863Seric (void) close(1); 7679538Seric (void) dup(fileno(CurEnv->e_xfp)); 7684709Seric } 7694082Seric (void) close(2); 7704082Seric (void) dup(1); 7714709Seric 7724709Seric /* arrange to get standard input */ 7734709Seric (void) close(mpvect[1]); 7744082Seric (void) close(0); 7754709Seric if (dup(mpvect[0]) < 0) 776294Seric { 7772898Seric syserr("Cannot dup to zero!"); 7782898Seric _exit(EX_OSERR); 779294Seric } 7804709Seric (void) close(mpvect[0]); 7812968Seric if (!bitset(M_RESTR, m->m_flags)) 7824215Seric { 7834417Seric if (ctladdr->q_uid == 0) 7844417Seric { 7854417Seric (void) setgid(DefGid); 7864417Seric (void) setuid(DefUid); 7874417Seric } 7884417Seric else 7894415Seric { 7904417Seric (void) setgid(ctladdr->q_gid); 7914417Seric (void) setuid(ctladdr->q_uid); 7924415Seric } 7934215Seric } 7949370Seric 7952774Seric /* 7962774Seric ** We have to be careful with vfork - we can't mung up the 7972774Seric ** memory but we don't want the mailer to inherit any extra 7982774Seric ** open files. Chances are the mailer won't 7992774Seric ** care about an extra file, but then again you never know. 8002774Seric ** Actually, we would like to close(fileno(pwf)), but it's 8012774Seric ** declared static so we can't. But if we fclose(pwf), which 8022774Seric ** is what endpwent does, it closes it in the parent too and 8032774Seric ** the next getpwnam will be slower. If you have a weird 8042774Seric ** mailer that chokes on the extra file you should do the 8059148Seric ** endpwent(). -MRH 8062774Seric ** 8072774Seric ** Similar comments apply to log. However, openlog is 8082774Seric ** clever enough to set the FIOCLEX mode on the file, 8092774Seric ** so it will be closed automatically on the exec. 8102774Seric */ 8112774Seric 8129370Seric closeall(); 8136038Seric 8146038Seric /* try to execute the mailer */ 815294Seric execv(m->m_mailer, pvp); 8166038Seric 817294Seric /* syserr fails because log is closed */ 818294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 8194214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 8204082Seric (void) fflush(stdout); 8211619Seric _exit(EX_UNAVAILABLE); 822294Seric } 823294Seric 8244709Seric /* 8254863Seric ** Set up return value. 8264709Seric */ 8274709Seric 8284709Seric (void) close(mpvect[0]); 8294709Seric mfile = fdopen(mpvect[1], "w"); 8304863Seric if (clever) 8314863Seric { 8324863Seric (void) close(rpvect[1]); 8334863Seric rfile = fdopen(rpvect[0], "r"); 8344863Seric } 835294Seric 8364863Seric *pmfile = mfile; 8374863Seric *prfile = rfile; 838294Seric 8394863Seric return (pid); 840294Seric } 841294Seric /* 842294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 843294Seric ** 844294Seric ** Parameters: 845294Seric ** stat -- the status code from the mailer (high byte 846294Seric ** only; core dumps must have been taken care of 847294Seric ** already). 848294Seric ** m -- the mailer descriptor for this mailer. 849294Seric ** 850294Seric ** Returns: 8514082Seric ** none. 852294Seric ** 853294Seric ** Side Effects: 8541518Seric ** Errors may be incremented. 855294Seric ** ExitStat may be set. 856294Seric */ 857294Seric 8589370Seric /*ARGSUSED*/ 85910105Seric giveresponse(stat, m, e) 860294Seric int stat; 8619370Seric register MAILER *m; 86210105Seric ENVELOPE *e; 863294Seric { 864294Seric register char *statmsg; 865294Seric extern char *SysExMsg[]; 866294Seric register int i; 867294Seric extern int N_SysEx; 86810105Seric char buf[MAXLINE]; 869294Seric 8704315Seric /* 8714315Seric ** Compute status message from code. 8724315Seric */ 8734315Seric 874294Seric i = stat - EX__BASE; 8759370Seric if (stat == 0) 8769370Seric statmsg = "250 Sent"; 8779370Seric else if (i < 0 || i > N_SysEx) 8789370Seric { 8799370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 8809370Seric stat = EX_UNAVAILABLE; 8819370Seric statmsg = buf; 8829370Seric } 88310105Seric else if (stat == EX_TEMPFAIL) 88410105Seric { 88510105Seric extern char *sys_errlist[]; 88610105Seric extern int sys_nerr; 88710105Seric 88810124Seric (void) strcpy(buf, SysExMsg[i]); 88910124Seric if (errno != 0) 89010105Seric { 89110124Seric (void) strcat(buf, ": "); 89210124Seric if (errno > 0 && errno < sys_nerr) 89310124Seric (void) strcat(buf, sys_errlist[errno]); 89410124Seric else 89510124Seric { 89610124Seric char xbuf[30]; 89710124Seric 89810124Seric (void) sprintf(xbuf, "Error %d", errno); 89910124Seric (void) strcat(buf, xbuf); 90010124Seric } 90110105Seric } 90210105Seric statmsg = buf; 90310105Seric } 904294Seric else 905294Seric statmsg = SysExMsg[i]; 9069370Seric 9079370Seric /* 9089370Seric ** Print the message as appropriate 9099370Seric */ 9109370Seric 91110105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 9128003Seric message(Arpa_Info, &statmsg[4]); 913294Seric else 914294Seric { 9151518Seric Errors++; 9169370Seric usrerr(statmsg); 917294Seric } 918294Seric 919294Seric /* 920294Seric ** Final cleanup. 921294Seric ** Log a record of the transaction. Compute the new 922294Seric ** ExitStat -- if we already had an error, stick with 923294Seric ** that. 924294Seric */ 925294Seric 9267680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 9278496Seric logdelivery(&statmsg[4]); 9287858Seric 9294621Seric if (stat != EX_TEMPFAIL) 9304621Seric setstat(stat); 93110105Seric if (stat != EX_OK) 93210105Seric { 93310105Seric if (e->e_message != NULL) 93410105Seric free(e->e_message); 93510105Seric e->e_message = newstr(&statmsg[4]); 93610105Seric } 93710124Seric errno = 0; 938294Seric } 939294Seric /* 9408496Seric ** LOGDELIVERY -- log the delivery in the system log 9418496Seric ** 9428496Seric ** Parameters: 9438496Seric ** stat -- the message to print for the status 9448496Seric ** 9458496Seric ** Returns: 9468496Seric ** none 9478496Seric ** 9488496Seric ** Side Effects: 9498496Seric ** none 9508496Seric */ 9518496Seric 9528496Seric logdelivery(stat) 9538496Seric char *stat; 9548496Seric { 9558496Seric extern char *pintvl(); 9568496Seric 9578496Seric # ifdef LOG 9588496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 9598496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 9608496Seric # endif LOG 9618496Seric } 9628496Seric /* 9636974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 964294Seric ** 9656974Seric ** This can be made an arbitrary message separator by changing $l 966294Seric ** 9676974Seric ** One of the ugliest hacks seen by human eyes is 9686974Seric ** contained herein: UUCP wants those stupid 9699370Seric ** "emote from <host>" lines. Why oh why does a 9706974Seric ** well-meaning programmer such as myself have to 9716974Seric ** deal with this kind of antique garbage???? 9726974Seric ** 973294Seric ** Parameters: 9746974Seric ** fp -- the file to output to. 9756974Seric ** m -- the mailer describing this entry. 97610064Seric ** crlf -- set if we want a CRLF at the end of the line. 977294Seric ** 978294Seric ** Returns: 9796974Seric ** none 980294Seric ** 981294Seric ** Side Effects: 9826974Seric ** outputs some text to fp. 983294Seric */ 984294Seric 98510064Seric putfromline(fp, m, crlf) 9866974Seric register FILE *fp; 9876974Seric register MAILER *m; 988294Seric { 9896974Seric char buf[MAXLINE]; 990294Seric 9916974Seric if (bitset(M_NHDR, m->m_flags)) 9926974Seric return; 9934315Seric 9946974Seric # ifdef UGLYUUCP 9956974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9964205Seric { 9976974Seric extern char *macvalue(); 9988178Seric char *sys = macvalue('g', CurEnv); 9996974Seric char *bang = index(sys, '!'); 10006041Seric 10016974Seric if (bang == NULL) 10026974Seric syserr("No ! in UUCP! (%s)", sys); 10035099Seric else 10049370Seric { 10056974Seric *bang = '\0'; 10069370Seric expand("From $f $d remote from $g\n", buf, 10079370Seric &buf[sizeof buf - 1], CurEnv); 10089370Seric *bang = '!'; 10099370Seric } 10106974Seric } 10116974Seric else 10125179Seric # endif UGLYUUCP 10136974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 101410064Seric putline(buf, fp, crlf, bitset(M_FULLSMTP, m->m_flags)); 10155981Seric } 10165981Seric /* 10176974Seric ** PUTBODY -- put the body of a message. 10186974Seric ** 10196974Seric ** Parameters: 10206974Seric ** fp -- file to output onto. 10216974Seric ** m -- a mailer descriptor. 10226974Seric ** xdot -- if set, use SMTP hidden dot algorithm. 10239538Seric ** e -- the envelope to put out. 10246974Seric ** 10256974Seric ** Returns: 10266974Seric ** none. 10276974Seric ** 10286974Seric ** Side Effects: 10296974Seric ** The message is written onto fp. 10306974Seric */ 10316974Seric 103210064Seric putbody(fp, m, xdot, e, crlf) 10336974Seric FILE *fp; 10349370Seric MAILER *m; 10356974Seric bool xdot; 10369538Seric register ENVELOPE *e; 10376974Seric { 10386974Seric char buf[MAXLINE + 1]; 10397123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 10406974Seric 10416974Seric /* 10426974Seric ** Output the body of the message 10436974Seric */ 10446974Seric 10459538Seric if (e->e_dfp == NULL) 10466974Seric { 10479538Seric if (e->e_df != NULL) 10489538Seric { 10499538Seric e->e_dfp = fopen(e->e_df, "r"); 10509538Seric if (e->e_dfp == NULL) 10519538Seric syserr("Cannot open %s", e->e_df); 10529538Seric } 10539538Seric else 105410064Seric putline("<<< No Message Collected >>>", fp, crlf, fullsmtp); 10559538Seric } 10569538Seric if (e->e_dfp != NULL) 10579538Seric { 10589538Seric rewind(e->e_dfp); 10596974Seric buf[0] = '.'; 10609538Seric while (!ferror(fp) && 10619538Seric fgets(&buf[1], sizeof buf - 1, e->e_dfp) != NULL) 10629538Seric { 106310064Seric putline((xdot && buf[1] == '.') ? buf : &buf[1], fp, crlf, fullsmtp); 10649538Seric } 10656974Seric 10669538Seric if (ferror(e->e_dfp)) 10676974Seric { 10686974Seric syserr("putbody: read error"); 10696974Seric ExitStat = EX_IOERR; 10706974Seric } 10716974Seric } 10726974Seric 10736974Seric (void) fflush(fp); 10746974Seric if (ferror(fp) && errno != EPIPE) 10756974Seric { 10766974Seric syserr("putbody: write error"); 10776974Seric ExitStat = EX_IOERR; 10786974Seric } 10796974Seric errno = 0; 10806974Seric } 10816974Seric /* 1082294Seric ** MAILFILE -- Send a message to a file. 1083294Seric ** 10844327Seric ** If the file has the setuid/setgid bits set, but NO execute 10854327Seric ** bits, sendmail will try to become the owner of that file 10864327Seric ** rather than the real user. Obviously, this only works if 10874327Seric ** sendmail runs as root. 10884327Seric ** 10899370Seric ** This could be done as a subordinate mailer, except that it 10909370Seric ** is used implicitly to save messages in ~/dead.letter. We 10919370Seric ** view this as being sufficiently important as to include it 10929370Seric ** here. For example, if the system is dying, we shouldn't have 10939370Seric ** to create another process plus some pipes to save the message. 10949370Seric ** 1095294Seric ** Parameters: 1096294Seric ** filename -- the name of the file to send to. 10974397Seric ** ctladdr -- the controlling address header -- includes 10984397Seric ** the userid/groupid to be when sending. 1099294Seric ** 1100294Seric ** Returns: 1101294Seric ** The exit code associated with the operation. 1102294Seric ** 1103294Seric ** Side Effects: 1104294Seric ** none. 1105294Seric */ 1106294Seric 11074397Seric mailfile(filename, ctladdr) 1108294Seric char *filename; 11094397Seric ADDRESS *ctladdr; 1110294Seric { 1111294Seric register FILE *f; 11124214Seric register int pid; 1113294Seric 11144214Seric /* 11154214Seric ** Fork so we can change permissions here. 11164214Seric ** Note that we MUST use fork, not vfork, because of 11174214Seric ** the complications of calling subroutines, etc. 11184214Seric */ 11194067Seric 11204214Seric DOFORK(fork); 11214214Seric 11224214Seric if (pid < 0) 11234214Seric return (EX_OSERR); 11244214Seric else if (pid == 0) 11254214Seric { 11264214Seric /* child -- actually write to file */ 11274327Seric struct stat stb; 11284327Seric 11294215Seric (void) signal(SIGINT, SIG_DFL); 11304215Seric (void) signal(SIGHUP, SIG_DFL); 11314215Seric (void) signal(SIGTERM, SIG_DFL); 11324327Seric umask(OldUmask); 11334327Seric if (stat(filename, &stb) < 0) 11344431Seric stb.st_mode = 0666; 11354327Seric if (bitset(0111, stb.st_mode)) 11364327Seric exit(EX_CANTCREAT); 11374401Seric if (ctladdr == NULL) 11386900Seric ctladdr = &CurEnv->e_from; 11394327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 11404417Seric { 11414417Seric if (ctladdr->q_uid == 0) 11424417Seric (void) setgid(DefGid); 11434417Seric else 11444417Seric (void) setgid(ctladdr->q_gid); 11454417Seric } 11464327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 11474417Seric { 11484417Seric if (ctladdr->q_uid == 0) 11494417Seric (void) setuid(DefUid); 11504417Seric else 11514417Seric (void) setuid(ctladdr->q_uid); 11524417Seric } 11536887Seric f = dfopen(filename, "a"); 11544214Seric if (f == NULL) 11554214Seric exit(EX_CANTCREAT); 11564214Seric 115710064Seric putfromline(f, ProgMailer, FALSE); 115810064Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv, FALSE); 11597123Seric fputs("\n", f); 116010064Seric (*CurEnv->e_putbody)(f, ProgMailer, FALSE, CurEnv, FALSE); 11614214Seric fputs("\n", f); 11624214Seric (void) fclose(f); 11634214Seric (void) fflush(stdout); 11644417Seric 11656887Seric /* reset ISUID & ISGID bits for paranoid systems */ 11664621Seric (void) chmod(filename, (int) stb.st_mode); 11674214Seric exit(EX_OK); 11684315Seric /*NOTREACHED*/ 11694214Seric } 11704214Seric else 11714214Seric { 11724214Seric /* parent -- wait for exit status */ 11739370Seric int st; 11744214Seric 11759370Seric st = waitfor(pid); 11769370Seric if ((st & 0377) != 0) 11779370Seric return (EX_UNAVAILABLE); 11789370Seric else 11799370Seric return ((st >> 8) & 0377); 11804214Seric } 1181294Seric } 11824550Seric /* 11834550Seric ** SENDALL -- actually send all the messages. 11844550Seric ** 11854550Seric ** Parameters: 11867043Seric ** e -- the envelope to send. 11879275Seric ** mode -- the delivery mode to use. 11884550Seric ** 11894550Seric ** Returns: 11904550Seric ** none. 11914550Seric ** 11924550Seric ** Side Effects: 11934550Seric ** Scans the send lists and sends everything it finds. 11947043Seric ** Delivers any appropriate error messages. 11959275Seric ** If we are running in a non-interactive mode, takes the 11969275Seric ** appropriate action. 11974550Seric */ 11984550Seric 11999275Seric sendall(e, mode) 12007043Seric ENVELOPE *e; 12019275Seric char mode; 12024550Seric { 12035008Seric register ADDRESS *q; 12047779Seric bool oldverbose; 12059275Seric int pid; 12064550Seric 12079370Seric #ifdef DEBUG 12088248Seric if (tTd(13, 1)) 12095032Seric { 12109275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 12117043Seric printaddr(e->e_sendqueue, TRUE); 12125032Seric } 12139370Seric #endif DEBUG 12145008Seric 12157043Seric /* 12169275Seric ** Do any preprocessing necessary for the mode we are running. 12179370Seric ** Check to make sure the hop count is reasonable. 12189370Seric ** Delete sends to the sender in mailing lists. 12197043Seric */ 12207043Seric 12219370Seric CurEnv = e; 12229370Seric 12239370Seric if (e->e_hopcount > MAXHOP) 12249275Seric { 12259370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 12269370Seric return; 12279370Seric } 12289275Seric 12299370Seric if (!MeToo) 12309370Seric { 12319370Seric e->e_from.q_flags |= QDONTSEND; 12329370Seric recipient(&e->e_from, &e->e_sendqueue); 12339275Seric } 12349370Seric 12359370Seric # ifdef QUEUE 12369335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 12379335Seric (mode != SM_VERIFY && SuperSafe)) && 12389335Seric !bitset(EF_INQUEUE, e->e_flags)) 12399370Seric queueup(e, TRUE, mode == SM_QUEUE); 12409275Seric #endif QUEUE 12419275Seric 12427779Seric oldverbose = Verbose; 12439275Seric switch (mode) 12449275Seric { 12459275Seric case SM_VERIFY: 12467779Seric Verbose = TRUE; 12479275Seric break; 12489275Seric 12499275Seric case SM_QUEUE: 12509335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 12519275Seric return; 12529275Seric 12539275Seric case SM_FORK: 12549538Seric if (e->e_xfp != NULL) 12559538Seric (void) fflush(e->e_xfp); 12569275Seric pid = fork(); 12579275Seric if (pid < 0) 12589275Seric { 12599275Seric mode = SM_DELIVER; 12609275Seric break; 12619275Seric } 12629275Seric else if (pid > 0) 12639293Seric { 12649293Seric /* be sure we leave the temp files to our child */ 12659335Seric e->e_id = e->e_df = NULL; 12669275Seric return; 12679293Seric } 12689275Seric 12699275Seric /* double fork to avoid zombies */ 12709275Seric if (fork() > 0) 12719275Seric exit(EX_OK); 12729275Seric 12739293Seric /* be sure we are immune from the terminal */ 1274*10133Seric disconnect(FALSE); 12759293Seric 12769275Seric break; 12779275Seric } 12789275Seric 12799275Seric /* 12809275Seric ** Run through the list and send everything. 12819275Seric */ 12829275Seric 12837043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12844550Seric { 12859275Seric if (mode == SM_VERIFY) 12864550Seric { 12879293Seric e->e_to = q->q_paddr; 12885008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 12897052Seric message(Arpa_Info, "deliverable"); 12904550Seric } 12915008Seric else 12929370Seric (void) deliver(e, q); 12934550Seric } 12947779Seric Verbose = oldverbose; 12957043Seric 12967043Seric /* 12977043Seric ** Now run through and check for errors. 12987043Seric */ 12997043Seric 13009275Seric if (mode == SM_VERIFY) 13017043Seric return; 13027043Seric 13037043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13047043Seric { 13057043Seric register ADDRESS *qq; 13067043Seric 13078248Seric # ifdef DEBUG 13088248Seric if (tTd(13, 3)) 13098248Seric { 13108248Seric printf("Checking "); 13118248Seric printaddr(q, FALSE); 13128248Seric } 13138248Seric # endif DEBUG 13148248Seric 13159335Seric /* only send errors if the message failed */ 13169335Seric if (!bitset(QBADADDR, q->q_flags)) 13179335Seric continue; 13187043Seric 13197043Seric /* we have an address that failed -- find the parent */ 13207043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 13217043Seric { 13227043Seric char obuf[MAXNAME + 6]; 13237043Seric extern char *aliaslookup(); 13247043Seric 13257043Seric /* we can only have owners for local addresses */ 13267043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 13277043Seric continue; 13287043Seric 13297043Seric /* see if the owner list exists */ 13307043Seric (void) strcpy(obuf, "owner-"); 13317047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 13327047Seric (void) strcat(obuf, "owner"); 13337047Seric else 13347047Seric (void) strcat(obuf, qq->q_user); 13357043Seric if (aliaslookup(obuf) == NULL) 13367043Seric continue; 13377043Seric 13388248Seric # ifdef DEBUG 13398248Seric if (tTd(13, 4)) 13408248Seric printf("Errors to %s\n", obuf); 13418248Seric # endif DEBUG 13428248Seric 13437043Seric /* owner list exists -- add it to the error queue */ 13449615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 13459370Seric ErrorMode == EM_MAIL; 13467043Seric break; 13477043Seric } 13487043Seric 13497043Seric /* if we did not find an owner, send to the sender */ 13508426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 13519615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 13527043Seric } 13539275Seric 13549275Seric if (mode == SM_FORK) 13559275Seric finis(); 13564550Seric } 1357