1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*10306Seric SCCSID(@(#)deliver.c 3.146 01/15/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; 39*10306Seric 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 */ 45*10306Seric char *pv[MAXPV+1]; 46*10306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 47*10306Seric char buf[MAXNAME]; 48*10306Seric char tfrombuf[MAXNAME]; /* translated from person */ 49*10306Seric extern bool checkcompat(); 50*10306Seric extern ADDRESS *getctladdr(); 51*10306Seric 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 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); 106*10306Seric (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 */ 1153233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1163233Seric { 1173233Seric if (bitset(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 */ 1824382Seric if (tobuf[0] != '\0' && !bitset(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 2163233Seric if (!checkcompat(to)) 217294Seric { 21810105Seric giveresponse(EX_UNAVAILABLE, m, e); 2193233Seric continue; 220294Seric } 2213233Seric 2223233Seric /* 2234099Seric ** Strip quote bits from names if the mailer is dumb 2244099Seric ** about them. 2253233Seric */ 2263233Seric 2273233Seric if (bitset(M_STRIPQ, m->m_flags)) 228294Seric { 2294099Seric stripquotes(user, TRUE); 2304099Seric stripquotes(host, TRUE); 2313233Seric } 2324099Seric else 2334099Seric { 2344099Seric stripquotes(user, FALSE); 2354099Seric stripquotes(host, FALSE); 2364099Seric } 2373233Seric 2389206Seric /* hack attack -- delivermail compatibility */ 2399206Seric if (m == ProgMailer && *user == '|') 2409206Seric user++; 2419206Seric 2423233Seric /* 2434161Seric ** If an error message has already been given, don't 2444161Seric ** bother to send to this address. 2454161Seric ** 2464161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2474161Seric ** >> NOTE >> cannot do any further aliasing; that 2484161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2494161Seric */ 2504161Seric 2517293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2524161Seric continue; 2534161Seric 2544283Seric /* save statistics.... */ 2559370Seric markstats(e, to); 2564283Seric 2574161Seric /* 2583233Seric ** See if this user name is "special". 2593233Seric ** If the user name has a slash in it, assume that this 2606974Seric ** is a file -- send it off without further ado. Note 2616974Seric ** that this type of addresses is not processed along 2626974Seric ** with the others, so we fudge on the To person. 2633233Seric */ 2643233Seric 2654596Seric if (m == LocalMailer) 2663233Seric { 2675599Seric if (user[0] == '/') 268294Seric { 2698003Seric rcode = mailfile(user, getctladdr(to)); 27010105Seric giveresponse(rcode, m, e); 2713233Seric continue; 272294Seric } 273294Seric } 2743233Seric 2754315Seric /* 2764315Seric ** Address is verified -- add this user to mailer 2774315Seric ** argv, and add it to the print list of recipients. 2784315Seric */ 2794315Seric 2806059Seric /* link together the chain of recipients */ 2816272Seric to->q_tchain = tochain; 2826272Seric tochain = to; 2836059Seric 2843233Seric /* create list of users for error messages */ 2859388Seric (void) strcat(tobuf, ","); 2864082Seric (void) strcat(tobuf, to->q_paddr); 2879370Seric define('u', user, e); /* to user */ 2889370Seric define('z', to->q_home, e); /* user's home */ 2893233Seric 2904863Seric /* 2916059Seric ** Expand out this user into argument list. 2924863Seric */ 2934863Seric 2946059Seric if (!clever) 2953233Seric { 2969370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 2974863Seric *pvp++ = newstr(buf); 2984863Seric if (pvp >= &pv[MAXPV - 2]) 2994863Seric { 3004863Seric /* allow some space for trailing parms */ 3014863Seric break; 3024863Seric } 3034863Seric } 304294Seric } 305294Seric 3064067Seric /* see if any addresses still exist */ 3074067Seric if (tobuf[0] == '\0') 3084863Seric { 3099370Seric define('g', (char *) NULL, e); 3104067Seric return (0); 3114863Seric } 3124067Seric 3133233Seric /* print out messages as full list */ 3149388Seric e->e_to = tobuf + 1; 3153233Seric 316294Seric /* 3173233Seric ** Fill out any parameters after the $u parameter. 318294Seric */ 319294Seric 3204863Seric while (!clever && *++mvp != NULL) 321294Seric { 3229370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3233233Seric *pvp++ = newstr(buf); 3243233Seric if (pvp >= &pv[MAXPV]) 3253233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 326294Seric } 3273233Seric *pvp++ = NULL; 328294Seric 329294Seric /* 330294Seric ** Call the mailer. 3312898Seric ** The argument vector gets built, pipes 332294Seric ** are created as necessary, and we fork & exec as 3332898Seric ** appropriate. 3344863Seric ** If we are running SMTP, we just need to clean up. 335294Seric */ 336294Seric 3379370Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 3389370Seric 3394397Seric if (ctladdr == NULL) 3409370Seric ctladdr = &e->e_from; 3415179Seric # ifdef SMTP 3424863Seric if (clever) 3434863Seric { 3449370Seric /* send the initial SMTP protocol */ 34510168Seric rcode = smtpinit(m, pv); 3469370Seric 3479388Seric if (rcode == EX_OK) 3489370Seric { 3499388Seric /* send the recipient list */ 3509388Seric tobuf[0] = '\0'; 3519388Seric for (to = tochain; to != NULL; to = to->q_tchain) 3529388Seric { 3539388Seric int i; 3549370Seric 3559388Seric e->e_to = to->q_paddr; 35610168Seric i = smtprcpt(to, m); 3579388Seric if (i != EX_OK) 3589388Seric { 35910092Seric markfailure(e, to, i); 36010105Seric giveresponse(i, m, e); 3619388Seric } 3629388Seric else 3639388Seric { 3649388Seric strcat(tobuf, ","); 3659388Seric strcat(tobuf, to->q_paddr); 3669388Seric } 3679388Seric } 3689388Seric 3699388Seric /* now send the data */ 3709388Seric if (tobuf[0] == '\0') 3719388Seric e->e_to = NULL; 3729370Seric else 3739370Seric { 3749388Seric e->e_to = tobuf + 1; 37510168Seric rcode = smtpdata(m, e); 3769370Seric } 3779388Seric 3789388Seric /* now close the connection */ 37910168Seric smtpquit(pv[0], m); 3809370Seric } 3814863Seric } 3824863Seric else 3835179Seric # endif SMTP 38410168Seric rcode = sendoff(e, m, pv, ctladdr); 3853233Seric 3864621Seric /* 3879388Seric ** Do final status disposal. 3889388Seric ** We check for something in tobuf for the SMTP case. 3899388Seric ** If we got a temporary failure, arrange to queue the 3909388Seric ** addressees. 3914621Seric */ 3924621Seric 3939388Seric if (tobuf[0] != '\0') 39410105Seric giveresponse(rcode, m, e); 3959388Seric if (rcode != EX_OK) 3964621Seric { 3975032Seric for (to = tochain; to != NULL; to = to->q_tchain) 39810092Seric markfailure(e, to, rcode); 3994621Seric } 4004621Seric 4014488Seric errno = 0; 4029370Seric define('g', (char *) NULL, e); 4038003Seric return (rcode); 4043233Seric } 4053233Seric /* 40610092Seric ** MARKFAILURE -- mark a failure on a specific address. 40710092Seric ** 40810092Seric ** Parameters: 40910092Seric ** e -- the envelope we are sending. 41010092Seric ** q -- the address to mark. 41110092Seric ** rcode -- the code signifying the particular failure. 41210092Seric ** 41310092Seric ** Returns: 41410092Seric ** none. 41510092Seric ** 41610092Seric ** Side Effects: 41710092Seric ** marks the address (and possibly the envelope) with the 41810092Seric ** failure so that an error will be returned or 41910092Seric ** the message will be queued, as appropriate. 42010092Seric */ 42110092Seric 42210092Seric markfailure(e, q, rcode) 42310092Seric register ENVELOPE *e; 42410092Seric register ADDRESS *q; 42510092Seric int rcode; 42610092Seric { 42710092Seric if (rcode == EX_OK) 42810092Seric return; 42910092Seric else if (rcode != EX_TEMPFAIL) 43010092Seric q->q_flags |= QBADADDR; 43110092Seric else if (curtime() > e->e_ctime + TimeOut) 43210092Seric { 43310092Seric extern char *pintvl(); 43410105Seric char buf[MAXLINE]; 43510092Seric 43610092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 43710105Seric { 43810105Seric (void) sprintf(buf, "Cannot send message for %s", 43910092Seric pintvl(TimeOut, FALSE)); 44010105Seric if (e->e_message != NULL) 44110105Seric free(e->e_message); 44210105Seric e->e_message = newstr(buf); 44310105Seric message(Arpa_Info, buf); 44410105Seric } 44510092Seric q->q_flags |= QBADADDR; 44610092Seric e->e_flags |= EF_TIMEOUT; 44710092Seric } 44810092Seric else 44910092Seric q->q_flags |= QQUEUEUP; 45010092Seric } 45110092Seric /* 4524214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4534214Seric ** 4544214Seric ** This MUST be a macro, since after a vfork we are running 4554214Seric ** two processes on the same stack!!! 4564214Seric ** 4574214Seric ** Parameters: 4584214Seric ** none. 4594214Seric ** 4604214Seric ** Returns: 4614214Seric ** From a macro??? You've got to be kidding! 4624214Seric ** 4634214Seric ** Side Effects: 4644214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4654214Seric ** pid of child in parent, zero in child. 4664214Seric ** -1 on unrecoverable error. 4674214Seric ** 4684214Seric ** Notes: 4694214Seric ** I'm awfully sorry this looks so awful. That's 4704214Seric ** vfork for you..... 4714214Seric */ 4724214Seric 4734214Seric # define NFORKTRIES 5 4749148Seric # ifdef VMUNIX 4754214Seric # define XFORK vfork 4769148Seric # else VMUNIX 4774214Seric # define XFORK fork 4789148Seric # endif VMUNIX 4794214Seric 4804214Seric # define DOFORK(fORKfN) \ 4814214Seric {\ 4824214Seric register int i;\ 4834214Seric \ 4844214Seric for (i = NFORKTRIES; i-- > 0; )\ 4854214Seric {\ 4864214Seric pid = fORKfN();\ 4874214Seric if (pid >= 0)\ 4884214Seric break;\ 4897003Seric sleep(NFORKTRIES - i);\ 4904214Seric }\ 4914214Seric } 4924214Seric /* 4934637Seric ** DOFORK -- simple fork interface to DOFORK. 4944637Seric ** 4954637Seric ** Parameters: 4964637Seric ** none. 4974637Seric ** 4984637Seric ** Returns: 4994637Seric ** pid of child in parent. 5004637Seric ** zero in child. 5014637Seric ** -1 on error. 5024637Seric ** 5034637Seric ** Side Effects: 5044637Seric ** returns twice, once in parent and once in child. 5054637Seric */ 5064637Seric 5074637Seric dofork() 5084637Seric { 5094637Seric register int pid; 5104637Seric 5114637Seric DOFORK(fork); 5124637Seric return (pid); 5134637Seric } 5144637Seric /* 5153233Seric ** SENDOFF -- send off call to mailer & collect response. 5163233Seric ** 5173233Seric ** Parameters: 5189370Seric ** e -- the envelope to mail. 5193233Seric ** m -- mailer descriptor. 5203233Seric ** pvp -- parameter vector to send to it. 5214397Seric ** ctladdr -- an address pointer controlling the 5224397Seric ** user/groupid etc. of the mailer. 5233233Seric ** 5243233Seric ** Returns: 5253233Seric ** exit status of mailer. 5263233Seric ** 5273233Seric ** Side Effects: 5283233Seric ** none. 5293233Seric */ 5303233Seric 53110168Seric sendoff(e, m, pvp, ctladdr) 5329370Seric register ENVELOPE *e; 5339370Seric MAILER *m; 5343233Seric char **pvp; 5354397Seric ADDRESS *ctladdr; 5363233Seric { 5374863Seric auto FILE *mfile; 5384863Seric auto FILE *rfile; 5393233Seric register int i; 5403233Seric int pid; 5414863Seric 5424863Seric /* 5434863Seric ** Create connection to mailer. 5444863Seric */ 5454863Seric 5464863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5474863Seric if (pid < 0) 5484863Seric return (-1); 5494863Seric 5504863Seric /* 5514863Seric ** Format and send message. 5524863Seric */ 5534863Seric 55410168Seric putfromline(mfile, m); 55510168Seric (*e->e_puthdr)(mfile, m, e); 55610168Seric putline("\n", mfile, m); 55710168Seric (*e->e_putbody)(mfile, m, e); 5584863Seric (void) fclose(mfile); 5594863Seric 5604863Seric i = endmailer(pid, pvp[0]); 5615981Seric 5625981Seric /* arrange a return receipt if requested */ 5639370Seric if (e->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 5645981Seric { 5659370Seric e->e_flags |= EF_SENDRECEIPT; 5665981Seric /* do we want to send back more info? */ 5675981Seric } 5685981Seric 5694863Seric return (i); 5704863Seric } 5714863Seric /* 5724863Seric ** ENDMAILER -- Wait for mailer to terminate. 5734863Seric ** 5744863Seric ** We should never get fatal errors (e.g., segmentation 5754863Seric ** violation), so we report those specially. For other 5764863Seric ** errors, we choose a status message (into statmsg), 5774863Seric ** and if it represents an error, we print it. 5784863Seric ** 5794863Seric ** Parameters: 5804863Seric ** pid -- pid of mailer. 5814863Seric ** name -- name of mailer (for error messages). 5824863Seric ** 5834863Seric ** Returns: 5844863Seric ** exit code of mailer. 5854863Seric ** 5864863Seric ** Side Effects: 5874863Seric ** none. 5884863Seric */ 5894863Seric 5904863Seric endmailer(pid, name) 5914863Seric int pid; 5924863Seric char *name; 5934863Seric { 5949370Seric int st; 5954863Seric 5966038Seric /* in the IPC case there is nothing to wait for */ 5976038Seric if (pid == 0) 5986038Seric return (EX_OK); 5996038Seric 6006038Seric /* wait for the mailer process to die and collect status */ 6019370Seric st = waitfor(pid); 6029370Seric if (st == -1) 6038127Seric { 6049370Seric syserr("endmailer %s: wait", name); 6059370Seric return (EX_SOFTWARE); 6064863Seric } 6076038Seric 6086038Seric /* see if it died a horrid death */ 6094863Seric if ((st & 0377) != 0) 6104863Seric { 6119370Seric syserr("endmailer %s: stat %o", name, st); 6124863Seric ExitStat = EX_UNAVAILABLE; 6139370Seric return (EX_UNAVAILABLE); 6144863Seric } 6156038Seric 6166038Seric /* normal death -- return status */ 6179370Seric st = (st >> 8) & 0377; 6189370Seric return (st); 6194863Seric } 6204863Seric /* 6214863Seric ** OPENMAILER -- open connection to mailer. 6224863Seric ** 6234863Seric ** Parameters: 6244863Seric ** m -- mailer descriptor. 6254863Seric ** pvp -- parameter vector to pass to mailer. 6264863Seric ** ctladdr -- controlling address for user. 6274863Seric ** clever -- create a full duplex connection. 6284863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6294863Seric ** prfile -- pointer to rfile (from mailer) connection. 6304863Seric ** 6314863Seric ** Returns: 6326038Seric ** pid of mailer ( > 0 ). 6334863Seric ** -1 on error. 6346038Seric ** zero on an IPC connection. 6354863Seric ** 6364863Seric ** Side Effects: 6374863Seric ** creates a mailer in a subprocess. 6384863Seric */ 6394863Seric 6404863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6419370Seric MAILER *m; 6424863Seric char **pvp; 6434863Seric ADDRESS *ctladdr; 6444863Seric bool clever; 6454863Seric FILE **pmfile; 6464863Seric FILE **prfile; 6474863Seric { 6484863Seric int pid; 6494709Seric int mpvect[2]; 6504863Seric int rpvect[2]; 6513233Seric FILE *mfile; 6524863Seric FILE *rfile; 6533233Seric extern FILE *fdopen(); 6543233Seric 6553233Seric # ifdef DEBUG 6567672Seric if (tTd(11, 1)) 657294Seric { 6588178Seric printf("openmailer:"); 6593233Seric printav(pvp); 660294Seric } 6613233Seric # endif DEBUG 6624488Seric errno = 0; 6633233Seric 6646038Seric /* 6656038Seric ** Deal with the special case of mail handled through an IPC 6666038Seric ** connection. 6676038Seric ** In this case we don't actually fork. We must be 6686038Seric ** running SMTP for this to work. We will return a 6696038Seric ** zero pid to indicate that we are running IPC. 6706038Seric */ 6716038Seric 6726038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6736038Seric { 6749370Seric #ifdef DAEMON 6756038Seric register int i; 6767285Seric register u_short port; 6776038Seric 6786038Seric if (!clever) 6796038Seric syserr("non-clever IPC"); 6806632Seric if (pvp[2] != NULL) 6817285Seric port = atoi(pvp[2]); 6826632Seric else 6837285Seric port = 0; 6847285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 6856038Seric if (i != EX_OK) 6866047Seric { 6876047Seric ExitStat = i; 6886038Seric return (-1); 6896047Seric } 6906038Seric else 6916038Seric return (0); 6929370Seric #else DAEMON 6939370Seric syserr("openmailer: no IPC"); 6949370Seric return (-1); 6959370Seric #endif DAEMON 6966038Seric } 6976038Seric 6982898Seric /* create a pipe to shove the mail through */ 6994709Seric if (pipe(mpvect) < 0) 700294Seric { 7019370Seric syserr("openmailer: pipe (to mailer)"); 702294Seric return (-1); 703294Seric } 7044863Seric 7059370Seric #ifdef SMTP 7064863Seric /* if this mailer speaks smtp, create a return pipe */ 7074863Seric if (clever && pipe(rpvect) < 0) 7084863Seric { 7099370Seric syserr("openmailer: pipe (from mailer)"); 7104863Seric (void) close(mpvect[0]); 7114863Seric (void) close(mpvect[1]); 7124863Seric return (-1); 7134863Seric } 7149370Seric #endif SMTP 7154863Seric 7166038Seric /* 7176038Seric ** Actually fork the mailer process. 7186038Seric ** DOFORK is clever about retrying. 7196038Seric */ 7206038Seric 7219538Seric if (CurEnv->e_xfp != NULL) 7229538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7239370Seric (void) fflush(stdout); 7244214Seric DOFORK(XFORK); 7254327Seric /* pid is set by DOFORK */ 726294Seric if (pid < 0) 727294Seric { 7286038Seric /* failure */ 7299370Seric syserr("openmailer: cannot fork"); 7304709Seric (void) close(mpvect[0]); 7314709Seric (void) close(mpvect[1]); 7329370Seric #ifdef SMTP 7334863Seric if (clever) 7344863Seric { 7354863Seric (void) close(rpvect[0]); 7364863Seric (void) close(rpvect[1]); 7374863Seric } 7389370Seric #endif SMTP 739294Seric return (-1); 740294Seric } 741294Seric else if (pid == 0) 742294Seric { 743294Seric /* child -- set up input & exec mailer */ 7441621Seric /* make diagnostic output be standard output */ 7454477Seric (void) signal(SIGINT, SIG_IGN); 7464477Seric (void) signal(SIGHUP, SIG_IGN); 7474215Seric (void) signal(SIGTERM, SIG_DFL); 7484709Seric 7494709Seric /* arrange to filter standard & diag output of command */ 7504863Seric if (clever) 7514709Seric { 7524863Seric (void) close(rpvect[0]); 7534709Seric (void) close(1); 7544863Seric (void) dup(rpvect[1]); 7554863Seric (void) close(rpvect[1]); 7564863Seric } 7579275Seric else if (OpMode == MD_SMTP || HoldErrs) 7584863Seric { 7599370Seric /* put mailer output in transcript */ 7604863Seric (void) close(1); 7619538Seric (void) dup(fileno(CurEnv->e_xfp)); 7624709Seric } 7634082Seric (void) close(2); 7644082Seric (void) dup(1); 7654709Seric 7664709Seric /* arrange to get standard input */ 7674709Seric (void) close(mpvect[1]); 7684082Seric (void) close(0); 7694709Seric if (dup(mpvect[0]) < 0) 770294Seric { 7712898Seric syserr("Cannot dup to zero!"); 7722898Seric _exit(EX_OSERR); 773294Seric } 7744709Seric (void) close(mpvect[0]); 7752968Seric if (!bitset(M_RESTR, m->m_flags)) 7764215Seric { 7774417Seric if (ctladdr->q_uid == 0) 7784417Seric { 7794417Seric (void) setgid(DefGid); 7804417Seric (void) setuid(DefUid); 7814417Seric } 7824417Seric else 7834415Seric { 7844417Seric (void) setgid(ctladdr->q_gid); 7854417Seric (void) setuid(ctladdr->q_uid); 7864415Seric } 7874215Seric } 7889370Seric 7892774Seric /* 7902774Seric ** We have to be careful with vfork - we can't mung up the 7912774Seric ** memory but we don't want the mailer to inherit any extra 7922774Seric ** open files. Chances are the mailer won't 7932774Seric ** care about an extra file, but then again you never know. 7942774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7952774Seric ** declared static so we can't. But if we fclose(pwf), which 7962774Seric ** is what endpwent does, it closes it in the parent too and 7972774Seric ** the next getpwnam will be slower. If you have a weird 7982774Seric ** mailer that chokes on the extra file you should do the 7999148Seric ** endpwent(). -MRH 8002774Seric ** 8012774Seric ** Similar comments apply to log. However, openlog is 8022774Seric ** clever enough to set the FIOCLEX mode on the file, 8032774Seric ** so it will be closed automatically on the exec. 8042774Seric */ 8052774Seric 8069370Seric closeall(); 8076038Seric 8086038Seric /* try to execute the mailer */ 809294Seric execv(m->m_mailer, pvp); 8106038Seric 811294Seric /* syserr fails because log is closed */ 812294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 8134214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 8144082Seric (void) fflush(stdout); 8151619Seric _exit(EX_UNAVAILABLE); 816294Seric } 817294Seric 8184709Seric /* 8194863Seric ** Set up return value. 8204709Seric */ 8214709Seric 8224709Seric (void) close(mpvect[0]); 8234709Seric mfile = fdopen(mpvect[1], "w"); 8244863Seric if (clever) 8254863Seric { 8264863Seric (void) close(rpvect[1]); 8274863Seric rfile = fdopen(rpvect[0], "r"); 8284863Seric } 829294Seric 8304863Seric *pmfile = mfile; 8314863Seric *prfile = rfile; 832294Seric 8334863Seric return (pid); 834294Seric } 835294Seric /* 836294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 837294Seric ** 838294Seric ** Parameters: 839294Seric ** stat -- the status code from the mailer (high byte 840294Seric ** only; core dumps must have been taken care of 841294Seric ** already). 842294Seric ** m -- the mailer descriptor for this mailer. 843294Seric ** 844294Seric ** Returns: 8454082Seric ** none. 846294Seric ** 847294Seric ** Side Effects: 8481518Seric ** Errors may be incremented. 849294Seric ** ExitStat may be set. 850294Seric */ 851294Seric 8529370Seric /*ARGSUSED*/ 85310105Seric giveresponse(stat, m, e) 854294Seric int stat; 8559370Seric register MAILER *m; 85610105Seric ENVELOPE *e; 857294Seric { 858294Seric register char *statmsg; 859294Seric extern char *SysExMsg[]; 860294Seric register int i; 861294Seric extern int N_SysEx; 86210105Seric char buf[MAXLINE]; 863294Seric 8644315Seric /* 8654315Seric ** Compute status message from code. 8664315Seric */ 8674315Seric 868294Seric i = stat - EX__BASE; 8699370Seric if (stat == 0) 8709370Seric statmsg = "250 Sent"; 8719370Seric else if (i < 0 || i > N_SysEx) 8729370Seric { 8739370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 8749370Seric stat = EX_UNAVAILABLE; 8759370Seric statmsg = buf; 8769370Seric } 87710105Seric else if (stat == EX_TEMPFAIL) 87810105Seric { 87910105Seric extern char *sys_errlist[]; 88010105Seric extern int sys_nerr; 88110105Seric 88210124Seric (void) strcpy(buf, SysExMsg[i]); 88310124Seric if (errno != 0) 88410105Seric { 88510124Seric (void) strcat(buf, ": "); 88610124Seric if (errno > 0 && errno < sys_nerr) 88710124Seric (void) strcat(buf, sys_errlist[errno]); 88810124Seric else 88910124Seric { 89010124Seric char xbuf[30]; 89110124Seric 89210124Seric (void) sprintf(xbuf, "Error %d", errno); 89310124Seric (void) strcat(buf, xbuf); 89410124Seric } 89510105Seric } 89610105Seric statmsg = buf; 89710105Seric } 898294Seric else 899294Seric statmsg = SysExMsg[i]; 9009370Seric 9019370Seric /* 9029370Seric ** Print the message as appropriate 9039370Seric */ 9049370Seric 90510105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 9068003Seric message(Arpa_Info, &statmsg[4]); 907294Seric else 908294Seric { 9091518Seric Errors++; 9109370Seric usrerr(statmsg); 911294Seric } 912294Seric 913294Seric /* 914294Seric ** Final cleanup. 915294Seric ** Log a record of the transaction. Compute the new 916294Seric ** ExitStat -- if we already had an error, stick with 917294Seric ** that. 918294Seric */ 919294Seric 9207680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 9218496Seric logdelivery(&statmsg[4]); 9227858Seric 9234621Seric if (stat != EX_TEMPFAIL) 9244621Seric setstat(stat); 92510105Seric if (stat != EX_OK) 92610105Seric { 92710105Seric if (e->e_message != NULL) 92810105Seric free(e->e_message); 92910105Seric e->e_message = newstr(&statmsg[4]); 93010105Seric } 93110124Seric errno = 0; 932294Seric } 933294Seric /* 9348496Seric ** LOGDELIVERY -- log the delivery in the system log 9358496Seric ** 9368496Seric ** Parameters: 9378496Seric ** stat -- the message to print for the status 9388496Seric ** 9398496Seric ** Returns: 9408496Seric ** none 9418496Seric ** 9428496Seric ** Side Effects: 9438496Seric ** none 9448496Seric */ 9458496Seric 9468496Seric logdelivery(stat) 9478496Seric char *stat; 9488496Seric { 9498496Seric extern char *pintvl(); 9508496Seric 9518496Seric # ifdef LOG 9528496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 9538496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 9548496Seric # endif LOG 9558496Seric } 9568496Seric /* 9576974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 958294Seric ** 9596974Seric ** This can be made an arbitrary message separator by changing $l 960294Seric ** 9616974Seric ** One of the ugliest hacks seen by human eyes is 9626974Seric ** contained herein: UUCP wants those stupid 9639370Seric ** "emote from <host>" lines. Why oh why does a 9646974Seric ** well-meaning programmer such as myself have to 9656974Seric ** deal with this kind of antique garbage???? 9666974Seric ** 967294Seric ** Parameters: 9686974Seric ** fp -- the file to output to. 9696974Seric ** m -- the mailer describing this entry. 970294Seric ** 971294Seric ** Returns: 9726974Seric ** none 973294Seric ** 974294Seric ** Side Effects: 9756974Seric ** outputs some text to fp. 976294Seric */ 977294Seric 97810168Seric putfromline(fp, m) 9796974Seric register FILE *fp; 9806974Seric register MAILER *m; 981294Seric { 9826974Seric char buf[MAXLINE]; 983294Seric 9846974Seric if (bitset(M_NHDR, m->m_flags)) 9856974Seric return; 9864315Seric 9876974Seric # ifdef UGLYUUCP 9886974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9894205Seric { 9906974Seric extern char *macvalue(); 9918178Seric char *sys = macvalue('g', CurEnv); 9926974Seric char *bang = index(sys, '!'); 9936041Seric 9946974Seric if (bang == NULL) 9956974Seric syserr("No ! in UUCP! (%s)", sys); 9965099Seric else 9979370Seric { 9986974Seric *bang = '\0'; 9999370Seric expand("From $f $d remote from $g\n", buf, 10009370Seric &buf[sizeof buf - 1], CurEnv); 10019370Seric *bang = '!'; 10029370Seric } 10036974Seric } 10046974Seric else 10055179Seric # endif UGLYUUCP 10066974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 100710168Seric putline(buf, fp, m); 10085981Seric } 10095981Seric /* 10106974Seric ** PUTBODY -- put the body of a message. 10116974Seric ** 10126974Seric ** Parameters: 10136974Seric ** fp -- file to output onto. 101410168Seric ** m -- a mailer descriptor to control output format. 10159538Seric ** e -- the envelope to put out. 10166974Seric ** 10176974Seric ** Returns: 10186974Seric ** none. 10196974Seric ** 10206974Seric ** Side Effects: 10216974Seric ** The message is written onto fp. 10226974Seric */ 10236974Seric 102410168Seric putbody(fp, m, e) 10256974Seric FILE *fp; 10269370Seric MAILER *m; 10279538Seric register ENVELOPE *e; 10286974Seric { 102910168Seric char buf[MAXLINE]; 10306974Seric 10316974Seric /* 10326974Seric ** Output the body of the message 10336974Seric */ 10346974Seric 10359538Seric if (e->e_dfp == NULL) 10366974Seric { 10379538Seric if (e->e_df != NULL) 10389538Seric { 10399538Seric e->e_dfp = fopen(e->e_df, "r"); 10409538Seric if (e->e_dfp == NULL) 10419538Seric syserr("Cannot open %s", e->e_df); 10429538Seric } 10439538Seric else 104410168Seric putline("<<< No Message Collected >>>", fp, m); 10459538Seric } 10469538Seric if (e->e_dfp != NULL) 10479538Seric { 10489538Seric rewind(e->e_dfp); 104910168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 105010168Seric putline(buf, fp, m); 10516974Seric 10529538Seric if (ferror(e->e_dfp)) 10536974Seric { 10546974Seric syserr("putbody: read error"); 10556974Seric ExitStat = EX_IOERR; 10566974Seric } 10576974Seric } 10586974Seric 10596974Seric (void) fflush(fp); 10606974Seric if (ferror(fp) && errno != EPIPE) 10616974Seric { 10626974Seric syserr("putbody: write error"); 10636974Seric ExitStat = EX_IOERR; 10646974Seric } 10656974Seric errno = 0; 10666974Seric } 10676974Seric /* 1068294Seric ** MAILFILE -- Send a message to a file. 1069294Seric ** 10704327Seric ** If the file has the setuid/setgid bits set, but NO execute 10714327Seric ** bits, sendmail will try to become the owner of that file 10724327Seric ** rather than the real user. Obviously, this only works if 10734327Seric ** sendmail runs as root. 10744327Seric ** 10759370Seric ** This could be done as a subordinate mailer, except that it 10769370Seric ** is used implicitly to save messages in ~/dead.letter. We 10779370Seric ** view this as being sufficiently important as to include it 10789370Seric ** here. For example, if the system is dying, we shouldn't have 10799370Seric ** to create another process plus some pipes to save the message. 10809370Seric ** 1081294Seric ** Parameters: 1082294Seric ** filename -- the name of the file to send to. 10834397Seric ** ctladdr -- the controlling address header -- includes 10844397Seric ** the userid/groupid to be when sending. 1085294Seric ** 1086294Seric ** Returns: 1087294Seric ** The exit code associated with the operation. 1088294Seric ** 1089294Seric ** Side Effects: 1090294Seric ** none. 1091294Seric */ 1092294Seric 10934397Seric mailfile(filename, ctladdr) 1094294Seric char *filename; 10954397Seric ADDRESS *ctladdr; 1096294Seric { 1097294Seric register FILE *f; 10984214Seric register int pid; 1099294Seric 11004214Seric /* 11014214Seric ** Fork so we can change permissions here. 11024214Seric ** Note that we MUST use fork, not vfork, because of 11034214Seric ** the complications of calling subroutines, etc. 11044214Seric */ 11054067Seric 11064214Seric DOFORK(fork); 11074214Seric 11084214Seric if (pid < 0) 11094214Seric return (EX_OSERR); 11104214Seric else if (pid == 0) 11114214Seric { 11124214Seric /* child -- actually write to file */ 11134327Seric struct stat stb; 11144327Seric 11154215Seric (void) signal(SIGINT, SIG_DFL); 11164215Seric (void) signal(SIGHUP, SIG_DFL); 11174215Seric (void) signal(SIGTERM, SIG_DFL); 11184327Seric umask(OldUmask); 11194327Seric if (stat(filename, &stb) < 0) 11204431Seric stb.st_mode = 0666; 11214327Seric if (bitset(0111, stb.st_mode)) 11224327Seric exit(EX_CANTCREAT); 11234401Seric if (ctladdr == NULL) 11246900Seric ctladdr = &CurEnv->e_from; 11254327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 11264417Seric { 11274417Seric if (ctladdr->q_uid == 0) 11284417Seric (void) setgid(DefGid); 11294417Seric else 11304417Seric (void) setgid(ctladdr->q_gid); 11314417Seric } 11324327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 11334417Seric { 11344417Seric if (ctladdr->q_uid == 0) 11354417Seric (void) setuid(DefUid); 11364417Seric else 11374417Seric (void) setuid(ctladdr->q_uid); 11384417Seric } 11396887Seric f = dfopen(filename, "a"); 11404214Seric if (f == NULL) 11414214Seric exit(EX_CANTCREAT); 11424214Seric 114310168Seric putfromline(f, ProgMailer); 114410168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 114510168Seric putline("\n", f, ProgMailer); 114610168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 114710168Seric putline("\n", f, ProgMailer); 11484214Seric (void) fclose(f); 11494214Seric (void) fflush(stdout); 11504417Seric 11516887Seric /* reset ISUID & ISGID bits for paranoid systems */ 11524621Seric (void) chmod(filename, (int) stb.st_mode); 11534214Seric exit(EX_OK); 11544315Seric /*NOTREACHED*/ 11554214Seric } 11564214Seric else 11574214Seric { 11584214Seric /* parent -- wait for exit status */ 11599370Seric int st; 11604214Seric 11619370Seric st = waitfor(pid); 11629370Seric if ((st & 0377) != 0) 11639370Seric return (EX_UNAVAILABLE); 11649370Seric else 11659370Seric return ((st >> 8) & 0377); 11664214Seric } 1167294Seric } 11684550Seric /* 11694550Seric ** SENDALL -- actually send all the messages. 11704550Seric ** 11714550Seric ** Parameters: 11727043Seric ** e -- the envelope to send. 11739275Seric ** mode -- the delivery mode to use. 11744550Seric ** 11754550Seric ** Returns: 11764550Seric ** none. 11774550Seric ** 11784550Seric ** Side Effects: 11794550Seric ** Scans the send lists and sends everything it finds. 11807043Seric ** Delivers any appropriate error messages. 11819275Seric ** If we are running in a non-interactive mode, takes the 11829275Seric ** appropriate action. 11834550Seric */ 11844550Seric 11859275Seric sendall(e, mode) 11867043Seric ENVELOPE *e; 11879275Seric char mode; 11884550Seric { 11895008Seric register ADDRESS *q; 11907779Seric bool oldverbose; 11919275Seric int pid; 11924550Seric 11939370Seric #ifdef DEBUG 11948248Seric if (tTd(13, 1)) 11955032Seric { 11969275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 11977043Seric printaddr(e->e_sendqueue, TRUE); 11985032Seric } 11999370Seric #endif DEBUG 12005008Seric 12017043Seric /* 12029275Seric ** Do any preprocessing necessary for the mode we are running. 12039370Seric ** Check to make sure the hop count is reasonable. 12049370Seric ** Delete sends to the sender in mailing lists. 12057043Seric */ 12067043Seric 12079370Seric CurEnv = e; 12089370Seric 12099370Seric if (e->e_hopcount > MAXHOP) 12109275Seric { 12119370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 12129370Seric return; 12139370Seric } 12149275Seric 12159370Seric if (!MeToo) 12169370Seric { 12179370Seric e->e_from.q_flags |= QDONTSEND; 12189370Seric recipient(&e->e_from, &e->e_sendqueue); 12199275Seric } 12209370Seric 12219370Seric # ifdef QUEUE 12229335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 12239335Seric (mode != SM_VERIFY && SuperSafe)) && 12249335Seric !bitset(EF_INQUEUE, e->e_flags)) 12259370Seric queueup(e, TRUE, mode == SM_QUEUE); 12269275Seric #endif QUEUE 12279275Seric 12287779Seric oldverbose = Verbose; 12299275Seric switch (mode) 12309275Seric { 12319275Seric case SM_VERIFY: 12327779Seric Verbose = TRUE; 12339275Seric break; 12349275Seric 12359275Seric case SM_QUEUE: 12369335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 12379275Seric return; 12389275Seric 12399275Seric case SM_FORK: 12409538Seric if (e->e_xfp != NULL) 12419538Seric (void) fflush(e->e_xfp); 12429275Seric pid = fork(); 12439275Seric if (pid < 0) 12449275Seric { 12459275Seric mode = SM_DELIVER; 12469275Seric break; 12479275Seric } 12489275Seric else if (pid > 0) 12499293Seric { 12509293Seric /* be sure we leave the temp files to our child */ 12519335Seric e->e_id = e->e_df = NULL; 12529275Seric return; 12539293Seric } 12549275Seric 12559275Seric /* double fork to avoid zombies */ 12569275Seric if (fork() > 0) 12579275Seric exit(EX_OK); 12589275Seric 12599293Seric /* be sure we are immune from the terminal */ 126010133Seric disconnect(FALSE); 12619293Seric 12629275Seric break; 12639275Seric } 12649275Seric 12659275Seric /* 12669275Seric ** Run through the list and send everything. 12679275Seric */ 12689275Seric 12697043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12704550Seric { 12719275Seric if (mode == SM_VERIFY) 12724550Seric { 12739293Seric e->e_to = q->q_paddr; 12745008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 12757052Seric message(Arpa_Info, "deliverable"); 12764550Seric } 12775008Seric else 12789370Seric (void) deliver(e, q); 12794550Seric } 12807779Seric Verbose = oldverbose; 12817043Seric 12827043Seric /* 12837043Seric ** Now run through and check for errors. 12847043Seric */ 12857043Seric 12869275Seric if (mode == SM_VERIFY) 12877043Seric return; 12887043Seric 12897043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12907043Seric { 12917043Seric register ADDRESS *qq; 12927043Seric 12938248Seric # ifdef DEBUG 12948248Seric if (tTd(13, 3)) 12958248Seric { 12968248Seric printf("Checking "); 12978248Seric printaddr(q, FALSE); 12988248Seric } 12998248Seric # endif DEBUG 13008248Seric 13019335Seric /* only send errors if the message failed */ 13029335Seric if (!bitset(QBADADDR, q->q_flags)) 13039335Seric continue; 13047043Seric 13057043Seric /* we have an address that failed -- find the parent */ 13067043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 13077043Seric { 13087043Seric char obuf[MAXNAME + 6]; 13097043Seric extern char *aliaslookup(); 13107043Seric 13117043Seric /* we can only have owners for local addresses */ 13127043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 13137043Seric continue; 13147043Seric 13157043Seric /* see if the owner list exists */ 13167043Seric (void) strcpy(obuf, "owner-"); 13177047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 13187047Seric (void) strcat(obuf, "owner"); 13197047Seric else 13207047Seric (void) strcat(obuf, qq->q_user); 13217043Seric if (aliaslookup(obuf) == NULL) 13227043Seric continue; 13237043Seric 13248248Seric # ifdef DEBUG 13258248Seric if (tTd(13, 4)) 13268248Seric printf("Errors to %s\n", obuf); 13278248Seric # endif DEBUG 13288248Seric 13297043Seric /* owner list exists -- add it to the error queue */ 13309615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 13319370Seric ErrorMode == EM_MAIL; 13327043Seric break; 13337043Seric } 13347043Seric 13357043Seric /* if we did not find an owner, send to the sender */ 13368426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 13379615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 13387043Seric } 13399275Seric 13409275Seric if (mode == SM_FORK) 13419275Seric finis(); 13424550Seric } 1343