1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*16150Seric SCCSID(@(#)deliver.c 4.6 03/11/84); 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 */ 105*16150Seric expand("\001f", 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"; 121*16150Seric expand("\001g", 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 { 134*16150Seric while ((p = index(p, '\001')) != 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 */ 38615531Seric smtpquit(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 { 76115772Seric int i; 76215772Seric 763294Seric /* child -- set up input & exec mailer */ 7641621Seric /* make diagnostic output be standard output */ 7654477Seric (void) signal(SIGINT, SIG_IGN); 7664477Seric (void) signal(SIGHUP, SIG_IGN); 7674215Seric (void) signal(SIGTERM, SIG_DFL); 7684709Seric 7694709Seric /* arrange to filter standard & diag output of command */ 7704863Seric if (clever) 7714709Seric { 7724863Seric (void) close(rpvect[0]); 7734709Seric (void) close(1); 7744863Seric (void) dup(rpvect[1]); 7754863Seric (void) close(rpvect[1]); 7764863Seric } 7779275Seric else if (OpMode == MD_SMTP || HoldErrs) 7784863Seric { 7799370Seric /* put mailer output in transcript */ 7804863Seric (void) close(1); 7819538Seric (void) dup(fileno(CurEnv->e_xfp)); 7824709Seric } 7834082Seric (void) close(2); 7844082Seric (void) dup(1); 7854709Seric 7864709Seric /* arrange to get standard input */ 7874709Seric (void) close(mpvect[1]); 7884082Seric (void) close(0); 7894709Seric if (dup(mpvect[0]) < 0) 790294Seric { 7912898Seric syserr("Cannot dup to zero!"); 7922898Seric _exit(EX_OSERR); 793294Seric } 7944709Seric (void) close(mpvect[0]); 79510682Seric if (!bitnset(M_RESTR, m->m_flags)) 7964215Seric { 7974417Seric if (ctladdr->q_uid == 0) 7984417Seric { 7994417Seric (void) setgid(DefGid); 8004417Seric (void) setuid(DefUid); 8014417Seric } 8024417Seric else 8034415Seric { 8044417Seric (void) setgid(ctladdr->q_gid); 8054417Seric (void) setuid(ctladdr->q_uid); 8064415Seric } 8074215Seric } 8089370Seric 80915772Seric /* arrange for all the files to be closed */ 81015772Seric for (i = 3; i < 50; i++) 81115772Seric #ifdef FIOCLEX 81215772Seric (void) ioctl(i, FIOCLEX, 0); 81315772Seric #else FIOCLEX 81415772Seric (void) close(i); 81515772Seric #endif FIOCLEX 8162774Seric 8176038Seric /* try to execute the mailer */ 818294Seric execv(m->m_mailer, pvp); 8196038Seric 82015772Seric #ifdef FIOCLEX 82115772Seric syserr("Cannot exec %s", m->m_mailer); 82215772Seric #else FIOCLEX 8234214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 8244082Seric (void) fflush(stdout); 82515772Seric #endif FIOCLEX 8261619Seric _exit(EX_UNAVAILABLE); 827294Seric } 828294Seric 8294709Seric /* 8304863Seric ** Set up return value. 8314709Seric */ 8324709Seric 8334709Seric (void) close(mpvect[0]); 8344709Seric mfile = fdopen(mpvect[1], "w"); 8354863Seric if (clever) 8364863Seric { 8374863Seric (void) close(rpvect[1]); 8384863Seric rfile = fdopen(rpvect[0], "r"); 8394863Seric } 840294Seric 8414863Seric *pmfile = mfile; 8424863Seric *prfile = rfile; 843294Seric 8444863Seric return (pid); 845294Seric } 846294Seric /* 847294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 848294Seric ** 849294Seric ** Parameters: 850294Seric ** stat -- the status code from the mailer (high byte 851294Seric ** only; core dumps must have been taken care of 852294Seric ** already). 853294Seric ** m -- the mailer descriptor for this mailer. 854294Seric ** 855294Seric ** Returns: 8564082Seric ** none. 857294Seric ** 858294Seric ** Side Effects: 8591518Seric ** Errors may be incremented. 860294Seric ** ExitStat may be set. 861294Seric */ 862294Seric 86310105Seric giveresponse(stat, m, e) 864294Seric int stat; 8659370Seric register MAILER *m; 86610105Seric ENVELOPE *e; 867294Seric { 868294Seric register char *statmsg; 869294Seric extern char *SysExMsg[]; 870294Seric register int i; 871294Seric extern int N_SysEx; 87210105Seric char buf[MAXLINE]; 873294Seric 87412135Seric #ifdef lint 87512135Seric if (m == NULL) 87612135Seric return; 87712135Seric #endif lint 87812135Seric 8794315Seric /* 8804315Seric ** Compute status message from code. 8814315Seric */ 8824315Seric 883294Seric i = stat - EX__BASE; 8849370Seric if (stat == 0) 8859370Seric statmsg = "250 Sent"; 8869370Seric else if (i < 0 || i > N_SysEx) 8879370Seric { 8889370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 8899370Seric stat = EX_UNAVAILABLE; 8909370Seric statmsg = buf; 8919370Seric } 89210105Seric else if (stat == EX_TEMPFAIL) 89310105Seric { 89410124Seric (void) strcpy(buf, SysExMsg[i]); 89510124Seric if (errno != 0) 89610105Seric { 89715137Seric extern char *errstring(); 89815137Seric 89910124Seric (void) strcat(buf, ": "); 90015137Seric (void) strcat(buf, errstring(errno)); 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 ** 967*16150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 968*16150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 969*16150Seric ** does a well-meaning programmer such as myself have to deal with 970*16150Seric ** this kind of antique garbage???? 9716974Seric ** 972294Seric ** Parameters: 9736974Seric ** fp -- the file to output to. 9746974Seric ** m -- the mailer describing this entry. 975294Seric ** 976294Seric ** Returns: 9776974Seric ** none 978294Seric ** 979294Seric ** Side Effects: 9806974Seric ** outputs some text to fp. 981294Seric */ 982294Seric 98310168Seric putfromline(fp, m) 9846974Seric register FILE *fp; 9856974Seric register MAILER *m; 986294Seric { 987*16150Seric char *template = "\001l\n"; 9886974Seric char buf[MAXLINE]; 989294Seric 99010682Seric if (bitnset(M_NHDR, m->m_flags)) 9916974Seric return; 9924315Seric 9936974Seric # ifdef UGLYUUCP 99410682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 9954205Seric { 99612223Seric char *bang; 99712223Seric char xbuf[MAXLINE]; 9986041Seric 999*16150Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 100012223Seric bang = index(buf, '!'); 10016974Seric if (bang == NULL) 100212223Seric syserr("No ! in UUCP! (%s)", buf); 10035099Seric else 10049370Seric { 100512223Seric *bang++ = '\0'; 1006*16150Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 100712223Seric template = xbuf; 10089370Seric } 10096974Seric } 10105179Seric # endif UGLYUUCP 101112223Seric expand(template, buf, &buf[sizeof buf - 1], CurEnv); 101210168Seric putline(buf, fp, m); 10135981Seric } 10145981Seric /* 10156974Seric ** PUTBODY -- put the body of a message. 10166974Seric ** 10176974Seric ** Parameters: 10186974Seric ** fp -- file to output onto. 101910168Seric ** m -- a mailer descriptor to control output format. 10209538Seric ** e -- the envelope to put out. 10216974Seric ** 10226974Seric ** Returns: 10236974Seric ** none. 10246974Seric ** 10256974Seric ** Side Effects: 10266974Seric ** The message is written onto fp. 10276974Seric */ 10286974Seric 102910168Seric putbody(fp, m, e) 10306974Seric FILE *fp; 10319370Seric MAILER *m; 10329538Seric register ENVELOPE *e; 10336974Seric { 103410168Seric char buf[MAXLINE]; 10356974Seric 10366974Seric /* 10376974Seric ** Output the body of the message 10386974Seric */ 10396974Seric 10409538Seric if (e->e_dfp == NULL) 10416974Seric { 10429538Seric if (e->e_df != NULL) 10439538Seric { 10449538Seric e->e_dfp = fopen(e->e_df, "r"); 10459538Seric if (e->e_dfp == NULL) 10469538Seric syserr("Cannot open %s", e->e_df); 10479538Seric } 10489538Seric else 104910168Seric putline("<<< No Message Collected >>>", fp, m); 10509538Seric } 10519538Seric if (e->e_dfp != NULL) 10529538Seric { 10539538Seric rewind(e->e_dfp); 105410168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 105510168Seric putline(buf, fp, m); 10566974Seric 10579538Seric if (ferror(e->e_dfp)) 10586974Seric { 10596974Seric syserr("putbody: read error"); 10606974Seric ExitStat = EX_IOERR; 10616974Seric } 10626974Seric } 10636974Seric 10646974Seric (void) fflush(fp); 10656974Seric if (ferror(fp) && errno != EPIPE) 10666974Seric { 10676974Seric syserr("putbody: write error"); 10686974Seric ExitStat = EX_IOERR; 10696974Seric } 10706974Seric errno = 0; 10716974Seric } 10726974Seric /* 1073294Seric ** MAILFILE -- Send a message to a file. 1074294Seric ** 10754327Seric ** If the file has the setuid/setgid bits set, but NO execute 10764327Seric ** bits, sendmail will try to become the owner of that file 10774327Seric ** rather than the real user. Obviously, this only works if 10784327Seric ** sendmail runs as root. 10794327Seric ** 10809370Seric ** This could be done as a subordinate mailer, except that it 10819370Seric ** is used implicitly to save messages in ~/dead.letter. We 10829370Seric ** view this as being sufficiently important as to include it 10839370Seric ** here. For example, if the system is dying, we shouldn't have 10849370Seric ** to create another process plus some pipes to save the message. 10859370Seric ** 1086294Seric ** Parameters: 1087294Seric ** filename -- the name of the file to send to. 10884397Seric ** ctladdr -- the controlling address header -- includes 10894397Seric ** the userid/groupid to be when sending. 1090294Seric ** 1091294Seric ** Returns: 1092294Seric ** The exit code associated with the operation. 1093294Seric ** 1094294Seric ** Side Effects: 1095294Seric ** none. 1096294Seric */ 1097294Seric 10984397Seric mailfile(filename, ctladdr) 1099294Seric char *filename; 11004397Seric ADDRESS *ctladdr; 1101294Seric { 1102294Seric register FILE *f; 11034214Seric register int pid; 1104294Seric 11054214Seric /* 11064214Seric ** Fork so we can change permissions here. 11074214Seric ** Note that we MUST use fork, not vfork, because of 11084214Seric ** the complications of calling subroutines, etc. 11094214Seric */ 11104067Seric 11114214Seric DOFORK(fork); 11124214Seric 11134214Seric if (pid < 0) 11144214Seric return (EX_OSERR); 11154214Seric else if (pid == 0) 11164214Seric { 11174214Seric /* child -- actually write to file */ 11184327Seric struct stat stb; 11194327Seric 11204215Seric (void) signal(SIGINT, SIG_DFL); 11214215Seric (void) signal(SIGHUP, SIG_DFL); 11224215Seric (void) signal(SIGTERM, SIG_DFL); 11234327Seric umask(OldUmask); 11244327Seric if (stat(filename, &stb) < 0) 112511935Seric { 112611935Seric errno = 0; 11274431Seric stb.st_mode = 0666; 112811935Seric } 11294327Seric if (bitset(0111, stb.st_mode)) 11304327Seric exit(EX_CANTCREAT); 11314401Seric if (ctladdr == NULL) 11326900Seric ctladdr = &CurEnv->e_from; 11334327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 11344417Seric { 11354417Seric if (ctladdr->q_uid == 0) 11364417Seric (void) setgid(DefGid); 11374417Seric else 11384417Seric (void) setgid(ctladdr->q_gid); 11394417Seric } 11404327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 11414417Seric { 11424417Seric if (ctladdr->q_uid == 0) 11434417Seric (void) setuid(DefUid); 11444417Seric else 11454417Seric (void) setuid(ctladdr->q_uid); 11464417Seric } 11476887Seric f = dfopen(filename, "a"); 11484214Seric if (f == NULL) 11494214Seric exit(EX_CANTCREAT); 11504214Seric 115110168Seric putfromline(f, ProgMailer); 115210168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 115310168Seric putline("\n", f, ProgMailer); 115410168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 115510168Seric putline("\n", f, ProgMailer); 11564214Seric (void) fclose(f); 11574214Seric (void) fflush(stdout); 11584417Seric 11596887Seric /* reset ISUID & ISGID bits for paranoid systems */ 11604621Seric (void) chmod(filename, (int) stb.st_mode); 11614214Seric exit(EX_OK); 11624315Seric /*NOTREACHED*/ 11634214Seric } 11644214Seric else 11654214Seric { 11664214Seric /* parent -- wait for exit status */ 11679370Seric int st; 11684214Seric 11699370Seric st = waitfor(pid); 11709370Seric if ((st & 0377) != 0) 11719370Seric return (EX_UNAVAILABLE); 11729370Seric else 11739370Seric return ((st >> 8) & 0377); 11744214Seric } 1175294Seric } 11764550Seric /* 11774550Seric ** SENDALL -- actually send all the messages. 11784550Seric ** 11794550Seric ** Parameters: 11807043Seric ** e -- the envelope to send. 118114874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 118214874Seric ** the current SendMode. 11834550Seric ** 11844550Seric ** Returns: 11854550Seric ** none. 11864550Seric ** 11874550Seric ** Side Effects: 11884550Seric ** Scans the send lists and sends everything it finds. 11897043Seric ** Delivers any appropriate error messages. 11909275Seric ** If we are running in a non-interactive mode, takes the 11919275Seric ** appropriate action. 11924550Seric */ 11934550Seric 11949275Seric sendall(e, mode) 11957043Seric ENVELOPE *e; 11969275Seric char mode; 11974550Seric { 11985008Seric register ADDRESS *q; 11997779Seric bool oldverbose; 12009275Seric int pid; 12014550Seric 120214874Seric /* determine actual delivery mode */ 120314874Seric if (mode == SM_DEFAULT) 120414874Seric { 120514874Seric extern int QueueLA; 120614874Seric 120714874Seric if (getla() > QueueLA) 120814874Seric mode = SM_QUEUE; 120914874Seric else 121014874Seric mode = SendMode; 121114874Seric } 121214874Seric 12139370Seric #ifdef DEBUG 12148248Seric if (tTd(13, 1)) 12155032Seric { 12169275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 12177043Seric printaddr(e->e_sendqueue, TRUE); 12185032Seric } 12199370Seric #endif DEBUG 12205008Seric 12217043Seric /* 12229275Seric ** Do any preprocessing necessary for the mode we are running. 12239370Seric ** Check to make sure the hop count is reasonable. 12249370Seric ** Delete sends to the sender in mailing lists. 12257043Seric */ 12267043Seric 12279370Seric CurEnv = e; 12289370Seric 12299370Seric if (e->e_hopcount > MAXHOP) 12309275Seric { 12319370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 12329370Seric return; 12339370Seric } 12349275Seric 12359370Seric if (!MeToo) 12369370Seric { 123712611Seric extern ADDRESS *recipient(); 123812611Seric 12399370Seric e->e_from.q_flags |= QDONTSEND; 124012611Seric (void) recipient(&e->e_from, &e->e_sendqueue); 12419275Seric } 12429370Seric 12439370Seric # ifdef QUEUE 12449335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 12459335Seric (mode != SM_VERIFY && SuperSafe)) && 12469335Seric !bitset(EF_INQUEUE, e->e_flags)) 12479370Seric queueup(e, TRUE, mode == SM_QUEUE); 12489275Seric #endif QUEUE 12499275Seric 12507779Seric oldverbose = Verbose; 12519275Seric switch (mode) 12529275Seric { 12539275Seric case SM_VERIFY: 12547779Seric Verbose = TRUE; 12559275Seric break; 12569275Seric 12579275Seric case SM_QUEUE: 12589335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 12599275Seric return; 12609275Seric 12619275Seric case SM_FORK: 12629538Seric if (e->e_xfp != NULL) 12639538Seric (void) fflush(e->e_xfp); 12649275Seric pid = fork(); 12659275Seric if (pid < 0) 12669275Seric { 12679275Seric mode = SM_DELIVER; 12689275Seric break; 12699275Seric } 12709275Seric else if (pid > 0) 12719293Seric { 12729293Seric /* be sure we leave the temp files to our child */ 12739335Seric e->e_id = e->e_df = NULL; 12749275Seric return; 12759293Seric } 12769275Seric 12779275Seric /* double fork to avoid zombies */ 12789275Seric if (fork() > 0) 12799275Seric exit(EX_OK); 12809275Seric 12819293Seric /* be sure we are immune from the terminal */ 128210133Seric disconnect(FALSE); 12839293Seric 12849275Seric break; 12859275Seric } 12869275Seric 12879275Seric /* 12889275Seric ** Run through the list and send everything. 12899275Seric */ 12909275Seric 12917043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12924550Seric { 12939275Seric if (mode == SM_VERIFY) 12944550Seric { 12959293Seric e->e_to = q->q_paddr; 12965008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 12977052Seric message(Arpa_Info, "deliverable"); 12984550Seric } 12995008Seric else 13009370Seric (void) deliver(e, q); 13014550Seric } 13027779Seric Verbose = oldverbose; 13037043Seric 13047043Seric /* 13057043Seric ** Now run through and check for errors. 13067043Seric */ 13077043Seric 13089275Seric if (mode == SM_VERIFY) 13097043Seric return; 13107043Seric 13117043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13127043Seric { 13137043Seric register ADDRESS *qq; 13147043Seric 13158248Seric # ifdef DEBUG 13168248Seric if (tTd(13, 3)) 13178248Seric { 13188248Seric printf("Checking "); 13198248Seric printaddr(q, FALSE); 13208248Seric } 13218248Seric # endif DEBUG 13228248Seric 13239335Seric /* only send errors if the message failed */ 13249335Seric if (!bitset(QBADADDR, q->q_flags)) 13259335Seric continue; 13267043Seric 13277043Seric /* we have an address that failed -- find the parent */ 13287043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 13297043Seric { 13307043Seric char obuf[MAXNAME + 6]; 13317043Seric extern char *aliaslookup(); 13327043Seric 13337043Seric /* we can only have owners for local addresses */ 133410682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 13357043Seric continue; 13367043Seric 13377043Seric /* see if the owner list exists */ 13387043Seric (void) strcpy(obuf, "owner-"); 13397047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 13407047Seric (void) strcat(obuf, "owner"); 13417047Seric else 13427047Seric (void) strcat(obuf, qq->q_user); 13437043Seric if (aliaslookup(obuf) == NULL) 13447043Seric continue; 13457043Seric 13468248Seric # ifdef DEBUG 13478248Seric if (tTd(13, 4)) 13488248Seric printf("Errors to %s\n", obuf); 13498248Seric # endif DEBUG 13508248Seric 13517043Seric /* owner list exists -- add it to the error queue */ 13529615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 13539370Seric ErrorMode == EM_MAIL; 13547043Seric break; 13557043Seric } 13567043Seric 13577043Seric /* if we did not find an owner, send to the sender */ 13588426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 13599615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 13607043Seric } 13619275Seric 13629275Seric if (mode == SM_FORK) 13639275Seric finis(); 13644550Seric } 1365