122701Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 642825Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822701Sdist 922701Sdist #ifndef lint 10*58247Seric static char sccsid[] = "@(#)deliver.c 6.27 (Berkeley) 02/26/93"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1458153Seric #include <signal.h> 1533931Sbostic #include <sys/stat.h> 1633931Sbostic #include <netdb.h> 1736030Sbostic #include <fcntl.h> 1833931Sbostic #include <errno.h> 1935651Seric #ifdef NAMED_BIND 2034022Sbostic #include <arpa/nameser.h> 2134022Sbostic #include <resolv.h> 2235651Seric #endif 23294Seric 24294Seric /* 254315Seric ** DELIVER -- Deliver a message to a list of addresses. 26294Seric ** 274315Seric ** This routine delivers to everyone on the same host as the 284315Seric ** user on the head of the list. It is clever about mailers 294315Seric ** that don't handle multiple users. It is NOT guaranteed 304315Seric ** that it will deliver to all these addresses however -- so 314315Seric ** deliver should be called once for each address on the 324315Seric ** list. 334315Seric ** 34294Seric ** Parameters: 359370Seric ** e -- the envelope to deliver. 364621Seric ** firstto -- head of the address list to deliver to. 37294Seric ** 38294Seric ** Returns: 39294Seric ** zero -- successfully delivered. 40294Seric ** else -- some failure, see ExitStat for more info. 41294Seric ** 42294Seric ** Side Effects: 43294Seric ** The standard input is passed off to someone. 44294Seric */ 45294Seric 469370Seric deliver(e, firstto) 479370Seric register ENVELOPE *e; 484621Seric ADDRESS *firstto; 49294Seric { 504452Seric char *host; /* host being sent to */ 514452Seric char *user; /* user being sent to */ 52294Seric char **pvp; 533233Seric register char **mvp; 543233Seric register char *p; 5510306Seric register MAILER *m; /* mailer for this recipient */ 564397Seric ADDRESS *ctladdr; 5754967Seric register MCI *mci; 584621Seric register ADDRESS *to = firstto; 594863Seric bool clever = FALSE; /* running user smtp to this mailer */ 605032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 6151951Seric int rcode; /* response code */ 6251951Seric char *from; /* pointer to from person */ 6357454Seric char *firstsig; /* signature of firstto */ 6410306Seric char *pv[MAXPV+1]; 6510306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 6610306Seric char buf[MAXNAME]; 6710306Seric char tfrombuf[MAXNAME]; /* translated from person */ 6851951Seric char rpathbuf[MAXNAME]; /* translated return path */ 6957441Seric extern int checkcompat(); 7010306Seric extern ADDRESS *getctladdr(); 7110306Seric extern char *remotename(); 7254967Seric extern MCI *openmailer(); 7357454Seric extern char *hostsignature(); 74294Seric 754488Seric errno = 0; 76*58247Seric if (bitset(QDONTSEND|QQUEUEUP, to->q_flags)) 773233Seric return (0); 78294Seric 7935651Seric #ifdef NAMED_BIND 8034022Sbostic /* unless interactive, try twice, over a minute */ 8134022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 8234022Sbostic _res.retrans = 30; 8334022Sbostic _res.retry = 2; 8434022Sbostic } 8536788Sbostic #endif 8634022Sbostic 876974Seric m = to->q_mailer; 886974Seric host = to->q_host; 896974Seric 907672Seric if (tTd(10, 1)) 913233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 926974Seric m->m_mno, host, to->q_user); 93294Seric 94294Seric /* 955903Seric ** If this mailer is expensive, and if we don't want to make 965903Seric ** connections now, just mark these addresses and return. 975903Seric ** This is useful if we want to batch connections to 985903Seric ** reduce load. This will cause the messages to be 995903Seric ** queued up, and a daemon will come along to send the 1005903Seric ** messages later. 1015903Seric ** This should be on a per-mailer basis. 1025903Seric */ 1035903Seric 10410682Seric if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && 1058428Seric !Verbose) 1065903Seric { 1075903Seric for (; to != NULL; to = to->q_next) 1088431Seric { 109*58247Seric if (bitset(QDONTSEND|QQUEUEUP, to->q_flags) || 110*58247Seric to->q_mailer != m) 1118431Seric continue; 1128431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 1139370Seric e->e_to = to->q_paddr; 11458151Seric message("queued"); 11558020Seric if (LogLevel > 8) 11654967Seric logdelivery("queued", e); 1178431Seric } 1189370Seric e->e_to = NULL; 1195903Seric return (0); 1205903Seric } 1215903Seric 1225903Seric /* 1233233Seric ** Do initial argv setup. 1243233Seric ** Insert the mailer name. Notice that $x expansion is 1253233Seric ** NOT done on the mailer name. Then, if the mailer has 1263233Seric ** a picky -f flag, we insert it as appropriate. This 1273233Seric ** code does not check for 'pv' overflow; this places a 1283233Seric ** manifest lower limit of 4 for MAXPV. 1298062Seric ** The from address rewrite is expected to make 1308062Seric ** the address relative to the other end. 1312968Seric */ 1322968Seric 1334452Seric /* rewrite from address, using rewriting rules */ 13458020Seric (void) strcpy(rpathbuf, remotename(e->e_returnpath, m, TRUE, FALSE, 13558020Seric TRUE, e)); 13651951Seric if (e->e_returnpath == e->e_sender) 13751951Seric { 13851951Seric from = rpathbuf; 13951951Seric } 14051951Seric else 14151951Seric { 14258020Seric (void) strcpy(tfrombuf, remotename(e->e_sender, m, TRUE, FALSE, 14358020Seric TRUE, e)); 14451951Seric from = tfrombuf; 14551951Seric } 1464452Seric 14751951Seric define('f', e->e_returnpath, e); /* raw return path */ 14851951Seric define('<', rpathbuf, e); /* translated return path */ 14951951Seric define('g', from, e); /* translated sender */ 1509370Seric define('h', host, e); /* to host */ 1513233Seric Errors = 0; 1523233Seric pvp = pv; 1533233Seric *pvp++ = m->m_argv[0]; 1542968Seric 1553233Seric /* insert -f or -r flag as appropriate */ 15610682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1573233Seric { 15810682Seric if (bitnset(M_FOPT, m->m_flags)) 1593233Seric *pvp++ = "-f"; 1603233Seric else 1613233Seric *pvp++ = "-r"; 16251951Seric *pvp++ = newstr(rpathbuf); 1633233Seric } 164294Seric 165294Seric /* 1663233Seric ** Append the other fixed parts of the argv. These run 1673233Seric ** up to the first entry containing "$u". There can only 1683233Seric ** be one of these, and there are only a few more slots 1693233Seric ** in the pv after it. 170294Seric */ 171294Seric 1723233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 173294Seric { 17458050Seric /* can't use strchr here because of sign extension problems */ 17558050Seric while (*p != '\0') 17658050Seric { 17758050Seric if ((*p++ & 0377) == MACROEXPAND) 17858050Seric { 17958050Seric if (*p == 'u') 18058050Seric break; 18158050Seric } 18258050Seric } 18358050Seric 18458050Seric if (*p != '\0') 1853233Seric break; 1863233Seric 1873233Seric /* this entry is safe -- go ahead and process it */ 1889370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1893233Seric *pvp++ = newstr(buf); 1903233Seric if (pvp >= &pv[MAXPV - 3]) 1913233Seric { 19258151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 1933233Seric return (-1); 1943233Seric } 195294Seric } 1964863Seric 1976038Seric /* 1986038Seric ** If we have no substitution for the user name in the argument 1996038Seric ** list, we know that we must supply the names otherwise -- and 2006038Seric ** SMTP is the answer!! 2016038Seric */ 2026038Seric 2033233Seric if (*mvp == NULL) 2044863Seric { 2054863Seric /* running SMTP */ 2065179Seric # ifdef SMTP 2074863Seric clever = TRUE; 2084863Seric *pvp = NULL; 20956795Seric # else /* SMTP */ 2106038Seric /* oops! we don't implement SMTP */ 21158151Seric syserr("554 SMTP style mailer"); 2125179Seric return (EX_SOFTWARE); 21356795Seric # endif /* SMTP */ 2144863Seric } 215294Seric 216294Seric /* 2173233Seric ** At this point *mvp points to the argument with $u. We 2183233Seric ** run through our address list and append all the addresses 2193233Seric ** we can. If we run out of space, do not fret! We can 2203233Seric ** always send another copy later. 221294Seric */ 222294Seric 2233233Seric tobuf[0] = '\0'; 2249370Seric e->e_to = tobuf; 2254397Seric ctladdr = NULL; 22657454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 2273233Seric for (; to != NULL; to = to->q_next) 228294Seric { 2293233Seric /* avoid sending multiple recipients to dumb mailers */ 23010682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 2313233Seric break; 2323233Seric 2333233Seric /* if already sent or not for this host, don't send */ 234*58247Seric if (bitset(QDONTSEND|QQUEUEUP, to->q_flags) || 23557454Seric to->q_mailer != firstto->q_mailer || 23657454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 2373233Seric continue; 2384397Seric 2398225Seric /* avoid overflowing tobuf */ 24042462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 2418225Seric break; 2428225Seric 2437672Seric if (tTd(10, 1)) 2445032Seric { 2455032Seric printf("\nsend to "); 2465032Seric printaddr(to, FALSE); 2475032Seric } 2485032Seric 2494397Seric /* compute effective uid/gid when sending */ 2504596Seric if (to->q_mailer == ProgMailer) 2514397Seric ctladdr = getctladdr(to); 2524397Seric 2533233Seric user = to->q_user; 2549370Seric e->e_to = to->q_paddr; 2553233Seric to->q_flags |= QDONTSEND; 25657731Seric if (tTd(10, 5)) 25757731Seric { 25857731Seric printf("deliver: QDONTSEND "); 25957731Seric printaddr(to, FALSE); 26057731Seric } 2613233Seric 2623233Seric /* 2633233Seric ** Check to see that these people are allowed to 2643233Seric ** talk to each other. 2653233Seric */ 2663233Seric 26710699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 26810699Seric { 26929914Seric NoReturn = TRUE; 27058151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 27110699Seric giveresponse(EX_UNAVAILABLE, m, e); 27210699Seric continue; 27310699Seric } 27457441Seric rcode = checkcompat(to, e); 27557459Seric if (rcode != EX_OK) 276294Seric { 27757459Seric giveresponse(rcode, m, e); 2783233Seric continue; 279294Seric } 2803233Seric 2813233Seric /* 2824099Seric ** Strip quote bits from names if the mailer is dumb 2834099Seric ** about them. 2843233Seric */ 2853233Seric 28610682Seric if (bitnset(M_STRIPQ, m->m_flags)) 287294Seric { 28854983Seric stripquotes(user); 28954983Seric stripquotes(host); 2903233Seric } 2913233Seric 2929206Seric /* hack attack -- delivermail compatibility */ 2939206Seric if (m == ProgMailer && *user == '|') 2949206Seric user++; 2959206Seric 2963233Seric /* 2974161Seric ** If an error message has already been given, don't 2984161Seric ** bother to send to this address. 2994161Seric ** 3004161Seric ** >>>>>>>>>> This clause assumes that the local mailer 3014161Seric ** >> NOTE >> cannot do any further aliasing; that 3024161Seric ** >>>>>>>>>> function is subsumed by sendmail. 3034161Seric */ 3044161Seric 3057293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 3064161Seric continue; 3074161Seric 3084283Seric /* save statistics.... */ 3099370Seric markstats(e, to); 3104283Seric 3114161Seric /* 3123233Seric ** See if this user name is "special". 3133233Seric ** If the user name has a slash in it, assume that this 3146974Seric ** is a file -- send it off without further ado. Note 3156974Seric ** that this type of addresses is not processed along 3166974Seric ** with the others, so we fudge on the To person. 3173233Seric */ 3183233Seric 31957402Seric if (m == FileMailer) 3203233Seric { 32157402Seric rcode = mailfile(user, getctladdr(to), e); 32257402Seric giveresponse(rcode, m, e); 32357402Seric if (rcode == EX_OK) 32457402Seric to->q_flags |= QSENT; 32557402Seric continue; 326294Seric } 3273233Seric 3284315Seric /* 3294315Seric ** Address is verified -- add this user to mailer 3304315Seric ** argv, and add it to the print list of recipients. 3314315Seric */ 3324315Seric 3336059Seric /* link together the chain of recipients */ 3346272Seric to->q_tchain = tochain; 3356272Seric tochain = to; 3366059Seric 3373233Seric /* create list of users for error messages */ 3389388Seric (void) strcat(tobuf, ","); 3394082Seric (void) strcat(tobuf, to->q_paddr); 3409370Seric define('u', user, e); /* to user */ 3419370Seric define('z', to->q_home, e); /* user's home */ 3423233Seric 3434863Seric /* 3446059Seric ** Expand out this user into argument list. 3454863Seric */ 3464863Seric 3476059Seric if (!clever) 3483233Seric { 3499370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3504863Seric *pvp++ = newstr(buf); 3514863Seric if (pvp >= &pv[MAXPV - 2]) 3524863Seric { 3534863Seric /* allow some space for trailing parms */ 3544863Seric break; 3554863Seric } 3564863Seric } 357294Seric } 358294Seric 3594067Seric /* see if any addresses still exist */ 3604067Seric if (tobuf[0] == '\0') 3614863Seric { 3629370Seric define('g', (char *) NULL, e); 36351951Seric define('<', (char *) NULL, e); 3644067Seric return (0); 3654863Seric } 3664067Seric 3673233Seric /* print out messages as full list */ 3689388Seric e->e_to = tobuf + 1; 3693233Seric 370294Seric /* 3713233Seric ** Fill out any parameters after the $u parameter. 372294Seric */ 373294Seric 3744863Seric while (!clever && *++mvp != NULL) 375294Seric { 3769370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3773233Seric *pvp++ = newstr(buf); 3783233Seric if (pvp >= &pv[MAXPV]) 37958151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 380294Seric } 3813233Seric *pvp++ = NULL; 382294Seric 383294Seric /* 384294Seric ** Call the mailer. 3852898Seric ** The argument vector gets built, pipes 386294Seric ** are created as necessary, and we fork & exec as 3872898Seric ** appropriate. 3884863Seric ** If we are running SMTP, we just need to clean up. 389294Seric */ 390294Seric 39141050Seric if (ctladdr == NULL) 39241050Seric ctladdr = &e->e_from; 39335651Seric #ifdef NAMED_BIND 39451313Seric if (ConfigLevel < 2) 39551313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 39635651Seric #endif 39754967Seric mci = openmailer(m, pv, ctladdr, clever, e); 39854967Seric if (mci == NULL) 39954967Seric { 40054967Seric /* catastrophic error */ 40157977Seric rcode = EX_OSERR; 40254967Seric goto give_up; 40354967Seric } 40454967Seric else if (mci->mci_state != MCIS_OPEN) 40554967Seric { 40654967Seric /* couldn't open the mailer */ 40754967Seric rcode = mci->mci_exitstat; 40855173Seric errno = mci->mci_errno; 40954967Seric if (rcode == EX_OK) 41054967Seric { 41154967Seric /* shouldn't happen */ 41258151Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 41357721Seric rcode, mci->mci_state, firstsig); 41454967Seric rcode = EX_SOFTWARE; 41554967Seric } 41654967Seric } 41754967Seric else if (!clever) 41854967Seric { 41954967Seric /* 42054967Seric ** Format and send message. 42154967Seric */ 42254967Seric 42354967Seric putfromline(mci->mci_out, m, e); 42454967Seric (*e->e_puthdr)(mci->mci_out, m, e); 42554967Seric putline("\n", mci->mci_out, m); 42654967Seric (*e->e_putbody)(mci->mci_out, m, e); 42754967Seric 42854967Seric /* get the exit status */ 42954967Seric rcode = endmailer(mci, pv[0]); 43054967Seric } 43154967Seric else 43233931Sbostic #ifdef SMTP 43335651Seric { 43454967Seric /* 43554967Seric ** Send the MAIL FROM: protocol 43654967Seric */ 43753751Seric 43854967Seric rcode = smtpmailfrom(m, mci, e); 43954967Seric if (rcode == EX_OK) 44035651Seric { 44154967Seric register char *t = tobuf; 44254967Seric register int i; 44353751Seric 44454967Seric /* send the recipient list */ 44554967Seric tobuf[0] = '\0'; 44654967Seric for (to = tochain; to != NULL; to = to->q_tchain) 44753738Seric { 44854967Seric e->e_to = to->q_paddr; 44954967Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 45053738Seric { 45154967Seric markfailure(e, to, i); 45254967Seric giveresponse(i, m, e); 4539388Seric } 45453738Seric else 45553738Seric { 45654967Seric *t++ = ','; 45754967Seric for (p = to->q_paddr; *p; *t++ = *p++) 45854967Seric continue; 4599388Seric } 46054967Seric } 4619388Seric 46254967Seric /* now send the data */ 46354967Seric if (tobuf[0] == '\0') 46454967Seric { 46554967Seric e->e_to = NULL; 46654967Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 46754967Seric smtprset(m, mci, e); 46854967Seric } 46954967Seric else 47054967Seric { 47154967Seric e->e_to = tobuf + 1; 47254967Seric rcode = smtpdata(m, mci, e); 47354967Seric } 47454967Seric 47554967Seric /* now close the connection */ 47654967Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 47753751Seric smtpquit(m, mci, e); 4789370Seric } 4794863Seric } 48054967Seric #else /* not SMTP */ 48133935Sbostic { 48258151Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 48357977Seric rcode = EX_CONFIG; 48454967Seric goto give_up; 48533935Sbostic } 48654967Seric #endif /* SMTP */ 48735651Seric #ifdef NAMED_BIND 48851313Seric if (ConfigLevel < 2) 48951313Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 49035651Seric #endif 4913233Seric 49254967Seric /* arrange a return receipt if requested */ 49358139Seric if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) 49454967Seric { 49554967Seric e->e_flags |= EF_SENDRECEIPT; 49654967Seric /* do we want to send back more info? */ 49754967Seric } 49854967Seric 4994621Seric /* 5009388Seric ** Do final status disposal. 5019388Seric ** We check for something in tobuf for the SMTP case. 5029388Seric ** If we got a temporary failure, arrange to queue the 5039388Seric ** addressees. 5044621Seric */ 5054621Seric 50654967Seric give_up: 5079388Seric if (tobuf[0] != '\0') 50810105Seric giveresponse(rcode, m, e); 50947284Seric for (to = tochain; to != NULL; to = to->q_tchain) 51054967Seric { 51147284Seric if (rcode != EX_OK) 51210092Seric markfailure(e, to, rcode); 51347284Seric else 51457589Seric { 51547284Seric to->q_flags |= QSENT; 51657589Seric e->e_nsent++; 51757589Seric } 51854967Seric } 5194621Seric 52054967Seric /* 52154967Seric ** Restore state and return. 52254967Seric */ 52354967Seric 5244488Seric errno = 0; 5259370Seric define('g', (char *) NULL, e); 52651951Seric define('<', (char *) NULL, e); 5278003Seric return (rcode); 5283233Seric } 5293233Seric /* 53010092Seric ** MARKFAILURE -- mark a failure on a specific address. 53110092Seric ** 53210092Seric ** Parameters: 53310092Seric ** e -- the envelope we are sending. 53410092Seric ** q -- the address to mark. 53510092Seric ** rcode -- the code signifying the particular failure. 53610092Seric ** 53710092Seric ** Returns: 53810092Seric ** none. 53910092Seric ** 54010092Seric ** Side Effects: 54110092Seric ** marks the address (and possibly the envelope) with the 54210092Seric ** failure so that an error will be returned or 54310092Seric ** the message will be queued, as appropriate. 54410092Seric */ 54510092Seric 54610092Seric markfailure(e, q, rcode) 54710092Seric register ENVELOPE *e; 54810092Seric register ADDRESS *q; 54910092Seric int rcode; 55010092Seric { 55110092Seric if (rcode == EX_OK) 55210092Seric return; 55340996Sbostic else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) 55410092Seric q->q_flags |= QBADADDR; 55510092Seric else if (curtime() > e->e_ctime + TimeOut) 55610092Seric { 55710092Seric extern char *pintvl(); 55810105Seric char buf[MAXLINE]; 55910092Seric 56010092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 56110105Seric { 56210105Seric (void) sprintf(buf, "Cannot send message for %s", 56310092Seric pintvl(TimeOut, FALSE)); 56410105Seric if (e->e_message != NULL) 56510105Seric free(e->e_message); 56610105Seric e->e_message = newstr(buf); 56758151Seric message(buf); 56810105Seric } 56910092Seric q->q_flags |= QBADADDR; 57010092Seric e->e_flags |= EF_TIMEOUT; 57157642Seric fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); 57210092Seric } 57310092Seric else 57410092Seric q->q_flags |= QQUEUEUP; 57510092Seric } 57610092Seric /* 5774214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5784214Seric ** 5794214Seric ** This MUST be a macro, since after a vfork we are running 5804214Seric ** two processes on the same stack!!! 5814214Seric ** 5824214Seric ** Parameters: 5834214Seric ** none. 5844214Seric ** 5854214Seric ** Returns: 5864214Seric ** From a macro??? You've got to be kidding! 5874214Seric ** 5884214Seric ** Side Effects: 5894214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5904214Seric ** pid of child in parent, zero in child. 5914214Seric ** -1 on unrecoverable error. 5924214Seric ** 5934214Seric ** Notes: 5944214Seric ** I'm awfully sorry this looks so awful. That's 5954214Seric ** vfork for you..... 5964214Seric */ 5974214Seric 5984214Seric # define NFORKTRIES 5 5994214Seric 60052107Seric # ifndef FORK 60152107Seric # define FORK fork 60252107Seric # endif 60352107Seric 6044214Seric # define DOFORK(fORKfN) \ 6054214Seric {\ 6064214Seric register int i;\ 6074214Seric \ 60823504Seric for (i = NFORKTRIES; --i >= 0; )\ 6094214Seric {\ 6104214Seric pid = fORKfN();\ 6114214Seric if (pid >= 0)\ 6124214Seric break;\ 61323504Seric if (i > 0)\ 61425617Seric sleep((unsigned) NFORKTRIES - i);\ 6154214Seric }\ 6164214Seric } 6174214Seric /* 6184637Seric ** DOFORK -- simple fork interface to DOFORK. 6194637Seric ** 6204637Seric ** Parameters: 6214637Seric ** none. 6224637Seric ** 6234637Seric ** Returns: 6244637Seric ** pid of child in parent. 6254637Seric ** zero in child. 6264637Seric ** -1 on error. 6274637Seric ** 6284637Seric ** Side Effects: 6294637Seric ** returns twice, once in parent and once in child. 6304637Seric */ 6314637Seric 6324637Seric dofork() 6334637Seric { 6344637Seric register int pid; 6354637Seric 6364637Seric DOFORK(fork); 6374637Seric return (pid); 6384637Seric } 6394637Seric /* 6404863Seric ** ENDMAILER -- Wait for mailer to terminate. 6414863Seric ** 6424863Seric ** We should never get fatal errors (e.g., segmentation 6434863Seric ** violation), so we report those specially. For other 6444863Seric ** errors, we choose a status message (into statmsg), 6454863Seric ** and if it represents an error, we print it. 6464863Seric ** 6474863Seric ** Parameters: 6484863Seric ** pid -- pid of mailer. 6494863Seric ** name -- name of mailer (for error messages). 6504863Seric ** 6514863Seric ** Returns: 6524863Seric ** exit code of mailer. 6534863Seric ** 6544863Seric ** Side Effects: 6554863Seric ** none. 6564863Seric */ 6574863Seric 65853738Seric endmailer(mci, name) 65954967Seric register MCI *mci; 6604863Seric char *name; 6614863Seric { 6629370Seric int st; 6634863Seric 66453738Seric /* close any connections */ 66553738Seric if (mci->mci_in != NULL) 66653738Seric (void) fclose(mci->mci_in); 66753738Seric if (mci->mci_out != NULL) 66853738Seric (void) fclose(mci->mci_out); 66953738Seric mci->mci_in = mci->mci_out = NULL; 67053738Seric mci->mci_state = MCIS_CLOSED; 67153738Seric 6726038Seric /* in the IPC case there is nothing to wait for */ 67353738Seric if (mci->mci_pid == 0) 6746038Seric return (EX_OK); 6756038Seric 6766038Seric /* wait for the mailer process to die and collect status */ 67753738Seric st = waitfor(mci->mci_pid); 6789370Seric if (st == -1) 6798127Seric { 6809370Seric syserr("endmailer %s: wait", name); 6819370Seric return (EX_SOFTWARE); 6824863Seric } 6836038Seric 6846038Seric /* see if it died a horrid death */ 6854863Seric if ((st & 0377) != 0) 6864863Seric { 68724941Seric syserr("mailer %s died with signal %o", name, st); 68824941Seric ExitStat = EX_TEMPFAIL; 68924941Seric return (EX_TEMPFAIL); 6904863Seric } 6916038Seric 6926038Seric /* normal death -- return status */ 6939370Seric st = (st >> 8) & 0377; 6949370Seric return (st); 6954863Seric } 6964863Seric /* 6974863Seric ** OPENMAILER -- open connection to mailer. 6984863Seric ** 6994863Seric ** Parameters: 7004863Seric ** m -- mailer descriptor. 7014863Seric ** pvp -- parameter vector to pass to mailer. 7024863Seric ** ctladdr -- controlling address for user. 7034863Seric ** clever -- create a full duplex connection. 7044863Seric ** 7054863Seric ** Returns: 70653738Seric ** The mail connection info struct for this connection. 70753738Seric ** NULL on failure. 7084863Seric ** 7094863Seric ** Side Effects: 7104863Seric ** creates a mailer in a subprocess. 7114863Seric */ 7124863Seric 71354967Seric MCI * 71454967Seric openmailer(m, pvp, ctladdr, clever, e) 7159370Seric MAILER *m; 7164863Seric char **pvp; 7174863Seric ADDRESS *ctladdr; 7184863Seric bool clever; 71954967Seric ENVELOPE *e; 7204863Seric { 7214863Seric int pid; 72254967Seric register MCI *mci; 7234709Seric int mpvect[2]; 7244863Seric int rpvect[2]; 7253233Seric extern FILE *fdopen(); 7263233Seric 7277672Seric if (tTd(11, 1)) 728294Seric { 7298178Seric printf("openmailer:"); 7303233Seric printav(pvp); 731294Seric } 7324488Seric errno = 0; 7333233Seric 73425050Seric CurHostName = m->m_mailer; 73525050Seric 7366038Seric /* 7376038Seric ** Deal with the special case of mail handled through an IPC 7386038Seric ** connection. 7396038Seric ** In this case we don't actually fork. We must be 7406038Seric ** running SMTP for this to work. We will return a 7416038Seric ** zero pid to indicate that we are running IPC. 74211160Seric ** We also handle a debug version that just talks to stdin/out. 7436038Seric */ 7446038Seric 74511160Seric /* check for Local Person Communication -- not for mortals!!! */ 74611160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 74711160Seric { 74854967Seric mci = (MCI *) xalloc(sizeof *mci); 74954993Seric bzero((char *) mci, sizeof *mci); 75053738Seric mci->mci_in = stdin; 75153738Seric mci->mci_out = stdout; 75254967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 75353751Seric mci->mci_mailer = m; 75411160Seric } 75554967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 75654967Seric strcmp(m->m_mailer, "[TCP]") == 0) 7576038Seric { 75852107Seric #ifdef DAEMON 75957454Seric register int i; 7607285Seric register u_short port; 76157454Seric char *curhost; 76254967Seric extern MCI *mci_get(); 76357454Seric extern char *hostsignature(); 7646038Seric 76525050Seric CurHostName = pvp[1]; 76657454Seric curhost = hostsignature(m, pvp[1], e); 76754967Seric 7686038Seric if (!clever) 76958151Seric syserr("554 non-clever IPC"); 7706632Seric if (pvp[2] != NULL) 7717285Seric port = atoi(pvp[2]); 7726632Seric else 7737285Seric port = 0; 77457454Seric while (*curhost != '\0') 77529433Sbloom { 77657454Seric register char *p; 77757454Seric char hostbuf[MAXNAME]; 77857454Seric 77957454Seric /* pull the next host from the signature */ 78057454Seric p = strchr(curhost, ':'); 78157454Seric if (p == NULL) 78257454Seric p = &curhost[strlen(curhost)]; 78357454Seric strncpy(hostbuf, curhost, p - curhost); 78457454Seric hostbuf[p - curhost] = '\0'; 78557454Seric if (*p != '\0') 78657454Seric p++; 78757454Seric curhost = p; 78857454Seric 78953738Seric /* see if we already know that this host is fried */ 79057454Seric CurHostName = hostbuf; 79157454Seric mci = mci_get(hostbuf, m); 79254967Seric if (mci->mci_state != MCIS_CLOSED) 79357387Seric { 79457387Seric if (tTd(11, 1)) 79557387Seric { 79657387Seric printf("openmailer: "); 79757387Seric mci_dump(mci); 79857387Seric } 79957943Seric CurHostName = mci->mci_host; 80053738Seric return mci; 80157387Seric } 80253751Seric mci->mci_mailer = m; 80354967Seric if (mci->mci_exitstat != EX_OK) 80454967Seric continue; 80554967Seric 80654967Seric /* try the connection */ 80757454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 80858151Seric message("Connecting to %s (%s)...", 80957454Seric hostbuf, m->m_name); 81057454Seric i = makeconnection(hostbuf, port, mci, 81154967Seric bitnset(M_SECURE_PORT, m->m_flags)); 81254967Seric mci->mci_exitstat = i; 81354967Seric mci->mci_errno = errno; 81454967Seric if (i == EX_OK) 81552106Seric { 81654967Seric mci->mci_state = MCIS_OPENING; 81754967Seric mci_cache(mci); 81854967Seric break; 81934022Sbostic } 82054967Seric else if (tTd(11, 1)) 82154967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 82254967Seric i, errno); 82353738Seric 82454967Seric 82553738Seric /* enter status of this host */ 82653738Seric setstat(i); 8276047Seric } 82854993Seric mci->mci_pid = 0; 82954967Seric #else /* no DAEMON */ 83058151Seric syserr("554 openmailer: no IPC"); 83157387Seric if (tTd(11, 1)) 83257387Seric printf("openmailer: NULL\n"); 83353738Seric return NULL; 83454967Seric #endif /* DAEMON */ 8356038Seric } 83654967Seric else 837294Seric { 83854967Seric /* create a pipe to shove the mail through */ 83954967Seric if (pipe(mpvect) < 0) 84054967Seric { 84154967Seric syserr("openmailer: pipe (to mailer)"); 84257387Seric if (tTd(11, 1)) 84357387Seric printf("openmailer: NULL\n"); 84454967Seric return NULL; 84554967Seric } 8464863Seric 84754967Seric /* if this mailer speaks smtp, create a return pipe */ 84854967Seric if (clever && pipe(rpvect) < 0) 84954967Seric { 85054967Seric syserr("openmailer: pipe (from mailer)"); 85154967Seric (void) close(mpvect[0]); 85254967Seric (void) close(mpvect[1]); 85357387Seric if (tTd(11, 1)) 85457387Seric printf("openmailer: NULL\n"); 85554967Seric return NULL; 85654967Seric } 8574863Seric 85854967Seric /* 85954967Seric ** Actually fork the mailer process. 86054967Seric ** DOFORK is clever about retrying. 86154967Seric ** 86254967Seric ** Dispose of SIGCHLD signal catchers that may be laying 86354967Seric ** around so that endmail will get it. 86454967Seric */ 8656038Seric 86654967Seric if (e->e_xfp != NULL) 86754967Seric (void) fflush(e->e_xfp); /* for debugging */ 86854967Seric (void) fflush(stdout); 86926434Seric # ifdef SIGCHLD 87054967Seric (void) signal(SIGCHLD, SIG_DFL); 87156795Seric # endif /* SIGCHLD */ 87254967Seric DOFORK(FORK); 87354967Seric /* pid is set by DOFORK */ 87454967Seric if (pid < 0) 8754863Seric { 87654967Seric /* failure */ 87754967Seric syserr("openmailer: cannot fork"); 87854967Seric (void) close(mpvect[0]); 87954967Seric (void) close(mpvect[1]); 88054967Seric if (clever) 88154967Seric { 88254967Seric (void) close(rpvect[0]); 88354967Seric (void) close(rpvect[1]); 88454967Seric } 88557387Seric if (tTd(11, 1)) 88657387Seric printf("openmailer: NULL\n"); 88754967Seric return NULL; 8884863Seric } 88954967Seric else if (pid == 0) 89054967Seric { 89154967Seric int i; 89256678Seric int saveerrno; 89357529Seric char *env[2]; 89454967Seric extern int DtableSize; 89515772Seric 89654967Seric /* child -- set up input & exec mailer */ 89754967Seric /* make diagnostic output be standard output */ 89854967Seric (void) signal(SIGINT, SIG_IGN); 89954967Seric (void) signal(SIGHUP, SIG_IGN); 90054967Seric (void) signal(SIGTERM, SIG_DFL); 9014709Seric 90258082Seric /* close any other cached connections */ 90358082Seric mci_flush(FALSE, mci); 90458082Seric 90554967Seric /* arrange to filter std & diag output of command */ 90654967Seric if (clever) 90754967Seric { 90854967Seric (void) close(rpvect[0]); 90954967Seric (void) close(1); 91054967Seric (void) dup(rpvect[1]); 91154967Seric (void) close(rpvect[1]); 91254967Seric } 91354967Seric else if (OpMode == MD_SMTP || HoldErrs) 91454967Seric { 91554967Seric /* put mailer output in transcript */ 91654967Seric (void) close(1); 91754967Seric (void) dup(fileno(e->e_xfp)); 91854967Seric } 91954967Seric (void) close(2); 92054967Seric (void) dup(1); 9214709Seric 92254967Seric /* arrange to get standard input */ 92354967Seric (void) close(mpvect[1]); 92454967Seric (void) close(0); 92554967Seric if (dup(mpvect[0]) < 0) 9264417Seric { 92754967Seric syserr("Cannot dup to zero!"); 92854967Seric _exit(EX_OSERR); 9294417Seric } 93054967Seric (void) close(mpvect[0]); 93154967Seric if (!bitnset(M_RESTR, m->m_flags)) 9324415Seric { 93354967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 93454967Seric { 93554967Seric (void) setgid(DefGid); 93654967Seric (void) initgroups(DefUser, DefGid); 93754967Seric (void) setuid(DefUid); 93854967Seric } 93954967Seric else 94054967Seric { 94154967Seric (void) setgid(ctladdr->q_gid); 94254967Seric (void) initgroups(ctladdr->q_ruser? 94354967Seric ctladdr->q_ruser: ctladdr->q_user, 94454967Seric ctladdr->q_gid); 94554967Seric (void) setuid(ctladdr->q_uid); 94654967Seric } 9474415Seric } 9489370Seric 94954967Seric /* arrange for all the files to be closed */ 95054967Seric for (i = 3; i < DtableSize; i++) 95154967Seric { 95254967Seric register int j; 95354967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 95454967Seric (void)fcntl(i, F_SETFD, j|1); 95554967Seric } 9562774Seric 95754967Seric /* try to execute the mailer */ 95857529Seric env[0] = "AGENT=sendmail"; 95957529Seric env[1] = NULL; 96057529Seric execve(m->m_mailer, pvp, env); 96156678Seric saveerrno = errno; 96254967Seric syserr("Cannot exec %s", m->m_mailer); 96354967Seric if (m == LocalMailer) 96454967Seric _exit(EX_TEMPFAIL); 96556678Seric switch (saveerrno) 96654967Seric { 96754967Seric case EIO: 96854967Seric case EAGAIN: 96954967Seric case ENOMEM: 97051835Seric # ifdef EPROCLIM 97154967Seric case EPROCLIM: 97251835Seric # endif 97358108Seric # ifdef ETIMEDOUT 97458108Seric case ETIMEDOUT: 97558108Seric # endif 97654967Seric _exit(EX_TEMPFAIL); 97754967Seric } 97854967Seric _exit(EX_UNAVAILABLE); 97951835Seric } 98054967Seric 98154967Seric /* 98254967Seric ** Set up return value. 98354967Seric */ 98454967Seric 98554967Seric mci = (MCI *) xalloc(sizeof *mci); 98654993Seric bzero((char *) mci, sizeof *mci); 98754967Seric mci->mci_mailer = m; 98854967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 98954993Seric mci->mci_pid = pid; 99054967Seric (void) close(mpvect[0]); 99154967Seric mci->mci_out = fdopen(mpvect[1], "w"); 99254967Seric if (clever) 99354967Seric { 99454967Seric (void) close(rpvect[1]); 99554967Seric mci->mci_in = fdopen(rpvect[0], "r"); 99654967Seric } 99754967Seric else 99854967Seric { 99954967Seric mci->mci_flags |= MCIF_TEMP; 100054967Seric mci->mci_in = NULL; 100154967Seric } 1002294Seric } 1003294Seric 10044709Seric /* 100554967Seric ** If we are in SMTP opening state, send initial protocol. 10064709Seric */ 10074709Seric 100854967Seric if (clever && mci->mci_state != MCIS_CLOSED) 10094863Seric { 101054967Seric smtpinit(m, mci, e); 101153738Seric } 101257387Seric if (tTd(11, 1)) 101357387Seric { 101457387Seric printf("openmailer: "); 101557387Seric mci_dump(mci); 101657387Seric } 1017294Seric 101853738Seric return mci; 1019294Seric } 1020294Seric /* 1021294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1022294Seric ** 1023294Seric ** Parameters: 1024294Seric ** stat -- the status code from the mailer (high byte 1025294Seric ** only; core dumps must have been taken care of 1026294Seric ** already). 1027294Seric ** m -- the mailer descriptor for this mailer. 1028294Seric ** 1029294Seric ** Returns: 10304082Seric ** none. 1031294Seric ** 1032294Seric ** Side Effects: 10331518Seric ** Errors may be incremented. 1034294Seric ** ExitStat may be set. 1035294Seric */ 1036294Seric 103710105Seric giveresponse(stat, m, e) 1038294Seric int stat; 10399370Seric register MAILER *m; 104010105Seric ENVELOPE *e; 1041294Seric { 1042294Seric register char *statmsg; 1043294Seric extern char *SysExMsg[]; 1044294Seric register int i; 104536788Sbostic extern int N_SysEx; 104636788Sbostic #ifdef NAMED_BIND 104736788Sbostic extern int h_errno; 104836788Sbostic #endif 104910105Seric char buf[MAXLINE]; 1050294Seric 105112135Seric #ifdef lint 105212135Seric if (m == NULL) 105312135Seric return; 105412135Seric #endif lint 105512135Seric 10564315Seric /* 10574315Seric ** Compute status message from code. 10584315Seric */ 10594315Seric 1060294Seric i = stat - EX__BASE; 10619370Seric if (stat == 0) 10629370Seric statmsg = "250 Sent"; 10639370Seric else if (i < 0 || i > N_SysEx) 10649370Seric { 10659370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 10669370Seric stat = EX_UNAVAILABLE; 10679370Seric statmsg = buf; 10689370Seric } 106910105Seric else if (stat == EX_TEMPFAIL) 107010105Seric { 107110124Seric (void) strcpy(buf, SysExMsg[i]); 107236788Sbostic #ifdef NAMED_BIND 107325527Smiriam if (h_errno == TRY_AGAIN) 107410105Seric { 107515137Seric extern char *errstring(); 107615137Seric 107725527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 107821061Seric } 107921061Seric else 108036788Sbostic #endif 108121061Seric { 108225527Smiriam if (errno != 0) 108325527Smiriam { 108425527Smiriam extern char *errstring(); 108525527Smiriam 108625527Smiriam statmsg = errstring(errno); 108725527Smiriam } 108825527Smiriam else 108925527Smiriam { 109021061Seric #ifdef SMTP 109125527Smiriam extern char SmtpError[]; 109221061Seric 109325527Smiriam statmsg = SmtpError; 109456795Seric #else /* SMTP */ 109525527Smiriam statmsg = NULL; 109656795Seric #endif /* SMTP */ 109725527Smiriam } 109821061Seric } 109921061Seric if (statmsg != NULL && statmsg[0] != '\0') 110021061Seric { 110110124Seric (void) strcat(buf, ": "); 110221061Seric (void) strcat(buf, statmsg); 110310105Seric } 110410105Seric statmsg = buf; 110510105Seric } 1106294Seric else 110721061Seric { 1108294Seric statmsg = SysExMsg[i]; 110921061Seric } 11109370Seric 11119370Seric /* 11129370Seric ** Print the message as appropriate 11139370Seric */ 11149370Seric 111510105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 111658151Seric message(&statmsg[4]); 1117294Seric else 1118294Seric { 11191518Seric Errors++; 11209370Seric usrerr(statmsg); 1121294Seric } 1122294Seric 1123294Seric /* 1124294Seric ** Final cleanup. 1125294Seric ** Log a record of the transaction. Compute the new 1126294Seric ** ExitStat -- if we already had an error, stick with 1127294Seric ** that. 1128294Seric */ 1129294Seric 113058020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 113154967Seric logdelivery(&statmsg[4], e); 11327858Seric 11334621Seric if (stat != EX_TEMPFAIL) 11344621Seric setstat(stat); 113510105Seric if (stat != EX_OK) 113610105Seric { 113710105Seric if (e->e_message != NULL) 113810105Seric free(e->e_message); 113910105Seric e->e_message = newstr(&statmsg[4]); 114010105Seric } 114110124Seric errno = 0; 114236788Sbostic #ifdef NAMED_BIND 114325527Smiriam h_errno = 0; 114436788Sbostic #endif 1145294Seric } 1146294Seric /* 11478496Seric ** LOGDELIVERY -- log the delivery in the system log 11488496Seric ** 11498496Seric ** Parameters: 11508496Seric ** stat -- the message to print for the status 11518496Seric ** 11528496Seric ** Returns: 11538496Seric ** none 11548496Seric ** 11558496Seric ** Side Effects: 11568496Seric ** none 11578496Seric */ 11588496Seric 115954967Seric logdelivery(stat, e) 11608496Seric char *stat; 116154967Seric register ENVELOPE *e; 11628496Seric { 11638496Seric extern char *pintvl(); 11648496Seric 11658496Seric # ifdef LOG 116654967Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", e->e_id, 116754967Seric e->e_to, pintvl(curtime() - e->e_ctime, TRUE), stat); 116856795Seric # endif /* LOG */ 11698496Seric } 11708496Seric /* 11716974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1172294Seric ** 11736974Seric ** This can be made an arbitrary message separator by changing $l 1174294Seric ** 117516150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 117616150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 117716150Seric ** does a well-meaning programmer such as myself have to deal with 117816150Seric ** this kind of antique garbage???? 11796974Seric ** 1180294Seric ** Parameters: 11816974Seric ** fp -- the file to output to. 11826974Seric ** m -- the mailer describing this entry. 1183294Seric ** 1184294Seric ** Returns: 11856974Seric ** none 1186294Seric ** 1187294Seric ** Side Effects: 11886974Seric ** outputs some text to fp. 1189294Seric */ 1190294Seric 119154967Seric putfromline(fp, m, e) 11926974Seric register FILE *fp; 11936974Seric register MAILER *m; 119454967Seric ENVELOPE *e; 1195294Seric { 119658050Seric char *template = "\201l\n"; 11976974Seric char buf[MAXLINE]; 1198294Seric 119910682Seric if (bitnset(M_NHDR, m->m_flags)) 12006974Seric return; 12014315Seric 12026974Seric # ifdef UGLYUUCP 120310682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 12044205Seric { 120512223Seric char *bang; 120612223Seric char xbuf[MAXLINE]; 12076041Seric 120858050Seric expand("\201<", buf, &buf[sizeof buf - 1], e); 120956795Seric bang = strchr(buf, '!'); 12106974Seric if (bang == NULL) 121158151Seric syserr("554 No ! in UUCP! (%s)", buf); 12125099Seric else 12139370Seric { 121412223Seric *bang++ = '\0'; 121558050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 121612223Seric template = xbuf; 12179370Seric } 12186974Seric } 121956795Seric # endif /* UGLYUUCP */ 122054967Seric expand(template, buf, &buf[sizeof buf - 1], e); 122110168Seric putline(buf, fp, m); 12225981Seric } 12235981Seric /* 12246974Seric ** PUTBODY -- put the body of a message. 12256974Seric ** 12266974Seric ** Parameters: 12276974Seric ** fp -- file to output onto. 122810168Seric ** m -- a mailer descriptor to control output format. 12299538Seric ** e -- the envelope to put out. 12306974Seric ** 12316974Seric ** Returns: 12326974Seric ** none. 12336974Seric ** 12346974Seric ** Side Effects: 12356974Seric ** The message is written onto fp. 12366974Seric */ 12376974Seric 123810168Seric putbody(fp, m, e) 12396974Seric FILE *fp; 12409370Seric MAILER *m; 12419538Seric register ENVELOPE *e; 12426974Seric { 124310168Seric char buf[MAXLINE]; 12446974Seric 12456974Seric /* 12466974Seric ** Output the body of the message 12476974Seric */ 12486974Seric 12499538Seric if (e->e_dfp == NULL) 12506974Seric { 12519538Seric if (e->e_df != NULL) 12529538Seric { 12539538Seric e->e_dfp = fopen(e->e_df, "r"); 12549538Seric if (e->e_dfp == NULL) 125540931Srick syserr("putbody: Cannot open %s for %s from %s", 125640931Srick e->e_df, e->e_to, e->e_from); 12579538Seric } 12589538Seric else 125910168Seric putline("<<< No Message Collected >>>", fp, m); 12609538Seric } 12619538Seric if (e->e_dfp != NULL) 12629538Seric { 12639538Seric rewind(e->e_dfp); 126410168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 126516875Seric { 126616875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 126740995Sbostic strncmp(buf, "From ", 5) == 0) 126823102Seric (void) putc('>', fp); 126910168Seric putline(buf, fp, m); 127016875Seric } 12716974Seric 12729538Seric if (ferror(e->e_dfp)) 12736974Seric { 12746974Seric syserr("putbody: read error"); 12756974Seric ExitStat = EX_IOERR; 12766974Seric } 12776974Seric } 12786974Seric 12796974Seric (void) fflush(fp); 12806974Seric if (ferror(fp) && errno != EPIPE) 12816974Seric { 12826974Seric syserr("putbody: write error"); 12836974Seric ExitStat = EX_IOERR; 12846974Seric } 12856974Seric errno = 0; 12866974Seric } 12876974Seric /* 128858170Seric ** PARENTBODY -- put the body of the parent of a message. 128958170Seric ** 129058170Seric ** Parameters: 129158170Seric ** fp -- file to output onto. 129258170Seric ** m -- a mailer descriptor to control output format. 129358170Seric ** e -- the envelope whose parent to put out. 129458170Seric ** 129558170Seric ** Returns: 129658170Seric ** none. 129758170Seric ** 129858170Seric ** Side Effects: 129958170Seric ** The message is written onto fp. 130058170Seric */ 130158170Seric 130258170Seric parentbody(fp, m, e) 130358170Seric FILE *fp; 130458170Seric MAILER *m; 130558170Seric register ENVELOPE *e; 130658170Seric { 130758170Seric putbody(fp, m, e->e_parent); 130858170Seric } 130958170Seric /* 1310294Seric ** MAILFILE -- Send a message to a file. 1311294Seric ** 13124327Seric ** If the file has the setuid/setgid bits set, but NO execute 13134327Seric ** bits, sendmail will try to become the owner of that file 13144327Seric ** rather than the real user. Obviously, this only works if 13154327Seric ** sendmail runs as root. 13164327Seric ** 13179370Seric ** This could be done as a subordinate mailer, except that it 13189370Seric ** is used implicitly to save messages in ~/dead.letter. We 13199370Seric ** view this as being sufficiently important as to include it 13209370Seric ** here. For example, if the system is dying, we shouldn't have 13219370Seric ** to create another process plus some pipes to save the message. 13229370Seric ** 1323294Seric ** Parameters: 1324294Seric ** filename -- the name of the file to send to. 13254397Seric ** ctladdr -- the controlling address header -- includes 13264397Seric ** the userid/groupid to be when sending. 1327294Seric ** 1328294Seric ** Returns: 1329294Seric ** The exit code associated with the operation. 1330294Seric ** 1331294Seric ** Side Effects: 1332294Seric ** none. 1333294Seric */ 1334294Seric 133554967Seric mailfile(filename, ctladdr, e) 1336294Seric char *filename; 13374397Seric ADDRESS *ctladdr; 133854967Seric register ENVELOPE *e; 1339294Seric { 1340294Seric register FILE *f; 13414214Seric register int pid; 134253751Seric int mode; 1343294Seric 13444214Seric /* 13454214Seric ** Fork so we can change permissions here. 13464214Seric ** Note that we MUST use fork, not vfork, because of 13474214Seric ** the complications of calling subroutines, etc. 13484214Seric */ 13494067Seric 13504214Seric DOFORK(fork); 13514214Seric 13524214Seric if (pid < 0) 13534214Seric return (EX_OSERR); 13544214Seric else if (pid == 0) 13554214Seric { 13564214Seric /* child -- actually write to file */ 13574327Seric struct stat stb; 13584327Seric 13594215Seric (void) signal(SIGINT, SIG_DFL); 13604215Seric (void) signal(SIGHUP, SIG_DFL); 13614215Seric (void) signal(SIGTERM, SIG_DFL); 136223102Seric (void) umask(OldUmask); 136352673Seric 13644327Seric if (stat(filename, &stb) < 0) 13654431Seric stb.st_mode = 0666; 136653751Seric mode = stb.st_mode; 136752673Seric 136852673Seric /* limit the errors to those actually caused in the child */ 136952673Seric errno = 0; 137052673Seric ExitStat = EX_OK; 137152673Seric 13724327Seric if (bitset(0111, stb.st_mode)) 13734327Seric exit(EX_CANTCREAT); 13744401Seric if (ctladdr == NULL) 137540931Srick ctladdr = &e->e_from; 137653751Seric else 137753751Seric { 137853751Seric /* ignore setuid and setgid bits */ 137953751Seric mode &= ~(S_ISGID|S_ISUID); 138053751Seric } 138153751Seric 138240931Srick /* we have to open the dfile BEFORE setuid */ 138353751Seric if (e->e_dfp == NULL && e->e_df != NULL) 138440931Srick { 138540931Srick e->e_dfp = fopen(e->e_df, "r"); 138652673Seric if (e->e_dfp == NULL) 138752673Seric { 138840931Srick syserr("mailfile: Cannot open %s for %s from %s", 138953751Seric e->e_df, e->e_to, e->e_from); 139040931Srick } 139140931Srick } 139240931Srick 139353751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 13944417Seric { 139552673Seric if (ctladdr->q_uid == 0) 139652673Seric { 13974417Seric (void) setgid(DefGid); 139840972Sbostic (void) initgroups(DefUser, DefGid); 139952673Seric } 140052673Seric else 140152673Seric { 14024417Seric (void) setgid(ctladdr->q_gid); 140353751Seric (void) initgroups(ctladdr->q_ruser ? 140453751Seric ctladdr->q_ruser : ctladdr->q_user, 140540972Sbostic ctladdr->q_gid); 140640972Sbostic } 14074417Seric } 140853751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 14094417Seric { 14104417Seric if (ctladdr->q_uid == 0) 14114417Seric (void) setuid(DefUid); 14124417Seric else 14134417Seric (void) setuid(ctladdr->q_uid); 14144417Seric } 141552673Seric FileName = filename; 141652673Seric LineNumber = 0; 14176887Seric f = dfopen(filename, "a"); 14184214Seric if (f == NULL) 141952673Seric { 142058151Seric message("554 cannot open"); 14214214Seric exit(EX_CANTCREAT); 142252673Seric } 14234214Seric 142454967Seric putfromline(f, ProgMailer, e); 142555012Seric (*e->e_puthdr)(f, ProgMailer, e); 142610168Seric putline("\n", f, ProgMailer); 142755012Seric (*e->e_putbody)(f, ProgMailer, e); 142810168Seric putline("\n", f, ProgMailer); 142952673Seric if (ferror(f)) 143052673Seric { 143158151Seric message("451 I/O error"); 143252673Seric setstat(EX_IOERR); 143352673Seric } 14344214Seric (void) fclose(f); 14354214Seric (void) fflush(stdout); 14364417Seric 14376887Seric /* reset ISUID & ISGID bits for paranoid systems */ 14384621Seric (void) chmod(filename, (int) stb.st_mode); 143952673Seric exit(ExitStat); 14404315Seric /*NOTREACHED*/ 14414214Seric } 14424214Seric else 14434214Seric { 14444214Seric /* parent -- wait for exit status */ 14459370Seric int st; 14464214Seric 14479370Seric st = waitfor(pid); 14489370Seric if ((st & 0377) != 0) 14499370Seric return (EX_UNAVAILABLE); 14509370Seric else 14519370Seric return ((st >> 8) & 0377); 145240931Srick /*NOTREACHED*/ 14534214Seric } 1454294Seric } 14554550Seric /* 14564550Seric ** SENDALL -- actually send all the messages. 14574550Seric ** 14584550Seric ** Parameters: 14597043Seric ** e -- the envelope to send. 146014874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 146114874Seric ** the current SendMode. 14624550Seric ** 14634550Seric ** Returns: 14644550Seric ** none. 14654550Seric ** 14664550Seric ** Side Effects: 14674550Seric ** Scans the send lists and sends everything it finds. 14687043Seric ** Delivers any appropriate error messages. 14699275Seric ** If we are running in a non-interactive mode, takes the 14709275Seric ** appropriate action. 14714550Seric */ 14724550Seric 14739275Seric sendall(e, mode) 14747043Seric ENVELOPE *e; 14759275Seric char mode; 14764550Seric { 14775008Seric register ADDRESS *q; 14787779Seric bool oldverbose; 14799275Seric int pid; 148058170Seric char *owner; 148158170Seric int otherowners; 148258170Seric ENVELOPE *splitenv = NULL; 148351937Seric # ifdef LOCKF 148451937Seric struct flock lfd; 148551937Seric # endif 14864550Seric 148714874Seric /* determine actual delivery mode */ 148814874Seric if (mode == SM_DEFAULT) 148914874Seric { 149024941Seric extern bool shouldqueue(); 149114874Seric 149258146Seric mode = SendMode; 149358146Seric if (mode != SM_VERIFY && 149458146Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 149514874Seric mode = SM_QUEUE; 149614874Seric } 149714874Seric 14988248Seric if (tTd(13, 1)) 14995032Seric { 15009275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 15017043Seric printaddr(e->e_sendqueue, TRUE); 15025032Seric } 15035008Seric 15047043Seric /* 15059275Seric ** Do any preprocessing necessary for the mode we are running. 15069370Seric ** Check to make sure the hop count is reasonable. 15079370Seric ** Delete sends to the sender in mailing lists. 15087043Seric */ 15097043Seric 15109370Seric CurEnv = e; 15119370Seric 151251305Seric if (e->e_hopcount > MaxHopCount) 15139275Seric { 151440931Srick errno = 0; 151558151Seric syserr("554 too many hops %d (%d max): from %s, to %s", 151657589Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 151757589Seric e->e_sendqueue->q_paddr); 15189370Seric return; 15199370Seric } 15209275Seric 15219370Seric if (!MeToo) 15229370Seric { 152312611Seric extern ADDRESS *recipient(); 152412611Seric 15259370Seric e->e_from.q_flags |= QDONTSEND; 152657731Seric if (tTd(13, 5)) 152757731Seric { 152857731Seric printf("sendall: QDONTSEND "); 152957731Seric printaddr(&e->e_from, FALSE); 153057731Seric } 153155012Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 15329275Seric } 15339370Seric 153458170Seric /* 153558170Seric ** Handle alias owners. 153658170Seric ** 153758170Seric ** We scan up the q_alias chain looking for owners. 153858170Seric ** We discard owners that are the same as the return path. 153958170Seric */ 154058170Seric 154158170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 154258170Seric { 154358170Seric register struct address *a; 154458170Seric 154558170Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 154658170Seric continue; 154758170Seric if (a != NULL) 154858170Seric q->q_owner = a->q_owner; 154958170Seric 155058170Seric if (q->q_owner != NULL && !bitset(QDONTSEND, q->q_flags) && 155158170Seric strcmp(q->q_owner, e->e_returnpath) == 0) 155258170Seric q->q_owner = NULL; 155358170Seric } 155458170Seric 155558170Seric owner = ""; 155658170Seric otherowners = 1; 155758170Seric while (owner != NULL && otherowners > 0) 155858170Seric { 155958170Seric owner = NULL; 156058170Seric otherowners = 0; 156158170Seric 156258170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 156358170Seric { 156458170Seric if (bitset(QDONTSEND, q->q_flags)) 156558170Seric continue; 156658170Seric 156758170Seric if (q->q_owner != NULL) 156858170Seric { 156958170Seric if (owner == NULL) 157058170Seric owner = q->q_owner; 157158170Seric else if (owner != q->q_owner) 157258170Seric { 157358170Seric if (strcmp(owner, q->q_owner) == 0) 157458170Seric { 157558170Seric /* make future comparisons cheap */ 157658170Seric q->q_owner = owner; 157758170Seric } 157858170Seric else 157958170Seric { 158058170Seric otherowners++; 158158170Seric } 158258170Seric owner = q->q_owner; 158358170Seric } 158458170Seric } 158558170Seric else 158658170Seric { 158758170Seric otherowners++; 158858170Seric } 158958170Seric } 159058170Seric 159158170Seric if (owner != NULL && otherowners > 0) 159258170Seric { 159358170Seric register ENVELOPE *ee; 159458170Seric extern HDR *copyheader(); 159558170Seric extern ADDRESS *copyqueue(); 159658170Seric 159758170Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 159858170Seric STRUCTCOPY(*e, *ee); 159958170Seric ee->e_id = NULL; 160058170Seric ee->e_parent = e; 160158170Seric ee->e_header = copyheader(e->e_header); 160258170Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 160358170Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 160458170Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE); 160558170Seric ee->e_returnpath = owner; 160658170Seric ee->e_putbody = parentbody; 160758170Seric ee->e_sibling = splitenv; 160858170Seric splitenv = ee; 160958170Seric 161058170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 161158170Seric if (q->q_owner == owner) 161258170Seric q->q_flags |= QDONTSEND; 161358170Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 161458170Seric if (q->q_owner != owner) 161558170Seric q->q_flags |= QDONTSEND; 161658170Seric 161758170Seric if (e->e_df != NULL && mode != SM_VERIFY) 161858170Seric { 161958170Seric ee->e_dfp = NULL; 162058170Seric ee->e_df = queuename(ee, 'd'); 162158170Seric if (link(e->e_df, ee->e_df) < 0) 162258170Seric { 162358170Seric syserr("sendall: link(%s, %s)", 162458170Seric e->e_df, ee->e_df); 162558170Seric } 162658170Seric } 162758170Seric } 162858170Seric } 162958170Seric 163058170Seric if (owner != NULL) 163158170Seric e->e_returnpath = owner; 163258170Seric 16339370Seric # ifdef QUEUE 16349335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 16359335Seric (mode != SM_VERIFY && SuperSafe)) && 16369335Seric !bitset(EF_INQUEUE, e->e_flags)) 163751920Seric queueup(e, TRUE, mode == SM_QUEUE); 163856795Seric #endif /* QUEUE */ 16399275Seric 164058170Seric if (splitenv != NULL) 164158170Seric { 164258170Seric if (tTd(13, 1)) 164358170Seric { 164458170Seric printf("\nsendall: Split queue; remaining queue:\n"); 164558170Seric printaddr(e->e_sendqueue, TRUE); 164658170Seric } 164758170Seric 164858170Seric while (splitenv != NULL) 164958170Seric { 165058170Seric sendall(splitenv, mode); 165158170Seric splitenv = splitenv->e_sibling; 165258170Seric } 165358170Seric 165458170Seric CurEnv = e; 165558170Seric } 165658170Seric 16577779Seric oldverbose = Verbose; 16589275Seric switch (mode) 16599275Seric { 16609275Seric case SM_VERIFY: 16617779Seric Verbose = TRUE; 16629275Seric break; 16639275Seric 16649275Seric case SM_QUEUE: 166551916Seric queueonly: 16669335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 16679275Seric return; 16689275Seric 16699275Seric case SM_FORK: 16709538Seric if (e->e_xfp != NULL) 16719538Seric (void) fflush(e->e_xfp); 167251916Seric 167351916Seric # ifdef LOCKF 167451916Seric /* 167551916Seric ** Since lockf has the interesting semantic that the 167651937Seric ** lock is lost when we fork, we have to risk losing 167751937Seric ** the lock here by closing before the fork, and then 167851937Seric ** trying to get it back in the child. 167951916Seric */ 168051916Seric 168151920Seric if (e->e_lockfp != NULL) 168251916Seric { 168351920Seric (void) fclose(e->e_lockfp); 168451920Seric e->e_lockfp = NULL; 168551916Seric } 168651916Seric # endif /* LOCKF */ 168751916Seric 16889275Seric pid = fork(); 16899275Seric if (pid < 0) 16909275Seric { 169151916Seric goto queueonly; 16929275Seric } 16939275Seric else if (pid > 0) 16949293Seric { 16959293Seric /* be sure we leave the temp files to our child */ 16969335Seric e->e_id = e->e_df = NULL; 169751916Seric # ifndef LOCKF 169851920Seric if (e->e_lockfp != NULL) 169957731Seric { 170051920Seric (void) fclose(e->e_lockfp); 170157731Seric e->e_lockfp = NULL; 170257731Seric } 170351916Seric # endif 170457731Seric 170557731Seric /* close any random open files in the envelope */ 170657731Seric if (e->e_dfp != NULL) 170757731Seric { 170857731Seric (void) fclose(e->e_dfp); 170957731Seric e->e_dfp = NULL; 171057731Seric } 171157731Seric if (e->e_xfp != NULL) 171257731Seric { 171357731Seric (void) fclose(e->e_xfp); 171457731Seric e->e_xfp = NULL; 171557731Seric } 17169275Seric return; 17179293Seric } 17189275Seric 17199275Seric /* double fork to avoid zombies */ 17209275Seric if (fork() > 0) 17219275Seric exit(EX_OK); 17229275Seric 17239293Seric /* be sure we are immune from the terminal */ 172410133Seric disconnect(FALSE); 17259293Seric 172651911Seric # ifdef LOCKF 172751911Seric /* 172851916Seric ** Now try to get our lock back. 172951911Seric */ 173051911Seric 173151937Seric lfd.l_type = F_WRLCK; 173251937Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 173351920Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 173451920Seric if (e->e_lockfp == NULL || 173551937Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 173651911Seric { 173751916Seric /* oops.... lost it */ 173851911Seric # ifdef LOG 173958020Seric if (LogLevel > 29) 174051916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 174154967Seric e->e_id); 174251911Seric # endif /* LOG */ 174351916Seric exit(EX_OK); 174451911Seric } 174551911Seric # endif /* LOCKF */ 174651911Seric 174758082Seric /* 174858082Seric ** Close any cached connections. 174958082Seric ** 175058082Seric ** We don't send the QUIT protocol because the parent 175158082Seric ** still knows about the connection. 175258082Seric ** 175358082Seric ** This should only happen when delivering an error 175458082Seric ** message. 175558082Seric */ 175658082Seric 175758082Seric mci_flush(FALSE, NULL); 175858082Seric 17599275Seric break; 17609275Seric } 17619275Seric 17629275Seric /* 17639275Seric ** Run through the list and send everything. 17649275Seric */ 17659275Seric 176657589Seric e->e_nsent = 0; 17677043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 17684550Seric { 17699275Seric if (mode == SM_VERIFY) 17704550Seric { 17719293Seric e->e_to = q->q_paddr; 17725008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 177358151Seric message("deliverable"); 17744550Seric } 177547284Seric else if (!bitset(QDONTSEND, q->q_flags)) 177647284Seric { 177750533Seric # ifdef QUEUE 177847284Seric /* 177947284Seric ** Checkpoint the send list every few addresses 178047284Seric */ 178147284Seric 178257589Seric if (e->e_nsent >= CheckpointInterval) 178347284Seric { 178451920Seric queueup(e, TRUE, FALSE); 178557589Seric e->e_nsent = 0; 178647284Seric } 178750533Seric # endif /* QUEUE */ 178857589Seric (void) deliver(e, q); 178947284Seric } 17904550Seric } 17917779Seric Verbose = oldverbose; 17927043Seric 17937043Seric /* 17947043Seric ** Now run through and check for errors. 17957043Seric */ 17967043Seric 179751920Seric if (mode == SM_VERIFY) 17987043Seric return; 17997043Seric 18007043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 18017043Seric { 18028248Seric if (tTd(13, 3)) 18038248Seric { 18048248Seric printf("Checking "); 18058248Seric printaddr(q, FALSE); 18068248Seric } 18078248Seric 18089335Seric /* only send errors if the message failed */ 18099335Seric if (!bitset(QBADADDR, q->q_flags)) 18109335Seric continue; 18117043Seric 181258170Seric if (q->q_owner == NULL) 181358170Seric (void) sendtolist(e->e_from.q_paddr, NULL, 181458082Seric &e->e_errorqueue, e); 18157043Seric } 18169275Seric 18179275Seric if (mode == SM_FORK) 18189275Seric finis(); 18194550Seric } 182057454Seric /* 182157454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 182257454Seric ** 182357454Seric ** The signature describes how we are going to send this -- it 182457454Seric ** can be just the hostname (for non-Internet hosts) or can be 182557454Seric ** an ordered list of MX hosts. 182657454Seric ** 182757454Seric ** Parameters: 182857454Seric ** m -- the mailer describing this host. 182957454Seric ** host -- the host name. 183057454Seric ** e -- the current envelope. 183157454Seric ** 183257454Seric ** Returns: 183357454Seric ** The signature for this host. 183457454Seric ** 183557454Seric ** Side Effects: 183657454Seric ** Can tweak the symbol table. 183757454Seric */ 183857454Seric 183957454Seric char * 184057454Seric hostsignature(m, host, e) 184157454Seric register MAILER *m; 184257454Seric char *host; 184357454Seric ENVELOPE *e; 184457454Seric { 184557454Seric register char *p; 184657454Seric register STAB *s; 184757454Seric int i; 184857454Seric int len; 184957454Seric #ifdef NAMED_BIND 185057454Seric int nmx; 185157454Seric auto int rcode; 185257454Seric char *mxhosts[MAXMXHOSTS + 1]; 185357454Seric static char myhostbuf[MAXNAME]; 185457454Seric #endif 185557454Seric 185657454Seric /* 185757454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 185857454Seric */ 185957454Seric 186057454Seric p = m->m_mailer; 186157454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 186257454Seric { 186357454Seric /* just an ordinary mailer */ 186457454Seric return host; 186557454Seric } 186657454Seric 186757454Seric /* 186857454Seric ** If it is a numeric address, just return it. 186957454Seric */ 187057454Seric 187157454Seric if (host[0] == '[') 187257454Seric return host; 187357454Seric 187457454Seric /* 187557454Seric ** Look it up in the symbol table. 187657454Seric */ 187757454Seric 187857454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 187957454Seric if (s->s_hostsig != NULL) 188057454Seric return s->s_hostsig; 188157454Seric 188257454Seric /* 188357454Seric ** Not already there -- create a signature. 188457454Seric */ 188557454Seric 188657454Seric #ifdef NAMED_BIND 188757454Seric if (myhostbuf[0] == '\0') 188858050Seric expand("\201j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e); 188957454Seric 189057454Seric nmx = getmxrr(host, mxhosts, myhostbuf, &rcode); 189157454Seric if (nmx <= 0) 189257454Seric { 189357454Seric register MCI *mci; 189457454Seric extern int errno; 189557454Seric extern MCI *mci_get(); 189657454Seric 189757454Seric /* update the connection info for this host */ 189857454Seric mci = mci_get(host, m); 189957454Seric mci->mci_exitstat = rcode; 190057454Seric mci->mci_errno = errno; 190157454Seric 190257454Seric /* and return the original host name as the signature */ 190357454Seric s->s_hostsig = host; 190457454Seric return host; 190557454Seric } 190657454Seric 190757454Seric len = 0; 190857454Seric for (i = 0; i < nmx; i++) 190957454Seric { 191057454Seric len += strlen(mxhosts[i]) + 1; 191157454Seric } 191257454Seric s->s_hostsig = p = xalloc(len); 191357454Seric for (i = 0; i < nmx; i++) 191457454Seric { 191557454Seric if (i != 0) 191657454Seric *p++ = ':'; 191757454Seric strcpy(p, mxhosts[i]); 191857454Seric p += strlen(p); 191957454Seric } 192057454Seric makelower(s->s_hostsig); 192157454Seric #else 192257454Seric /* not using BIND -- the signature is just the host name */ 192357454Seric s->s_hostsig = host; 192457454Seric #endif 192557454Seric if (tTd(17, 1)) 192657454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 192757454Seric return s->s_hostsig; 192857454Seric } 1929