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*58524Seric static char sccsid[] = "@(#)deliver.c 6.39 (Berkeley) 03/06/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; 78657454Seric 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; 90257529Seric char *env[2]; 90354967Seric extern int DtableSize; 90415772Seric 90554967Seric /* child -- set up input & exec mailer */ 90654967Seric /* make diagnostic output be standard output */ 90754967Seric (void) signal(SIGINT, SIG_IGN); 90854967Seric (void) signal(SIGHUP, SIG_IGN); 90954967Seric (void) signal(SIGTERM, SIG_DFL); 9104709Seric 91158082Seric /* close any other cached connections */ 91258082Seric mci_flush(FALSE, mci); 91358082Seric 91454967Seric /* arrange to filter std & diag output of command */ 91554967Seric if (clever) 91654967Seric { 91754967Seric (void) close(rpvect[0]); 91854967Seric (void) close(1); 91954967Seric (void) dup(rpvect[1]); 92054967Seric (void) close(rpvect[1]); 92154967Seric } 92254967Seric else if (OpMode == MD_SMTP || HoldErrs) 92354967Seric { 92454967Seric /* put mailer output in transcript */ 92554967Seric (void) close(1); 92654967Seric (void) dup(fileno(e->e_xfp)); 92754967Seric } 92854967Seric (void) close(2); 92954967Seric (void) dup(1); 9304709Seric 93154967Seric /* arrange to get standard input */ 93254967Seric (void) close(mpvect[1]); 93354967Seric (void) close(0); 93454967Seric if (dup(mpvect[0]) < 0) 9354417Seric { 93654967Seric syserr("Cannot dup to zero!"); 93754967Seric _exit(EX_OSERR); 9384417Seric } 93954967Seric (void) close(mpvect[0]); 94054967Seric if (!bitnset(M_RESTR, m->m_flags)) 9414415Seric { 94254967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 94354967Seric { 94454967Seric (void) setgid(DefGid); 94554967Seric (void) initgroups(DefUser, DefGid); 94654967Seric (void) setuid(DefUid); 94754967Seric } 94854967Seric else 94954967Seric { 95054967Seric (void) setgid(ctladdr->q_gid); 95154967Seric (void) initgroups(ctladdr->q_ruser? 95254967Seric ctladdr->q_ruser: ctladdr->q_user, 95354967Seric ctladdr->q_gid); 95454967Seric (void) setuid(ctladdr->q_uid); 95554967Seric } 9564415Seric } 9579370Seric 95854967Seric /* arrange for all the files to be closed */ 95954967Seric for (i = 3; i < DtableSize; i++) 96054967Seric { 96154967Seric register int j; 96254967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 96354967Seric (void)fcntl(i, F_SETFD, j|1); 96454967Seric } 9652774Seric 96654967Seric /* try to execute the mailer */ 96757529Seric env[0] = "AGENT=sendmail"; 96857529Seric env[1] = NULL; 96957529Seric execve(m->m_mailer, pvp, env); 97056678Seric saveerrno = errno; 97154967Seric syserr("Cannot exec %s", m->m_mailer); 97254967Seric if (m == LocalMailer) 97354967Seric _exit(EX_TEMPFAIL); 97456678Seric switch (saveerrno) 97554967Seric { 97654967Seric case EIO: 97754967Seric case EAGAIN: 97854967Seric case ENOMEM: 97951835Seric # ifdef EPROCLIM 98054967Seric case EPROCLIM: 98151835Seric # endif 98258108Seric # ifdef ETIMEDOUT 98358108Seric case ETIMEDOUT: 98458108Seric # endif 98554967Seric _exit(EX_TEMPFAIL); 98654967Seric } 98754967Seric _exit(EX_UNAVAILABLE); 98851835Seric } 98954967Seric 99054967Seric /* 99154967Seric ** Set up return value. 99254967Seric */ 99354967Seric 99454967Seric mci = (MCI *) xalloc(sizeof *mci); 99554993Seric bzero((char *) mci, sizeof *mci); 99654967Seric mci->mci_mailer = m; 99754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 99854993Seric mci->mci_pid = pid; 99954967Seric (void) close(mpvect[0]); 100054967Seric mci->mci_out = fdopen(mpvect[1], "w"); 100154967Seric if (clever) 100254967Seric { 100354967Seric (void) close(rpvect[1]); 100454967Seric mci->mci_in = fdopen(rpvect[0], "r"); 100554967Seric } 100654967Seric else 100754967Seric { 100854967Seric mci->mci_flags |= MCIF_TEMP; 100954967Seric mci->mci_in = NULL; 101054967Seric } 1011294Seric } 1012294Seric 10134709Seric /* 101454967Seric ** If we are in SMTP opening state, send initial protocol. 10154709Seric */ 10164709Seric 101754967Seric if (clever && mci->mci_state != MCIS_CLOSED) 10184863Seric { 101954967Seric smtpinit(m, mci, e); 102053738Seric } 102157387Seric if (tTd(11, 1)) 102257387Seric { 102357387Seric printf("openmailer: "); 102457387Seric mci_dump(mci); 102557387Seric } 1026294Seric 102753738Seric return mci; 1028294Seric } 1029294Seric /* 1030294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1031294Seric ** 1032294Seric ** Parameters: 1033294Seric ** stat -- the status code from the mailer (high byte 1034294Seric ** only; core dumps must have been taken care of 1035294Seric ** already). 103658337Seric ** m -- the mailer info for this mailer. 103758337Seric ** mci -- the mailer connection info -- can be NULL if the 103858337Seric ** response is given before the connection is made. 103958337Seric ** e -- the current envelope. 1040294Seric ** 1041294Seric ** Returns: 10424082Seric ** none. 1043294Seric ** 1044294Seric ** Side Effects: 10451518Seric ** Errors may be incremented. 1046294Seric ** ExitStat may be set. 1047294Seric */ 1048294Seric 104958337Seric giveresponse(stat, m, mci, e) 1050294Seric int stat; 10519370Seric register MAILER *m; 105258337Seric register MCI *mci; 105310105Seric ENVELOPE *e; 1054294Seric { 1055294Seric register char *statmsg; 1056294Seric extern char *SysExMsg[]; 1057294Seric register int i; 105836788Sbostic extern int N_SysEx; 105936788Sbostic #ifdef NAMED_BIND 106036788Sbostic extern int h_errno; 106136788Sbostic #endif 106210105Seric char buf[MAXLINE]; 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 { 107910124Seric (void) strcpy(buf, SysExMsg[i]); 108036788Sbostic #ifdef NAMED_BIND 108125527Smiriam if (h_errno == TRY_AGAIN) 108210105Seric { 108315137Seric extern char *errstring(); 108415137Seric 108525527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 108621061Seric } 108721061Seric else 108836788Sbostic #endif 108921061Seric { 109025527Smiriam if (errno != 0) 109125527Smiriam { 109225527Smiriam extern char *errstring(); 109325527Smiriam 109425527Smiriam statmsg = errstring(errno); 109525527Smiriam } 109625527Smiriam else 109725527Smiriam { 109821061Seric #ifdef SMTP 109925527Smiriam extern char SmtpError[]; 110021061Seric 110125527Smiriam statmsg = SmtpError; 110256795Seric #else /* SMTP */ 110325527Smiriam statmsg = NULL; 110456795Seric #endif /* SMTP */ 110525527Smiriam } 110621061Seric } 110721061Seric if (statmsg != NULL && statmsg[0] != '\0') 110821061Seric { 110910124Seric (void) strcat(buf, ": "); 111021061Seric (void) strcat(buf, statmsg); 111110105Seric } 111210105Seric statmsg = buf; 111310105Seric } 1114294Seric else 111521061Seric { 1116294Seric statmsg = SysExMsg[i]; 111721061Seric } 11189370Seric 11199370Seric /* 11209370Seric ** Print the message as appropriate 11219370Seric */ 11229370Seric 112310105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1124*58524Seric message(&statmsg[4], errstring(errno)); 1125294Seric else 1126294Seric { 11271518Seric Errors++; 1128*58524Seric usrerr(statmsg, errstring(errno)); 1129294Seric } 1130294Seric 1131294Seric /* 1132294Seric ** Final cleanup. 1133294Seric ** Log a record of the transaction. Compute the new 1134294Seric ** ExitStat -- if we already had an error, stick with 1135294Seric ** that. 1136294Seric */ 1137294Seric 113858020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 113958337Seric logdelivery(m, mci, &statmsg[4], e); 11407858Seric 11414621Seric if (stat != EX_TEMPFAIL) 11424621Seric setstat(stat); 114310105Seric if (stat != EX_OK) 114410105Seric { 114510105Seric if (e->e_message != NULL) 114610105Seric free(e->e_message); 114710105Seric e->e_message = newstr(&statmsg[4]); 114810105Seric } 114910124Seric errno = 0; 115036788Sbostic #ifdef NAMED_BIND 115125527Smiriam h_errno = 0; 115236788Sbostic #endif 1153294Seric } 1154294Seric /* 11558496Seric ** LOGDELIVERY -- log the delivery in the system log 11568496Seric ** 11578496Seric ** Parameters: 115858337Seric ** m -- the mailer info. Can be NULL for initial queue. 115958337Seric ** mci -- the mailer connection info -- can be NULL if the 116058337Seric ** log is occuring when no connection is active. 116158337Seric ** stat -- the message to print for the status. 116258337Seric ** e -- the current envelope. 11638496Seric ** 11648496Seric ** Returns: 11658496Seric ** none 11668496Seric ** 11678496Seric ** Side Effects: 11688496Seric ** none 11698496Seric */ 11708496Seric 117158337Seric logdelivery(m, mci, stat, e) 117258337Seric MAILER *m; 117358337Seric register MCI *mci; 11748496Seric char *stat; 117554967Seric register ENVELOPE *e; 11768496Seric { 117758343Seric # ifdef LOG 117858337Seric char *curhost; 117958418Seric char buf[512]; 11808496Seric extern char *pintvl(); 118158343Seric extern char *macvalue(); 11828496Seric 118358513Seric (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 118458337Seric 118558513Seric if (m != NULL) 118658305Seric { 118758513Seric (void) strcat(buf, ", mailer="); 118858513Seric (void) strcat(buf, m->m_name); 118958305Seric } 119058513Seric 119158513Seric if (mci != NULL && mci->mci_host != NULL) 119258305Seric { 119358305Seric # ifdef DAEMON 119458343Seric extern struct sockaddr_in CurHostAddr; 119558343Seric extern char *inet_ntoa(); 119658513Seric # endif 119758305Seric 119858513Seric (void) strcat(buf, ", relay="); 119958513Seric (void) strcat(buf, mci->mci_host); 120058513Seric 120158513Seric # ifdef DAEMON 120258513Seric (void) strcat(buf, " ("); 120358513Seric (void) strcat(buf, inet_ntoa(CurHostAddr.sin_addr)); 120458513Seric (void) strcat(buf, ")"); 120558305Seric # endif 120658305Seric } 120758343Seric else 120858513Seric { 120958513Seric char *p = macvalue('h', e); 121058343Seric 121158513Seric if (p != NULL && p[0] != '\0') 121258513Seric { 121358513Seric (void) strcat(buf, ", relay="); 121458513Seric (void) strcat(buf, p); 121558513Seric } 121658513Seric } 121758418Seric 121858418Seric syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", 121958418Seric e->e_id, e->e_to, buf, stat); 122056795Seric # endif /* LOG */ 12218496Seric } 12228496Seric /* 12236974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1224294Seric ** 12256974Seric ** This can be made an arbitrary message separator by changing $l 1226294Seric ** 122716150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 122816150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 122916150Seric ** does a well-meaning programmer such as myself have to deal with 123016150Seric ** this kind of antique garbage???? 12316974Seric ** 1232294Seric ** Parameters: 12336974Seric ** fp -- the file to output to. 12346974Seric ** m -- the mailer describing this entry. 1235294Seric ** 1236294Seric ** Returns: 12376974Seric ** none 1238294Seric ** 1239294Seric ** Side Effects: 12406974Seric ** outputs some text to fp. 1241294Seric */ 1242294Seric 124354967Seric putfromline(fp, m, e) 12446974Seric register FILE *fp; 12456974Seric register MAILER *m; 124654967Seric ENVELOPE *e; 1247294Seric { 124858050Seric char *template = "\201l\n"; 12496974Seric char buf[MAXLINE]; 1250294Seric 125110682Seric if (bitnset(M_NHDR, m->m_flags)) 12526974Seric return; 12534315Seric 12546974Seric # ifdef UGLYUUCP 125510682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 12564205Seric { 125712223Seric char *bang; 125812223Seric char xbuf[MAXLINE]; 12596041Seric 126058050Seric expand("\201<", buf, &buf[sizeof buf - 1], e); 126156795Seric bang = strchr(buf, '!'); 12626974Seric if (bang == NULL) 126358151Seric syserr("554 No ! in UUCP! (%s)", buf); 12645099Seric else 12659370Seric { 126612223Seric *bang++ = '\0'; 126758050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 126812223Seric template = xbuf; 12699370Seric } 12706974Seric } 127156795Seric # endif /* UGLYUUCP */ 127254967Seric expand(template, buf, &buf[sizeof buf - 1], e); 127310168Seric putline(buf, fp, m); 12745981Seric } 12755981Seric /* 12766974Seric ** PUTBODY -- put the body of a message. 12776974Seric ** 12786974Seric ** Parameters: 12796974Seric ** fp -- file to output onto. 128010168Seric ** m -- a mailer descriptor to control output format. 12819538Seric ** e -- the envelope to put out. 12826974Seric ** 12836974Seric ** Returns: 12846974Seric ** none. 12856974Seric ** 12866974Seric ** Side Effects: 12876974Seric ** The message is written onto fp. 12886974Seric */ 12896974Seric 129010168Seric putbody(fp, m, e) 12916974Seric FILE *fp; 12929370Seric MAILER *m; 12939538Seric register ENVELOPE *e; 12946974Seric { 129510168Seric char buf[MAXLINE]; 12966974Seric 12976974Seric /* 12986974Seric ** Output the body of the message 12996974Seric */ 13006974Seric 13019538Seric if (e->e_dfp == NULL) 13026974Seric { 13039538Seric if (e->e_df != NULL) 13049538Seric { 13059538Seric e->e_dfp = fopen(e->e_df, "r"); 13069538Seric if (e->e_dfp == NULL) 130740931Srick syserr("putbody: Cannot open %s for %s from %s", 130840931Srick e->e_df, e->e_to, e->e_from); 13099538Seric } 13109538Seric else 131110168Seric putline("<<< No Message Collected >>>", fp, m); 13129538Seric } 13139538Seric if (e->e_dfp != NULL) 13149538Seric { 13159538Seric rewind(e->e_dfp); 131610168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 131716875Seric { 131816875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 131940995Sbostic strncmp(buf, "From ", 5) == 0) 132023102Seric (void) putc('>', fp); 132110168Seric putline(buf, fp, m); 132216875Seric } 13236974Seric 13249538Seric if (ferror(e->e_dfp)) 13256974Seric { 13266974Seric syserr("putbody: read error"); 13276974Seric ExitStat = EX_IOERR; 13286974Seric } 13296974Seric } 13306974Seric 13316974Seric (void) fflush(fp); 13326974Seric if (ferror(fp) && errno != EPIPE) 13336974Seric { 13346974Seric syserr("putbody: write error"); 13356974Seric ExitStat = EX_IOERR; 13366974Seric } 13376974Seric errno = 0; 13386974Seric } 13396974Seric /* 134058170Seric ** PARENTBODY -- put the body of the parent of a message. 134158170Seric ** 134258170Seric ** Parameters: 134358170Seric ** fp -- file to output onto. 134458170Seric ** m -- a mailer descriptor to control output format. 134558170Seric ** e -- the envelope whose parent to put out. 134658170Seric ** 134758170Seric ** Returns: 134858170Seric ** none. 134958170Seric ** 135058170Seric ** Side Effects: 135158170Seric ** The message is written onto fp. 135258170Seric */ 135358170Seric 135458170Seric parentbody(fp, m, e) 135558170Seric FILE *fp; 135658170Seric MAILER *m; 135758170Seric register ENVELOPE *e; 135858170Seric { 135958170Seric putbody(fp, m, e->e_parent); 136058170Seric } 136158170Seric /* 1362294Seric ** MAILFILE -- Send a message to a file. 1363294Seric ** 13644327Seric ** If the file has the setuid/setgid bits set, but NO execute 13654327Seric ** bits, sendmail will try to become the owner of that file 13664327Seric ** rather than the real user. Obviously, this only works if 13674327Seric ** sendmail runs as root. 13684327Seric ** 13699370Seric ** This could be done as a subordinate mailer, except that it 13709370Seric ** is used implicitly to save messages in ~/dead.letter. We 13719370Seric ** view this as being sufficiently important as to include it 13729370Seric ** here. For example, if the system is dying, we shouldn't have 13739370Seric ** to create another process plus some pipes to save the message. 13749370Seric ** 1375294Seric ** Parameters: 1376294Seric ** filename -- the name of the file to send to. 13774397Seric ** ctladdr -- the controlling address header -- includes 13784397Seric ** the userid/groupid to be when sending. 1379294Seric ** 1380294Seric ** Returns: 1381294Seric ** The exit code associated with the operation. 1382294Seric ** 1383294Seric ** Side Effects: 1384294Seric ** none. 1385294Seric */ 1386294Seric 138754967Seric mailfile(filename, ctladdr, e) 1388294Seric char *filename; 13894397Seric ADDRESS *ctladdr; 139054967Seric register ENVELOPE *e; 1391294Seric { 1392294Seric register FILE *f; 13934214Seric register int pid; 139453751Seric int mode; 1395294Seric 13964214Seric /* 13974214Seric ** Fork so we can change permissions here. 13984214Seric ** Note that we MUST use fork, not vfork, because of 13994214Seric ** the complications of calling subroutines, etc. 14004214Seric */ 14014067Seric 14024214Seric DOFORK(fork); 14034214Seric 14044214Seric if (pid < 0) 14054214Seric return (EX_OSERR); 14064214Seric else if (pid == 0) 14074214Seric { 14084214Seric /* child -- actually write to file */ 14094327Seric struct stat stb; 14104327Seric 14114215Seric (void) signal(SIGINT, SIG_DFL); 14124215Seric (void) signal(SIGHUP, SIG_DFL); 14134215Seric (void) signal(SIGTERM, SIG_DFL); 141423102Seric (void) umask(OldUmask); 141552673Seric 14164327Seric if (stat(filename, &stb) < 0) 14174431Seric stb.st_mode = 0666; 141853751Seric mode = stb.st_mode; 141952673Seric 142052673Seric /* limit the errors to those actually caused in the child */ 142152673Seric errno = 0; 142252673Seric ExitStat = EX_OK; 142352673Seric 14244327Seric if (bitset(0111, stb.st_mode)) 14254327Seric exit(EX_CANTCREAT); 14264401Seric if (ctladdr == NULL) 142740931Srick ctladdr = &e->e_from; 142853751Seric else 142953751Seric { 143053751Seric /* ignore setuid and setgid bits */ 143153751Seric mode &= ~(S_ISGID|S_ISUID); 143253751Seric } 143353751Seric 143440931Srick /* we have to open the dfile BEFORE setuid */ 143553751Seric if (e->e_dfp == NULL && e->e_df != NULL) 143640931Srick { 143740931Srick e->e_dfp = fopen(e->e_df, "r"); 143852673Seric if (e->e_dfp == NULL) 143952673Seric { 144040931Srick syserr("mailfile: Cannot open %s for %s from %s", 144153751Seric e->e_df, e->e_to, e->e_from); 144240931Srick } 144340931Srick } 144440931Srick 144553751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 14464417Seric { 144752673Seric if (ctladdr->q_uid == 0) 144852673Seric { 14494417Seric (void) setgid(DefGid); 145040972Sbostic (void) initgroups(DefUser, DefGid); 145152673Seric } 145252673Seric else 145352673Seric { 14544417Seric (void) setgid(ctladdr->q_gid); 145553751Seric (void) initgroups(ctladdr->q_ruser ? 145653751Seric ctladdr->q_ruser : ctladdr->q_user, 145740972Sbostic ctladdr->q_gid); 145840972Sbostic } 14594417Seric } 146053751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 14614417Seric { 14624417Seric if (ctladdr->q_uid == 0) 14634417Seric (void) setuid(DefUid); 14644417Seric else 14654417Seric (void) setuid(ctladdr->q_uid); 14664417Seric } 146752673Seric FileName = filename; 146852673Seric LineNumber = 0; 14696887Seric f = dfopen(filename, "a"); 14704214Seric if (f == NULL) 147152673Seric { 147258151Seric message("554 cannot open"); 14734214Seric exit(EX_CANTCREAT); 147452673Seric } 14754214Seric 147654967Seric putfromline(f, ProgMailer, e); 147755012Seric (*e->e_puthdr)(f, ProgMailer, e); 147810168Seric putline("\n", f, ProgMailer); 147955012Seric (*e->e_putbody)(f, ProgMailer, e); 148010168Seric putline("\n", f, ProgMailer); 148152673Seric if (ferror(f)) 148252673Seric { 148358151Seric message("451 I/O error"); 148452673Seric setstat(EX_IOERR); 148552673Seric } 14864214Seric (void) fclose(f); 14874214Seric (void) fflush(stdout); 14884417Seric 14896887Seric /* reset ISUID & ISGID bits for paranoid systems */ 14904621Seric (void) chmod(filename, (int) stb.st_mode); 149152673Seric exit(ExitStat); 14924315Seric /*NOTREACHED*/ 14934214Seric } 14944214Seric else 14954214Seric { 14964214Seric /* parent -- wait for exit status */ 14979370Seric int st; 14984214Seric 14999370Seric st = waitfor(pid); 15009370Seric if ((st & 0377) != 0) 15019370Seric return (EX_UNAVAILABLE); 15029370Seric else 15039370Seric return ((st >> 8) & 0377); 150440931Srick /*NOTREACHED*/ 15054214Seric } 1506294Seric } 15074550Seric /* 15084550Seric ** SENDALL -- actually send all the messages. 15094550Seric ** 15104550Seric ** Parameters: 15117043Seric ** e -- the envelope to send. 151214874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 151314874Seric ** the current SendMode. 15144550Seric ** 15154550Seric ** Returns: 15164550Seric ** none. 15174550Seric ** 15184550Seric ** Side Effects: 15194550Seric ** Scans the send lists and sends everything it finds. 15207043Seric ** Delivers any appropriate error messages. 15219275Seric ** If we are running in a non-interactive mode, takes the 15229275Seric ** appropriate action. 15234550Seric */ 15244550Seric 15259275Seric sendall(e, mode) 15267043Seric ENVELOPE *e; 15279275Seric char mode; 15284550Seric { 15295008Seric register ADDRESS *q; 15307779Seric bool oldverbose; 15319275Seric int pid; 153258170Seric char *owner; 153358170Seric int otherowners; 153458170Seric ENVELOPE *splitenv = NULL; 153551937Seric # ifdef LOCKF 153651937Seric struct flock lfd; 153751937Seric # endif 15384550Seric 153914874Seric /* determine actual delivery mode */ 154014874Seric if (mode == SM_DEFAULT) 154114874Seric { 154224941Seric extern bool shouldqueue(); 154314874Seric 154458146Seric mode = SendMode; 154558146Seric if (mode != SM_VERIFY && 154658146Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 154714874Seric mode = SM_QUEUE; 154814874Seric } 154914874Seric 15508248Seric if (tTd(13, 1)) 15515032Seric { 15529275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 15537043Seric printaddr(e->e_sendqueue, TRUE); 15545032Seric } 15555008Seric 15567043Seric /* 15579275Seric ** Do any preprocessing necessary for the mode we are running. 15589370Seric ** Check to make sure the hop count is reasonable. 15599370Seric ** Delete sends to the sender in mailing lists. 15607043Seric */ 15617043Seric 15629370Seric CurEnv = e; 15639370Seric 156451305Seric if (e->e_hopcount > MaxHopCount) 15659275Seric { 156640931Srick errno = 0; 156758151Seric syserr("554 too many hops %d (%d max): from %s, to %s", 156857589Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 156957589Seric e->e_sendqueue->q_paddr); 15709370Seric return; 15719370Seric } 15729275Seric 15739370Seric if (!MeToo) 15749370Seric { 157512611Seric extern ADDRESS *recipient(); 157612611Seric 15779370Seric e->e_from.q_flags |= QDONTSEND; 157857731Seric if (tTd(13, 5)) 157957731Seric { 158057731Seric printf("sendall: QDONTSEND "); 158157731Seric printaddr(&e->e_from, FALSE); 158257731Seric } 158355012Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 15849275Seric } 15859370Seric 158658170Seric /* 158758170Seric ** Handle alias owners. 158858170Seric ** 158958170Seric ** We scan up the q_alias chain looking for owners. 159058170Seric ** We discard owners that are the same as the return path. 159158170Seric */ 159258170Seric 159358170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 159458170Seric { 159558170Seric register struct address *a; 159658170Seric 159758170Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 159858170Seric continue; 159958170Seric if (a != NULL) 160058170Seric q->q_owner = a->q_owner; 160158170Seric 160258170Seric if (q->q_owner != NULL && !bitset(QDONTSEND, q->q_flags) && 160358170Seric strcmp(q->q_owner, e->e_returnpath) == 0) 160458170Seric q->q_owner = NULL; 160558170Seric } 160658170Seric 160758170Seric owner = ""; 160858170Seric otherowners = 1; 160958170Seric while (owner != NULL && otherowners > 0) 161058170Seric { 161158170Seric owner = NULL; 161258170Seric otherowners = 0; 161358170Seric 161458170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 161558170Seric { 161658170Seric if (bitset(QDONTSEND, q->q_flags)) 161758170Seric continue; 161858170Seric 161958170Seric if (q->q_owner != NULL) 162058170Seric { 162158170Seric if (owner == NULL) 162258170Seric owner = q->q_owner; 162358170Seric else if (owner != q->q_owner) 162458170Seric { 162558170Seric if (strcmp(owner, q->q_owner) == 0) 162658170Seric { 162758170Seric /* make future comparisons cheap */ 162858170Seric q->q_owner = owner; 162958170Seric } 163058170Seric else 163158170Seric { 163258170Seric otherowners++; 163358170Seric } 163458170Seric owner = q->q_owner; 163558170Seric } 163658170Seric } 163758170Seric else 163858170Seric { 163958170Seric otherowners++; 164058170Seric } 164158170Seric } 164258170Seric 164358170Seric if (owner != NULL && otherowners > 0) 164458170Seric { 164558170Seric register ENVELOPE *ee; 164658170Seric extern HDR *copyheader(); 164758170Seric extern ADDRESS *copyqueue(); 164858170Seric 164958170Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 165058170Seric STRUCTCOPY(*e, *ee); 165158170Seric ee->e_id = NULL; 165258170Seric ee->e_parent = e; 165358170Seric ee->e_header = copyheader(e->e_header); 165458170Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 165558170Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 165658170Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE); 165758170Seric ee->e_returnpath = owner; 165858170Seric ee->e_putbody = parentbody; 165958170Seric ee->e_sibling = splitenv; 166058170Seric splitenv = ee; 166158170Seric 166258170Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 166358170Seric if (q->q_owner == owner) 166458170Seric q->q_flags |= QDONTSEND; 166558170Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 166658170Seric if (q->q_owner != owner) 166758170Seric q->q_flags |= QDONTSEND; 166858170Seric 166958170Seric if (e->e_df != NULL && mode != SM_VERIFY) 167058170Seric { 167158170Seric ee->e_dfp = NULL; 167258293Seric ee->e_df = newstr(queuename(ee, 'd')); 167358170Seric if (link(e->e_df, ee->e_df) < 0) 167458170Seric { 167558170Seric syserr("sendall: link(%s, %s)", 167658170Seric e->e_df, ee->e_df); 167758170Seric } 167858170Seric } 167958170Seric } 168058170Seric } 168158170Seric 168258170Seric if (owner != NULL) 168358170Seric e->e_returnpath = owner; 168458170Seric 16859370Seric # ifdef QUEUE 16869335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 16879335Seric (mode != SM_VERIFY && SuperSafe)) && 16889335Seric !bitset(EF_INQUEUE, e->e_flags)) 168951920Seric queueup(e, TRUE, mode == SM_QUEUE); 169056795Seric #endif /* QUEUE */ 16919275Seric 169258170Seric if (splitenv != NULL) 169358170Seric { 169458170Seric if (tTd(13, 1)) 169558170Seric { 169658170Seric printf("\nsendall: Split queue; remaining queue:\n"); 169758170Seric printaddr(e->e_sendqueue, TRUE); 169858170Seric } 169958170Seric 170058170Seric while (splitenv != NULL) 170158170Seric { 170258170Seric sendall(splitenv, mode); 170358170Seric splitenv = splitenv->e_sibling; 170458170Seric } 170558170Seric 170658170Seric CurEnv = e; 170758170Seric } 170858170Seric 17097779Seric oldverbose = Verbose; 17109275Seric switch (mode) 17119275Seric { 17129275Seric case SM_VERIFY: 17137779Seric Verbose = TRUE; 17149275Seric break; 17159275Seric 17169275Seric case SM_QUEUE: 171751916Seric queueonly: 17189335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 17199275Seric return; 17209275Seric 17219275Seric case SM_FORK: 17229538Seric if (e->e_xfp != NULL) 17239538Seric (void) fflush(e->e_xfp); 172451916Seric 172551916Seric # ifdef LOCKF 172651916Seric /* 172751916Seric ** Since lockf has the interesting semantic that the 172851937Seric ** lock is lost when we fork, we have to risk losing 172951937Seric ** the lock here by closing before the fork, and then 173051937Seric ** trying to get it back in the child. 173151916Seric */ 173251916Seric 173351920Seric if (e->e_lockfp != NULL) 173451916Seric { 173551920Seric (void) fclose(e->e_lockfp); 173651920Seric e->e_lockfp = NULL; 173751916Seric } 173851916Seric # endif /* LOCKF */ 173951916Seric 17409275Seric pid = fork(); 17419275Seric if (pid < 0) 17429275Seric { 174351916Seric goto queueonly; 17449275Seric } 17459275Seric else if (pid > 0) 17469293Seric { 17479293Seric /* be sure we leave the temp files to our child */ 17489335Seric e->e_id = e->e_df = NULL; 174951916Seric # ifndef LOCKF 175051920Seric if (e->e_lockfp != NULL) 175157731Seric { 175251920Seric (void) fclose(e->e_lockfp); 175357731Seric e->e_lockfp = NULL; 175457731Seric } 175551916Seric # endif 175657731Seric 175757731Seric /* close any random open files in the envelope */ 175857731Seric if (e->e_dfp != NULL) 175957731Seric { 176057731Seric (void) fclose(e->e_dfp); 176157731Seric e->e_dfp = NULL; 176257731Seric } 176357731Seric if (e->e_xfp != NULL) 176457731Seric { 176557731Seric (void) fclose(e->e_xfp); 176657731Seric e->e_xfp = NULL; 176757731Seric } 17689275Seric return; 17699293Seric } 17709275Seric 17719275Seric /* double fork to avoid zombies */ 17729275Seric if (fork() > 0) 17739275Seric exit(EX_OK); 17749275Seric 17759293Seric /* be sure we are immune from the terminal */ 177610133Seric disconnect(FALSE); 17779293Seric 177851911Seric # ifdef LOCKF 177951911Seric /* 178051916Seric ** Now try to get our lock back. 178151911Seric */ 178251911Seric 178351937Seric lfd.l_type = F_WRLCK; 178451937Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 178551920Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 178651920Seric if (e->e_lockfp == NULL || 178751937Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 178851911Seric { 178951916Seric /* oops.... lost it */ 179051911Seric # ifdef LOG 179158020Seric if (LogLevel > 29) 179251916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 179354967Seric e->e_id); 179451911Seric # endif /* LOG */ 179551916Seric exit(EX_OK); 179651911Seric } 179751911Seric # endif /* LOCKF */ 179851911Seric 179958082Seric /* 180058082Seric ** Close any cached connections. 180158082Seric ** 180258082Seric ** We don't send the QUIT protocol because the parent 180358082Seric ** still knows about the connection. 180458082Seric ** 180558082Seric ** This should only happen when delivering an error 180658082Seric ** message. 180758082Seric */ 180858082Seric 180958082Seric mci_flush(FALSE, NULL); 181058082Seric 18119275Seric break; 18129275Seric } 18139275Seric 18149275Seric /* 18159275Seric ** Run through the list and send everything. 18169275Seric */ 18179275Seric 181857589Seric e->e_nsent = 0; 18197043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 18204550Seric { 18219275Seric if (mode == SM_VERIFY) 18224550Seric { 18239293Seric e->e_to = q->q_paddr; 18245008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 182558151Seric message("deliverable"); 18264550Seric } 182747284Seric else if (!bitset(QDONTSEND, q->q_flags)) 182847284Seric { 182950533Seric # ifdef QUEUE 183047284Seric /* 183147284Seric ** Checkpoint the send list every few addresses 183247284Seric */ 183347284Seric 183457589Seric if (e->e_nsent >= CheckpointInterval) 183547284Seric { 183651920Seric queueup(e, TRUE, FALSE); 183757589Seric e->e_nsent = 0; 183847284Seric } 183950533Seric # endif /* QUEUE */ 184057589Seric (void) deliver(e, q); 184147284Seric } 18424550Seric } 18437779Seric Verbose = oldverbose; 18447043Seric 18457043Seric /* 18467043Seric ** Now run through and check for errors. 18477043Seric */ 18487043Seric 184951920Seric if (mode == SM_VERIFY) 18507043Seric return; 18517043Seric 18527043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 18537043Seric { 18548248Seric if (tTd(13, 3)) 18558248Seric { 18568248Seric printf("Checking "); 18578248Seric printaddr(q, FALSE); 18588248Seric } 18598248Seric 18609335Seric /* only send errors if the message failed */ 18619335Seric if (!bitset(QBADADDR, q->q_flags)) 18629335Seric continue; 18637043Seric 186458303Seric if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) 186558170Seric (void) sendtolist(e->e_from.q_paddr, NULL, 186658082Seric &e->e_errorqueue, e); 18677043Seric } 18689275Seric 18699275Seric if (mode == SM_FORK) 18709275Seric finis(); 18714550Seric } 187257454Seric /* 187357454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 187457454Seric ** 187557454Seric ** The signature describes how we are going to send this -- it 187657454Seric ** can be just the hostname (for non-Internet hosts) or can be 187757454Seric ** an ordered list of MX hosts. 187857454Seric ** 187957454Seric ** Parameters: 188057454Seric ** m -- the mailer describing this host. 188157454Seric ** host -- the host name. 188257454Seric ** e -- the current envelope. 188357454Seric ** 188457454Seric ** Returns: 188557454Seric ** The signature for this host. 188657454Seric ** 188757454Seric ** Side Effects: 188857454Seric ** Can tweak the symbol table. 188957454Seric */ 189057454Seric 189157454Seric char * 189257454Seric hostsignature(m, host, e) 189357454Seric register MAILER *m; 189457454Seric char *host; 189557454Seric ENVELOPE *e; 189657454Seric { 189757454Seric register char *p; 189857454Seric register STAB *s; 189957454Seric int i; 190057454Seric int len; 190157454Seric #ifdef NAMED_BIND 190257454Seric int nmx; 190357454Seric auto int rcode; 190457454Seric char *mxhosts[MAXMXHOSTS + 1]; 190557454Seric static char myhostbuf[MAXNAME]; 190657454Seric #endif 190757454Seric 190857454Seric /* 190957454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 191057454Seric */ 191157454Seric 191257454Seric p = m->m_mailer; 191357454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 191457454Seric { 191557454Seric /* just an ordinary mailer */ 191657454Seric return host; 191757454Seric } 191857454Seric 191957454Seric /* 192057454Seric ** If it is a numeric address, just return it. 192157454Seric */ 192257454Seric 192357454Seric if (host[0] == '[') 192457454Seric return host; 192557454Seric 192657454Seric /* 192757454Seric ** Look it up in the symbol table. 192857454Seric */ 192957454Seric 193057454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 193157454Seric if (s->s_hostsig != NULL) 193257454Seric return s->s_hostsig; 193357454Seric 193457454Seric /* 193557454Seric ** Not already there -- create a signature. 193657454Seric */ 193757454Seric 193857454Seric #ifdef NAMED_BIND 193957454Seric if (myhostbuf[0] == '\0') 194058050Seric expand("\201j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e); 194157454Seric 194257454Seric nmx = getmxrr(host, mxhosts, myhostbuf, &rcode); 194357454Seric if (nmx <= 0) 194457454Seric { 194557454Seric register MCI *mci; 194657454Seric extern int errno; 194757454Seric extern MCI *mci_get(); 194857454Seric 194957454Seric /* update the connection info for this host */ 195057454Seric mci = mci_get(host, m); 195157454Seric mci->mci_exitstat = rcode; 195257454Seric mci->mci_errno = errno; 195357454Seric 195457454Seric /* and return the original host name as the signature */ 195557454Seric s->s_hostsig = host; 195657454Seric return host; 195757454Seric } 195857454Seric 195957454Seric len = 0; 196057454Seric for (i = 0; i < nmx; i++) 196157454Seric { 196257454Seric len += strlen(mxhosts[i]) + 1; 196357454Seric } 196457454Seric s->s_hostsig = p = xalloc(len); 196557454Seric for (i = 0; i < nmx; i++) 196657454Seric { 196757454Seric if (i != 0) 196857454Seric *p++ = ':'; 196957454Seric strcpy(p, mxhosts[i]); 197057454Seric p += strlen(p); 197157454Seric } 197257454Seric makelower(s->s_hostsig); 197357454Seric #else 197457454Seric /* not using BIND -- the signature is just the host name */ 197557454Seric s->s_hostsig = host; 197657454Seric #endif 197757454Seric if (tTd(17, 1)) 197857454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 197957454Seric return s->s_hostsig; 198057454Seric } 1981