1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*11935Seric SCCSID(@(#)deliver.c 3.150 04/17/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; 3910306Seric register MAILER *m; /* mailer for this recipient */ 404397Seric ADDRESS *ctladdr; 414621Seric register ADDRESS *to = firstto; 424863Seric bool clever = FALSE; /* running user smtp to this mailer */ 435032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 448003Seric register int rcode; /* response code */ 4510306Seric char *pv[MAXPV+1]; 4610306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 4710306Seric char buf[MAXNAME]; 4810306Seric char tfrombuf[MAXNAME]; /* translated from person */ 4910306Seric extern bool checkcompat(); 5010306Seric extern ADDRESS *getctladdr(); 5110306Seric extern char *remotename(); 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 7610682Seric if (NoConnect && !QueueRun && bitnset(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); 10610306Seric (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); 1074452Seric 1089370Seric define('g', tfrombuf, e); /* translated sender address */ 1099370Seric define('h', host, e); /* to host */ 1103233Seric Errors = 0; 1113233Seric pvp = pv; 1123233Seric *pvp++ = m->m_argv[0]; 1132968Seric 1143233Seric /* insert -f or -r flag as appropriate */ 11510682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1163233Seric { 11710682Seric if (bitnset(M_FOPT, m->m_flags)) 1183233Seric *pvp++ = "-f"; 1193233Seric else 1203233Seric *pvp++ = "-r"; 1219370Seric expand("$g", buf, &buf[sizeof buf - 1], e); 1223233Seric *pvp++ = newstr(buf); 1233233Seric } 124294Seric 125294Seric /* 1263233Seric ** Append the other fixed parts of the argv. These run 1273233Seric ** up to the first entry containing "$u". There can only 1283233Seric ** be one of these, and there are only a few more slots 1293233Seric ** in the pv after it. 130294Seric */ 131294Seric 1323233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 133294Seric { 1343233Seric while ((p = index(p, '$')) != NULL) 1353233Seric if (*++p == 'u') 1363233Seric break; 1373233Seric if (p != NULL) 1383233Seric break; 1393233Seric 1403233Seric /* this entry is safe -- go ahead and process it */ 1419370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1423233Seric *pvp++ = newstr(buf); 1433233Seric if (pvp >= &pv[MAXPV - 3]) 1443233Seric { 1453233Seric syserr("Too many parameters to %s before $u", pv[0]); 1463233Seric return (-1); 1473233Seric } 148294Seric } 1494863Seric 1506038Seric /* 1516038Seric ** If we have no substitution for the user name in the argument 1526038Seric ** list, we know that we must supply the names otherwise -- and 1536038Seric ** SMTP is the answer!! 1546038Seric */ 1556038Seric 1563233Seric if (*mvp == NULL) 1574863Seric { 1584863Seric /* running SMTP */ 1595179Seric # ifdef SMTP 1604863Seric clever = TRUE; 1614863Seric *pvp = NULL; 1625179Seric # else SMTP 1636038Seric /* oops! we don't implement SMTP */ 1645179Seric syserr("SMTP style mailer"); 1655179Seric return (EX_SOFTWARE); 1665179Seric # endif SMTP 1674863Seric } 168294Seric 169294Seric /* 1703233Seric ** At this point *mvp points to the argument with $u. We 1713233Seric ** run through our address list and append all the addresses 1723233Seric ** we can. If we run out of space, do not fret! We can 1733233Seric ** always send another copy later. 174294Seric */ 175294Seric 1763233Seric tobuf[0] = '\0'; 1779370Seric e->e_to = tobuf; 1784397Seric ctladdr = NULL; 1793233Seric for (; to != NULL; to = to->q_next) 180294Seric { 1813233Seric /* avoid sending multiple recipients to dumb mailers */ 18210682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 1833233Seric break; 1843233Seric 1853233Seric /* if already sent or not for this host, don't send */ 1867052Seric if (bitset(QDONTSEND, to->q_flags) || 1877052Seric strcmp(to->q_host, host) != 0 || 1887052Seric to->q_mailer != firstto->q_mailer) 1893233Seric continue; 1904397Seric 1918225Seric /* avoid overflowing tobuf */ 1929370Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 1938225Seric break; 1948225Seric 1955032Seric # ifdef DEBUG 1967672Seric if (tTd(10, 1)) 1975032Seric { 1985032Seric printf("\nsend to "); 1995032Seric printaddr(to, FALSE); 2005032Seric } 2015032Seric # endif DEBUG 2025032Seric 2034397Seric /* compute effective uid/gid when sending */ 2044596Seric if (to->q_mailer == ProgMailer) 2054397Seric ctladdr = getctladdr(to); 2064397Seric 2073233Seric user = to->q_user; 2089370Seric e->e_to = to->q_paddr; 2093233Seric to->q_flags |= QDONTSEND; 2103233Seric 2113233Seric /* 2123233Seric ** Check to see that these people are allowed to 2133233Seric ** talk to each other. 2143233Seric */ 2153233Seric 21610699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 21710699Seric { 21810699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 21910699Seric NoReturn = TRUE; 22010699Seric giveresponse(EX_UNAVAILABLE, m, e); 22110699Seric continue; 22210699Seric } 2233233Seric if (!checkcompat(to)) 224294Seric { 22510105Seric giveresponse(EX_UNAVAILABLE, m, e); 2263233Seric continue; 227294Seric } 2283233Seric 2293233Seric /* 2304099Seric ** Strip quote bits from names if the mailer is dumb 2314099Seric ** about them. 2323233Seric */ 2333233Seric 23410682Seric if (bitnset(M_STRIPQ, m->m_flags)) 235294Seric { 2364099Seric stripquotes(user, TRUE); 2374099Seric stripquotes(host, TRUE); 2383233Seric } 2394099Seric else 2404099Seric { 2414099Seric stripquotes(user, FALSE); 2424099Seric stripquotes(host, FALSE); 2434099Seric } 2443233Seric 2459206Seric /* hack attack -- delivermail compatibility */ 2469206Seric if (m == ProgMailer && *user == '|') 2479206Seric user++; 2489206Seric 2493233Seric /* 2504161Seric ** If an error message has already been given, don't 2514161Seric ** bother to send to this address. 2524161Seric ** 2534161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2544161Seric ** >> NOTE >> cannot do any further aliasing; that 2554161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2564161Seric */ 2574161Seric 2587293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2594161Seric continue; 2604161Seric 2614283Seric /* save statistics.... */ 2629370Seric markstats(e, to); 2634283Seric 2644161Seric /* 2653233Seric ** See if this user name is "special". 2663233Seric ** If the user name has a slash in it, assume that this 2676974Seric ** is a file -- send it off without further ado. Note 2686974Seric ** that this type of addresses is not processed along 2696974Seric ** with the others, so we fudge on the To person. 2703233Seric */ 2713233Seric 2724596Seric if (m == LocalMailer) 2733233Seric { 2745599Seric if (user[0] == '/') 275294Seric { 2768003Seric rcode = mailfile(user, getctladdr(to)); 27710105Seric giveresponse(rcode, m, e); 2783233Seric continue; 279294Seric } 280294Seric } 2813233Seric 2824315Seric /* 2834315Seric ** Address is verified -- add this user to mailer 2844315Seric ** argv, and add it to the print list of recipients. 2854315Seric */ 2864315Seric 2876059Seric /* link together the chain of recipients */ 2886272Seric to->q_tchain = tochain; 2896272Seric tochain = to; 2906059Seric 2913233Seric /* create list of users for error messages */ 2929388Seric (void) strcat(tobuf, ","); 2934082Seric (void) strcat(tobuf, to->q_paddr); 2949370Seric define('u', user, e); /* to user */ 2959370Seric define('z', to->q_home, e); /* user's home */ 2963233Seric 2974863Seric /* 2986059Seric ** Expand out this user into argument list. 2994863Seric */ 3004863Seric 3016059Seric if (!clever) 3023233Seric { 3039370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3044863Seric *pvp++ = newstr(buf); 3054863Seric if (pvp >= &pv[MAXPV - 2]) 3064863Seric { 3074863Seric /* allow some space for trailing parms */ 3084863Seric break; 3094863Seric } 3104863Seric } 311294Seric } 312294Seric 3134067Seric /* see if any addresses still exist */ 3144067Seric if (tobuf[0] == '\0') 3154863Seric { 3169370Seric define('g', (char *) NULL, e); 3174067Seric return (0); 3184863Seric } 3194067Seric 3203233Seric /* print out messages as full list */ 3219388Seric e->e_to = tobuf + 1; 3223233Seric 323294Seric /* 3243233Seric ** Fill out any parameters after the $u parameter. 325294Seric */ 326294Seric 3274863Seric while (!clever && *++mvp != NULL) 328294Seric { 3299370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3303233Seric *pvp++ = newstr(buf); 3313233Seric if (pvp >= &pv[MAXPV]) 3323233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 333294Seric } 3343233Seric *pvp++ = NULL; 335294Seric 336294Seric /* 337294Seric ** Call the mailer. 3382898Seric ** The argument vector gets built, pipes 339294Seric ** are created as necessary, and we fork & exec as 3402898Seric ** appropriate. 3414863Seric ** If we are running SMTP, we just need to clean up. 342294Seric */ 343294Seric 3449370Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 3459370Seric 3464397Seric if (ctladdr == NULL) 3479370Seric ctladdr = &e->e_from; 3485179Seric # ifdef SMTP 3494863Seric if (clever) 3504863Seric { 3519370Seric /* send the initial SMTP protocol */ 35210168Seric rcode = smtpinit(m, pv); 3539370Seric 3549388Seric if (rcode == EX_OK) 3559370Seric { 3569388Seric /* send the recipient list */ 3579388Seric tobuf[0] = '\0'; 3589388Seric for (to = tochain; to != NULL; to = to->q_tchain) 3599388Seric { 3609388Seric int i; 3619370Seric 3629388Seric e->e_to = to->q_paddr; 36310168Seric i = smtprcpt(to, m); 3649388Seric if (i != EX_OK) 3659388Seric { 36610092Seric markfailure(e, to, i); 36710105Seric giveresponse(i, m, e); 3689388Seric } 3699388Seric else 3709388Seric { 3719388Seric strcat(tobuf, ","); 3729388Seric strcat(tobuf, to->q_paddr); 3739388Seric } 3749388Seric } 3759388Seric 3769388Seric /* now send the data */ 3779388Seric if (tobuf[0] == '\0') 3789388Seric e->e_to = NULL; 3799370Seric else 3809370Seric { 3819388Seric e->e_to = tobuf + 1; 38210168Seric rcode = smtpdata(m, e); 3839370Seric } 3849388Seric 3859388Seric /* now close the connection */ 38610168Seric smtpquit(pv[0], m); 3879370Seric } 3884863Seric } 3894863Seric else 3905179Seric # endif SMTP 39110168Seric rcode = sendoff(e, m, pv, ctladdr); 3923233Seric 3934621Seric /* 3949388Seric ** Do final status disposal. 3959388Seric ** We check for something in tobuf for the SMTP case. 3969388Seric ** If we got a temporary failure, arrange to queue the 3979388Seric ** addressees. 3984621Seric */ 3994621Seric 4009388Seric if (tobuf[0] != '\0') 40110105Seric giveresponse(rcode, m, e); 4029388Seric if (rcode != EX_OK) 4034621Seric { 4045032Seric for (to = tochain; to != NULL; to = to->q_tchain) 40510092Seric markfailure(e, to, rcode); 4064621Seric } 4074621Seric 4084488Seric errno = 0; 4099370Seric define('g', (char *) NULL, e); 4108003Seric return (rcode); 4113233Seric } 4123233Seric /* 41310092Seric ** MARKFAILURE -- mark a failure on a specific address. 41410092Seric ** 41510092Seric ** Parameters: 41610092Seric ** e -- the envelope we are sending. 41710092Seric ** q -- the address to mark. 41810092Seric ** rcode -- the code signifying the particular failure. 41910092Seric ** 42010092Seric ** Returns: 42110092Seric ** none. 42210092Seric ** 42310092Seric ** Side Effects: 42410092Seric ** marks the address (and possibly the envelope) with the 42510092Seric ** failure so that an error will be returned or 42610092Seric ** the message will be queued, as appropriate. 42710092Seric */ 42810092Seric 42910092Seric markfailure(e, q, rcode) 43010092Seric register ENVELOPE *e; 43110092Seric register ADDRESS *q; 43210092Seric int rcode; 43310092Seric { 43410092Seric if (rcode == EX_OK) 43510092Seric return; 43610092Seric else if (rcode != EX_TEMPFAIL) 43710092Seric q->q_flags |= QBADADDR; 43810092Seric else if (curtime() > e->e_ctime + TimeOut) 43910092Seric { 44010092Seric extern char *pintvl(); 44110105Seric char buf[MAXLINE]; 44210092Seric 44310092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 44410105Seric { 44510105Seric (void) sprintf(buf, "Cannot send message for %s", 44610092Seric pintvl(TimeOut, FALSE)); 44710105Seric if (e->e_message != NULL) 44810105Seric free(e->e_message); 44910105Seric e->e_message = newstr(buf); 45010105Seric message(Arpa_Info, buf); 45110105Seric } 45210092Seric q->q_flags |= QBADADDR; 45310092Seric e->e_flags |= EF_TIMEOUT; 45410092Seric } 45510092Seric else 45610092Seric q->q_flags |= QQUEUEUP; 45710092Seric } 45810092Seric /* 4594214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4604214Seric ** 4614214Seric ** This MUST be a macro, since after a vfork we are running 4624214Seric ** two processes on the same stack!!! 4634214Seric ** 4644214Seric ** Parameters: 4654214Seric ** none. 4664214Seric ** 4674214Seric ** Returns: 4684214Seric ** From a macro??? You've got to be kidding! 4694214Seric ** 4704214Seric ** Side Effects: 4714214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4724214Seric ** pid of child in parent, zero in child. 4734214Seric ** -1 on unrecoverable error. 4744214Seric ** 4754214Seric ** Notes: 4764214Seric ** I'm awfully sorry this looks so awful. That's 4774214Seric ** vfork for you..... 4784214Seric */ 4794214Seric 4804214Seric # define NFORKTRIES 5 4819148Seric # ifdef VMUNIX 4824214Seric # define XFORK vfork 4839148Seric # else VMUNIX 4844214Seric # define XFORK fork 4859148Seric # endif VMUNIX 4864214Seric 4874214Seric # define DOFORK(fORKfN) \ 4884214Seric {\ 4894214Seric register int i;\ 4904214Seric \ 4914214Seric for (i = NFORKTRIES; i-- > 0; )\ 4924214Seric {\ 4934214Seric pid = fORKfN();\ 4944214Seric if (pid >= 0)\ 4954214Seric break;\ 4967003Seric sleep(NFORKTRIES - i);\ 4974214Seric }\ 4984214Seric } 4994214Seric /* 5004637Seric ** DOFORK -- simple fork interface to DOFORK. 5014637Seric ** 5024637Seric ** Parameters: 5034637Seric ** none. 5044637Seric ** 5054637Seric ** Returns: 5064637Seric ** pid of child in parent. 5074637Seric ** zero in child. 5084637Seric ** -1 on error. 5094637Seric ** 5104637Seric ** Side Effects: 5114637Seric ** returns twice, once in parent and once in child. 5124637Seric */ 5134637Seric 5144637Seric dofork() 5154637Seric { 5164637Seric register int pid; 5174637Seric 5184637Seric DOFORK(fork); 5194637Seric return (pid); 5204637Seric } 5214637Seric /* 5223233Seric ** SENDOFF -- send off call to mailer & collect response. 5233233Seric ** 5243233Seric ** Parameters: 5259370Seric ** e -- the envelope to mail. 5263233Seric ** m -- mailer descriptor. 5273233Seric ** pvp -- parameter vector to send to it. 5284397Seric ** ctladdr -- an address pointer controlling the 5294397Seric ** user/groupid etc. of the mailer. 5303233Seric ** 5313233Seric ** Returns: 5323233Seric ** exit status of mailer. 5333233Seric ** 5343233Seric ** Side Effects: 5353233Seric ** none. 5363233Seric */ 5373233Seric 53810168Seric sendoff(e, m, pvp, ctladdr) 5399370Seric register ENVELOPE *e; 5409370Seric MAILER *m; 5413233Seric char **pvp; 5424397Seric ADDRESS *ctladdr; 5433233Seric { 5444863Seric auto FILE *mfile; 5454863Seric auto FILE *rfile; 5463233Seric register int i; 5473233Seric int pid; 5484863Seric 5494863Seric /* 5504863Seric ** Create connection to mailer. 5514863Seric */ 5524863Seric 5534863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5544863Seric if (pid < 0) 5554863Seric return (-1); 5564863Seric 5574863Seric /* 5584863Seric ** Format and send message. 5594863Seric */ 5604863Seric 56110168Seric putfromline(mfile, m); 56210168Seric (*e->e_puthdr)(mfile, m, e); 56310168Seric putline("\n", mfile, m); 56410168Seric (*e->e_putbody)(mfile, m, e); 5654863Seric (void) fclose(mfile); 5664863Seric 5674863Seric i = endmailer(pid, pvp[0]); 5685981Seric 5695981Seric /* arrange a return receipt if requested */ 57010682Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 5715981Seric { 5729370Seric e->e_flags |= EF_SENDRECEIPT; 5735981Seric /* do we want to send back more info? */ 5745981Seric } 5755981Seric 5764863Seric return (i); 5774863Seric } 5784863Seric /* 5794863Seric ** ENDMAILER -- Wait for mailer to terminate. 5804863Seric ** 5814863Seric ** We should never get fatal errors (e.g., segmentation 5824863Seric ** violation), so we report those specially. For other 5834863Seric ** errors, we choose a status message (into statmsg), 5844863Seric ** and if it represents an error, we print it. 5854863Seric ** 5864863Seric ** Parameters: 5874863Seric ** pid -- pid of mailer. 5884863Seric ** name -- name of mailer (for error messages). 5894863Seric ** 5904863Seric ** Returns: 5914863Seric ** exit code of mailer. 5924863Seric ** 5934863Seric ** Side Effects: 5944863Seric ** none. 5954863Seric */ 5964863Seric 5974863Seric endmailer(pid, name) 5984863Seric int pid; 5994863Seric char *name; 6004863Seric { 6019370Seric int st; 6024863Seric 6036038Seric /* in the IPC case there is nothing to wait for */ 6046038Seric if (pid == 0) 6056038Seric return (EX_OK); 6066038Seric 6076038Seric /* wait for the mailer process to die and collect status */ 6089370Seric st = waitfor(pid); 6099370Seric if (st == -1) 6108127Seric { 6119370Seric syserr("endmailer %s: wait", name); 6129370Seric return (EX_SOFTWARE); 6134863Seric } 6146038Seric 6156038Seric /* see if it died a horrid death */ 6164863Seric if ((st & 0377) != 0) 6174863Seric { 6189370Seric syserr("endmailer %s: stat %o", name, st); 6194863Seric ExitStat = EX_UNAVAILABLE; 6209370Seric return (EX_UNAVAILABLE); 6214863Seric } 6226038Seric 6236038Seric /* normal death -- return status */ 6249370Seric st = (st >> 8) & 0377; 6259370Seric return (st); 6264863Seric } 6274863Seric /* 6284863Seric ** OPENMAILER -- open connection to mailer. 6294863Seric ** 6304863Seric ** Parameters: 6314863Seric ** m -- mailer descriptor. 6324863Seric ** pvp -- parameter vector to pass to mailer. 6334863Seric ** ctladdr -- controlling address for user. 6344863Seric ** clever -- create a full duplex connection. 6354863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6364863Seric ** prfile -- pointer to rfile (from mailer) connection. 6374863Seric ** 6384863Seric ** Returns: 6396038Seric ** pid of mailer ( > 0 ). 6404863Seric ** -1 on error. 6416038Seric ** zero on an IPC connection. 6424863Seric ** 6434863Seric ** Side Effects: 6444863Seric ** creates a mailer in a subprocess. 6454863Seric */ 6464863Seric 6474863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6489370Seric MAILER *m; 6494863Seric char **pvp; 6504863Seric ADDRESS *ctladdr; 6514863Seric bool clever; 6524863Seric FILE **pmfile; 6534863Seric FILE **prfile; 6544863Seric { 6554863Seric int pid; 6564709Seric int mpvect[2]; 6574863Seric int rpvect[2]; 6583233Seric FILE *mfile; 6594863Seric FILE *rfile; 6603233Seric extern FILE *fdopen(); 6613233Seric 6623233Seric # ifdef DEBUG 6637672Seric if (tTd(11, 1)) 664294Seric { 6658178Seric printf("openmailer:"); 6663233Seric printav(pvp); 667294Seric } 6683233Seric # endif DEBUG 6694488Seric errno = 0; 6703233Seric 6716038Seric /* 6726038Seric ** Deal with the special case of mail handled through an IPC 6736038Seric ** connection. 6746038Seric ** In this case we don't actually fork. We must be 6756038Seric ** running SMTP for this to work. We will return a 6766038Seric ** zero pid to indicate that we are running IPC. 67711160Seric ** We also handle a debug version that just talks to stdin/out. 6786038Seric */ 6796038Seric 68011160Seric #ifdef DEBUG 68111160Seric /* check for Local Person Communication -- not for mortals!!! */ 68211160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 68311160Seric { 68411160Seric *pmfile = stdout; 68511160Seric *prfile = stdin; 68611160Seric return (0); 68711160Seric } 68811160Seric #endif DEBUG 68911160Seric 6906038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6916038Seric { 6929370Seric #ifdef DAEMON 6936038Seric register int i; 6947285Seric register u_short port; 6956038Seric 6966038Seric if (!clever) 6976038Seric syserr("non-clever IPC"); 6986632Seric if (pvp[2] != NULL) 6997285Seric port = atoi(pvp[2]); 7006632Seric else 7017285Seric port = 0; 7027285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 7036038Seric if (i != EX_OK) 7046047Seric { 7056047Seric ExitStat = i; 7066038Seric return (-1); 7076047Seric } 7086038Seric else 7096038Seric return (0); 7109370Seric #else DAEMON 7119370Seric syserr("openmailer: no IPC"); 7129370Seric return (-1); 7139370Seric #endif DAEMON 7146038Seric } 7156038Seric 7162898Seric /* create a pipe to shove the mail through */ 7174709Seric if (pipe(mpvect) < 0) 718294Seric { 7199370Seric syserr("openmailer: pipe (to mailer)"); 720294Seric return (-1); 721294Seric } 7224863Seric 7239370Seric #ifdef SMTP 7244863Seric /* if this mailer speaks smtp, create a return pipe */ 7254863Seric if (clever && pipe(rpvect) < 0) 7264863Seric { 7279370Seric syserr("openmailer: pipe (from mailer)"); 7284863Seric (void) close(mpvect[0]); 7294863Seric (void) close(mpvect[1]); 7304863Seric return (-1); 7314863Seric } 7329370Seric #endif SMTP 7334863Seric 7346038Seric /* 7356038Seric ** Actually fork the mailer process. 7366038Seric ** DOFORK is clever about retrying. 7376038Seric */ 7386038Seric 7399538Seric if (CurEnv->e_xfp != NULL) 7409538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7419370Seric (void) fflush(stdout); 7424214Seric DOFORK(XFORK); 7434327Seric /* pid is set by DOFORK */ 744294Seric if (pid < 0) 745294Seric { 7466038Seric /* failure */ 7479370Seric syserr("openmailer: cannot fork"); 7484709Seric (void) close(mpvect[0]); 7494709Seric (void) close(mpvect[1]); 7509370Seric #ifdef SMTP 7514863Seric if (clever) 7524863Seric { 7534863Seric (void) close(rpvect[0]); 7544863Seric (void) close(rpvect[1]); 7554863Seric } 7569370Seric #endif SMTP 757294Seric return (-1); 758294Seric } 759294Seric else if (pid == 0) 760294Seric { 761294Seric /* child -- set up input & exec mailer */ 7621621Seric /* make diagnostic output be standard output */ 7634477Seric (void) signal(SIGINT, SIG_IGN); 7644477Seric (void) signal(SIGHUP, SIG_IGN); 7654215Seric (void) signal(SIGTERM, SIG_DFL); 7664709Seric 7674709Seric /* arrange to filter standard & diag output of command */ 7684863Seric if (clever) 7694709Seric { 7704863Seric (void) close(rpvect[0]); 7714709Seric (void) close(1); 7724863Seric (void) dup(rpvect[1]); 7734863Seric (void) close(rpvect[1]); 7744863Seric } 7759275Seric else if (OpMode == MD_SMTP || HoldErrs) 7764863Seric { 7779370Seric /* put mailer output in transcript */ 7784863Seric (void) close(1); 7799538Seric (void) dup(fileno(CurEnv->e_xfp)); 7804709Seric } 7814082Seric (void) close(2); 7824082Seric (void) dup(1); 7834709Seric 7844709Seric /* arrange to get standard input */ 7854709Seric (void) close(mpvect[1]); 7864082Seric (void) close(0); 7874709Seric if (dup(mpvect[0]) < 0) 788294Seric { 7892898Seric syserr("Cannot dup to zero!"); 7902898Seric _exit(EX_OSERR); 791294Seric } 7924709Seric (void) close(mpvect[0]); 79310682Seric if (!bitnset(M_RESTR, m->m_flags)) 7944215Seric { 7954417Seric if (ctladdr->q_uid == 0) 7964417Seric { 7974417Seric (void) setgid(DefGid); 7984417Seric (void) setuid(DefUid); 7994417Seric } 8004417Seric else 8014415Seric { 8024417Seric (void) setgid(ctladdr->q_gid); 8034417Seric (void) setuid(ctladdr->q_uid); 8044415Seric } 8054215Seric } 8069370Seric 8072774Seric /* 8082774Seric ** We have to be careful with vfork - we can't mung up the 8092774Seric ** memory but we don't want the mailer to inherit any extra 8102774Seric ** open files. Chances are the mailer won't 8112774Seric ** care about an extra file, but then again you never know. 8122774Seric ** Actually, we would like to close(fileno(pwf)), but it's 8132774Seric ** declared static so we can't. But if we fclose(pwf), which 8142774Seric ** is what endpwent does, it closes it in the parent too and 8152774Seric ** the next getpwnam will be slower. If you have a weird 8162774Seric ** mailer that chokes on the extra file you should do the 8179148Seric ** endpwent(). -MRH 8182774Seric ** 8192774Seric ** Similar comments apply to log. However, openlog is 8202774Seric ** clever enough to set the FIOCLEX mode on the file, 8212774Seric ** so it will be closed automatically on the exec. 8222774Seric */ 8232774Seric 8249370Seric closeall(); 8256038Seric 8266038Seric /* try to execute the mailer */ 827294Seric execv(m->m_mailer, pvp); 8286038Seric 829294Seric /* syserr fails because log is closed */ 830294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 8314214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 8324082Seric (void) fflush(stdout); 8331619Seric _exit(EX_UNAVAILABLE); 834294Seric } 835294Seric 8364709Seric /* 8374863Seric ** Set up return value. 8384709Seric */ 8394709Seric 8404709Seric (void) close(mpvect[0]); 8414709Seric mfile = fdopen(mpvect[1], "w"); 8424863Seric if (clever) 8434863Seric { 8444863Seric (void) close(rpvect[1]); 8454863Seric rfile = fdopen(rpvect[0], "r"); 8464863Seric } 847294Seric 8484863Seric *pmfile = mfile; 8494863Seric *prfile = rfile; 850294Seric 8514863Seric return (pid); 852294Seric } 853294Seric /* 854294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 855294Seric ** 856294Seric ** Parameters: 857294Seric ** stat -- the status code from the mailer (high byte 858294Seric ** only; core dumps must have been taken care of 859294Seric ** already). 860294Seric ** m -- the mailer descriptor for this mailer. 861294Seric ** 862294Seric ** Returns: 8634082Seric ** none. 864294Seric ** 865294Seric ** Side Effects: 8661518Seric ** Errors may be incremented. 867294Seric ** ExitStat may be set. 868294Seric */ 869294Seric 8709370Seric /*ARGSUSED*/ 87110105Seric giveresponse(stat, m, e) 872294Seric int stat; 8739370Seric register MAILER *m; 87410105Seric ENVELOPE *e; 875294Seric { 876294Seric register char *statmsg; 877294Seric extern char *SysExMsg[]; 878294Seric register int i; 879294Seric extern int N_SysEx; 88010105Seric char buf[MAXLINE]; 881294Seric 8824315Seric /* 8834315Seric ** Compute status message from code. 8844315Seric */ 8854315Seric 886294Seric i = stat - EX__BASE; 8879370Seric if (stat == 0) 8889370Seric statmsg = "250 Sent"; 8899370Seric else if (i < 0 || i > N_SysEx) 8909370Seric { 8919370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 8929370Seric stat = EX_UNAVAILABLE; 8939370Seric statmsg = buf; 8949370Seric } 89510105Seric else if (stat == EX_TEMPFAIL) 89610105Seric { 89710105Seric extern char *sys_errlist[]; 89810105Seric extern int sys_nerr; 89910105Seric 90010124Seric (void) strcpy(buf, SysExMsg[i]); 90110124Seric if (errno != 0) 90210105Seric { 90310124Seric (void) strcat(buf, ": "); 90410124Seric if (errno > 0 && errno < sys_nerr) 90510124Seric (void) strcat(buf, sys_errlist[errno]); 90610124Seric else 90710124Seric { 90810124Seric char xbuf[30]; 90910124Seric 91010124Seric (void) sprintf(xbuf, "Error %d", errno); 91110124Seric (void) strcat(buf, xbuf); 91210124Seric } 91310105Seric } 91410105Seric statmsg = buf; 91510105Seric } 916294Seric else 917294Seric statmsg = SysExMsg[i]; 9189370Seric 9199370Seric /* 9209370Seric ** Print the message as appropriate 9219370Seric */ 9229370Seric 92310105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 9248003Seric message(Arpa_Info, &statmsg[4]); 925294Seric else 926294Seric { 9271518Seric Errors++; 9289370Seric usrerr(statmsg); 929294Seric } 930294Seric 931294Seric /* 932294Seric ** Final cleanup. 933294Seric ** Log a record of the transaction. Compute the new 934294Seric ** ExitStat -- if we already had an error, stick with 935294Seric ** that. 936294Seric */ 937294Seric 9387680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 9398496Seric logdelivery(&statmsg[4]); 9407858Seric 9414621Seric if (stat != EX_TEMPFAIL) 9424621Seric setstat(stat); 94310105Seric if (stat != EX_OK) 94410105Seric { 94510105Seric if (e->e_message != NULL) 94610105Seric free(e->e_message); 94710105Seric e->e_message = newstr(&statmsg[4]); 94810105Seric } 94910124Seric errno = 0; 950294Seric } 951294Seric /* 9528496Seric ** LOGDELIVERY -- log the delivery in the system log 9538496Seric ** 9548496Seric ** Parameters: 9558496Seric ** stat -- the message to print for the status 9568496Seric ** 9578496Seric ** Returns: 9588496Seric ** none 9598496Seric ** 9608496Seric ** Side Effects: 9618496Seric ** none 9628496Seric */ 9638496Seric 9648496Seric logdelivery(stat) 9658496Seric char *stat; 9668496Seric { 9678496Seric extern char *pintvl(); 9688496Seric 9698496Seric # ifdef LOG 9708496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 9718496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 9728496Seric # endif LOG 9738496Seric } 9748496Seric /* 9756974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 976294Seric ** 9776974Seric ** This can be made an arbitrary message separator by changing $l 978294Seric ** 9796974Seric ** One of the ugliest hacks seen by human eyes is 9806974Seric ** contained herein: UUCP wants those stupid 9819370Seric ** "emote from <host>" lines. Why oh why does a 9826974Seric ** well-meaning programmer such as myself have to 9836974Seric ** deal with this kind of antique garbage???? 9846974Seric ** 985294Seric ** Parameters: 9866974Seric ** fp -- the file to output to. 9876974Seric ** m -- the mailer describing this entry. 988294Seric ** 989294Seric ** Returns: 9906974Seric ** none 991294Seric ** 992294Seric ** Side Effects: 9936974Seric ** outputs some text to fp. 994294Seric */ 995294Seric 99610168Seric putfromline(fp, m) 9976974Seric register FILE *fp; 9986974Seric register MAILER *m; 999294Seric { 10006974Seric char buf[MAXLINE]; 1001294Seric 100210682Seric if (bitnset(M_NHDR, m->m_flags)) 10036974Seric return; 10044315Seric 10056974Seric # ifdef UGLYUUCP 100610682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 10074205Seric { 10086974Seric extern char *macvalue(); 10098178Seric char *sys = macvalue('g', CurEnv); 10106974Seric char *bang = index(sys, '!'); 10116041Seric 10126974Seric if (bang == NULL) 10136974Seric syserr("No ! in UUCP! (%s)", sys); 10145099Seric else 10159370Seric { 10166974Seric *bang = '\0'; 10179370Seric expand("From $f $d remote from $g\n", buf, 10189370Seric &buf[sizeof buf - 1], CurEnv); 10199370Seric *bang = '!'; 10209370Seric } 10216974Seric } 10226974Seric else 10235179Seric # endif UGLYUUCP 10246974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 102510168Seric putline(buf, fp, m); 10265981Seric } 10275981Seric /* 10286974Seric ** PUTBODY -- put the body of a message. 10296974Seric ** 10306974Seric ** Parameters: 10316974Seric ** fp -- file to output onto. 103210168Seric ** m -- a mailer descriptor to control output format. 10339538Seric ** e -- the envelope to put out. 10346974Seric ** 10356974Seric ** Returns: 10366974Seric ** none. 10376974Seric ** 10386974Seric ** Side Effects: 10396974Seric ** The message is written onto fp. 10406974Seric */ 10416974Seric 104210168Seric putbody(fp, m, e) 10436974Seric FILE *fp; 10449370Seric MAILER *m; 10459538Seric register ENVELOPE *e; 10466974Seric { 104710168Seric char buf[MAXLINE]; 10486974Seric 10496974Seric /* 10506974Seric ** Output the body of the message 10516974Seric */ 10526974Seric 10539538Seric if (e->e_dfp == NULL) 10546974Seric { 10559538Seric if (e->e_df != NULL) 10569538Seric { 10579538Seric e->e_dfp = fopen(e->e_df, "r"); 10589538Seric if (e->e_dfp == NULL) 10599538Seric syserr("Cannot open %s", e->e_df); 10609538Seric } 10619538Seric else 106210168Seric putline("<<< No Message Collected >>>", fp, m); 10639538Seric } 10649538Seric if (e->e_dfp != NULL) 10659538Seric { 10669538Seric rewind(e->e_dfp); 106710168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 106810168Seric putline(buf, fp, m); 10696974Seric 10709538Seric if (ferror(e->e_dfp)) 10716974Seric { 10726974Seric syserr("putbody: read error"); 10736974Seric ExitStat = EX_IOERR; 10746974Seric } 10756974Seric } 10766974Seric 10776974Seric (void) fflush(fp); 10786974Seric if (ferror(fp) && errno != EPIPE) 10796974Seric { 10806974Seric syserr("putbody: write error"); 10816974Seric ExitStat = EX_IOERR; 10826974Seric } 10836974Seric errno = 0; 10846974Seric } 10856974Seric /* 1086294Seric ** MAILFILE -- Send a message to a file. 1087294Seric ** 10884327Seric ** If the file has the setuid/setgid bits set, but NO execute 10894327Seric ** bits, sendmail will try to become the owner of that file 10904327Seric ** rather than the real user. Obviously, this only works if 10914327Seric ** sendmail runs as root. 10924327Seric ** 10939370Seric ** This could be done as a subordinate mailer, except that it 10949370Seric ** is used implicitly to save messages in ~/dead.letter. We 10959370Seric ** view this as being sufficiently important as to include it 10969370Seric ** here. For example, if the system is dying, we shouldn't have 10979370Seric ** to create another process plus some pipes to save the message. 10989370Seric ** 1099294Seric ** Parameters: 1100294Seric ** filename -- the name of the file to send to. 11014397Seric ** ctladdr -- the controlling address header -- includes 11024397Seric ** the userid/groupid to be when sending. 1103294Seric ** 1104294Seric ** Returns: 1105294Seric ** The exit code associated with the operation. 1106294Seric ** 1107294Seric ** Side Effects: 1108294Seric ** none. 1109294Seric */ 1110294Seric 11114397Seric mailfile(filename, ctladdr) 1112294Seric char *filename; 11134397Seric ADDRESS *ctladdr; 1114294Seric { 1115294Seric register FILE *f; 11164214Seric register int pid; 1117294Seric 11184214Seric /* 11194214Seric ** Fork so we can change permissions here. 11204214Seric ** Note that we MUST use fork, not vfork, because of 11214214Seric ** the complications of calling subroutines, etc. 11224214Seric */ 11234067Seric 11244214Seric DOFORK(fork); 11254214Seric 11264214Seric if (pid < 0) 11274214Seric return (EX_OSERR); 11284214Seric else if (pid == 0) 11294214Seric { 11304214Seric /* child -- actually write to file */ 11314327Seric struct stat stb; 11324327Seric 11334215Seric (void) signal(SIGINT, SIG_DFL); 11344215Seric (void) signal(SIGHUP, SIG_DFL); 11354215Seric (void) signal(SIGTERM, SIG_DFL); 11364327Seric umask(OldUmask); 11374327Seric if (stat(filename, &stb) < 0) 1138*11935Seric { 1139*11935Seric errno = 0; 11404431Seric stb.st_mode = 0666; 1141*11935Seric } 11424327Seric if (bitset(0111, stb.st_mode)) 11434327Seric exit(EX_CANTCREAT); 11444401Seric if (ctladdr == NULL) 11456900Seric ctladdr = &CurEnv->e_from; 11464327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 11474417Seric { 11484417Seric if (ctladdr->q_uid == 0) 11494417Seric (void) setgid(DefGid); 11504417Seric else 11514417Seric (void) setgid(ctladdr->q_gid); 11524417Seric } 11534327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 11544417Seric { 11554417Seric if (ctladdr->q_uid == 0) 11564417Seric (void) setuid(DefUid); 11574417Seric else 11584417Seric (void) setuid(ctladdr->q_uid); 11594417Seric } 11606887Seric f = dfopen(filename, "a"); 11614214Seric if (f == NULL) 11624214Seric exit(EX_CANTCREAT); 11634214Seric 116410168Seric putfromline(f, ProgMailer); 116510168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 116610168Seric putline("\n", f, ProgMailer); 116710168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 116810168Seric putline("\n", f, ProgMailer); 11694214Seric (void) fclose(f); 11704214Seric (void) fflush(stdout); 11714417Seric 11726887Seric /* reset ISUID & ISGID bits for paranoid systems */ 11734621Seric (void) chmod(filename, (int) stb.st_mode); 11744214Seric exit(EX_OK); 11754315Seric /*NOTREACHED*/ 11764214Seric } 11774214Seric else 11784214Seric { 11794214Seric /* parent -- wait for exit status */ 11809370Seric int st; 11814214Seric 11829370Seric st = waitfor(pid); 11839370Seric if ((st & 0377) != 0) 11849370Seric return (EX_UNAVAILABLE); 11859370Seric else 11869370Seric return ((st >> 8) & 0377); 11874214Seric } 1188294Seric } 11894550Seric /* 11904550Seric ** SENDALL -- actually send all the messages. 11914550Seric ** 11924550Seric ** Parameters: 11937043Seric ** e -- the envelope to send. 11949275Seric ** mode -- the delivery mode to use. 11954550Seric ** 11964550Seric ** Returns: 11974550Seric ** none. 11984550Seric ** 11994550Seric ** Side Effects: 12004550Seric ** Scans the send lists and sends everything it finds. 12017043Seric ** Delivers any appropriate error messages. 12029275Seric ** If we are running in a non-interactive mode, takes the 12039275Seric ** appropriate action. 12044550Seric */ 12054550Seric 12069275Seric sendall(e, mode) 12077043Seric ENVELOPE *e; 12089275Seric char mode; 12094550Seric { 12105008Seric register ADDRESS *q; 12117779Seric bool oldverbose; 12129275Seric int pid; 12134550Seric 12149370Seric #ifdef DEBUG 12158248Seric if (tTd(13, 1)) 12165032Seric { 12179275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 12187043Seric printaddr(e->e_sendqueue, TRUE); 12195032Seric } 12209370Seric #endif DEBUG 12215008Seric 12227043Seric /* 12239275Seric ** Do any preprocessing necessary for the mode we are running. 12249370Seric ** Check to make sure the hop count is reasonable. 12259370Seric ** Delete sends to the sender in mailing lists. 12267043Seric */ 12277043Seric 12289370Seric CurEnv = e; 12299370Seric 12309370Seric if (e->e_hopcount > MAXHOP) 12319275Seric { 12329370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 12339370Seric return; 12349370Seric } 12359275Seric 12369370Seric if (!MeToo) 12379370Seric { 12389370Seric e->e_from.q_flags |= QDONTSEND; 12399370Seric recipient(&e->e_from, &e->e_sendqueue); 12409275Seric } 12419370Seric 12429370Seric # ifdef QUEUE 12439335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 12449335Seric (mode != SM_VERIFY && SuperSafe)) && 12459335Seric !bitset(EF_INQUEUE, e->e_flags)) 12469370Seric queueup(e, TRUE, mode == SM_QUEUE); 12479275Seric #endif QUEUE 12489275Seric 12497779Seric oldverbose = Verbose; 12509275Seric switch (mode) 12519275Seric { 12529275Seric case SM_VERIFY: 12537779Seric Verbose = TRUE; 12549275Seric break; 12559275Seric 12569275Seric case SM_QUEUE: 12579335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 12589275Seric return; 12599275Seric 12609275Seric case SM_FORK: 12619538Seric if (e->e_xfp != NULL) 12629538Seric (void) fflush(e->e_xfp); 12639275Seric pid = fork(); 12649275Seric if (pid < 0) 12659275Seric { 12669275Seric mode = SM_DELIVER; 12679275Seric break; 12689275Seric } 12699275Seric else if (pid > 0) 12709293Seric { 12719293Seric /* be sure we leave the temp files to our child */ 12729335Seric e->e_id = e->e_df = NULL; 12739275Seric return; 12749293Seric } 12759275Seric 12769275Seric /* double fork to avoid zombies */ 12779275Seric if (fork() > 0) 12789275Seric exit(EX_OK); 12799275Seric 12809293Seric /* be sure we are immune from the terminal */ 128110133Seric disconnect(FALSE); 12829293Seric 12839275Seric break; 12849275Seric } 12859275Seric 12869275Seric /* 12879275Seric ** Run through the list and send everything. 12889275Seric */ 12899275Seric 12907043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12914550Seric { 12929275Seric if (mode == SM_VERIFY) 12934550Seric { 12949293Seric e->e_to = q->q_paddr; 12955008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 12967052Seric message(Arpa_Info, "deliverable"); 12974550Seric } 12985008Seric else 12999370Seric (void) deliver(e, q); 13004550Seric } 13017779Seric Verbose = oldverbose; 13027043Seric 13037043Seric /* 13047043Seric ** Now run through and check for errors. 13057043Seric */ 13067043Seric 13079275Seric if (mode == SM_VERIFY) 13087043Seric return; 13097043Seric 13107043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13117043Seric { 13127043Seric register ADDRESS *qq; 13137043Seric 13148248Seric # ifdef DEBUG 13158248Seric if (tTd(13, 3)) 13168248Seric { 13178248Seric printf("Checking "); 13188248Seric printaddr(q, FALSE); 13198248Seric } 13208248Seric # endif DEBUG 13218248Seric 13229335Seric /* only send errors if the message failed */ 13239335Seric if (!bitset(QBADADDR, q->q_flags)) 13249335Seric continue; 13257043Seric 13267043Seric /* we have an address that failed -- find the parent */ 13277043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 13287043Seric { 13297043Seric char obuf[MAXNAME + 6]; 13307043Seric extern char *aliaslookup(); 13317043Seric 13327043Seric /* we can only have owners for local addresses */ 133310682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 13347043Seric continue; 13357043Seric 13367043Seric /* see if the owner list exists */ 13377043Seric (void) strcpy(obuf, "owner-"); 13387047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 13397047Seric (void) strcat(obuf, "owner"); 13407047Seric else 13417047Seric (void) strcat(obuf, qq->q_user); 13427043Seric if (aliaslookup(obuf) == NULL) 13437043Seric continue; 13447043Seric 13458248Seric # ifdef DEBUG 13468248Seric if (tTd(13, 4)) 13478248Seric printf("Errors to %s\n", obuf); 13488248Seric # endif DEBUG 13498248Seric 13507043Seric /* owner list exists -- add it to the error queue */ 13519615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 13529370Seric ErrorMode == EM_MAIL; 13537043Seric break; 13547043Seric } 13557043Seric 13567043Seric /* if we did not find an owner, send to the sender */ 13578426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 13589615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 13597043Seric } 13609275Seric 13619275Seric if (mode == SM_FORK) 13629275Seric finis(); 13634550Seric } 1364