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*58675Seric static char sccsid[] = "@(#)deliver.c 6.43 (Berkeley) 03/14/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; 7658247Seric 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 { 10958247Seric if (bitset(QDONTSEND|QQUEUEUP, to->q_flags) || 11058247Seric 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) 11658337Seric logdelivery(m, NULL, "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, 13558509Seric TRUE, FALSE, 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, 14358509Seric TRUE, FALSE, 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 */ 23458247Seric 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); 27158337Seric giveresponse(EX_UNAVAILABLE, m, NULL, e); 27210699Seric continue; 27310699Seric } 27457441Seric rcode = checkcompat(to, e); 27557459Seric if (rcode != EX_OK) 276294Seric { 27758337Seric giveresponse(rcode, m, NULL, 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); 32258337Seric giveresponse(rcode, m, NULL, 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 39158309Seric if (ctladdr == NULL && m != ProgMailer) 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); 45258337Seric giveresponse(i, m, mci, 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') 50858337Seric giveresponse(rcode, m, mci, 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 76858479Seric if (curhost == NULL || curhost[0] == '\0') 76958479Seric { 77058479Seric syserr("null signature"); 77158479Seric return NULL; 77258479Seric } 77358479Seric 7746038Seric if (!clever) 77558479Seric { 77658151Seric syserr("554 non-clever IPC"); 77758479Seric return NULL; 77858479Seric } 7796632Seric if (pvp[2] != NULL) 7807285Seric port = atoi(pvp[2]); 7816632Seric else 7827285Seric port = 0; 78357454Seric while (*curhost != '\0') 78429433Sbloom { 78557454Seric register char *p; 78658664Seric static char hostbuf[MAXNAME]; 78757454Seric 78857454Seric /* pull the next host from the signature */ 78957454Seric p = strchr(curhost, ':'); 79057454Seric if (p == NULL) 79157454Seric p = &curhost[strlen(curhost)]; 79257454Seric strncpy(hostbuf, curhost, p - curhost); 79357454Seric hostbuf[p - curhost] = '\0'; 79457454Seric if (*p != '\0') 79557454Seric p++; 79657454Seric curhost = p; 79757454Seric 79853738Seric /* see if we already know that this host is fried */ 79957454Seric CurHostName = hostbuf; 80057454Seric mci = mci_get(hostbuf, m); 80154967Seric if (mci->mci_state != MCIS_CLOSED) 80257387Seric { 80357387Seric if (tTd(11, 1)) 80457387Seric { 80557387Seric printf("openmailer: "); 80657387Seric mci_dump(mci); 80757387Seric } 80857943Seric CurHostName = mci->mci_host; 80953738Seric return mci; 81057387Seric } 81153751Seric mci->mci_mailer = m; 81254967Seric if (mci->mci_exitstat != EX_OK) 81354967Seric continue; 81454967Seric 81554967Seric /* try the connection */ 81657454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 81758151Seric message("Connecting to %s (%s)...", 81857454Seric hostbuf, m->m_name); 81957454Seric i = makeconnection(hostbuf, port, mci, 82054967Seric bitnset(M_SECURE_PORT, m->m_flags)); 82154967Seric mci->mci_exitstat = i; 82254967Seric mci->mci_errno = errno; 82354967Seric if (i == EX_OK) 82452106Seric { 82554967Seric mci->mci_state = MCIS_OPENING; 82654967Seric mci_cache(mci); 82754967Seric break; 82834022Sbostic } 82954967Seric else if (tTd(11, 1)) 83054967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 83154967Seric i, errno); 83253738Seric 83354967Seric 83453738Seric /* enter status of this host */ 83553738Seric setstat(i); 8366047Seric } 83754993Seric mci->mci_pid = 0; 83854967Seric #else /* no DAEMON */ 83958151Seric syserr("554 openmailer: no IPC"); 84057387Seric if (tTd(11, 1)) 84157387Seric printf("openmailer: NULL\n"); 84253738Seric return NULL; 84354967Seric #endif /* DAEMON */ 8446038Seric } 84554967Seric else 846294Seric { 84754967Seric /* create a pipe to shove the mail through */ 84854967Seric if (pipe(mpvect) < 0) 84954967Seric { 85054967Seric syserr("openmailer: pipe (to mailer)"); 85157387Seric if (tTd(11, 1)) 85257387Seric printf("openmailer: NULL\n"); 85354967Seric return NULL; 85454967Seric } 8554863Seric 85654967Seric /* if this mailer speaks smtp, create a return pipe */ 85754967Seric if (clever && pipe(rpvect) < 0) 85854967Seric { 85954967Seric syserr("openmailer: pipe (from mailer)"); 86054967Seric (void) close(mpvect[0]); 86154967Seric (void) close(mpvect[1]); 86257387Seric if (tTd(11, 1)) 86357387Seric printf("openmailer: NULL\n"); 86454967Seric return NULL; 86554967Seric } 8664863Seric 86754967Seric /* 86854967Seric ** Actually fork the mailer process. 86954967Seric ** DOFORK is clever about retrying. 87054967Seric ** 87154967Seric ** Dispose of SIGCHLD signal catchers that may be laying 87254967Seric ** around so that endmail will get it. 87354967Seric */ 8746038Seric 87554967Seric if (e->e_xfp != NULL) 87654967Seric (void) fflush(e->e_xfp); /* for debugging */ 87754967Seric (void) fflush(stdout); 87826434Seric # ifdef SIGCHLD 87954967Seric (void) signal(SIGCHLD, SIG_DFL); 88056795Seric # endif /* SIGCHLD */ 88154967Seric DOFORK(FORK); 88254967Seric /* pid is set by DOFORK */ 88354967Seric if (pid < 0) 8844863Seric { 88554967Seric /* failure */ 88654967Seric syserr("openmailer: cannot fork"); 88754967Seric (void) close(mpvect[0]); 88854967Seric (void) close(mpvect[1]); 88954967Seric if (clever) 89054967Seric { 89154967Seric (void) close(rpvect[0]); 89254967Seric (void) close(rpvect[1]); 89354967Seric } 89457387Seric if (tTd(11, 1)) 89557387Seric printf("openmailer: NULL\n"); 89654967Seric return NULL; 8974863Seric } 89854967Seric else if (pid == 0) 89954967Seric { 90054967Seric int i; 90156678Seric int saveerrno; 902*58675Seric char **ep; 903*58675Seric char *env[MAXUSERENVIRON]; 904*58675Seric extern char **environ; 90554967Seric extern int DtableSize; 90615772Seric 90754967Seric /* child -- set up input & exec mailer */ 90854967Seric /* make diagnostic output be standard output */ 90954967Seric (void) signal(SIGINT, SIG_IGN); 91054967Seric (void) signal(SIGHUP, SIG_IGN); 91154967Seric (void) signal(SIGTERM, SIG_DFL); 9124709Seric 91358082Seric /* close any other cached connections */ 91458082Seric mci_flush(FALSE, mci); 91558082Seric 91654967Seric /* arrange to filter std & diag output of command */ 91754967Seric if (clever) 91854967Seric { 91954967Seric (void) close(rpvect[0]); 92054967Seric (void) close(1); 92154967Seric (void) dup(rpvect[1]); 92254967Seric (void) close(rpvect[1]); 92354967Seric } 92454967Seric else if (OpMode == MD_SMTP || HoldErrs) 92554967Seric { 92654967Seric /* put mailer output in transcript */ 92754967Seric (void) close(1); 92854967Seric (void) dup(fileno(e->e_xfp)); 92954967Seric } 93054967Seric (void) close(2); 93154967Seric (void) dup(1); 9324709Seric 93354967Seric /* arrange to get standard input */ 93454967Seric (void) close(mpvect[1]); 93554967Seric (void) close(0); 93654967Seric if (dup(mpvect[0]) < 0) 9374417Seric { 93854967Seric syserr("Cannot dup to zero!"); 93954967Seric _exit(EX_OSERR); 9404417Seric } 94154967Seric (void) close(mpvect[0]); 94254967Seric if (!bitnset(M_RESTR, m->m_flags)) 9434415Seric { 94454967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 94554967Seric { 94654967Seric (void) setgid(DefGid); 94754967Seric (void) initgroups(DefUser, DefGid); 94854967Seric (void) setuid(DefUid); 94954967Seric } 95054967Seric else 95154967Seric { 95254967Seric (void) setgid(ctladdr->q_gid); 95354967Seric (void) initgroups(ctladdr->q_ruser? 95454967Seric ctladdr->q_ruser: ctladdr->q_user, 95554967Seric ctladdr->q_gid); 95654967Seric (void) setuid(ctladdr->q_uid); 95754967Seric } 9584415Seric } 9599370Seric 96054967Seric /* arrange for all the files to be closed */ 96154967Seric for (i = 3; i < DtableSize; i++) 96254967Seric { 96354967Seric register int j; 96454967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 96554967Seric (void)fcntl(i, F_SETFD, j|1); 96654967Seric } 9672774Seric 968*58675Seric /* set up the mailer environment */ 969*58675Seric i = 0; 970*58675Seric env[i++] = "AGENT=sendmail"; 971*58675Seric for (ep = environ; *ep != NULL; ep++) 972*58675Seric { 973*58675Seric if (strncmp(*ep, "TZ=", 3) == 0) 974*58675Seric env[i++] = *ep; 975*58675Seric } 976*58675Seric env[i++] = NULL; 977*58675Seric 97854967Seric /* try to execute the mailer */ 97957529Seric execve(m->m_mailer, pvp, env); 98056678Seric saveerrno = errno; 98154967Seric syserr("Cannot exec %s", m->m_mailer); 98254967Seric if (m == LocalMailer) 98354967Seric _exit(EX_TEMPFAIL); 98458542Seric if (transienterror(saveerrno)) 98554967Seric _exit(EX_TEMPFAIL); 98654967Seric _exit(EX_UNAVAILABLE); 98751835Seric } 98854967Seric 98954967Seric /* 99054967Seric ** Set up return value. 99154967Seric */ 99254967Seric 99354967Seric mci = (MCI *) xalloc(sizeof *mci); 99454993Seric bzero((char *) mci, sizeof *mci); 99554967Seric mci->mci_mailer = m; 99654967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 99754993Seric mci->mci_pid = pid; 99854967Seric (void) close(mpvect[0]); 99954967Seric mci->mci_out = fdopen(mpvect[1], "w"); 100054967Seric if (clever) 100154967Seric { 100254967Seric (void) close(rpvect[1]); 100354967Seric mci->mci_in = fdopen(rpvect[0], "r"); 100454967Seric } 100554967Seric else 100654967Seric { 100754967Seric mci->mci_flags |= MCIF_TEMP; 100854967Seric mci->mci_in = NULL; 100954967Seric } 1010294Seric } 1011294Seric 10124709Seric /* 101354967Seric ** If we are in SMTP opening state, send initial protocol. 10144709Seric */ 10154709Seric 101654967Seric if (clever && mci->mci_state != MCIS_CLOSED) 10174863Seric { 101854967Seric smtpinit(m, mci, e); 101953738Seric } 102057387Seric if (tTd(11, 1)) 102157387Seric { 102257387Seric printf("openmailer: "); 102357387Seric mci_dump(mci); 102457387Seric } 1025294Seric 102653738Seric return mci; 1027294Seric } 1028294Seric /* 1029294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1030294Seric ** 1031294Seric ** Parameters: 1032294Seric ** stat -- the status code from the mailer (high byte 1033294Seric ** only; core dumps must have been taken care of 1034294Seric ** already). 103558337Seric ** m -- the mailer info for this mailer. 103658337Seric ** mci -- the mailer connection info -- can be NULL if the 103758337Seric ** response is given before the connection is made. 103858337Seric ** e -- the current envelope. 1039294Seric ** 1040294Seric ** Returns: 10414082Seric ** none. 1042294Seric ** 1043294Seric ** Side Effects: 10441518Seric ** Errors may be incremented. 1045294Seric ** ExitStat may be set. 1046294Seric */ 1047294Seric 104858337Seric giveresponse(stat, m, mci, e) 1049294Seric int stat; 10509370Seric register MAILER *m; 105158337Seric register MCI *mci; 105210105Seric ENVELOPE *e; 1053294Seric { 1054294Seric register char *statmsg; 1055294Seric extern char *SysExMsg[]; 1056294Seric register int i; 105736788Sbostic extern int N_SysEx; 105836788Sbostic #ifdef NAMED_BIND 105936788Sbostic extern int h_errno; 106036788Sbostic #endif 106110105Seric char buf[MAXLINE]; 106258664Seric extern char *errstring(); 1063294Seric 10644315Seric /* 10654315Seric ** Compute status message from code. 10664315Seric */ 10674315Seric 1068294Seric i = stat - EX__BASE; 10699370Seric if (stat == 0) 10709370Seric statmsg = "250 Sent"; 10719370Seric else if (i < 0 || i > N_SysEx) 10729370Seric { 10739370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 10749370Seric stat = EX_UNAVAILABLE; 10759370Seric statmsg = buf; 10769370Seric } 107710105Seric else if (stat == EX_TEMPFAIL) 107810105Seric { 107958664Seric (void) strcpy(buf, SysExMsg[i] + 1); 108036788Sbostic #ifdef NAMED_BIND 108125527Smiriam if (h_errno == TRY_AGAIN) 108225527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 108321061Seric else 108436788Sbostic #endif 108521061Seric { 108625527Smiriam if (errno != 0) 108725527Smiriam statmsg = errstring(errno); 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]; 110958664Seric if (*statmsg++ == ':') 111058664Seric { 111158664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 111258664Seric statmsg = buf; 111358664Seric } 111421061Seric } 11159370Seric 11169370Seric /* 11179370Seric ** Print the message as appropriate 11189370Seric */ 11199370Seric 112010105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 112158524Seric message(&statmsg[4], errstring(errno)); 1122294Seric else 1123294Seric { 11241518Seric Errors++; 112558524Seric usrerr(statmsg, errstring(errno)); 1126294Seric } 1127294Seric 1128294Seric /* 1129294Seric ** Final cleanup. 1130294Seric ** Log a record of the transaction. Compute the new 1131294Seric ** ExitStat -- if we already had an error, stick with 1132294Seric ** that. 1133294Seric */ 1134294Seric 113558020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 113658337Seric logdelivery(m, mci, &statmsg[4], e); 11377858Seric 11384621Seric if (stat != EX_TEMPFAIL) 11394621Seric setstat(stat); 114010105Seric if (stat != EX_OK) 114110105Seric { 114210105Seric if (e->e_message != NULL) 114310105Seric free(e->e_message); 114410105Seric e->e_message = newstr(&statmsg[4]); 114510105Seric } 114610124Seric errno = 0; 114736788Sbostic #ifdef NAMED_BIND 114825527Smiriam h_errno = 0; 114936788Sbostic #endif 1150294Seric } 1151294Seric /* 11528496Seric ** LOGDELIVERY -- log the delivery in the system log 11538496Seric ** 11548496Seric ** Parameters: 115558337Seric ** m -- the mailer info. Can be NULL for initial queue. 115658337Seric ** mci -- the mailer connection info -- can be NULL if the 115758337Seric ** log is occuring when no connection is active. 115858337Seric ** stat -- the message to print for the status. 115958337Seric ** e -- the current envelope. 11608496Seric ** 11618496Seric ** Returns: 11628496Seric ** none 11638496Seric ** 11648496Seric ** Side Effects: 11658496Seric ** none 11668496Seric */ 11678496Seric 116858337Seric logdelivery(m, mci, stat, e) 116958337Seric MAILER *m; 117058337Seric register MCI *mci; 11718496Seric char *stat; 117254967Seric register ENVELOPE *e; 11738496Seric { 117458343Seric # ifdef LOG 117558337Seric char *curhost; 117658418Seric char buf[512]; 11778496Seric extern char *pintvl(); 117858343Seric extern char *macvalue(); 11798496Seric 118058513Seric (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 118158337Seric 118258513Seric if (m != NULL) 118358305Seric { 118458513Seric (void) strcat(buf, ", mailer="); 118558513Seric (void) strcat(buf, m->m_name); 118658305Seric } 118758513Seric 118858513Seric if (mci != NULL && mci->mci_host != NULL) 118958305Seric { 119058305Seric # ifdef DAEMON 119158343Seric extern struct sockaddr_in CurHostAddr; 119258343Seric extern char *inet_ntoa(); 119358513Seric # endif 119458305Seric 119558513Seric (void) strcat(buf, ", relay="); 119658513Seric (void) strcat(buf, mci->mci_host); 119758513Seric 119858513Seric # ifdef DAEMON 119958513Seric (void) strcat(buf, " ("); 120058513Seric (void) strcat(buf, inet_ntoa(CurHostAddr.sin_addr)); 120158513Seric (void) strcat(buf, ")"); 120258305Seric # endif 120358305Seric } 120458343Seric else 120558513Seric { 120658513Seric char *p = macvalue('h', e); 120758343Seric 120858513Seric if (p != NULL && p[0] != '\0') 120958513Seric { 121058513Seric (void) strcat(buf, ", relay="); 121158513Seric (void) strcat(buf, p); 121258513Seric } 121358513Seric } 121458418Seric 121558418Seric syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", 121658418Seric e->e_id, e->e_to, buf, stat); 121756795Seric # endif /* LOG */ 12188496Seric } 12198496Seric /* 12206974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1221294Seric ** 12226974Seric ** This can be made an arbitrary message separator by changing $l 1223294Seric ** 122416150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 122516150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 122616150Seric ** does a well-meaning programmer such as myself have to deal with 122716150Seric ** this kind of antique garbage???? 12286974Seric ** 1229294Seric ** Parameters: 12306974Seric ** fp -- the file to output to. 12316974Seric ** m -- the mailer describing this entry. 1232294Seric ** 1233294Seric ** Returns: 12346974Seric ** none 1235294Seric ** 1236294Seric ** Side Effects: 12376974Seric ** outputs some text to fp. 1238294Seric */ 1239294Seric 124054967Seric putfromline(fp, m, e) 12416974Seric register FILE *fp; 12426974Seric register MAILER *m; 124354967Seric ENVELOPE *e; 1244294Seric { 124558050Seric char *template = "\201l\n"; 12466974Seric char buf[MAXLINE]; 1247294Seric 124810682Seric if (bitnset(M_NHDR, m->m_flags)) 12496974Seric return; 12504315Seric 12516974Seric # ifdef UGLYUUCP 125210682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 12534205Seric { 125412223Seric char *bang; 125512223Seric char xbuf[MAXLINE]; 12566041Seric 125758050Seric expand("\201<", buf, &buf[sizeof buf - 1], e); 125856795Seric bang = strchr(buf, '!'); 12596974Seric if (bang == NULL) 126058151Seric syserr("554 No ! in UUCP! (%s)", buf); 12615099Seric else 12629370Seric { 126312223Seric *bang++ = '\0'; 126458050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 126512223Seric template = xbuf; 12669370Seric } 12676974Seric } 126856795Seric # endif /* UGLYUUCP */ 126954967Seric expand(template, buf, &buf[sizeof buf - 1], e); 127010168Seric putline(buf, fp, m); 12715981Seric } 12725981Seric /* 12736974Seric ** PUTBODY -- put the body of a message. 12746974Seric ** 12756974Seric ** Parameters: 12766974Seric ** fp -- file to output onto. 127710168Seric ** m -- a mailer descriptor to control output format. 12789538Seric ** e -- the envelope to put out. 12796974Seric ** 12806974Seric ** Returns: 12816974Seric ** none. 12826974Seric ** 12836974Seric ** Side Effects: 12846974Seric ** The message is written onto fp. 12856974Seric */ 12866974Seric 128710168Seric putbody(fp, m, e) 12886974Seric FILE *fp; 12899370Seric MAILER *m; 12909538Seric register ENVELOPE *e; 12916974Seric { 129210168Seric char buf[MAXLINE]; 12936974Seric 12946974Seric /* 12956974Seric ** Output the body of the message 12966974Seric */ 12976974Seric 12989538Seric if (e->e_dfp == NULL) 12996974Seric { 13009538Seric if (e->e_df != NULL) 13019538Seric { 13029538Seric e->e_dfp = fopen(e->e_df, "r"); 13039538Seric if (e->e_dfp == NULL) 130440931Srick syserr("putbody: Cannot open %s for %s from %s", 130540931Srick e->e_df, e->e_to, e->e_from); 13069538Seric } 13079538Seric else 130810168Seric putline("<<< No Message Collected >>>", fp, m); 13099538Seric } 13109538Seric if (e->e_dfp != NULL) 13119538Seric { 13129538Seric rewind(e->e_dfp); 131310168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 131416875Seric { 131516875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 131640995Sbostic strncmp(buf, "From ", 5) == 0) 131723102Seric (void) putc('>', fp); 131810168Seric putline(buf, fp, m); 131916875Seric } 13206974Seric 13219538Seric if (ferror(e->e_dfp)) 13226974Seric { 13236974Seric syserr("putbody: read error"); 13246974Seric ExitStat = EX_IOERR; 13256974Seric } 13266974Seric } 13276974Seric 13286974Seric (void) fflush(fp); 13296974Seric if (ferror(fp) && errno != EPIPE) 13306974Seric { 13316974Seric syserr("putbody: write error"); 13326974Seric ExitStat = EX_IOERR; 13336974Seric } 13346974Seric errno = 0; 13356974Seric } 13366974Seric /* 133758170Seric ** PARENTBODY -- put the body of the parent of a message. 133858170Seric ** 133958170Seric ** Parameters: 134058170Seric ** fp -- file to output onto. 134158170Seric ** m -- a mailer descriptor to control output format. 134258170Seric ** e -- the envelope whose parent to put out. 134358170Seric ** 134458170Seric ** Returns: 134558170Seric ** none. 134658170Seric ** 134758170Seric ** Side Effects: 134858170Seric ** The message is written onto fp. 134958170Seric */ 135058170Seric 135158170Seric parentbody(fp, m, e) 135258170Seric FILE *fp; 135358170Seric MAILER *m; 135458170Seric register ENVELOPE *e; 135558170Seric { 135658170Seric putbody(fp, m, e->e_parent); 135758170Seric } 135858170Seric /* 1359294Seric ** MAILFILE -- Send a message to a file. 1360294Seric ** 13614327Seric ** If the file has the setuid/setgid bits set, but NO execute 13624327Seric ** bits, sendmail will try to become the owner of that file 13634327Seric ** rather than the real user. Obviously, this only works if 13644327Seric ** sendmail runs as root. 13654327Seric ** 13669370Seric ** This could be done as a subordinate mailer, except that it 13679370Seric ** is used implicitly to save messages in ~/dead.letter. We 13689370Seric ** view this as being sufficiently important as to include it 13699370Seric ** here. For example, if the system is dying, we shouldn't have 13709370Seric ** to create another process plus some pipes to save the message. 13719370Seric ** 1372294Seric ** Parameters: 1373294Seric ** filename -- the name of the file to send to. 13744397Seric ** ctladdr -- the controlling address header -- includes 13754397Seric ** the userid/groupid to be when sending. 1376294Seric ** 1377294Seric ** Returns: 1378294Seric ** The exit code associated with the operation. 1379294Seric ** 1380294Seric ** Side Effects: 1381294Seric ** none. 1382294Seric */ 1383294Seric 138454967Seric mailfile(filename, ctladdr, e) 1385294Seric char *filename; 13864397Seric ADDRESS *ctladdr; 138754967Seric register ENVELOPE *e; 1388294Seric { 1389294Seric register FILE *f; 13904214Seric register int pid; 139153751Seric int mode; 1392294Seric 13934214Seric /* 13944214Seric ** Fork so we can change permissions here. 13954214Seric ** Note that we MUST use fork, not vfork, because of 13964214Seric ** the complications of calling subroutines, etc. 13974214Seric */ 13984067Seric 13994214Seric DOFORK(fork); 14004214Seric 14014214Seric if (pid < 0) 14024214Seric return (EX_OSERR); 14034214Seric else if (pid == 0) 14044214Seric { 14054214Seric /* child -- actually write to file */ 14064327Seric struct stat stb; 14074327Seric 14084215Seric (void) signal(SIGINT, SIG_DFL); 14094215Seric (void) signal(SIGHUP, SIG_DFL); 14104215Seric (void) signal(SIGTERM, SIG_DFL); 141123102Seric (void) umask(OldUmask); 141252673Seric 14134327Seric if (stat(filename, &stb) < 0) 14144431Seric stb.st_mode = 0666; 141553751Seric mode = stb.st_mode; 141652673Seric 141752673Seric /* limit the errors to those actually caused in the child */ 141852673Seric errno = 0; 141952673Seric ExitStat = EX_OK; 142052673Seric 14214327Seric if (bitset(0111, stb.st_mode)) 14224327Seric exit(EX_CANTCREAT); 14234401Seric if (ctladdr == NULL) 142440931Srick ctladdr = &e->e_from; 142553751Seric else 142653751Seric { 142753751Seric /* ignore setuid and setgid bits */ 142853751Seric mode &= ~(S_ISGID|S_ISUID); 142953751Seric } 143053751Seric 143140931Srick /* we have to open the dfile BEFORE setuid */ 143253751Seric if (e->e_dfp == NULL && e->e_df != NULL) 143340931Srick { 143440931Srick e->e_dfp = fopen(e->e_df, "r"); 143552673Seric if (e->e_dfp == NULL) 143652673Seric { 143740931Srick syserr("mailfile: Cannot open %s for %s from %s", 143853751Seric e->e_df, e->e_to, e->e_from); 143940931Srick } 144040931Srick } 144140931Srick 144253751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 14434417Seric { 144452673Seric if (ctladdr->q_uid == 0) 144552673Seric { 14464417Seric (void) setgid(DefGid); 144740972Sbostic (void) initgroups(DefUser, DefGid); 144852673Seric } 144952673Seric else 145052673Seric { 14514417Seric (void) setgid(ctladdr->q_gid); 145253751Seric (void) initgroups(ctladdr->q_ruser ? 145353751Seric ctladdr->q_ruser : ctladdr->q_user, 145440972Sbostic ctladdr->q_gid); 145540972Sbostic } 14564417Seric } 145753751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 14584417Seric { 14594417Seric if (ctladdr->q_uid == 0) 14604417Seric (void) setuid(DefUid); 14614417Seric else 14624417Seric (void) setuid(ctladdr->q_uid); 14634417Seric } 146452673Seric FileName = filename; 146552673Seric LineNumber = 0; 14666887Seric f = dfopen(filename, "a"); 14674214Seric if (f == NULL) 146852673Seric { 146958151Seric message("554 cannot open"); 14704214Seric exit(EX_CANTCREAT); 147152673Seric } 14724214Seric 147354967Seric putfromline(f, ProgMailer, e); 147455012Seric (*e->e_puthdr)(f, ProgMailer, e); 147510168Seric putline("\n", f, ProgMailer); 147655012Seric (*e->e_putbody)(f, ProgMailer, e); 147710168Seric putline("\n", f, ProgMailer); 147852673Seric if (ferror(f)) 147952673Seric { 148058151Seric message("451 I/O error"); 148152673Seric setstat(EX_IOERR); 148252673Seric } 14834214Seric (void) fclose(f); 14844214Seric (void) fflush(stdout); 14854417Seric 14866887Seric /* reset ISUID & ISGID bits for paranoid systems */ 14874621Seric (void) chmod(filename, (int) stb.st_mode); 148852673Seric exit(ExitStat); 14894315Seric /*NOTREACHED*/ 14904214Seric } 14914214Seric else 14924214Seric { 14934214Seric /* parent -- wait for exit status */ 14949370Seric int st; 14954214Seric 14969370Seric st = waitfor(pid); 14979370Seric if ((st & 0377) != 0) 14989370Seric return (EX_UNAVAILABLE); 14999370Seric else 15009370Seric return ((st >> 8) & 0377); 150140931Srick /*NOTREACHED*/ 15024214Seric } 1503294Seric } 15044550Seric /* 15054550Seric ** SENDALL -- actually send all the messages. 15064550Seric ** 15074550Seric ** Parameters: 15087043Seric ** e -- the envelope to send. 150914874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 151014874Seric ** the current SendMode. 15114550Seric ** 15124550Seric ** Returns: 15134550Seric ** none. 15144550Seric ** 15154550Seric ** Side Effects: 15164550Seric ** Scans the send lists and sends everything it finds. 15177043Seric ** Delivers any appropriate error messages. 15189275Seric ** If we are running in a non-interactive mode, takes the 15199275Seric ** appropriate action. 15204550Seric */ 15214550Seric 15229275Seric sendall(e, mode) 15237043Seric ENVELOPE *e; 15249275Seric char mode; 15254550Seric { 15265008Seric register ADDRESS *q; 15277779Seric bool oldverbose; 15289275Seric int pid; 152958170Seric char *owner; 153058170Seric int otherowners; 153158170Seric ENVELOPE *splitenv = NULL; 153251937Seric # ifdef LOCKF 153351937Seric struct flock lfd; 153451937Seric # endif 15354550Seric 153614874Seric /* determine actual delivery mode */ 153714874Seric if (mode == SM_DEFAULT) 153814874Seric { 153924941Seric extern bool shouldqueue(); 154014874Seric 154158146Seric mode = SendMode; 154258146Seric if (mode != SM_VERIFY && 154358146Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 154414874Seric mode = SM_QUEUE; 154514874Seric } 154614874Seric 15478248Seric if (tTd(13, 1)) 15485032Seric { 15499275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 15507043Seric printaddr(e->e_sendqueue, TRUE); 15515032Seric } 15525008Seric 15537043Seric /* 15549275Seric ** Do any preprocessing necessary for the mode we are running. 15559370Seric ** Check to make sure the hop count is reasonable. 15569370Seric ** Delete sends to the sender in mailing lists. 15577043Seric */ 15587043Seric 15599370Seric CurEnv = e; 15609370Seric 156151305Seric if (e->e_hopcount > MaxHopCount) 15629275Seric { 156340931Srick errno = 0; 156458151Seric syserr("554 too many hops %d (%d max): from %s, to %s", 156557589Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 156657589Seric e->e_sendqueue->q_paddr); 15679370Seric return; 15689370Seric } 15699275Seric 15709370Seric if (!MeToo) 15719370Seric { 157212611Seric extern ADDRESS *recipient(); 157312611Seric 15749370Seric e->e_from.q_flags |= QDONTSEND; 157557731Seric if (tTd(13, 5)) 157657731Seric { 157757731Seric printf("sendall: QDONTSEND "); 157857731Seric printaddr(&e->e_from, FALSE); 157957731Seric } 158055012Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 15819275Seric } 15829370Seric 158358170Seric /* 158458170Seric ** Handle alias owners. 158558170Seric ** 158658170Seric ** We scan up the q_alias chain looking for owners. 158758170Seric ** We discard owners that are the same as the return path. 158858170Seric */ 158958170Seric 159058170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 159158170Seric { 159258170Seric register struct address *a; 159358170Seric 159458170Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 159558170Seric continue; 159658170Seric if (a != NULL) 159758170Seric q->q_owner = a->q_owner; 159858170Seric 159958170Seric if (q->q_owner != NULL && !bitset(QDONTSEND, q->q_flags) && 160058170Seric strcmp(q->q_owner, e->e_returnpath) == 0) 160158170Seric q->q_owner = NULL; 160258170Seric } 160358170Seric 160458170Seric owner = ""; 160558170Seric otherowners = 1; 160658170Seric while (owner != NULL && otherowners > 0) 160758170Seric { 160858170Seric owner = NULL; 160958170Seric otherowners = 0; 161058170Seric 161158170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 161258170Seric { 161358170Seric if (bitset(QDONTSEND, q->q_flags)) 161458170Seric continue; 161558170Seric 161658170Seric if (q->q_owner != NULL) 161758170Seric { 161858170Seric if (owner == NULL) 161958170Seric owner = q->q_owner; 162058170Seric else if (owner != q->q_owner) 162158170Seric { 162258170Seric if (strcmp(owner, q->q_owner) == 0) 162358170Seric { 162458170Seric /* make future comparisons cheap */ 162558170Seric q->q_owner = owner; 162658170Seric } 162758170Seric else 162858170Seric { 162958170Seric otherowners++; 163058170Seric } 163158170Seric owner = q->q_owner; 163258170Seric } 163358170Seric } 163458170Seric else 163558170Seric { 163658170Seric otherowners++; 163758170Seric } 163858170Seric } 163958170Seric 164058170Seric if (owner != NULL && otherowners > 0) 164158170Seric { 164258170Seric register ENVELOPE *ee; 164358170Seric extern HDR *copyheader(); 164458170Seric extern ADDRESS *copyqueue(); 164558170Seric 164658170Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 164758170Seric STRUCTCOPY(*e, *ee); 164858170Seric ee->e_id = NULL; 164958170Seric ee->e_parent = e; 165058170Seric ee->e_header = copyheader(e->e_header); 165158170Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 165258170Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 165358170Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE); 165458170Seric ee->e_returnpath = owner; 165558170Seric ee->e_putbody = parentbody; 165658170Seric ee->e_sibling = splitenv; 165758170Seric splitenv = ee; 165858170Seric 165958170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 166058170Seric if (q->q_owner == owner) 166158170Seric q->q_flags |= QDONTSEND; 166258170Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 166358170Seric if (q->q_owner != owner) 166458170Seric q->q_flags |= QDONTSEND; 166558170Seric 166658170Seric if (e->e_df != NULL && mode != SM_VERIFY) 166758170Seric { 166858170Seric ee->e_dfp = NULL; 166958293Seric ee->e_df = newstr(queuename(ee, 'd')); 167058170Seric if (link(e->e_df, ee->e_df) < 0) 167158170Seric { 167258170Seric syserr("sendall: link(%s, %s)", 167358170Seric e->e_df, ee->e_df); 167458170Seric } 167558170Seric } 167658170Seric } 167758170Seric } 167858170Seric 167958170Seric if (owner != NULL) 168058170Seric e->e_returnpath = owner; 168158170Seric 16829370Seric # ifdef QUEUE 16839335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 16849335Seric (mode != SM_VERIFY && SuperSafe)) && 16859335Seric !bitset(EF_INQUEUE, e->e_flags)) 168651920Seric queueup(e, TRUE, mode == SM_QUEUE); 168756795Seric #endif /* QUEUE */ 16889275Seric 168958170Seric if (splitenv != NULL) 169058170Seric { 169158170Seric if (tTd(13, 1)) 169258170Seric { 169358170Seric printf("\nsendall: Split queue; remaining queue:\n"); 169458170Seric printaddr(e->e_sendqueue, TRUE); 169558170Seric } 169658170Seric 169758170Seric while (splitenv != NULL) 169858170Seric { 169958170Seric sendall(splitenv, mode); 170058170Seric splitenv = splitenv->e_sibling; 170158170Seric } 170258170Seric 170358170Seric CurEnv = e; 170458170Seric } 170558170Seric 17067779Seric oldverbose = Verbose; 17079275Seric switch (mode) 17089275Seric { 17099275Seric case SM_VERIFY: 17107779Seric Verbose = TRUE; 17119275Seric break; 17129275Seric 17139275Seric case SM_QUEUE: 171451916Seric queueonly: 17159335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 17169275Seric return; 17179275Seric 17189275Seric case SM_FORK: 17199538Seric if (e->e_xfp != NULL) 17209538Seric (void) fflush(e->e_xfp); 172151916Seric 172251916Seric # ifdef LOCKF 172351916Seric /* 172451916Seric ** Since lockf has the interesting semantic that the 172551937Seric ** lock is lost when we fork, we have to risk losing 172651937Seric ** the lock here by closing before the fork, and then 172751937Seric ** trying to get it back in the child. 172851916Seric */ 172951916Seric 173051920Seric if (e->e_lockfp != NULL) 173151916Seric { 173251920Seric (void) fclose(e->e_lockfp); 173351920Seric e->e_lockfp = NULL; 173451916Seric } 173551916Seric # endif /* LOCKF */ 173651916Seric 17379275Seric pid = fork(); 17389275Seric if (pid < 0) 17399275Seric { 174051916Seric goto queueonly; 17419275Seric } 17429275Seric else if (pid > 0) 17439293Seric { 17449293Seric /* be sure we leave the temp files to our child */ 17459335Seric e->e_id = e->e_df = NULL; 174651916Seric # ifndef LOCKF 174751920Seric if (e->e_lockfp != NULL) 174857731Seric { 174951920Seric (void) fclose(e->e_lockfp); 175057731Seric e->e_lockfp = NULL; 175157731Seric } 175251916Seric # endif 175357731Seric 175457731Seric /* close any random open files in the envelope */ 175557731Seric if (e->e_dfp != NULL) 175657731Seric { 175757731Seric (void) fclose(e->e_dfp); 175857731Seric e->e_dfp = NULL; 175957731Seric } 176057731Seric if (e->e_xfp != NULL) 176157731Seric { 176257731Seric (void) fclose(e->e_xfp); 176357731Seric e->e_xfp = NULL; 176457731Seric } 17659275Seric return; 17669293Seric } 17679275Seric 17689275Seric /* double fork to avoid zombies */ 17699275Seric if (fork() > 0) 17709275Seric exit(EX_OK); 17719275Seric 17729293Seric /* be sure we are immune from the terminal */ 177310133Seric disconnect(FALSE); 17749293Seric 177551911Seric # ifdef LOCKF 177651911Seric /* 177751916Seric ** Now try to get our lock back. 177851911Seric */ 177951911Seric 178051937Seric lfd.l_type = F_WRLCK; 178151937Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 178251920Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 178351920Seric if (e->e_lockfp == NULL || 178451937Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 178551911Seric { 178651916Seric /* oops.... lost it */ 178751911Seric # ifdef LOG 178858020Seric if (LogLevel > 29) 178951916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 179054967Seric e->e_id); 179151911Seric # endif /* LOG */ 179251916Seric exit(EX_OK); 179351911Seric } 179451911Seric # endif /* LOCKF */ 179551911Seric 179658082Seric /* 179758082Seric ** Close any cached connections. 179858082Seric ** 179958082Seric ** We don't send the QUIT protocol because the parent 180058082Seric ** still knows about the connection. 180158082Seric ** 180258082Seric ** This should only happen when delivering an error 180358082Seric ** message. 180458082Seric */ 180558082Seric 180658082Seric mci_flush(FALSE, NULL); 180758082Seric 18089275Seric break; 18099275Seric } 18109275Seric 18119275Seric /* 18129275Seric ** Run through the list and send everything. 18139275Seric */ 18149275Seric 181557589Seric e->e_nsent = 0; 18167043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 18174550Seric { 18189275Seric if (mode == SM_VERIFY) 18194550Seric { 18209293Seric e->e_to = q->q_paddr; 18215008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 182258151Seric message("deliverable"); 18234550Seric } 182447284Seric else if (!bitset(QDONTSEND, q->q_flags)) 182547284Seric { 182650533Seric # ifdef QUEUE 182747284Seric /* 182847284Seric ** Checkpoint the send list every few addresses 182947284Seric */ 183047284Seric 183157589Seric if (e->e_nsent >= CheckpointInterval) 183247284Seric { 183351920Seric queueup(e, TRUE, FALSE); 183457589Seric e->e_nsent = 0; 183547284Seric } 183650533Seric # endif /* QUEUE */ 183757589Seric (void) deliver(e, q); 183847284Seric } 18394550Seric } 18407779Seric Verbose = oldverbose; 18417043Seric 18427043Seric /* 18437043Seric ** Now run through and check for errors. 18447043Seric */ 18457043Seric 184651920Seric if (mode == SM_VERIFY) 18477043Seric return; 18487043Seric 18497043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 18507043Seric { 18518248Seric if (tTd(13, 3)) 18528248Seric { 18538248Seric printf("Checking "); 18548248Seric printaddr(q, FALSE); 18558248Seric } 18568248Seric 18579335Seric /* only send errors if the message failed */ 18589335Seric if (!bitset(QBADADDR, q->q_flags)) 18599335Seric continue; 18607043Seric 186158303Seric if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) 186258170Seric (void) sendtolist(e->e_from.q_paddr, NULL, 186358082Seric &e->e_errorqueue, e); 18647043Seric } 18659275Seric 18669275Seric if (mode == SM_FORK) 18679275Seric finis(); 18684550Seric } 186957454Seric /* 187057454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 187157454Seric ** 187257454Seric ** The signature describes how we are going to send this -- it 187357454Seric ** can be just the hostname (for non-Internet hosts) or can be 187457454Seric ** an ordered list of MX hosts. 187557454Seric ** 187657454Seric ** Parameters: 187757454Seric ** m -- the mailer describing this host. 187857454Seric ** host -- the host name. 187957454Seric ** e -- the current envelope. 188057454Seric ** 188157454Seric ** Returns: 188257454Seric ** The signature for this host. 188357454Seric ** 188457454Seric ** Side Effects: 188557454Seric ** Can tweak the symbol table. 188657454Seric */ 188757454Seric 188857454Seric char * 188957454Seric hostsignature(m, host, e) 189057454Seric register MAILER *m; 189157454Seric char *host; 189257454Seric ENVELOPE *e; 189357454Seric { 189457454Seric register char *p; 189557454Seric register STAB *s; 189657454Seric int i; 189757454Seric int len; 189857454Seric #ifdef NAMED_BIND 189957454Seric int nmx; 190057454Seric auto int rcode; 190157454Seric char *mxhosts[MAXMXHOSTS + 1]; 190257454Seric static char myhostbuf[MAXNAME]; 190357454Seric #endif 190457454Seric 190557454Seric /* 190657454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 190757454Seric */ 190857454Seric 190957454Seric p = m->m_mailer; 191057454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 191157454Seric { 191257454Seric /* just an ordinary mailer */ 191357454Seric return host; 191457454Seric } 191557454Seric 191657454Seric /* 191757454Seric ** If it is a numeric address, just return it. 191857454Seric */ 191957454Seric 192057454Seric if (host[0] == '[') 192157454Seric return host; 192257454Seric 192357454Seric /* 192457454Seric ** Look it up in the symbol table. 192557454Seric */ 192657454Seric 192757454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 192857454Seric if (s->s_hostsig != NULL) 192957454Seric return s->s_hostsig; 193057454Seric 193157454Seric /* 193257454Seric ** Not already there -- create a signature. 193357454Seric */ 193457454Seric 193557454Seric #ifdef NAMED_BIND 193657454Seric if (myhostbuf[0] == '\0') 193758050Seric expand("\201j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e); 193857454Seric 193957454Seric nmx = getmxrr(host, mxhosts, myhostbuf, &rcode); 194058664Seric 194157454Seric if (nmx <= 0) 194257454Seric { 194357454Seric register MCI *mci; 194457454Seric extern int errno; 194557454Seric extern MCI *mci_get(); 194657454Seric 194757454Seric /* update the connection info for this host */ 194857454Seric mci = mci_get(host, m); 194957454Seric mci->mci_exitstat = rcode; 195057454Seric mci->mci_errno = errno; 195157454Seric 195257454Seric /* and return the original host name as the signature */ 195357454Seric s->s_hostsig = host; 195457454Seric return host; 195557454Seric } 195657454Seric 195757454Seric len = 0; 195857454Seric for (i = 0; i < nmx; i++) 195957454Seric { 196057454Seric len += strlen(mxhosts[i]) + 1; 196157454Seric } 196257454Seric s->s_hostsig = p = xalloc(len); 196357454Seric for (i = 0; i < nmx; i++) 196457454Seric { 196557454Seric if (i != 0) 196657454Seric *p++ = ':'; 196757454Seric strcpy(p, mxhosts[i]); 196857454Seric p += strlen(p); 196957454Seric } 197057454Seric makelower(s->s_hostsig); 197157454Seric #else 197257454Seric /* not using BIND -- the signature is just the host name */ 197357454Seric s->s_hostsig = host; 197457454Seric #endif 197557454Seric if (tTd(17, 1)) 197657454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 197757454Seric return s->s_hostsig; 197857454Seric } 1979