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*68689Seric static char sccsid[] = "@(#)deliver.c 8.139 (Berkeley) 03/30/95"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1433931Sbostic #include <netdb.h> 1533931Sbostic #include <errno.h> 1666334Seric #if NAMED_BIND 1734022Sbostic #include <resolv.h> 1863753Seric 1963753Seric extern int h_errno; 2035651Seric #endif 21294Seric 2265075Seric extern char SmtpError[]; 2365075Seric 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 4268627Seric void 4358820Seric sendall(e, mode) 4458820Seric ENVELOPE *e; 4558820Seric char mode; 4658820Seric { 4758820Seric register ADDRESS *q; 4858820Seric char *owner; 4958820Seric int otherowners; 5066009Seric register ENVELOPE *ee; 5166009Seric ENVELOPE *splitenv = NULL; 5268627Seric bool oldverbose = Verbose; 5368627Seric bool somedeliveries = FALSE; 5468627Seric int pid; 5568627Seric extern void sendenvelope(); 5658820Seric 5763839Seric /* 5863839Seric ** If we have had global, fatal errors, don't bother sending 5963839Seric ** the message at all if we are in SMTP mode. Local errors 6063839Seric ** (e.g., a single address failing) will still cause the other 6163839Seric ** addresses to be sent. 6263839Seric */ 6363839Seric 6465580Seric if (bitset(EF_FATALERRS, e->e_flags) && 6565580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 6661092Seric { 6761092Seric e->e_flags |= EF_CLRQUEUE; 6861092Seric return; 6961092Seric } 7061092Seric 7158820Seric /* determine actual delivery mode */ 7264826Seric CurrentLA = getla(); 7358820Seric if (mode == SM_DEFAULT) 7458820Seric { 7558820Seric mode = e->e_sendmode; 7658820Seric if (mode != SM_VERIFY && 7758820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 7858820Seric mode = SM_QUEUE; 7958820Seric } 8058820Seric 8158820Seric if (tTd(13, 1)) 8258820Seric { 8368627Seric extern void printenvflags(); 8468627Seric 8564310Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 8664310Seric mode, e->e_id); 8758820Seric printaddr(&e->e_from, FALSE); 8868627Seric printf("\te_flags = "); 8968627Seric printenvflags(e); 9058820Seric printf("sendqueue:\n"); 9158820Seric printaddr(e->e_sendqueue, TRUE); 9258820Seric } 9358820Seric 9458820Seric /* 9558820Seric ** Do any preprocessing necessary for the mode we are running. 9658820Seric ** Check to make sure the hop count is reasonable. 9758820Seric ** Delete sends to the sender in mailing lists. 9858820Seric */ 9958820Seric 10058820Seric CurEnv = e; 10158820Seric 10258820Seric if (e->e_hopcount > MaxHopCount) 10358820Seric { 10458820Seric errno = 0; 10568627Seric queueup(e, TRUE, mode == SM_QUEUE); 10666258Seric e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 10764495Seric syserr("554 too many hops %d (%d max): from %s via %s, to %s", 10858820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 10966003Seric RealHostName == NULL ? "localhost" : RealHostName, 11066003Seric e->e_sendqueue->q_paddr); 11158820Seric return; 11258820Seric } 11358820Seric 11459435Seric /* 11559435Seric ** Do sender deletion. 11659435Seric ** 11759435Seric ** If the sender has the QQUEUEUP flag set, skip this. 11859435Seric ** This can happen if the name server is hosed when you 11959435Seric ** are trying to send mail. The result is that the sender 12059435Seric ** is instantiated in the queue as a recipient. 12159435Seric */ 12259435Seric 12364118Seric if (!bitset(EF_METOO, e->e_flags) && 12464118Seric !bitset(QQUEUEUP, e->e_from.q_flags)) 12558820Seric { 12658820Seric if (tTd(13, 5)) 12758820Seric { 12858820Seric printf("sendall: QDONTSEND "); 12958820Seric printaddr(&e->e_from, FALSE); 13058820Seric } 13158820Seric e->e_from.q_flags |= QDONTSEND; 13268627Seric (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 13358820Seric } 13458820Seric 13558820Seric /* 13658820Seric ** Handle alias owners. 13758820Seric ** 13858820Seric ** We scan up the q_alias chain looking for owners. 13958820Seric ** We discard owners that are the same as the return path. 14058820Seric */ 14158820Seric 14258820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14358820Seric { 14458820Seric register struct address *a; 14558820Seric 14658820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 14758820Seric continue; 14858820Seric if (a != NULL) 14958820Seric q->q_owner = a->q_owner; 15058820Seric 15158820Seric if (q->q_owner != NULL && 15258820Seric !bitset(QDONTSEND, q->q_flags) && 15358820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 15458820Seric q->q_owner = NULL; 15558820Seric } 15658820Seric 15758820Seric owner = ""; 15858820Seric otherowners = 1; 15958820Seric while (owner != NULL && otherowners > 0) 16058820Seric { 16158820Seric owner = NULL; 16258820Seric otherowners = 0; 16358820Seric 16458820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16558820Seric { 16658820Seric if (bitset(QDONTSEND, q->q_flags)) 16758820Seric continue; 16858820Seric 16958820Seric if (q->q_owner != NULL) 17058820Seric { 17158820Seric if (owner == NULL) 17258820Seric owner = q->q_owner; 17358820Seric else if (owner != q->q_owner) 17458820Seric { 17558820Seric if (strcmp(owner, q->q_owner) == 0) 17658820Seric { 17758820Seric /* make future comparisons cheap */ 17858820Seric q->q_owner = owner; 17958820Seric } 18058820Seric else 18158820Seric { 18258820Seric otherowners++; 18358820Seric } 18458820Seric owner = q->q_owner; 18558820Seric } 18658820Seric } 18758820Seric else 18858820Seric { 18958820Seric otherowners++; 19058820Seric } 19168627Seric 19268627Seric /* 19368627Seric ** If this mailer is expensive, and if we don't 19468627Seric ** want to make connections now, just mark these 19568627Seric ** addresses and return. This is useful if we 19668627Seric ** want to batch connections to reduce load. This 19768627Seric ** will cause the messages to be queued up, and a 19868627Seric ** daemon will come along to send the messages later. 19968627Seric */ 20068627Seric 20168627Seric if (bitset(QBADADDR|QQUEUEUP, q->q_flags)) 20268627Seric continue; 20368627Seric if (NoConnect && !Verbose && 20468627Seric bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 20568627Seric { 20668627Seric q->q_flags |= QQUEUEUP; 20768627Seric e->e_to = q->q_paddr; 20868627Seric message("queued"); 20968627Seric if (LogLevel > 8) 21068627Seric logdelivery(q->q_mailer, NULL, 21168627Seric "queued", NULL, 21268627Seric (time_t) 0, e); 21368627Seric e->e_to = NULL; 21468627Seric } 21568627Seric else 21668627Seric { 21768627Seric somedeliveries = TRUE; 21868627Seric } 21958820Seric } 22058820Seric 22158820Seric if (owner != NULL && otherowners > 0) 22258820Seric { 22358820Seric extern HDR *copyheader(); 22458820Seric extern ADDRESS *copyqueue(); 22558820Seric 22658820Seric /* 22758820Seric ** Split this envelope into two. 22858820Seric */ 22958820Seric 23058820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 23158820Seric *ee = *e; 23258820Seric ee->e_id = NULL; 23358820Seric (void) queuename(ee, '\0'); 23458820Seric 23558820Seric if (tTd(13, 1)) 23658820Seric printf("sendall: split %s into %s\n", 23758820Seric e->e_id, ee->e_id); 23858820Seric 23958820Seric ee->e_header = copyheader(e->e_header); 24058820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 24158820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 24268627Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 24366784Seric ee->e_flags |= EF_NORECEIPT; 24458820Seric setsender(owner, ee, NULL, TRUE); 24558820Seric if (tTd(13, 5)) 24658820Seric { 24758820Seric printf("sendall(split): QDONTSEND "); 24858820Seric printaddr(&ee->e_from, FALSE); 24958820Seric } 25058820Seric ee->e_from.q_flags |= QDONTSEND; 25158820Seric ee->e_dfp = NULL; 25258820Seric ee->e_xfp = NULL; 25358820Seric ee->e_errormode = EM_MAIL; 25466009Seric ee->e_sibling = splitenv; 25566009Seric splitenv = ee; 25658820Seric 25758820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 25868627Seric { 25958820Seric if (q->q_owner == owner) 26066305Seric { 26158820Seric q->q_flags |= QDONTSEND; 26266305Seric q->q_flags &= ~QQUEUEUP; 26366305Seric } 26468627Seric } 26558820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 26668627Seric { 26758820Seric if (q->q_owner != owner) 26866305Seric { 26958820Seric q->q_flags |= QDONTSEND; 27066305Seric q->q_flags &= ~QQUEUEUP; 27166305Seric } 27268627Seric else 27368627Seric { 27468627Seric /* clear DSN parameters */ 27568627Seric q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); 27668627Seric q->q_flags |= QPINGONFAILURE|QPINGONDELAY; 27768627Seric } 27868627Seric } 27958820Seric 28068627Seric if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 28158820Seric { 28268627Seric char df1buf[20], df2buf[20]; 28368627Seric 28458820Seric ee->e_dfp = NULL; 28568627Seric strcpy(df1buf, queuename(e, 'd')); 28668627Seric strcpy(df2buf, queuename(ee, 'd')); 28768627Seric if (link(df1buf, df2buf) < 0) 28858820Seric { 28958820Seric syserr("sendall: link(%s, %s)", 29068627Seric df1buf, df2buf); 29158820Seric } 29258820Seric } 29358820Seric #ifdef LOG 29458820Seric if (LogLevel > 4) 29566012Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 29666012Seric ee->e_id, e->e_id, owner); 29758820Seric #endif 29858820Seric } 29958820Seric } 30058820Seric 30158820Seric if (owner != NULL) 30258820Seric { 30358820Seric setsender(owner, e, NULL, TRUE); 30458820Seric if (tTd(13, 5)) 30558820Seric { 30658820Seric printf("sendall(owner): QDONTSEND "); 30758820Seric printaddr(&e->e_from, FALSE); 30858820Seric } 30958820Seric e->e_from.q_flags |= QDONTSEND; 31058820Seric e->e_errormode = EM_MAIL; 31166784Seric e->e_flags |= EF_NORECEIPT; 31258820Seric } 31358820Seric 31468627Seric /* if nothing to be delivered, just queue up everything */ 31568627Seric if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY) 31668627Seric mode = SM_QUEUE; 31768627Seric 31866009Seric # ifdef QUEUE 31966009Seric if ((mode == SM_QUEUE || mode == SM_FORK || 32066009Seric (mode != SM_VERIFY && SuperSafe)) && 32166009Seric !bitset(EF_INQUEUE, e->e_flags)) 32258916Seric { 32366009Seric /* be sure everything is instantiated in the queue */ 32468627Seric queueup(e, TRUE, mode == SM_QUEUE); 32566009Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 32668627Seric queueup(ee, TRUE, mode == SM_QUEUE); 32758916Seric } 32866009Seric #endif /* QUEUE */ 32958916Seric 33063839Seric /* 33168627Seric ** If we belong in background, fork now. 33263839Seric */ 33363839Seric 33458916Seric switch (mode) 33558916Seric { 33658916Seric case SM_VERIFY: 33758916Seric Verbose = TRUE; 33858916Seric break; 33958916Seric 34058916Seric case SM_QUEUE: 34158916Seric queueonly: 34268627Seric if (e->e_nrcpts > 0) 34368627Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 34458916Seric return; 34558916Seric 34658916Seric case SM_FORK: 34758916Seric if (e->e_xfp != NULL) 34858916Seric (void) fflush(e->e_xfp); 34958916Seric 35065830Seric # if !HASFLOCK 35158916Seric /* 35264296Seric ** Since fcntl locking has the interesting semantic that 35364296Seric ** the lock is owned by a process, not by an open file 35464296Seric ** descriptor, we have to flush this to the queue, and 35564296Seric ** then restart from scratch in the child. 35658916Seric */ 35758916Seric 35868627Seric { 35968627Seric /* save id for future use */ 36068627Seric char *qid = e->e_id; 36158916Seric 36268627Seric /* now drop the envelope in the parent */ 36368627Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 36468627Seric dropenvelope(e); 36564296Seric 36668627Seric /* and reacquire in the child */ 36768627Seric (void) dowork(qid, TRUE, FALSE, e); 36868627Seric } 36964296Seric 37064296Seric return; 37164296Seric 37264296Seric # else /* HASFLOCK */ 37364296Seric 37458916Seric pid = fork(); 37558916Seric if (pid < 0) 37658916Seric { 37758916Seric goto queueonly; 37858916Seric } 37958916Seric else if (pid > 0) 38058916Seric { 38164310Seric /* be sure we leave the temp files to our child */ 38264310Seric /* can't call unlockqueue to avoid unlink of xfp */ 38364310Seric if (e->e_lockfp != NULL) 38468627Seric (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); 38564310Seric e->e_lockfp = NULL; 38664310Seric 38764310Seric /* close any random open files in the envelope */ 38864310Seric closexscript(e); 38964310Seric if (e->e_dfp != NULL) 39068627Seric (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); 39164310Seric e->e_dfp = NULL; 39268627Seric e->e_id = NULL; 39368627Seric e->e_flags &= ~EF_HAS_DF; 39466017Seric 39566017Seric /* catch intermediate zombie */ 39666017Seric (void) waitfor(pid); 39758916Seric return; 39858916Seric } 39958916Seric 40058916Seric /* double fork to avoid zombies */ 40166017Seric pid = fork(); 40266017Seric if (pid > 0) 40358916Seric exit(EX_OK); 40458916Seric 40558916Seric /* be sure we are immune from the terminal */ 40663839Seric disconnect(1, e); 40758916Seric 40866017Seric /* prevent parent from waiting if there was an error */ 40966017Seric if (pid < 0) 41066017Seric { 41166017Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 41266017Seric finis(); 41366017Seric } 41466017Seric 41558916Seric /* 41658916Seric ** Close any cached connections. 41758916Seric ** 41858916Seric ** We don't send the QUIT protocol because the parent 41958916Seric ** still knows about the connection. 42058916Seric ** 42158916Seric ** This should only happen when delivering an error 42258916Seric ** message. 42358916Seric */ 42458916Seric 42558916Seric mci_flush(FALSE, NULL); 42658916Seric 42764296Seric # endif /* HASFLOCK */ 42864296Seric 42958916Seric break; 43058916Seric } 43158916Seric 43268627Seric if (splitenv != NULL) 43368627Seric { 43468627Seric if (tTd(13, 1)) 43568627Seric { 43668627Seric printf("\nsendall: Split queue; remaining queue:\n"); 43768627Seric printaddr(e->e_sendqueue, TRUE); 43868627Seric } 43968627Seric 44068627Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 44168627Seric { 44268627Seric CurEnv = ee; 44368627Seric if (mode != SM_VERIFY) 44468627Seric openxscript(ee); 44568627Seric sendenvelope(ee, mode); 44668627Seric dropenvelope(ee); 44768627Seric } 44868627Seric 44968627Seric CurEnv = e; 45068627Seric } 45168627Seric sendenvelope(e, mode); 45268627Seric Verbose = oldverbose; 45368627Seric } 45468627Seric 45568627Seric void 45668627Seric sendenvelope(e, mode) 45768627Seric register ENVELOPE *e; 45868627Seric char mode; 45968627Seric { 46068627Seric register ADDRESS *q; 46168627Seric bool didany; 46268627Seric 46358820Seric /* 46468627Seric ** If we have had global, fatal errors, don't bother sending 46568627Seric ** the message at all if we are in SMTP mode. Local errors 46668627Seric ** (e.g., a single address failing) will still cause the other 46768627Seric ** addresses to be sent. 46868627Seric */ 46968627Seric 47068627Seric if (bitset(EF_FATALERRS, e->e_flags) && 47168627Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 47268627Seric { 47368627Seric e->e_flags |= EF_CLRQUEUE; 47468627Seric return; 47568627Seric } 47668627Seric 47768627Seric /* 47858820Seric ** Run through the list and send everything. 47963965Seric ** 48063965Seric ** Set EF_GLOBALERRS so that error messages during delivery 48163965Seric ** result in returned mail. 48258820Seric */ 48358820Seric 48458820Seric e->e_nsent = 0; 48563965Seric e->e_flags |= EF_GLOBALERRS; 48668627Seric didany = FALSE; 48764696Seric 48864696Seric /* now run through the queue */ 48958820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 49058820Seric { 49164441Seric #ifdef XDEBUG 49264441Seric char wbuf[MAXNAME + 20]; 49364441Seric 49464441Seric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 49564441Seric checkfd012(wbuf); 49664441Seric #endif 49758820Seric if (mode == SM_VERIFY) 49858820Seric { 49958820Seric e->e_to = q->q_paddr; 50058820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 50160173Seric { 50264942Seric if (q->q_host != NULL && q->q_host[0] != '\0') 50364942Seric message("deliverable: mailer %s, host %s, user %s", 50464942Seric q->q_mailer->m_name, 50564942Seric q->q_host, 50664942Seric q->q_user); 50764942Seric else 50864942Seric message("deliverable: mailer %s, user %s", 50964942Seric q->q_mailer->m_name, 51064942Seric q->q_user); 51160173Seric } 51258820Seric } 51358820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 51458820Seric { 51558820Seric # ifdef QUEUE 51658820Seric /* 51758820Seric ** Checkpoint the send list every few addresses 51858820Seric */ 51958820Seric 52058820Seric if (e->e_nsent >= CheckpointInterval) 52158820Seric { 52258820Seric queueup(e, TRUE, FALSE); 52358820Seric e->e_nsent = 0; 52458820Seric } 52558820Seric # endif /* QUEUE */ 52658820Seric (void) deliver(e, q); 52768627Seric didany = TRUE; 52858820Seric } 52958820Seric } 53068627Seric if (didany) 53168627Seric { 53268627Seric e->e_dtime = curtime(); 53368627Seric e->e_ntries++; 53468627Seric } 53558820Seric 53664441Seric #ifdef XDEBUG 53764441Seric checkfd012("end of sendenvelope"); 53864441Seric #endif 53964441Seric 54058820Seric if (mode == SM_FORK) 54158820Seric finis(); 54258820Seric } 54358820Seric /* 54458820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 54558820Seric ** 54658820Seric ** This MUST be a macro, since after a vfork we are running 54758820Seric ** two processes on the same stack!!! 54858820Seric ** 54958820Seric ** Parameters: 55058820Seric ** none. 55158820Seric ** 55258820Seric ** Returns: 55358820Seric ** From a macro??? You've got to be kidding! 55458820Seric ** 55558820Seric ** Side Effects: 55658820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 55758820Seric ** pid of child in parent, zero in child. 55858820Seric ** -1 on unrecoverable error. 55958820Seric ** 56058820Seric ** Notes: 56158820Seric ** I'm awfully sorry this looks so awful. That's 56258820Seric ** vfork for you..... 56358820Seric */ 56458820Seric 56558820Seric # define NFORKTRIES 5 56658820Seric 56758820Seric # ifndef FORK 56858820Seric # define FORK fork 56958820Seric # endif 57058820Seric 57158820Seric # define DOFORK(fORKfN) \ 57258820Seric {\ 57358820Seric register int i;\ 57458820Seric \ 57558820Seric for (i = NFORKTRIES; --i >= 0; )\ 57658820Seric {\ 57758820Seric pid = fORKfN();\ 57858820Seric if (pid >= 0)\ 57958820Seric break;\ 58058820Seric if (i > 0)\ 58158820Seric sleep((unsigned) NFORKTRIES - i);\ 58258820Seric }\ 58358820Seric } 58458820Seric /* 58558820Seric ** DOFORK -- simple fork interface to DOFORK. 58658820Seric ** 58758820Seric ** Parameters: 58858820Seric ** none. 58958820Seric ** 59058820Seric ** Returns: 59158820Seric ** pid of child in parent. 59258820Seric ** zero in child. 59358820Seric ** -1 on error. 59458820Seric ** 59558820Seric ** Side Effects: 59658820Seric ** returns twice, once in parent and once in child. 59758820Seric */ 59858820Seric 59958820Seric dofork() 60058820Seric { 60168627Seric register int pid = -1; 60258820Seric 60358820Seric DOFORK(fork); 60458820Seric return (pid); 60558820Seric } 60658820Seric /* 6074315Seric ** DELIVER -- Deliver a message to a list of addresses. 608294Seric ** 6094315Seric ** This routine delivers to everyone on the same host as the 6104315Seric ** user on the head of the list. It is clever about mailers 6114315Seric ** that don't handle multiple users. It is NOT guaranteed 6124315Seric ** that it will deliver to all these addresses however -- so 6134315Seric ** deliver should be called once for each address on the 6144315Seric ** list. 6154315Seric ** 616294Seric ** Parameters: 6179370Seric ** e -- the envelope to deliver. 6184621Seric ** firstto -- head of the address list to deliver to. 619294Seric ** 620294Seric ** Returns: 621294Seric ** zero -- successfully delivered. 622294Seric ** else -- some failure, see ExitStat for more info. 623294Seric ** 624294Seric ** Side Effects: 625294Seric ** The standard input is passed off to someone. 626294Seric */ 627294Seric 62868627Seric int 6299370Seric deliver(e, firstto) 6309370Seric register ENVELOPE *e; 6314621Seric ADDRESS *firstto; 632294Seric { 6334452Seric char *host; /* host being sent to */ 6344452Seric char *user; /* user being sent to */ 635294Seric char **pvp; 6363233Seric register char **mvp; 6373233Seric register char *p; 63810306Seric register MAILER *m; /* mailer for this recipient */ 6394397Seric ADDRESS *ctladdr; 64054967Seric register MCI *mci; 6414621Seric register ADDRESS *to = firstto; 6424863Seric bool clever = FALSE; /* running user smtp to this mailer */ 64368627Seric ADDRESS *tochain = NULL; /* users chain in this mailer call */ 64451951Seric int rcode; /* response code */ 64557454Seric char *firstsig; /* signature of firstto */ 64668627Seric int pid = -1; 64758820Seric char *curhost; 64868627Seric time_t xstart; 64958820Seric int mpvect[2]; 65058820Seric int rpvect[2]; 65110306Seric char *pv[MAXPV+1]; 65258704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 65368627Seric char buf[MAXNAME + 1]; 65468627Seric char rpathbuf[MAXNAME + 1]; /* translated return path */ 65557441Seric extern int checkcompat(); 656294Seric 6574488Seric errno = 0; 65858680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6593233Seric return (0); 660294Seric 66166334Seric #if NAMED_BIND 66234022Sbostic /* unless interactive, try twice, over a minute */ 66365580Seric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 66465580Seric { 66534022Sbostic _res.retrans = 30; 66634022Sbostic _res.retry = 2; 66734022Sbostic } 66836788Sbostic #endif 66934022Sbostic 6706974Seric m = to->q_mailer; 6716974Seric host = to->q_host; 67258803Seric CurEnv = e; /* just in case */ 67359044Seric e->e_statmsg = NULL; 67464718Seric SmtpError[0] = '\0'; 67568627Seric xstart = curtime(); 6766974Seric 6777672Seric if (tTd(10, 1)) 67866010Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 67966010Seric e->e_id, m->m_name, host, to->q_user); 68064725Seric if (tTd(10, 100)) 68164725Seric printopenfds(FALSE); 682294Seric 683294Seric /* 6843233Seric ** Do initial argv setup. 6853233Seric ** Insert the mailer name. Notice that $x expansion is 6863233Seric ** NOT done on the mailer name. Then, if the mailer has 6873233Seric ** a picky -f flag, we insert it as appropriate. This 6883233Seric ** code does not check for 'pv' overflow; this places a 6893233Seric ** manifest lower limit of 4 for MAXPV. 6908062Seric ** The from address rewrite is expected to make 6918062Seric ** the address relative to the other end. 6922968Seric */ 6932968Seric 6944452Seric /* rewrite from address, using rewriting rules */ 69559163Seric rcode = EX_OK; 69668627Seric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 69768627Seric p = e->e_sender; 69868627Seric else 69968627Seric p = e->e_from.q_paddr; 70068627Seric (void) strcpy(rpathbuf, remotename(p, m, 70159163Seric RF_SENDERADDR|RF_CANONICAL, 70259163Seric &rcode, e)); 70358680Seric define('g', rpathbuf, e); /* translated return path */ 7049370Seric define('h', host, e); /* to host */ 7053233Seric Errors = 0; 7063233Seric pvp = pv; 7073233Seric *pvp++ = m->m_argv[0]; 7082968Seric 7093233Seric /* insert -f or -r flag as appropriate */ 71010682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 7113233Seric { 71210682Seric if (bitnset(M_FOPT, m->m_flags)) 7133233Seric *pvp++ = "-f"; 7143233Seric else 7153233Seric *pvp++ = "-r"; 71651951Seric *pvp++ = newstr(rpathbuf); 7173233Seric } 718294Seric 719294Seric /* 7203233Seric ** Append the other fixed parts of the argv. These run 7213233Seric ** up to the first entry containing "$u". There can only 7223233Seric ** be one of these, and there are only a few more slots 7233233Seric ** in the pv after it. 724294Seric */ 725294Seric 7263233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 727294Seric { 72858050Seric /* can't use strchr here because of sign extension problems */ 72958050Seric while (*p != '\0') 73058050Seric { 73158050Seric if ((*p++ & 0377) == MACROEXPAND) 73258050Seric { 73358050Seric if (*p == 'u') 73458050Seric break; 73558050Seric } 73658050Seric } 73758050Seric 73858050Seric if (*p != '\0') 7393233Seric break; 7403233Seric 7413233Seric /* this entry is safe -- go ahead and process it */ 74268627Seric expand(*mvp, buf, sizeof buf, e); 7433233Seric *pvp++ = newstr(buf); 7443233Seric if (pvp >= &pv[MAXPV - 3]) 7453233Seric { 74658151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7473233Seric return (-1); 7483233Seric } 749294Seric } 7504863Seric 7516038Seric /* 7526038Seric ** If we have no substitution for the user name in the argument 7536038Seric ** list, we know that we must supply the names otherwise -- and 7546038Seric ** SMTP is the answer!! 7556038Seric */ 7566038Seric 7573233Seric if (*mvp == NULL) 7584863Seric { 7594863Seric /* running SMTP */ 7605179Seric # ifdef SMTP 7614863Seric clever = TRUE; 7624863Seric *pvp = NULL; 76356795Seric # else /* SMTP */ 7646038Seric /* oops! we don't implement SMTP */ 76564718Seric syserr("554 SMTP style mailer not implemented"); 7665179Seric return (EX_SOFTWARE); 76756795Seric # endif /* SMTP */ 7684863Seric } 769294Seric 770294Seric /* 7713233Seric ** At this point *mvp points to the argument with $u. We 7723233Seric ** run through our address list and append all the addresses 7733233Seric ** we can. If we run out of space, do not fret! We can 7743233Seric ** always send another copy later. 775294Seric */ 776294Seric 7773233Seric tobuf[0] = '\0'; 7789370Seric e->e_to = tobuf; 7794397Seric ctladdr = NULL; 78057454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7813233Seric for (; to != NULL; to = to->q_next) 782294Seric { 7833233Seric /* avoid sending multiple recipients to dumb mailers */ 78410682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7853233Seric break; 7863233Seric 7873233Seric /* if already sent or not for this host, don't send */ 78858680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 78957454Seric to->q_mailer != firstto->q_mailer || 79057454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7913233Seric continue; 7924397Seric 7938225Seric /* avoid overflowing tobuf */ 79442462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7958225Seric break; 7968225Seric 7977672Seric if (tTd(10, 1)) 7985032Seric { 7995032Seric printf("\nsend to "); 8005032Seric printaddr(to, FALSE); 8015032Seric } 8025032Seric 8034397Seric /* compute effective uid/gid when sending */ 80468627Seric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 80565137Seric ctladdr = getctladdr(to); 8064397Seric 80768627Seric if (tTd(10, 2)) 80868627Seric { 80968627Seric printf("ctladdr="); 81068627Seric printaddr(ctladdr, FALSE); 81168627Seric } 81268627Seric 8133233Seric user = to->q_user; 8149370Seric e->e_to = to->q_paddr; 81557731Seric if (tTd(10, 5)) 81657731Seric { 81757731Seric printf("deliver: QDONTSEND "); 81857731Seric printaddr(to, FALSE); 81957731Seric } 82058680Seric to->q_flags |= QDONTSEND; 8213233Seric 8223233Seric /* 8233233Seric ** Check to see that these people are allowed to 8243233Seric ** talk to each other. 8253233Seric */ 8263233Seric 82710699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 82810699Seric { 82968627Seric e->e_flags |= EF_NO_BODY_RETN; 83058151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 83168627Seric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 83210699Seric continue; 83310699Seric } 83468627Seric #if NAMED_BIND 83568627Seric h_errno = 0; 83668627Seric #endif 83757441Seric rcode = checkcompat(to, e); 83857459Seric if (rcode != EX_OK) 839294Seric { 84068627Seric markfailure(e, to, NULL, rcode); 84168627Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8423233Seric continue; 843294Seric } 8443233Seric 8453233Seric /* 8464099Seric ** Strip quote bits from names if the mailer is dumb 8474099Seric ** about them. 8483233Seric */ 8493233Seric 85010682Seric if (bitnset(M_STRIPQ, m->m_flags)) 851294Seric { 85254983Seric stripquotes(user); 85354983Seric stripquotes(host); 8543233Seric } 8553233Seric 8569206Seric /* hack attack -- delivermail compatibility */ 8579206Seric if (m == ProgMailer && *user == '|') 8589206Seric user++; 8599206Seric 8603233Seric /* 8614161Seric ** If an error message has already been given, don't 8624161Seric ** bother to send to this address. 8634161Seric ** 8644161Seric ** >>>>>>>>>> This clause assumes that the local mailer 8654161Seric ** >> NOTE >> cannot do any further aliasing; that 8664161Seric ** >>>>>>>>>> function is subsumed by sendmail. 8674161Seric */ 8684161Seric 8697293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8704161Seric continue; 8714161Seric 8724283Seric /* save statistics.... */ 8739370Seric markstats(e, to); 8744283Seric 8754161Seric /* 8763233Seric ** See if this user name is "special". 8773233Seric ** If the user name has a slash in it, assume that this 8786974Seric ** is a file -- send it off without further ado. Note 8796974Seric ** that this type of addresses is not processed along 8806974Seric ** with the others, so we fudge on the To person. 8813233Seric */ 8823233Seric 88357402Seric if (m == FileMailer) 8843233Seric { 88565060Seric rcode = mailfile(user, ctladdr, e); 88668627Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 88768627Seric e->e_nsent++; 88857402Seric if (rcode == EX_OK) 88968627Seric { 89057402Seric to->q_flags |= QSENT; 89168627Seric if (bitnset(M_LOCALMAILER, m->m_flags) && 89268627Seric (e->e_receiptto != NULL || 89368627Seric bitset(QPINGONSUCCESS, to->q_flags))) 89468627Seric { 89568627Seric to->q_flags |= QREPORT; 89668627Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 89768627Seric to->q_paddr); 89868627Seric } 89968627Seric } 90068627Seric to->q_statdate = curtime(); 90157402Seric continue; 902294Seric } 9033233Seric 9044315Seric /* 9054315Seric ** Address is verified -- add this user to mailer 9064315Seric ** argv, and add it to the print list of recipients. 9074315Seric */ 9084315Seric 9096059Seric /* link together the chain of recipients */ 9106272Seric to->q_tchain = tochain; 9116272Seric tochain = to; 9126059Seric 9133233Seric /* create list of users for error messages */ 9149388Seric (void) strcat(tobuf, ","); 9154082Seric (void) strcat(tobuf, to->q_paddr); 9169370Seric define('u', user, e); /* to user */ 91764694Seric p = to->q_home; 91864694Seric if (p == NULL && ctladdr != NULL) 91964694Seric p = ctladdr->q_home; 92064694Seric define('z', p, e); /* user's home */ 9213233Seric 9224863Seric /* 9236059Seric ** Expand out this user into argument list. 9244863Seric */ 9254863Seric 9266059Seric if (!clever) 9273233Seric { 92868627Seric expand(*mvp, buf, sizeof buf, e); 9294863Seric *pvp++ = newstr(buf); 9304863Seric if (pvp >= &pv[MAXPV - 2]) 9314863Seric { 9324863Seric /* allow some space for trailing parms */ 9334863Seric break; 9344863Seric } 9354863Seric } 936294Seric } 937294Seric 9384067Seric /* see if any addresses still exist */ 9394067Seric if (tobuf[0] == '\0') 9404863Seric { 9419370Seric define('g', (char *) NULL, e); 9424067Seric return (0); 9434863Seric } 9444067Seric 9453233Seric /* print out messages as full list */ 9469388Seric e->e_to = tobuf + 1; 9473233Seric 948294Seric /* 9493233Seric ** Fill out any parameters after the $u parameter. 950294Seric */ 951294Seric 9524863Seric while (!clever && *++mvp != NULL) 953294Seric { 95468627Seric expand(*mvp, buf, sizeof buf, e); 9553233Seric *pvp++ = newstr(buf); 9563233Seric if (pvp >= &pv[MAXPV]) 95758151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 958294Seric } 9593233Seric *pvp++ = NULL; 960294Seric 961294Seric /* 962294Seric ** Call the mailer. 9632898Seric ** The argument vector gets built, pipes 964294Seric ** are created as necessary, and we fork & exec as 9652898Seric ** appropriate. 9664863Seric ** If we are running SMTP, we just need to clean up. 967294Seric */ 968294Seric 96965137Seric /*XXX this seems a bit wierd */ 97065750Seric if (ctladdr == NULL && m != ProgMailer && 97165750Seric bitset(QGOODUID, e->e_from.q_flags)) 97265137Seric ctladdr = &e->e_from; 97365137Seric 97466334Seric #if NAMED_BIND 97551313Seric if (ConfigLevel < 2) 97651313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 97735651Seric #endif 97854967Seric 9797672Seric if (tTd(11, 1)) 980294Seric { 9818178Seric printf("openmailer:"); 98258820Seric printav(pv); 983294Seric } 9844488Seric errno = 0; 98568627Seric #if NAMED_BIND 98668627Seric h_errno = 0; 98768627Seric #endif 9883233Seric 98968627Seric CurHostName = NULL; 99025050Seric 9916038Seric /* 9926038Seric ** Deal with the special case of mail handled through an IPC 9936038Seric ** connection. 9946038Seric ** In this case we don't actually fork. We must be 9956038Seric ** running SMTP for this to work. We will return a 9966038Seric ** zero pid to indicate that we are running IPC. 99711160Seric ** We also handle a debug version that just talks to stdin/out. 9986038Seric */ 9996038Seric 100058820Seric curhost = NULL; 100164334Seric SmtpPhase = NULL; 100264718Seric mci = NULL; 100358820Seric 100464401Seric #ifdef XDEBUG 100564401Seric { 100664401Seric char wbuf[MAXLINE]; 100764401Seric 100864401Seric /* make absolutely certain 0, 1, and 2 are in use */ 100964401Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 101064401Seric checkfd012(wbuf); 101164401Seric } 101264401Seric #endif 101364401Seric 101468627Seric /* check for 8-bit available */ 101568627Seric if (bitset(EF_HAS8BIT, e->e_flags) && 101668627Seric bitnset(M_7BITS, m->m_flags) && 101768627Seric !bitset(MM_MIME8BIT, MimeMode)) 101868627Seric { 101968627Seric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 102068627Seric rcode = EX_DATAERR; 102168627Seric goto give_up; 102268627Seric } 102368627Seric 102411160Seric /* check for Local Person Communication -- not for mortals!!! */ 102511160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 102611160Seric { 102754967Seric mci = (MCI *) xalloc(sizeof *mci); 102854993Seric bzero((char *) mci, sizeof *mci); 102953738Seric mci->mci_in = stdin; 103053738Seric mci->mci_out = stdout; 103154967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 103253751Seric mci->mci_mailer = m; 103311160Seric } 103454967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 103554967Seric strcmp(m->m_mailer, "[TCP]") == 0) 10366038Seric { 103752107Seric #ifdef DAEMON 103857454Seric register int i; 103968627Seric register u_short port = 0; 10406038Seric 104164844Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 104264844Seric { 104364844Seric syserr("null host name for %s mailer", m->m_mailer); 104464844Seric rcode = EX_CONFIG; 104564844Seric goto give_up; 104664844Seric } 104764844Seric 104858820Seric CurHostName = pv[1]; 104958820Seric curhost = hostsignature(m, pv[1], e); 105054967Seric 105158479Seric if (curhost == NULL || curhost[0] == '\0') 105258479Seric { 105364844Seric syserr("null host signature for %s", pv[1]); 105467133Seric rcode = EX_CONFIG; 105558820Seric goto give_up; 105658479Seric } 105758479Seric 10586038Seric if (!clever) 105958479Seric { 106058151Seric syserr("554 non-clever IPC"); 106164718Seric rcode = EX_CONFIG; 106258820Seric goto give_up; 106358479Seric } 106458820Seric if (pv[2] != NULL) 106558820Seric port = atoi(pv[2]); 106658820Seric tryhost: 106757454Seric while (*curhost != '\0') 106829433Sbloom { 106957454Seric register char *p; 107068627Seric static char hostbuf[MAXNAME + 1]; 107157454Seric 107257454Seric /* pull the next host from the signature */ 107357454Seric p = strchr(curhost, ':'); 107457454Seric if (p == NULL) 107557454Seric p = &curhost[strlen(curhost)]; 107664718Seric if (p == curhost) 107764718Seric { 107864718Seric syserr("deliver: null host name in signature"); 107964726Seric curhost++; 108064718Seric continue; 108164718Seric } 108257454Seric strncpy(hostbuf, curhost, p - curhost); 108357454Seric hostbuf[p - curhost] = '\0'; 108457454Seric if (*p != '\0') 108557454Seric p++; 108657454Seric curhost = p; 108757454Seric 108853738Seric /* see if we already know that this host is fried */ 108957454Seric CurHostName = hostbuf; 109057454Seric mci = mci_get(hostbuf, m); 109154967Seric if (mci->mci_state != MCIS_CLOSED) 109257387Seric { 109357387Seric if (tTd(11, 1)) 109457387Seric { 109557387Seric printf("openmailer: "); 109664731Seric mci_dump(mci, FALSE); 109757387Seric } 109857943Seric CurHostName = mci->mci_host; 109968627Seric message("Using cached connection to %s via %s...", 110068627Seric hostbuf, m->m_name); 110158820Seric break; 110257387Seric } 110353751Seric mci->mci_mailer = m; 110454967Seric if (mci->mci_exitstat != EX_OK) 110554967Seric continue; 110654967Seric 110754967Seric /* try the connection */ 110857454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 110968627Seric message("Connecting to %s via %s...", 111057454Seric hostbuf, m->m_name); 111157454Seric i = makeconnection(hostbuf, port, mci, 111254967Seric bitnset(M_SECURE_PORT, m->m_flags)); 111354967Seric mci->mci_exitstat = i; 111454967Seric mci->mci_errno = errno; 111566334Seric #if NAMED_BIND 111663753Seric mci->mci_herrno = h_errno; 111763753Seric #endif 111854967Seric if (i == EX_OK) 111952106Seric { 112054967Seric mci->mci_state = MCIS_OPENING; 112154967Seric mci_cache(mci); 112263753Seric if (TrafficLogFile != NULL) 112363753Seric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 112463753Seric getpid(), hostbuf); 112554967Seric break; 112634022Sbostic } 112754967Seric else if (tTd(11, 1)) 112854967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 112954967Seric i, errno); 113053738Seric 113153738Seric /* enter status of this host */ 113253738Seric setstat(i); 113364718Seric 113464718Seric /* should print some message here for -v mode */ 11356047Seric } 113664718Seric if (mci == NULL) 113764718Seric { 113864718Seric syserr("deliver: no host name"); 113964718Seric rcode = EX_OSERR; 114064718Seric goto give_up; 114164718Seric } 114254993Seric mci->mci_pid = 0; 114354967Seric #else /* no DAEMON */ 114458151Seric syserr("554 openmailer: no IPC"); 114557387Seric if (tTd(11, 1)) 114657387Seric printf("openmailer: NULL\n"); 114764718Seric rcode = EX_UNAVAILABLE; 114864718Seric goto give_up; 114954967Seric #endif /* DAEMON */ 11506038Seric } 115154967Seric else 1152294Seric { 115368627Seric /* flush any expired connections */ 115468627Seric (void) mci_scan(NULL); 115568627Seric 115668627Seric /* announce the connection to verbose listeners */ 115768627Seric if (host == NULL || host[0] == '\0') 115868627Seric message("Connecting to %s...", m->m_name); 115968627Seric else 116068627Seric message("Connecting to %s via %s...", host, m->m_name); 116163753Seric if (TrafficLogFile != NULL) 116258852Seric { 116363753Seric char **av; 116458925Seric 116563753Seric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 116663753Seric for (av = pv; *av != NULL; av++) 116763753Seric fprintf(TrafficLogFile, " %s", *av); 116863753Seric fprintf(TrafficLogFile, "\n"); 116958852Seric } 117058852Seric 117154967Seric /* create a pipe to shove the mail through */ 117254967Seric if (pipe(mpvect) < 0) 117354967Seric { 117458925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 117558925Seric e->e_to, m->m_name); 117657387Seric if (tTd(11, 1)) 117757387Seric printf("openmailer: NULL\n"); 117858820Seric rcode = EX_OSERR; 117958820Seric goto give_up; 118054967Seric } 11814863Seric 118254967Seric /* if this mailer speaks smtp, create a return pipe */ 118354967Seric if (clever && pipe(rpvect) < 0) 118454967Seric { 118558925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 118658925Seric e->e_to, m->m_name); 118754967Seric (void) close(mpvect[0]); 118854967Seric (void) close(mpvect[1]); 118957387Seric if (tTd(11, 1)) 119057387Seric printf("openmailer: NULL\n"); 119158820Seric rcode = EX_OSERR; 119258820Seric goto give_up; 119354967Seric } 11944863Seric 119554967Seric /* 119654967Seric ** Actually fork the mailer process. 119754967Seric ** DOFORK is clever about retrying. 119854967Seric ** 119954967Seric ** Dispose of SIGCHLD signal catchers that may be laying 120054967Seric ** around so that endmail will get it. 120154967Seric */ 12026038Seric 120354967Seric if (e->e_xfp != NULL) 120454967Seric (void) fflush(e->e_xfp); /* for debugging */ 120554967Seric (void) fflush(stdout); 120626434Seric # ifdef SIGCHLD 120764035Seric (void) setsignal(SIGCHLD, SIG_DFL); 120856795Seric # endif /* SIGCHLD */ 120954967Seric DOFORK(FORK); 121054967Seric /* pid is set by DOFORK */ 121154967Seric if (pid < 0) 12124863Seric { 121354967Seric /* failure */ 121458925Seric syserr("%s... openmailer(%s): cannot fork", 121558925Seric e->e_to, m->m_name); 121654967Seric (void) close(mpvect[0]); 121754967Seric (void) close(mpvect[1]); 121854967Seric if (clever) 121954967Seric { 122054967Seric (void) close(rpvect[0]); 122154967Seric (void) close(rpvect[1]); 122254967Seric } 122357387Seric if (tTd(11, 1)) 122457387Seric printf("openmailer: NULL\n"); 122558820Seric rcode = EX_OSERR; 122658820Seric goto give_up; 12274863Seric } 122854967Seric else if (pid == 0) 122954967Seric { 123054967Seric int i; 123156678Seric int saveerrno; 123258675Seric char **ep; 123358675Seric char *env[MAXUSERENVIRON]; 123458675Seric extern char **environ; 123554967Seric extern int DtableSize; 123615772Seric 123768475Seric if (e->e_lockfp != NULL) 123868589Seric (void) close(fileno(e->e_lockfp)); 123968475Seric 124054967Seric /* child -- set up input & exec mailer */ 124164035Seric (void) setsignal(SIGINT, SIG_IGN); 124264035Seric (void) setsignal(SIGHUP, SIG_IGN); 124364035Seric (void) setsignal(SIGTERM, SIG_DFL); 12444709Seric 124564145Seric /* reset user and group */ 124668627Seric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 124764145Seric { 124868627Seric (void) setgid(m->m_gid); 124968627Seric (void) setuid(m->m_uid); 125068627Seric } 125168627Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 125268627Seric { 125368627Seric (void) initgroups(ctladdr->q_ruser? 125468627Seric ctladdr->q_ruser: ctladdr->q_user, 125568627Seric ctladdr->q_gid); 125668627Seric (void) setgid(ctladdr->q_gid); 125768627Seric (void) setuid(ctladdr->q_uid); 125868627Seric } 125968627Seric else 126068627Seric { 126168627Seric (void) initgroups(DefUser, DefGid); 126268627Seric if (m->m_gid == 0) 126364837Seric (void) setgid(DefGid); 126468627Seric else 126568627Seric (void) setgid(m->m_gid); 126668627Seric if (m->m_uid == 0) 126764145Seric (void) setuid(DefUid); 126864145Seric else 126968627Seric (void) setuid(m->m_uid); 127064145Seric } 127164145Seric 127264145Seric if (tTd(11, 2)) 127364145Seric printf("openmailer: running as r/euid=%d/%d\n", 127464145Seric getuid(), geteuid()); 127564145Seric 127658935Seric /* move into some "safe" directory */ 127758935Seric if (m->m_execdir != NULL) 127858935Seric { 127958935Seric char *p, *q; 128068627Seric char buf[MAXLINE + 1]; 128158935Seric 128258935Seric for (p = m->m_execdir; p != NULL; p = q) 128358935Seric { 128458935Seric q = strchr(p, ':'); 128558935Seric if (q != NULL) 128658935Seric *q = '\0'; 128768627Seric expand(p, buf, sizeof buf, e); 128858935Seric if (q != NULL) 128958935Seric *q++ = ':'; 129058935Seric if (tTd(11, 20)) 129158935Seric printf("openmailer: trydir %s\n", 129258935Seric buf); 129358935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 129458935Seric break; 129558935Seric } 129658935Seric } 129758935Seric 129854967Seric /* arrange to filter std & diag output of command */ 129954967Seric if (clever) 130054967Seric { 130154967Seric (void) close(rpvect[0]); 130258852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 130358852Seric { 130458925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 130558925Seric e->e_to, m->m_name, rpvect[1]); 130658852Seric _exit(EX_OSERR); 130758852Seric } 130854967Seric (void) close(rpvect[1]); 130954967Seric } 131066089Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 131166089Seric HoldErrs || DisConnected) 131254967Seric { 131354967Seric /* put mailer output in transcript */ 131458852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 131558852Seric { 131658925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 131758925Seric e->e_to, m->m_name, 131858852Seric fileno(e->e_xfp)); 131958852Seric _exit(EX_OSERR); 132058852Seric } 132154967Seric } 132258852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 132358852Seric { 132458925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 132558925Seric e->e_to, m->m_name); 132658852Seric _exit(EX_OSERR); 132758852Seric } 13284709Seric 132954967Seric /* arrange to get standard input */ 133054967Seric (void) close(mpvect[1]); 133158731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13324417Seric { 133358925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 133458925Seric e->e_to, m->m_name, mpvect[0]); 133554967Seric _exit(EX_OSERR); 13364417Seric } 133754967Seric (void) close(mpvect[0]); 13389370Seric 133954967Seric /* arrange for all the files to be closed */ 134054967Seric for (i = 3; i < DtableSize; i++) 134154967Seric { 134254967Seric register int j; 134364145Seric 134454967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 134564145Seric (void) fcntl(i, F_SETFD, j | 1); 134654967Seric } 13472774Seric 134866017Seric /* 134966017Seric ** Set up the mailer environment 135068627Seric ** _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag. 135166017Seric ** TZ is timezone information. 135266017Seric ** SYSTYPE is Apollo software sys type (required). 135366017Seric ** ISP is Apollo hardware system type (required). 135466017Seric */ 135566017Seric 135658675Seric i = 0; 135758675Seric env[i++] = "AGENT=sendmail"; 135868627Seric env[i++] = "_FORCE_MAIL_LOCAL_=yes"; 135958675Seric for (ep = environ; *ep != NULL; ep++) 136058675Seric { 136166017Seric if (strncmp(*ep, "TZ=", 3) == 0 || 136266017Seric strncmp(*ep, "ISP=", 4) == 0 || 136366017Seric strncmp(*ep, "SYSTYPE=", 8) == 0) 136458675Seric env[i++] = *ep; 136558675Seric } 136668627Seric env[i] = NULL; 136758675Seric 136866746Seric /* run disconnected from terminal */ 136966746Seric (void) setsid(); 137066746Seric 137154967Seric /* try to execute the mailer */ 137258820Seric execve(m->m_mailer, pv, env); 137356678Seric saveerrno = errno; 137454967Seric syserr("Cannot exec %s", m->m_mailer); 137568627Seric if (bitnset(M_LOCALMAILER, m->m_flags) || 137668627Seric transienterror(saveerrno)) 137760008Seric _exit(EX_OSERR); 137854967Seric _exit(EX_UNAVAILABLE); 137951835Seric } 138054967Seric 138154967Seric /* 138254967Seric ** Set up return value. 138354967Seric */ 138454967Seric 138554967Seric mci = (MCI *) xalloc(sizeof *mci); 138654993Seric bzero((char *) mci, sizeof *mci); 138754967Seric mci->mci_mailer = m; 138854967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 138954993Seric mci->mci_pid = pid; 139054967Seric (void) close(mpvect[0]); 139154967Seric mci->mci_out = fdopen(mpvect[1], "w"); 139264724Seric if (mci->mci_out == NULL) 139364724Seric { 139464724Seric syserr("deliver: cannot create mailer output channel, fd=%d", 139564724Seric mpvect[1]); 139664724Seric (void) close(mpvect[1]); 139764724Seric if (clever) 139864724Seric { 139964724Seric (void) close(rpvect[0]); 140064724Seric (void) close(rpvect[1]); 140164724Seric } 140264724Seric rcode = EX_OSERR; 140364724Seric goto give_up; 140464724Seric } 140554967Seric if (clever) 140654967Seric { 140754967Seric (void) close(rpvect[1]); 140854967Seric mci->mci_in = fdopen(rpvect[0], "r"); 140964724Seric if (mci->mci_in == NULL) 141064724Seric { 141164724Seric syserr("deliver: cannot create mailer input channel, fd=%d", 141264724Seric mpvect[1]); 141364724Seric (void) close(rpvect[0]); 141464724Seric fclose(mci->mci_out); 141564724Seric mci->mci_out = NULL; 141664724Seric rcode = EX_OSERR; 141764724Seric goto give_up; 141864724Seric } 141954967Seric } 142054967Seric else 142154967Seric { 142254967Seric mci->mci_flags |= MCIF_TEMP; 142354967Seric mci->mci_in = NULL; 142454967Seric } 1425294Seric } 1426294Seric 14274709Seric /* 142854967Seric ** If we are in SMTP opening state, send initial protocol. 14294709Seric */ 14304709Seric 143154967Seric if (clever && mci->mci_state != MCIS_CLOSED) 14324863Seric { 143354967Seric smtpinit(m, mci, e); 143453738Seric } 143568627Seric 143668627Seric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 143768627Seric mci->mci_flags |= MCIF_CVT8TO7; 143868627Seric else 143968627Seric mci->mci_flags &= ~MCIF_CVT8TO7; 144068627Seric 144157387Seric if (tTd(11, 1)) 144257387Seric { 144357387Seric printf("openmailer: "); 144464731Seric mci_dump(mci, FALSE); 144557387Seric } 1446294Seric 144758820Seric if (mci->mci_state != MCIS_OPEN) 144858820Seric { 144958820Seric /* couldn't open the mailer */ 145058820Seric rcode = mci->mci_exitstat; 145158820Seric errno = mci->mci_errno; 145266334Seric #if NAMED_BIND 145363753Seric h_errno = mci->mci_herrno; 145463753Seric #endif 145558820Seric if (rcode == EX_OK) 145658820Seric { 145758820Seric /* shouldn't happen */ 145858820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 145958820Seric rcode, mci->mci_state, firstsig); 146058820Seric rcode = EX_SOFTWARE; 146158820Seric } 146268627Seric else if (curhost != NULL && *curhost != '\0') 146359958Seric { 146459958Seric /* try next MX site */ 146559958Seric goto tryhost; 146659958Seric } 146758820Seric } 146858820Seric else if (!clever) 146958820Seric { 147058820Seric /* 147158820Seric ** Format and send message. 147258820Seric */ 147358820Seric 147465870Seric putfromline(mci, e); 147568627Seric (*e->e_puthdr)(mci, e->e_header, e); 147668228Seric (*e->e_putbody)(mci, e, NULL); 147758820Seric 147858820Seric /* get the exit status */ 147958820Seric rcode = endmailer(mci, e, pv); 148058820Seric } 148158820Seric else 148258820Seric #ifdef SMTP 148358820Seric { 148458820Seric /* 148558820Seric ** Send the MAIL FROM: protocol 148658820Seric */ 148758820Seric 148858820Seric rcode = smtpmailfrom(m, mci, e); 148958820Seric if (rcode == EX_OK) 149058820Seric { 149158820Seric register char *t = tobuf; 149258820Seric register int i; 149358820Seric 149458820Seric /* send the recipient list */ 149558820Seric tobuf[0] = '\0'; 149658820Seric for (to = tochain; to != NULL; to = to->q_tchain) 149758820Seric { 149858820Seric e->e_to = to->q_paddr; 149958820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 150058820Seric { 150168627Seric markfailure(e, to, mci, i); 150268627Seric giveresponse(i, m, mci, ctladdr, xstart, e); 150358820Seric } 150458820Seric else 150558820Seric { 150658820Seric *t++ = ','; 150758820Seric for (p = to->q_paddr; *p; *t++ = *p++) 150858820Seric continue; 150964372Seric *t = '\0'; 151058820Seric } 151158820Seric } 151258820Seric 151358820Seric /* now send the data */ 151458820Seric if (tobuf[0] == '\0') 151558820Seric { 151658820Seric rcode = EX_OK; 151758820Seric e->e_to = NULL; 151858820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 151958820Seric smtprset(m, mci, e); 152058820Seric } 152158820Seric else 152258820Seric { 152358820Seric e->e_to = tobuf + 1; 152458820Seric rcode = smtpdata(m, mci, e); 152558820Seric } 152658820Seric 152758820Seric /* now close the connection */ 152858820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 152958820Seric smtpquit(m, mci, e); 153058820Seric } 153164922Seric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 153258820Seric { 153358820Seric /* try next MX site */ 153458820Seric goto tryhost; 153558820Seric } 153658820Seric } 153758820Seric #else /* not SMTP */ 153858820Seric { 153958820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 154058820Seric rcode = EX_CONFIG; 154158820Seric goto give_up; 154258820Seric } 154358820Seric #endif /* SMTP */ 154466334Seric #if NAMED_BIND 154558820Seric if (ConfigLevel < 2) 154658820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 154758820Seric #endif 154858820Seric 154958820Seric /* arrange a return receipt if requested */ 155064718Seric if (rcode == EX_OK && e->e_receiptto != NULL && 155164718Seric bitnset(M_LOCALMAILER, m->m_flags)) 155258820Seric { 155358820Seric e->e_flags |= EF_SENDRECEIPT; 155458820Seric /* do we want to send back more info? */ 155558820Seric } 155658820Seric 155758820Seric /* 155858820Seric ** Do final status disposal. 155958820Seric ** We check for something in tobuf for the SMTP case. 156058820Seric ** If we got a temporary failure, arrange to queue the 156158820Seric ** addressees. 156258820Seric */ 156358820Seric 156458820Seric give_up: 156558820Seric if (tobuf[0] != '\0') 156668627Seric giveresponse(rcode, m, mci, ctladdr, xstart, e); 156758820Seric for (to = tochain; to != NULL; to = to->q_tchain) 156858820Seric { 156958820Seric if (rcode != EX_OK) 157068627Seric markfailure(e, to, mci, rcode); 157168627Seric else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) 157258820Seric { 157358820Seric to->q_flags |= QSENT; 157468627Seric to->q_statdate = curtime(); 157558820Seric e->e_nsent++; 157668627Seric if (bitnset(M_LOCALMAILER, m->m_flags) && 157768627Seric (e->e_receiptto != NULL || 157868627Seric bitset(QPINGONSUCCESS, to->q_flags))) 157964718Seric { 158068627Seric to->q_flags |= QREPORT; 158164718Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 158264718Seric to->q_paddr); 158364718Seric } 158468627Seric else if (bitset(QPINGONSUCCESS, to->q_flags) && 158568627Seric bitset(QPRIMARY, to->q_flags) && 158668627Seric !bitset(MCIF_DSN, mci->mci_flags)) 158768627Seric { 158868627Seric to->q_flags |= QRELAYED; 158968627Seric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 159068627Seric to->q_paddr); 159168627Seric } 159258820Seric } 159358820Seric } 159458820Seric 159558820Seric /* 159658820Seric ** Restore state and return. 159758820Seric */ 159858820Seric 159964401Seric #ifdef XDEBUG 160064401Seric { 160164401Seric char wbuf[MAXLINE]; 160264401Seric 160364401Seric /* make absolutely certain 0, 1, and 2 are in use */ 160464554Seric sprintf(wbuf, "%s... end of deliver(%s)", 160564554Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 160664554Seric m->m_name); 160764401Seric checkfd012(wbuf); 160864401Seric } 160964401Seric #endif 161064401Seric 161158820Seric errno = 0; 161258820Seric define('g', (char *) NULL, e); 161358820Seric return (rcode); 1614294Seric } 1615294Seric /* 161658820Seric ** MARKFAILURE -- mark a failure on a specific address. 161758820Seric ** 161858820Seric ** Parameters: 161958820Seric ** e -- the envelope we are sending. 162058820Seric ** q -- the address to mark. 162168627Seric ** mci -- mailer connection information. 162258820Seric ** rcode -- the code signifying the particular failure. 162358820Seric ** 162458820Seric ** Returns: 162558820Seric ** none. 162658820Seric ** 162758820Seric ** Side Effects: 162858820Seric ** marks the address (and possibly the envelope) with the 162958820Seric ** failure so that an error will be returned or 163058820Seric ** the message will be queued, as appropriate. 163158820Seric */ 163258820Seric 163368627Seric markfailure(e, q, mci, rcode) 163458820Seric register ENVELOPE *e; 163558820Seric register ADDRESS *q; 163668627Seric register MCI *mci; 163758820Seric int rcode; 163858820Seric { 163968627Seric char *stat = NULL; 164058820Seric 164165051Seric switch (rcode) 164265051Seric { 164365051Seric case EX_OK: 164465051Seric break; 164565051Seric 164665051Seric case EX_TEMPFAIL: 164765051Seric case EX_IOERR: 164865051Seric case EX_OSERR: 164963753Seric q->q_flags |= QQUEUEUP; 165065051Seric break; 165165051Seric 165265051Seric default: 165358820Seric q->q_flags |= QBADADDR; 165465051Seric break; 165565051Seric } 165668627Seric 165768627Seric if (q->q_status == NULL && mci != NULL) 165868627Seric q->q_status = mci->mci_status; 165968627Seric switch (rcode) 166068627Seric { 166168627Seric case EX_USAGE: 166268627Seric stat = "5.5.4"; 166368627Seric break; 166468627Seric 166568627Seric case EX_DATAERR: 166668627Seric stat = "5.5.2"; 166768627Seric break; 166868627Seric 166968627Seric case EX_NOUSER: 167068627Seric case EX_NOHOST: 167168627Seric stat = "5.1.1"; 167268627Seric break; 167368627Seric 167468627Seric case EX_NOINPUT: 167568627Seric case EX_CANTCREAT: 167668627Seric case EX_NOPERM: 167768627Seric stat = "5.3.0"; 167868627Seric break; 167968627Seric 168068627Seric case EX_UNAVAILABLE: 168168627Seric case EX_SOFTWARE: 168268627Seric case EX_OSFILE: 168368627Seric case EX_PROTOCOL: 168468627Seric case EX_CONFIG: 168568627Seric stat = "5.5.0"; 168668627Seric break; 168768627Seric 168868627Seric case EX_OSERR: 168968627Seric case EX_IOERR: 169068627Seric stat = "4.5.0"; 169168627Seric break; 169268627Seric 169368627Seric case EX_TEMPFAIL: 169468627Seric stat = "4.2.0"; 169568627Seric break; 169668627Seric } 169768627Seric if (stat != NULL && q->q_status == NULL) 169868627Seric q->q_status = stat; 169968627Seric 170068627Seric q->q_statdate = curtime(); 170168627Seric if (CurHostName != NULL && CurHostName[0] != '\0') 170268627Seric q->q_statmta = newstr(CurHostName); 170368627Seric if (rcode != EX_OK && q->q_rstatus == NULL) 170468627Seric { 170568627Seric char buf[30]; 170668627Seric 170768627Seric (void) sprintf(buf, "%d", rcode); 170868627Seric q->q_rstatus = newstr(buf); 170968627Seric } 171058820Seric } 171158820Seric /* 171258820Seric ** ENDMAILER -- Wait for mailer to terminate. 171358820Seric ** 171458820Seric ** We should never get fatal errors (e.g., segmentation 171558820Seric ** violation), so we report those specially. For other 171658820Seric ** errors, we choose a status message (into statmsg), 171758820Seric ** and if it represents an error, we print it. 171858820Seric ** 171958820Seric ** Parameters: 172058820Seric ** pid -- pid of mailer. 172158820Seric ** e -- the current envelope. 172258820Seric ** pv -- the parameter vector that invoked the mailer 172358820Seric ** (for error messages). 172458820Seric ** 172558820Seric ** Returns: 172658820Seric ** exit code of mailer. 172758820Seric ** 172858820Seric ** Side Effects: 172958820Seric ** none. 173058820Seric */ 173158820Seric 173258820Seric endmailer(mci, e, pv) 173358820Seric register MCI *mci; 173458820Seric register ENVELOPE *e; 173558820Seric char **pv; 173658820Seric { 173758820Seric int st; 173858820Seric 173958820Seric /* close any connections */ 174058820Seric if (mci->mci_in != NULL) 174165198Seric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 174258820Seric if (mci->mci_out != NULL) 174365198Seric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 174458820Seric mci->mci_in = mci->mci_out = NULL; 174558820Seric mci->mci_state = MCIS_CLOSED; 174658820Seric 174758820Seric /* in the IPC case there is nothing to wait for */ 174858820Seric if (mci->mci_pid == 0) 174958820Seric return (EX_OK); 175058820Seric 175158820Seric /* wait for the mailer process to die and collect status */ 175258820Seric st = waitfor(mci->mci_pid); 175358820Seric if (st == -1) 175458820Seric { 175558820Seric syserr("endmailer %s: wait", pv[0]); 175658820Seric return (EX_SOFTWARE); 175758820Seric } 175858820Seric 175964379Seric if (WIFEXITED(st)) 176058820Seric { 176164379Seric /* normal death -- return status */ 176264379Seric return (WEXITSTATUS(st)); 176364379Seric } 176458820Seric 176564379Seric /* it died a horrid death */ 176665545Seric syserr("451 mailer %s died with signal %o", 176765545Seric mci->mci_mailer->m_name, st); 176858820Seric 176964379Seric /* log the arguments */ 177065194Seric if (pv != NULL && e->e_xfp != NULL) 177164379Seric { 177264379Seric register char **av; 177358820Seric 177464379Seric fprintf(e->e_xfp, "Arguments:"); 177564379Seric for (av = pv; *av != NULL; av++) 177664379Seric fprintf(e->e_xfp, " %s", *av); 177764379Seric fprintf(e->e_xfp, "\n"); 177858820Seric } 177958820Seric 178064379Seric ExitStat = EX_TEMPFAIL; 178164379Seric return (EX_TEMPFAIL); 178258820Seric } 178358820Seric /* 1784294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1785294Seric ** 1786294Seric ** Parameters: 1787294Seric ** stat -- the status code from the mailer (high byte 1788294Seric ** only; core dumps must have been taken care of 1789294Seric ** already). 179058337Seric ** m -- the mailer info for this mailer. 179158337Seric ** mci -- the mailer connection info -- can be NULL if the 179258337Seric ** response is given before the connection is made. 179364771Seric ** ctladdr -- the controlling address for the recipient 179464771Seric ** address(es). 179568627Seric ** xstart -- the transaction start time, for computing 179668627Seric ** transaction delays. 179758337Seric ** e -- the current envelope. 1798294Seric ** 1799294Seric ** Returns: 18004082Seric ** none. 1801294Seric ** 1802294Seric ** Side Effects: 18031518Seric ** Errors may be incremented. 1804294Seric ** ExitStat may be set. 1805294Seric */ 1806294Seric 180768627Seric giveresponse(stat, m, mci, ctladdr, xstart, e) 1808294Seric int stat; 18099370Seric register MAILER *m; 181058337Seric register MCI *mci; 181164771Seric ADDRESS *ctladdr; 181268627Seric time_t xstart; 181310105Seric ENVELOPE *e; 1814294Seric { 181560094Seric register const char *statmsg; 1816294Seric extern char *SysExMsg[]; 1817294Seric register int i; 181836788Sbostic extern int N_SysEx; 181910105Seric char buf[MAXLINE]; 1820294Seric 18214315Seric /* 18224315Seric ** Compute status message from code. 18234315Seric */ 18244315Seric 1825294Seric i = stat - EX__BASE; 18269370Seric if (stat == 0) 182758852Seric { 18289370Seric statmsg = "250 Sent"; 182958916Seric if (e->e_statmsg != NULL) 183058852Seric { 183158916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 183258852Seric statmsg = buf; 183358852Seric } 183458852Seric } 18359370Seric else if (i < 0 || i > N_SysEx) 18369370Seric { 18379370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 18389370Seric stat = EX_UNAVAILABLE; 18399370Seric statmsg = buf; 18409370Seric } 184110105Seric else if (stat == EX_TEMPFAIL) 184210105Seric { 184358664Seric (void) strcpy(buf, SysExMsg[i] + 1); 184466334Seric #if NAMED_BIND 184525527Smiriam if (h_errno == TRY_AGAIN) 184663993Seric statmsg = errstring(h_errno+E_DNSBASE); 184721061Seric else 184836788Sbostic #endif 184921061Seric { 185025527Smiriam if (errno != 0) 185125527Smiriam statmsg = errstring(errno); 185225527Smiriam else 185325527Smiriam { 185421061Seric #ifdef SMTP 185525527Smiriam statmsg = SmtpError; 185656795Seric #else /* SMTP */ 185725527Smiriam statmsg = NULL; 185856795Seric #endif /* SMTP */ 185925527Smiriam } 186021061Seric } 186121061Seric if (statmsg != NULL && statmsg[0] != '\0') 186221061Seric { 186310124Seric (void) strcat(buf, ": "); 186421061Seric (void) strcat(buf, statmsg); 186510105Seric } 186610105Seric statmsg = buf; 186710105Seric } 186866334Seric #if NAMED_BIND 186963753Seric else if (stat == EX_NOHOST && h_errno != 0) 187063753Seric { 187163993Seric statmsg = errstring(h_errno + E_DNSBASE); 187267077Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 187363753Seric statmsg = buf; 187463753Seric } 187563753Seric #endif 1876294Seric else 187721061Seric { 1878294Seric statmsg = SysExMsg[i]; 187958664Seric if (*statmsg++ == ':') 188058664Seric { 188158664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 188258664Seric statmsg = buf; 188358664Seric } 188421061Seric } 18859370Seric 18869370Seric /* 18879370Seric ** Print the message as appropriate 18889370Seric */ 18899370Seric 189010105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 189164718Seric { 189264718Seric extern char MsgBuf[]; 189364718Seric 189466307Seric message("%s", &statmsg[4]); 189564718Seric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 189664718Seric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 189764718Seric } 1898294Seric else 1899294Seric { 190067077Seric char mbuf[8]; 190167077Seric 19021518Seric Errors++; 190367077Seric sprintf(mbuf, "%.3s %%s", statmsg); 190467077Seric usrerr(mbuf, &statmsg[4]); 1905294Seric } 1906294Seric 1907294Seric /* 1908294Seric ** Final cleanup. 1909294Seric ** Log a record of the transaction. Compute the new 1910294Seric ** ExitStat -- if we already had an error, stick with 1911294Seric ** that. 1912294Seric */ 1913294Seric 191458020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 191568627Seric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 19167858Seric 191766323Seric if (tTd(11, 2)) 191866323Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 191967962Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 192066323Seric 19214621Seric if (stat != EX_TEMPFAIL) 19224621Seric setstat(stat); 192364952Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 192410105Seric { 192510105Seric if (e->e_message != NULL) 192610105Seric free(e->e_message); 192710105Seric e->e_message = newstr(&statmsg[4]); 192810105Seric } 192910124Seric errno = 0; 193066334Seric #if NAMED_BIND 193125527Smiriam h_errno = 0; 193236788Sbostic #endif 1933294Seric } 1934294Seric /* 19358496Seric ** LOGDELIVERY -- log the delivery in the system log 19368496Seric ** 193764969Seric ** Care is taken to avoid logging lines that are too long, because 193864969Seric ** some versions of syslog have an unfortunate proclivity for core 193964969Seric ** dumping. This is a hack, to be sure, that is at best empirical. 194064969Seric ** 19418496Seric ** Parameters: 194258337Seric ** m -- the mailer info. Can be NULL for initial queue. 194358337Seric ** mci -- the mailer connection info -- can be NULL if the 194458337Seric ** log is occuring when no connection is active. 194558337Seric ** stat -- the message to print for the status. 194664771Seric ** ctladdr -- the controlling address for the to list. 194768627Seric ** xstart -- the transaction start time, used for 194868627Seric ** computing transaction delay. 194958337Seric ** e -- the current envelope. 19508496Seric ** 19518496Seric ** Returns: 19528496Seric ** none 19538496Seric ** 19548496Seric ** Side Effects: 19558496Seric ** none 19568496Seric */ 19578496Seric 195868627Seric logdelivery(m, mci, stat, ctladdr, xstart, e) 195958337Seric MAILER *m; 196058337Seric register MCI *mci; 19618496Seric char *stat; 196264771Seric ADDRESS *ctladdr; 196368627Seric time_t xstart; 196454967Seric register ENVELOPE *e; 19658496Seric { 196658343Seric # ifdef LOG 196764771Seric register char *bp; 196864969Seric register char *p; 196964969Seric int l; 197058418Seric char buf[512]; 19718496Seric 197265059Seric # if (SYSLOG_BUFSIZE) >= 256 197364771Seric bp = buf; 197464771Seric if (ctladdr != NULL) 197564771Seric { 197664771Seric strcpy(bp, ", ctladdr="); 197765016Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 197864771Seric bp += strlen(bp); 197964771Seric if (bitset(QGOODUID, ctladdr->q_flags)) 198064771Seric { 198164771Seric (void) sprintf(bp, " (%d/%d)", 198264771Seric ctladdr->q_uid, ctladdr->q_gid); 198364771Seric bp += strlen(bp); 198464771Seric } 198564771Seric } 198658337Seric 198768627Seric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 198864771Seric bp += strlen(bp); 198964771Seric 199068627Seric if (xstart != (time_t) 0) 199168627Seric { 199268627Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 199368627Seric bp += strlen(bp); 199468627Seric } 199568627Seric 199658513Seric if (m != NULL) 199758305Seric { 199864771Seric (void) strcpy(bp, ", mailer="); 199964771Seric (void) strcat(bp, m->m_name); 200064771Seric bp += strlen(bp); 200158305Seric } 200258513Seric 200358513Seric if (mci != NULL && mci->mci_host != NULL) 200458305Seric { 200558305Seric # ifdef DAEMON 200658755Seric extern SOCKADDR CurHostAddr; 200758513Seric # endif 200858305Seric 200964771Seric (void) strcpy(bp, ", relay="); 201064771Seric (void) strcat(bp, mci->mci_host); 201158513Seric 201258513Seric # ifdef DAEMON 201365919Seric (void) strcat(bp, " ["); 201464771Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 201565919Seric (void) strcat(bp, "]"); 201658305Seric # endif 201758305Seric } 201866894Seric else if (strcmp(stat, "queued") != 0) 201958513Seric { 202058513Seric char *p = macvalue('h', e); 202158343Seric 202258513Seric if (p != NULL && p[0] != '\0') 202358513Seric { 202464771Seric (void) strcpy(bp, ", relay="); 202564771Seric (void) strcat(bp, p); 202658513Seric } 202758513Seric } 202864922Seric bp += strlen(bp); 202964969Seric 203065059Seric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 203165059Seric #if (STATLEN) < 63 203265059Seric # undef STATLEN 203365059Seric # define STATLEN 63 203465059Seric #endif 203565059Seric #if (STATLEN) > 203 203665059Seric # undef STATLEN 203765059Seric # define STATLEN 203 203865059Seric #endif 203965059Seric 204065059Seric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 204164969Seric { 204264969Seric /* desperation move -- truncate data */ 204365059Seric bp = buf + sizeof buf - ((STATLEN) + 17); 204464969Seric strcpy(bp, "..."); 204564969Seric bp += 3; 204664969Seric } 204764969Seric 204864969Seric (void) strcpy(bp, ", stat="); 204964969Seric bp += strlen(bp); 205065059Seric 205165059Seric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 205258418Seric 205364969Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 205464969Seric p = e->e_to; 205564969Seric while (strlen(p) >= l) 205664969Seric { 205764969Seric register char *q = strchr(p + l, ','); 205864969Seric 205965008Seric if (q == NULL) 206064969Seric break; 206164969Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 206264969Seric e->e_id, ++q - p, p, buf); 206364969Seric p = q; 206464969Seric } 206564969Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 206665059Seric 206765059Seric # else /* we have a very short log buffer size */ 206865059Seric 206966258Seric l = SYSLOG_BUFSIZE - 85; 207065059Seric p = e->e_to; 207165059Seric while (strlen(p) >= l) 207265059Seric { 207365059Seric register char *q = strchr(p + l, ','); 207465059Seric 207565059Seric if (q == NULL) 207665059Seric break; 207765059Seric syslog(LOG_INFO, "%s: to=%.*s [more]", 207865059Seric e->e_id, ++q - p, p); 207965059Seric p = q; 208065059Seric } 208165059Seric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 208265059Seric 208365059Seric if (ctladdr != NULL) 208465059Seric { 208565059Seric bp = buf; 208665059Seric strcpy(buf, "ctladdr="); 208765059Seric bp += strlen(buf); 208865059Seric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 208965059Seric bp += strlen(buf); 209065059Seric if (bitset(QGOODUID, ctladdr->q_flags)) 209165059Seric { 209265059Seric (void) sprintf(bp, " (%d/%d)", 209365059Seric ctladdr->q_uid, ctladdr->q_gid); 209465059Seric bp += strlen(bp); 209565059Seric } 209665059Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 209765059Seric } 209865650Seric bp = buf; 209965650Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 210065650Seric bp += strlen(bp); 210168627Seric if (xstart != (time_t) 0) 210268627Seric { 210368627Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 210468627Seric bp += strlen(bp); 210568627Seric } 210665059Seric 210765059Seric if (m != NULL) 210865650Seric { 210965650Seric sprintf(bp, ", mailer=%s", m->m_name); 211065650Seric bp += strlen(bp); 211165650Seric } 211266009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 211365059Seric 211466009Seric buf[0] = '\0'; 211565059Seric if (mci != NULL && mci->mci_host != NULL) 211665059Seric { 211765059Seric # ifdef DAEMON 211865059Seric extern SOCKADDR CurHostAddr; 211965059Seric # endif 212065059Seric 212166021Seric sprintf(buf, "relay=%s", mci->mci_host); 212265059Seric 212365059Seric # ifdef DAEMON 212466009Seric (void) strcat(buf, " ["); 212566009Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 212666009Seric (void) strcat(buf, "]"); 212765059Seric # endif 212865059Seric } 212966894Seric else if (strcmp(stat, "queued") != 0) 213065059Seric { 213165059Seric char *p = macvalue('h', e); 213265059Seric 213365059Seric if (p != NULL && p[0] != '\0') 213466021Seric sprintf(buf, "relay=%s", p); 213565059Seric } 213666009Seric if (buf[0] != '\0') 213766009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 213865059Seric 213965059Seric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 214065059Seric # endif /* short log buffer */ 214156795Seric # endif /* LOG */ 21428496Seric } 21438496Seric /* 21446974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 2145294Seric ** 21466974Seric ** This can be made an arbitrary message separator by changing $l 2147294Seric ** 214816150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 214916150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 215016150Seric ** does a well-meaning programmer such as myself have to deal with 215116150Seric ** this kind of antique garbage???? 21526974Seric ** 2153294Seric ** Parameters: 215465870Seric ** mci -- the connection information. 215565870Seric ** e -- the envelope. 2156294Seric ** 2157294Seric ** Returns: 21586974Seric ** none 2159294Seric ** 2160294Seric ** Side Effects: 21616974Seric ** outputs some text to fp. 2162294Seric */ 2163294Seric 216465870Seric putfromline(mci, e) 216565870Seric register MCI *mci; 216654967Seric ENVELOPE *e; 2167294Seric { 216858050Seric char *template = "\201l\n"; 21696974Seric char buf[MAXLINE]; 2170294Seric 217165870Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 21726974Seric return; 21734315Seric 21746974Seric # ifdef UGLYUUCP 217565870Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 21764205Seric { 217712223Seric char *bang; 217812223Seric char xbuf[MAXLINE]; 21796041Seric 218068627Seric expand("\201g", buf, sizeof buf, e); 218156795Seric bang = strchr(buf, '!'); 21826974Seric if (bang == NULL) 218364370Seric { 218464370Seric errno = 0; 218564370Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 218664370Seric } 21875099Seric else 21889370Seric { 218912223Seric *bang++ = '\0'; 219058050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 219112223Seric template = xbuf; 21929370Seric } 21936974Seric } 219456795Seric # endif /* UGLYUUCP */ 219568627Seric expand(template, buf, sizeof buf, e); 219668627Seric putxline(buf, mci, FALSE); 21975981Seric } 21985981Seric /* 21996974Seric ** PUTBODY -- put the body of a message. 22006974Seric ** 22016974Seric ** Parameters: 220265870Seric ** mci -- the connection information. 22039538Seric ** e -- the envelope to put out. 220459730Seric ** separator -- if non-NULL, a message separator that must 220559730Seric ** not be permitted in the resulting message. 22066974Seric ** 22076974Seric ** Returns: 22086974Seric ** none. 22096974Seric ** 22106974Seric ** Side Effects: 22116974Seric ** The message is written onto fp. 22126974Seric */ 22136974Seric 221468627Seric /* values for output state variable */ 221568627Seric #define OS_HEAD 0 /* at beginning of line */ 221668627Seric #define OS_CR 1 /* read a carriage return */ 221768627Seric #define OS_INLINE 2 /* putting rest of line */ 221868627Seric 221968228Seric putbody(mci, e, separator) 222065870Seric register MCI *mci; 22219538Seric register ENVELOPE *e; 222259730Seric char *separator; 22236974Seric { 222410168Seric char buf[MAXLINE]; 22256974Seric 22266974Seric /* 22276974Seric ** Output the body of the message 22286974Seric */ 22296974Seric 223068627Seric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 223168627Seric { 223268627Seric char *df = queuename(e, 'd'); 223368627Seric 223468627Seric e->e_dfp = fopen(df, "r"); 223568627Seric if (e->e_dfp == NULL) 223668627Seric syserr("putbody: Cannot open %s for %s from %s", 223768627Seric df, e->e_to, e->e_from.q_paddr); 223868627Seric } 22399538Seric if (e->e_dfp == NULL) 22406974Seric { 224168627Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 22429538Seric { 224368627Seric putline("", mci); 224468627Seric mci->mci_flags &= ~MCIF_INHEADER; 22459538Seric } 224668627Seric putline("<<< No Message Collected >>>", mci); 224768627Seric goto endofmessage; 224868627Seric } 224968627Seric if (e->e_dfino == (ino_t) 0) 225068627Seric { 225168627Seric struct stat stbuf; 225268627Seric 225368627Seric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 225468627Seric e->e_dfino = -1; 225568609Seric else 225668627Seric { 225768627Seric e->e_dfdev = stbuf.st_dev; 225868627Seric e->e_dfino = stbuf.st_ino; 225968627Seric } 226068515Seric } 226168627Seric rewind(e->e_dfp); 226268627Seric 226368627Seric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 226468515Seric { 226568627Seric char *boundaries[MAXMIMENESTING + 1]; 226668627Seric 226768627Seric /* 226868627Seric ** Do 8 to 7 bit MIME conversion. 226968627Seric */ 227068627Seric 227168627Seric /* make sure it looks like a MIME message */ 227268627Seric if (hvalue("MIME-Version", e->e_header) == NULL) 227368627Seric putline("MIME-Version: 1.0", mci); 227468627Seric 227568627Seric if (hvalue("Content-Type", e->e_header) == NULL) 227668515Seric { 227768627Seric sprintf(buf, "Content-Type: text/plain; charset=%s", 227868627Seric defcharset(e)); 227967813Seric putline(buf, mci); 228067813Seric } 228167813Seric 228268627Seric /* now do the hard work */ 228368627Seric boundaries[0] = NULL; 228468627Seric mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 228568627Seric } 228668627Seric else 228768627Seric { 228868627Seric int ostate; 228968627Seric register char *bp; 229068627Seric register char *pbp; 229168627Seric register int c; 229268627Seric int padc; 229368627Seric char *buflim; 229468627Seric int pos = 0; 229568627Seric char peekbuf[10]; 229668627Seric 229768627Seric /* we can pass it through unmodified */ 229868627Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 229916875Seric { 230068627Seric putline("", mci); 230168627Seric mci->mci_flags &= ~MCIF_INHEADER; 230267546Seric } 230368627Seric 230468627Seric /* determine end of buffer; allow for short mailer lines */ 230568627Seric buflim = &buf[sizeof buf - 1]; 230668627Seric if (mci->mci_mailer->m_linelimit > 0 && 230768627Seric mci->mci_mailer->m_linelimit < sizeof buf - 1) 230868627Seric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 230968627Seric 231068627Seric /* copy temp file to output with mapping */ 231168627Seric ostate = OS_HEAD; 231268627Seric bp = buf; 231368627Seric pbp = peekbuf; 231468627Seric while (!ferror(mci->mci_out)) 231568627Seric { 231668627Seric register char *xp; 231768627Seric 231868627Seric if (pbp > peekbuf) 231968627Seric c = *--pbp; 232068627Seric else if ((c = fgetc(e->e_dfp)) == EOF) 232168627Seric break; 232268627Seric if (bitset(MCIF_7BIT, mci->mci_flags)) 232368627Seric c &= 0x7f; 232468627Seric switch (ostate) 232568627Seric { 232668627Seric case OS_HEAD: 232768627Seric if (c != '\r' && c != '\n' && bp < buflim) 232868627Seric { 232968627Seric *bp++ = c; 233068627Seric break; 233168627Seric } 233268627Seric 233368627Seric /* check beginning of line for special cases */ 233468627Seric *bp = '\0'; 233568627Seric pos = 0; 233668627Seric padc = EOF; 233768627Seric if (buf[0] == 'F' && 233868627Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 233968627Seric strncmp(buf, "From ", 5) == 0) 234068627Seric { 234168627Seric padc = '>'; 234268627Seric } 234368627Seric if (buf[0] == '-' && buf[1] == '-' && 234468627Seric separator != NULL) 234568627Seric { 234668627Seric /* possible separator */ 234768627Seric int sl = strlen(separator); 234868627Seric 234968627Seric if (strncmp(&buf[2], separator, sl) == 0) 235068627Seric padc = ' '; 235168627Seric } 235268627Seric if (buf[0] == '.' && 235368627Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 235468627Seric { 235568627Seric padc = '.'; 235668627Seric } 235768627Seric 235868627Seric /* now copy out saved line */ 235968627Seric if (TrafficLogFile != NULL) 236068627Seric { 236168627Seric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 236268627Seric if (padc != EOF) 236368627Seric fputc(padc, TrafficLogFile); 236468627Seric for (xp = buf; xp < bp; xp++) 236568627Seric fputc(*xp, TrafficLogFile); 236668627Seric if (c == '\n') 236768627Seric fputs(mci->mci_mailer->m_eol, 236868627Seric TrafficLogFile); 236968627Seric } 237068627Seric if (padc != EOF) 237168627Seric { 237268627Seric fputc(padc, mci->mci_out); 237368627Seric pos++; 237468627Seric } 237568627Seric for (xp = buf; xp < bp; xp++) 237668627Seric fputc(*xp, mci->mci_out); 237768627Seric if (c == '\n') 237868627Seric { 237968627Seric fputs(mci->mci_mailer->m_eol, 238068627Seric mci->mci_out); 238168627Seric pos = 0; 238268627Seric } 238368627Seric else 238468627Seric { 238568627Seric pos += bp - buf; 238668627Seric if (c != '\r') 238768627Seric *pbp++ = c; 238868627Seric } 238968627Seric bp = buf; 239068627Seric 239168627Seric /* determine next state */ 239268627Seric if (c == '\n') 239368627Seric ostate = OS_HEAD; 239468627Seric else if (c == '\r') 239568627Seric ostate = OS_CR; 239668627Seric else 239768627Seric ostate = OS_INLINE; 239868627Seric continue; 239968627Seric 240068627Seric case OS_CR: 240168627Seric if (c == '\n') 240268627Seric { 240368627Seric /* got CRLF */ 240468627Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 240568627Seric if (TrafficLogFile != NULL) 240668627Seric { 240768627Seric fputs(mci->mci_mailer->m_eol, 240868627Seric TrafficLogFile); 240968627Seric } 241068627Seric ostate = OS_HEAD; 241168627Seric continue; 241268627Seric } 241368627Seric 241468627Seric /* had a naked carriage return */ 241568627Seric *pbp++ = c; 241668627Seric c = '\r'; 241768627Seric goto putch; 241868627Seric 241968627Seric case OS_INLINE: 242068627Seric if (c == '\r') 242168627Seric { 242268627Seric ostate = OS_CR; 242368627Seric continue; 242468627Seric } 242568627Seric putch: 242668627Seric if (mci->mci_mailer->m_linelimit > 0 && 242768627Seric pos > mci->mci_mailer->m_linelimit && 242868627Seric c != '\n') 242968627Seric { 243068627Seric putc('!', mci->mci_out); 243168627Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 243268627Seric if (TrafficLogFile != NULL) 243368627Seric { 243468627Seric fprintf(TrafficLogFile, "!%s", 243568627Seric mci->mci_mailer->m_eol); 243668627Seric } 243768627Seric ostate = OS_HEAD; 243868627Seric *pbp++ = c; 243968627Seric continue; 244068627Seric } 244168627Seric if (TrafficLogFile != NULL) 244268627Seric fputc(c, TrafficLogFile); 244368627Seric putc(c, mci->mci_out); 244468627Seric pos++; 244568627Seric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 244668627Seric break; 244768627Seric } 244868627Seric } 244967599Seric } 24506974Seric 245168627Seric if (ferror(e->e_dfp)) 245268627Seric { 245368627Seric syserr("putbody: df%s: read error", e->e_id); 245468627Seric ExitStat = EX_IOERR; 245568627Seric } 245668627Seric 245768627Seric endofmessage: 245859542Seric /* some mailers want extra blank line at end of message */ 245965870Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 246065870Seric buf[0] != '\0' && buf[0] != '\n') 246165870Seric putline("", mci); 246259542Seric 246365870Seric (void) fflush(mci->mci_out); 246465870Seric if (ferror(mci->mci_out) && errno != EPIPE) 24656974Seric { 24666974Seric syserr("putbody: write error"); 24676974Seric ExitStat = EX_IOERR; 24686974Seric } 24696974Seric errno = 0; 24706974Seric } 24716974Seric /* 2472294Seric ** MAILFILE -- Send a message to a file. 2473294Seric ** 24744327Seric ** If the file has the setuid/setgid bits set, but NO execute 24754327Seric ** bits, sendmail will try to become the owner of that file 24764327Seric ** rather than the real user. Obviously, this only works if 24774327Seric ** sendmail runs as root. 24784327Seric ** 24799370Seric ** This could be done as a subordinate mailer, except that it 24809370Seric ** is used implicitly to save messages in ~/dead.letter. We 24819370Seric ** view this as being sufficiently important as to include it 24829370Seric ** here. For example, if the system is dying, we shouldn't have 24839370Seric ** to create another process plus some pipes to save the message. 24849370Seric ** 2485294Seric ** Parameters: 2486294Seric ** filename -- the name of the file to send to. 24874397Seric ** ctladdr -- the controlling address header -- includes 24884397Seric ** the userid/groupid to be when sending. 2489294Seric ** 2490294Seric ** Returns: 2491294Seric ** The exit code associated with the operation. 2492294Seric ** 2493294Seric ** Side Effects: 2494294Seric ** none. 2495294Seric */ 2496294Seric 249754967Seric mailfile(filename, ctladdr, e) 2498294Seric char *filename; 24994397Seric ADDRESS *ctladdr; 250054967Seric register ENVELOPE *e; 2501294Seric { 2502294Seric register FILE *f; 250368627Seric register int pid = -1; 250453751Seric int mode; 2505294Seric 250659267Seric if (tTd(11, 1)) 250759267Seric { 250859267Seric printf("mailfile %s\n ctladdr=", filename); 250959267Seric printaddr(ctladdr, FALSE); 251059267Seric } 251159267Seric 251263753Seric if (e->e_xfp != NULL) 251363753Seric fflush(e->e_xfp); 251463753Seric 25154214Seric /* 25164214Seric ** Fork so we can change permissions here. 25174214Seric ** Note that we MUST use fork, not vfork, because of 25184214Seric ** the complications of calling subroutines, etc. 25194214Seric */ 25204067Seric 25214214Seric DOFORK(fork); 25224214Seric 25234214Seric if (pid < 0) 25244214Seric return (EX_OSERR); 25254214Seric else if (pid == 0) 25264214Seric { 25274214Seric /* child -- actually write to file */ 25284327Seric struct stat stb; 252968475Seric struct stat fsb; 253065870Seric MCI mcibuf; 253168490Seric int oflags = O_WRONLY|O_APPEND; 25324327Seric 253368475Seric if (e->e_lockfp != NULL) 2534*68689Seric (void) close(fileno(e->e_lockfp)); 253568475Seric 253664035Seric (void) setsignal(SIGINT, SIG_DFL); 253764035Seric (void) setsignal(SIGHUP, SIG_DFL); 253864035Seric (void) setsignal(SIGTERM, SIG_DFL); 253923102Seric (void) umask(OldUmask); 254052673Seric 254168627Seric #ifdef HASLSTAT 254268627Seric if ((SafeFileEnv != NULL ? lstat(filename, &stb) 254368627Seric : stat(filename, &stb)) < 0) 254468627Seric #else 25454327Seric if (stat(filename, &stb) < 0) 254668627Seric #endif 254768490Seric { 254859745Seric stb.st_mode = FileMode; 254968490Seric oflags |= O_CREAT|O_EXCL; 255068490Seric } 255168627Seric else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || 255268627Seric (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) 255368475Seric exit(EX_CANTCREAT); 255453751Seric mode = stb.st_mode; 255552673Seric 255652673Seric /* limit the errors to those actually caused in the child */ 255752673Seric errno = 0; 255852673Seric ExitStat = EX_OK; 255952673Seric 256064823Seric if (ctladdr != NULL) 256153751Seric { 256253751Seric /* ignore setuid and setgid bits */ 256353751Seric mode &= ~(S_ISGID|S_ISUID); 256453751Seric } 256553751Seric 256640931Srick /* we have to open the dfile BEFORE setuid */ 256768627Seric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 256840931Srick { 256968627Seric char *df = queuename(e, 'd'); 257068627Seric 257168627Seric e->e_dfp = fopen(df, "r"); 257252673Seric if (e->e_dfp == NULL) 257352673Seric { 257440931Srick syserr("mailfile: Cannot open %s for %s from %s", 257568627Seric df, e->e_to, e->e_from.q_paddr); 257640931Srick } 257740931Srick } 257840931Srick 257968627Seric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 258068490Seric { 258168627Seric int i; 258268627Seric 258368627Seric if (chroot(SafeFileEnv) < 0) 258468490Seric { 258568627Seric syserr("mailfile: Cannot chroot(%s)", 258668627Seric SafeFileEnv); 258768627Seric exit(EX_CANTCREAT); 258868490Seric } 258968627Seric i = strlen(SafeFileEnv); 259068627Seric if (strncmp(SafeFileEnv, filename, i) == 0) 259168627Seric filename += i; 259268627Seric } 259368627Seric if (chdir("/") < 0) 259468627Seric syserr("mailfile: cannot chdir(/)"); 259568627Seric 259668627Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 259768627Seric { 259868627Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 259953751Seric (void) initgroups(ctladdr->q_ruser ? 260053751Seric ctladdr->q_ruser : ctladdr->q_user, 260140972Sbostic ctladdr->q_gid); 260268627Seric else if (FileMailer != NULL && FileMailer->m_gid != 0) 260368627Seric (void) initgroups(DefUser, FileMailer->m_gid); 260468627Seric else 260568627Seric (void) initgroups(DefUser, DefGid); 26064417Seric } 260753751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 26084417Seric { 260968627Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 261068627Seric (void) setuid(ctladdr->q_uid); 261168627Seric else if (FileMailer != NULL && FileMailer->m_uid != 0) 261268627Seric (void) setuid(FileMailer->m_uid); 261368627Seric else 261468609Seric (void) setuid(DefUid); 26154417Seric } 261652673Seric FileName = filename; 261752673Seric LineNumber = 0; 261868490Seric f = dfopen(filename, oflags, FileMode); 26194214Seric if (f == NULL) 262052673Seric { 262164387Seric message("554 cannot open: %s", errstring(errno)); 26224214Seric exit(EX_CANTCREAT); 262352673Seric } 262468475Seric if (fstat(fileno(f), &fsb) < 0 || 262568627Seric (!bitset(O_CREAT, oflags) && 262668490Seric (stb.st_nlink != fsb.st_nlink || 262768490Seric stb.st_dev != fsb.st_dev || 262868490Seric stb.st_ino != fsb.st_ino || 262968627Seric stb.st_uid != fsb.st_uid))) 263068475Seric { 263168475Seric message("554 cannot write: file changed after open"); 263268475Seric exit(EX_CANTCREAT); 263368475Seric } 26344214Seric 263565870Seric bzero(&mcibuf, sizeof mcibuf); 263665870Seric mcibuf.mci_mailer = FileMailer; 263765870Seric mcibuf.mci_out = f; 263865870Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 263965870Seric mcibuf.mci_flags |= MCIF_7BIT; 264065870Seric 264165870Seric putfromline(&mcibuf, e); 264268627Seric (*e->e_puthdr)(&mcibuf, e->e_header, e); 264368228Seric (*e->e_putbody)(&mcibuf, e, NULL); 264465870Seric putline("\n", &mcibuf); 264552673Seric if (ferror(f)) 264652673Seric { 264764387Seric message("451 I/O error: %s", errstring(errno)); 264852673Seric setstat(EX_IOERR); 264952673Seric } 265058680Seric (void) xfclose(f, "mailfile", filename); 26514214Seric (void) fflush(stdout); 26524417Seric 26536887Seric /* reset ISUID & ISGID bits for paranoid systems */ 26544621Seric (void) chmod(filename, (int) stb.st_mode); 265552673Seric exit(ExitStat); 26564315Seric /*NOTREACHED*/ 26574214Seric } 26584214Seric else 26594214Seric { 26604214Seric /* parent -- wait for exit status */ 26619370Seric int st; 26624214Seric 26639370Seric st = waitfor(pid); 266464379Seric if (WIFEXITED(st)) 266564379Seric return (WEXITSTATUS(st)); 266664379Seric else 266764387Seric { 266864387Seric syserr("child died on signal %d", st); 26699370Seric return (EX_UNAVAILABLE); 267064387Seric } 267140931Srick /*NOTREACHED*/ 26724214Seric } 2673294Seric } 26744550Seric /* 267557454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 267657454Seric ** 267757454Seric ** The signature describes how we are going to send this -- it 267857454Seric ** can be just the hostname (for non-Internet hosts) or can be 267957454Seric ** an ordered list of MX hosts. 268057454Seric ** 268157454Seric ** Parameters: 268257454Seric ** m -- the mailer describing this host. 268357454Seric ** host -- the host name. 268457454Seric ** e -- the current envelope. 268557454Seric ** 268657454Seric ** Returns: 268757454Seric ** The signature for this host. 268857454Seric ** 268957454Seric ** Side Effects: 269057454Seric ** Can tweak the symbol table. 269157454Seric */ 269257454Seric 269357454Seric char * 269457454Seric hostsignature(m, host, e) 269557454Seric register MAILER *m; 269657454Seric char *host; 269757454Seric ENVELOPE *e; 269857454Seric { 269957454Seric register char *p; 270057454Seric register STAB *s; 270157454Seric int i; 270257454Seric int len; 270366334Seric #if NAMED_BIND 270457454Seric int nmx; 270557454Seric auto int rcode; 270659076Seric char *hp; 270759076Seric char *endp; 270868627Seric int oldoptions = _res.options; 270957454Seric char *mxhosts[MAXMXHOSTS + 1]; 271057454Seric #endif 271157454Seric 271257454Seric /* 271357454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 271457454Seric */ 271557454Seric 271657454Seric p = m->m_mailer; 271757454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 271857454Seric { 271957454Seric /* just an ordinary mailer */ 272057454Seric return host; 272157454Seric } 272257454Seric 272357454Seric /* 272457454Seric ** Look it up in the symbol table. 272557454Seric */ 272657454Seric 272757454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 272857454Seric if (s->s_hostsig != NULL) 272957454Seric return s->s_hostsig; 273057454Seric 273157454Seric /* 273257454Seric ** Not already there -- create a signature. 273357454Seric */ 273457454Seric 273566334Seric #if NAMED_BIND 273659111Seric if (ConfigLevel < 2) 273759111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 273859111Seric 273959076Seric for (hp = host; hp != NULL; hp = endp) 274057454Seric { 274159076Seric endp = strchr(hp, ':'); 274259076Seric if (endp != NULL) 274359076Seric *endp = '\0'; 274457454Seric 274559273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 274657454Seric 274759076Seric if (nmx <= 0) 274859076Seric { 274959076Seric register MCI *mci; 275057454Seric 275159076Seric /* update the connection info for this host */ 275259076Seric mci = mci_get(hp, m); 275359076Seric mci->mci_exitstat = rcode; 275459076Seric mci->mci_errno = errno; 275563753Seric mci->mci_herrno = h_errno; 275659076Seric 275759076Seric /* and return the original host name as the signature */ 275859076Seric nmx = 1; 275959076Seric mxhosts[0] = hp; 276059076Seric } 276159076Seric 276259076Seric len = 0; 276359076Seric for (i = 0; i < nmx; i++) 276459076Seric { 276559076Seric len += strlen(mxhosts[i]) + 1; 276659076Seric } 276759076Seric if (s->s_hostsig != NULL) 276859076Seric len += strlen(s->s_hostsig) + 1; 276959076Seric p = xalloc(len); 277059076Seric if (s->s_hostsig != NULL) 277159076Seric { 277259076Seric (void) strcpy(p, s->s_hostsig); 277359076Seric free(s->s_hostsig); 277459076Seric s->s_hostsig = p; 277559076Seric p += strlen(p); 277657454Seric *p++ = ':'; 277759076Seric } 277859076Seric else 277959076Seric s->s_hostsig = p; 278059076Seric for (i = 0; i < nmx; i++) 278159076Seric { 278259076Seric if (i != 0) 278359076Seric *p++ = ':'; 278459076Seric strcpy(p, mxhosts[i]); 278559076Seric p += strlen(p); 278659076Seric } 278759076Seric if (endp != NULL) 278859076Seric *endp++ = ':'; 278957454Seric } 279057454Seric makelower(s->s_hostsig); 279159111Seric if (ConfigLevel < 2) 279259111Seric _res.options = oldoptions; 279357454Seric #else 279457454Seric /* not using BIND -- the signature is just the host name */ 279557454Seric s->s_hostsig = host; 279657454Seric #endif 279757454Seric if (tTd(17, 1)) 279857454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 279957454Seric return s->s_hostsig; 280057454Seric } 280168627Seric /* 280268627Seric ** SETSTATUS -- set the address status for return messages 280368627Seric ** 280468627Seric ** Parameters: 280568627Seric ** a -- the address to set. 280668627Seric ** msg -- the text of the message, which must be in standard 280768627Seric ** SMTP form (3 digits, a space, and a message). 280868627Seric ** 280968627Seric ** Returns: 281068627Seric ** none. 281168627Seric */ 281268627Seric 281368627Seric setstatus(a, msg) 281468627Seric register ADDRESS *a; 281568627Seric char *msg; 281668627Seric { 281768627Seric char buf[MAXLINE]; 281868627Seric 281968627Seric if (a->q_rstatus != NULL) 282068627Seric free(a->q_rstatus); 282168627Seric if (strlen(msg) > 4) 282268627Seric { 282368627Seric register char *p, *q; 282468627Seric int parenlev = 0; 282568627Seric 282668627Seric strncpy(buf, msg, 4); 282768627Seric p = &buf[4]; 282868627Seric *p++ = '('; 282968627Seric for (q = &msg[4]; *q != '\0'; q++) 283068627Seric { 283168627Seric switch (*q) 283268627Seric { 283368627Seric case '(': 283468627Seric parenlev++; 283568627Seric break; 283668627Seric 283768627Seric case ')': 283868627Seric if (parenlev > 0) 283968627Seric parenlev--; 284068627Seric else 284168627Seric *p++ = '\\'; 284268627Seric break; 284368627Seric } 284468627Seric *p++ = *q; 284568627Seric } 284668627Seric while (parenlev-- >= 0) 284768627Seric *p++ = ')'; 284868627Seric *p++ = '\0'; 284968627Seric msg = buf; 285068627Seric } 285168627Seric a->q_rstatus = newstr(msg); 285268627Seric } 2853