122701Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 362523Sbostic * Copyright (c) 1988, 1993 462523Sbostic * The Regents of the University of California. All rights reserved. 533728Sbostic * 642825Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822701Sdist 922701Sdist #ifndef lint 10*63753Seric static char sccsid[] = "@(#)deliver.c 8.2 (Berkeley) 07/11/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> 20*63753Seric 21*63753Seric extern int h_errno; 2235651Seric #endif 23294Seric 24294Seric /* 2558820Seric ** SENDALL -- actually send all the messages. 2658820Seric ** 2758820Seric ** Parameters: 2858820Seric ** e -- the envelope to send. 2958820Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 3058820Seric ** the current e->e_sendmode. 3158820Seric ** 3258820Seric ** Returns: 3358820Seric ** none. 3458820Seric ** 3558820Seric ** Side Effects: 3658820Seric ** Scans the send lists and sends everything it finds. 3758820Seric ** Delivers any appropriate error messages. 3858820Seric ** If we are running in a non-interactive mode, takes the 3958820Seric ** appropriate action. 4058820Seric */ 4158820Seric 4258820Seric sendall(e, mode) 4358820Seric ENVELOPE *e; 4458820Seric char mode; 4558820Seric { 4658820Seric register ADDRESS *q; 4758820Seric char *owner; 4858820Seric int otherowners; 4958820Seric register ENVELOPE *ee; 5058820Seric ENVELOPE *splitenv = NULL; 5158929Seric bool announcequeueup; 5258820Seric 5361092Seric if (bitset(EF_FATALERRS, e->e_flags)) 5461092Seric { 5561092Seric /* this will get a return message -- so don't send it */ 5661092Seric e->e_flags |= EF_CLRQUEUE; 5761092Seric return; 5861092Seric } 5961092Seric 6058820Seric /* determine actual delivery mode */ 6158820Seric if (mode == SM_DEFAULT) 6258820Seric { 6358820Seric mode = e->e_sendmode; 6458820Seric if (mode != SM_VERIFY && 6558820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 6658820Seric mode = SM_QUEUE; 6758929Seric announcequeueup = mode == SM_QUEUE; 6858820Seric } 6958929Seric else 7058929Seric announcequeueup = FALSE; 7158820Seric 7258820Seric if (tTd(13, 1)) 7358820Seric { 7458820Seric printf("\nSENDALL: mode %c, e_from ", mode); 7558820Seric printaddr(&e->e_from, FALSE); 7658820Seric printf("sendqueue:\n"); 7758820Seric printaddr(e->e_sendqueue, TRUE); 7858820Seric } 7958820Seric 8058820Seric /* 8158820Seric ** Do any preprocessing necessary for the mode we are running. 8258820Seric ** Check to make sure the hop count is reasonable. 8358820Seric ** Delete sends to the sender in mailing lists. 8458820Seric */ 8558820Seric 8658820Seric CurEnv = e; 8758820Seric 8858820Seric if (e->e_hopcount > MaxHopCount) 8958820Seric { 9058820Seric errno = 0; 9158820Seric syserr("554 too many hops %d (%d max): from %s, to %s", 9258820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 9358820Seric e->e_sendqueue->q_paddr); 9458820Seric return; 9558820Seric } 9658820Seric 9759435Seric /* 9859435Seric ** Do sender deletion. 9959435Seric ** 10059435Seric ** If the sender has the QQUEUEUP flag set, skip this. 10159435Seric ** This can happen if the name server is hosed when you 10259435Seric ** are trying to send mail. The result is that the sender 10359435Seric ** is instantiated in the queue as a recipient. 10459435Seric */ 10559435Seric 10659435Seric if (!MeToo && !bitset(QQUEUEUP, e->e_from.q_flags)) 10758820Seric { 10858820Seric if (tTd(13, 5)) 10958820Seric { 11058820Seric printf("sendall: QDONTSEND "); 11158820Seric printaddr(&e->e_from, FALSE); 11258820Seric } 11358820Seric e->e_from.q_flags |= QDONTSEND; 11458820Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 11558820Seric } 11658820Seric 11758820Seric /* 11858820Seric ** Handle alias owners. 11958820Seric ** 12058820Seric ** We scan up the q_alias chain looking for owners. 12158820Seric ** We discard owners that are the same as the return path. 12258820Seric */ 12358820Seric 12458820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12558820Seric { 12658820Seric register struct address *a; 12758820Seric 12858820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 12958820Seric continue; 13058820Seric if (a != NULL) 13158820Seric q->q_owner = a->q_owner; 13258820Seric 13358820Seric if (q->q_owner != NULL && 13458820Seric !bitset(QDONTSEND, q->q_flags) && 13558820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 13658820Seric q->q_owner = NULL; 13758820Seric } 13858820Seric 13958820Seric owner = ""; 14058820Seric otherowners = 1; 14158820Seric while (owner != NULL && otherowners > 0) 14258820Seric { 14358820Seric owner = NULL; 14458820Seric otherowners = 0; 14558820Seric 14658820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14758820Seric { 14858820Seric if (bitset(QDONTSEND, q->q_flags)) 14958820Seric continue; 15058820Seric 15158820Seric if (q->q_owner != NULL) 15258820Seric { 15358820Seric if (owner == NULL) 15458820Seric owner = q->q_owner; 15558820Seric else if (owner != q->q_owner) 15658820Seric { 15758820Seric if (strcmp(owner, q->q_owner) == 0) 15858820Seric { 15958820Seric /* make future comparisons cheap */ 16058820Seric q->q_owner = owner; 16158820Seric } 16258820Seric else 16358820Seric { 16458820Seric otherowners++; 16558820Seric } 16658820Seric owner = q->q_owner; 16758820Seric } 16858820Seric } 16958820Seric else 17058820Seric { 17158820Seric otherowners++; 17258820Seric } 17358820Seric } 17458820Seric 17558820Seric if (owner != NULL && otherowners > 0) 17658820Seric { 17758820Seric extern HDR *copyheader(); 17858820Seric extern ADDRESS *copyqueue(); 17958820Seric 18058820Seric /* 18158820Seric ** Split this envelope into two. 18258820Seric */ 18358820Seric 18458820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 18558820Seric *ee = *e; 18658820Seric ee->e_id = NULL; 18758820Seric (void) queuename(ee, '\0'); 18858820Seric 18958820Seric if (tTd(13, 1)) 19058820Seric printf("sendall: split %s into %s\n", 19158820Seric e->e_id, ee->e_id); 19258820Seric 19358820Seric ee->e_header = copyheader(e->e_header); 19458820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 19558820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 19658916Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); 19758820Seric setsender(owner, ee, NULL, TRUE); 19858820Seric if (tTd(13, 5)) 19958820Seric { 20058820Seric printf("sendall(split): QDONTSEND "); 20158820Seric printaddr(&ee->e_from, FALSE); 20258820Seric } 20358820Seric ee->e_from.q_flags |= QDONTSEND; 20458820Seric ee->e_dfp = NULL; 20558820Seric ee->e_xfp = NULL; 20658820Seric ee->e_lockfp = NULL; 20758820Seric ee->e_df = NULL; 20858820Seric ee->e_errormode = EM_MAIL; 20958820Seric ee->e_sibling = splitenv; 21058820Seric splitenv = ee; 21158820Seric 21258820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 21358820Seric if (q->q_owner == owner) 21458820Seric q->q_flags |= QDONTSEND; 21558820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 21658820Seric if (q->q_owner != owner) 21758820Seric q->q_flags |= QDONTSEND; 21858820Seric 21958820Seric if (e->e_df != NULL && mode != SM_VERIFY) 22058820Seric { 22158820Seric ee->e_dfp = NULL; 22258820Seric ee->e_df = newstr(queuename(ee, 'd')); 22358820Seric if (link(e->e_df, ee->e_df) < 0) 22458820Seric { 22558820Seric syserr("sendall: link(%s, %s)", 22658820Seric e->e_df, ee->e_df); 22758820Seric } 22858820Seric } 22958820Seric 23058820Seric if (mode != SM_VERIFY) 23158820Seric openxscript(ee); 23258820Seric #ifdef LOG 23358820Seric if (LogLevel > 4) 23458820Seric syslog(LOG_INFO, "%s: clone %s", 23558820Seric ee->e_id, e->e_id); 23658820Seric #endif 23758820Seric } 23858820Seric } 23958820Seric 24058820Seric if (owner != NULL) 24158820Seric { 24258820Seric setsender(owner, e, NULL, TRUE); 24358820Seric if (tTd(13, 5)) 24458820Seric { 24558820Seric printf("sendall(owner): QDONTSEND "); 24658820Seric printaddr(&e->e_from, FALSE); 24758820Seric } 24858820Seric e->e_from.q_flags |= QDONTSEND; 24958820Seric e->e_errormode = EM_MAIL; 25058820Seric } 25158820Seric 25258916Seric # ifdef QUEUE 25358916Seric if ((mode == SM_QUEUE || mode == SM_FORK || 25458916Seric (mode != SM_VERIFY && SuperSafe)) && 25558916Seric !bitset(EF_INQUEUE, e->e_flags)) 25658916Seric { 25758916Seric /* be sure everything is instantiated in the queue */ 25858929Seric queueup(e, TRUE, announcequeueup); 25958916Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 26058929Seric queueup(ee, TRUE, announcequeueup); 26158916Seric } 26258916Seric #endif /* QUEUE */ 26358916Seric 26458820Seric if (splitenv != NULL) 26558820Seric { 26658820Seric if (tTd(13, 1)) 26758820Seric { 26858820Seric printf("\nsendall: Split queue; remaining queue:\n"); 26958820Seric printaddr(e->e_sendqueue, TRUE); 27058820Seric } 27158820Seric 27258820Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 27358820Seric { 27458820Seric CurEnv = ee; 27558820Seric sendenvelope(ee, mode); 27658820Seric } 27758820Seric 27858820Seric CurEnv = e; 27958820Seric } 28058820Seric sendenvelope(e, mode); 28158820Seric 28258820Seric for (; splitenv != NULL; splitenv = splitenv->e_sibling) 28358820Seric dropenvelope(splitenv); 28458820Seric } 28558820Seric 28658820Seric sendenvelope(e, mode) 28758820Seric register ENVELOPE *e; 28858820Seric char mode; 28958820Seric { 29058916Seric bool oldverbose; 29158916Seric int pid; 29258820Seric register ADDRESS *q; 29358916Seric #ifdef LOCKF 29458916Seric struct flock lfd; 29558916Seric #endif 29658820Seric 29758916Seric oldverbose = Verbose; 29858916Seric switch (mode) 29958916Seric { 30058916Seric case SM_VERIFY: 30158916Seric Verbose = TRUE; 30258916Seric break; 30358916Seric 30458916Seric case SM_QUEUE: 30558916Seric queueonly: 30658916Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 30758916Seric return; 30858916Seric 30958916Seric case SM_FORK: 31058916Seric if (e->e_xfp != NULL) 31158916Seric (void) fflush(e->e_xfp); 31258916Seric 31358916Seric # ifdef LOCKF 31458916Seric /* 31558916Seric ** Since lockf has the interesting semantic that the 31658916Seric ** lock is lost when we fork, we have to risk losing 31758916Seric ** the lock here by closing before the fork, and then 31858916Seric ** trying to get it back in the child. 31958916Seric */ 32058916Seric 32158916Seric if (e->e_lockfp != NULL) 32258916Seric { 32358916Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 32458916Seric e->e_lockfp = NULL; 32558916Seric } 32658916Seric # endif /* LOCKF */ 32758916Seric 32858916Seric pid = fork(); 32958916Seric if (pid < 0) 33058916Seric { 33158916Seric goto queueonly; 33258916Seric } 33358916Seric else if (pid > 0) 33458916Seric { 33558916Seric /* be sure we leave the temp files to our child */ 33658916Seric e->e_id = e->e_df = NULL; 33758916Seric # ifndef LOCKF 33858916Seric if (e->e_lockfp != NULL) 33958916Seric { 34058916Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 34158916Seric e->e_lockfp = NULL; 34258916Seric } 34358916Seric # endif 34458916Seric 34558916Seric /* close any random open files in the envelope */ 34658916Seric if (e->e_dfp != NULL) 34758916Seric { 34858916Seric (void) xfclose(e->e_dfp, "sendenvelope", "dfp"); 34958916Seric e->e_dfp = NULL; 35058916Seric } 35158916Seric if (e->e_xfp != NULL) 35258916Seric { 35358916Seric (void) xfclose(e->e_xfp, "sendenvelope", "xfp"); 35458916Seric e->e_xfp = NULL; 35558916Seric } 35658916Seric return; 35758916Seric } 35858916Seric 35958916Seric /* double fork to avoid zombies */ 36058916Seric if (fork() > 0) 36158916Seric exit(EX_OK); 36258916Seric 36358916Seric /* be sure we are immune from the terminal */ 36458916Seric disconnect(FALSE, e); 36558916Seric 36658916Seric # ifdef LOCKF 36758916Seric /* 36858916Seric ** Now try to get our lock back. 36958916Seric */ 37058916Seric 37158916Seric lfd.l_type = F_WRLCK; 37258916Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 37358916Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 37458916Seric if (e->e_lockfp == NULL || 37558916Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 37658916Seric { 37758916Seric /* oops.... lost it */ 37858916Seric if (tTd(13, 1)) 37958916Seric printf("sendenvelope: %s lost lock: lockfp=%x, %s\n", 38058916Seric e->e_id, e->e_lockfp, errstring(errno)); 38158916Seric 38258916Seric # ifdef LOG 38358916Seric if (LogLevel > 29) 38458916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 38558916Seric e->e_id); 38658916Seric # endif /* LOG */ 38758916Seric exit(EX_OK); 38858916Seric } 38958916Seric # endif /* LOCKF */ 39058916Seric 39158916Seric /* 39258916Seric ** Close any cached connections. 39358916Seric ** 39458916Seric ** We don't send the QUIT protocol because the parent 39558916Seric ** still knows about the connection. 39658916Seric ** 39758916Seric ** This should only happen when delivering an error 39858916Seric ** message. 39958916Seric */ 40058916Seric 40158916Seric mci_flush(FALSE, NULL); 40258916Seric 40358916Seric break; 40458916Seric } 40558916Seric 40658820Seric /* 40758820Seric ** Run through the list and send everything. 40858820Seric */ 40958820Seric 41058820Seric e->e_nsent = 0; 41158820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 41258820Seric { 41358820Seric if (mode == SM_VERIFY) 41458820Seric { 41558820Seric e->e_to = q->q_paddr; 41658820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 41760173Seric { 41860173Seric message("deliverable: mailer %s, host %s, user %s", 41960173Seric q->q_mailer->m_name, 42060173Seric q->q_host, 42160173Seric q->q_user); 42260173Seric } 42358820Seric } 42458820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 42558820Seric { 42658820Seric # ifdef QUEUE 42758820Seric /* 42858820Seric ** Checkpoint the send list every few addresses 42958820Seric */ 43058820Seric 43158820Seric if (e->e_nsent >= CheckpointInterval) 43258820Seric { 43358820Seric queueup(e, TRUE, FALSE); 43458820Seric e->e_nsent = 0; 43558820Seric } 43658820Seric # endif /* QUEUE */ 43758820Seric (void) deliver(e, q); 43858820Seric } 43958820Seric } 44058820Seric Verbose = oldverbose; 44158820Seric 44258820Seric /* 44358820Seric ** Now run through and check for errors. 44458820Seric */ 44558820Seric 44658820Seric if (mode == SM_VERIFY) 44758820Seric { 44858820Seric return; 44958820Seric } 45058820Seric 45158820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 45258820Seric { 45358820Seric if (tTd(13, 3)) 45458820Seric { 45558820Seric printf("Checking "); 45658820Seric printaddr(q, FALSE); 45758820Seric } 45858820Seric 45958820Seric /* only send errors if the message failed */ 46058916Seric if (!bitset(QBADADDR, q->q_flags) || 46158916Seric bitset(QDONTSEND, q->q_flags)) 46258820Seric continue; 46358820Seric 46458820Seric e->e_flags |= EF_FATALERRS; 46558820Seric 46658820Seric if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) 46758820Seric (void) sendtolist(e->e_from.q_paddr, NULL, 46858820Seric &e->e_errorqueue, e); 46958820Seric } 47058820Seric 47158820Seric if (mode == SM_FORK) 47258820Seric finis(); 47358820Seric } 47458820Seric /* 47558820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 47658820Seric ** 47758820Seric ** This MUST be a macro, since after a vfork we are running 47858820Seric ** two processes on the same stack!!! 47958820Seric ** 48058820Seric ** Parameters: 48158820Seric ** none. 48258820Seric ** 48358820Seric ** Returns: 48458820Seric ** From a macro??? You've got to be kidding! 48558820Seric ** 48658820Seric ** Side Effects: 48758820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 48858820Seric ** pid of child in parent, zero in child. 48958820Seric ** -1 on unrecoverable error. 49058820Seric ** 49158820Seric ** Notes: 49258820Seric ** I'm awfully sorry this looks so awful. That's 49358820Seric ** vfork for you..... 49458820Seric */ 49558820Seric 49658820Seric # define NFORKTRIES 5 49758820Seric 49858820Seric # ifndef FORK 49958820Seric # define FORK fork 50058820Seric # endif 50158820Seric 50258820Seric # define DOFORK(fORKfN) \ 50358820Seric {\ 50458820Seric register int i;\ 50558820Seric \ 50658820Seric for (i = NFORKTRIES; --i >= 0; )\ 50758820Seric {\ 50858820Seric pid = fORKfN();\ 50958820Seric if (pid >= 0)\ 51058820Seric break;\ 51158820Seric if (i > 0)\ 51258820Seric sleep((unsigned) NFORKTRIES - i);\ 51358820Seric }\ 51458820Seric } 51558820Seric /* 51658820Seric ** DOFORK -- simple fork interface to DOFORK. 51758820Seric ** 51858820Seric ** Parameters: 51958820Seric ** none. 52058820Seric ** 52158820Seric ** Returns: 52258820Seric ** pid of child in parent. 52358820Seric ** zero in child. 52458820Seric ** -1 on error. 52558820Seric ** 52658820Seric ** Side Effects: 52758820Seric ** returns twice, once in parent and once in child. 52858820Seric */ 52958820Seric 53058820Seric dofork() 53158820Seric { 53258820Seric register int pid; 53358820Seric 53458820Seric DOFORK(fork); 53558820Seric return (pid); 53658820Seric } 53758820Seric /* 5384315Seric ** DELIVER -- Deliver a message to a list of addresses. 539294Seric ** 5404315Seric ** This routine delivers to everyone on the same host as the 5414315Seric ** user on the head of the list. It is clever about mailers 5424315Seric ** that don't handle multiple users. It is NOT guaranteed 5434315Seric ** that it will deliver to all these addresses however -- so 5444315Seric ** deliver should be called once for each address on the 5454315Seric ** list. 5464315Seric ** 547294Seric ** Parameters: 5489370Seric ** e -- the envelope to deliver. 5494621Seric ** firstto -- head of the address list to deliver to. 550294Seric ** 551294Seric ** Returns: 552294Seric ** zero -- successfully delivered. 553294Seric ** else -- some failure, see ExitStat for more info. 554294Seric ** 555294Seric ** Side Effects: 556294Seric ** The standard input is passed off to someone. 557294Seric */ 558294Seric 5599370Seric deliver(e, firstto) 5609370Seric register ENVELOPE *e; 5614621Seric ADDRESS *firstto; 562294Seric { 5634452Seric char *host; /* host being sent to */ 5644452Seric char *user; /* user being sent to */ 565294Seric char **pvp; 5663233Seric register char **mvp; 5673233Seric register char *p; 56810306Seric register MAILER *m; /* mailer for this recipient */ 5694397Seric ADDRESS *ctladdr; 57054967Seric register MCI *mci; 5714621Seric register ADDRESS *to = firstto; 5724863Seric bool clever = FALSE; /* running user smtp to this mailer */ 5735032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 57451951Seric int rcode; /* response code */ 57557454Seric char *firstsig; /* signature of firstto */ 57658820Seric int pid; 57758820Seric char *curhost; 57858820Seric int mpvect[2]; 57958820Seric int rpvect[2]; 58010306Seric char *pv[MAXPV+1]; 58158704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 58210306Seric char buf[MAXNAME]; 58351951Seric char rpathbuf[MAXNAME]; /* translated return path */ 58457441Seric extern int checkcompat(); 58558820Seric extern FILE *fdopen(); 586294Seric 5874488Seric errno = 0; 58858680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 5893233Seric return (0); 590294Seric 59135651Seric #ifdef NAMED_BIND 59234022Sbostic /* unless interactive, try twice, over a minute */ 59334022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 59434022Sbostic _res.retrans = 30; 59534022Sbostic _res.retry = 2; 59634022Sbostic } 59736788Sbostic #endif 59834022Sbostic 5996974Seric m = to->q_mailer; 6006974Seric host = to->q_host; 60158803Seric CurEnv = e; /* just in case */ 60259044Seric e->e_statmsg = NULL; 6036974Seric 6047672Seric if (tTd(10, 1)) 6053233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 6066974Seric m->m_mno, host, to->q_user); 607294Seric 608294Seric /* 6095903Seric ** If this mailer is expensive, and if we don't want to make 6105903Seric ** connections now, just mark these addresses and return. 6115903Seric ** This is useful if we want to batch connections to 6125903Seric ** reduce load. This will cause the messages to be 6135903Seric ** queued up, and a daemon will come along to send the 6145903Seric ** messages later. 6155903Seric ** This should be on a per-mailer basis. 6165903Seric */ 6175903Seric 61858737Seric if (NoConnect && !bitset(EF_QUEUERUN, e->e_flags) && 61958737Seric bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 6205903Seric { 6215903Seric for (; to != NULL; to = to->q_next) 6228431Seric { 62358680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 62458247Seric to->q_mailer != m) 6258431Seric continue; 6268431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 6279370Seric e->e_to = to->q_paddr; 62858151Seric message("queued"); 62958020Seric if (LogLevel > 8) 63058337Seric logdelivery(m, NULL, "queued", e); 6318431Seric } 6329370Seric e->e_to = NULL; 6335903Seric return (0); 6345903Seric } 6355903Seric 6365903Seric /* 6373233Seric ** Do initial argv setup. 6383233Seric ** Insert the mailer name. Notice that $x expansion is 6393233Seric ** NOT done on the mailer name. Then, if the mailer has 6403233Seric ** a picky -f flag, we insert it as appropriate. This 6413233Seric ** code does not check for 'pv' overflow; this places a 6423233Seric ** manifest lower limit of 4 for MAXPV. 6438062Seric ** The from address rewrite is expected to make 6448062Seric ** the address relative to the other end. 6452968Seric */ 6462968Seric 6474452Seric /* rewrite from address, using rewriting rules */ 64859163Seric rcode = EX_OK; 64959163Seric (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, 65059163Seric RF_SENDERADDR|RF_CANONICAL, 65159163Seric &rcode, e)); 65258680Seric define('g', rpathbuf, e); /* translated return path */ 6539370Seric define('h', host, e); /* to host */ 6543233Seric Errors = 0; 6553233Seric pvp = pv; 6563233Seric *pvp++ = m->m_argv[0]; 6572968Seric 6583233Seric /* insert -f or -r flag as appropriate */ 65910682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6603233Seric { 66110682Seric if (bitnset(M_FOPT, m->m_flags)) 6623233Seric *pvp++ = "-f"; 6633233Seric else 6643233Seric *pvp++ = "-r"; 66551951Seric *pvp++ = newstr(rpathbuf); 6663233Seric } 667294Seric 668294Seric /* 6693233Seric ** Append the other fixed parts of the argv. These run 6703233Seric ** up to the first entry containing "$u". There can only 6713233Seric ** be one of these, and there are only a few more slots 6723233Seric ** in the pv after it. 673294Seric */ 674294Seric 6753233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 676294Seric { 67758050Seric /* can't use strchr here because of sign extension problems */ 67858050Seric while (*p != '\0') 67958050Seric { 68058050Seric if ((*p++ & 0377) == MACROEXPAND) 68158050Seric { 68258050Seric if (*p == 'u') 68358050Seric break; 68458050Seric } 68558050Seric } 68658050Seric 68758050Seric if (*p != '\0') 6883233Seric break; 6893233Seric 6903233Seric /* this entry is safe -- go ahead and process it */ 6919370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 6923233Seric *pvp++ = newstr(buf); 6933233Seric if (pvp >= &pv[MAXPV - 3]) 6943233Seric { 69558151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 6963233Seric return (-1); 6973233Seric } 698294Seric } 6994863Seric 7006038Seric /* 7016038Seric ** If we have no substitution for the user name in the argument 7026038Seric ** list, we know that we must supply the names otherwise -- and 7036038Seric ** SMTP is the answer!! 7046038Seric */ 7056038Seric 7063233Seric if (*mvp == NULL) 7074863Seric { 7084863Seric /* running SMTP */ 7095179Seric # ifdef SMTP 7104863Seric clever = TRUE; 7114863Seric *pvp = NULL; 71256795Seric # else /* SMTP */ 7136038Seric /* oops! we don't implement SMTP */ 71458151Seric syserr("554 SMTP style mailer"); 7155179Seric return (EX_SOFTWARE); 71656795Seric # endif /* SMTP */ 7174863Seric } 718294Seric 719294Seric /* 7203233Seric ** At this point *mvp points to the argument with $u. We 7213233Seric ** run through our address list and append all the addresses 7223233Seric ** we can. If we run out of space, do not fret! We can 7233233Seric ** always send another copy later. 724294Seric */ 725294Seric 7263233Seric tobuf[0] = '\0'; 7279370Seric e->e_to = tobuf; 7284397Seric ctladdr = NULL; 72957454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7303233Seric for (; to != NULL; to = to->q_next) 731294Seric { 7323233Seric /* avoid sending multiple recipients to dumb mailers */ 73310682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7343233Seric break; 7353233Seric 7363233Seric /* if already sent or not for this host, don't send */ 73758680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 73857454Seric to->q_mailer != firstto->q_mailer || 73957454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7403233Seric continue; 7414397Seric 7428225Seric /* avoid overflowing tobuf */ 74342462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7448225Seric break; 7458225Seric 7467672Seric if (tTd(10, 1)) 7475032Seric { 7485032Seric printf("\nsend to "); 7495032Seric printaddr(to, FALSE); 7505032Seric } 7515032Seric 7524397Seric /* compute effective uid/gid when sending */ 7534596Seric if (to->q_mailer == ProgMailer) 7544397Seric ctladdr = getctladdr(to); 7554397Seric 7563233Seric user = to->q_user; 7579370Seric e->e_to = to->q_paddr; 75857731Seric if (tTd(10, 5)) 75957731Seric { 76057731Seric printf("deliver: QDONTSEND "); 76157731Seric printaddr(to, FALSE); 76257731Seric } 76358680Seric to->q_flags |= QDONTSEND; 7643233Seric 7653233Seric /* 7663233Seric ** Check to see that these people are allowed to 7673233Seric ** talk to each other. 7683233Seric */ 7693233Seric 77010699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 77110699Seric { 77229914Seric NoReturn = TRUE; 77358151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 77458337Seric giveresponse(EX_UNAVAILABLE, m, NULL, e); 77510699Seric continue; 77610699Seric } 77757441Seric rcode = checkcompat(to, e); 77857459Seric if (rcode != EX_OK) 779294Seric { 78058337Seric giveresponse(rcode, m, NULL, e); 7813233Seric continue; 782294Seric } 7833233Seric 7843233Seric /* 7854099Seric ** Strip quote bits from names if the mailer is dumb 7864099Seric ** about them. 7873233Seric */ 7883233Seric 78910682Seric if (bitnset(M_STRIPQ, m->m_flags)) 790294Seric { 79154983Seric stripquotes(user); 79254983Seric stripquotes(host); 7933233Seric } 7943233Seric 7959206Seric /* hack attack -- delivermail compatibility */ 7969206Seric if (m == ProgMailer && *user == '|') 7979206Seric user++; 7989206Seric 7993233Seric /* 8004161Seric ** If an error message has already been given, don't 8014161Seric ** bother to send to this address. 8024161Seric ** 8034161Seric ** >>>>>>>>>> This clause assumes that the local mailer 8044161Seric ** >> NOTE >> cannot do any further aliasing; that 8054161Seric ** >>>>>>>>>> function is subsumed by sendmail. 8064161Seric */ 8074161Seric 8087293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8094161Seric continue; 8104161Seric 8114283Seric /* save statistics.... */ 8129370Seric markstats(e, to); 8134283Seric 8144161Seric /* 8153233Seric ** See if this user name is "special". 8163233Seric ** If the user name has a slash in it, assume that this 8176974Seric ** is a file -- send it off without further ado. Note 8186974Seric ** that this type of addresses is not processed along 8196974Seric ** with the others, so we fudge on the To person. 8203233Seric */ 8213233Seric 82257402Seric if (m == FileMailer) 8233233Seric { 82457402Seric rcode = mailfile(user, getctladdr(to), e); 82558337Seric giveresponse(rcode, m, NULL, e); 82657402Seric if (rcode == EX_OK) 82757402Seric to->q_flags |= QSENT; 82857402Seric continue; 829294Seric } 8303233Seric 8314315Seric /* 8324315Seric ** Address is verified -- add this user to mailer 8334315Seric ** argv, and add it to the print list of recipients. 8344315Seric */ 8354315Seric 8366059Seric /* link together the chain of recipients */ 8376272Seric to->q_tchain = tochain; 8386272Seric tochain = to; 8396059Seric 8403233Seric /* create list of users for error messages */ 8419388Seric (void) strcat(tobuf, ","); 8424082Seric (void) strcat(tobuf, to->q_paddr); 8439370Seric define('u', user, e); /* to user */ 8449370Seric define('z', to->q_home, e); /* user's home */ 8453233Seric 8464863Seric /* 8476059Seric ** Expand out this user into argument list. 8484863Seric */ 8494863Seric 8506059Seric if (!clever) 8513233Seric { 8529370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8534863Seric *pvp++ = newstr(buf); 8544863Seric if (pvp >= &pv[MAXPV - 2]) 8554863Seric { 8564863Seric /* allow some space for trailing parms */ 8574863Seric break; 8584863Seric } 8594863Seric } 860294Seric } 861294Seric 8624067Seric /* see if any addresses still exist */ 8634067Seric if (tobuf[0] == '\0') 8644863Seric { 8659370Seric define('g', (char *) NULL, e); 8664067Seric return (0); 8674863Seric } 8684067Seric 8693233Seric /* print out messages as full list */ 8709388Seric e->e_to = tobuf + 1; 8713233Seric 872294Seric /* 8733233Seric ** Fill out any parameters after the $u parameter. 874294Seric */ 875294Seric 8764863Seric while (!clever && *++mvp != NULL) 877294Seric { 8789370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8793233Seric *pvp++ = newstr(buf); 8803233Seric if (pvp >= &pv[MAXPV]) 88158151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 882294Seric } 8833233Seric *pvp++ = NULL; 884294Seric 885294Seric /* 886294Seric ** Call the mailer. 8872898Seric ** The argument vector gets built, pipes 888294Seric ** are created as necessary, and we fork & exec as 8892898Seric ** appropriate. 8904863Seric ** If we are running SMTP, we just need to clean up. 891294Seric */ 892294Seric 89358309Seric if (ctladdr == NULL && m != ProgMailer) 89441050Seric ctladdr = &e->e_from; 89535651Seric #ifdef NAMED_BIND 89651313Seric if (ConfigLevel < 2) 89751313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 89835651Seric #endif 89954967Seric 9007672Seric if (tTd(11, 1)) 901294Seric { 9028178Seric printf("openmailer:"); 90358820Seric printav(pv); 904294Seric } 9054488Seric errno = 0; 9063233Seric 90725050Seric CurHostName = m->m_mailer; 90825050Seric 9096038Seric /* 9106038Seric ** Deal with the special case of mail handled through an IPC 9116038Seric ** connection. 9126038Seric ** In this case we don't actually fork. We must be 9136038Seric ** running SMTP for this to work. We will return a 9146038Seric ** zero pid to indicate that we are running IPC. 91511160Seric ** We also handle a debug version that just talks to stdin/out. 9166038Seric */ 9176038Seric 91858820Seric curhost = NULL; 91958820Seric 92011160Seric /* check for Local Person Communication -- not for mortals!!! */ 92111160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 92211160Seric { 92354967Seric mci = (MCI *) xalloc(sizeof *mci); 92454993Seric bzero((char *) mci, sizeof *mci); 92553738Seric mci->mci_in = stdin; 92653738Seric mci->mci_out = stdout; 92754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 92853751Seric mci->mci_mailer = m; 92911160Seric } 93054967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 93154967Seric strcmp(m->m_mailer, "[TCP]") == 0) 9326038Seric { 93352107Seric #ifdef DAEMON 93457454Seric register int i; 9357285Seric register u_short port; 9366038Seric 93758820Seric CurHostName = pv[1]; 93858820Seric curhost = hostsignature(m, pv[1], e); 93954967Seric 94058479Seric if (curhost == NULL || curhost[0] == '\0') 94158479Seric { 94258479Seric syserr("null signature"); 94358820Seric rcode = EX_OSERR; 94458820Seric goto give_up; 94558479Seric } 94658479Seric 9476038Seric if (!clever) 94858479Seric { 94958151Seric syserr("554 non-clever IPC"); 95058820Seric rcode = EX_OSERR; 95158820Seric goto give_up; 95258479Seric } 95358820Seric if (pv[2] != NULL) 95458820Seric port = atoi(pv[2]); 9556632Seric else 9567285Seric port = 0; 95758820Seric tryhost: 95858820Seric mci = NULL; 95957454Seric while (*curhost != '\0') 96029433Sbloom { 96157454Seric register char *p; 96258664Seric static char hostbuf[MAXNAME]; 96357454Seric 96458820Seric mci = NULL; 96558820Seric 96657454Seric /* pull the next host from the signature */ 96757454Seric p = strchr(curhost, ':'); 96857454Seric if (p == NULL) 96957454Seric p = &curhost[strlen(curhost)]; 97057454Seric strncpy(hostbuf, curhost, p - curhost); 97157454Seric hostbuf[p - curhost] = '\0'; 97257454Seric if (*p != '\0') 97357454Seric p++; 97457454Seric curhost = p; 97557454Seric 97653738Seric /* see if we already know that this host is fried */ 97757454Seric CurHostName = hostbuf; 97857454Seric mci = mci_get(hostbuf, m); 97954967Seric if (mci->mci_state != MCIS_CLOSED) 98057387Seric { 98157387Seric if (tTd(11, 1)) 98257387Seric { 98357387Seric printf("openmailer: "); 98457387Seric mci_dump(mci); 98557387Seric } 98657943Seric CurHostName = mci->mci_host; 98758820Seric break; 98857387Seric } 98953751Seric mci->mci_mailer = m; 99054967Seric if (mci->mci_exitstat != EX_OK) 99154967Seric continue; 99254967Seric 99354967Seric /* try the connection */ 99457454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 99558151Seric message("Connecting to %s (%s)...", 99657454Seric hostbuf, m->m_name); 99757454Seric i = makeconnection(hostbuf, port, mci, 99854967Seric bitnset(M_SECURE_PORT, m->m_flags)); 99954967Seric mci->mci_exitstat = i; 100054967Seric mci->mci_errno = errno; 1001*63753Seric #ifdef NAMED_BIND 1002*63753Seric mci->mci_herrno = h_errno; 1003*63753Seric #endif 100454967Seric if (i == EX_OK) 100552106Seric { 100654967Seric mci->mci_state = MCIS_OPENING; 100754967Seric mci_cache(mci); 1008*63753Seric if (TrafficLogFile != NULL) 1009*63753Seric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 1010*63753Seric getpid(), hostbuf); 101154967Seric break; 101234022Sbostic } 101354967Seric else if (tTd(11, 1)) 101454967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 101554967Seric i, errno); 101653738Seric 101754967Seric 101853738Seric /* enter status of this host */ 101953738Seric setstat(i); 10206047Seric } 102154993Seric mci->mci_pid = 0; 102254967Seric #else /* no DAEMON */ 102358151Seric syserr("554 openmailer: no IPC"); 102457387Seric if (tTd(11, 1)) 102557387Seric printf("openmailer: NULL\n"); 102653738Seric return NULL; 102754967Seric #endif /* DAEMON */ 10286038Seric } 102954967Seric else 1030294Seric { 1031*63753Seric #ifdef XDEBUG 1032*63753Seric char wbuf[MAXLINE]; 103358852Seric 103458852Seric /* make absolutely certain 0, 1, and 2 are in use */ 1035*63753Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 1036*63753Seric checkfd012(wbuf); 1037*63753Seric #endif 1038*63753Seric 1039*63753Seric if (TrafficLogFile != NULL) 104058852Seric { 1041*63753Seric char **av; 104258925Seric 1043*63753Seric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 1044*63753Seric for (av = pv; *av != NULL; av++) 1045*63753Seric fprintf(TrafficLogFile, " %s", *av); 1046*63753Seric fprintf(TrafficLogFile, "\n"); 104758852Seric } 104858852Seric 104954967Seric /* create a pipe to shove the mail through */ 105054967Seric if (pipe(mpvect) < 0) 105154967Seric { 105258925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 105358925Seric e->e_to, m->m_name); 105457387Seric if (tTd(11, 1)) 105557387Seric printf("openmailer: NULL\n"); 105658820Seric rcode = EX_OSERR; 105758820Seric goto give_up; 105854967Seric } 10594863Seric 106054967Seric /* if this mailer speaks smtp, create a return pipe */ 106154967Seric if (clever && pipe(rpvect) < 0) 106254967Seric { 106358925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 106458925Seric e->e_to, m->m_name); 106554967Seric (void) close(mpvect[0]); 106654967Seric (void) close(mpvect[1]); 106757387Seric if (tTd(11, 1)) 106857387Seric printf("openmailer: NULL\n"); 106958820Seric rcode = EX_OSERR; 107058820Seric goto give_up; 107154967Seric } 10724863Seric 107354967Seric /* 107454967Seric ** Actually fork the mailer process. 107554967Seric ** DOFORK is clever about retrying. 107654967Seric ** 107754967Seric ** Dispose of SIGCHLD signal catchers that may be laying 107854967Seric ** around so that endmail will get it. 107954967Seric */ 10806038Seric 108154967Seric if (e->e_xfp != NULL) 108254967Seric (void) fflush(e->e_xfp); /* for debugging */ 108354967Seric (void) fflush(stdout); 108426434Seric # ifdef SIGCHLD 108554967Seric (void) signal(SIGCHLD, SIG_DFL); 108656795Seric # endif /* SIGCHLD */ 108754967Seric DOFORK(FORK); 108854967Seric /* pid is set by DOFORK */ 108954967Seric if (pid < 0) 10904863Seric { 109154967Seric /* failure */ 109258925Seric syserr("%s... openmailer(%s): cannot fork", 109358925Seric e->e_to, m->m_name); 109454967Seric (void) close(mpvect[0]); 109554967Seric (void) close(mpvect[1]); 109654967Seric if (clever) 109754967Seric { 109854967Seric (void) close(rpvect[0]); 109954967Seric (void) close(rpvect[1]); 110054967Seric } 110157387Seric if (tTd(11, 1)) 110257387Seric printf("openmailer: NULL\n"); 110358820Seric rcode = EX_OSERR; 110458820Seric goto give_up; 11054863Seric } 110654967Seric else if (pid == 0) 110754967Seric { 110854967Seric int i; 110956678Seric int saveerrno; 111058675Seric char **ep; 111158675Seric char *env[MAXUSERENVIRON]; 111258675Seric extern char **environ; 111354967Seric extern int DtableSize; 111415772Seric 111554967Seric /* child -- set up input & exec mailer */ 111654967Seric /* make diagnostic output be standard output */ 111754967Seric (void) signal(SIGINT, SIG_IGN); 111854967Seric (void) signal(SIGHUP, SIG_IGN); 111954967Seric (void) signal(SIGTERM, SIG_DFL); 11204709Seric 112158082Seric /* close any other cached connections */ 112258082Seric mci_flush(FALSE, mci); 112358082Seric 112458935Seric /* move into some "safe" directory */ 112558935Seric if (m->m_execdir != NULL) 112658935Seric { 112758935Seric char *p, *q; 112858935Seric char buf[MAXLINE]; 112958935Seric 113058935Seric for (p = m->m_execdir; p != NULL; p = q) 113158935Seric { 113258935Seric q = strchr(p, ':'); 113358935Seric if (q != NULL) 113458935Seric *q = '\0'; 113558935Seric expand(p, buf, &buf[sizeof buf] - 1, e); 113658935Seric if (q != NULL) 113758935Seric *q++ = ':'; 113858935Seric if (tTd(11, 20)) 113958935Seric printf("openmailer: trydir %s\n", 114058935Seric buf); 114158935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 114258935Seric break; 114358935Seric } 114458935Seric } 114558935Seric 114654967Seric /* arrange to filter std & diag output of command */ 114754967Seric if (clever) 114854967Seric { 114954967Seric (void) close(rpvect[0]); 115058852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 115158852Seric { 115258925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 115358925Seric e->e_to, m->m_name, rpvect[1]); 115458852Seric _exit(EX_OSERR); 115558852Seric } 115654967Seric (void) close(rpvect[1]); 115754967Seric } 115854967Seric else if (OpMode == MD_SMTP || HoldErrs) 115954967Seric { 116054967Seric /* put mailer output in transcript */ 116158852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 116258852Seric { 116358925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 116458925Seric e->e_to, m->m_name, 116558852Seric fileno(e->e_xfp)); 116658852Seric _exit(EX_OSERR); 116758852Seric } 116854967Seric } 116958852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 117058852Seric { 117158925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 117258925Seric e->e_to, m->m_name); 117358852Seric _exit(EX_OSERR); 117458852Seric } 11754709Seric 117654967Seric /* arrange to get standard input */ 117754967Seric (void) close(mpvect[1]); 117858731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 11794417Seric { 118058925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 118158925Seric e->e_to, m->m_name, mpvect[0]); 118254967Seric _exit(EX_OSERR); 11834417Seric } 118454967Seric (void) close(mpvect[0]); 118554967Seric if (!bitnset(M_RESTR, m->m_flags)) 11864415Seric { 118754967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 118854967Seric { 118954967Seric (void) setgid(DefGid); 119054967Seric (void) initgroups(DefUser, DefGid); 119154967Seric (void) setuid(DefUid); 119254967Seric } 119354967Seric else 119454967Seric { 119554967Seric (void) setgid(ctladdr->q_gid); 119654967Seric (void) initgroups(ctladdr->q_ruser? 119754967Seric ctladdr->q_ruser: ctladdr->q_user, 119854967Seric ctladdr->q_gid); 119954967Seric (void) setuid(ctladdr->q_uid); 120054967Seric } 12014415Seric } 12029370Seric 120354967Seric /* arrange for all the files to be closed */ 120454967Seric for (i = 3; i < DtableSize; i++) 120554967Seric { 120654967Seric register int j; 120754967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 120854967Seric (void)fcntl(i, F_SETFD, j|1); 120954967Seric } 12102774Seric 121158675Seric /* set up the mailer environment */ 121258675Seric i = 0; 121358675Seric env[i++] = "AGENT=sendmail"; 121458675Seric for (ep = environ; *ep != NULL; ep++) 121558675Seric { 121658675Seric if (strncmp(*ep, "TZ=", 3) == 0) 121758675Seric env[i++] = *ep; 121858675Seric } 121958675Seric env[i++] = NULL; 122058675Seric 122154967Seric /* try to execute the mailer */ 122258820Seric execve(m->m_mailer, pv, env); 122356678Seric saveerrno = errno; 122454967Seric syserr("Cannot exec %s", m->m_mailer); 122560008Seric if (m == LocalMailer || transienterror(saveerrno)) 122660008Seric _exit(EX_OSERR); 122754967Seric _exit(EX_UNAVAILABLE); 122851835Seric } 122954967Seric 123054967Seric /* 123154967Seric ** Set up return value. 123254967Seric */ 123354967Seric 123454967Seric mci = (MCI *) xalloc(sizeof *mci); 123554993Seric bzero((char *) mci, sizeof *mci); 123654967Seric mci->mci_mailer = m; 123754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 123854993Seric mci->mci_pid = pid; 123954967Seric (void) close(mpvect[0]); 124054967Seric mci->mci_out = fdopen(mpvect[1], "w"); 124154967Seric if (clever) 124254967Seric { 124354967Seric (void) close(rpvect[1]); 124454967Seric mci->mci_in = fdopen(rpvect[0], "r"); 124554967Seric } 124654967Seric else 124754967Seric { 124854967Seric mci->mci_flags |= MCIF_TEMP; 124954967Seric mci->mci_in = NULL; 125054967Seric } 1251294Seric } 1252294Seric 12534709Seric /* 125454967Seric ** If we are in SMTP opening state, send initial protocol. 12554709Seric */ 12564709Seric 125754967Seric if (clever && mci->mci_state != MCIS_CLOSED) 12584863Seric { 125954967Seric smtpinit(m, mci, e); 126053738Seric } 126157387Seric if (tTd(11, 1)) 126257387Seric { 126357387Seric printf("openmailer: "); 126457387Seric mci_dump(mci); 126557387Seric } 1266294Seric 126758820Seric if (mci->mci_state != MCIS_OPEN) 126858820Seric { 126958820Seric /* couldn't open the mailer */ 127058820Seric rcode = mci->mci_exitstat; 127158820Seric errno = mci->mci_errno; 1272*63753Seric #ifdef NAMED_BIND 1273*63753Seric h_errno = mci->mci_herrno; 1274*63753Seric #endif 127558820Seric if (rcode == EX_OK) 127658820Seric { 127758820Seric /* shouldn't happen */ 127858820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 127958820Seric rcode, mci->mci_state, firstsig); 128058820Seric rcode = EX_SOFTWARE; 128158820Seric } 128259993Seric else if (rcode == EX_TEMPFAIL && *curhost != '\0') 128359958Seric { 128459958Seric /* try next MX site */ 128559958Seric goto tryhost; 128659958Seric } 128758820Seric } 128858820Seric else if (!clever) 128958820Seric { 129058820Seric /* 129158820Seric ** Format and send message. 129258820Seric */ 129358820Seric 129458820Seric putfromline(mci->mci_out, m, e); 129558820Seric (*e->e_puthdr)(mci->mci_out, m, e); 129658820Seric putline("\n", mci->mci_out, m); 129759730Seric (*e->e_putbody)(mci->mci_out, m, e, NULL); 129858820Seric 129958820Seric /* get the exit status */ 130058820Seric rcode = endmailer(mci, e, pv); 130158820Seric } 130258820Seric else 130358820Seric #ifdef SMTP 130458820Seric { 130558820Seric /* 130658820Seric ** Send the MAIL FROM: protocol 130758820Seric */ 130858820Seric 130958820Seric rcode = smtpmailfrom(m, mci, e); 131058820Seric if (rcode == EX_OK) 131158820Seric { 131258820Seric register char *t = tobuf; 131358820Seric register int i; 131458820Seric 131558820Seric /* send the recipient list */ 131658820Seric tobuf[0] = '\0'; 131758820Seric for (to = tochain; to != NULL; to = to->q_tchain) 131858820Seric { 131958820Seric e->e_to = to->q_paddr; 132058820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 132158820Seric { 132258820Seric markfailure(e, to, i); 132358820Seric giveresponse(i, m, mci, e); 132458820Seric } 132558820Seric else 132658820Seric { 132758820Seric *t++ = ','; 132858820Seric for (p = to->q_paddr; *p; *t++ = *p++) 132958820Seric continue; 133058820Seric } 133158820Seric } 133258820Seric 133358820Seric /* now send the data */ 133458820Seric if (tobuf[0] == '\0') 133558820Seric { 133658820Seric rcode = EX_OK; 133758820Seric e->e_to = NULL; 133858820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 133958820Seric smtprset(m, mci, e); 134058820Seric } 134158820Seric else 134258820Seric { 134358820Seric e->e_to = tobuf + 1; 134458820Seric rcode = smtpdata(m, mci, e); 134558820Seric } 134658820Seric 134758820Seric /* now close the connection */ 134858820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 134958820Seric smtpquit(m, mci, e); 135058820Seric } 135158820Seric if (rcode != EX_OK && *curhost != '\0') 135258820Seric { 135358820Seric /* try next MX site */ 135458820Seric goto tryhost; 135558820Seric } 135658820Seric } 135758820Seric #else /* not SMTP */ 135858820Seric { 135958820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 136058820Seric rcode = EX_CONFIG; 136158820Seric goto give_up; 136258820Seric } 136358820Seric #endif /* SMTP */ 136458820Seric #ifdef NAMED_BIND 136558820Seric if (ConfigLevel < 2) 136658820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 136758820Seric #endif 136858820Seric 136958820Seric /* arrange a return receipt if requested */ 137058820Seric if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) 137158820Seric { 137258820Seric e->e_flags |= EF_SENDRECEIPT; 137358820Seric /* do we want to send back more info? */ 137458820Seric } 137558820Seric 137658820Seric /* 137758820Seric ** Do final status disposal. 137858820Seric ** We check for something in tobuf for the SMTP case. 137958820Seric ** If we got a temporary failure, arrange to queue the 138058820Seric ** addressees. 138158820Seric */ 138258820Seric 138358820Seric give_up: 138458820Seric if (tobuf[0] != '\0') 138558820Seric giveresponse(rcode, m, mci, e); 138658820Seric for (to = tochain; to != NULL; to = to->q_tchain) 138758820Seric { 138858820Seric if (rcode != EX_OK) 138958820Seric markfailure(e, to, rcode); 139058820Seric else 139158820Seric { 139258820Seric to->q_flags |= QSENT; 139358820Seric e->e_nsent++; 139458820Seric } 139558820Seric } 139658820Seric 139758820Seric /* 139858820Seric ** Restore state and return. 139958820Seric */ 140058820Seric 140158820Seric errno = 0; 140258820Seric define('g', (char *) NULL, e); 140358820Seric return (rcode); 1404294Seric } 1405294Seric /* 140658820Seric ** MARKFAILURE -- mark a failure on a specific address. 140758820Seric ** 140858820Seric ** Parameters: 140958820Seric ** e -- the envelope we are sending. 141058820Seric ** q -- the address to mark. 141158820Seric ** rcode -- the code signifying the particular failure. 141258820Seric ** 141358820Seric ** Returns: 141458820Seric ** none. 141558820Seric ** 141658820Seric ** Side Effects: 141758820Seric ** marks the address (and possibly the envelope) with the 141858820Seric ** failure so that an error will be returned or 141958820Seric ** the message will be queued, as appropriate. 142058820Seric */ 142158820Seric 142258820Seric markfailure(e, q, rcode) 142358820Seric register ENVELOPE *e; 142458820Seric register ADDRESS *q; 142558820Seric int rcode; 142658820Seric { 142758820Seric char buf[MAXLINE]; 142858820Seric 142958820Seric if (rcode == EX_OK) 143058820Seric return; 1431*63753Seric else if (rcode == EX_TEMPFAIL) 1432*63753Seric q->q_flags |= QQUEUEUP; 1433*63753Seric else if (rcode != EX_IOERR && rcode != EX_OSERR) 143458820Seric q->q_flags |= QBADADDR; 143558820Seric } 143658820Seric /* 143758820Seric ** ENDMAILER -- Wait for mailer to terminate. 143858820Seric ** 143958820Seric ** We should never get fatal errors (e.g., segmentation 144058820Seric ** violation), so we report those specially. For other 144158820Seric ** errors, we choose a status message (into statmsg), 144258820Seric ** and if it represents an error, we print it. 144358820Seric ** 144458820Seric ** Parameters: 144558820Seric ** pid -- pid of mailer. 144658820Seric ** e -- the current envelope. 144758820Seric ** pv -- the parameter vector that invoked the mailer 144858820Seric ** (for error messages). 144958820Seric ** 145058820Seric ** Returns: 145158820Seric ** exit code of mailer. 145258820Seric ** 145358820Seric ** Side Effects: 145458820Seric ** none. 145558820Seric */ 145658820Seric 145758820Seric endmailer(mci, e, pv) 145858820Seric register MCI *mci; 145958820Seric register ENVELOPE *e; 146058820Seric char **pv; 146158820Seric { 146258820Seric int st; 146358820Seric 146458820Seric /* close any connections */ 146558820Seric if (mci->mci_in != NULL) 146658820Seric (void) xfclose(mci->mci_in, pv[0], "mci_in"); 146758820Seric if (mci->mci_out != NULL) 146858820Seric (void) xfclose(mci->mci_out, pv[0], "mci_out"); 146958820Seric mci->mci_in = mci->mci_out = NULL; 147058820Seric mci->mci_state = MCIS_CLOSED; 147158820Seric 147258820Seric /* in the IPC case there is nothing to wait for */ 147358820Seric if (mci->mci_pid == 0) 147458820Seric return (EX_OK); 147558820Seric 147658820Seric /* wait for the mailer process to die and collect status */ 147758820Seric st = waitfor(mci->mci_pid); 147858820Seric if (st == -1) 147958820Seric { 148058820Seric syserr("endmailer %s: wait", pv[0]); 148158820Seric return (EX_SOFTWARE); 148258820Seric } 148358820Seric 148458820Seric /* see if it died a horrid death */ 148558820Seric if ((st & 0377) != 0) 148658820Seric { 148758820Seric syserr("mailer %s died with signal %o", pv[0], st); 148858820Seric 148958820Seric /* log the arguments */ 149058820Seric if (e->e_xfp != NULL) 149158820Seric { 149258820Seric register char **av; 149358820Seric 149458820Seric fprintf(e->e_xfp, "Arguments:"); 149558820Seric for (av = pv; *av != NULL; av++) 149658820Seric fprintf(e->e_xfp, " %s", *av); 149758820Seric fprintf(e->e_xfp, "\n"); 149858820Seric } 149958820Seric 150058820Seric ExitStat = EX_TEMPFAIL; 150158820Seric return (EX_TEMPFAIL); 150258820Seric } 150358820Seric 150458820Seric /* normal death -- return status */ 150558820Seric st = (st >> 8) & 0377; 150658820Seric return (st); 150758820Seric } 150858820Seric /* 1509294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1510294Seric ** 1511294Seric ** Parameters: 1512294Seric ** stat -- the status code from the mailer (high byte 1513294Seric ** only; core dumps must have been taken care of 1514294Seric ** already). 151558337Seric ** m -- the mailer info for this mailer. 151658337Seric ** mci -- the mailer connection info -- can be NULL if the 151758337Seric ** response is given before the connection is made. 151858337Seric ** e -- the current envelope. 1519294Seric ** 1520294Seric ** Returns: 15214082Seric ** none. 1522294Seric ** 1523294Seric ** Side Effects: 15241518Seric ** Errors may be incremented. 1525294Seric ** ExitStat may be set. 1526294Seric */ 1527294Seric 152858337Seric giveresponse(stat, m, mci, e) 1529294Seric int stat; 15309370Seric register MAILER *m; 153158337Seric register MCI *mci; 153210105Seric ENVELOPE *e; 1533294Seric { 153460094Seric register const char *statmsg; 1535294Seric extern char *SysExMsg[]; 1536294Seric register int i; 153736788Sbostic extern int N_SysEx; 153810105Seric char buf[MAXLINE]; 1539294Seric 15404315Seric /* 15414315Seric ** Compute status message from code. 15424315Seric */ 15434315Seric 1544294Seric i = stat - EX__BASE; 15459370Seric if (stat == 0) 154658852Seric { 15479370Seric statmsg = "250 Sent"; 154858916Seric if (e->e_statmsg != NULL) 154958852Seric { 155058916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 155158852Seric statmsg = buf; 155258852Seric } 155358852Seric } 15549370Seric else if (i < 0 || i > N_SysEx) 15559370Seric { 15569370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 15579370Seric stat = EX_UNAVAILABLE; 15589370Seric statmsg = buf; 15599370Seric } 156010105Seric else if (stat == EX_TEMPFAIL) 156110105Seric { 156258664Seric (void) strcpy(buf, SysExMsg[i] + 1); 156336788Sbostic #ifdef NAMED_BIND 156425527Smiriam if (h_errno == TRY_AGAIN) 156525527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 156621061Seric else 156736788Sbostic #endif 156821061Seric { 156925527Smiriam if (errno != 0) 157025527Smiriam statmsg = errstring(errno); 157125527Smiriam else 157225527Smiriam { 157321061Seric #ifdef SMTP 157425527Smiriam extern char SmtpError[]; 157521061Seric 157625527Smiriam statmsg = SmtpError; 157756795Seric #else /* SMTP */ 157825527Smiriam statmsg = NULL; 157956795Seric #endif /* SMTP */ 158025527Smiriam } 158121061Seric } 158221061Seric if (statmsg != NULL && statmsg[0] != '\0') 158321061Seric { 158410124Seric (void) strcat(buf, ": "); 158521061Seric (void) strcat(buf, statmsg); 158610105Seric } 158710105Seric statmsg = buf; 158810105Seric } 1589*63753Seric #ifdef NAMED_BIND 1590*63753Seric else if (stat == EX_NOHOST && h_errno != 0) 1591*63753Seric { 1592*63753Seric statmsg = errstring(h_errno + MAX_ERRNO); 1593*63753Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i], statmsg); 1594*63753Seric statmsg = buf; 1595*63753Seric } 1596*63753Seric #endif 1597294Seric else 159821061Seric { 1599294Seric statmsg = SysExMsg[i]; 160058664Seric if (*statmsg++ == ':') 160158664Seric { 160258664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 160358664Seric statmsg = buf; 160458664Seric } 160521061Seric } 16069370Seric 16079370Seric /* 16089370Seric ** Print the message as appropriate 16099370Seric */ 16109370Seric 161110105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 161258524Seric message(&statmsg[4], errstring(errno)); 1613294Seric else 1614294Seric { 16151518Seric Errors++; 161658524Seric usrerr(statmsg, errstring(errno)); 1617294Seric } 1618294Seric 1619294Seric /* 1620294Seric ** Final cleanup. 1621294Seric ** Log a record of the transaction. Compute the new 1622294Seric ** ExitStat -- if we already had an error, stick with 1623294Seric ** that. 1624294Seric */ 1625294Seric 162658020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 162758337Seric logdelivery(m, mci, &statmsg[4], e); 16287858Seric 16294621Seric if (stat != EX_TEMPFAIL) 16304621Seric setstat(stat); 163110105Seric if (stat != EX_OK) 163210105Seric { 163310105Seric if (e->e_message != NULL) 163410105Seric free(e->e_message); 163510105Seric e->e_message = newstr(&statmsg[4]); 163610105Seric } 163710124Seric errno = 0; 163836788Sbostic #ifdef NAMED_BIND 163925527Smiriam h_errno = 0; 164036788Sbostic #endif 1641294Seric } 1642294Seric /* 16438496Seric ** LOGDELIVERY -- log the delivery in the system log 16448496Seric ** 16458496Seric ** Parameters: 164658337Seric ** m -- the mailer info. Can be NULL for initial queue. 164758337Seric ** mci -- the mailer connection info -- can be NULL if the 164858337Seric ** log is occuring when no connection is active. 164958337Seric ** stat -- the message to print for the status. 165058337Seric ** e -- the current envelope. 16518496Seric ** 16528496Seric ** Returns: 16538496Seric ** none 16548496Seric ** 16558496Seric ** Side Effects: 16568496Seric ** none 16578496Seric */ 16588496Seric 165958337Seric logdelivery(m, mci, stat, e) 166058337Seric MAILER *m; 166158337Seric register MCI *mci; 16628496Seric char *stat; 166354967Seric register ENVELOPE *e; 16648496Seric { 166558343Seric # ifdef LOG 166658418Seric char buf[512]; 16678496Seric 166858513Seric (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 166958337Seric 167058513Seric if (m != NULL) 167158305Seric { 167258513Seric (void) strcat(buf, ", mailer="); 167358513Seric (void) strcat(buf, m->m_name); 167458305Seric } 167558513Seric 167658513Seric if (mci != NULL && mci->mci_host != NULL) 167758305Seric { 167858305Seric # ifdef DAEMON 167958755Seric extern SOCKADDR CurHostAddr; 168058513Seric # endif 168158305Seric 168258513Seric (void) strcat(buf, ", relay="); 168358513Seric (void) strcat(buf, mci->mci_host); 168458513Seric 168558513Seric # ifdef DAEMON 168658513Seric (void) strcat(buf, " ("); 168758755Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 168858513Seric (void) strcat(buf, ")"); 168958305Seric # endif 169058305Seric } 169158343Seric else 169258513Seric { 169358513Seric char *p = macvalue('h', e); 169458343Seric 169558513Seric if (p != NULL && p[0] != '\0') 169658513Seric { 169758513Seric (void) strcat(buf, ", relay="); 169858513Seric (void) strcat(buf, p); 169958513Seric } 170058513Seric } 170158418Seric 170258418Seric syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", 170358418Seric e->e_id, e->e_to, buf, stat); 170456795Seric # endif /* LOG */ 17058496Seric } 17068496Seric /* 17076974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1708294Seric ** 17096974Seric ** This can be made an arbitrary message separator by changing $l 1710294Seric ** 171116150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 171216150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 171316150Seric ** does a well-meaning programmer such as myself have to deal with 171416150Seric ** this kind of antique garbage???? 17156974Seric ** 1716294Seric ** Parameters: 17176974Seric ** fp -- the file to output to. 17186974Seric ** m -- the mailer describing this entry. 1719294Seric ** 1720294Seric ** Returns: 17216974Seric ** none 1722294Seric ** 1723294Seric ** Side Effects: 17246974Seric ** outputs some text to fp. 1725294Seric */ 1726294Seric 172754967Seric putfromline(fp, m, e) 17286974Seric register FILE *fp; 17296974Seric register MAILER *m; 173054967Seric ENVELOPE *e; 1731294Seric { 173258050Seric char *template = "\201l\n"; 17336974Seric char buf[MAXLINE]; 1734294Seric 173510682Seric if (bitnset(M_NHDR, m->m_flags)) 17366974Seric return; 17374315Seric 17386974Seric # ifdef UGLYUUCP 173910682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 17404205Seric { 174112223Seric char *bang; 174212223Seric char xbuf[MAXLINE]; 17436041Seric 174458680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 174556795Seric bang = strchr(buf, '!'); 17466974Seric if (bang == NULL) 174758151Seric syserr("554 No ! in UUCP! (%s)", buf); 17485099Seric else 17499370Seric { 175012223Seric *bang++ = '\0'; 175158050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 175212223Seric template = xbuf; 17539370Seric } 17546974Seric } 175556795Seric # endif /* UGLYUUCP */ 175654967Seric expand(template, buf, &buf[sizeof buf - 1], e); 175710168Seric putline(buf, fp, m); 17585981Seric } 17595981Seric /* 17606974Seric ** PUTBODY -- put the body of a message. 17616974Seric ** 17626974Seric ** Parameters: 17636974Seric ** fp -- file to output onto. 176410168Seric ** m -- a mailer descriptor to control output format. 17659538Seric ** e -- the envelope to put out. 176659730Seric ** separator -- if non-NULL, a message separator that must 176759730Seric ** not be permitted in the resulting message. 17686974Seric ** 17696974Seric ** Returns: 17706974Seric ** none. 17716974Seric ** 17726974Seric ** Side Effects: 17736974Seric ** The message is written onto fp. 17746974Seric */ 17756974Seric 177659730Seric putbody(fp, m, e, separator) 17776974Seric FILE *fp; 17789370Seric MAILER *m; 17799538Seric register ENVELOPE *e; 178059730Seric char *separator; 17816974Seric { 178210168Seric char buf[MAXLINE]; 17836974Seric 17846974Seric /* 17856974Seric ** Output the body of the message 17866974Seric */ 17876974Seric 17889538Seric if (e->e_dfp == NULL) 17896974Seric { 17909538Seric if (e->e_df != NULL) 17919538Seric { 17929538Seric e->e_dfp = fopen(e->e_df, "r"); 17939538Seric if (e->e_dfp == NULL) 179440931Srick syserr("putbody: Cannot open %s for %s from %s", 179540931Srick e->e_df, e->e_to, e->e_from); 17969538Seric } 17979538Seric else 179810168Seric putline("<<< No Message Collected >>>", fp, m); 17999538Seric } 18009538Seric if (e->e_dfp != NULL) 18019538Seric { 18029538Seric rewind(e->e_dfp); 180310168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 180416875Seric { 180516875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 180640995Sbostic strncmp(buf, "From ", 5) == 0) 180723102Seric (void) putc('>', fp); 180859730Seric if (buf[0] == '-' && buf[1] == '-' && separator != NULL) 180959730Seric { 181059730Seric /* possible separator */ 181159730Seric int sl = strlen(separator); 181259730Seric 181359730Seric if (strncmp(&buf[2], separator, sl) == 0) 181459730Seric (void) putc(' ', fp); 181559730Seric } 181610168Seric putline(buf, fp, m); 181716875Seric } 18186974Seric 18199538Seric if (ferror(e->e_dfp)) 18206974Seric { 18216974Seric syserr("putbody: read error"); 18226974Seric ExitStat = EX_IOERR; 18236974Seric } 18246974Seric } 18256974Seric 182659542Seric /* some mailers want extra blank line at end of message */ 182759542Seric if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n') 182859542Seric putline("", fp, m); 182959542Seric 18306974Seric (void) fflush(fp); 18316974Seric if (ferror(fp) && errno != EPIPE) 18326974Seric { 18336974Seric syserr("putbody: write error"); 18346974Seric ExitStat = EX_IOERR; 18356974Seric } 18366974Seric errno = 0; 18376974Seric } 18386974Seric /* 1839294Seric ** MAILFILE -- Send a message to a file. 1840294Seric ** 18414327Seric ** If the file has the setuid/setgid bits set, but NO execute 18424327Seric ** bits, sendmail will try to become the owner of that file 18434327Seric ** rather than the real user. Obviously, this only works if 18444327Seric ** sendmail runs as root. 18454327Seric ** 18469370Seric ** This could be done as a subordinate mailer, except that it 18479370Seric ** is used implicitly to save messages in ~/dead.letter. We 18489370Seric ** view this as being sufficiently important as to include it 18499370Seric ** here. For example, if the system is dying, we shouldn't have 18509370Seric ** to create another process plus some pipes to save the message. 18519370Seric ** 1852294Seric ** Parameters: 1853294Seric ** filename -- the name of the file to send to. 18544397Seric ** ctladdr -- the controlling address header -- includes 18554397Seric ** the userid/groupid to be when sending. 1856294Seric ** 1857294Seric ** Returns: 1858294Seric ** The exit code associated with the operation. 1859294Seric ** 1860294Seric ** Side Effects: 1861294Seric ** none. 1862294Seric */ 1863294Seric 186454967Seric mailfile(filename, ctladdr, e) 1865294Seric char *filename; 18664397Seric ADDRESS *ctladdr; 186754967Seric register ENVELOPE *e; 1868294Seric { 1869294Seric register FILE *f; 18704214Seric register int pid; 187153751Seric int mode; 1872294Seric 187359267Seric if (tTd(11, 1)) 187459267Seric { 187559267Seric printf("mailfile %s\n ctladdr=", filename); 187659267Seric printaddr(ctladdr, FALSE); 187759267Seric } 187859267Seric 1879*63753Seric if (e->e_xfp != NULL) 1880*63753Seric fflush(e->e_xfp); 1881*63753Seric 18824214Seric /* 18834214Seric ** Fork so we can change permissions here. 18844214Seric ** Note that we MUST use fork, not vfork, because of 18854214Seric ** the complications of calling subroutines, etc. 18864214Seric */ 18874067Seric 18884214Seric DOFORK(fork); 18894214Seric 18904214Seric if (pid < 0) 18914214Seric return (EX_OSERR); 18924214Seric else if (pid == 0) 18934214Seric { 18944214Seric /* child -- actually write to file */ 18954327Seric struct stat stb; 18964327Seric 18974215Seric (void) signal(SIGINT, SIG_DFL); 18984215Seric (void) signal(SIGHUP, SIG_DFL); 18994215Seric (void) signal(SIGTERM, SIG_DFL); 190023102Seric (void) umask(OldUmask); 190152673Seric 19024327Seric if (stat(filename, &stb) < 0) 190359745Seric stb.st_mode = FileMode; 190453751Seric mode = stb.st_mode; 190552673Seric 190652673Seric /* limit the errors to those actually caused in the child */ 190752673Seric errno = 0; 190852673Seric ExitStat = EX_OK; 190952673Seric 19104327Seric if (bitset(0111, stb.st_mode)) 19114327Seric exit(EX_CANTCREAT); 19124401Seric if (ctladdr == NULL) 191340931Srick ctladdr = &e->e_from; 191453751Seric else 191553751Seric { 191653751Seric /* ignore setuid and setgid bits */ 191753751Seric mode &= ~(S_ISGID|S_ISUID); 191853751Seric } 191953751Seric 192040931Srick /* we have to open the dfile BEFORE setuid */ 192153751Seric if (e->e_dfp == NULL && e->e_df != NULL) 192240931Srick { 192340931Srick e->e_dfp = fopen(e->e_df, "r"); 192452673Seric if (e->e_dfp == NULL) 192552673Seric { 192640931Srick syserr("mailfile: Cannot open %s for %s from %s", 192753751Seric e->e_df, e->e_to, e->e_from); 192840931Srick } 192940931Srick } 193040931Srick 193153751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 19324417Seric { 193352673Seric if (ctladdr->q_uid == 0) 193452673Seric { 19354417Seric (void) setgid(DefGid); 193640972Sbostic (void) initgroups(DefUser, DefGid); 193752673Seric } 193852673Seric else 193952673Seric { 19404417Seric (void) setgid(ctladdr->q_gid); 194153751Seric (void) initgroups(ctladdr->q_ruser ? 194253751Seric ctladdr->q_ruser : ctladdr->q_user, 194340972Sbostic ctladdr->q_gid); 194440972Sbostic } 19454417Seric } 194653751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 19474417Seric { 19484417Seric if (ctladdr->q_uid == 0) 19494417Seric (void) setuid(DefUid); 19504417Seric else 19514417Seric (void) setuid(ctladdr->q_uid); 19524417Seric } 195352673Seric FileName = filename; 195452673Seric LineNumber = 0; 195559745Seric f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); 19564214Seric if (f == NULL) 195752673Seric { 195858151Seric message("554 cannot open"); 19594214Seric exit(EX_CANTCREAT); 196052673Seric } 19614214Seric 196259275Seric putfromline(f, FileMailer, e); 196359275Seric (*e->e_puthdr)(f, FileMailer, e); 196459275Seric putline("\n", f, FileMailer); 196559730Seric (*e->e_putbody)(f, FileMailer, e, NULL); 196659275Seric putline("\n", f, FileMailer); 196752673Seric if (ferror(f)) 196852673Seric { 196958151Seric message("451 I/O error"); 197052673Seric setstat(EX_IOERR); 197152673Seric } 197258680Seric (void) xfclose(f, "mailfile", filename); 19734214Seric (void) fflush(stdout); 19744417Seric 19756887Seric /* reset ISUID & ISGID bits for paranoid systems */ 19764621Seric (void) chmod(filename, (int) stb.st_mode); 197752673Seric exit(ExitStat); 19784315Seric /*NOTREACHED*/ 19794214Seric } 19804214Seric else 19814214Seric { 19824214Seric /* parent -- wait for exit status */ 19839370Seric int st; 19844214Seric 19859370Seric st = waitfor(pid); 19869370Seric if ((st & 0377) != 0) 19879370Seric return (EX_UNAVAILABLE); 19889370Seric else 19899370Seric return ((st >> 8) & 0377); 199040931Srick /*NOTREACHED*/ 19914214Seric } 1992294Seric } 19934550Seric /* 199457454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 199557454Seric ** 199657454Seric ** The signature describes how we are going to send this -- it 199757454Seric ** can be just the hostname (for non-Internet hosts) or can be 199857454Seric ** an ordered list of MX hosts. 199957454Seric ** 200057454Seric ** Parameters: 200157454Seric ** m -- the mailer describing this host. 200257454Seric ** host -- the host name. 200357454Seric ** e -- the current envelope. 200457454Seric ** 200557454Seric ** Returns: 200657454Seric ** The signature for this host. 200757454Seric ** 200857454Seric ** Side Effects: 200957454Seric ** Can tweak the symbol table. 201057454Seric */ 201157454Seric 201257454Seric char * 201357454Seric hostsignature(m, host, e) 201457454Seric register MAILER *m; 201557454Seric char *host; 201657454Seric ENVELOPE *e; 201757454Seric { 201857454Seric register char *p; 201957454Seric register STAB *s; 202057454Seric int i; 202157454Seric int len; 202257454Seric #ifdef NAMED_BIND 202357454Seric int nmx; 202457454Seric auto int rcode; 202559076Seric char *hp; 202659076Seric char *endp; 202759111Seric int oldoptions; 202857454Seric char *mxhosts[MAXMXHOSTS + 1]; 202957454Seric #endif 203057454Seric 203157454Seric /* 203257454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 203357454Seric */ 203457454Seric 203557454Seric p = m->m_mailer; 203657454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 203757454Seric { 203857454Seric /* just an ordinary mailer */ 203957454Seric return host; 204057454Seric } 204157454Seric 204257454Seric /* 204357454Seric ** If it is a numeric address, just return it. 204457454Seric */ 204557454Seric 204657454Seric if (host[0] == '[') 204757454Seric return host; 204857454Seric 204957454Seric /* 205057454Seric ** Look it up in the symbol table. 205157454Seric */ 205257454Seric 205357454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 205457454Seric if (s->s_hostsig != NULL) 205557454Seric return s->s_hostsig; 205657454Seric 205757454Seric /* 205857454Seric ** Not already there -- create a signature. 205957454Seric */ 206057454Seric 206157454Seric #ifdef NAMED_BIND 206259111Seric if (ConfigLevel < 2) 206359111Seric { 206459111Seric oldoptions = _res.options; 206559111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 206659111Seric } 206759111Seric 206859076Seric for (hp = host; hp != NULL; hp = endp) 206957454Seric { 207059076Seric endp = strchr(hp, ':'); 207159076Seric if (endp != NULL) 207259076Seric *endp = '\0'; 207357454Seric 207459273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 207557454Seric 207659076Seric if (nmx <= 0) 207759076Seric { 207859076Seric register MCI *mci; 207959076Seric extern int errno; 208057454Seric 208159076Seric /* update the connection info for this host */ 208259076Seric mci = mci_get(hp, m); 208359076Seric mci->mci_exitstat = rcode; 208459076Seric mci->mci_errno = errno; 2085*63753Seric #ifdef NAMED_BIND 2086*63753Seric mci->mci_herrno = h_errno; 2087*63753Seric #endif 208859076Seric 208959076Seric /* and return the original host name as the signature */ 209059076Seric nmx = 1; 209159076Seric mxhosts[0] = hp; 209259076Seric } 209359076Seric 209459076Seric len = 0; 209559076Seric for (i = 0; i < nmx; i++) 209659076Seric { 209759076Seric len += strlen(mxhosts[i]) + 1; 209859076Seric } 209959076Seric if (s->s_hostsig != NULL) 210059076Seric len += strlen(s->s_hostsig) + 1; 210159076Seric p = xalloc(len); 210259076Seric if (s->s_hostsig != NULL) 210359076Seric { 210459076Seric (void) strcpy(p, s->s_hostsig); 210559076Seric free(s->s_hostsig); 210659076Seric s->s_hostsig = p; 210759076Seric p += strlen(p); 210857454Seric *p++ = ':'; 210959076Seric } 211059076Seric else 211159076Seric s->s_hostsig = p; 211259076Seric for (i = 0; i < nmx; i++) 211359076Seric { 211459076Seric if (i != 0) 211559076Seric *p++ = ':'; 211659076Seric strcpy(p, mxhosts[i]); 211759076Seric p += strlen(p); 211859076Seric } 211959076Seric if (endp != NULL) 212059076Seric *endp++ = ':'; 212157454Seric } 212257454Seric makelower(s->s_hostsig); 212359111Seric if (ConfigLevel < 2) 212459111Seric _res.options = oldoptions; 212557454Seric #else 212657454Seric /* not using BIND -- the signature is just the host name */ 212757454Seric s->s_hostsig = host; 212857454Seric #endif 212957454Seric if (tTd(17, 1)) 213057454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 213157454Seric return s->s_hostsig; 213257454Seric } 2133