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*60008Seric static char sccsid[] = "@(#)deliver.c 6.75 (Berkeley) 05/14/93"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1458153Seric #include <signal.h> 1533931Sbostic #include <netdb.h> 1633931Sbostic #include <errno.h> 1735651Seric #ifdef NAMED_BIND 1834022Sbostic #include <arpa/nameser.h> 1934022Sbostic #include <resolv.h> 2035651Seric #endif 21294Seric 22294Seric /* 2358820Seric ** SENDALL -- actually send all the messages. 2458820Seric ** 2558820Seric ** Parameters: 2658820Seric ** e -- the envelope to send. 2758820Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 2858820Seric ** the current e->e_sendmode. 2958820Seric ** 3058820Seric ** Returns: 3158820Seric ** none. 3258820Seric ** 3358820Seric ** Side Effects: 3458820Seric ** Scans the send lists and sends everything it finds. 3558820Seric ** Delivers any appropriate error messages. 3658820Seric ** If we are running in a non-interactive mode, takes the 3758820Seric ** appropriate action. 3858820Seric */ 3958820Seric 4058820Seric sendall(e, mode) 4158820Seric ENVELOPE *e; 4258820Seric char mode; 4358820Seric { 4458820Seric register ADDRESS *q; 4558820Seric char *owner; 4658820Seric int otherowners; 4758820Seric register ENVELOPE *ee; 4858820Seric ENVELOPE *splitenv = NULL; 4958929Seric bool announcequeueup; 5058820Seric 5158820Seric /* determine actual delivery mode */ 5258820Seric if (mode == SM_DEFAULT) 5358820Seric { 5458820Seric extern bool shouldqueue(); 5558820Seric 5658820Seric mode = e->e_sendmode; 5758820Seric if (mode != SM_VERIFY && 5858820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 5958820Seric mode = SM_QUEUE; 6058929Seric announcequeueup = mode == SM_QUEUE; 6158820Seric } 6258929Seric else 6358929Seric announcequeueup = FALSE; 6458820Seric 6558820Seric if (tTd(13, 1)) 6658820Seric { 6758820Seric printf("\nSENDALL: mode %c, e_from ", mode); 6858820Seric printaddr(&e->e_from, FALSE); 6958820Seric printf("sendqueue:\n"); 7058820Seric printaddr(e->e_sendqueue, TRUE); 7158820Seric } 7258820Seric 7358820Seric /* 7458820Seric ** Do any preprocessing necessary for the mode we are running. 7558820Seric ** Check to make sure the hop count is reasonable. 7658820Seric ** Delete sends to the sender in mailing lists. 7758820Seric */ 7858820Seric 7958820Seric CurEnv = e; 8058820Seric 8158820Seric if (e->e_hopcount > MaxHopCount) 8258820Seric { 8358820Seric errno = 0; 8458820Seric syserr("554 too many hops %d (%d max): from %s, to %s", 8558820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 8658820Seric e->e_sendqueue->q_paddr); 8758820Seric return; 8858820Seric } 8958820Seric 9059435Seric /* 9159435Seric ** Do sender deletion. 9259435Seric ** 9359435Seric ** If the sender has the QQUEUEUP flag set, skip this. 9459435Seric ** This can happen if the name server is hosed when you 9559435Seric ** are trying to send mail. The result is that the sender 9659435Seric ** is instantiated in the queue as a recipient. 9759435Seric */ 9859435Seric 9959435Seric if (!MeToo && !bitset(QQUEUEUP, e->e_from.q_flags)) 10058820Seric { 10158820Seric extern ADDRESS *recipient(); 10258820Seric 10358820Seric if (tTd(13, 5)) 10458820Seric { 10558820Seric printf("sendall: QDONTSEND "); 10658820Seric printaddr(&e->e_from, FALSE); 10758820Seric } 10858820Seric e->e_from.q_flags |= QDONTSEND; 10958820Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 11058820Seric } 11158820Seric 11258820Seric /* 11358820Seric ** Handle alias owners. 11458820Seric ** 11558820Seric ** We scan up the q_alias chain looking for owners. 11658820Seric ** We discard owners that are the same as the return path. 11758820Seric */ 11858820Seric 11958820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12058820Seric { 12158820Seric register struct address *a; 12258820Seric 12358820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 12458820Seric continue; 12558820Seric if (a != NULL) 12658820Seric q->q_owner = a->q_owner; 12758820Seric 12858820Seric if (q->q_owner != NULL && 12958820Seric !bitset(QDONTSEND, q->q_flags) && 13058820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 13158820Seric q->q_owner = NULL; 13258820Seric } 13358820Seric 13458820Seric owner = ""; 13558820Seric otherowners = 1; 13658820Seric while (owner != NULL && otherowners > 0) 13758820Seric { 13858820Seric owner = NULL; 13958820Seric otherowners = 0; 14058820Seric 14158820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14258820Seric { 14358820Seric if (bitset(QDONTSEND, q->q_flags)) 14458820Seric continue; 14558820Seric 14658820Seric if (q->q_owner != NULL) 14758820Seric { 14858820Seric if (owner == NULL) 14958820Seric owner = q->q_owner; 15058820Seric else if (owner != q->q_owner) 15158820Seric { 15258820Seric if (strcmp(owner, q->q_owner) == 0) 15358820Seric { 15458820Seric /* make future comparisons cheap */ 15558820Seric q->q_owner = owner; 15658820Seric } 15758820Seric else 15858820Seric { 15958820Seric otherowners++; 16058820Seric } 16158820Seric owner = q->q_owner; 16258820Seric } 16358820Seric } 16458820Seric else 16558820Seric { 16658820Seric otherowners++; 16758820Seric } 16858820Seric } 16958820Seric 17058820Seric if (owner != NULL && otherowners > 0) 17158820Seric { 17258820Seric extern HDR *copyheader(); 17358820Seric extern ADDRESS *copyqueue(); 17458820Seric 17558820Seric /* 17658820Seric ** Split this envelope into two. 17758820Seric */ 17858820Seric 17958820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 18058820Seric *ee = *e; 18158820Seric ee->e_id = NULL; 18258820Seric (void) queuename(ee, '\0'); 18358820Seric 18458820Seric if (tTd(13, 1)) 18558820Seric printf("sendall: split %s into %s\n", 18658820Seric e->e_id, ee->e_id); 18758820Seric 18858820Seric ee->e_header = copyheader(e->e_header); 18958820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 19058820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 19158916Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); 19258820Seric setsender(owner, ee, NULL, TRUE); 19358820Seric if (tTd(13, 5)) 19458820Seric { 19558820Seric printf("sendall(split): QDONTSEND "); 19658820Seric printaddr(&ee->e_from, FALSE); 19758820Seric } 19858820Seric ee->e_from.q_flags |= QDONTSEND; 19958820Seric ee->e_dfp = NULL; 20058820Seric ee->e_xfp = NULL; 20158820Seric ee->e_lockfp = NULL; 20258820Seric ee->e_df = NULL; 20358820Seric ee->e_errormode = EM_MAIL; 20458820Seric ee->e_sibling = splitenv; 20558820Seric splitenv = ee; 20658820Seric 20758820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 20858820Seric if (q->q_owner == owner) 20958820Seric q->q_flags |= QDONTSEND; 21058820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 21158820Seric if (q->q_owner != owner) 21258820Seric q->q_flags |= QDONTSEND; 21358820Seric 21458820Seric if (e->e_df != NULL && mode != SM_VERIFY) 21558820Seric { 21658820Seric ee->e_dfp = NULL; 21758820Seric ee->e_df = newstr(queuename(ee, 'd')); 21858820Seric if (link(e->e_df, ee->e_df) < 0) 21958820Seric { 22058820Seric syserr("sendall: link(%s, %s)", 22158820Seric e->e_df, ee->e_df); 22258820Seric } 22358820Seric } 22458820Seric 22558820Seric if (mode != SM_VERIFY) 22658820Seric openxscript(ee); 22758820Seric #ifdef LOG 22858820Seric if (LogLevel > 4) 22958820Seric syslog(LOG_INFO, "%s: clone %s", 23058820Seric ee->e_id, e->e_id); 23158820Seric #endif 23258820Seric } 23358820Seric } 23458820Seric 23558820Seric if (owner != NULL) 23658820Seric { 23758820Seric setsender(owner, e, NULL, TRUE); 23858820Seric if (tTd(13, 5)) 23958820Seric { 24058820Seric printf("sendall(owner): QDONTSEND "); 24158820Seric printaddr(&e->e_from, FALSE); 24258820Seric } 24358820Seric e->e_from.q_flags |= QDONTSEND; 24458820Seric e->e_errormode = EM_MAIL; 24558820Seric } 24658820Seric 24758916Seric # ifdef QUEUE 24858916Seric if ((mode == SM_QUEUE || mode == SM_FORK || 24958916Seric (mode != SM_VERIFY && SuperSafe)) && 25058916Seric !bitset(EF_INQUEUE, e->e_flags)) 25158916Seric { 25258916Seric /* be sure everything is instantiated in the queue */ 25358929Seric queueup(e, TRUE, announcequeueup); 25458916Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 25558929Seric queueup(ee, TRUE, announcequeueup); 25658916Seric } 25758916Seric #endif /* QUEUE */ 25858916Seric 25958820Seric if (splitenv != NULL) 26058820Seric { 26158820Seric if (tTd(13, 1)) 26258820Seric { 26358820Seric printf("\nsendall: Split queue; remaining queue:\n"); 26458820Seric printaddr(e->e_sendqueue, TRUE); 26558820Seric } 26658820Seric 26758820Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 26858820Seric { 26958820Seric CurEnv = ee; 27058820Seric sendenvelope(ee, mode); 27158820Seric } 27258820Seric 27358820Seric CurEnv = e; 27458820Seric } 27558820Seric sendenvelope(e, mode); 27658820Seric 27758820Seric for (; splitenv != NULL; splitenv = splitenv->e_sibling) 27858820Seric dropenvelope(splitenv); 27958820Seric } 28058820Seric 28158820Seric sendenvelope(e, mode) 28258820Seric register ENVELOPE *e; 28358820Seric char mode; 28458820Seric { 28558916Seric bool oldverbose; 28658916Seric int pid; 28758820Seric register ADDRESS *q; 28858916Seric #ifdef LOCKF 28958916Seric struct flock lfd; 29058916Seric #endif 29158820Seric 29258916Seric oldverbose = Verbose; 29358916Seric switch (mode) 29458916Seric { 29558916Seric case SM_VERIFY: 29658916Seric Verbose = TRUE; 29758916Seric break; 29858916Seric 29958916Seric case SM_QUEUE: 30058916Seric queueonly: 30158916Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 30258916Seric return; 30358916Seric 30458916Seric case SM_FORK: 30558916Seric if (e->e_xfp != NULL) 30658916Seric (void) fflush(e->e_xfp); 30758916Seric 30858916Seric # ifdef LOCKF 30958916Seric /* 31058916Seric ** Since lockf has the interesting semantic that the 31158916Seric ** lock is lost when we fork, we have to risk losing 31258916Seric ** the lock here by closing before the fork, and then 31358916Seric ** trying to get it back in the child. 31458916Seric */ 31558916Seric 31658916Seric if (e->e_lockfp != NULL) 31758916Seric { 31858916Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 31958916Seric e->e_lockfp = NULL; 32058916Seric } 32158916Seric # endif /* LOCKF */ 32258916Seric 32358916Seric pid = fork(); 32458916Seric if (pid < 0) 32558916Seric { 32658916Seric goto queueonly; 32758916Seric } 32858916Seric else if (pid > 0) 32958916Seric { 33058916Seric /* be sure we leave the temp files to our child */ 33158916Seric e->e_id = e->e_df = NULL; 33258916Seric # ifndef LOCKF 33358916Seric if (e->e_lockfp != NULL) 33458916Seric { 33558916Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 33658916Seric e->e_lockfp = NULL; 33758916Seric } 33858916Seric # endif 33958916Seric 34058916Seric /* close any random open files in the envelope */ 34158916Seric if (e->e_dfp != NULL) 34258916Seric { 34358916Seric (void) xfclose(e->e_dfp, "sendenvelope", "dfp"); 34458916Seric e->e_dfp = NULL; 34558916Seric } 34658916Seric if (e->e_xfp != NULL) 34758916Seric { 34858916Seric (void) xfclose(e->e_xfp, "sendenvelope", "xfp"); 34958916Seric e->e_xfp = NULL; 35058916Seric } 35158916Seric return; 35258916Seric } 35358916Seric 35458916Seric /* double fork to avoid zombies */ 35558916Seric if (fork() > 0) 35658916Seric exit(EX_OK); 35758916Seric 35858916Seric /* be sure we are immune from the terminal */ 35958916Seric disconnect(FALSE, e); 36058916Seric 36158916Seric # ifdef LOCKF 36258916Seric /* 36358916Seric ** Now try to get our lock back. 36458916Seric */ 36558916Seric 36658916Seric lfd.l_type = F_WRLCK; 36758916Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 36858916Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 36958916Seric if (e->e_lockfp == NULL || 37058916Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 37158916Seric { 37258916Seric /* oops.... lost it */ 37358916Seric if (tTd(13, 1)) 37458916Seric printf("sendenvelope: %s lost lock: lockfp=%x, %s\n", 37558916Seric e->e_id, e->e_lockfp, errstring(errno)); 37658916Seric 37758916Seric # ifdef LOG 37858916Seric if (LogLevel > 29) 37958916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 38058916Seric e->e_id); 38158916Seric # endif /* LOG */ 38258916Seric exit(EX_OK); 38358916Seric } 38458916Seric # endif /* LOCKF */ 38558916Seric 38658916Seric /* 38758916Seric ** Close any cached connections. 38858916Seric ** 38958916Seric ** We don't send the QUIT protocol because the parent 39058916Seric ** still knows about the connection. 39158916Seric ** 39258916Seric ** This should only happen when delivering an error 39358916Seric ** message. 39458916Seric */ 39558916Seric 39658916Seric mci_flush(FALSE, NULL); 39758916Seric 39858916Seric break; 39958916Seric } 40058916Seric 40158820Seric /* 40258820Seric ** Run through the list and send everything. 40358820Seric */ 40458820Seric 40558820Seric e->e_nsent = 0; 40658820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 40758820Seric { 40858820Seric if (mode == SM_VERIFY) 40958820Seric { 41058820Seric e->e_to = q->q_paddr; 41158820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 41258820Seric message("deliverable"); 41358820Seric } 41458820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 41558820Seric { 41658820Seric # ifdef QUEUE 41758820Seric /* 41858820Seric ** Checkpoint the send list every few addresses 41958820Seric */ 42058820Seric 42158820Seric if (e->e_nsent >= CheckpointInterval) 42258820Seric { 42358820Seric queueup(e, TRUE, FALSE); 42458820Seric e->e_nsent = 0; 42558820Seric } 42658820Seric # endif /* QUEUE */ 42758820Seric (void) deliver(e, q); 42858820Seric } 42958820Seric } 43058820Seric Verbose = oldverbose; 43158820Seric 43258820Seric /* 43358820Seric ** Now run through and check for errors. 43458820Seric */ 43558820Seric 43658820Seric if (mode == SM_VERIFY) 43758820Seric { 43858820Seric return; 43958820Seric } 44058820Seric 44158820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 44258820Seric { 44358820Seric if (tTd(13, 3)) 44458820Seric { 44558820Seric printf("Checking "); 44658820Seric printaddr(q, FALSE); 44758820Seric } 44858820Seric 44958820Seric /* only send errors if the message failed */ 45058916Seric if (!bitset(QBADADDR, q->q_flags) || 45158916Seric bitset(QDONTSEND, q->q_flags)) 45258820Seric continue; 45358820Seric 45458820Seric e->e_flags |= EF_FATALERRS; 45558820Seric 45658820Seric if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) 45758820Seric (void) sendtolist(e->e_from.q_paddr, NULL, 45858820Seric &e->e_errorqueue, e); 45958820Seric } 46058820Seric 46158820Seric if (mode == SM_FORK) 46258820Seric finis(); 46358820Seric } 46458820Seric /* 46558820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 46658820Seric ** 46758820Seric ** This MUST be a macro, since after a vfork we are running 46858820Seric ** two processes on the same stack!!! 46958820Seric ** 47058820Seric ** Parameters: 47158820Seric ** none. 47258820Seric ** 47358820Seric ** Returns: 47458820Seric ** From a macro??? You've got to be kidding! 47558820Seric ** 47658820Seric ** Side Effects: 47758820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 47858820Seric ** pid of child in parent, zero in child. 47958820Seric ** -1 on unrecoverable error. 48058820Seric ** 48158820Seric ** Notes: 48258820Seric ** I'm awfully sorry this looks so awful. That's 48358820Seric ** vfork for you..... 48458820Seric */ 48558820Seric 48658820Seric # define NFORKTRIES 5 48758820Seric 48858820Seric # ifndef FORK 48958820Seric # define FORK fork 49058820Seric # endif 49158820Seric 49258820Seric # define DOFORK(fORKfN) \ 49358820Seric {\ 49458820Seric register int i;\ 49558820Seric \ 49658820Seric for (i = NFORKTRIES; --i >= 0; )\ 49758820Seric {\ 49858820Seric pid = fORKfN();\ 49958820Seric if (pid >= 0)\ 50058820Seric break;\ 50158820Seric if (i > 0)\ 50258820Seric sleep((unsigned) NFORKTRIES - i);\ 50358820Seric }\ 50458820Seric } 50558820Seric /* 50658820Seric ** DOFORK -- simple fork interface to DOFORK. 50758820Seric ** 50858820Seric ** Parameters: 50958820Seric ** none. 51058820Seric ** 51158820Seric ** Returns: 51258820Seric ** pid of child in parent. 51358820Seric ** zero in child. 51458820Seric ** -1 on error. 51558820Seric ** 51658820Seric ** Side Effects: 51758820Seric ** returns twice, once in parent and once in child. 51858820Seric */ 51958820Seric 52058820Seric dofork() 52158820Seric { 52258820Seric register int pid; 52358820Seric 52458820Seric DOFORK(fork); 52558820Seric return (pid); 52658820Seric } 52758820Seric /* 5284315Seric ** DELIVER -- Deliver a message to a list of addresses. 529294Seric ** 5304315Seric ** This routine delivers to everyone on the same host as the 5314315Seric ** user on the head of the list. It is clever about mailers 5324315Seric ** that don't handle multiple users. It is NOT guaranteed 5334315Seric ** that it will deliver to all these addresses however -- so 5344315Seric ** deliver should be called once for each address on the 5354315Seric ** list. 5364315Seric ** 537294Seric ** Parameters: 5389370Seric ** e -- the envelope to deliver. 5394621Seric ** firstto -- head of the address list to deliver to. 540294Seric ** 541294Seric ** Returns: 542294Seric ** zero -- successfully delivered. 543294Seric ** else -- some failure, see ExitStat for more info. 544294Seric ** 545294Seric ** Side Effects: 546294Seric ** The standard input is passed off to someone. 547294Seric */ 548294Seric 5499370Seric deliver(e, firstto) 5509370Seric register ENVELOPE *e; 5514621Seric ADDRESS *firstto; 552294Seric { 5534452Seric char *host; /* host being sent to */ 5544452Seric char *user; /* user being sent to */ 555294Seric char **pvp; 5563233Seric register char **mvp; 5573233Seric register char *p; 55810306Seric register MAILER *m; /* mailer for this recipient */ 5594397Seric ADDRESS *ctladdr; 56054967Seric register MCI *mci; 5614621Seric register ADDRESS *to = firstto; 5624863Seric bool clever = FALSE; /* running user smtp to this mailer */ 5635032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 56451951Seric int rcode; /* response code */ 56557454Seric char *firstsig; /* signature of firstto */ 56658820Seric int pid; 56758820Seric char *curhost; 56858820Seric int mpvect[2]; 56958820Seric int rpvect[2]; 57010306Seric char *pv[MAXPV+1]; 57158704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 57210306Seric char buf[MAXNAME]; 57351951Seric char rpathbuf[MAXNAME]; /* translated return path */ 57457441Seric extern int checkcompat(); 57510306Seric extern ADDRESS *getctladdr(); 57610306Seric extern char *remotename(); 57757454Seric extern char *hostsignature(); 57858820Seric extern FILE *fdopen(); 579294Seric 5804488Seric errno = 0; 58158680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 5823233Seric return (0); 583294Seric 58435651Seric #ifdef NAMED_BIND 58534022Sbostic /* unless interactive, try twice, over a minute */ 58634022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 58734022Sbostic _res.retrans = 30; 58834022Sbostic _res.retry = 2; 58934022Sbostic } 59036788Sbostic #endif 59134022Sbostic 5926974Seric m = to->q_mailer; 5936974Seric host = to->q_host; 59458803Seric CurEnv = e; /* just in case */ 59559044Seric e->e_statmsg = NULL; 5966974Seric 5977672Seric if (tTd(10, 1)) 5983233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 5996974Seric m->m_mno, host, to->q_user); 600294Seric 601294Seric /* 6025903Seric ** If this mailer is expensive, and if we don't want to make 6035903Seric ** connections now, just mark these addresses and return. 6045903Seric ** This is useful if we want to batch connections to 6055903Seric ** reduce load. This will cause the messages to be 6065903Seric ** queued up, and a daemon will come along to send the 6075903Seric ** messages later. 6085903Seric ** This should be on a per-mailer basis. 6095903Seric */ 6105903Seric 61158737Seric if (NoConnect && !bitset(EF_QUEUERUN, e->e_flags) && 61258737Seric bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 6135903Seric { 6145903Seric for (; to != NULL; to = to->q_next) 6158431Seric { 61658680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 61758247Seric to->q_mailer != m) 6188431Seric continue; 6198431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 6209370Seric e->e_to = to->q_paddr; 62158151Seric message("queued"); 62258020Seric if (LogLevel > 8) 62358337Seric logdelivery(m, NULL, "queued", e); 6248431Seric } 6259370Seric e->e_to = NULL; 6265903Seric return (0); 6275903Seric } 6285903Seric 6295903Seric /* 6303233Seric ** Do initial argv setup. 6313233Seric ** Insert the mailer name. Notice that $x expansion is 6323233Seric ** NOT done on the mailer name. Then, if the mailer has 6333233Seric ** a picky -f flag, we insert it as appropriate. This 6343233Seric ** code does not check for 'pv' overflow; this places a 6353233Seric ** manifest lower limit of 4 for MAXPV. 6368062Seric ** The from address rewrite is expected to make 6378062Seric ** the address relative to the other end. 6382968Seric */ 6392968Seric 6404452Seric /* rewrite from address, using rewriting rules */ 64159163Seric rcode = EX_OK; 64259163Seric (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, 64359163Seric RF_SENDERADDR|RF_CANONICAL, 64459163Seric &rcode, e)); 64558680Seric define('g', rpathbuf, e); /* translated return path */ 6469370Seric define('h', host, e); /* to host */ 6473233Seric Errors = 0; 6483233Seric pvp = pv; 6493233Seric *pvp++ = m->m_argv[0]; 6502968Seric 6513233Seric /* insert -f or -r flag as appropriate */ 65210682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6533233Seric { 65410682Seric if (bitnset(M_FOPT, m->m_flags)) 6553233Seric *pvp++ = "-f"; 6563233Seric else 6573233Seric *pvp++ = "-r"; 65851951Seric *pvp++ = newstr(rpathbuf); 6593233Seric } 660294Seric 661294Seric /* 6623233Seric ** Append the other fixed parts of the argv. These run 6633233Seric ** up to the first entry containing "$u". There can only 6643233Seric ** be one of these, and there are only a few more slots 6653233Seric ** in the pv after it. 666294Seric */ 667294Seric 6683233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 669294Seric { 67058050Seric /* can't use strchr here because of sign extension problems */ 67158050Seric while (*p != '\0') 67258050Seric { 67358050Seric if ((*p++ & 0377) == MACROEXPAND) 67458050Seric { 67558050Seric if (*p == 'u') 67658050Seric break; 67758050Seric } 67858050Seric } 67958050Seric 68058050Seric if (*p != '\0') 6813233Seric break; 6823233Seric 6833233Seric /* this entry is safe -- go ahead and process it */ 6849370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 6853233Seric *pvp++ = newstr(buf); 6863233Seric if (pvp >= &pv[MAXPV - 3]) 6873233Seric { 68858151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 6893233Seric return (-1); 6903233Seric } 691294Seric } 6924863Seric 6936038Seric /* 6946038Seric ** If we have no substitution for the user name in the argument 6956038Seric ** list, we know that we must supply the names otherwise -- and 6966038Seric ** SMTP is the answer!! 6976038Seric */ 6986038Seric 6993233Seric if (*mvp == NULL) 7004863Seric { 7014863Seric /* running SMTP */ 7025179Seric # ifdef SMTP 7034863Seric clever = TRUE; 7044863Seric *pvp = NULL; 70556795Seric # else /* SMTP */ 7066038Seric /* oops! we don't implement SMTP */ 70758151Seric syserr("554 SMTP style mailer"); 7085179Seric return (EX_SOFTWARE); 70956795Seric # endif /* SMTP */ 7104863Seric } 711294Seric 712294Seric /* 7133233Seric ** At this point *mvp points to the argument with $u. We 7143233Seric ** run through our address list and append all the addresses 7153233Seric ** we can. If we run out of space, do not fret! We can 7163233Seric ** always send another copy later. 717294Seric */ 718294Seric 7193233Seric tobuf[0] = '\0'; 7209370Seric e->e_to = tobuf; 7214397Seric ctladdr = NULL; 72257454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7233233Seric for (; to != NULL; to = to->q_next) 724294Seric { 7253233Seric /* avoid sending multiple recipients to dumb mailers */ 72610682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7273233Seric break; 7283233Seric 7293233Seric /* if already sent or not for this host, don't send */ 73058680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 73157454Seric to->q_mailer != firstto->q_mailer || 73257454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7333233Seric continue; 7344397Seric 7358225Seric /* avoid overflowing tobuf */ 73642462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7378225Seric break; 7388225Seric 7397672Seric if (tTd(10, 1)) 7405032Seric { 7415032Seric printf("\nsend to "); 7425032Seric printaddr(to, FALSE); 7435032Seric } 7445032Seric 7454397Seric /* compute effective uid/gid when sending */ 7464596Seric if (to->q_mailer == ProgMailer) 7474397Seric ctladdr = getctladdr(to); 7484397Seric 7493233Seric user = to->q_user; 7509370Seric e->e_to = to->q_paddr; 75157731Seric if (tTd(10, 5)) 75257731Seric { 75357731Seric printf("deliver: QDONTSEND "); 75457731Seric printaddr(to, FALSE); 75557731Seric } 75658680Seric to->q_flags |= QDONTSEND; 7573233Seric 7583233Seric /* 7593233Seric ** Check to see that these people are allowed to 7603233Seric ** talk to each other. 7613233Seric */ 7623233Seric 76310699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 76410699Seric { 76529914Seric NoReturn = TRUE; 76658151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 76758337Seric giveresponse(EX_UNAVAILABLE, m, NULL, e); 76810699Seric continue; 76910699Seric } 77057441Seric rcode = checkcompat(to, e); 77157459Seric if (rcode != EX_OK) 772294Seric { 77358337Seric giveresponse(rcode, m, NULL, e); 7743233Seric continue; 775294Seric } 7763233Seric 7773233Seric /* 7784099Seric ** Strip quote bits from names if the mailer is dumb 7794099Seric ** about them. 7803233Seric */ 7813233Seric 78210682Seric if (bitnset(M_STRIPQ, m->m_flags)) 783294Seric { 78454983Seric stripquotes(user); 78554983Seric stripquotes(host); 7863233Seric } 7873233Seric 7889206Seric /* hack attack -- delivermail compatibility */ 7899206Seric if (m == ProgMailer && *user == '|') 7909206Seric user++; 7919206Seric 7923233Seric /* 7934161Seric ** If an error message has already been given, don't 7944161Seric ** bother to send to this address. 7954161Seric ** 7964161Seric ** >>>>>>>>>> This clause assumes that the local mailer 7974161Seric ** >> NOTE >> cannot do any further aliasing; that 7984161Seric ** >>>>>>>>>> function is subsumed by sendmail. 7994161Seric */ 8004161Seric 8017293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8024161Seric continue; 8034161Seric 8044283Seric /* save statistics.... */ 8059370Seric markstats(e, to); 8064283Seric 8074161Seric /* 8083233Seric ** See if this user name is "special". 8093233Seric ** If the user name has a slash in it, assume that this 8106974Seric ** is a file -- send it off without further ado. Note 8116974Seric ** that this type of addresses is not processed along 8126974Seric ** with the others, so we fudge on the To person. 8133233Seric */ 8143233Seric 81557402Seric if (m == FileMailer) 8163233Seric { 81757402Seric rcode = mailfile(user, getctladdr(to), e); 81858337Seric giveresponse(rcode, m, NULL, e); 81957402Seric if (rcode == EX_OK) 82057402Seric to->q_flags |= QSENT; 82157402Seric continue; 822294Seric } 8233233Seric 8244315Seric /* 8254315Seric ** Address is verified -- add this user to mailer 8264315Seric ** argv, and add it to the print list of recipients. 8274315Seric */ 8284315Seric 8296059Seric /* link together the chain of recipients */ 8306272Seric to->q_tchain = tochain; 8316272Seric tochain = to; 8326059Seric 8333233Seric /* create list of users for error messages */ 8349388Seric (void) strcat(tobuf, ","); 8354082Seric (void) strcat(tobuf, to->q_paddr); 8369370Seric define('u', user, e); /* to user */ 8379370Seric define('z', to->q_home, e); /* user's home */ 8383233Seric 8394863Seric /* 8406059Seric ** Expand out this user into argument list. 8414863Seric */ 8424863Seric 8436059Seric if (!clever) 8443233Seric { 8459370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8464863Seric *pvp++ = newstr(buf); 8474863Seric if (pvp >= &pv[MAXPV - 2]) 8484863Seric { 8494863Seric /* allow some space for trailing parms */ 8504863Seric break; 8514863Seric } 8524863Seric } 853294Seric } 854294Seric 8554067Seric /* see if any addresses still exist */ 8564067Seric if (tobuf[0] == '\0') 8574863Seric { 8589370Seric define('g', (char *) NULL, e); 8594067Seric return (0); 8604863Seric } 8614067Seric 8623233Seric /* print out messages as full list */ 8639388Seric e->e_to = tobuf + 1; 8643233Seric 865294Seric /* 8663233Seric ** Fill out any parameters after the $u parameter. 867294Seric */ 868294Seric 8694863Seric while (!clever && *++mvp != NULL) 870294Seric { 8719370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8723233Seric *pvp++ = newstr(buf); 8733233Seric if (pvp >= &pv[MAXPV]) 87458151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 875294Seric } 8763233Seric *pvp++ = NULL; 877294Seric 878294Seric /* 879294Seric ** Call the mailer. 8802898Seric ** The argument vector gets built, pipes 881294Seric ** are created as necessary, and we fork & exec as 8822898Seric ** appropriate. 8834863Seric ** If we are running SMTP, we just need to clean up. 884294Seric */ 885294Seric 88658309Seric if (ctladdr == NULL && m != ProgMailer) 88741050Seric ctladdr = &e->e_from; 88835651Seric #ifdef NAMED_BIND 88951313Seric if (ConfigLevel < 2) 89051313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 89135651Seric #endif 89254967Seric 8937672Seric if (tTd(11, 1)) 894294Seric { 8958178Seric printf("openmailer:"); 89658820Seric printav(pv); 897294Seric } 8984488Seric errno = 0; 8993233Seric 90025050Seric CurHostName = m->m_mailer; 90125050Seric 9026038Seric /* 9036038Seric ** Deal with the special case of mail handled through an IPC 9046038Seric ** connection. 9056038Seric ** In this case we don't actually fork. We must be 9066038Seric ** running SMTP for this to work. We will return a 9076038Seric ** zero pid to indicate that we are running IPC. 90811160Seric ** We also handle a debug version that just talks to stdin/out. 9096038Seric */ 9106038Seric 91158820Seric curhost = NULL; 91258820Seric 91311160Seric /* check for Local Person Communication -- not for mortals!!! */ 91411160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 91511160Seric { 91654967Seric mci = (MCI *) xalloc(sizeof *mci); 91754993Seric bzero((char *) mci, sizeof *mci); 91853738Seric mci->mci_in = stdin; 91953738Seric mci->mci_out = stdout; 92054967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 92153751Seric mci->mci_mailer = m; 92211160Seric } 92354967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 92454967Seric strcmp(m->m_mailer, "[TCP]") == 0) 9256038Seric { 92652107Seric #ifdef DAEMON 92757454Seric register int i; 9287285Seric register u_short port; 92954967Seric extern MCI *mci_get(); 93057454Seric extern char *hostsignature(); 9316038Seric 93258820Seric CurHostName = pv[1]; 93358820Seric curhost = hostsignature(m, pv[1], e); 93454967Seric 93558479Seric if (curhost == NULL || curhost[0] == '\0') 93658479Seric { 93758479Seric syserr("null signature"); 93858820Seric rcode = EX_OSERR; 93958820Seric goto give_up; 94058479Seric } 94158479Seric 9426038Seric if (!clever) 94358479Seric { 94458151Seric syserr("554 non-clever IPC"); 94558820Seric rcode = EX_OSERR; 94658820Seric goto give_up; 94758479Seric } 94858820Seric if (pv[2] != NULL) 94958820Seric port = atoi(pv[2]); 9506632Seric else 9517285Seric port = 0; 95258820Seric tryhost: 95358820Seric mci = NULL; 95457454Seric while (*curhost != '\0') 95529433Sbloom { 95657454Seric register char *p; 95758664Seric static char hostbuf[MAXNAME]; 95857454Seric 95958820Seric mci = NULL; 96058820Seric 96157454Seric /* pull the next host from the signature */ 96257454Seric p = strchr(curhost, ':'); 96357454Seric if (p == NULL) 96457454Seric p = &curhost[strlen(curhost)]; 96557454Seric strncpy(hostbuf, curhost, p - curhost); 96657454Seric hostbuf[p - curhost] = '\0'; 96757454Seric if (*p != '\0') 96857454Seric p++; 96957454Seric curhost = p; 97057454Seric 97153738Seric /* see if we already know that this host is fried */ 97257454Seric CurHostName = hostbuf; 97357454Seric mci = mci_get(hostbuf, m); 97454967Seric if (mci->mci_state != MCIS_CLOSED) 97557387Seric { 97657387Seric if (tTd(11, 1)) 97757387Seric { 97857387Seric printf("openmailer: "); 97957387Seric mci_dump(mci); 98057387Seric } 98157943Seric CurHostName = mci->mci_host; 98258820Seric break; 98357387Seric } 98453751Seric mci->mci_mailer = m; 98554967Seric if (mci->mci_exitstat != EX_OK) 98654967Seric continue; 98754967Seric 98854967Seric /* try the connection */ 98957454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 99058151Seric message("Connecting to %s (%s)...", 99157454Seric hostbuf, m->m_name); 99257454Seric i = makeconnection(hostbuf, port, mci, 99354967Seric bitnset(M_SECURE_PORT, m->m_flags)); 99454967Seric mci->mci_exitstat = i; 99554967Seric mci->mci_errno = errno; 99654967Seric if (i == EX_OK) 99752106Seric { 99854967Seric mci->mci_state = MCIS_OPENING; 99954967Seric mci_cache(mci); 100054967Seric break; 100134022Sbostic } 100254967Seric else if (tTd(11, 1)) 100354967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 100454967Seric i, errno); 100553738Seric 100654967Seric 100753738Seric /* enter status of this host */ 100853738Seric setstat(i); 10096047Seric } 101054993Seric mci->mci_pid = 0; 101154967Seric #else /* no DAEMON */ 101258151Seric syserr("554 openmailer: no IPC"); 101357387Seric if (tTd(11, 1)) 101457387Seric printf("openmailer: NULL\n"); 101553738Seric return NULL; 101654967Seric #endif /* DAEMON */ 10176038Seric } 101854967Seric else 1019294Seric { 102058852Seric int i; 102158852Seric struct stat stbuf; 102258852Seric 102358852Seric /* make absolutely certain 0, 1, and 2 are in use */ 102458852Seric for (i = 0; i < 3; i++) 102558852Seric { 102658852Seric if (fstat(i, &stbuf) < 0) 102758852Seric { 102858852Seric /* oops.... */ 102958925Seric int fd; 103058925Seric 103158925Seric syserr("%s... openmailer(%s): fd %d not open", 103258925Seric e->e_to, m->m_name, i); 103358925Seric fd = open("/dev/null", O_RDONLY, 0666); 103458925Seric if (fd != i) 103558925Seric { 103658925Seric (void) dup2(fd, i); 103758925Seric (void) close(fd); 103858925Seric } 103958852Seric } 104058852Seric } 104158852Seric 104254967Seric /* create a pipe to shove the mail through */ 104354967Seric if (pipe(mpvect) < 0) 104454967Seric { 104558925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 104658925Seric e->e_to, m->m_name); 104757387Seric if (tTd(11, 1)) 104857387Seric printf("openmailer: NULL\n"); 104958820Seric rcode = EX_OSERR; 105058820Seric goto give_up; 105154967Seric } 10524863Seric 105354967Seric /* if this mailer speaks smtp, create a return pipe */ 105454967Seric if (clever && pipe(rpvect) < 0) 105554967Seric { 105658925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 105758925Seric e->e_to, m->m_name); 105854967Seric (void) close(mpvect[0]); 105954967Seric (void) close(mpvect[1]); 106057387Seric if (tTd(11, 1)) 106157387Seric printf("openmailer: NULL\n"); 106258820Seric rcode = EX_OSERR; 106358820Seric goto give_up; 106454967Seric } 10654863Seric 106654967Seric /* 106754967Seric ** Actually fork the mailer process. 106854967Seric ** DOFORK is clever about retrying. 106954967Seric ** 107054967Seric ** Dispose of SIGCHLD signal catchers that may be laying 107154967Seric ** around so that endmail will get it. 107254967Seric */ 10736038Seric 107454967Seric if (e->e_xfp != NULL) 107554967Seric (void) fflush(e->e_xfp); /* for debugging */ 107654967Seric (void) fflush(stdout); 107726434Seric # ifdef SIGCHLD 107854967Seric (void) signal(SIGCHLD, SIG_DFL); 107956795Seric # endif /* SIGCHLD */ 108054967Seric DOFORK(FORK); 108154967Seric /* pid is set by DOFORK */ 108254967Seric if (pid < 0) 10834863Seric { 108454967Seric /* failure */ 108558925Seric syserr("%s... openmailer(%s): cannot fork", 108658925Seric e->e_to, m->m_name); 108754967Seric (void) close(mpvect[0]); 108854967Seric (void) close(mpvect[1]); 108954967Seric if (clever) 109054967Seric { 109154967Seric (void) close(rpvect[0]); 109254967Seric (void) close(rpvect[1]); 109354967Seric } 109457387Seric if (tTd(11, 1)) 109557387Seric printf("openmailer: NULL\n"); 109658820Seric rcode = EX_OSERR; 109758820Seric goto give_up; 10984863Seric } 109954967Seric else if (pid == 0) 110054967Seric { 110154967Seric int i; 110256678Seric int saveerrno; 110358675Seric char **ep; 110458675Seric char *env[MAXUSERENVIRON]; 110558675Seric extern char **environ; 110654967Seric extern int DtableSize; 110715772Seric 110854967Seric /* child -- set up input & exec mailer */ 110954967Seric /* make diagnostic output be standard output */ 111054967Seric (void) signal(SIGINT, SIG_IGN); 111154967Seric (void) signal(SIGHUP, SIG_IGN); 111254967Seric (void) signal(SIGTERM, SIG_DFL); 11134709Seric 111458082Seric /* close any other cached connections */ 111558082Seric mci_flush(FALSE, mci); 111658082Seric 111758935Seric /* move into some "safe" directory */ 111858935Seric if (m->m_execdir != NULL) 111958935Seric { 112058935Seric char *p, *q; 112158935Seric char buf[MAXLINE]; 112258935Seric 112358935Seric for (p = m->m_execdir; p != NULL; p = q) 112458935Seric { 112558935Seric q = strchr(p, ':'); 112658935Seric if (q != NULL) 112758935Seric *q = '\0'; 112858935Seric expand(p, buf, &buf[sizeof buf] - 1, e); 112958935Seric if (q != NULL) 113058935Seric *q++ = ':'; 113158935Seric if (tTd(11, 20)) 113258935Seric printf("openmailer: trydir %s\n", 113358935Seric buf); 113458935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 113558935Seric break; 113658935Seric } 113758935Seric } 113858935Seric 113954967Seric /* arrange to filter std & diag output of command */ 114054967Seric if (clever) 114154967Seric { 114254967Seric (void) close(rpvect[0]); 114358852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 114458852Seric { 114558925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 114658925Seric e->e_to, m->m_name, rpvect[1]); 114758852Seric _exit(EX_OSERR); 114858852Seric } 114954967Seric (void) close(rpvect[1]); 115054967Seric } 115154967Seric else if (OpMode == MD_SMTP || HoldErrs) 115254967Seric { 115354967Seric /* put mailer output in transcript */ 115458852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 115558852Seric { 115658925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 115758925Seric e->e_to, m->m_name, 115858852Seric fileno(e->e_xfp)); 115958852Seric _exit(EX_OSERR); 116058852Seric } 116154967Seric } 116258852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 116358852Seric { 116458925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 116558925Seric e->e_to, m->m_name); 116658852Seric _exit(EX_OSERR); 116758852Seric } 11684709Seric 116954967Seric /* arrange to get standard input */ 117054967Seric (void) close(mpvect[1]); 117158731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 11724417Seric { 117358925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 117458925Seric e->e_to, m->m_name, mpvect[0]); 117554967Seric _exit(EX_OSERR); 11764417Seric } 117754967Seric (void) close(mpvect[0]); 117854967Seric if (!bitnset(M_RESTR, m->m_flags)) 11794415Seric { 118054967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 118154967Seric { 118254967Seric (void) setgid(DefGid); 118354967Seric (void) initgroups(DefUser, DefGid); 118454967Seric (void) setuid(DefUid); 118554967Seric } 118654967Seric else 118754967Seric { 118854967Seric (void) setgid(ctladdr->q_gid); 118954967Seric (void) initgroups(ctladdr->q_ruser? 119054967Seric ctladdr->q_ruser: ctladdr->q_user, 119154967Seric ctladdr->q_gid); 119254967Seric (void) setuid(ctladdr->q_uid); 119354967Seric } 11944415Seric } 11959370Seric 119654967Seric /* arrange for all the files to be closed */ 119754967Seric for (i = 3; i < DtableSize; i++) 119854967Seric { 119954967Seric register int j; 120054967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 120154967Seric (void)fcntl(i, F_SETFD, j|1); 120254967Seric } 12032774Seric 120458675Seric /* set up the mailer environment */ 120558675Seric i = 0; 120658675Seric env[i++] = "AGENT=sendmail"; 120758675Seric for (ep = environ; *ep != NULL; ep++) 120858675Seric { 120958675Seric if (strncmp(*ep, "TZ=", 3) == 0) 121058675Seric env[i++] = *ep; 121158675Seric } 121258675Seric env[i++] = NULL; 121358675Seric 121454967Seric /* try to execute the mailer */ 121558820Seric execve(m->m_mailer, pv, env); 121656678Seric saveerrno = errno; 121754967Seric syserr("Cannot exec %s", m->m_mailer); 1218*60008Seric if (m == LocalMailer || transienterror(saveerrno)) 1219*60008Seric _exit(EX_OSERR); 122054967Seric _exit(EX_UNAVAILABLE); 122151835Seric } 122254967Seric 122354967Seric /* 122454967Seric ** Set up return value. 122554967Seric */ 122654967Seric 122754967Seric mci = (MCI *) xalloc(sizeof *mci); 122854993Seric bzero((char *) mci, sizeof *mci); 122954967Seric mci->mci_mailer = m; 123054967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 123154993Seric mci->mci_pid = pid; 123254967Seric (void) close(mpvect[0]); 123354967Seric mci->mci_out = fdopen(mpvect[1], "w"); 123454967Seric if (clever) 123554967Seric { 123654967Seric (void) close(rpvect[1]); 123754967Seric mci->mci_in = fdopen(rpvect[0], "r"); 123854967Seric } 123954967Seric else 124054967Seric { 124154967Seric mci->mci_flags |= MCIF_TEMP; 124254967Seric mci->mci_in = NULL; 124354967Seric } 1244294Seric } 1245294Seric 12464709Seric /* 124754967Seric ** If we are in SMTP opening state, send initial protocol. 12484709Seric */ 12494709Seric 125054967Seric if (clever && mci->mci_state != MCIS_CLOSED) 12514863Seric { 125254967Seric smtpinit(m, mci, e); 125353738Seric } 125457387Seric if (tTd(11, 1)) 125557387Seric { 125657387Seric printf("openmailer: "); 125757387Seric mci_dump(mci); 125857387Seric } 1259294Seric 126058820Seric if (mci->mci_state != MCIS_OPEN) 126158820Seric { 126258820Seric /* couldn't open the mailer */ 126358820Seric rcode = mci->mci_exitstat; 126458820Seric errno = mci->mci_errno; 126558820Seric if (rcode == EX_OK) 126658820Seric { 126758820Seric /* shouldn't happen */ 126858820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 126958820Seric rcode, mci->mci_state, firstsig); 127058820Seric rcode = EX_SOFTWARE; 127158820Seric } 127259993Seric else if (rcode == EX_TEMPFAIL && *curhost != '\0') 127359958Seric { 127459958Seric /* try next MX site */ 127559958Seric goto tryhost; 127659958Seric } 127758820Seric } 127858820Seric else if (!clever) 127958820Seric { 128058820Seric /* 128158820Seric ** Format and send message. 128258820Seric */ 128358820Seric 128458820Seric putfromline(mci->mci_out, m, e); 128558820Seric (*e->e_puthdr)(mci->mci_out, m, e); 128658820Seric putline("\n", mci->mci_out, m); 128759730Seric (*e->e_putbody)(mci->mci_out, m, e, NULL); 128858820Seric 128958820Seric /* get the exit status */ 129058820Seric rcode = endmailer(mci, e, pv); 129158820Seric } 129258820Seric else 129358820Seric #ifdef SMTP 129458820Seric { 129558820Seric /* 129658820Seric ** Send the MAIL FROM: protocol 129758820Seric */ 129858820Seric 129958820Seric rcode = smtpmailfrom(m, mci, e); 130058820Seric if (rcode == EX_OK) 130158820Seric { 130258820Seric register char *t = tobuf; 130358820Seric register int i; 130458820Seric 130558820Seric /* send the recipient list */ 130658820Seric tobuf[0] = '\0'; 130758820Seric for (to = tochain; to != NULL; to = to->q_tchain) 130858820Seric { 130958820Seric e->e_to = to->q_paddr; 131058820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 131158820Seric { 131258820Seric markfailure(e, to, i); 131358820Seric giveresponse(i, m, mci, e); 131458820Seric } 131558820Seric else 131658820Seric { 131758820Seric *t++ = ','; 131858820Seric for (p = to->q_paddr; *p; *t++ = *p++) 131958820Seric continue; 132058820Seric } 132158820Seric } 132258820Seric 132358820Seric /* now send the data */ 132458820Seric if (tobuf[0] == '\0') 132558820Seric { 132658820Seric rcode = EX_OK; 132758820Seric e->e_to = NULL; 132858820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 132958820Seric smtprset(m, mci, e); 133058820Seric } 133158820Seric else 133258820Seric { 133358820Seric e->e_to = tobuf + 1; 133458820Seric rcode = smtpdata(m, mci, e); 133558820Seric } 133658820Seric 133758820Seric /* now close the connection */ 133858820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 133958820Seric smtpquit(m, mci, e); 134058820Seric } 134158820Seric if (rcode != EX_OK && *curhost != '\0') 134258820Seric { 134358820Seric /* try next MX site */ 134458820Seric goto tryhost; 134558820Seric } 134658820Seric } 134758820Seric #else /* not SMTP */ 134858820Seric { 134958820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 135058820Seric rcode = EX_CONFIG; 135158820Seric goto give_up; 135258820Seric } 135358820Seric #endif /* SMTP */ 135458820Seric #ifdef NAMED_BIND 135558820Seric if (ConfigLevel < 2) 135658820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 135758820Seric #endif 135858820Seric 135958820Seric /* arrange a return receipt if requested */ 136058820Seric if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) 136158820Seric { 136258820Seric e->e_flags |= EF_SENDRECEIPT; 136358820Seric /* do we want to send back more info? */ 136458820Seric } 136558820Seric 136658820Seric /* 136758820Seric ** Do final status disposal. 136858820Seric ** We check for something in tobuf for the SMTP case. 136958820Seric ** If we got a temporary failure, arrange to queue the 137058820Seric ** addressees. 137158820Seric */ 137258820Seric 137358820Seric give_up: 137458820Seric if (tobuf[0] != '\0') 137558820Seric giveresponse(rcode, m, mci, e); 137658820Seric for (to = tochain; to != NULL; to = to->q_tchain) 137758820Seric { 137858820Seric if (rcode != EX_OK) 137958820Seric markfailure(e, to, rcode); 138058820Seric else 138158820Seric { 138258820Seric to->q_flags |= QSENT; 138358820Seric e->e_nsent++; 138458820Seric } 138558820Seric } 138658820Seric 138758820Seric /* 138858820Seric ** Restore state and return. 138958820Seric */ 139058820Seric 139158820Seric errno = 0; 139258820Seric define('g', (char *) NULL, e); 139358820Seric return (rcode); 1394294Seric } 1395294Seric /* 139658820Seric ** MARKFAILURE -- mark a failure on a specific address. 139758820Seric ** 139858820Seric ** Parameters: 139958820Seric ** e -- the envelope we are sending. 140058820Seric ** q -- the address to mark. 140158820Seric ** rcode -- the code signifying the particular failure. 140258820Seric ** 140358820Seric ** Returns: 140458820Seric ** none. 140558820Seric ** 140658820Seric ** Side Effects: 140758820Seric ** marks the address (and possibly the envelope) with the 140858820Seric ** failure so that an error will be returned or 140958820Seric ** the message will be queued, as appropriate. 141058820Seric */ 141158820Seric 141258820Seric markfailure(e, q, rcode) 141358820Seric register ENVELOPE *e; 141458820Seric register ADDRESS *q; 141558820Seric int rcode; 141658820Seric { 141758820Seric char buf[MAXLINE]; 141858820Seric extern char *pintvl(); 141958820Seric 142058820Seric if (rcode == EX_OK) 142158820Seric return; 142258820Seric else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) 142358820Seric q->q_flags |= QBADADDR; 142458820Seric else if (curtime() > e->e_ctime + TimeOuts.to_q_return) 142558820Seric { 142658820Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 142758820Seric { 142858820Seric (void) sprintf(buf, "Cannot send message for %s", 142958820Seric pintvl(TimeOuts.to_q_return, FALSE)); 143058820Seric if (e->e_message != NULL) 143158820Seric free(e->e_message); 143258820Seric e->e_message = newstr(buf); 143358820Seric message(buf); 143458820Seric } 143558820Seric q->q_flags |= QBADADDR; 143658820Seric e->e_flags |= EF_TIMEOUT; 143758820Seric fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); 143858820Seric } 143958820Seric else 144058820Seric { 144158820Seric q->q_flags |= QQUEUEUP; 144258820Seric if (TimeOuts.to_q_warning > 0 && 144358820Seric curtime() > e->e_ctime + TimeOuts.to_q_warning) 144458820Seric { 144558820Seric if (!bitset(EF_WARNING, e->e_flags) && 144658820Seric e->e_class >= 0) 144758820Seric { 144858820Seric (void) sprintf(buf, 144958820Seric "warning: cannot send message for %s", 145058820Seric pintvl(TimeOuts.to_q_warning, FALSE)); 145158820Seric if (e->e_message != NULL) 145258820Seric free(e->e_message); 145358820Seric e->e_message = newstr(buf); 145458820Seric message(buf); 145558820Seric e->e_flags |= EF_WARNING|EF_TIMEOUT; 145658820Seric } 145758820Seric fprintf(e->e_xfp, 145858820Seric "%s... Warning: message still undelivered after %s\n", 145958820Seric q->q_paddr, pintvl(TimeOuts.to_q_warning, FALSE)); 146058820Seric fprintf(e->e_xfp, "Will keep trying until message is %s old\n", 146158820Seric pintvl(TimeOuts.to_q_return, FALSE)); 146258820Seric } 146358820Seric } 146458820Seric } 146558820Seric /* 146658820Seric ** ENDMAILER -- Wait for mailer to terminate. 146758820Seric ** 146858820Seric ** We should never get fatal errors (e.g., segmentation 146958820Seric ** violation), so we report those specially. For other 147058820Seric ** errors, we choose a status message (into statmsg), 147158820Seric ** and if it represents an error, we print it. 147258820Seric ** 147358820Seric ** Parameters: 147458820Seric ** pid -- pid of mailer. 147558820Seric ** e -- the current envelope. 147658820Seric ** pv -- the parameter vector that invoked the mailer 147758820Seric ** (for error messages). 147858820Seric ** 147958820Seric ** Returns: 148058820Seric ** exit code of mailer. 148158820Seric ** 148258820Seric ** Side Effects: 148358820Seric ** none. 148458820Seric */ 148558820Seric 148658820Seric endmailer(mci, e, pv) 148758820Seric register MCI *mci; 148858820Seric register ENVELOPE *e; 148958820Seric char **pv; 149058820Seric { 149158820Seric int st; 149258820Seric 149358820Seric /* close any connections */ 149458820Seric if (mci->mci_in != NULL) 149558820Seric (void) xfclose(mci->mci_in, pv[0], "mci_in"); 149658820Seric if (mci->mci_out != NULL) 149758820Seric (void) xfclose(mci->mci_out, pv[0], "mci_out"); 149858820Seric mci->mci_in = mci->mci_out = NULL; 149958820Seric mci->mci_state = MCIS_CLOSED; 150058820Seric 150158820Seric /* in the IPC case there is nothing to wait for */ 150258820Seric if (mci->mci_pid == 0) 150358820Seric return (EX_OK); 150458820Seric 150558820Seric /* wait for the mailer process to die and collect status */ 150658820Seric st = waitfor(mci->mci_pid); 150758820Seric if (st == -1) 150858820Seric { 150958820Seric syserr("endmailer %s: wait", pv[0]); 151058820Seric return (EX_SOFTWARE); 151158820Seric } 151258820Seric 151358820Seric /* see if it died a horrid death */ 151458820Seric if ((st & 0377) != 0) 151558820Seric { 151658820Seric syserr("mailer %s died with signal %o", pv[0], st); 151758820Seric 151858820Seric /* log the arguments */ 151958820Seric if (e->e_xfp != NULL) 152058820Seric { 152158820Seric register char **av; 152258820Seric 152358820Seric fprintf(e->e_xfp, "Arguments:"); 152458820Seric for (av = pv; *av != NULL; av++) 152558820Seric fprintf(e->e_xfp, " %s", *av); 152658820Seric fprintf(e->e_xfp, "\n"); 152758820Seric } 152858820Seric 152958820Seric ExitStat = EX_TEMPFAIL; 153058820Seric return (EX_TEMPFAIL); 153158820Seric } 153258820Seric 153358820Seric /* normal death -- return status */ 153458820Seric st = (st >> 8) & 0377; 153558820Seric return (st); 153658820Seric } 153758820Seric /* 1538294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1539294Seric ** 1540294Seric ** Parameters: 1541294Seric ** stat -- the status code from the mailer (high byte 1542294Seric ** only; core dumps must have been taken care of 1543294Seric ** already). 154458337Seric ** m -- the mailer info for this mailer. 154558337Seric ** mci -- the mailer connection info -- can be NULL if the 154658337Seric ** response is given before the connection is made. 154758337Seric ** e -- the current envelope. 1548294Seric ** 1549294Seric ** Returns: 15504082Seric ** none. 1551294Seric ** 1552294Seric ** Side Effects: 15531518Seric ** Errors may be incremented. 1554294Seric ** ExitStat may be set. 1555294Seric */ 1556294Seric 155758337Seric giveresponse(stat, m, mci, e) 1558294Seric int stat; 15599370Seric register MAILER *m; 156058337Seric register MCI *mci; 156110105Seric ENVELOPE *e; 1562294Seric { 1563294Seric register char *statmsg; 1564294Seric extern char *SysExMsg[]; 1565294Seric register int i; 156636788Sbostic extern int N_SysEx; 156736788Sbostic #ifdef NAMED_BIND 156836788Sbostic extern int h_errno; 156936788Sbostic #endif 157010105Seric char buf[MAXLINE]; 157158664Seric extern char *errstring(); 1572294Seric 15734315Seric /* 15744315Seric ** Compute status message from code. 15754315Seric */ 15764315Seric 1577294Seric i = stat - EX__BASE; 15789370Seric if (stat == 0) 157958852Seric { 15809370Seric statmsg = "250 Sent"; 158158916Seric if (e->e_statmsg != NULL) 158258852Seric { 158358916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 158458852Seric statmsg = buf; 158558852Seric } 158658852Seric } 15879370Seric else if (i < 0 || i > N_SysEx) 15889370Seric { 15899370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 15909370Seric stat = EX_UNAVAILABLE; 15919370Seric statmsg = buf; 15929370Seric } 159310105Seric else if (stat == EX_TEMPFAIL) 159410105Seric { 159558664Seric (void) strcpy(buf, SysExMsg[i] + 1); 159636788Sbostic #ifdef NAMED_BIND 159725527Smiriam if (h_errno == TRY_AGAIN) 159825527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 159921061Seric else 160036788Sbostic #endif 160121061Seric { 160225527Smiriam if (errno != 0) 160325527Smiriam statmsg = errstring(errno); 160425527Smiriam else 160525527Smiriam { 160621061Seric #ifdef SMTP 160725527Smiriam extern char SmtpError[]; 160821061Seric 160925527Smiriam statmsg = SmtpError; 161056795Seric #else /* SMTP */ 161125527Smiriam statmsg = NULL; 161256795Seric #endif /* SMTP */ 161325527Smiriam } 161421061Seric } 161521061Seric if (statmsg != NULL && statmsg[0] != '\0') 161621061Seric { 161710124Seric (void) strcat(buf, ": "); 161821061Seric (void) strcat(buf, statmsg); 161910105Seric } 162010105Seric statmsg = buf; 162110105Seric } 1622294Seric else 162321061Seric { 1624294Seric statmsg = SysExMsg[i]; 162558664Seric if (*statmsg++ == ':') 162658664Seric { 162758664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 162858664Seric statmsg = buf; 162958664Seric } 163021061Seric } 16319370Seric 16329370Seric /* 16339370Seric ** Print the message as appropriate 16349370Seric */ 16359370Seric 163610105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 163758524Seric message(&statmsg[4], errstring(errno)); 1638294Seric else 1639294Seric { 16401518Seric Errors++; 164158524Seric usrerr(statmsg, errstring(errno)); 1642294Seric } 1643294Seric 1644294Seric /* 1645294Seric ** Final cleanup. 1646294Seric ** Log a record of the transaction. Compute the new 1647294Seric ** ExitStat -- if we already had an error, stick with 1648294Seric ** that. 1649294Seric */ 1650294Seric 165158020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 165258337Seric logdelivery(m, mci, &statmsg[4], e); 16537858Seric 16544621Seric if (stat != EX_TEMPFAIL) 16554621Seric setstat(stat); 165610105Seric if (stat != EX_OK) 165710105Seric { 165810105Seric if (e->e_message != NULL) 165910105Seric free(e->e_message); 166010105Seric e->e_message = newstr(&statmsg[4]); 166110105Seric } 166210124Seric errno = 0; 166336788Sbostic #ifdef NAMED_BIND 166425527Smiriam h_errno = 0; 166536788Sbostic #endif 1666294Seric } 1667294Seric /* 16688496Seric ** LOGDELIVERY -- log the delivery in the system log 16698496Seric ** 16708496Seric ** Parameters: 167158337Seric ** m -- the mailer info. Can be NULL for initial queue. 167258337Seric ** mci -- the mailer connection info -- can be NULL if the 167358337Seric ** log is occuring when no connection is active. 167458337Seric ** stat -- the message to print for the status. 167558337Seric ** e -- the current envelope. 16768496Seric ** 16778496Seric ** Returns: 16788496Seric ** none 16798496Seric ** 16808496Seric ** Side Effects: 16818496Seric ** none 16828496Seric */ 16838496Seric 168458337Seric logdelivery(m, mci, stat, e) 168558337Seric MAILER *m; 168658337Seric register MCI *mci; 16878496Seric char *stat; 168854967Seric register ENVELOPE *e; 16898496Seric { 169058343Seric # ifdef LOG 169158337Seric char *curhost; 169258418Seric char buf[512]; 16938496Seric extern char *pintvl(); 169458343Seric extern char *macvalue(); 16958496Seric 169658513Seric (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 169758337Seric 169858513Seric if (m != NULL) 169958305Seric { 170058513Seric (void) strcat(buf, ", mailer="); 170158513Seric (void) strcat(buf, m->m_name); 170258305Seric } 170358513Seric 170458513Seric if (mci != NULL && mci->mci_host != NULL) 170558305Seric { 170658305Seric # ifdef DAEMON 170758755Seric extern SOCKADDR CurHostAddr; 170858755Seric extern char *anynet_ntoa(); 170958513Seric # endif 171058305Seric 171158513Seric (void) strcat(buf, ", relay="); 171258513Seric (void) strcat(buf, mci->mci_host); 171358513Seric 171458513Seric # ifdef DAEMON 171558513Seric (void) strcat(buf, " ("); 171658755Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 171758513Seric (void) strcat(buf, ")"); 171858305Seric # endif 171958305Seric } 172058343Seric else 172158513Seric { 172258513Seric char *p = macvalue('h', e); 172358343Seric 172458513Seric if (p != NULL && p[0] != '\0') 172558513Seric { 172658513Seric (void) strcat(buf, ", relay="); 172758513Seric (void) strcat(buf, p); 172858513Seric } 172958513Seric } 173058418Seric 173158418Seric syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", 173258418Seric e->e_id, e->e_to, buf, stat); 173356795Seric # endif /* LOG */ 17348496Seric } 17358496Seric /* 17366974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1737294Seric ** 17386974Seric ** This can be made an arbitrary message separator by changing $l 1739294Seric ** 174016150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 174116150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 174216150Seric ** does a well-meaning programmer such as myself have to deal with 174316150Seric ** this kind of antique garbage???? 17446974Seric ** 1745294Seric ** Parameters: 17466974Seric ** fp -- the file to output to. 17476974Seric ** m -- the mailer describing this entry. 1748294Seric ** 1749294Seric ** Returns: 17506974Seric ** none 1751294Seric ** 1752294Seric ** Side Effects: 17536974Seric ** outputs some text to fp. 1754294Seric */ 1755294Seric 175654967Seric putfromline(fp, m, e) 17576974Seric register FILE *fp; 17586974Seric register MAILER *m; 175954967Seric ENVELOPE *e; 1760294Seric { 176158050Seric char *template = "\201l\n"; 17626974Seric char buf[MAXLINE]; 1763294Seric 176410682Seric if (bitnset(M_NHDR, m->m_flags)) 17656974Seric return; 17664315Seric 17676974Seric # ifdef UGLYUUCP 176810682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 17694205Seric { 177012223Seric char *bang; 177112223Seric char xbuf[MAXLINE]; 17726041Seric 177358680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 177456795Seric bang = strchr(buf, '!'); 17756974Seric if (bang == NULL) 177658151Seric syserr("554 No ! in UUCP! (%s)", buf); 17775099Seric else 17789370Seric { 177912223Seric *bang++ = '\0'; 178058050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 178112223Seric template = xbuf; 17829370Seric } 17836974Seric } 178456795Seric # endif /* UGLYUUCP */ 178554967Seric expand(template, buf, &buf[sizeof buf - 1], e); 178610168Seric putline(buf, fp, m); 17875981Seric } 17885981Seric /* 17896974Seric ** PUTBODY -- put the body of a message. 17906974Seric ** 17916974Seric ** Parameters: 17926974Seric ** fp -- file to output onto. 179310168Seric ** m -- a mailer descriptor to control output format. 17949538Seric ** e -- the envelope to put out. 179559730Seric ** separator -- if non-NULL, a message separator that must 179659730Seric ** not be permitted in the resulting message. 17976974Seric ** 17986974Seric ** Returns: 17996974Seric ** none. 18006974Seric ** 18016974Seric ** Side Effects: 18026974Seric ** The message is written onto fp. 18036974Seric */ 18046974Seric 180559730Seric putbody(fp, m, e, separator) 18066974Seric FILE *fp; 18079370Seric MAILER *m; 18089538Seric register ENVELOPE *e; 180959730Seric char *separator; 18106974Seric { 181110168Seric char buf[MAXLINE]; 18126974Seric 18136974Seric /* 18146974Seric ** Output the body of the message 18156974Seric */ 18166974Seric 18179538Seric if (e->e_dfp == NULL) 18186974Seric { 18199538Seric if (e->e_df != NULL) 18209538Seric { 18219538Seric e->e_dfp = fopen(e->e_df, "r"); 18229538Seric if (e->e_dfp == NULL) 182340931Srick syserr("putbody: Cannot open %s for %s from %s", 182440931Srick e->e_df, e->e_to, e->e_from); 18259538Seric } 18269538Seric else 182710168Seric putline("<<< No Message Collected >>>", fp, m); 18289538Seric } 18299538Seric if (e->e_dfp != NULL) 18309538Seric { 18319538Seric rewind(e->e_dfp); 183210168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 183316875Seric { 183416875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 183540995Sbostic strncmp(buf, "From ", 5) == 0) 183623102Seric (void) putc('>', fp); 183759730Seric if (buf[0] == '-' && buf[1] == '-' && separator != NULL) 183859730Seric { 183959730Seric /* possible separator */ 184059730Seric int sl = strlen(separator); 184159730Seric 184259730Seric if (strncmp(&buf[2], separator, sl) == 0) 184359730Seric (void) putc(' ', fp); 184459730Seric } 184510168Seric putline(buf, fp, m); 184616875Seric } 18476974Seric 18489538Seric if (ferror(e->e_dfp)) 18496974Seric { 18506974Seric syserr("putbody: read error"); 18516974Seric ExitStat = EX_IOERR; 18526974Seric } 18536974Seric } 18546974Seric 185559542Seric /* some mailers want extra blank line at end of message */ 185659542Seric if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n') 185759542Seric putline("", fp, m); 185859542Seric 18596974Seric (void) fflush(fp); 18606974Seric if (ferror(fp) && errno != EPIPE) 18616974Seric { 18626974Seric syserr("putbody: write error"); 18636974Seric ExitStat = EX_IOERR; 18646974Seric } 18656974Seric errno = 0; 18666974Seric } 18676974Seric /* 1868294Seric ** MAILFILE -- Send a message to a file. 1869294Seric ** 18704327Seric ** If the file has the setuid/setgid bits set, but NO execute 18714327Seric ** bits, sendmail will try to become the owner of that file 18724327Seric ** rather than the real user. Obviously, this only works if 18734327Seric ** sendmail runs as root. 18744327Seric ** 18759370Seric ** This could be done as a subordinate mailer, except that it 18769370Seric ** is used implicitly to save messages in ~/dead.letter. We 18779370Seric ** view this as being sufficiently important as to include it 18789370Seric ** here. For example, if the system is dying, we shouldn't have 18799370Seric ** to create another process plus some pipes to save the message. 18809370Seric ** 1881294Seric ** Parameters: 1882294Seric ** filename -- the name of the file to send to. 18834397Seric ** ctladdr -- the controlling address header -- includes 18844397Seric ** the userid/groupid to be when sending. 1885294Seric ** 1886294Seric ** Returns: 1887294Seric ** The exit code associated with the operation. 1888294Seric ** 1889294Seric ** Side Effects: 1890294Seric ** none. 1891294Seric */ 1892294Seric 189354967Seric mailfile(filename, ctladdr, e) 1894294Seric char *filename; 18954397Seric ADDRESS *ctladdr; 189654967Seric register ENVELOPE *e; 1897294Seric { 1898294Seric register FILE *f; 18994214Seric register int pid; 190053751Seric int mode; 1901294Seric 190259267Seric if (tTd(11, 1)) 190359267Seric { 190459267Seric printf("mailfile %s\n ctladdr=", filename); 190559267Seric printaddr(ctladdr, FALSE); 190659267Seric } 190759267Seric 19084214Seric /* 19094214Seric ** Fork so we can change permissions here. 19104214Seric ** Note that we MUST use fork, not vfork, because of 19114214Seric ** the complications of calling subroutines, etc. 19124214Seric */ 19134067Seric 19144214Seric DOFORK(fork); 19154214Seric 19164214Seric if (pid < 0) 19174214Seric return (EX_OSERR); 19184214Seric else if (pid == 0) 19194214Seric { 19204214Seric /* child -- actually write to file */ 19214327Seric struct stat stb; 19224327Seric 19234215Seric (void) signal(SIGINT, SIG_DFL); 19244215Seric (void) signal(SIGHUP, SIG_DFL); 19254215Seric (void) signal(SIGTERM, SIG_DFL); 192623102Seric (void) umask(OldUmask); 192752673Seric 19284327Seric if (stat(filename, &stb) < 0) 192959745Seric stb.st_mode = FileMode; 193053751Seric mode = stb.st_mode; 193152673Seric 193252673Seric /* limit the errors to those actually caused in the child */ 193352673Seric errno = 0; 193452673Seric ExitStat = EX_OK; 193552673Seric 19364327Seric if (bitset(0111, stb.st_mode)) 19374327Seric exit(EX_CANTCREAT); 19384401Seric if (ctladdr == NULL) 193940931Srick ctladdr = &e->e_from; 194053751Seric else 194153751Seric { 194253751Seric /* ignore setuid and setgid bits */ 194353751Seric mode &= ~(S_ISGID|S_ISUID); 194453751Seric } 194553751Seric 194640931Srick /* we have to open the dfile BEFORE setuid */ 194753751Seric if (e->e_dfp == NULL && e->e_df != NULL) 194840931Srick { 194940931Srick e->e_dfp = fopen(e->e_df, "r"); 195052673Seric if (e->e_dfp == NULL) 195152673Seric { 195240931Srick syserr("mailfile: Cannot open %s for %s from %s", 195353751Seric e->e_df, e->e_to, e->e_from); 195440931Srick } 195540931Srick } 195640931Srick 195753751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 19584417Seric { 195952673Seric if (ctladdr->q_uid == 0) 196052673Seric { 19614417Seric (void) setgid(DefGid); 196240972Sbostic (void) initgroups(DefUser, DefGid); 196352673Seric } 196452673Seric else 196552673Seric { 19664417Seric (void) setgid(ctladdr->q_gid); 196753751Seric (void) initgroups(ctladdr->q_ruser ? 196853751Seric ctladdr->q_ruser : ctladdr->q_user, 196940972Sbostic ctladdr->q_gid); 197040972Sbostic } 19714417Seric } 197253751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 19734417Seric { 19744417Seric if (ctladdr->q_uid == 0) 19754417Seric (void) setuid(DefUid); 19764417Seric else 19774417Seric (void) setuid(ctladdr->q_uid); 19784417Seric } 197952673Seric FileName = filename; 198052673Seric LineNumber = 0; 198159745Seric f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); 19824214Seric if (f == NULL) 198352673Seric { 198458151Seric message("554 cannot open"); 19854214Seric exit(EX_CANTCREAT); 198652673Seric } 19874214Seric 198859275Seric putfromline(f, FileMailer, e); 198959275Seric (*e->e_puthdr)(f, FileMailer, e); 199059275Seric putline("\n", f, FileMailer); 199159730Seric (*e->e_putbody)(f, FileMailer, e, NULL); 199259275Seric putline("\n", f, FileMailer); 199352673Seric if (ferror(f)) 199452673Seric { 199558151Seric message("451 I/O error"); 199652673Seric setstat(EX_IOERR); 199752673Seric } 199858680Seric (void) xfclose(f, "mailfile", filename); 19994214Seric (void) fflush(stdout); 20004417Seric 20016887Seric /* reset ISUID & ISGID bits for paranoid systems */ 20024621Seric (void) chmod(filename, (int) stb.st_mode); 200352673Seric exit(ExitStat); 20044315Seric /*NOTREACHED*/ 20054214Seric } 20064214Seric else 20074214Seric { 20084214Seric /* parent -- wait for exit status */ 20099370Seric int st; 20104214Seric 20119370Seric st = waitfor(pid); 20129370Seric if ((st & 0377) != 0) 20139370Seric return (EX_UNAVAILABLE); 20149370Seric else 20159370Seric return ((st >> 8) & 0377); 201640931Srick /*NOTREACHED*/ 20174214Seric } 2018294Seric } 20194550Seric /* 202057454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 202157454Seric ** 202257454Seric ** The signature describes how we are going to send this -- it 202357454Seric ** can be just the hostname (for non-Internet hosts) or can be 202457454Seric ** an ordered list of MX hosts. 202557454Seric ** 202657454Seric ** Parameters: 202757454Seric ** m -- the mailer describing this host. 202857454Seric ** host -- the host name. 202957454Seric ** e -- the current envelope. 203057454Seric ** 203157454Seric ** Returns: 203257454Seric ** The signature for this host. 203357454Seric ** 203457454Seric ** Side Effects: 203557454Seric ** Can tweak the symbol table. 203657454Seric */ 203757454Seric 203857454Seric char * 203957454Seric hostsignature(m, host, e) 204057454Seric register MAILER *m; 204157454Seric char *host; 204257454Seric ENVELOPE *e; 204357454Seric { 204457454Seric register char *p; 204557454Seric register STAB *s; 204657454Seric int i; 204757454Seric int len; 204857454Seric #ifdef NAMED_BIND 204957454Seric int nmx; 205057454Seric auto int rcode; 205159076Seric char *hp; 205259076Seric char *endp; 205359111Seric int oldoptions; 205457454Seric char *mxhosts[MAXMXHOSTS + 1]; 205557454Seric #endif 205657454Seric 205757454Seric /* 205857454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 205957454Seric */ 206057454Seric 206157454Seric p = m->m_mailer; 206257454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 206357454Seric { 206457454Seric /* just an ordinary mailer */ 206557454Seric return host; 206657454Seric } 206757454Seric 206857454Seric /* 206957454Seric ** If it is a numeric address, just return it. 207057454Seric */ 207157454Seric 207257454Seric if (host[0] == '[') 207357454Seric return host; 207457454Seric 207557454Seric /* 207657454Seric ** Look it up in the symbol table. 207757454Seric */ 207857454Seric 207957454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 208057454Seric if (s->s_hostsig != NULL) 208157454Seric return s->s_hostsig; 208257454Seric 208357454Seric /* 208457454Seric ** Not already there -- create a signature. 208557454Seric */ 208657454Seric 208757454Seric #ifdef NAMED_BIND 208859111Seric if (ConfigLevel < 2) 208959111Seric { 209059111Seric oldoptions = _res.options; 209159111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 209259111Seric } 209359111Seric 209459076Seric for (hp = host; hp != NULL; hp = endp) 209557454Seric { 209659076Seric endp = strchr(hp, ':'); 209759076Seric if (endp != NULL) 209859076Seric *endp = '\0'; 209957454Seric 210059273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 210157454Seric 210259076Seric if (nmx <= 0) 210359076Seric { 210459076Seric register MCI *mci; 210559076Seric extern int errno; 210659076Seric extern MCI *mci_get(); 210757454Seric 210859076Seric /* update the connection info for this host */ 210959076Seric mci = mci_get(hp, m); 211059076Seric mci->mci_exitstat = rcode; 211159076Seric mci->mci_errno = errno; 211259076Seric 211359076Seric /* and return the original host name as the signature */ 211459076Seric nmx = 1; 211559076Seric mxhosts[0] = hp; 211659076Seric } 211759076Seric 211859076Seric len = 0; 211959076Seric for (i = 0; i < nmx; i++) 212059076Seric { 212159076Seric len += strlen(mxhosts[i]) + 1; 212259076Seric } 212359076Seric if (s->s_hostsig != NULL) 212459076Seric len += strlen(s->s_hostsig) + 1; 212559076Seric p = xalloc(len); 212659076Seric if (s->s_hostsig != NULL) 212759076Seric { 212859076Seric (void) strcpy(p, s->s_hostsig); 212959076Seric free(s->s_hostsig); 213059076Seric s->s_hostsig = p; 213159076Seric p += strlen(p); 213257454Seric *p++ = ':'; 213359076Seric } 213459076Seric else 213559076Seric s->s_hostsig = p; 213659076Seric for (i = 0; i < nmx; i++) 213759076Seric { 213859076Seric if (i != 0) 213959076Seric *p++ = ':'; 214059076Seric strcpy(p, mxhosts[i]); 214159076Seric p += strlen(p); 214259076Seric } 214359076Seric if (endp != NULL) 214459076Seric *endp++ = ':'; 214557454Seric } 214657454Seric makelower(s->s_hostsig); 214759111Seric if (ConfigLevel < 2) 214859111Seric _res.options = oldoptions; 214957454Seric #else 215057454Seric /* not using BIND -- the signature is just the host name */ 215157454Seric s->s_hostsig = host; 215257454Seric #endif 215357454Seric if (tTd(17, 1)) 215457454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 215557454Seric return s->s_hostsig; 215657454Seric } 2157