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*68706Seric static char sccsid[] = "@(#)deliver.c 8.142 (Berkeley) 03/31/95"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1433931Sbostic #include <errno.h> 1566334Seric #if NAMED_BIND 1634022Sbostic #include <resolv.h> 1763753Seric 1863753Seric extern int h_errno; 1935651Seric #endif 20294Seric 2165075Seric extern char SmtpError[]; 2265075Seric 23294Seric /* 2458820Seric ** SENDALL -- actually send all the messages. 2558820Seric ** 2658820Seric ** Parameters: 2758820Seric ** e -- the envelope to send. 2858820Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 2958820Seric ** the current e->e_sendmode. 3058820Seric ** 3158820Seric ** Returns: 3258820Seric ** none. 3358820Seric ** 3458820Seric ** Side Effects: 3558820Seric ** Scans the send lists and sends everything it finds. 3658820Seric ** Delivers any appropriate error messages. 3758820Seric ** If we are running in a non-interactive mode, takes the 3858820Seric ** appropriate action. 3958820Seric */ 4058820Seric 4168627Seric void 4258820Seric sendall(e, mode) 4358820Seric ENVELOPE *e; 4458820Seric char mode; 4558820Seric { 4658820Seric register ADDRESS *q; 4758820Seric char *owner; 4858820Seric int otherowners; 4966009Seric register ENVELOPE *ee; 5066009Seric ENVELOPE *splitenv = NULL; 5168627Seric bool oldverbose = Verbose; 5268627Seric bool somedeliveries = FALSE; 5368627Seric int pid; 5468627Seric extern void sendenvelope(); 5558820Seric 5663839Seric /* 5763839Seric ** If we have had global, fatal errors, don't bother sending 5863839Seric ** the message at all if we are in SMTP mode. Local errors 5963839Seric ** (e.g., a single address failing) will still cause the other 6063839Seric ** addresses to be sent. 6163839Seric */ 6263839Seric 6365580Seric if (bitset(EF_FATALERRS, e->e_flags) && 6465580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 6561092Seric { 6661092Seric e->e_flags |= EF_CLRQUEUE; 6761092Seric return; 6861092Seric } 6961092Seric 7058820Seric /* determine actual delivery mode */ 7164826Seric CurrentLA = getla(); 7258820Seric if (mode == SM_DEFAULT) 7358820Seric { 7458820Seric mode = e->e_sendmode; 7558820Seric if (mode != SM_VERIFY && 7658820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 7758820Seric mode = SM_QUEUE; 7858820Seric } 7958820Seric 8058820Seric if (tTd(13, 1)) 8158820Seric { 8268627Seric extern void printenvflags(); 8368627Seric 8464310Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 8564310Seric mode, e->e_id); 8658820Seric printaddr(&e->e_from, FALSE); 8768627Seric printf("\te_flags = "); 8868627Seric printenvflags(e); 8958820Seric printf("sendqueue:\n"); 9058820Seric printaddr(e->e_sendqueue, TRUE); 9158820Seric } 9258820Seric 9358820Seric /* 9458820Seric ** Do any preprocessing necessary for the mode we are running. 9558820Seric ** Check to make sure the hop count is reasonable. 9658820Seric ** Delete sends to the sender in mailing lists. 9758820Seric */ 9858820Seric 9958820Seric CurEnv = e; 10058820Seric 10158820Seric if (e->e_hopcount > MaxHopCount) 10258820Seric { 10358820Seric errno = 0; 10468627Seric queueup(e, TRUE, mode == SM_QUEUE); 10566258Seric e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 10664495Seric syserr("554 too many hops %d (%d max): from %s via %s, to %s", 10758820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 10866003Seric RealHostName == NULL ? "localhost" : RealHostName, 10966003Seric e->e_sendqueue->q_paddr); 11058820Seric return; 11158820Seric } 11258820Seric 11359435Seric /* 11459435Seric ** Do sender deletion. 11559435Seric ** 11659435Seric ** If the sender has the QQUEUEUP flag set, skip this. 11759435Seric ** This can happen if the name server is hosed when you 11859435Seric ** are trying to send mail. The result is that the sender 11959435Seric ** is instantiated in the queue as a recipient. 12059435Seric */ 12159435Seric 12264118Seric if (!bitset(EF_METOO, e->e_flags) && 12364118Seric !bitset(QQUEUEUP, e->e_from.q_flags)) 12458820Seric { 12558820Seric if (tTd(13, 5)) 12658820Seric { 12758820Seric printf("sendall: QDONTSEND "); 12858820Seric printaddr(&e->e_from, FALSE); 12958820Seric } 13058820Seric e->e_from.q_flags |= QDONTSEND; 13168627Seric (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 13258820Seric } 13358820Seric 13458820Seric /* 13558820Seric ** Handle alias owners. 13658820Seric ** 13758820Seric ** We scan up the q_alias chain looking for owners. 13858820Seric ** We discard owners that are the same as the return path. 13958820Seric */ 14058820Seric 14158820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14258820Seric { 14358820Seric register struct address *a; 14458820Seric 14558820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 14658820Seric continue; 14758820Seric if (a != NULL) 14858820Seric q->q_owner = a->q_owner; 14958820Seric 15058820Seric if (q->q_owner != NULL && 15158820Seric !bitset(QDONTSEND, q->q_flags) && 15258820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 15358820Seric q->q_owner = NULL; 15458820Seric } 15558820Seric 15658820Seric owner = ""; 15758820Seric otherowners = 1; 15858820Seric while (owner != NULL && otherowners > 0) 15958820Seric { 16058820Seric owner = NULL; 16158820Seric otherowners = 0; 16258820Seric 16358820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16458820Seric { 16558820Seric if (bitset(QDONTSEND, q->q_flags)) 16658820Seric continue; 16758820Seric 16858820Seric if (q->q_owner != NULL) 16958820Seric { 17058820Seric if (owner == NULL) 17158820Seric owner = q->q_owner; 17258820Seric else if (owner != q->q_owner) 17358820Seric { 17458820Seric if (strcmp(owner, q->q_owner) == 0) 17558820Seric { 17658820Seric /* make future comparisons cheap */ 17758820Seric q->q_owner = owner; 17858820Seric } 17958820Seric else 18058820Seric { 18158820Seric otherowners++; 18258820Seric } 18358820Seric owner = q->q_owner; 18458820Seric } 18558820Seric } 18658820Seric else 18758820Seric { 18858820Seric otherowners++; 18958820Seric } 19068627Seric 19168627Seric /* 19268627Seric ** If this mailer is expensive, and if we don't 19368627Seric ** want to make connections now, just mark these 19468627Seric ** addresses and return. This is useful if we 19568627Seric ** want to batch connections to reduce load. This 19668627Seric ** will cause the messages to be queued up, and a 19768627Seric ** daemon will come along to send the messages later. 19868627Seric */ 19968627Seric 20068627Seric if (bitset(QBADADDR|QQUEUEUP, q->q_flags)) 20168627Seric continue; 20268627Seric if (NoConnect && !Verbose && 20368627Seric bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 20468627Seric { 20568627Seric q->q_flags |= QQUEUEUP; 20668627Seric e->e_to = q->q_paddr; 20768627Seric message("queued"); 20868627Seric if (LogLevel > 8) 20968627Seric logdelivery(q->q_mailer, NULL, 21068627Seric "queued", NULL, 21168627Seric (time_t) 0, e); 21268627Seric e->e_to = NULL; 21368627Seric } 21468627Seric else 21568627Seric { 21668627Seric somedeliveries = TRUE; 21768627Seric } 21858820Seric } 21958820Seric 22058820Seric if (owner != NULL && otherowners > 0) 22158820Seric { 22258820Seric extern HDR *copyheader(); 22358820Seric extern ADDRESS *copyqueue(); 22458820Seric 22558820Seric /* 22658820Seric ** Split this envelope into two. 22758820Seric */ 22858820Seric 22958820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 23058820Seric *ee = *e; 23158820Seric ee->e_id = NULL; 23258820Seric (void) queuename(ee, '\0'); 23358820Seric 23458820Seric if (tTd(13, 1)) 23558820Seric printf("sendall: split %s into %s\n", 23658820Seric e->e_id, ee->e_id); 23758820Seric 23858820Seric ee->e_header = copyheader(e->e_header); 23958820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 24058820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 24168627Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 24266784Seric ee->e_flags |= EF_NORECEIPT; 24358820Seric setsender(owner, ee, NULL, TRUE); 24458820Seric if (tTd(13, 5)) 24558820Seric { 24658820Seric printf("sendall(split): QDONTSEND "); 24758820Seric printaddr(&ee->e_from, FALSE); 24858820Seric } 24958820Seric ee->e_from.q_flags |= QDONTSEND; 25058820Seric ee->e_dfp = NULL; 25158820Seric ee->e_xfp = NULL; 25258820Seric ee->e_errormode = EM_MAIL; 25366009Seric ee->e_sibling = splitenv; 25466009Seric splitenv = ee; 25558820Seric 25658820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 25768627Seric { 25858820Seric if (q->q_owner == owner) 25966305Seric { 26058820Seric q->q_flags |= QDONTSEND; 26166305Seric q->q_flags &= ~QQUEUEUP; 26266305Seric } 26368627Seric } 26458820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 26568627Seric { 26658820Seric if (q->q_owner != owner) 26766305Seric { 26858820Seric q->q_flags |= QDONTSEND; 26966305Seric q->q_flags &= ~QQUEUEUP; 27066305Seric } 27168627Seric else 27268627Seric { 27368627Seric /* clear DSN parameters */ 27468627Seric q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); 27568627Seric q->q_flags |= QPINGONFAILURE|QPINGONDELAY; 27668627Seric } 27768627Seric } 27858820Seric 27968627Seric if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 28058820Seric { 28168627Seric char df1buf[20], df2buf[20]; 28268627Seric 28358820Seric ee->e_dfp = NULL; 28468627Seric strcpy(df1buf, queuename(e, 'd')); 28568627Seric strcpy(df2buf, queuename(ee, 'd')); 28668627Seric if (link(df1buf, df2buf) < 0) 28758820Seric { 28858820Seric syserr("sendall: link(%s, %s)", 28968627Seric df1buf, df2buf); 29058820Seric } 29158820Seric } 29258820Seric #ifdef LOG 29358820Seric if (LogLevel > 4) 29466012Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 29566012Seric ee->e_id, e->e_id, owner); 29658820Seric #endif 29758820Seric } 29858820Seric } 29958820Seric 30058820Seric if (owner != NULL) 30158820Seric { 30258820Seric setsender(owner, e, NULL, TRUE); 30358820Seric if (tTd(13, 5)) 30458820Seric { 30558820Seric printf("sendall(owner): QDONTSEND "); 30658820Seric printaddr(&e->e_from, FALSE); 30758820Seric } 30858820Seric e->e_from.q_flags |= QDONTSEND; 30958820Seric e->e_errormode = EM_MAIL; 31066784Seric e->e_flags |= EF_NORECEIPT; 31158820Seric } 31258820Seric 31368627Seric /* if nothing to be delivered, just queue up everything */ 31468627Seric if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY) 31568627Seric mode = SM_QUEUE; 31668627Seric 31766009Seric # ifdef QUEUE 31866009Seric if ((mode == SM_QUEUE || mode == SM_FORK || 31966009Seric (mode != SM_VERIFY && SuperSafe)) && 32066009Seric !bitset(EF_INQUEUE, e->e_flags)) 32158916Seric { 32266009Seric /* be sure everything is instantiated in the queue */ 32368627Seric queueup(e, TRUE, mode == SM_QUEUE); 32466009Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 32568627Seric queueup(ee, TRUE, mode == SM_QUEUE); 32658916Seric } 32766009Seric #endif /* QUEUE */ 32858916Seric 32963839Seric /* 33068627Seric ** If we belong in background, fork now. 33163839Seric */ 33263839Seric 33358916Seric switch (mode) 33458916Seric { 33558916Seric case SM_VERIFY: 33658916Seric Verbose = TRUE; 33758916Seric break; 33858916Seric 33958916Seric case SM_QUEUE: 34058916Seric queueonly: 34168627Seric if (e->e_nrcpts > 0) 34268627Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 34358916Seric return; 34458916Seric 34558916Seric case SM_FORK: 34658916Seric if (e->e_xfp != NULL) 34758916Seric (void) fflush(e->e_xfp); 34858916Seric 34965830Seric # if !HASFLOCK 35058916Seric /* 35164296Seric ** Since fcntl locking has the interesting semantic that 35264296Seric ** the lock is owned by a process, not by an open file 35364296Seric ** descriptor, we have to flush this to the queue, and 35464296Seric ** then restart from scratch in the child. 35558916Seric */ 35658916Seric 35768627Seric { 35868627Seric /* save id for future use */ 35968627Seric char *qid = e->e_id; 36058916Seric 36168627Seric /* now drop the envelope in the parent */ 36268627Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 36368627Seric dropenvelope(e); 36464296Seric 36568627Seric /* and reacquire in the child */ 36668627Seric (void) dowork(qid, TRUE, FALSE, e); 36768627Seric } 36864296Seric 36964296Seric return; 37064296Seric 37164296Seric # else /* HASFLOCK */ 37264296Seric 37358916Seric pid = fork(); 37458916Seric if (pid < 0) 37558916Seric { 37658916Seric goto queueonly; 37758916Seric } 37858916Seric else if (pid > 0) 37958916Seric { 38064310Seric /* be sure we leave the temp files to our child */ 38164310Seric /* can't call unlockqueue to avoid unlink of xfp */ 38264310Seric if (e->e_lockfp != NULL) 38368627Seric (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); 38464310Seric e->e_lockfp = NULL; 38564310Seric 38664310Seric /* close any random open files in the envelope */ 38764310Seric closexscript(e); 38864310Seric if (e->e_dfp != NULL) 38968627Seric (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); 39064310Seric e->e_dfp = NULL; 39168627Seric e->e_id = NULL; 39268627Seric e->e_flags &= ~EF_HAS_DF; 39366017Seric 39466017Seric /* catch intermediate zombie */ 39566017Seric (void) waitfor(pid); 39658916Seric return; 39758916Seric } 39858916Seric 39958916Seric /* double fork to avoid zombies */ 40066017Seric pid = fork(); 40166017Seric if (pid > 0) 40258916Seric exit(EX_OK); 40358916Seric 40458916Seric /* be sure we are immune from the terminal */ 40563839Seric disconnect(1, e); 40658916Seric 40766017Seric /* prevent parent from waiting if there was an error */ 40866017Seric if (pid < 0) 40966017Seric { 41066017Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 41166017Seric finis(); 41266017Seric } 41366017Seric 41458916Seric /* 41558916Seric ** Close any cached connections. 41658916Seric ** 41758916Seric ** We don't send the QUIT protocol because the parent 41858916Seric ** still knows about the connection. 41958916Seric ** 42058916Seric ** This should only happen when delivering an error 42158916Seric ** message. 42258916Seric */ 42358916Seric 42458916Seric mci_flush(FALSE, NULL); 42558916Seric 42664296Seric # endif /* HASFLOCK */ 42764296Seric 42858916Seric break; 42958916Seric } 43058916Seric 43168627Seric if (splitenv != NULL) 43268627Seric { 43368627Seric if (tTd(13, 1)) 43468627Seric { 43568627Seric printf("\nsendall: Split queue; remaining queue:\n"); 43668627Seric printaddr(e->e_sendqueue, TRUE); 43768627Seric } 43868627Seric 43968627Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 44068627Seric { 44168627Seric CurEnv = ee; 44268627Seric if (mode != SM_VERIFY) 44368627Seric openxscript(ee); 44468627Seric sendenvelope(ee, mode); 44568627Seric dropenvelope(ee); 44668627Seric } 44768627Seric 44868627Seric CurEnv = e; 44968627Seric } 45068627Seric sendenvelope(e, mode); 45168627Seric Verbose = oldverbose; 45268627Seric } 45368627Seric 45468627Seric void 45568627Seric sendenvelope(e, mode) 45668627Seric register ENVELOPE *e; 45768627Seric char mode; 45868627Seric { 45968627Seric register ADDRESS *q; 46068627Seric bool didany; 46168627Seric 46258820Seric /* 46368627Seric ** If we have had global, fatal errors, don't bother sending 46468627Seric ** the message at all if we are in SMTP mode. Local errors 46568627Seric ** (e.g., a single address failing) will still cause the other 46668627Seric ** addresses to be sent. 46768627Seric */ 46868627Seric 46968627Seric if (bitset(EF_FATALERRS, e->e_flags) && 47068627Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 47168627Seric { 47268627Seric e->e_flags |= EF_CLRQUEUE; 47368627Seric return; 47468627Seric } 47568627Seric 47668627Seric /* 47758820Seric ** Run through the list and send everything. 47863965Seric ** 47963965Seric ** Set EF_GLOBALERRS so that error messages during delivery 48063965Seric ** result in returned mail. 48158820Seric */ 48258820Seric 48358820Seric e->e_nsent = 0; 48463965Seric e->e_flags |= EF_GLOBALERRS; 48568627Seric didany = FALSE; 48664696Seric 48764696Seric /* now run through the queue */ 48858820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 48958820Seric { 49064441Seric #ifdef XDEBUG 49164441Seric char wbuf[MAXNAME + 20]; 49264441Seric 49364441Seric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 49464441Seric checkfd012(wbuf); 49564441Seric #endif 49658820Seric if (mode == SM_VERIFY) 49758820Seric { 49858820Seric e->e_to = q->q_paddr; 49958820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 50060173Seric { 50164942Seric if (q->q_host != NULL && q->q_host[0] != '\0') 50264942Seric message("deliverable: mailer %s, host %s, user %s", 50364942Seric q->q_mailer->m_name, 50464942Seric q->q_host, 50564942Seric q->q_user); 50664942Seric else 50764942Seric message("deliverable: mailer %s, user %s", 50864942Seric q->q_mailer->m_name, 50964942Seric q->q_user); 51060173Seric } 51158820Seric } 51258820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 51358820Seric { 51458820Seric # ifdef QUEUE 51558820Seric /* 51658820Seric ** Checkpoint the send list every few addresses 51758820Seric */ 51858820Seric 51958820Seric if (e->e_nsent >= CheckpointInterval) 52058820Seric { 52158820Seric queueup(e, TRUE, FALSE); 52258820Seric e->e_nsent = 0; 52358820Seric } 52458820Seric # endif /* QUEUE */ 52558820Seric (void) deliver(e, q); 52668627Seric didany = TRUE; 52758820Seric } 52858820Seric } 52968627Seric if (didany) 53068627Seric { 53168627Seric e->e_dtime = curtime(); 53268627Seric e->e_ntries++; 53368627Seric } 53458820Seric 53564441Seric #ifdef XDEBUG 53664441Seric checkfd012("end of sendenvelope"); 53764441Seric #endif 53864441Seric 53958820Seric if (mode == SM_FORK) 54058820Seric finis(); 54158820Seric } 54258820Seric /* 54358820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 54458820Seric ** 54558820Seric ** This MUST be a macro, since after a vfork we are running 54658820Seric ** two processes on the same stack!!! 54758820Seric ** 54858820Seric ** Parameters: 54958820Seric ** none. 55058820Seric ** 55158820Seric ** Returns: 55258820Seric ** From a macro??? You've got to be kidding! 55358820Seric ** 55458820Seric ** Side Effects: 55558820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 55658820Seric ** pid of child in parent, zero in child. 55758820Seric ** -1 on unrecoverable error. 55858820Seric ** 55958820Seric ** Notes: 56058820Seric ** I'm awfully sorry this looks so awful. That's 56158820Seric ** vfork for you..... 56258820Seric */ 56358820Seric 56458820Seric # define NFORKTRIES 5 56558820Seric 56658820Seric # ifndef FORK 56758820Seric # define FORK fork 56858820Seric # endif 56958820Seric 57058820Seric # define DOFORK(fORKfN) \ 57158820Seric {\ 57258820Seric register int i;\ 57358820Seric \ 57458820Seric for (i = NFORKTRIES; --i >= 0; )\ 57558820Seric {\ 57658820Seric pid = fORKfN();\ 57758820Seric if (pid >= 0)\ 57858820Seric break;\ 57958820Seric if (i > 0)\ 58058820Seric sleep((unsigned) NFORKTRIES - i);\ 58158820Seric }\ 58258820Seric } 58358820Seric /* 58458820Seric ** DOFORK -- simple fork interface to DOFORK. 58558820Seric ** 58658820Seric ** Parameters: 58758820Seric ** none. 58858820Seric ** 58958820Seric ** Returns: 59058820Seric ** pid of child in parent. 59158820Seric ** zero in child. 59258820Seric ** -1 on error. 59358820Seric ** 59458820Seric ** Side Effects: 59558820Seric ** returns twice, once in parent and once in child. 59658820Seric */ 59758820Seric 59858820Seric dofork() 59958820Seric { 60068627Seric register int pid = -1; 60158820Seric 60258820Seric DOFORK(fork); 60358820Seric return (pid); 60458820Seric } 60558820Seric /* 6064315Seric ** DELIVER -- Deliver a message to a list of addresses. 607294Seric ** 6084315Seric ** This routine delivers to everyone on the same host as the 6094315Seric ** user on the head of the list. It is clever about mailers 6104315Seric ** that don't handle multiple users. It is NOT guaranteed 6114315Seric ** that it will deliver to all these addresses however -- so 6124315Seric ** deliver should be called once for each address on the 6134315Seric ** list. 6144315Seric ** 615294Seric ** Parameters: 6169370Seric ** e -- the envelope to deliver. 6174621Seric ** firstto -- head of the address list to deliver to. 618294Seric ** 619294Seric ** Returns: 620294Seric ** zero -- successfully delivered. 621294Seric ** else -- some failure, see ExitStat for more info. 622294Seric ** 623294Seric ** Side Effects: 624294Seric ** The standard input is passed off to someone. 625294Seric */ 626294Seric 62768627Seric int 6289370Seric deliver(e, firstto) 6299370Seric register ENVELOPE *e; 6304621Seric ADDRESS *firstto; 631294Seric { 6324452Seric char *host; /* host being sent to */ 6334452Seric char *user; /* user being sent to */ 634294Seric char **pvp; 6353233Seric register char **mvp; 6363233Seric register char *p; 63710306Seric register MAILER *m; /* mailer for this recipient */ 6384397Seric ADDRESS *ctladdr; 63954967Seric register MCI *mci; 6404621Seric register ADDRESS *to = firstto; 6414863Seric bool clever = FALSE; /* running user smtp to this mailer */ 64268627Seric ADDRESS *tochain = NULL; /* users chain in this mailer call */ 64351951Seric int rcode; /* response code */ 64457454Seric char *firstsig; /* signature of firstto */ 64568627Seric int pid = -1; 64658820Seric char *curhost; 64768627Seric time_t xstart; 64858820Seric int mpvect[2]; 64958820Seric int rpvect[2]; 65010306Seric char *pv[MAXPV+1]; 65158704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 65268627Seric char buf[MAXNAME + 1]; 65368627Seric char rpathbuf[MAXNAME + 1]; /* translated return path */ 65457441Seric extern int checkcompat(); 655294Seric 6564488Seric errno = 0; 65758680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6583233Seric return (0); 659294Seric 66066334Seric #if NAMED_BIND 66134022Sbostic /* unless interactive, try twice, over a minute */ 66265580Seric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 66365580Seric { 66434022Sbostic _res.retrans = 30; 66534022Sbostic _res.retry = 2; 66634022Sbostic } 66736788Sbostic #endif 66834022Sbostic 6696974Seric m = to->q_mailer; 6706974Seric host = to->q_host; 67158803Seric CurEnv = e; /* just in case */ 67259044Seric e->e_statmsg = NULL; 67364718Seric SmtpError[0] = '\0'; 67468627Seric xstart = curtime(); 6756974Seric 6767672Seric if (tTd(10, 1)) 67766010Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 67866010Seric e->e_id, m->m_name, host, to->q_user); 67964725Seric if (tTd(10, 100)) 68064725Seric printopenfds(FALSE); 681294Seric 682294Seric /* 6833233Seric ** Do initial argv setup. 6843233Seric ** Insert the mailer name. Notice that $x expansion is 6853233Seric ** NOT done on the mailer name. Then, if the mailer has 6863233Seric ** a picky -f flag, we insert it as appropriate. This 6873233Seric ** code does not check for 'pv' overflow; this places a 6883233Seric ** manifest lower limit of 4 for MAXPV. 6898062Seric ** The from address rewrite is expected to make 6908062Seric ** the address relative to the other end. 6912968Seric */ 6922968Seric 6934452Seric /* rewrite from address, using rewriting rules */ 69459163Seric rcode = EX_OK; 69568627Seric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 69668627Seric p = e->e_sender; 69768627Seric else 69868627Seric p = e->e_from.q_paddr; 69968627Seric (void) strcpy(rpathbuf, remotename(p, m, 70059163Seric RF_SENDERADDR|RF_CANONICAL, 70159163Seric &rcode, e)); 70258680Seric define('g', rpathbuf, e); /* translated return path */ 7039370Seric define('h', host, e); /* to host */ 7043233Seric Errors = 0; 7053233Seric pvp = pv; 7063233Seric *pvp++ = m->m_argv[0]; 7072968Seric 7083233Seric /* insert -f or -r flag as appropriate */ 70910682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 7103233Seric { 71110682Seric if (bitnset(M_FOPT, m->m_flags)) 7123233Seric *pvp++ = "-f"; 7133233Seric else 7143233Seric *pvp++ = "-r"; 71551951Seric *pvp++ = newstr(rpathbuf); 7163233Seric } 717294Seric 718294Seric /* 7193233Seric ** Append the other fixed parts of the argv. These run 7203233Seric ** up to the first entry containing "$u". There can only 7213233Seric ** be one of these, and there are only a few more slots 7223233Seric ** in the pv after it. 723294Seric */ 724294Seric 7253233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 726294Seric { 72758050Seric /* can't use strchr here because of sign extension problems */ 72858050Seric while (*p != '\0') 72958050Seric { 73058050Seric if ((*p++ & 0377) == MACROEXPAND) 73158050Seric { 73258050Seric if (*p == 'u') 73358050Seric break; 73458050Seric } 73558050Seric } 73658050Seric 73758050Seric if (*p != '\0') 7383233Seric break; 7393233Seric 7403233Seric /* this entry is safe -- go ahead and process it */ 74168627Seric expand(*mvp, buf, sizeof buf, e); 7423233Seric *pvp++ = newstr(buf); 7433233Seric if (pvp >= &pv[MAXPV - 3]) 7443233Seric { 74558151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7463233Seric return (-1); 7473233Seric } 748294Seric } 7494863Seric 7506038Seric /* 7516038Seric ** If we have no substitution for the user name in the argument 7526038Seric ** list, we know that we must supply the names otherwise -- and 7536038Seric ** SMTP is the answer!! 7546038Seric */ 7556038Seric 7563233Seric if (*mvp == NULL) 7574863Seric { 7584863Seric /* running SMTP */ 7595179Seric # ifdef SMTP 7604863Seric clever = TRUE; 7614863Seric *pvp = NULL; 76256795Seric # else /* SMTP */ 7636038Seric /* oops! we don't implement SMTP */ 76464718Seric syserr("554 SMTP style mailer not implemented"); 7655179Seric return (EX_SOFTWARE); 76656795Seric # endif /* SMTP */ 7674863Seric } 768294Seric 769294Seric /* 7703233Seric ** At this point *mvp points to the argument with $u. We 7713233Seric ** run through our address list and append all the addresses 7723233Seric ** we can. If we run out of space, do not fret! We can 7733233Seric ** always send another copy later. 774294Seric */ 775294Seric 7763233Seric tobuf[0] = '\0'; 7779370Seric e->e_to = tobuf; 7784397Seric ctladdr = NULL; 77957454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7803233Seric for (; to != NULL; to = to->q_next) 781294Seric { 7823233Seric /* avoid sending multiple recipients to dumb mailers */ 78310682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7843233Seric break; 7853233Seric 7863233Seric /* if already sent or not for this host, don't send */ 78758680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 78857454Seric to->q_mailer != firstto->q_mailer || 78957454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7903233Seric continue; 7914397Seric 7928225Seric /* avoid overflowing tobuf */ 79342462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7948225Seric break; 7958225Seric 7967672Seric if (tTd(10, 1)) 7975032Seric { 7985032Seric printf("\nsend to "); 7995032Seric printaddr(to, FALSE); 8005032Seric } 8015032Seric 8024397Seric /* compute effective uid/gid when sending */ 80368627Seric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 80465137Seric ctladdr = getctladdr(to); 8054397Seric 80668627Seric if (tTd(10, 2)) 80768627Seric { 80868627Seric printf("ctladdr="); 80968627Seric printaddr(ctladdr, FALSE); 81068627Seric } 81168627Seric 8123233Seric user = to->q_user; 8139370Seric e->e_to = to->q_paddr; 81457731Seric if (tTd(10, 5)) 81557731Seric { 81657731Seric printf("deliver: QDONTSEND "); 81757731Seric printaddr(to, FALSE); 81857731Seric } 81958680Seric to->q_flags |= QDONTSEND; 8203233Seric 8213233Seric /* 8223233Seric ** Check to see that these people are allowed to 8233233Seric ** talk to each other. 8243233Seric */ 8253233Seric 82610699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 82710699Seric { 82868627Seric e->e_flags |= EF_NO_BODY_RETN; 82958151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 83068627Seric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 83110699Seric continue; 83210699Seric } 83368627Seric #if NAMED_BIND 83468627Seric h_errno = 0; 83568627Seric #endif 83657441Seric rcode = checkcompat(to, e); 83757459Seric if (rcode != EX_OK) 838294Seric { 83968627Seric markfailure(e, to, NULL, rcode); 84068627Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8413233Seric continue; 842294Seric } 8433233Seric 8443233Seric /* 8454099Seric ** Strip quote bits from names if the mailer is dumb 8464099Seric ** about them. 8473233Seric */ 8483233Seric 84910682Seric if (bitnset(M_STRIPQ, m->m_flags)) 850294Seric { 85154983Seric stripquotes(user); 85254983Seric stripquotes(host); 8533233Seric } 8543233Seric 8559206Seric /* hack attack -- delivermail compatibility */ 8569206Seric if (m == ProgMailer && *user == '|') 8579206Seric user++; 8589206Seric 8593233Seric /* 8604161Seric ** If an error message has already been given, don't 8614161Seric ** bother to send to this address. 8624161Seric ** 8634161Seric ** >>>>>>>>>> This clause assumes that the local mailer 8644161Seric ** >> NOTE >> cannot do any further aliasing; that 8654161Seric ** >>>>>>>>>> function is subsumed by sendmail. 8664161Seric */ 8674161Seric 8687293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8694161Seric continue; 8704161Seric 8714283Seric /* save statistics.... */ 8729370Seric markstats(e, to); 8734283Seric 8744161Seric /* 8753233Seric ** See if this user name is "special". 8763233Seric ** If the user name has a slash in it, assume that this 8776974Seric ** is a file -- send it off without further ado. Note 8786974Seric ** that this type of addresses is not processed along 8796974Seric ** with the others, so we fudge on the To person. 8803233Seric */ 8813233Seric 88257402Seric if (m == FileMailer) 8833233Seric { 88465060Seric rcode = mailfile(user, ctladdr, e); 88568627Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 88668627Seric e->e_nsent++; 88757402Seric if (rcode == EX_OK) 88868627Seric { 88957402Seric to->q_flags |= QSENT; 89068627Seric if (bitnset(M_LOCALMAILER, m->m_flags) && 89168627Seric (e->e_receiptto != NULL || 89268627Seric bitset(QPINGONSUCCESS, to->q_flags))) 89368627Seric { 89468627Seric to->q_flags |= QREPORT; 89568627Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 89668627Seric to->q_paddr); 89768627Seric } 89868627Seric } 89968627Seric to->q_statdate = curtime(); 90057402Seric continue; 901294Seric } 9023233Seric 9034315Seric /* 9044315Seric ** Address is verified -- add this user to mailer 9054315Seric ** argv, and add it to the print list of recipients. 9064315Seric */ 9074315Seric 9086059Seric /* link together the chain of recipients */ 9096272Seric to->q_tchain = tochain; 9106272Seric tochain = to; 9116059Seric 9123233Seric /* create list of users for error messages */ 9139388Seric (void) strcat(tobuf, ","); 9144082Seric (void) strcat(tobuf, to->q_paddr); 9159370Seric define('u', user, e); /* to user */ 91664694Seric p = to->q_home; 91764694Seric if (p == NULL && ctladdr != NULL) 91864694Seric p = ctladdr->q_home; 91964694Seric define('z', p, e); /* user's home */ 9203233Seric 9214863Seric /* 9226059Seric ** Expand out this user into argument list. 9234863Seric */ 9244863Seric 9256059Seric if (!clever) 9263233Seric { 92768627Seric expand(*mvp, buf, sizeof buf, e); 9284863Seric *pvp++ = newstr(buf); 9294863Seric if (pvp >= &pv[MAXPV - 2]) 9304863Seric { 9314863Seric /* allow some space for trailing parms */ 9324863Seric break; 9334863Seric } 9344863Seric } 935294Seric } 936294Seric 9374067Seric /* see if any addresses still exist */ 9384067Seric if (tobuf[0] == '\0') 9394863Seric { 9409370Seric define('g', (char *) NULL, e); 9414067Seric return (0); 9424863Seric } 9434067Seric 9443233Seric /* print out messages as full list */ 9459388Seric e->e_to = tobuf + 1; 9463233Seric 947294Seric /* 9483233Seric ** Fill out any parameters after the $u parameter. 949294Seric */ 950294Seric 9514863Seric while (!clever && *++mvp != NULL) 952294Seric { 95368627Seric expand(*mvp, buf, sizeof buf, e); 9543233Seric *pvp++ = newstr(buf); 9553233Seric if (pvp >= &pv[MAXPV]) 95658151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 957294Seric } 9583233Seric *pvp++ = NULL; 959294Seric 960294Seric /* 961294Seric ** Call the mailer. 9622898Seric ** The argument vector gets built, pipes 963294Seric ** are created as necessary, and we fork & exec as 9642898Seric ** appropriate. 9654863Seric ** If we are running SMTP, we just need to clean up. 966294Seric */ 967294Seric 96865137Seric /*XXX this seems a bit wierd */ 96965750Seric if (ctladdr == NULL && m != ProgMailer && 97065750Seric bitset(QGOODUID, e->e_from.q_flags)) 97165137Seric ctladdr = &e->e_from; 97265137Seric 97366334Seric #if NAMED_BIND 97451313Seric if (ConfigLevel < 2) 97551313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 97635651Seric #endif 97754967Seric 9787672Seric if (tTd(11, 1)) 979294Seric { 9808178Seric printf("openmailer:"); 98158820Seric printav(pv); 982294Seric } 9834488Seric errno = 0; 98468627Seric #if NAMED_BIND 98568627Seric h_errno = 0; 98668627Seric #endif 9873233Seric 98868627Seric CurHostName = NULL; 98925050Seric 9906038Seric /* 9916038Seric ** Deal with the special case of mail handled through an IPC 9926038Seric ** connection. 9936038Seric ** In this case we don't actually fork. We must be 9946038Seric ** running SMTP for this to work. We will return a 9956038Seric ** zero pid to indicate that we are running IPC. 99611160Seric ** We also handle a debug version that just talks to stdin/out. 9976038Seric */ 9986038Seric 99958820Seric curhost = NULL; 100064334Seric SmtpPhase = NULL; 100164718Seric mci = NULL; 100258820Seric 100364401Seric #ifdef XDEBUG 100464401Seric { 100564401Seric char wbuf[MAXLINE]; 100664401Seric 100764401Seric /* make absolutely certain 0, 1, and 2 are in use */ 100864401Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 100964401Seric checkfd012(wbuf); 101064401Seric } 101164401Seric #endif 101264401Seric 101368627Seric /* check for 8-bit available */ 101468627Seric if (bitset(EF_HAS8BIT, e->e_flags) && 101568627Seric bitnset(M_7BITS, m->m_flags) && 101668627Seric !bitset(MM_MIME8BIT, MimeMode)) 101768627Seric { 101868627Seric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 101968627Seric rcode = EX_DATAERR; 102068627Seric goto give_up; 102168627Seric } 102268627Seric 102311160Seric /* check for Local Person Communication -- not for mortals!!! */ 102411160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 102511160Seric { 102654967Seric mci = (MCI *) xalloc(sizeof *mci); 102754993Seric bzero((char *) mci, sizeof *mci); 102853738Seric mci->mci_in = stdin; 102953738Seric mci->mci_out = stdout; 103054967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 103153751Seric mci->mci_mailer = m; 103211160Seric } 103354967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 103454967Seric strcmp(m->m_mailer, "[TCP]") == 0) 10356038Seric { 103652107Seric #ifdef DAEMON 103757454Seric register int i; 103868627Seric register u_short port = 0; 10396038Seric 104064844Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 104164844Seric { 104264844Seric syserr("null host name for %s mailer", m->m_mailer); 104364844Seric rcode = EX_CONFIG; 104464844Seric goto give_up; 104564844Seric } 104664844Seric 104758820Seric CurHostName = pv[1]; 104858820Seric curhost = hostsignature(m, pv[1], e); 104954967Seric 105058479Seric if (curhost == NULL || curhost[0] == '\0') 105158479Seric { 105264844Seric syserr("null host signature for %s", pv[1]); 105367133Seric rcode = EX_CONFIG; 105458820Seric goto give_up; 105558479Seric } 105658479Seric 10576038Seric if (!clever) 105858479Seric { 105958151Seric syserr("554 non-clever IPC"); 106064718Seric rcode = EX_CONFIG; 106158820Seric goto give_up; 106258479Seric } 106358820Seric if (pv[2] != NULL) 106458820Seric port = atoi(pv[2]); 106558820Seric tryhost: 106657454Seric while (*curhost != '\0') 106729433Sbloom { 106857454Seric register char *p; 106968627Seric static char hostbuf[MAXNAME + 1]; 107057454Seric 107157454Seric /* pull the next host from the signature */ 107257454Seric p = strchr(curhost, ':'); 107357454Seric if (p == NULL) 107457454Seric p = &curhost[strlen(curhost)]; 107564718Seric if (p == curhost) 107664718Seric { 107764718Seric syserr("deliver: null host name in signature"); 107864726Seric curhost++; 107964718Seric continue; 108064718Seric } 108157454Seric strncpy(hostbuf, curhost, p - curhost); 108257454Seric hostbuf[p - curhost] = '\0'; 108357454Seric if (*p != '\0') 108457454Seric p++; 108557454Seric curhost = p; 108657454Seric 108753738Seric /* see if we already know that this host is fried */ 108857454Seric CurHostName = hostbuf; 108957454Seric mci = mci_get(hostbuf, m); 109054967Seric if (mci->mci_state != MCIS_CLOSED) 109157387Seric { 109257387Seric if (tTd(11, 1)) 109357387Seric { 109457387Seric printf("openmailer: "); 109564731Seric mci_dump(mci, FALSE); 109657387Seric } 109757943Seric CurHostName = mci->mci_host; 109868627Seric message("Using cached connection to %s via %s...", 109968627Seric hostbuf, m->m_name); 110058820Seric break; 110157387Seric } 110253751Seric mci->mci_mailer = m; 110354967Seric if (mci->mci_exitstat != EX_OK) 110454967Seric continue; 110554967Seric 110654967Seric /* try the connection */ 110757454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 110868627Seric message("Connecting to %s via %s...", 110957454Seric hostbuf, m->m_name); 111057454Seric i = makeconnection(hostbuf, port, mci, 111154967Seric bitnset(M_SECURE_PORT, m->m_flags)); 111254967Seric mci->mci_exitstat = i; 111354967Seric mci->mci_errno = errno; 111466334Seric #if NAMED_BIND 111563753Seric mci->mci_herrno = h_errno; 111663753Seric #endif 111754967Seric if (i == EX_OK) 111852106Seric { 111954967Seric mci->mci_state = MCIS_OPENING; 112054967Seric mci_cache(mci); 112163753Seric if (TrafficLogFile != NULL) 112263753Seric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 112363753Seric getpid(), hostbuf); 112454967Seric break; 112534022Sbostic } 112654967Seric else if (tTd(11, 1)) 112754967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 112854967Seric i, errno); 112953738Seric 113053738Seric /* enter status of this host */ 113153738Seric setstat(i); 113264718Seric 113364718Seric /* should print some message here for -v mode */ 11346047Seric } 113564718Seric if (mci == NULL) 113664718Seric { 113764718Seric syserr("deliver: no host name"); 113864718Seric rcode = EX_OSERR; 113964718Seric goto give_up; 114064718Seric } 114154993Seric mci->mci_pid = 0; 114254967Seric #else /* no DAEMON */ 114358151Seric syserr("554 openmailer: no IPC"); 114457387Seric if (tTd(11, 1)) 114557387Seric printf("openmailer: NULL\n"); 114664718Seric rcode = EX_UNAVAILABLE; 114764718Seric goto give_up; 114854967Seric #endif /* DAEMON */ 11496038Seric } 115054967Seric else 1151294Seric { 115268627Seric /* flush any expired connections */ 115368627Seric (void) mci_scan(NULL); 115468627Seric 115568627Seric /* announce the connection to verbose listeners */ 115668627Seric if (host == NULL || host[0] == '\0') 115768627Seric message("Connecting to %s...", m->m_name); 115868627Seric else 115968627Seric message("Connecting to %s via %s...", host, m->m_name); 116063753Seric if (TrafficLogFile != NULL) 116158852Seric { 116263753Seric char **av; 116358925Seric 116463753Seric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 116563753Seric for (av = pv; *av != NULL; av++) 116663753Seric fprintf(TrafficLogFile, " %s", *av); 116763753Seric fprintf(TrafficLogFile, "\n"); 116858852Seric } 116958852Seric 117054967Seric /* create a pipe to shove the mail through */ 117154967Seric if (pipe(mpvect) < 0) 117254967Seric { 117358925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 117458925Seric e->e_to, m->m_name); 117557387Seric if (tTd(11, 1)) 117657387Seric printf("openmailer: NULL\n"); 117758820Seric rcode = EX_OSERR; 117858820Seric goto give_up; 117954967Seric } 11804863Seric 118154967Seric /* if this mailer speaks smtp, create a return pipe */ 118254967Seric if (clever && pipe(rpvect) < 0) 118354967Seric { 118458925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 118558925Seric e->e_to, m->m_name); 118654967Seric (void) close(mpvect[0]); 118754967Seric (void) close(mpvect[1]); 118857387Seric if (tTd(11, 1)) 118957387Seric printf("openmailer: NULL\n"); 119058820Seric rcode = EX_OSERR; 119158820Seric goto give_up; 119254967Seric } 11934863Seric 119454967Seric /* 119554967Seric ** Actually fork the mailer process. 119654967Seric ** DOFORK is clever about retrying. 119754967Seric ** 119854967Seric ** Dispose of SIGCHLD signal catchers that may be laying 119954967Seric ** around so that endmail will get it. 120054967Seric */ 12016038Seric 120254967Seric if (e->e_xfp != NULL) 120354967Seric (void) fflush(e->e_xfp); /* for debugging */ 120454967Seric (void) fflush(stdout); 120526434Seric # ifdef SIGCHLD 120664035Seric (void) setsignal(SIGCHLD, SIG_DFL); 120756795Seric # endif /* SIGCHLD */ 120854967Seric DOFORK(FORK); 120954967Seric /* pid is set by DOFORK */ 121054967Seric if (pid < 0) 12114863Seric { 121254967Seric /* failure */ 121358925Seric syserr("%s... openmailer(%s): cannot fork", 121458925Seric e->e_to, m->m_name); 121554967Seric (void) close(mpvect[0]); 121654967Seric (void) close(mpvect[1]); 121754967Seric if (clever) 121854967Seric { 121954967Seric (void) close(rpvect[0]); 122054967Seric (void) close(rpvect[1]); 122154967Seric } 122257387Seric if (tTd(11, 1)) 122357387Seric printf("openmailer: NULL\n"); 122458820Seric rcode = EX_OSERR; 122558820Seric goto give_up; 12264863Seric } 122754967Seric else if (pid == 0) 122854967Seric { 122954967Seric int i; 123056678Seric int saveerrno; 123158675Seric char **ep; 123258675Seric char *env[MAXUSERENVIRON]; 123358675Seric extern char **environ; 123454967Seric extern int DtableSize; 123515772Seric 123668475Seric if (e->e_lockfp != NULL) 123768589Seric (void) close(fileno(e->e_lockfp)); 123868475Seric 123954967Seric /* child -- set up input & exec mailer */ 124064035Seric (void) setsignal(SIGINT, SIG_IGN); 124164035Seric (void) setsignal(SIGHUP, SIG_IGN); 124264035Seric (void) setsignal(SIGTERM, SIG_DFL); 12434709Seric 124464145Seric /* reset user and group */ 124568627Seric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 124664145Seric { 124768627Seric (void) setgid(m->m_gid); 124868627Seric (void) setuid(m->m_uid); 124968627Seric } 125068627Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 125168627Seric { 125268627Seric (void) initgroups(ctladdr->q_ruser? 125368627Seric ctladdr->q_ruser: ctladdr->q_user, 125468627Seric ctladdr->q_gid); 125568627Seric (void) setgid(ctladdr->q_gid); 125668627Seric (void) setuid(ctladdr->q_uid); 125768627Seric } 125868627Seric else 125968627Seric { 126068627Seric (void) initgroups(DefUser, DefGid); 126168627Seric if (m->m_gid == 0) 126264837Seric (void) setgid(DefGid); 126368627Seric else 126468627Seric (void) setgid(m->m_gid); 126568627Seric if (m->m_uid == 0) 126664145Seric (void) setuid(DefUid); 126764145Seric else 126868627Seric (void) setuid(m->m_uid); 126964145Seric } 127064145Seric 127164145Seric if (tTd(11, 2)) 127264145Seric printf("openmailer: running as r/euid=%d/%d\n", 127364145Seric getuid(), geteuid()); 127464145Seric 127558935Seric /* move into some "safe" directory */ 127658935Seric if (m->m_execdir != NULL) 127758935Seric { 127858935Seric char *p, *q; 127968627Seric char buf[MAXLINE + 1]; 128058935Seric 128158935Seric for (p = m->m_execdir; p != NULL; p = q) 128258935Seric { 128358935Seric q = strchr(p, ':'); 128458935Seric if (q != NULL) 128558935Seric *q = '\0'; 128668627Seric expand(p, buf, sizeof buf, e); 128758935Seric if (q != NULL) 128858935Seric *q++ = ':'; 128958935Seric if (tTd(11, 20)) 129058935Seric printf("openmailer: trydir %s\n", 129158935Seric buf); 129258935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 129358935Seric break; 129458935Seric } 129558935Seric } 129658935Seric 129754967Seric /* arrange to filter std & diag output of command */ 129854967Seric if (clever) 129954967Seric { 130054967Seric (void) close(rpvect[0]); 130158852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 130258852Seric { 130358925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 130458925Seric e->e_to, m->m_name, rpvect[1]); 130558852Seric _exit(EX_OSERR); 130658852Seric } 130754967Seric (void) close(rpvect[1]); 130854967Seric } 130966089Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 131066089Seric HoldErrs || DisConnected) 131154967Seric { 131254967Seric /* put mailer output in transcript */ 131358852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 131458852Seric { 131558925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 131658925Seric e->e_to, m->m_name, 131758852Seric fileno(e->e_xfp)); 131858852Seric _exit(EX_OSERR); 131958852Seric } 132054967Seric } 132158852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 132258852Seric { 132358925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 132458925Seric e->e_to, m->m_name); 132558852Seric _exit(EX_OSERR); 132658852Seric } 13274709Seric 132854967Seric /* arrange to get standard input */ 132954967Seric (void) close(mpvect[1]); 133058731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13314417Seric { 133258925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 133358925Seric e->e_to, m->m_name, mpvect[0]); 133454967Seric _exit(EX_OSERR); 13354417Seric } 133654967Seric (void) close(mpvect[0]); 13379370Seric 133854967Seric /* arrange for all the files to be closed */ 133954967Seric for (i = 3; i < DtableSize; i++) 134054967Seric { 134154967Seric register int j; 134264145Seric 134354967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 134464145Seric (void) fcntl(i, F_SETFD, j | 1); 134554967Seric } 13462774Seric 134766017Seric /* 134866017Seric ** Set up the mailer environment 134968627Seric ** _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag. 135066017Seric ** TZ is timezone information. 135166017Seric ** SYSTYPE is Apollo software sys type (required). 135266017Seric ** ISP is Apollo hardware system type (required). 135366017Seric */ 135466017Seric 135558675Seric i = 0; 135658675Seric env[i++] = "AGENT=sendmail"; 135768627Seric env[i++] = "_FORCE_MAIL_LOCAL_=yes"; 135858675Seric for (ep = environ; *ep != NULL; ep++) 135958675Seric { 136066017Seric if (strncmp(*ep, "TZ=", 3) == 0 || 136166017Seric strncmp(*ep, "ISP=", 4) == 0 || 136266017Seric strncmp(*ep, "SYSTYPE=", 8) == 0) 136358675Seric env[i++] = *ep; 136458675Seric } 136568627Seric env[i] = NULL; 136658675Seric 136766746Seric /* run disconnected from terminal */ 136866746Seric (void) setsid(); 136966746Seric 137054967Seric /* try to execute the mailer */ 137168705Seric execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) env); 137256678Seric saveerrno = errno; 137354967Seric syserr("Cannot exec %s", m->m_mailer); 137468627Seric if (bitnset(M_LOCALMAILER, m->m_flags) || 137568627Seric transienterror(saveerrno)) 137660008Seric _exit(EX_OSERR); 137754967Seric _exit(EX_UNAVAILABLE); 137851835Seric } 137954967Seric 138054967Seric /* 138154967Seric ** Set up return value. 138254967Seric */ 138354967Seric 138454967Seric mci = (MCI *) xalloc(sizeof *mci); 138554993Seric bzero((char *) mci, sizeof *mci); 138654967Seric mci->mci_mailer = m; 138754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 138854993Seric mci->mci_pid = pid; 138954967Seric (void) close(mpvect[0]); 139054967Seric mci->mci_out = fdopen(mpvect[1], "w"); 139164724Seric if (mci->mci_out == NULL) 139264724Seric { 139364724Seric syserr("deliver: cannot create mailer output channel, fd=%d", 139464724Seric mpvect[1]); 139564724Seric (void) close(mpvect[1]); 139664724Seric if (clever) 139764724Seric { 139864724Seric (void) close(rpvect[0]); 139964724Seric (void) close(rpvect[1]); 140064724Seric } 140164724Seric rcode = EX_OSERR; 140264724Seric goto give_up; 140364724Seric } 140454967Seric if (clever) 140554967Seric { 140654967Seric (void) close(rpvect[1]); 140754967Seric mci->mci_in = fdopen(rpvect[0], "r"); 140864724Seric if (mci->mci_in == NULL) 140964724Seric { 141064724Seric syserr("deliver: cannot create mailer input channel, fd=%d", 141164724Seric mpvect[1]); 141264724Seric (void) close(rpvect[0]); 141364724Seric fclose(mci->mci_out); 141464724Seric mci->mci_out = NULL; 141564724Seric rcode = EX_OSERR; 141664724Seric goto give_up; 141764724Seric } 141854967Seric } 141954967Seric else 142054967Seric { 142154967Seric mci->mci_flags |= MCIF_TEMP; 142254967Seric mci->mci_in = NULL; 142354967Seric } 1424294Seric } 1425294Seric 14264709Seric /* 142754967Seric ** If we are in SMTP opening state, send initial protocol. 14284709Seric */ 14294709Seric 143054967Seric if (clever && mci->mci_state != MCIS_CLOSED) 14314863Seric { 143254967Seric smtpinit(m, mci, e); 143353738Seric } 143468627Seric 143568627Seric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 143668627Seric mci->mci_flags |= MCIF_CVT8TO7; 143768627Seric else 143868627Seric mci->mci_flags &= ~MCIF_CVT8TO7; 143968627Seric 144057387Seric if (tTd(11, 1)) 144157387Seric { 144257387Seric printf("openmailer: "); 144364731Seric mci_dump(mci, FALSE); 144457387Seric } 1445294Seric 144658820Seric if (mci->mci_state != MCIS_OPEN) 144758820Seric { 144858820Seric /* couldn't open the mailer */ 144958820Seric rcode = mci->mci_exitstat; 145058820Seric errno = mci->mci_errno; 145166334Seric #if NAMED_BIND 145263753Seric h_errno = mci->mci_herrno; 145363753Seric #endif 145458820Seric if (rcode == EX_OK) 145558820Seric { 145658820Seric /* shouldn't happen */ 145758820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 145858820Seric rcode, mci->mci_state, firstsig); 145958820Seric rcode = EX_SOFTWARE; 146058820Seric } 146168627Seric else if (curhost != NULL && *curhost != '\0') 146259958Seric { 146359958Seric /* try next MX site */ 146459958Seric goto tryhost; 146559958Seric } 146658820Seric } 146758820Seric else if (!clever) 146858820Seric { 146958820Seric /* 147058820Seric ** Format and send message. 147158820Seric */ 147258820Seric 147365870Seric putfromline(mci, e); 147468627Seric (*e->e_puthdr)(mci, e->e_header, e); 147568228Seric (*e->e_putbody)(mci, e, NULL); 147658820Seric 147758820Seric /* get the exit status */ 147858820Seric rcode = endmailer(mci, e, pv); 147958820Seric } 148058820Seric else 148158820Seric #ifdef SMTP 148258820Seric { 148358820Seric /* 148458820Seric ** Send the MAIL FROM: protocol 148558820Seric */ 148658820Seric 148758820Seric rcode = smtpmailfrom(m, mci, e); 148858820Seric if (rcode == EX_OK) 148958820Seric { 149058820Seric register char *t = tobuf; 149158820Seric register int i; 149258820Seric 149358820Seric /* send the recipient list */ 149458820Seric tobuf[0] = '\0'; 149558820Seric for (to = tochain; to != NULL; to = to->q_tchain) 149658820Seric { 149758820Seric e->e_to = to->q_paddr; 149858820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 149958820Seric { 150068627Seric markfailure(e, to, mci, i); 150168627Seric giveresponse(i, m, mci, ctladdr, xstart, e); 150258820Seric } 150358820Seric else 150458820Seric { 150558820Seric *t++ = ','; 150658820Seric for (p = to->q_paddr; *p; *t++ = *p++) 150758820Seric continue; 150864372Seric *t = '\0'; 150958820Seric } 151058820Seric } 151158820Seric 151258820Seric /* now send the data */ 151358820Seric if (tobuf[0] == '\0') 151458820Seric { 151558820Seric rcode = EX_OK; 151658820Seric e->e_to = NULL; 151758820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 151858820Seric smtprset(m, mci, e); 151958820Seric } 152058820Seric else 152158820Seric { 152258820Seric e->e_to = tobuf + 1; 152358820Seric rcode = smtpdata(m, mci, e); 152458820Seric } 152558820Seric 152658820Seric /* now close the connection */ 152758820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 152858820Seric smtpquit(m, mci, e); 152958820Seric } 153064922Seric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 153158820Seric { 153258820Seric /* try next MX site */ 153358820Seric goto tryhost; 153458820Seric } 153558820Seric } 153658820Seric #else /* not SMTP */ 153758820Seric { 153858820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 153958820Seric rcode = EX_CONFIG; 154058820Seric goto give_up; 154158820Seric } 154258820Seric #endif /* SMTP */ 154366334Seric #if NAMED_BIND 154458820Seric if (ConfigLevel < 2) 154558820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 154658820Seric #endif 154758820Seric 154858820Seric /* arrange a return receipt if requested */ 154964718Seric if (rcode == EX_OK && e->e_receiptto != NULL && 155064718Seric bitnset(M_LOCALMAILER, m->m_flags)) 155158820Seric { 155258820Seric e->e_flags |= EF_SENDRECEIPT; 155358820Seric /* do we want to send back more info? */ 155458820Seric } 155558820Seric 155658820Seric /* 155758820Seric ** Do final status disposal. 155858820Seric ** We check for something in tobuf for the SMTP case. 155958820Seric ** If we got a temporary failure, arrange to queue the 156058820Seric ** addressees. 156158820Seric */ 156258820Seric 156358820Seric give_up: 156458820Seric if (tobuf[0] != '\0') 156568627Seric giveresponse(rcode, m, mci, ctladdr, xstart, e); 156658820Seric for (to = tochain; to != NULL; to = to->q_tchain) 156758820Seric { 156858820Seric if (rcode != EX_OK) 156968627Seric markfailure(e, to, mci, rcode); 157068627Seric else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) 157158820Seric { 157258820Seric to->q_flags |= QSENT; 157368627Seric to->q_statdate = curtime(); 157458820Seric e->e_nsent++; 157568627Seric if (bitnset(M_LOCALMAILER, m->m_flags) && 157668627Seric (e->e_receiptto != NULL || 157768627Seric bitset(QPINGONSUCCESS, to->q_flags))) 157864718Seric { 157968627Seric to->q_flags |= QREPORT; 158064718Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 158164718Seric to->q_paddr); 158264718Seric } 158368627Seric else if (bitset(QPINGONSUCCESS, to->q_flags) && 158468627Seric bitset(QPRIMARY, to->q_flags) && 158568627Seric !bitset(MCIF_DSN, mci->mci_flags)) 158668627Seric { 158768627Seric to->q_flags |= QRELAYED; 158868627Seric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 158968627Seric to->q_paddr); 159068627Seric } 159158820Seric } 159258820Seric } 159358820Seric 159458820Seric /* 159558820Seric ** Restore state and return. 159658820Seric */ 159758820Seric 159864401Seric #ifdef XDEBUG 159964401Seric { 160064401Seric char wbuf[MAXLINE]; 160164401Seric 160264401Seric /* make absolutely certain 0, 1, and 2 are in use */ 160364554Seric sprintf(wbuf, "%s... end of deliver(%s)", 160464554Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 160564554Seric m->m_name); 160664401Seric checkfd012(wbuf); 160764401Seric } 160864401Seric #endif 160964401Seric 161058820Seric errno = 0; 161158820Seric define('g', (char *) NULL, e); 161258820Seric return (rcode); 1613294Seric } 1614294Seric /* 161558820Seric ** MARKFAILURE -- mark a failure on a specific address. 161658820Seric ** 161758820Seric ** Parameters: 161858820Seric ** e -- the envelope we are sending. 161958820Seric ** q -- the address to mark. 162068627Seric ** mci -- mailer connection information. 162158820Seric ** rcode -- the code signifying the particular failure. 162258820Seric ** 162358820Seric ** Returns: 162458820Seric ** none. 162558820Seric ** 162658820Seric ** Side Effects: 162758820Seric ** marks the address (and possibly the envelope) with the 162858820Seric ** failure so that an error will be returned or 162958820Seric ** the message will be queued, as appropriate. 163058820Seric */ 163158820Seric 163268627Seric markfailure(e, q, mci, rcode) 163358820Seric register ENVELOPE *e; 163458820Seric register ADDRESS *q; 163568627Seric register MCI *mci; 163658820Seric int rcode; 163758820Seric { 163868627Seric char *stat = NULL; 163958820Seric 164065051Seric switch (rcode) 164165051Seric { 164265051Seric case EX_OK: 164365051Seric break; 164465051Seric 164565051Seric case EX_TEMPFAIL: 164665051Seric case EX_IOERR: 164765051Seric case EX_OSERR: 164863753Seric q->q_flags |= QQUEUEUP; 164965051Seric break; 165065051Seric 165165051Seric default: 165258820Seric q->q_flags |= QBADADDR; 165365051Seric break; 165465051Seric } 165568627Seric 165668627Seric if (q->q_status == NULL && mci != NULL) 165768627Seric q->q_status = mci->mci_status; 165868627Seric switch (rcode) 165968627Seric { 166068627Seric case EX_USAGE: 166168627Seric stat = "5.5.4"; 166268627Seric break; 166368627Seric 166468627Seric case EX_DATAERR: 166568627Seric stat = "5.5.2"; 166668627Seric break; 166768627Seric 166868627Seric case EX_NOUSER: 166968627Seric case EX_NOHOST: 167068627Seric stat = "5.1.1"; 167168627Seric break; 167268627Seric 167368627Seric case EX_NOINPUT: 167468627Seric case EX_CANTCREAT: 167568627Seric case EX_NOPERM: 167668627Seric stat = "5.3.0"; 167768627Seric break; 167868627Seric 167968627Seric case EX_UNAVAILABLE: 168068627Seric case EX_SOFTWARE: 168168627Seric case EX_OSFILE: 168268627Seric case EX_PROTOCOL: 168368627Seric case EX_CONFIG: 168468627Seric stat = "5.5.0"; 168568627Seric break; 168668627Seric 168768627Seric case EX_OSERR: 168868627Seric case EX_IOERR: 168968627Seric stat = "4.5.0"; 169068627Seric break; 169168627Seric 169268627Seric case EX_TEMPFAIL: 169368627Seric stat = "4.2.0"; 169468627Seric break; 169568627Seric } 169668627Seric if (stat != NULL && q->q_status == NULL) 169768627Seric q->q_status = stat; 169868627Seric 169968627Seric q->q_statdate = curtime(); 170068627Seric if (CurHostName != NULL && CurHostName[0] != '\0') 170168627Seric q->q_statmta = newstr(CurHostName); 170268627Seric if (rcode != EX_OK && q->q_rstatus == NULL) 170368627Seric { 170468627Seric char buf[30]; 170568627Seric 170668627Seric (void) sprintf(buf, "%d", rcode); 170768627Seric q->q_rstatus = newstr(buf); 170868627Seric } 170958820Seric } 171058820Seric /* 171158820Seric ** ENDMAILER -- Wait for mailer to terminate. 171258820Seric ** 171358820Seric ** We should never get fatal errors (e.g., segmentation 171458820Seric ** violation), so we report those specially. For other 171558820Seric ** errors, we choose a status message (into statmsg), 171658820Seric ** and if it represents an error, we print it. 171758820Seric ** 171858820Seric ** Parameters: 171958820Seric ** pid -- pid of mailer. 172058820Seric ** e -- the current envelope. 172158820Seric ** pv -- the parameter vector that invoked the mailer 172258820Seric ** (for error messages). 172358820Seric ** 172458820Seric ** Returns: 172558820Seric ** exit code of mailer. 172658820Seric ** 172758820Seric ** Side Effects: 172858820Seric ** none. 172958820Seric */ 173058820Seric 173158820Seric endmailer(mci, e, pv) 173258820Seric register MCI *mci; 173358820Seric register ENVELOPE *e; 173458820Seric char **pv; 173558820Seric { 173658820Seric int st; 173758820Seric 173858820Seric /* close any connections */ 173958820Seric if (mci->mci_in != NULL) 174065198Seric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 174158820Seric if (mci->mci_out != NULL) 174265198Seric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 174358820Seric mci->mci_in = mci->mci_out = NULL; 174458820Seric mci->mci_state = MCIS_CLOSED; 174558820Seric 174658820Seric /* in the IPC case there is nothing to wait for */ 174758820Seric if (mci->mci_pid == 0) 174858820Seric return (EX_OK); 174958820Seric 175058820Seric /* wait for the mailer process to die and collect status */ 175158820Seric st = waitfor(mci->mci_pid); 175258820Seric if (st == -1) 175358820Seric { 175458820Seric syserr("endmailer %s: wait", pv[0]); 175558820Seric return (EX_SOFTWARE); 175658820Seric } 175758820Seric 175864379Seric if (WIFEXITED(st)) 175958820Seric { 176064379Seric /* normal death -- return status */ 176164379Seric return (WEXITSTATUS(st)); 176264379Seric } 176358820Seric 176464379Seric /* it died a horrid death */ 176565545Seric syserr("451 mailer %s died with signal %o", 176665545Seric mci->mci_mailer->m_name, st); 176758820Seric 176864379Seric /* log the arguments */ 176965194Seric if (pv != NULL && e->e_xfp != NULL) 177064379Seric { 177164379Seric register char **av; 177258820Seric 177364379Seric fprintf(e->e_xfp, "Arguments:"); 177464379Seric for (av = pv; *av != NULL; av++) 177564379Seric fprintf(e->e_xfp, " %s", *av); 177664379Seric fprintf(e->e_xfp, "\n"); 177758820Seric } 177858820Seric 177964379Seric ExitStat = EX_TEMPFAIL; 178064379Seric return (EX_TEMPFAIL); 178158820Seric } 178258820Seric /* 1783294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1784294Seric ** 1785294Seric ** Parameters: 1786294Seric ** stat -- the status code from the mailer (high byte 1787294Seric ** only; core dumps must have been taken care of 1788294Seric ** already). 178958337Seric ** m -- the mailer info for this mailer. 179058337Seric ** mci -- the mailer connection info -- can be NULL if the 179158337Seric ** response is given before the connection is made. 179264771Seric ** ctladdr -- the controlling address for the recipient 179364771Seric ** address(es). 179468627Seric ** xstart -- the transaction start time, for computing 179568627Seric ** transaction delays. 179658337Seric ** e -- the current envelope. 1797294Seric ** 1798294Seric ** Returns: 17994082Seric ** none. 1800294Seric ** 1801294Seric ** Side Effects: 18021518Seric ** Errors may be incremented. 1803294Seric ** ExitStat may be set. 1804294Seric */ 1805294Seric 180668627Seric giveresponse(stat, m, mci, ctladdr, xstart, e) 1807294Seric int stat; 18089370Seric register MAILER *m; 180958337Seric register MCI *mci; 181064771Seric ADDRESS *ctladdr; 181168627Seric time_t xstart; 181210105Seric ENVELOPE *e; 1813294Seric { 181460094Seric register const char *statmsg; 1815294Seric extern char *SysExMsg[]; 1816294Seric register int i; 181736788Sbostic extern int N_SysEx; 181810105Seric char buf[MAXLINE]; 1819294Seric 18204315Seric /* 18214315Seric ** Compute status message from code. 18224315Seric */ 18234315Seric 1824294Seric i = stat - EX__BASE; 18259370Seric if (stat == 0) 182658852Seric { 18279370Seric statmsg = "250 Sent"; 182858916Seric if (e->e_statmsg != NULL) 182958852Seric { 183058916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 183158852Seric statmsg = buf; 183258852Seric } 183358852Seric } 18349370Seric else if (i < 0 || i > N_SysEx) 18359370Seric { 18369370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 18379370Seric stat = EX_UNAVAILABLE; 18389370Seric statmsg = buf; 18399370Seric } 184010105Seric else if (stat == EX_TEMPFAIL) 184110105Seric { 184258664Seric (void) strcpy(buf, SysExMsg[i] + 1); 184366334Seric #if NAMED_BIND 184425527Smiriam if (h_errno == TRY_AGAIN) 184563993Seric statmsg = errstring(h_errno+E_DNSBASE); 184621061Seric else 184736788Sbostic #endif 184821061Seric { 184925527Smiriam if (errno != 0) 185025527Smiriam statmsg = errstring(errno); 185125527Smiriam else 185225527Smiriam { 185321061Seric #ifdef SMTP 185425527Smiriam statmsg = SmtpError; 185556795Seric #else /* SMTP */ 185625527Smiriam statmsg = NULL; 185756795Seric #endif /* SMTP */ 185825527Smiriam } 185921061Seric } 186021061Seric if (statmsg != NULL && statmsg[0] != '\0') 186121061Seric { 186210124Seric (void) strcat(buf, ": "); 186321061Seric (void) strcat(buf, statmsg); 186410105Seric } 186510105Seric statmsg = buf; 186610105Seric } 186766334Seric #if NAMED_BIND 186863753Seric else if (stat == EX_NOHOST && h_errno != 0) 186963753Seric { 187063993Seric statmsg = errstring(h_errno + E_DNSBASE); 187167077Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 187263753Seric statmsg = buf; 187363753Seric } 187463753Seric #endif 1875294Seric else 187621061Seric { 1877294Seric statmsg = SysExMsg[i]; 187858664Seric if (*statmsg++ == ':') 187958664Seric { 188058664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 188158664Seric statmsg = buf; 188258664Seric } 188321061Seric } 18849370Seric 18859370Seric /* 18869370Seric ** Print the message as appropriate 18879370Seric */ 18889370Seric 188910105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 189064718Seric { 189164718Seric extern char MsgBuf[]; 189264718Seric 189366307Seric message("%s", &statmsg[4]); 189464718Seric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 189564718Seric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 189664718Seric } 1897294Seric else 1898294Seric { 189967077Seric char mbuf[8]; 190067077Seric 19011518Seric Errors++; 190267077Seric sprintf(mbuf, "%.3s %%s", statmsg); 190367077Seric usrerr(mbuf, &statmsg[4]); 1904294Seric } 1905294Seric 1906294Seric /* 1907294Seric ** Final cleanup. 1908294Seric ** Log a record of the transaction. Compute the new 1909294Seric ** ExitStat -- if we already had an error, stick with 1910294Seric ** that. 1911294Seric */ 1912294Seric 191358020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 191468627Seric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 19157858Seric 191666323Seric if (tTd(11, 2)) 191766323Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 191867962Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 191966323Seric 19204621Seric if (stat != EX_TEMPFAIL) 19214621Seric setstat(stat); 192264952Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 192310105Seric { 192410105Seric if (e->e_message != NULL) 192510105Seric free(e->e_message); 192610105Seric e->e_message = newstr(&statmsg[4]); 192710105Seric } 192810124Seric errno = 0; 192966334Seric #if NAMED_BIND 193025527Smiriam h_errno = 0; 193136788Sbostic #endif 1932294Seric } 1933294Seric /* 19348496Seric ** LOGDELIVERY -- log the delivery in the system log 19358496Seric ** 193664969Seric ** Care is taken to avoid logging lines that are too long, because 193764969Seric ** some versions of syslog have an unfortunate proclivity for core 193864969Seric ** dumping. This is a hack, to be sure, that is at best empirical. 193964969Seric ** 19408496Seric ** Parameters: 194158337Seric ** m -- the mailer info. Can be NULL for initial queue. 194258337Seric ** mci -- the mailer connection info -- can be NULL if the 194358337Seric ** log is occuring when no connection is active. 194458337Seric ** stat -- the message to print for the status. 194564771Seric ** ctladdr -- the controlling address for the to list. 194668627Seric ** xstart -- the transaction start time, used for 194768627Seric ** computing transaction delay. 194858337Seric ** e -- the current envelope. 19498496Seric ** 19508496Seric ** Returns: 19518496Seric ** none 19528496Seric ** 19538496Seric ** Side Effects: 19548496Seric ** none 19558496Seric */ 19568496Seric 195768627Seric logdelivery(m, mci, stat, ctladdr, xstart, e) 195858337Seric MAILER *m; 195958337Seric register MCI *mci; 19608496Seric char *stat; 196164771Seric ADDRESS *ctladdr; 196268627Seric time_t xstart; 196354967Seric register ENVELOPE *e; 19648496Seric { 196558343Seric # ifdef LOG 196664771Seric register char *bp; 196764969Seric register char *p; 196864969Seric int l; 196958418Seric char buf[512]; 19708496Seric 197165059Seric # if (SYSLOG_BUFSIZE) >= 256 197264771Seric bp = buf; 197364771Seric if (ctladdr != NULL) 197464771Seric { 197564771Seric strcpy(bp, ", ctladdr="); 197665016Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 197764771Seric bp += strlen(bp); 197864771Seric if (bitset(QGOODUID, ctladdr->q_flags)) 197964771Seric { 198064771Seric (void) sprintf(bp, " (%d/%d)", 198164771Seric ctladdr->q_uid, ctladdr->q_gid); 198264771Seric bp += strlen(bp); 198364771Seric } 198464771Seric } 198558337Seric 198668627Seric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 198764771Seric bp += strlen(bp); 198864771Seric 198968627Seric if (xstart != (time_t) 0) 199068627Seric { 199168627Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 199268627Seric bp += strlen(bp); 199368627Seric } 199468627Seric 199558513Seric if (m != NULL) 199658305Seric { 199764771Seric (void) strcpy(bp, ", mailer="); 199864771Seric (void) strcat(bp, m->m_name); 199964771Seric bp += strlen(bp); 200058305Seric } 200158513Seric 200258513Seric if (mci != NULL && mci->mci_host != NULL) 200358305Seric { 200458305Seric # ifdef DAEMON 200558755Seric extern SOCKADDR CurHostAddr; 200658513Seric # endif 200758305Seric 200864771Seric (void) strcpy(bp, ", relay="); 200964771Seric (void) strcat(bp, mci->mci_host); 201058513Seric 201158513Seric # ifdef DAEMON 201265919Seric (void) strcat(bp, " ["); 201364771Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 201465919Seric (void) strcat(bp, "]"); 201558305Seric # endif 201658305Seric } 201766894Seric else if (strcmp(stat, "queued") != 0) 201858513Seric { 201958513Seric char *p = macvalue('h', e); 202058343Seric 202158513Seric if (p != NULL && p[0] != '\0') 202258513Seric { 202364771Seric (void) strcpy(bp, ", relay="); 202464771Seric (void) strcat(bp, p); 202558513Seric } 202658513Seric } 202764922Seric bp += strlen(bp); 202864969Seric 202965059Seric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 203065059Seric #if (STATLEN) < 63 203165059Seric # undef STATLEN 203265059Seric # define STATLEN 63 203365059Seric #endif 203465059Seric #if (STATLEN) > 203 203565059Seric # undef STATLEN 203665059Seric # define STATLEN 203 203765059Seric #endif 203865059Seric 203965059Seric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 204064969Seric { 204164969Seric /* desperation move -- truncate data */ 204265059Seric bp = buf + sizeof buf - ((STATLEN) + 17); 204364969Seric strcpy(bp, "..."); 204464969Seric bp += 3; 204564969Seric } 204664969Seric 204764969Seric (void) strcpy(bp, ", stat="); 204864969Seric bp += strlen(bp); 204965059Seric 205065059Seric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 205158418Seric 205264969Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 205364969Seric p = e->e_to; 2054*68706Seric while (strlen(p) >= (SIZE_T) l) 205564969Seric { 205664969Seric register char *q = strchr(p + l, ','); 205764969Seric 205865008Seric if (q == NULL) 205964969Seric break; 206064969Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 206164969Seric e->e_id, ++q - p, p, buf); 206264969Seric p = q; 206364969Seric } 206464969Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 206565059Seric 206665059Seric # else /* we have a very short log buffer size */ 206765059Seric 206866258Seric l = SYSLOG_BUFSIZE - 85; 206965059Seric p = e->e_to; 207065059Seric while (strlen(p) >= l) 207165059Seric { 207265059Seric register char *q = strchr(p + l, ','); 207365059Seric 207465059Seric if (q == NULL) 207565059Seric break; 207665059Seric syslog(LOG_INFO, "%s: to=%.*s [more]", 207765059Seric e->e_id, ++q - p, p); 207865059Seric p = q; 207965059Seric } 208065059Seric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 208165059Seric 208265059Seric if (ctladdr != NULL) 208365059Seric { 208465059Seric bp = buf; 208565059Seric strcpy(buf, "ctladdr="); 208665059Seric bp += strlen(buf); 208765059Seric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 208865059Seric bp += strlen(buf); 208965059Seric if (bitset(QGOODUID, ctladdr->q_flags)) 209065059Seric { 209165059Seric (void) sprintf(bp, " (%d/%d)", 209265059Seric ctladdr->q_uid, ctladdr->q_gid); 209365059Seric bp += strlen(bp); 209465059Seric } 209565059Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 209665059Seric } 209765650Seric bp = buf; 209865650Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 209965650Seric bp += strlen(bp); 210068627Seric if (xstart != (time_t) 0) 210168627Seric { 210268627Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 210368627Seric bp += strlen(bp); 210468627Seric } 210565059Seric 210665059Seric if (m != NULL) 210765650Seric { 210865650Seric sprintf(bp, ", mailer=%s", m->m_name); 210965650Seric bp += strlen(bp); 211065650Seric } 211166009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 211265059Seric 211366009Seric buf[0] = '\0'; 211465059Seric if (mci != NULL && mci->mci_host != NULL) 211565059Seric { 211665059Seric # ifdef DAEMON 211765059Seric extern SOCKADDR CurHostAddr; 211865059Seric # endif 211965059Seric 212066021Seric sprintf(buf, "relay=%s", mci->mci_host); 212165059Seric 212265059Seric # ifdef DAEMON 212366009Seric (void) strcat(buf, " ["); 212466009Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 212566009Seric (void) strcat(buf, "]"); 212665059Seric # endif 212765059Seric } 212866894Seric else if (strcmp(stat, "queued") != 0) 212965059Seric { 213065059Seric char *p = macvalue('h', e); 213165059Seric 213265059Seric if (p != NULL && p[0] != '\0') 213366021Seric sprintf(buf, "relay=%s", p); 213465059Seric } 213566009Seric if (buf[0] != '\0') 213666009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 213765059Seric 213865059Seric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 213965059Seric # endif /* short log buffer */ 214056795Seric # endif /* LOG */ 21418496Seric } 21428496Seric /* 21436974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 2144294Seric ** 21456974Seric ** This can be made an arbitrary message separator by changing $l 2146294Seric ** 214716150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 214816150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 214916150Seric ** does a well-meaning programmer such as myself have to deal with 215016150Seric ** this kind of antique garbage???? 21516974Seric ** 2152294Seric ** Parameters: 215365870Seric ** mci -- the connection information. 215465870Seric ** e -- the envelope. 2155294Seric ** 2156294Seric ** Returns: 21576974Seric ** none 2158294Seric ** 2159294Seric ** Side Effects: 21606974Seric ** outputs some text to fp. 2161294Seric */ 2162294Seric 216365870Seric putfromline(mci, e) 216465870Seric register MCI *mci; 216554967Seric ENVELOPE *e; 2166294Seric { 216758050Seric char *template = "\201l\n"; 21686974Seric char buf[MAXLINE]; 2169294Seric 217065870Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 21716974Seric return; 21724315Seric 21736974Seric # ifdef UGLYUUCP 217465870Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 21754205Seric { 217612223Seric char *bang; 217712223Seric char xbuf[MAXLINE]; 21786041Seric 217968627Seric expand("\201g", buf, sizeof buf, e); 218056795Seric bang = strchr(buf, '!'); 21816974Seric if (bang == NULL) 218264370Seric { 218364370Seric errno = 0; 218464370Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 218564370Seric } 21865099Seric else 21879370Seric { 218812223Seric *bang++ = '\0'; 218958050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 219012223Seric template = xbuf; 21919370Seric } 21926974Seric } 219356795Seric # endif /* UGLYUUCP */ 219468627Seric expand(template, buf, sizeof buf, e); 219568627Seric putxline(buf, mci, FALSE); 21965981Seric } 21975981Seric /* 21986974Seric ** PUTBODY -- put the body of a message. 21996974Seric ** 22006974Seric ** Parameters: 220165870Seric ** mci -- the connection information. 22029538Seric ** e -- the envelope to put out. 220359730Seric ** separator -- if non-NULL, a message separator that must 220459730Seric ** not be permitted in the resulting message. 22056974Seric ** 22066974Seric ** Returns: 22076974Seric ** none. 22086974Seric ** 22096974Seric ** Side Effects: 22106974Seric ** The message is written onto fp. 22116974Seric */ 22126974Seric 221368627Seric /* values for output state variable */ 221468627Seric #define OS_HEAD 0 /* at beginning of line */ 221568627Seric #define OS_CR 1 /* read a carriage return */ 221668627Seric #define OS_INLINE 2 /* putting rest of line */ 221768627Seric 221868228Seric putbody(mci, e, separator) 221965870Seric register MCI *mci; 22209538Seric register ENVELOPE *e; 222159730Seric char *separator; 22226974Seric { 222310168Seric char buf[MAXLINE]; 22246974Seric 22256974Seric /* 22266974Seric ** Output the body of the message 22276974Seric */ 22286974Seric 222968627Seric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 223068627Seric { 223168627Seric char *df = queuename(e, 'd'); 223268627Seric 223368627Seric e->e_dfp = fopen(df, "r"); 223468627Seric if (e->e_dfp == NULL) 223568627Seric syserr("putbody: Cannot open %s for %s from %s", 223668627Seric df, e->e_to, e->e_from.q_paddr); 223768627Seric } 22389538Seric if (e->e_dfp == NULL) 22396974Seric { 224068627Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 22419538Seric { 224268627Seric putline("", mci); 224368627Seric mci->mci_flags &= ~MCIF_INHEADER; 22449538Seric } 224568627Seric putline("<<< No Message Collected >>>", mci); 224668627Seric goto endofmessage; 224768627Seric } 224868627Seric if (e->e_dfino == (ino_t) 0) 224968627Seric { 225068627Seric struct stat stbuf; 225168627Seric 225268627Seric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 225368627Seric e->e_dfino = -1; 225468609Seric else 225568627Seric { 225668627Seric e->e_dfdev = stbuf.st_dev; 225768627Seric e->e_dfino = stbuf.st_ino; 225868627Seric } 225968515Seric } 226068627Seric rewind(e->e_dfp); 226168627Seric 226268627Seric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 226368515Seric { 226468627Seric char *boundaries[MAXMIMENESTING + 1]; 226568627Seric 226668627Seric /* 226768627Seric ** Do 8 to 7 bit MIME conversion. 226868627Seric */ 226968627Seric 227068627Seric /* make sure it looks like a MIME message */ 227168627Seric if (hvalue("MIME-Version", e->e_header) == NULL) 227268627Seric putline("MIME-Version: 1.0", mci); 227368627Seric 227468627Seric if (hvalue("Content-Type", e->e_header) == NULL) 227568515Seric { 227668627Seric sprintf(buf, "Content-Type: text/plain; charset=%s", 227768627Seric defcharset(e)); 227867813Seric putline(buf, mci); 227967813Seric } 228067813Seric 228168627Seric /* now do the hard work */ 228268627Seric boundaries[0] = NULL; 228368627Seric mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 228468627Seric } 228568627Seric else 228668627Seric { 228768627Seric int ostate; 228868627Seric register char *bp; 228968627Seric register char *pbp; 229068627Seric register int c; 229168627Seric int padc; 229268627Seric char *buflim; 229368627Seric int pos = 0; 229468627Seric char peekbuf[10]; 229568627Seric 229668627Seric /* we can pass it through unmodified */ 229768627Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 229816875Seric { 229968627Seric putline("", mci); 230068627Seric mci->mci_flags &= ~MCIF_INHEADER; 230167546Seric } 230268627Seric 230368627Seric /* determine end of buffer; allow for short mailer lines */ 230468627Seric buflim = &buf[sizeof buf - 1]; 230568627Seric if (mci->mci_mailer->m_linelimit > 0 && 230668627Seric mci->mci_mailer->m_linelimit < sizeof buf - 1) 230768627Seric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 230868627Seric 230968627Seric /* copy temp file to output with mapping */ 231068627Seric ostate = OS_HEAD; 231168627Seric bp = buf; 231268627Seric pbp = peekbuf; 231368627Seric while (!ferror(mci->mci_out)) 231468627Seric { 231568627Seric register char *xp; 231668627Seric 231768627Seric if (pbp > peekbuf) 231868627Seric c = *--pbp; 231968627Seric else if ((c = fgetc(e->e_dfp)) == EOF) 232068627Seric break; 232168627Seric if (bitset(MCIF_7BIT, mci->mci_flags)) 232268627Seric c &= 0x7f; 232368627Seric switch (ostate) 232468627Seric { 232568627Seric case OS_HEAD: 232668627Seric if (c != '\r' && c != '\n' && bp < buflim) 232768627Seric { 232868627Seric *bp++ = c; 232968627Seric break; 233068627Seric } 233168627Seric 233268627Seric /* check beginning of line for special cases */ 233368627Seric *bp = '\0'; 233468627Seric pos = 0; 233568627Seric padc = EOF; 233668627Seric if (buf[0] == 'F' && 233768627Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 233868627Seric strncmp(buf, "From ", 5) == 0) 233968627Seric { 234068627Seric padc = '>'; 234168627Seric } 234268627Seric if (buf[0] == '-' && buf[1] == '-' && 234368627Seric separator != NULL) 234468627Seric { 234568627Seric /* possible separator */ 234668627Seric int sl = strlen(separator); 234768627Seric 234868627Seric if (strncmp(&buf[2], separator, sl) == 0) 234968627Seric padc = ' '; 235068627Seric } 235168627Seric if (buf[0] == '.' && 235268627Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 235368627Seric { 235468627Seric padc = '.'; 235568627Seric } 235668627Seric 235768627Seric /* now copy out saved line */ 235868627Seric if (TrafficLogFile != NULL) 235968627Seric { 236068627Seric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 236168627Seric if (padc != EOF) 236268627Seric fputc(padc, TrafficLogFile); 236368627Seric for (xp = buf; xp < bp; xp++) 236468627Seric fputc(*xp, TrafficLogFile); 236568627Seric if (c == '\n') 236668627Seric fputs(mci->mci_mailer->m_eol, 236768627Seric TrafficLogFile); 236868627Seric } 236968627Seric if (padc != EOF) 237068627Seric { 237168627Seric fputc(padc, mci->mci_out); 237268627Seric pos++; 237368627Seric } 237468627Seric for (xp = buf; xp < bp; xp++) 237568627Seric fputc(*xp, mci->mci_out); 237668627Seric if (c == '\n') 237768627Seric { 237868627Seric fputs(mci->mci_mailer->m_eol, 237968627Seric mci->mci_out); 238068627Seric pos = 0; 238168627Seric } 238268627Seric else 238368627Seric { 238468627Seric pos += bp - buf; 238568627Seric if (c != '\r') 238668627Seric *pbp++ = c; 238768627Seric } 238868627Seric bp = buf; 238968627Seric 239068627Seric /* determine next state */ 239168627Seric if (c == '\n') 239268627Seric ostate = OS_HEAD; 239368627Seric else if (c == '\r') 239468627Seric ostate = OS_CR; 239568627Seric else 239668627Seric ostate = OS_INLINE; 239768627Seric continue; 239868627Seric 239968627Seric case OS_CR: 240068627Seric if (c == '\n') 240168627Seric { 240268627Seric /* got CRLF */ 240368627Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 240468627Seric if (TrafficLogFile != NULL) 240568627Seric { 240668627Seric fputs(mci->mci_mailer->m_eol, 240768627Seric TrafficLogFile); 240868627Seric } 240968627Seric ostate = OS_HEAD; 241068627Seric continue; 241168627Seric } 241268627Seric 241368627Seric /* had a naked carriage return */ 241468627Seric *pbp++ = c; 241568627Seric c = '\r'; 241668627Seric goto putch; 241768627Seric 241868627Seric case OS_INLINE: 241968627Seric if (c == '\r') 242068627Seric { 242168627Seric ostate = OS_CR; 242268627Seric continue; 242368627Seric } 242468627Seric putch: 242568627Seric if (mci->mci_mailer->m_linelimit > 0 && 242668627Seric pos > mci->mci_mailer->m_linelimit && 242768627Seric c != '\n') 242868627Seric { 242968627Seric putc('!', mci->mci_out); 243068627Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 243168627Seric if (TrafficLogFile != NULL) 243268627Seric { 243368627Seric fprintf(TrafficLogFile, "!%s", 243468627Seric mci->mci_mailer->m_eol); 243568627Seric } 243668627Seric ostate = OS_HEAD; 243768627Seric *pbp++ = c; 243868627Seric continue; 243968627Seric } 244068627Seric if (TrafficLogFile != NULL) 244168627Seric fputc(c, TrafficLogFile); 244268627Seric putc(c, mci->mci_out); 244368627Seric pos++; 244468627Seric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 244568627Seric break; 244668627Seric } 244768627Seric } 244867599Seric } 24496974Seric 245068627Seric if (ferror(e->e_dfp)) 245168627Seric { 245268627Seric syserr("putbody: df%s: read error", e->e_id); 245368627Seric ExitStat = EX_IOERR; 245468627Seric } 245568627Seric 245668627Seric endofmessage: 245759542Seric /* some mailers want extra blank line at end of message */ 245865870Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 245965870Seric buf[0] != '\0' && buf[0] != '\n') 246065870Seric putline("", mci); 246159542Seric 246265870Seric (void) fflush(mci->mci_out); 246365870Seric if (ferror(mci->mci_out) && errno != EPIPE) 24646974Seric { 24656974Seric syserr("putbody: write error"); 24666974Seric ExitStat = EX_IOERR; 24676974Seric } 24686974Seric errno = 0; 24696974Seric } 24706974Seric /* 2471294Seric ** MAILFILE -- Send a message to a file. 2472294Seric ** 24734327Seric ** If the file has the setuid/setgid bits set, but NO execute 24744327Seric ** bits, sendmail will try to become the owner of that file 24754327Seric ** rather than the real user. Obviously, this only works if 24764327Seric ** sendmail runs as root. 24774327Seric ** 24789370Seric ** This could be done as a subordinate mailer, except that it 24799370Seric ** is used implicitly to save messages in ~/dead.letter. We 24809370Seric ** view this as being sufficiently important as to include it 24819370Seric ** here. For example, if the system is dying, we shouldn't have 24829370Seric ** to create another process plus some pipes to save the message. 24839370Seric ** 2484294Seric ** Parameters: 2485294Seric ** filename -- the name of the file to send to. 24864397Seric ** ctladdr -- the controlling address header -- includes 24874397Seric ** the userid/groupid to be when sending. 2488294Seric ** 2489294Seric ** Returns: 2490294Seric ** The exit code associated with the operation. 2491294Seric ** 2492294Seric ** Side Effects: 2493294Seric ** none. 2494294Seric */ 2495294Seric 249654967Seric mailfile(filename, ctladdr, e) 2497294Seric char *filename; 24984397Seric ADDRESS *ctladdr; 249954967Seric register ENVELOPE *e; 2500294Seric { 2501294Seric register FILE *f; 250268627Seric register int pid = -1; 250353751Seric int mode; 2504294Seric 250559267Seric if (tTd(11, 1)) 250659267Seric { 250759267Seric printf("mailfile %s\n ctladdr=", filename); 250859267Seric printaddr(ctladdr, FALSE); 250959267Seric } 251059267Seric 251163753Seric if (e->e_xfp != NULL) 251263753Seric fflush(e->e_xfp); 251363753Seric 25144214Seric /* 25154214Seric ** Fork so we can change permissions here. 25164214Seric ** Note that we MUST use fork, not vfork, because of 25174214Seric ** the complications of calling subroutines, etc. 25184214Seric */ 25194067Seric 25204214Seric DOFORK(fork); 25214214Seric 25224214Seric if (pid < 0) 25234214Seric return (EX_OSERR); 25244214Seric else if (pid == 0) 25254214Seric { 25264214Seric /* child -- actually write to file */ 25274327Seric struct stat stb; 252868475Seric struct stat fsb; 252965870Seric MCI mcibuf; 253068490Seric int oflags = O_WRONLY|O_APPEND; 25314327Seric 253268475Seric if (e->e_lockfp != NULL) 253368689Seric (void) close(fileno(e->e_lockfp)); 253468475Seric 253564035Seric (void) setsignal(SIGINT, SIG_DFL); 253664035Seric (void) setsignal(SIGHUP, SIG_DFL); 253764035Seric (void) setsignal(SIGTERM, SIG_DFL); 253823102Seric (void) umask(OldUmask); 253952673Seric 254068627Seric #ifdef HASLSTAT 254168627Seric if ((SafeFileEnv != NULL ? lstat(filename, &stb) 254268627Seric : stat(filename, &stb)) < 0) 254368627Seric #else 25444327Seric if (stat(filename, &stb) < 0) 254568627Seric #endif 254668490Seric { 254759745Seric stb.st_mode = FileMode; 254868490Seric oflags |= O_CREAT|O_EXCL; 254968490Seric } 255068627Seric else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || 255168627Seric (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) 255268475Seric exit(EX_CANTCREAT); 255353751Seric mode = stb.st_mode; 255452673Seric 255552673Seric /* limit the errors to those actually caused in the child */ 255652673Seric errno = 0; 255752673Seric ExitStat = EX_OK; 255852673Seric 255964823Seric if (ctladdr != NULL) 256053751Seric { 256153751Seric /* ignore setuid and setgid bits */ 256253751Seric mode &= ~(S_ISGID|S_ISUID); 256353751Seric } 256453751Seric 256540931Srick /* we have to open the dfile BEFORE setuid */ 256668627Seric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 256740931Srick { 256868627Seric char *df = queuename(e, 'd'); 256968627Seric 257068627Seric e->e_dfp = fopen(df, "r"); 257152673Seric if (e->e_dfp == NULL) 257252673Seric { 257340931Srick syserr("mailfile: Cannot open %s for %s from %s", 257468627Seric df, e->e_to, e->e_from.q_paddr); 257540931Srick } 257640931Srick } 257740931Srick 257868627Seric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 257968490Seric { 258068627Seric int i; 258168627Seric 258268627Seric if (chroot(SafeFileEnv) < 0) 258368490Seric { 258468627Seric syserr("mailfile: Cannot chroot(%s)", 258568627Seric SafeFileEnv); 258668627Seric exit(EX_CANTCREAT); 258768490Seric } 258868627Seric i = strlen(SafeFileEnv); 258968627Seric if (strncmp(SafeFileEnv, filename, i) == 0) 259068627Seric filename += i; 259168627Seric } 259268627Seric if (chdir("/") < 0) 259368627Seric syserr("mailfile: cannot chdir(/)"); 259468627Seric 259568627Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 259668627Seric { 259768627Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 259853751Seric (void) initgroups(ctladdr->q_ruser ? 259953751Seric ctladdr->q_ruser : ctladdr->q_user, 260040972Sbostic ctladdr->q_gid); 260168627Seric else if (FileMailer != NULL && FileMailer->m_gid != 0) 260268627Seric (void) initgroups(DefUser, FileMailer->m_gid); 260368627Seric else 260468627Seric (void) initgroups(DefUser, DefGid); 26054417Seric } 260653751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 26074417Seric { 260868627Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 260968627Seric (void) setuid(ctladdr->q_uid); 261068627Seric else if (FileMailer != NULL && FileMailer->m_uid != 0) 261168627Seric (void) setuid(FileMailer->m_uid); 261268627Seric else 261368609Seric (void) setuid(DefUid); 26144417Seric } 261552673Seric FileName = filename; 261652673Seric LineNumber = 0; 261768490Seric f = dfopen(filename, oflags, FileMode); 26184214Seric if (f == NULL) 261952673Seric { 262064387Seric message("554 cannot open: %s", errstring(errno)); 26214214Seric exit(EX_CANTCREAT); 262252673Seric } 262368475Seric if (fstat(fileno(f), &fsb) < 0 || 262468627Seric (!bitset(O_CREAT, oflags) && 262568490Seric (stb.st_nlink != fsb.st_nlink || 262668490Seric stb.st_dev != fsb.st_dev || 262768490Seric stb.st_ino != fsb.st_ino || 262868627Seric stb.st_uid != fsb.st_uid))) 262968475Seric { 263068475Seric message("554 cannot write: file changed after open"); 263168475Seric exit(EX_CANTCREAT); 263268475Seric } 26334214Seric 263465870Seric bzero(&mcibuf, sizeof mcibuf); 263565870Seric mcibuf.mci_mailer = FileMailer; 263665870Seric mcibuf.mci_out = f; 263765870Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 263865870Seric mcibuf.mci_flags |= MCIF_7BIT; 263965870Seric 264065870Seric putfromline(&mcibuf, e); 264168627Seric (*e->e_puthdr)(&mcibuf, e->e_header, e); 264268228Seric (*e->e_putbody)(&mcibuf, e, NULL); 264365870Seric putline("\n", &mcibuf); 264452673Seric if (ferror(f)) 264552673Seric { 264664387Seric message("451 I/O error: %s", errstring(errno)); 264752673Seric setstat(EX_IOERR); 264852673Seric } 264958680Seric (void) xfclose(f, "mailfile", filename); 26504214Seric (void) fflush(stdout); 26514417Seric 26526887Seric /* reset ISUID & ISGID bits for paranoid systems */ 26534621Seric (void) chmod(filename, (int) stb.st_mode); 265452673Seric exit(ExitStat); 26554315Seric /*NOTREACHED*/ 26564214Seric } 26574214Seric else 26584214Seric { 26594214Seric /* parent -- wait for exit status */ 26609370Seric int st; 26614214Seric 26629370Seric st = waitfor(pid); 266364379Seric if (WIFEXITED(st)) 266464379Seric return (WEXITSTATUS(st)); 266564379Seric else 266664387Seric { 266764387Seric syserr("child died on signal %d", st); 26689370Seric return (EX_UNAVAILABLE); 266964387Seric } 267040931Srick /*NOTREACHED*/ 26714214Seric } 2672294Seric } 26734550Seric /* 267457454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 267557454Seric ** 267657454Seric ** The signature describes how we are going to send this -- it 267757454Seric ** can be just the hostname (for non-Internet hosts) or can be 267857454Seric ** an ordered list of MX hosts. 267957454Seric ** 268057454Seric ** Parameters: 268157454Seric ** m -- the mailer describing this host. 268257454Seric ** host -- the host name. 268357454Seric ** e -- the current envelope. 268457454Seric ** 268557454Seric ** Returns: 268657454Seric ** The signature for this host. 268757454Seric ** 268857454Seric ** Side Effects: 268957454Seric ** Can tweak the symbol table. 269057454Seric */ 269157454Seric 269257454Seric char * 269357454Seric hostsignature(m, host, e) 269457454Seric register MAILER *m; 269557454Seric char *host; 269657454Seric ENVELOPE *e; 269757454Seric { 269857454Seric register char *p; 269957454Seric register STAB *s; 270057454Seric int i; 270157454Seric int len; 270266334Seric #if NAMED_BIND 270357454Seric int nmx; 270457454Seric auto int rcode; 270559076Seric char *hp; 270659076Seric char *endp; 270768627Seric int oldoptions = _res.options; 270857454Seric char *mxhosts[MAXMXHOSTS + 1]; 270957454Seric #endif 271057454Seric 271157454Seric /* 271257454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 271357454Seric */ 271457454Seric 271557454Seric p = m->m_mailer; 271657454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 271757454Seric { 271857454Seric /* just an ordinary mailer */ 271957454Seric return host; 272057454Seric } 272157454Seric 272257454Seric /* 272357454Seric ** Look it up in the symbol table. 272457454Seric */ 272557454Seric 272657454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 272757454Seric if (s->s_hostsig != NULL) 272857454Seric return s->s_hostsig; 272957454Seric 273057454Seric /* 273157454Seric ** Not already there -- create a signature. 273257454Seric */ 273357454Seric 273466334Seric #if NAMED_BIND 273559111Seric if (ConfigLevel < 2) 273659111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 273759111Seric 273859076Seric for (hp = host; hp != NULL; hp = endp) 273957454Seric { 274059076Seric endp = strchr(hp, ':'); 274159076Seric if (endp != NULL) 274259076Seric *endp = '\0'; 274357454Seric 274459273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 274557454Seric 274659076Seric if (nmx <= 0) 274759076Seric { 274859076Seric register MCI *mci; 274957454Seric 275059076Seric /* update the connection info for this host */ 275159076Seric mci = mci_get(hp, m); 275259076Seric mci->mci_exitstat = rcode; 275359076Seric mci->mci_errno = errno; 275463753Seric mci->mci_herrno = h_errno; 275559076Seric 275659076Seric /* and return the original host name as the signature */ 275759076Seric nmx = 1; 275859076Seric mxhosts[0] = hp; 275959076Seric } 276059076Seric 276159076Seric len = 0; 276259076Seric for (i = 0; i < nmx; i++) 276359076Seric { 276459076Seric len += strlen(mxhosts[i]) + 1; 276559076Seric } 276659076Seric if (s->s_hostsig != NULL) 276759076Seric len += strlen(s->s_hostsig) + 1; 276859076Seric p = xalloc(len); 276959076Seric if (s->s_hostsig != NULL) 277059076Seric { 277159076Seric (void) strcpy(p, s->s_hostsig); 277259076Seric free(s->s_hostsig); 277359076Seric s->s_hostsig = p; 277459076Seric p += strlen(p); 277557454Seric *p++ = ':'; 277659076Seric } 277759076Seric else 277859076Seric s->s_hostsig = p; 277959076Seric for (i = 0; i < nmx; i++) 278059076Seric { 278159076Seric if (i != 0) 278259076Seric *p++ = ':'; 278359076Seric strcpy(p, mxhosts[i]); 278459076Seric p += strlen(p); 278559076Seric } 278659076Seric if (endp != NULL) 278759076Seric *endp++ = ':'; 278857454Seric } 278957454Seric makelower(s->s_hostsig); 279059111Seric if (ConfigLevel < 2) 279159111Seric _res.options = oldoptions; 279257454Seric #else 279357454Seric /* not using BIND -- the signature is just the host name */ 279457454Seric s->s_hostsig = host; 279557454Seric #endif 279657454Seric if (tTd(17, 1)) 279757454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 279857454Seric return s->s_hostsig; 279957454Seric } 280068627Seric /* 280168627Seric ** SETSTATUS -- set the address status for return messages 280268627Seric ** 280368627Seric ** Parameters: 280468627Seric ** a -- the address to set. 280568627Seric ** msg -- the text of the message, which must be in standard 280668627Seric ** SMTP form (3 digits, a space, and a message). 280768627Seric ** 280868627Seric ** Returns: 280968627Seric ** none. 281068627Seric */ 281168627Seric 281268627Seric setstatus(a, msg) 281368627Seric register ADDRESS *a; 281468627Seric char *msg; 281568627Seric { 281668627Seric char buf[MAXLINE]; 281768627Seric 281868627Seric if (a->q_rstatus != NULL) 281968627Seric free(a->q_rstatus); 2820*68706Seric if (strlen(msg) > (SIZE_T) 4) 282168627Seric { 282268627Seric register char *p, *q; 282368627Seric int parenlev = 0; 282468627Seric 282568627Seric strncpy(buf, msg, 4); 282668627Seric p = &buf[4]; 282768627Seric *p++ = '('; 282868627Seric for (q = &msg[4]; *q != '\0'; q++) 282968627Seric { 283068627Seric switch (*q) 283168627Seric { 283268627Seric case '(': 283368627Seric parenlev++; 283468627Seric break; 283568627Seric 283668627Seric case ')': 283768627Seric if (parenlev > 0) 283868627Seric parenlev--; 283968627Seric else 284068627Seric *p++ = '\\'; 284168627Seric break; 284268627Seric } 284368627Seric *p++ = *q; 284468627Seric } 284568627Seric while (parenlev-- >= 0) 284668627Seric *p++ = ')'; 284768627Seric *p++ = '\0'; 284868627Seric msg = buf; 284968627Seric } 285068627Seric a->q_rstatus = newstr(msg); 285168627Seric } 2852