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*66089Seric static char sccsid[] = "@(#)deliver.c 8.73 (Berkeley) 02/14/94"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1433931Sbostic #include <netdb.h> 1533931Sbostic #include <errno.h> 1635651Seric #ifdef NAMED_BIND 1734022Sbostic #include <arpa/nameser.h> 1834022Sbostic #include <resolv.h> 1963753Seric 2063753Seric extern int h_errno; 2135651Seric #endif 22294Seric 2365075Seric extern char SmtpError[]; 2465075Seric 25294Seric /* 2658820Seric ** SENDALL -- actually send all the messages. 2758820Seric ** 2858820Seric ** Parameters: 2958820Seric ** e -- the envelope to send. 3058820Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 3158820Seric ** the current e->e_sendmode. 3258820Seric ** 3358820Seric ** Returns: 3458820Seric ** none. 3558820Seric ** 3658820Seric ** Side Effects: 3758820Seric ** Scans the send lists and sends everything it finds. 3858820Seric ** Delivers any appropriate error messages. 3958820Seric ** If we are running in a non-interactive mode, takes the 4058820Seric ** appropriate action. 4158820Seric */ 4258820Seric 4358820Seric sendall(e, mode) 4458820Seric ENVELOPE *e; 4558820Seric char mode; 4658820Seric { 4758820Seric register ADDRESS *q; 4858820Seric char *owner; 4958820Seric int otherowners; 5066009Seric register ENVELOPE *ee; 5166009Seric ENVELOPE *splitenv = NULL; 5258929Seric bool announcequeueup; 5358820Seric 5463839Seric /* 5563839Seric ** If we have had global, fatal errors, don't bother sending 5663839Seric ** the message at all if we are in SMTP mode. Local errors 5763839Seric ** (e.g., a single address failing) will still cause the other 5863839Seric ** addresses to be sent. 5963839Seric */ 6063839Seric 6165580Seric if (bitset(EF_FATALERRS, e->e_flags) && 6265580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 6361092Seric { 6461092Seric e->e_flags |= EF_CLRQUEUE; 6561092Seric return; 6661092Seric } 6761092Seric 6858820Seric /* determine actual delivery mode */ 6964826Seric CurrentLA = getla(); 7058820Seric if (mode == SM_DEFAULT) 7158820Seric { 7258820Seric mode = e->e_sendmode; 7358820Seric if (mode != SM_VERIFY && 7458820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 7558820Seric mode = SM_QUEUE; 7658929Seric announcequeueup = mode == SM_QUEUE; 7758820Seric } 7858929Seric else 7958929Seric announcequeueup = FALSE; 8058820Seric 8158820Seric if (tTd(13, 1)) 8258820Seric { 8364310Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 8464310Seric mode, e->e_id); 8558820Seric printaddr(&e->e_from, FALSE); 8658820Seric printf("sendqueue:\n"); 8758820Seric printaddr(e->e_sendqueue, TRUE); 8858820Seric } 8958820Seric 9058820Seric /* 9158820Seric ** Do any preprocessing necessary for the mode we are running. 9258820Seric ** Check to make sure the hop count is reasonable. 9358820Seric ** Delete sends to the sender in mailing lists. 9458820Seric */ 9558820Seric 9658820Seric CurEnv = e; 9758820Seric 9858820Seric if (e->e_hopcount > MaxHopCount) 9958820Seric { 10058820Seric errno = 0; 10164495Seric syserr("554 too many hops %d (%d max): from %s via %s, to %s", 10258820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 10366003Seric RealHostName == NULL ? "localhost" : RealHostName, 10466003Seric e->e_sendqueue->q_paddr); 10558820Seric return; 10658820Seric } 10758820Seric 10859435Seric /* 10959435Seric ** Do sender deletion. 11059435Seric ** 11159435Seric ** If the sender has the QQUEUEUP flag set, skip this. 11259435Seric ** This can happen if the name server is hosed when you 11359435Seric ** are trying to send mail. The result is that the sender 11459435Seric ** is instantiated in the queue as a recipient. 11559435Seric */ 11659435Seric 11764118Seric if (!bitset(EF_METOO, e->e_flags) && 11864118Seric !bitset(QQUEUEUP, e->e_from.q_flags)) 11958820Seric { 12058820Seric if (tTd(13, 5)) 12158820Seric { 12258820Seric printf("sendall: QDONTSEND "); 12358820Seric printaddr(&e->e_from, FALSE); 12458820Seric } 12558820Seric e->e_from.q_flags |= QDONTSEND; 12658820Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 12758820Seric } 12858820Seric 12958820Seric /* 13058820Seric ** Handle alias owners. 13158820Seric ** 13258820Seric ** We scan up the q_alias chain looking for owners. 13358820Seric ** We discard owners that are the same as the return path. 13458820Seric */ 13558820Seric 13658820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13758820Seric { 13858820Seric register struct address *a; 13958820Seric 14058820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 14158820Seric continue; 14258820Seric if (a != NULL) 14358820Seric q->q_owner = a->q_owner; 14458820Seric 14558820Seric if (q->q_owner != NULL && 14658820Seric !bitset(QDONTSEND, q->q_flags) && 14758820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 14858820Seric q->q_owner = NULL; 14958820Seric } 15058820Seric 15158820Seric owner = ""; 15258820Seric otherowners = 1; 15358820Seric while (owner != NULL && otherowners > 0) 15458820Seric { 15558820Seric owner = NULL; 15658820Seric otherowners = 0; 15758820Seric 15858820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15958820Seric { 16058820Seric if (bitset(QDONTSEND, q->q_flags)) 16158820Seric continue; 16258820Seric 16358820Seric if (q->q_owner != NULL) 16458820Seric { 16558820Seric if (owner == NULL) 16658820Seric owner = q->q_owner; 16758820Seric else if (owner != q->q_owner) 16858820Seric { 16958820Seric if (strcmp(owner, q->q_owner) == 0) 17058820Seric { 17158820Seric /* make future comparisons cheap */ 17258820Seric q->q_owner = owner; 17358820Seric } 17458820Seric else 17558820Seric { 17658820Seric otherowners++; 17758820Seric } 17858820Seric owner = q->q_owner; 17958820Seric } 18058820Seric } 18158820Seric else 18258820Seric { 18358820Seric otherowners++; 18458820Seric } 18558820Seric } 18658820Seric 18758820Seric if (owner != NULL && otherowners > 0) 18858820Seric { 18958820Seric extern HDR *copyheader(); 19058820Seric extern ADDRESS *copyqueue(); 19158820Seric 19258820Seric /* 19358820Seric ** Split this envelope into two. 19458820Seric */ 19558820Seric 19658820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 19758820Seric *ee = *e; 19858820Seric ee->e_id = NULL; 19958820Seric (void) queuename(ee, '\0'); 20058820Seric 20158820Seric if (tTd(13, 1)) 20258820Seric printf("sendall: split %s into %s\n", 20358820Seric e->e_id, ee->e_id); 20458820Seric 20558820Seric ee->e_header = copyheader(e->e_header); 20658820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 20758820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 20858916Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); 20958820Seric setsender(owner, ee, NULL, TRUE); 21058820Seric if (tTd(13, 5)) 21158820Seric { 21258820Seric printf("sendall(split): QDONTSEND "); 21358820Seric printaddr(&ee->e_from, FALSE); 21458820Seric } 21558820Seric ee->e_from.q_flags |= QDONTSEND; 21658820Seric ee->e_dfp = NULL; 21758820Seric ee->e_xfp = NULL; 21858820Seric ee->e_df = NULL; 21958820Seric ee->e_errormode = EM_MAIL; 22066009Seric ee->e_sibling = splitenv; 22166009Seric splitenv = ee; 22258820Seric 22358820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 22458820Seric if (q->q_owner == owner) 22558820Seric q->q_flags |= QDONTSEND; 22658820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 22758820Seric if (q->q_owner != owner) 22858820Seric q->q_flags |= QDONTSEND; 22958820Seric 23058820Seric if (e->e_df != NULL && mode != SM_VERIFY) 23158820Seric { 23258820Seric ee->e_dfp = NULL; 23364086Seric ee->e_df = queuename(ee, 'd'); 23464086Seric ee->e_df = newstr(ee->e_df); 23558820Seric if (link(e->e_df, ee->e_df) < 0) 23658820Seric { 23758820Seric syserr("sendall: link(%s, %s)", 23858820Seric e->e_df, ee->e_df); 23958820Seric } 24058820Seric } 24158820Seric #ifdef LOG 24258820Seric if (LogLevel > 4) 24366012Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 24466012Seric ee->e_id, e->e_id, owner); 24558820Seric #endif 24658820Seric } 24758820Seric } 24858820Seric 24958820Seric if (owner != NULL) 25058820Seric { 25158820Seric setsender(owner, e, NULL, TRUE); 25258820Seric if (tTd(13, 5)) 25358820Seric { 25458820Seric printf("sendall(owner): QDONTSEND "); 25558820Seric printaddr(&e->e_from, FALSE); 25658820Seric } 25758820Seric e->e_from.q_flags |= QDONTSEND; 25858820Seric e->e_errormode = EM_MAIL; 25958820Seric } 26058820Seric 26166009Seric # ifdef QUEUE 26266009Seric if ((mode == SM_QUEUE || mode == SM_FORK || 26366009Seric (mode != SM_VERIFY && SuperSafe)) && 26466009Seric !bitset(EF_INQUEUE, e->e_flags)) 26558916Seric { 26666009Seric /* be sure everything is instantiated in the queue */ 26766009Seric queueup(e, TRUE, announcequeueup); 26866009Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 26966009Seric queueup(ee, TRUE, announcequeueup); 27058916Seric } 27166009Seric #endif /* QUEUE */ 27258916Seric 27366009Seric if (splitenv != NULL) 27466009Seric { 27566009Seric if (tTd(13, 1)) 27666009Seric { 27766009Seric printf("\nsendall: Split queue; remaining queue:\n"); 27866009Seric printaddr(e->e_sendqueue, TRUE); 27966009Seric } 28066009Seric 28166009Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 28266009Seric { 28366009Seric CurEnv = ee; 28466010Seric if (mode != SM_VERIFY) 28566010Seric openxscript(ee); 28666009Seric sendenvelope(ee, mode); 28766010Seric dropenvelope(ee); 28866009Seric } 28966009Seric 29066009Seric CurEnv = e; 29166009Seric } 29266009Seric sendenvelope(e, mode); 29358820Seric } 29458820Seric 29566009Seric sendenvelope(e, mode) 29658820Seric register ENVELOPE *e; 29758820Seric char mode; 29858820Seric { 29958916Seric bool oldverbose; 30058916Seric int pid; 30158820Seric register ADDRESS *q; 30264296Seric char *qf; 30364296Seric char *id; 30458820Seric 30563839Seric /* 30663839Seric ** If we have had global, fatal errors, don't bother sending 30763839Seric ** the message at all if we are in SMTP mode. Local errors 30863839Seric ** (e.g., a single address failing) will still cause the other 30963839Seric ** addresses to be sent. 31063839Seric */ 31163839Seric 31265580Seric if (bitset(EF_FATALERRS, e->e_flags) && 31365580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 31463839Seric { 31563839Seric e->e_flags |= EF_CLRQUEUE; 31663839Seric return; 31763839Seric } 31863839Seric 31958916Seric oldverbose = Verbose; 32058916Seric switch (mode) 32158916Seric { 32258916Seric case SM_VERIFY: 32358916Seric Verbose = TRUE; 32458916Seric break; 32558916Seric 32658916Seric case SM_QUEUE: 32758916Seric queueonly: 32858916Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 32958916Seric return; 33058916Seric 33158916Seric case SM_FORK: 33258916Seric if (e->e_xfp != NULL) 33358916Seric (void) fflush(e->e_xfp); 33458916Seric 33565830Seric # if !HASFLOCK 33658916Seric /* 33764296Seric ** Since fcntl locking has the interesting semantic that 33864296Seric ** the lock is owned by a process, not by an open file 33964296Seric ** descriptor, we have to flush this to the queue, and 34064296Seric ** then restart from scratch in the child. 34158916Seric */ 34258916Seric 34364296Seric /* save id for future use */ 34464296Seric id = e->e_id; 34558916Seric 34664296Seric /* now drop the envelope in the parent */ 34764296Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 34864296Seric dropenvelope(e); 34964296Seric 35064296Seric /* and reacquire in the child */ 35164296Seric (void) dowork(id, TRUE, FALSE, e); 35264296Seric 35364296Seric return; 35464296Seric 35564296Seric # else /* HASFLOCK */ 35664296Seric 35758916Seric pid = fork(); 35858916Seric if (pid < 0) 35958916Seric { 36058916Seric goto queueonly; 36158916Seric } 36258916Seric else if (pid > 0) 36358916Seric { 36464310Seric /* be sure we leave the temp files to our child */ 36564310Seric /* can't call unlockqueue to avoid unlink of xfp */ 36664310Seric if (e->e_lockfp != NULL) 36764310Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 36864310Seric e->e_lockfp = NULL; 36964310Seric 37064310Seric /* close any random open files in the envelope */ 37164310Seric closexscript(e); 37264310Seric if (e->e_dfp != NULL) 37364310Seric (void) xfclose(e->e_dfp, "sendenvelope", e->e_df); 37464310Seric e->e_dfp = NULL; 37564310Seric e->e_id = e->e_df = NULL; 37666017Seric 37766017Seric /* catch intermediate zombie */ 37866017Seric (void) waitfor(pid); 37958916Seric return; 38058916Seric } 38158916Seric 38258916Seric /* double fork to avoid zombies */ 38366017Seric pid = fork(); 38466017Seric if (pid > 0) 38558916Seric exit(EX_OK); 38658916Seric 38758916Seric /* be sure we are immune from the terminal */ 38863839Seric disconnect(1, e); 38958916Seric 39066017Seric /* prevent parent from waiting if there was an error */ 39166017Seric if (pid < 0) 39266017Seric { 39366017Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 39466017Seric finis(); 39566017Seric } 39666017Seric 39758916Seric /* 39858916Seric ** Close any cached connections. 39958916Seric ** 40058916Seric ** We don't send the QUIT protocol because the parent 40158916Seric ** still knows about the connection. 40258916Seric ** 40358916Seric ** This should only happen when delivering an error 40458916Seric ** message. 40558916Seric */ 40658916Seric 40758916Seric mci_flush(FALSE, NULL); 40858916Seric 40964296Seric # endif /* HASFLOCK */ 41064296Seric 41158916Seric break; 41258916Seric } 41358916Seric 41458820Seric /* 41558820Seric ** Run through the list and send everything. 41663965Seric ** 41763965Seric ** Set EF_GLOBALERRS so that error messages during delivery 41863965Seric ** result in returned mail. 41958820Seric */ 42058820Seric 42158820Seric e->e_nsent = 0; 42263965Seric e->e_flags |= EF_GLOBALERRS; 42364696Seric 42464696Seric /* now run through the queue */ 42558820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 42658820Seric { 42764441Seric #ifdef XDEBUG 42864441Seric char wbuf[MAXNAME + 20]; 42964441Seric 43064441Seric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 43164441Seric checkfd012(wbuf); 43264441Seric #endif 43358820Seric if (mode == SM_VERIFY) 43458820Seric { 43558820Seric e->e_to = q->q_paddr; 43658820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 43760173Seric { 43864942Seric if (q->q_host != NULL && q->q_host[0] != '\0') 43964942Seric message("deliverable: mailer %s, host %s, user %s", 44064942Seric q->q_mailer->m_name, 44164942Seric q->q_host, 44264942Seric q->q_user); 44364942Seric else 44464942Seric message("deliverable: mailer %s, user %s", 44564942Seric q->q_mailer->m_name, 44664942Seric q->q_user); 44760173Seric } 44858820Seric } 44958820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 45058820Seric { 45158820Seric # ifdef QUEUE 45258820Seric /* 45358820Seric ** Checkpoint the send list every few addresses 45458820Seric */ 45558820Seric 45658820Seric if (e->e_nsent >= CheckpointInterval) 45758820Seric { 45858820Seric queueup(e, TRUE, FALSE); 45958820Seric e->e_nsent = 0; 46058820Seric } 46158820Seric # endif /* QUEUE */ 46258820Seric (void) deliver(e, q); 46358820Seric } 46458820Seric } 46558820Seric Verbose = oldverbose; 46658820Seric 46764441Seric #ifdef XDEBUG 46864441Seric checkfd012("end of sendenvelope"); 46964441Seric #endif 47064441Seric 47158820Seric if (mode == SM_FORK) 47258820Seric finis(); 47358820Seric } 47458820Seric /* 47558820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 47658820Seric ** 47758820Seric ** This MUST be a macro, since after a vfork we are running 47858820Seric ** two processes on the same stack!!! 47958820Seric ** 48058820Seric ** Parameters: 48158820Seric ** none. 48258820Seric ** 48358820Seric ** Returns: 48458820Seric ** From a macro??? You've got to be kidding! 48558820Seric ** 48658820Seric ** Side Effects: 48758820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 48858820Seric ** pid of child in parent, zero in child. 48958820Seric ** -1 on unrecoverable error. 49058820Seric ** 49158820Seric ** Notes: 49258820Seric ** I'm awfully sorry this looks so awful. That's 49358820Seric ** vfork for you..... 49458820Seric */ 49558820Seric 49658820Seric # define NFORKTRIES 5 49758820Seric 49858820Seric # ifndef FORK 49958820Seric # define FORK fork 50058820Seric # endif 50158820Seric 50258820Seric # define DOFORK(fORKfN) \ 50358820Seric {\ 50458820Seric register int i;\ 50558820Seric \ 50658820Seric for (i = NFORKTRIES; --i >= 0; )\ 50758820Seric {\ 50858820Seric pid = fORKfN();\ 50958820Seric if (pid >= 0)\ 51058820Seric break;\ 51158820Seric if (i > 0)\ 51258820Seric sleep((unsigned) NFORKTRIES - i);\ 51358820Seric }\ 51458820Seric } 51558820Seric /* 51658820Seric ** DOFORK -- simple fork interface to DOFORK. 51758820Seric ** 51858820Seric ** Parameters: 51958820Seric ** none. 52058820Seric ** 52158820Seric ** Returns: 52258820Seric ** pid of child in parent. 52358820Seric ** zero in child. 52458820Seric ** -1 on error. 52558820Seric ** 52658820Seric ** Side Effects: 52758820Seric ** returns twice, once in parent and once in child. 52858820Seric */ 52958820Seric 53058820Seric dofork() 53158820Seric { 53258820Seric register int pid; 53358820Seric 53458820Seric DOFORK(fork); 53558820Seric return (pid); 53658820Seric } 53758820Seric /* 5384315Seric ** DELIVER -- Deliver a message to a list of addresses. 539294Seric ** 5404315Seric ** This routine delivers to everyone on the same host as the 5414315Seric ** user on the head of the list. It is clever about mailers 5424315Seric ** that don't handle multiple users. It is NOT guaranteed 5434315Seric ** that it will deliver to all these addresses however -- so 5444315Seric ** deliver should be called once for each address on the 5454315Seric ** list. 5464315Seric ** 547294Seric ** Parameters: 5489370Seric ** e -- the envelope to deliver. 5494621Seric ** firstto -- head of the address list to deliver to. 550294Seric ** 551294Seric ** Returns: 552294Seric ** zero -- successfully delivered. 553294Seric ** else -- some failure, see ExitStat for more info. 554294Seric ** 555294Seric ** Side Effects: 556294Seric ** The standard input is passed off to someone. 557294Seric */ 558294Seric 5599370Seric deliver(e, firstto) 5609370Seric register ENVELOPE *e; 5614621Seric ADDRESS *firstto; 562294Seric { 5634452Seric char *host; /* host being sent to */ 5644452Seric char *user; /* user being sent to */ 565294Seric char **pvp; 5663233Seric register char **mvp; 5673233Seric register char *p; 56810306Seric register MAILER *m; /* mailer for this recipient */ 5694397Seric ADDRESS *ctladdr; 57054967Seric register MCI *mci; 5714621Seric register ADDRESS *to = firstto; 5724863Seric bool clever = FALSE; /* running user smtp to this mailer */ 5735032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 57451951Seric int rcode; /* response code */ 57557454Seric char *firstsig; /* signature of firstto */ 57658820Seric int pid; 57758820Seric char *curhost; 57858820Seric int mpvect[2]; 57958820Seric int rpvect[2]; 58010306Seric char *pv[MAXPV+1]; 58158704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 58210306Seric char buf[MAXNAME]; 58351951Seric char rpathbuf[MAXNAME]; /* translated return path */ 58457441Seric extern int checkcompat(); 585294Seric 5864488Seric errno = 0; 58758680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 5883233Seric return (0); 589294Seric 59035651Seric #ifdef NAMED_BIND 59134022Sbostic /* unless interactive, try twice, over a minute */ 59265580Seric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 59365580Seric { 59434022Sbostic _res.retrans = 30; 59534022Sbostic _res.retry = 2; 59634022Sbostic } 59736788Sbostic #endif 59834022Sbostic 5996974Seric m = to->q_mailer; 6006974Seric host = to->q_host; 60158803Seric CurEnv = e; /* just in case */ 60259044Seric e->e_statmsg = NULL; 60364718Seric SmtpError[0] = '\0'; 6046974Seric 6057672Seric if (tTd(10, 1)) 60666010Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 60766010Seric e->e_id, m->m_name, host, to->q_user); 60864725Seric if (tTd(10, 100)) 60964725Seric printopenfds(FALSE); 610294Seric 611294Seric /* 6125903Seric ** If this mailer is expensive, and if we don't want to make 6135903Seric ** connections now, just mark these addresses and return. 6145903Seric ** This is useful if we want to batch connections to 6155903Seric ** reduce load. This will cause the messages to be 6165903Seric ** queued up, and a daemon will come along to send the 6175903Seric ** messages later. 6185903Seric ** This should be on a per-mailer basis. 6195903Seric */ 6205903Seric 62164658Seric if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 6225903Seric { 6235903Seric for (; to != NULL; to = to->q_next) 6248431Seric { 62558680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 62658247Seric to->q_mailer != m) 6278431Seric continue; 62863853Seric to->q_flags |= QQUEUEUP; 6299370Seric e->e_to = to->q_paddr; 63058151Seric message("queued"); 63158020Seric if (LogLevel > 8) 63264771Seric logdelivery(m, NULL, "queued", NULL, e); 6338431Seric } 6349370Seric e->e_to = NULL; 6355903Seric return (0); 6365903Seric } 6375903Seric 6385903Seric /* 6393233Seric ** Do initial argv setup. 6403233Seric ** Insert the mailer name. Notice that $x expansion is 6413233Seric ** NOT done on the mailer name. Then, if the mailer has 6423233Seric ** a picky -f flag, we insert it as appropriate. This 6433233Seric ** code does not check for 'pv' overflow; this places a 6443233Seric ** manifest lower limit of 4 for MAXPV. 6458062Seric ** The from address rewrite is expected to make 6468062Seric ** the address relative to the other end. 6472968Seric */ 6482968Seric 6494452Seric /* rewrite from address, using rewriting rules */ 65059163Seric rcode = EX_OK; 65159163Seric (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, 65259163Seric RF_SENDERADDR|RF_CANONICAL, 65359163Seric &rcode, e)); 65458680Seric define('g', rpathbuf, e); /* translated return path */ 6559370Seric define('h', host, e); /* to host */ 6563233Seric Errors = 0; 6573233Seric pvp = pv; 6583233Seric *pvp++ = m->m_argv[0]; 6592968Seric 6603233Seric /* insert -f or -r flag as appropriate */ 66110682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6623233Seric { 66310682Seric if (bitnset(M_FOPT, m->m_flags)) 6643233Seric *pvp++ = "-f"; 6653233Seric else 6663233Seric *pvp++ = "-r"; 66751951Seric *pvp++ = newstr(rpathbuf); 6683233Seric } 669294Seric 670294Seric /* 6713233Seric ** Append the other fixed parts of the argv. These run 6723233Seric ** up to the first entry containing "$u". There can only 6733233Seric ** be one of these, and there are only a few more slots 6743233Seric ** in the pv after it. 675294Seric */ 676294Seric 6773233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 678294Seric { 67958050Seric /* can't use strchr here because of sign extension problems */ 68058050Seric while (*p != '\0') 68158050Seric { 68258050Seric if ((*p++ & 0377) == MACROEXPAND) 68358050Seric { 68458050Seric if (*p == 'u') 68558050Seric break; 68658050Seric } 68758050Seric } 68858050Seric 68958050Seric if (*p != '\0') 6903233Seric break; 6913233Seric 6923233Seric /* this entry is safe -- go ahead and process it */ 6939370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 6943233Seric *pvp++ = newstr(buf); 6953233Seric if (pvp >= &pv[MAXPV - 3]) 6963233Seric { 69758151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 6983233Seric return (-1); 6993233Seric } 700294Seric } 7014863Seric 7026038Seric /* 7036038Seric ** If we have no substitution for the user name in the argument 7046038Seric ** list, we know that we must supply the names otherwise -- and 7056038Seric ** SMTP is the answer!! 7066038Seric */ 7076038Seric 7083233Seric if (*mvp == NULL) 7094863Seric { 7104863Seric /* running SMTP */ 7115179Seric # ifdef SMTP 7124863Seric clever = TRUE; 7134863Seric *pvp = NULL; 71456795Seric # else /* SMTP */ 7156038Seric /* oops! we don't implement SMTP */ 71664718Seric syserr("554 SMTP style mailer not implemented"); 7175179Seric return (EX_SOFTWARE); 71856795Seric # endif /* SMTP */ 7194863Seric } 720294Seric 721294Seric /* 7223233Seric ** At this point *mvp points to the argument with $u. We 7233233Seric ** run through our address list and append all the addresses 7243233Seric ** we can. If we run out of space, do not fret! We can 7253233Seric ** always send another copy later. 726294Seric */ 727294Seric 7283233Seric tobuf[0] = '\0'; 7299370Seric e->e_to = tobuf; 7304397Seric ctladdr = NULL; 73157454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7323233Seric for (; to != NULL; to = to->q_next) 733294Seric { 7343233Seric /* avoid sending multiple recipients to dumb mailers */ 73510682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7363233Seric break; 7373233Seric 7383233Seric /* if already sent or not for this host, don't send */ 73958680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 74057454Seric to->q_mailer != firstto->q_mailer || 74157454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7423233Seric continue; 7434397Seric 7448225Seric /* avoid overflowing tobuf */ 74542462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7468225Seric break; 7478225Seric 7487672Seric if (tTd(10, 1)) 7495032Seric { 7505032Seric printf("\nsend to "); 7515032Seric printaddr(to, FALSE); 7525032Seric } 7535032Seric 7544397Seric /* compute effective uid/gid when sending */ 75565137Seric /* XXX perhaps this should be to->q_mailer != LocalMailer ?? */ 75665137Seric /* XXX perhaps it should be a mailer flag? */ 75765137Seric if (to->q_mailer == ProgMailer || to->q_mailer == FileMailer) 75865137Seric ctladdr = getctladdr(to); 7594397Seric 7603233Seric user = to->q_user; 7619370Seric e->e_to = to->q_paddr; 76257731Seric if (tTd(10, 5)) 76357731Seric { 76457731Seric printf("deliver: QDONTSEND "); 76557731Seric printaddr(to, FALSE); 76657731Seric } 76758680Seric to->q_flags |= QDONTSEND; 7683233Seric 7693233Seric /* 7703233Seric ** Check to see that these people are allowed to 7713233Seric ** talk to each other. 7723233Seric */ 7733233Seric 77410699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 77510699Seric { 77629914Seric NoReturn = TRUE; 77758151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 77864771Seric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e); 77910699Seric continue; 78010699Seric } 78157441Seric rcode = checkcompat(to, e); 78257459Seric if (rcode != EX_OK) 783294Seric { 78463787Seric markfailure(e, to, rcode); 78564771Seric giveresponse(rcode, m, NULL, ctladdr, e); 7863233Seric continue; 787294Seric } 7883233Seric 7893233Seric /* 7904099Seric ** Strip quote bits from names if the mailer is dumb 7914099Seric ** about them. 7923233Seric */ 7933233Seric 79410682Seric if (bitnset(M_STRIPQ, m->m_flags)) 795294Seric { 79654983Seric stripquotes(user); 79754983Seric stripquotes(host); 7983233Seric } 7993233Seric 8009206Seric /* hack attack -- delivermail compatibility */ 8019206Seric if (m == ProgMailer && *user == '|') 8029206Seric user++; 8039206Seric 8043233Seric /* 8054161Seric ** If an error message has already been given, don't 8064161Seric ** bother to send to this address. 8074161Seric ** 8084161Seric ** >>>>>>>>>> This clause assumes that the local mailer 8094161Seric ** >> NOTE >> cannot do any further aliasing; that 8104161Seric ** >>>>>>>>>> function is subsumed by sendmail. 8114161Seric */ 8124161Seric 8137293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8144161Seric continue; 8154161Seric 8164283Seric /* save statistics.... */ 8179370Seric markstats(e, to); 8184283Seric 8194161Seric /* 8203233Seric ** See if this user name is "special". 8213233Seric ** If the user name has a slash in it, assume that this 8226974Seric ** is a file -- send it off without further ado. Note 8236974Seric ** that this type of addresses is not processed along 8246974Seric ** with the others, so we fudge on the To person. 8253233Seric */ 8263233Seric 82757402Seric if (m == FileMailer) 8283233Seric { 82965060Seric rcode = mailfile(user, ctladdr, e); 83065060Seric giveresponse(rcode, m, NULL, ctladdr, e); 83157402Seric if (rcode == EX_OK) 83257402Seric to->q_flags |= QSENT; 83357402Seric continue; 834294Seric } 8353233Seric 8364315Seric /* 8374315Seric ** Address is verified -- add this user to mailer 8384315Seric ** argv, and add it to the print list of recipients. 8394315Seric */ 8404315Seric 8416059Seric /* link together the chain of recipients */ 8426272Seric to->q_tchain = tochain; 8436272Seric tochain = to; 8446059Seric 8453233Seric /* create list of users for error messages */ 8469388Seric (void) strcat(tobuf, ","); 8474082Seric (void) strcat(tobuf, to->q_paddr); 8489370Seric define('u', user, e); /* to user */ 84964694Seric p = to->q_home; 85064694Seric if (p == NULL && ctladdr != NULL) 85164694Seric p = ctladdr->q_home; 85264694Seric define('z', p, e); /* user's home */ 8533233Seric 8544863Seric /* 8556059Seric ** Expand out this user into argument list. 8564863Seric */ 8574863Seric 8586059Seric if (!clever) 8593233Seric { 8609370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8614863Seric *pvp++ = newstr(buf); 8624863Seric if (pvp >= &pv[MAXPV - 2]) 8634863Seric { 8644863Seric /* allow some space for trailing parms */ 8654863Seric break; 8664863Seric } 8674863Seric } 868294Seric } 869294Seric 8704067Seric /* see if any addresses still exist */ 8714067Seric if (tobuf[0] == '\0') 8724863Seric { 8739370Seric define('g', (char *) NULL, e); 8744067Seric return (0); 8754863Seric } 8764067Seric 8773233Seric /* print out messages as full list */ 8789388Seric e->e_to = tobuf + 1; 8793233Seric 880294Seric /* 8813233Seric ** Fill out any parameters after the $u parameter. 882294Seric */ 883294Seric 8844863Seric while (!clever && *++mvp != NULL) 885294Seric { 8869370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8873233Seric *pvp++ = newstr(buf); 8883233Seric if (pvp >= &pv[MAXPV]) 88958151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 890294Seric } 8913233Seric *pvp++ = NULL; 892294Seric 893294Seric /* 894294Seric ** Call the mailer. 8952898Seric ** The argument vector gets built, pipes 896294Seric ** are created as necessary, and we fork & exec as 8972898Seric ** appropriate. 8984863Seric ** If we are running SMTP, we just need to clean up. 899294Seric */ 900294Seric 90165137Seric /*XXX this seems a bit wierd */ 90265750Seric if (ctladdr == NULL && m != ProgMailer && 90365750Seric bitset(QGOODUID, e->e_from.q_flags)) 90465137Seric ctladdr = &e->e_from; 90565137Seric 90635651Seric #ifdef NAMED_BIND 90751313Seric if (ConfigLevel < 2) 90851313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 90935651Seric #endif 91054967Seric 9117672Seric if (tTd(11, 1)) 912294Seric { 9138178Seric printf("openmailer:"); 91458820Seric printav(pv); 915294Seric } 9164488Seric errno = 0; 9173233Seric 91825050Seric CurHostName = m->m_mailer; 91925050Seric 9206038Seric /* 9216038Seric ** Deal with the special case of mail handled through an IPC 9226038Seric ** connection. 9236038Seric ** In this case we don't actually fork. We must be 9246038Seric ** running SMTP for this to work. We will return a 9256038Seric ** zero pid to indicate that we are running IPC. 92611160Seric ** We also handle a debug version that just talks to stdin/out. 9276038Seric */ 9286038Seric 92958820Seric curhost = NULL; 93064334Seric SmtpPhase = NULL; 93164718Seric mci = NULL; 93258820Seric 93364401Seric #ifdef XDEBUG 93464401Seric { 93564401Seric char wbuf[MAXLINE]; 93664401Seric 93764401Seric /* make absolutely certain 0, 1, and 2 are in use */ 93864401Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 93964401Seric checkfd012(wbuf); 94064401Seric } 94164401Seric #endif 94264401Seric 94311160Seric /* check for Local Person Communication -- not for mortals!!! */ 94411160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 94511160Seric { 94654967Seric mci = (MCI *) xalloc(sizeof *mci); 94754993Seric bzero((char *) mci, sizeof *mci); 94853738Seric mci->mci_in = stdin; 94953738Seric mci->mci_out = stdout; 95054967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 95153751Seric mci->mci_mailer = m; 95211160Seric } 95354967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 95454967Seric strcmp(m->m_mailer, "[TCP]") == 0) 9556038Seric { 95652107Seric #ifdef DAEMON 95757454Seric register int i; 9587285Seric register u_short port; 9596038Seric 96064844Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 96164844Seric { 96264844Seric syserr("null host name for %s mailer", m->m_mailer); 96364844Seric rcode = EX_CONFIG; 96464844Seric goto give_up; 96564844Seric } 96664844Seric 96758820Seric CurHostName = pv[1]; 96858820Seric curhost = hostsignature(m, pv[1], e); 96954967Seric 97058479Seric if (curhost == NULL || curhost[0] == '\0') 97158479Seric { 97264844Seric syserr("null host signature for %s", pv[1]); 97358820Seric rcode = EX_OSERR; 97458820Seric goto give_up; 97558479Seric } 97658479Seric 9776038Seric if (!clever) 97858479Seric { 97958151Seric syserr("554 non-clever IPC"); 98064718Seric rcode = EX_CONFIG; 98158820Seric goto give_up; 98258479Seric } 98358820Seric if (pv[2] != NULL) 98458820Seric port = atoi(pv[2]); 9856632Seric else 9867285Seric port = 0; 98758820Seric tryhost: 98857454Seric while (*curhost != '\0') 98929433Sbloom { 99057454Seric register char *p; 99158664Seric static char hostbuf[MAXNAME]; 99257454Seric 99357454Seric /* pull the next host from the signature */ 99457454Seric p = strchr(curhost, ':'); 99557454Seric if (p == NULL) 99657454Seric p = &curhost[strlen(curhost)]; 99764718Seric if (p == curhost) 99864718Seric { 99964718Seric syserr("deliver: null host name in signature"); 100064726Seric curhost++; 100164718Seric continue; 100264718Seric } 100357454Seric strncpy(hostbuf, curhost, p - curhost); 100457454Seric hostbuf[p - curhost] = '\0'; 100557454Seric if (*p != '\0') 100657454Seric p++; 100757454Seric curhost = p; 100857454Seric 100953738Seric /* see if we already know that this host is fried */ 101057454Seric CurHostName = hostbuf; 101157454Seric mci = mci_get(hostbuf, m); 101254967Seric if (mci->mci_state != MCIS_CLOSED) 101357387Seric { 101457387Seric if (tTd(11, 1)) 101557387Seric { 101657387Seric printf("openmailer: "); 101764731Seric mci_dump(mci, FALSE); 101857387Seric } 101957943Seric CurHostName = mci->mci_host; 102058820Seric break; 102157387Seric } 102253751Seric mci->mci_mailer = m; 102354967Seric if (mci->mci_exitstat != EX_OK) 102454967Seric continue; 102554967Seric 102654967Seric /* try the connection */ 102757454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 102858151Seric message("Connecting to %s (%s)...", 102957454Seric hostbuf, m->m_name); 103057454Seric i = makeconnection(hostbuf, port, mci, 103154967Seric bitnset(M_SECURE_PORT, m->m_flags)); 103254967Seric mci->mci_exitstat = i; 103354967Seric mci->mci_errno = errno; 103463753Seric #ifdef NAMED_BIND 103563753Seric mci->mci_herrno = h_errno; 103663753Seric #endif 103754967Seric if (i == EX_OK) 103852106Seric { 103954967Seric mci->mci_state = MCIS_OPENING; 104054967Seric mci_cache(mci); 104163753Seric if (TrafficLogFile != NULL) 104263753Seric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 104363753Seric getpid(), hostbuf); 104454967Seric break; 104534022Sbostic } 104654967Seric else if (tTd(11, 1)) 104754967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 104854967Seric i, errno); 104953738Seric 105053738Seric /* enter status of this host */ 105153738Seric setstat(i); 105264718Seric 105364718Seric /* should print some message here for -v mode */ 10546047Seric } 105564718Seric if (mci == NULL) 105664718Seric { 105764718Seric syserr("deliver: no host name"); 105864718Seric rcode = EX_OSERR; 105964718Seric goto give_up; 106064718Seric } 106154993Seric mci->mci_pid = 0; 106254967Seric #else /* no DAEMON */ 106358151Seric syserr("554 openmailer: no IPC"); 106457387Seric if (tTd(11, 1)) 106557387Seric printf("openmailer: NULL\n"); 106664718Seric rcode = EX_UNAVAILABLE; 106764718Seric goto give_up; 106854967Seric #endif /* DAEMON */ 10696038Seric } 107054967Seric else 1071294Seric { 107263753Seric if (TrafficLogFile != NULL) 107358852Seric { 107463753Seric char **av; 107558925Seric 107663753Seric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 107763753Seric for (av = pv; *av != NULL; av++) 107863753Seric fprintf(TrafficLogFile, " %s", *av); 107963753Seric fprintf(TrafficLogFile, "\n"); 108058852Seric } 108158852Seric 108254967Seric /* create a pipe to shove the mail through */ 108354967Seric if (pipe(mpvect) < 0) 108454967Seric { 108558925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 108658925Seric e->e_to, m->m_name); 108757387Seric if (tTd(11, 1)) 108857387Seric printf("openmailer: NULL\n"); 108958820Seric rcode = EX_OSERR; 109058820Seric goto give_up; 109154967Seric } 10924863Seric 109354967Seric /* if this mailer speaks smtp, create a return pipe */ 109454967Seric if (clever && pipe(rpvect) < 0) 109554967Seric { 109658925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 109758925Seric e->e_to, m->m_name); 109854967Seric (void) close(mpvect[0]); 109954967Seric (void) close(mpvect[1]); 110057387Seric if (tTd(11, 1)) 110157387Seric printf("openmailer: NULL\n"); 110258820Seric rcode = EX_OSERR; 110358820Seric goto give_up; 110454967Seric } 11054863Seric 110654967Seric /* 110754967Seric ** Actually fork the mailer process. 110854967Seric ** DOFORK is clever about retrying. 110954967Seric ** 111054967Seric ** Dispose of SIGCHLD signal catchers that may be laying 111154967Seric ** around so that endmail will get it. 111254967Seric */ 11136038Seric 111454967Seric if (e->e_xfp != NULL) 111554967Seric (void) fflush(e->e_xfp); /* for debugging */ 111654967Seric (void) fflush(stdout); 111726434Seric # ifdef SIGCHLD 111864035Seric (void) setsignal(SIGCHLD, SIG_DFL); 111956795Seric # endif /* SIGCHLD */ 112054967Seric DOFORK(FORK); 112154967Seric /* pid is set by DOFORK */ 112254967Seric if (pid < 0) 11234863Seric { 112454967Seric /* failure */ 112558925Seric syserr("%s... openmailer(%s): cannot fork", 112658925Seric e->e_to, m->m_name); 112754967Seric (void) close(mpvect[0]); 112854967Seric (void) close(mpvect[1]); 112954967Seric if (clever) 113054967Seric { 113154967Seric (void) close(rpvect[0]); 113254967Seric (void) close(rpvect[1]); 113354967Seric } 113457387Seric if (tTd(11, 1)) 113557387Seric printf("openmailer: NULL\n"); 113658820Seric rcode = EX_OSERR; 113758820Seric goto give_up; 11384863Seric } 113954967Seric else if (pid == 0) 114054967Seric { 114154967Seric int i; 114256678Seric int saveerrno; 114358675Seric char **ep; 114458675Seric char *env[MAXUSERENVIRON]; 114558675Seric extern char **environ; 114654967Seric extern int DtableSize; 114715772Seric 114854967Seric /* child -- set up input & exec mailer */ 114964035Seric (void) setsignal(SIGINT, SIG_IGN); 115064035Seric (void) setsignal(SIGHUP, SIG_IGN); 115164035Seric (void) setsignal(SIGTERM, SIG_DFL); 11524709Seric 115364145Seric /* reset user and group */ 115464145Seric if (!bitnset(M_RESTR, m->m_flags)) 115564145Seric { 115664145Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 115764145Seric { 115864145Seric (void) initgroups(DefUser, DefGid); 115964837Seric (void) setgid(DefGid); 116064145Seric (void) setuid(DefUid); 116164145Seric } 116264145Seric else 116364145Seric { 116464145Seric (void) initgroups(ctladdr->q_ruser? 116564145Seric ctladdr->q_ruser: ctladdr->q_user, 116664145Seric ctladdr->q_gid); 116764970Seric (void) setgid(ctladdr->q_gid); 116864145Seric (void) setuid(ctladdr->q_uid); 116964145Seric } 117064145Seric } 117164145Seric 117264145Seric if (tTd(11, 2)) 117364145Seric printf("openmailer: running as r/euid=%d/%d\n", 117464145Seric getuid(), geteuid()); 117564145Seric 117658935Seric /* move into some "safe" directory */ 117758935Seric if (m->m_execdir != NULL) 117858935Seric { 117958935Seric char *p, *q; 118058935Seric char buf[MAXLINE]; 118158935Seric 118258935Seric for (p = m->m_execdir; p != NULL; p = q) 118358935Seric { 118458935Seric q = strchr(p, ':'); 118558935Seric if (q != NULL) 118658935Seric *q = '\0'; 118758935Seric expand(p, buf, &buf[sizeof buf] - 1, e); 118858935Seric if (q != NULL) 118958935Seric *q++ = ':'; 119058935Seric if (tTd(11, 20)) 119158935Seric printf("openmailer: trydir %s\n", 119258935Seric buf); 119358935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 119458935Seric break; 119558935Seric } 119658935Seric } 119758935Seric 119854967Seric /* arrange to filter std & diag output of command */ 119954967Seric if (clever) 120054967Seric { 120154967Seric (void) close(rpvect[0]); 120258852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 120358852Seric { 120458925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 120558925Seric e->e_to, m->m_name, rpvect[1]); 120658852Seric _exit(EX_OSERR); 120758852Seric } 120854967Seric (void) close(rpvect[1]); 120954967Seric } 1210*66089Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 1211*66089Seric HoldErrs || DisConnected) 121254967Seric { 121354967Seric /* put mailer output in transcript */ 121458852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 121558852Seric { 121658925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 121758925Seric e->e_to, m->m_name, 121858852Seric fileno(e->e_xfp)); 121958852Seric _exit(EX_OSERR); 122058852Seric } 122154967Seric } 122258852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 122358852Seric { 122458925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 122558925Seric e->e_to, m->m_name); 122658852Seric _exit(EX_OSERR); 122758852Seric } 12284709Seric 122954967Seric /* arrange to get standard input */ 123054967Seric (void) close(mpvect[1]); 123158731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 12324417Seric { 123358925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 123458925Seric e->e_to, m->m_name, mpvect[0]); 123554967Seric _exit(EX_OSERR); 12364417Seric } 123754967Seric (void) close(mpvect[0]); 12389370Seric 123954967Seric /* arrange for all the files to be closed */ 124054967Seric for (i = 3; i < DtableSize; i++) 124154967Seric { 124254967Seric register int j; 124364145Seric 124454967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 124564145Seric (void) fcntl(i, F_SETFD, j | 1); 124654967Seric } 12472774Seric 124866017Seric /* 124966017Seric ** Set up the mailer environment 125066017Seric ** TZ is timezone information. 125166017Seric ** SYSTYPE is Apollo software sys type (required). 125266017Seric ** ISP is Apollo hardware system type (required). 125366017Seric */ 125466017Seric 125558675Seric i = 0; 125658675Seric env[i++] = "AGENT=sendmail"; 125758675Seric for (ep = environ; *ep != NULL; ep++) 125858675Seric { 125966017Seric if (strncmp(*ep, "TZ=", 3) == 0 || 126066017Seric strncmp(*ep, "ISP=", 4) == 0 || 126166017Seric strncmp(*ep, "SYSTYPE=", 8) == 0) 126258675Seric env[i++] = *ep; 126358675Seric } 126458675Seric env[i++] = NULL; 126558675Seric 126654967Seric /* try to execute the mailer */ 126758820Seric execve(m->m_mailer, pv, env); 126856678Seric saveerrno = errno; 126954967Seric syserr("Cannot exec %s", m->m_mailer); 127060008Seric if (m == LocalMailer || transienterror(saveerrno)) 127160008Seric _exit(EX_OSERR); 127254967Seric _exit(EX_UNAVAILABLE); 127351835Seric } 127454967Seric 127554967Seric /* 127654967Seric ** Set up return value. 127754967Seric */ 127854967Seric 127954967Seric mci = (MCI *) xalloc(sizeof *mci); 128054993Seric bzero((char *) mci, sizeof *mci); 128154967Seric mci->mci_mailer = m; 128254967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 128354993Seric mci->mci_pid = pid; 128454967Seric (void) close(mpvect[0]); 128554967Seric mci->mci_out = fdopen(mpvect[1], "w"); 128664724Seric if (mci->mci_out == NULL) 128764724Seric { 128864724Seric syserr("deliver: cannot create mailer output channel, fd=%d", 128964724Seric mpvect[1]); 129064724Seric (void) close(mpvect[1]); 129164724Seric if (clever) 129264724Seric { 129364724Seric (void) close(rpvect[0]); 129464724Seric (void) close(rpvect[1]); 129564724Seric } 129664724Seric rcode = EX_OSERR; 129764724Seric goto give_up; 129864724Seric } 129954967Seric if (clever) 130054967Seric { 130154967Seric (void) close(rpvect[1]); 130254967Seric mci->mci_in = fdopen(rpvect[0], "r"); 130364724Seric if (mci->mci_in == NULL) 130464724Seric { 130564724Seric syserr("deliver: cannot create mailer input channel, fd=%d", 130664724Seric mpvect[1]); 130764724Seric (void) close(rpvect[0]); 130864724Seric fclose(mci->mci_out); 130964724Seric mci->mci_out = NULL; 131064724Seric rcode = EX_OSERR; 131164724Seric goto give_up; 131264724Seric } 131354967Seric } 131454967Seric else 131554967Seric { 131654967Seric mci->mci_flags |= MCIF_TEMP; 131754967Seric mci->mci_in = NULL; 131854967Seric } 1319294Seric } 1320294Seric 13214709Seric /* 132254967Seric ** If we are in SMTP opening state, send initial protocol. 13234709Seric */ 13244709Seric 132554967Seric if (clever && mci->mci_state != MCIS_CLOSED) 13264863Seric { 132754967Seric smtpinit(m, mci, e); 132853738Seric } 132957387Seric if (tTd(11, 1)) 133057387Seric { 133157387Seric printf("openmailer: "); 133264731Seric mci_dump(mci, FALSE); 133357387Seric } 1334294Seric 133558820Seric if (mci->mci_state != MCIS_OPEN) 133658820Seric { 133758820Seric /* couldn't open the mailer */ 133858820Seric rcode = mci->mci_exitstat; 133958820Seric errno = mci->mci_errno; 134063753Seric #ifdef NAMED_BIND 134163753Seric h_errno = mci->mci_herrno; 134263753Seric #endif 134358820Seric if (rcode == EX_OK) 134458820Seric { 134558820Seric /* shouldn't happen */ 134658820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 134758820Seric rcode, mci->mci_state, firstsig); 134858820Seric rcode = EX_SOFTWARE; 134958820Seric } 135064922Seric else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') 135159958Seric { 135259958Seric /* try next MX site */ 135359958Seric goto tryhost; 135459958Seric } 135558820Seric } 135658820Seric else if (!clever) 135758820Seric { 135858820Seric /* 135958820Seric ** Format and send message. 136058820Seric */ 136158820Seric 136265870Seric putfromline(mci, e); 136365870Seric (*e->e_puthdr)(mci, e); 136465870Seric putline("\n", mci); 136565870Seric (*e->e_putbody)(mci, e, NULL); 136658820Seric 136758820Seric /* get the exit status */ 136858820Seric rcode = endmailer(mci, e, pv); 136958820Seric } 137058820Seric else 137158820Seric #ifdef SMTP 137258820Seric { 137358820Seric /* 137458820Seric ** Send the MAIL FROM: protocol 137558820Seric */ 137658820Seric 137758820Seric rcode = smtpmailfrom(m, mci, e); 137858820Seric if (rcode == EX_OK) 137958820Seric { 138058820Seric register char *t = tobuf; 138158820Seric register int i; 138258820Seric 138358820Seric /* send the recipient list */ 138458820Seric tobuf[0] = '\0'; 138558820Seric for (to = tochain; to != NULL; to = to->q_tchain) 138658820Seric { 138758820Seric e->e_to = to->q_paddr; 138858820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 138958820Seric { 139058820Seric markfailure(e, to, i); 139164771Seric giveresponse(i, m, mci, ctladdr, e); 139258820Seric } 139358820Seric else 139458820Seric { 139558820Seric *t++ = ','; 139658820Seric for (p = to->q_paddr; *p; *t++ = *p++) 139758820Seric continue; 139864372Seric *t = '\0'; 139958820Seric } 140058820Seric } 140158820Seric 140258820Seric /* now send the data */ 140358820Seric if (tobuf[0] == '\0') 140458820Seric { 140558820Seric rcode = EX_OK; 140658820Seric e->e_to = NULL; 140758820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 140858820Seric smtprset(m, mci, e); 140958820Seric } 141058820Seric else 141158820Seric { 141258820Seric e->e_to = tobuf + 1; 141358820Seric rcode = smtpdata(m, mci, e); 141458820Seric } 141558820Seric 141658820Seric /* now close the connection */ 141758820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 141858820Seric smtpquit(m, mci, e); 141958820Seric } 142064922Seric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 142158820Seric { 142258820Seric /* try next MX site */ 142358820Seric goto tryhost; 142458820Seric } 142558820Seric } 142658820Seric #else /* not SMTP */ 142758820Seric { 142858820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 142958820Seric rcode = EX_CONFIG; 143058820Seric goto give_up; 143158820Seric } 143258820Seric #endif /* SMTP */ 143358820Seric #ifdef NAMED_BIND 143458820Seric if (ConfigLevel < 2) 143558820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 143658820Seric #endif 143758820Seric 143858820Seric /* arrange a return receipt if requested */ 143964718Seric if (rcode == EX_OK && e->e_receiptto != NULL && 144064718Seric bitnset(M_LOCALMAILER, m->m_flags)) 144158820Seric { 144258820Seric e->e_flags |= EF_SENDRECEIPT; 144358820Seric /* do we want to send back more info? */ 144458820Seric } 144558820Seric 144658820Seric /* 144758820Seric ** Do final status disposal. 144858820Seric ** We check for something in tobuf for the SMTP case. 144958820Seric ** If we got a temporary failure, arrange to queue the 145058820Seric ** addressees. 145158820Seric */ 145258820Seric 145358820Seric give_up: 145458820Seric if (tobuf[0] != '\0') 145564771Seric giveresponse(rcode, m, mci, ctladdr, e); 145658820Seric for (to = tochain; to != NULL; to = to->q_tchain) 145758820Seric { 145858820Seric if (rcode != EX_OK) 145958820Seric markfailure(e, to, rcode); 146058820Seric else 146158820Seric { 146258820Seric to->q_flags |= QSENT; 146358820Seric e->e_nsent++; 146464718Seric if (e->e_receiptto != NULL && 146564718Seric bitnset(M_LOCALMAILER, m->m_flags)) 146664718Seric { 146764718Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 146864718Seric to->q_paddr); 146964718Seric } 147058820Seric } 147158820Seric } 147258820Seric 147358820Seric /* 147458820Seric ** Restore state and return. 147558820Seric */ 147658820Seric 147764401Seric #ifdef XDEBUG 147864401Seric { 147964401Seric char wbuf[MAXLINE]; 148064401Seric 148164401Seric /* make absolutely certain 0, 1, and 2 are in use */ 148264554Seric sprintf(wbuf, "%s... end of deliver(%s)", 148364554Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 148464554Seric m->m_name); 148564401Seric checkfd012(wbuf); 148664401Seric } 148764401Seric #endif 148864401Seric 148958820Seric errno = 0; 149058820Seric define('g', (char *) NULL, e); 149158820Seric return (rcode); 1492294Seric } 1493294Seric /* 149458820Seric ** MARKFAILURE -- mark a failure on a specific address. 149558820Seric ** 149658820Seric ** Parameters: 149758820Seric ** e -- the envelope we are sending. 149858820Seric ** q -- the address to mark. 149958820Seric ** rcode -- the code signifying the particular failure. 150058820Seric ** 150158820Seric ** Returns: 150258820Seric ** none. 150358820Seric ** 150458820Seric ** Side Effects: 150558820Seric ** marks the address (and possibly the envelope) with the 150658820Seric ** failure so that an error will be returned or 150758820Seric ** the message will be queued, as appropriate. 150858820Seric */ 150958820Seric 151058820Seric markfailure(e, q, rcode) 151158820Seric register ENVELOPE *e; 151258820Seric register ADDRESS *q; 151358820Seric int rcode; 151458820Seric { 151558820Seric char buf[MAXLINE]; 151658820Seric 151765051Seric switch (rcode) 151865051Seric { 151965051Seric case EX_OK: 152065051Seric break; 152165051Seric 152265051Seric case EX_TEMPFAIL: 152365051Seric case EX_IOERR: 152465051Seric case EX_OSERR: 152563753Seric q->q_flags |= QQUEUEUP; 152665051Seric break; 152765051Seric 152865051Seric default: 152958820Seric q->q_flags |= QBADADDR; 153065051Seric break; 153165051Seric } 153258820Seric } 153358820Seric /* 153458820Seric ** ENDMAILER -- Wait for mailer to terminate. 153558820Seric ** 153658820Seric ** We should never get fatal errors (e.g., segmentation 153758820Seric ** violation), so we report those specially. For other 153858820Seric ** errors, we choose a status message (into statmsg), 153958820Seric ** and if it represents an error, we print it. 154058820Seric ** 154158820Seric ** Parameters: 154258820Seric ** pid -- pid of mailer. 154358820Seric ** e -- the current envelope. 154458820Seric ** pv -- the parameter vector that invoked the mailer 154558820Seric ** (for error messages). 154658820Seric ** 154758820Seric ** Returns: 154858820Seric ** exit code of mailer. 154958820Seric ** 155058820Seric ** Side Effects: 155158820Seric ** none. 155258820Seric */ 155358820Seric 155458820Seric endmailer(mci, e, pv) 155558820Seric register MCI *mci; 155658820Seric register ENVELOPE *e; 155758820Seric char **pv; 155858820Seric { 155958820Seric int st; 156058820Seric 156158820Seric /* close any connections */ 156258820Seric if (mci->mci_in != NULL) 156365198Seric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 156458820Seric if (mci->mci_out != NULL) 156565198Seric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 156658820Seric mci->mci_in = mci->mci_out = NULL; 156758820Seric mci->mci_state = MCIS_CLOSED; 156858820Seric 156958820Seric /* in the IPC case there is nothing to wait for */ 157058820Seric if (mci->mci_pid == 0) 157158820Seric return (EX_OK); 157258820Seric 157358820Seric /* wait for the mailer process to die and collect status */ 157458820Seric st = waitfor(mci->mci_pid); 157558820Seric if (st == -1) 157658820Seric { 157758820Seric syserr("endmailer %s: wait", pv[0]); 157858820Seric return (EX_SOFTWARE); 157958820Seric } 158058820Seric 158164379Seric if (WIFEXITED(st)) 158258820Seric { 158364379Seric /* normal death -- return status */ 158464379Seric return (WEXITSTATUS(st)); 158564379Seric } 158658820Seric 158764379Seric /* it died a horrid death */ 158865545Seric syserr("451 mailer %s died with signal %o", 158965545Seric mci->mci_mailer->m_name, st); 159058820Seric 159164379Seric /* log the arguments */ 159265194Seric if (pv != NULL && e->e_xfp != NULL) 159364379Seric { 159464379Seric register char **av; 159558820Seric 159664379Seric fprintf(e->e_xfp, "Arguments:"); 159764379Seric for (av = pv; *av != NULL; av++) 159864379Seric fprintf(e->e_xfp, " %s", *av); 159964379Seric fprintf(e->e_xfp, "\n"); 160058820Seric } 160158820Seric 160264379Seric ExitStat = EX_TEMPFAIL; 160364379Seric return (EX_TEMPFAIL); 160458820Seric } 160558820Seric /* 1606294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1607294Seric ** 1608294Seric ** Parameters: 1609294Seric ** stat -- the status code from the mailer (high byte 1610294Seric ** only; core dumps must have been taken care of 1611294Seric ** already). 161258337Seric ** m -- the mailer info for this mailer. 161358337Seric ** mci -- the mailer connection info -- can be NULL if the 161458337Seric ** response is given before the connection is made. 161564771Seric ** ctladdr -- the controlling address for the recipient 161664771Seric ** address(es). 161758337Seric ** e -- the current envelope. 1618294Seric ** 1619294Seric ** Returns: 16204082Seric ** none. 1621294Seric ** 1622294Seric ** Side Effects: 16231518Seric ** Errors may be incremented. 1624294Seric ** ExitStat may be set. 1625294Seric */ 1626294Seric 162764771Seric giveresponse(stat, m, mci, ctladdr, e) 1628294Seric int stat; 16299370Seric register MAILER *m; 163058337Seric register MCI *mci; 163164771Seric ADDRESS *ctladdr; 163210105Seric ENVELOPE *e; 1633294Seric { 163460094Seric register const char *statmsg; 1635294Seric extern char *SysExMsg[]; 1636294Seric register int i; 163736788Sbostic extern int N_SysEx; 163810105Seric char buf[MAXLINE]; 1639294Seric 16404315Seric /* 16414315Seric ** Compute status message from code. 16424315Seric */ 16434315Seric 1644294Seric i = stat - EX__BASE; 16459370Seric if (stat == 0) 164658852Seric { 16479370Seric statmsg = "250 Sent"; 164858916Seric if (e->e_statmsg != NULL) 164958852Seric { 165058916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 165158852Seric statmsg = buf; 165258852Seric } 165358852Seric } 16549370Seric else if (i < 0 || i > N_SysEx) 16559370Seric { 16569370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 16579370Seric stat = EX_UNAVAILABLE; 16589370Seric statmsg = buf; 16599370Seric } 166010105Seric else if (stat == EX_TEMPFAIL) 166110105Seric { 166258664Seric (void) strcpy(buf, SysExMsg[i] + 1); 166336788Sbostic #ifdef NAMED_BIND 166425527Smiriam if (h_errno == TRY_AGAIN) 166563993Seric statmsg = errstring(h_errno+E_DNSBASE); 166621061Seric else 166736788Sbostic #endif 166821061Seric { 166925527Smiriam if (errno != 0) 167025527Smiriam statmsg = errstring(errno); 167125527Smiriam else 167225527Smiriam { 167321061Seric #ifdef SMTP 167425527Smiriam statmsg = SmtpError; 167556795Seric #else /* SMTP */ 167625527Smiriam statmsg = NULL; 167756795Seric #endif /* SMTP */ 167825527Smiriam } 167921061Seric } 168021061Seric if (statmsg != NULL && statmsg[0] != '\0') 168121061Seric { 168210124Seric (void) strcat(buf, ": "); 168321061Seric (void) strcat(buf, statmsg); 168410105Seric } 168510105Seric statmsg = buf; 168610105Seric } 168763753Seric #ifdef NAMED_BIND 168863753Seric else if (stat == EX_NOHOST && h_errno != 0) 168963753Seric { 169063993Seric statmsg = errstring(h_errno + E_DNSBASE); 169163753Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i], statmsg); 169263753Seric statmsg = buf; 169363753Seric } 169463753Seric #endif 1695294Seric else 169621061Seric { 1697294Seric statmsg = SysExMsg[i]; 169858664Seric if (*statmsg++ == ':') 169958664Seric { 170058664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 170158664Seric statmsg = buf; 170258664Seric } 170321061Seric } 17049370Seric 17059370Seric /* 17069370Seric ** Print the message as appropriate 17079370Seric */ 17089370Seric 170910105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 171064718Seric { 171164718Seric extern char MsgBuf[]; 171264718Seric 171358524Seric message(&statmsg[4], errstring(errno)); 171464718Seric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 171564718Seric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 171664718Seric } 1717294Seric else 1718294Seric { 17191518Seric Errors++; 172058524Seric usrerr(statmsg, errstring(errno)); 1721294Seric } 1722294Seric 1723294Seric /* 1724294Seric ** Final cleanup. 1725294Seric ** Log a record of the transaction. Compute the new 1726294Seric ** ExitStat -- if we already had an error, stick with 1727294Seric ** that. 1728294Seric */ 1729294Seric 173058020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 173164771Seric logdelivery(m, mci, &statmsg[4], ctladdr, e); 17327858Seric 17334621Seric if (stat != EX_TEMPFAIL) 17344621Seric setstat(stat); 173564952Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 173610105Seric { 173710105Seric if (e->e_message != NULL) 173810105Seric free(e->e_message); 173910105Seric e->e_message = newstr(&statmsg[4]); 174010105Seric } 174110124Seric errno = 0; 174236788Sbostic #ifdef NAMED_BIND 174325527Smiriam h_errno = 0; 174436788Sbostic #endif 1745294Seric } 1746294Seric /* 17478496Seric ** LOGDELIVERY -- log the delivery in the system log 17488496Seric ** 174964969Seric ** Care is taken to avoid logging lines that are too long, because 175064969Seric ** some versions of syslog have an unfortunate proclivity for core 175164969Seric ** dumping. This is a hack, to be sure, that is at best empirical. 175264969Seric ** 17538496Seric ** Parameters: 175458337Seric ** m -- the mailer info. Can be NULL for initial queue. 175558337Seric ** mci -- the mailer connection info -- can be NULL if the 175658337Seric ** log is occuring when no connection is active. 175758337Seric ** stat -- the message to print for the status. 175864771Seric ** ctladdr -- the controlling address for the to list. 175958337Seric ** e -- the current envelope. 17608496Seric ** 17618496Seric ** Returns: 17628496Seric ** none 17638496Seric ** 17648496Seric ** Side Effects: 17658496Seric ** none 17668496Seric */ 17678496Seric 176864771Seric logdelivery(m, mci, stat, ctladdr, e) 176958337Seric MAILER *m; 177058337Seric register MCI *mci; 17718496Seric char *stat; 177264771Seric ADDRESS *ctladdr; 177354967Seric register ENVELOPE *e; 17748496Seric { 177558343Seric # ifdef LOG 177664771Seric register char *bp; 177764969Seric register char *p; 177864969Seric int l; 177958418Seric char buf[512]; 17808496Seric 178165059Seric # if (SYSLOG_BUFSIZE) >= 256 178264771Seric bp = buf; 178364771Seric if (ctladdr != NULL) 178464771Seric { 178564771Seric strcpy(bp, ", ctladdr="); 178665016Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 178764771Seric bp += strlen(bp); 178864771Seric if (bitset(QGOODUID, ctladdr->q_flags)) 178964771Seric { 179064771Seric (void) sprintf(bp, " (%d/%d)", 179164771Seric ctladdr->q_uid, ctladdr->q_gid); 179264771Seric bp += strlen(bp); 179364771Seric } 179464771Seric } 179558337Seric 179664771Seric (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 179764771Seric bp += strlen(bp); 179864771Seric 179958513Seric if (m != NULL) 180058305Seric { 180164771Seric (void) strcpy(bp, ", mailer="); 180264771Seric (void) strcat(bp, m->m_name); 180364771Seric bp += strlen(bp); 180458305Seric } 180558513Seric 180658513Seric if (mci != NULL && mci->mci_host != NULL) 180758305Seric { 180858305Seric # ifdef DAEMON 180958755Seric extern SOCKADDR CurHostAddr; 181058513Seric # endif 181158305Seric 181264771Seric (void) strcpy(bp, ", relay="); 181364771Seric (void) strcat(bp, mci->mci_host); 181458513Seric 181558513Seric # ifdef DAEMON 181665919Seric (void) strcat(bp, " ["); 181764771Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 181865919Seric (void) strcat(bp, "]"); 181958305Seric # endif 182058305Seric } 182158343Seric else 182258513Seric { 182358513Seric char *p = macvalue('h', e); 182458343Seric 182558513Seric if (p != NULL && p[0] != '\0') 182658513Seric { 182764771Seric (void) strcpy(bp, ", relay="); 182864771Seric (void) strcat(bp, p); 182958513Seric } 183058513Seric } 183164922Seric bp += strlen(bp); 183264969Seric 183365059Seric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 183465059Seric #if (STATLEN) < 63 183565059Seric # undef STATLEN 183665059Seric # define STATLEN 63 183765059Seric #endif 183865059Seric #if (STATLEN) > 203 183965059Seric # undef STATLEN 184065059Seric # define STATLEN 203 184165059Seric #endif 184265059Seric 184365059Seric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 184464969Seric { 184564969Seric /* desperation move -- truncate data */ 184665059Seric bp = buf + sizeof buf - ((STATLEN) + 17); 184764969Seric strcpy(bp, "..."); 184864969Seric bp += 3; 184964969Seric } 185064969Seric 185164969Seric (void) strcpy(bp, ", stat="); 185264969Seric bp += strlen(bp); 185365059Seric 185465059Seric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 185558418Seric 185664969Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 185764969Seric p = e->e_to; 185864969Seric while (strlen(p) >= l) 185964969Seric { 186064969Seric register char *q = strchr(p + l, ','); 186164969Seric 186265008Seric if (q == NULL) 186364969Seric break; 186464969Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 186564969Seric e->e_id, ++q - p, p, buf); 186664969Seric p = q; 186764969Seric } 186864969Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 186965059Seric 187065059Seric # else /* we have a very short log buffer size */ 187165059Seric 187265650Seric l = SYSLOG_BUFSIZE - 80; 187365059Seric p = e->e_to; 187465059Seric while (strlen(p) >= l) 187565059Seric { 187665059Seric register char *q = strchr(p + l, ','); 187765059Seric 187865059Seric if (q == NULL) 187965059Seric break; 188065059Seric syslog(LOG_INFO, "%s: to=%.*s [more]", 188165059Seric e->e_id, ++q - p, p); 188265059Seric p = q; 188365059Seric } 188465059Seric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 188565059Seric 188665059Seric if (ctladdr != NULL) 188765059Seric { 188865059Seric bp = buf; 188965059Seric strcpy(buf, "ctladdr="); 189065059Seric bp += strlen(buf); 189165059Seric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 189265059Seric bp += strlen(buf); 189365059Seric if (bitset(QGOODUID, ctladdr->q_flags)) 189465059Seric { 189565059Seric (void) sprintf(bp, " (%d/%d)", 189665059Seric ctladdr->q_uid, ctladdr->q_gid); 189765059Seric bp += strlen(bp); 189865059Seric } 189965059Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 190065059Seric } 190165650Seric bp = buf; 190265650Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 190365650Seric bp += strlen(bp); 190465059Seric 190565059Seric if (m != NULL) 190665650Seric { 190765650Seric sprintf(bp, ", mailer=%s", m->m_name); 190865650Seric bp += strlen(bp); 190965650Seric } 191066009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 191165059Seric 191266009Seric buf[0] = '\0'; 191365059Seric if (mci != NULL && mci->mci_host != NULL) 191465059Seric { 191565059Seric # ifdef DAEMON 191665059Seric extern SOCKADDR CurHostAddr; 191765059Seric # endif 191865059Seric 191966021Seric sprintf(buf, "relay=%s", mci->mci_host); 192065059Seric 192165059Seric # ifdef DAEMON 192266009Seric (void) strcat(buf, " ["); 192366009Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 192466009Seric (void) strcat(buf, "]"); 192565059Seric # endif 192665059Seric } 192765059Seric else 192865059Seric { 192965059Seric char *p = macvalue('h', e); 193065059Seric 193165059Seric if (p != NULL && p[0] != '\0') 193266021Seric sprintf(buf, "relay=%s", p); 193365059Seric } 193466009Seric if (buf[0] != '\0') 193566009Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 193665059Seric 193765059Seric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 193865059Seric # endif /* short log buffer */ 193956795Seric # endif /* LOG */ 19408496Seric } 19418496Seric /* 19426974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1943294Seric ** 19446974Seric ** This can be made an arbitrary message separator by changing $l 1945294Seric ** 194616150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 194716150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 194816150Seric ** does a well-meaning programmer such as myself have to deal with 194916150Seric ** this kind of antique garbage???? 19506974Seric ** 1951294Seric ** Parameters: 195265870Seric ** mci -- the connection information. 195365870Seric ** e -- the envelope. 1954294Seric ** 1955294Seric ** Returns: 19566974Seric ** none 1957294Seric ** 1958294Seric ** Side Effects: 19596974Seric ** outputs some text to fp. 1960294Seric */ 1961294Seric 196265870Seric putfromline(mci, e) 196365870Seric register MCI *mci; 196454967Seric ENVELOPE *e; 1965294Seric { 196658050Seric char *template = "\201l\n"; 19676974Seric char buf[MAXLINE]; 1968294Seric 196965870Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 19706974Seric return; 19714315Seric 19726974Seric # ifdef UGLYUUCP 197365870Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 19744205Seric { 197512223Seric char *bang; 197612223Seric char xbuf[MAXLINE]; 19776041Seric 197858680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 197956795Seric bang = strchr(buf, '!'); 19806974Seric if (bang == NULL) 198164370Seric { 198264370Seric errno = 0; 198364370Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 198464370Seric } 19855099Seric else 19869370Seric { 198712223Seric *bang++ = '\0'; 198858050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 198912223Seric template = xbuf; 19909370Seric } 19916974Seric } 199256795Seric # endif /* UGLYUUCP */ 199354967Seric expand(template, buf, &buf[sizeof buf - 1], e); 199465870Seric putline(buf, mci); 19955981Seric } 19965981Seric /* 19976974Seric ** PUTBODY -- put the body of a message. 19986974Seric ** 19996974Seric ** Parameters: 200065870Seric ** mci -- the connection information. 20019538Seric ** e -- the envelope to put out. 200259730Seric ** separator -- if non-NULL, a message separator that must 200359730Seric ** not be permitted in the resulting message. 20046974Seric ** 20056974Seric ** Returns: 20066974Seric ** none. 20076974Seric ** 20086974Seric ** Side Effects: 20096974Seric ** The message is written onto fp. 20106974Seric */ 20116974Seric 201265870Seric putbody(mci, e, separator) 201365870Seric register MCI *mci; 20149538Seric register ENVELOPE *e; 201559730Seric char *separator; 20166974Seric { 201710168Seric char buf[MAXLINE]; 20186974Seric 20196974Seric /* 20206974Seric ** Output the body of the message 20216974Seric */ 20226974Seric 20239538Seric if (e->e_dfp == NULL) 20246974Seric { 20259538Seric if (e->e_df != NULL) 20269538Seric { 20279538Seric e->e_dfp = fopen(e->e_df, "r"); 20289538Seric if (e->e_dfp == NULL) 202940931Srick syserr("putbody: Cannot open %s for %s from %s", 203064118Seric e->e_df, e->e_to, e->e_from.q_paddr); 20319538Seric } 20329538Seric else 203365870Seric putline("<<< No Message Collected >>>", mci); 20349538Seric } 20359538Seric if (e->e_dfp != NULL) 20369538Seric { 20379538Seric rewind(e->e_dfp); 203865870Seric while (!ferror(mci->mci_out) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 203916875Seric { 204065870Seric if (buf[0] == 'F' && 204165870Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 204240995Sbostic strncmp(buf, "From ", 5) == 0) 204365870Seric (void) putc('>', mci->mci_out); 204459730Seric if (buf[0] == '-' && buf[1] == '-' && separator != NULL) 204559730Seric { 204659730Seric /* possible separator */ 204759730Seric int sl = strlen(separator); 204859730Seric 204959730Seric if (strncmp(&buf[2], separator, sl) == 0) 205065870Seric (void) putc(' ', mci->mci_out); 205159730Seric } 205265870Seric putline(buf, mci); 205316875Seric } 20546974Seric 20559538Seric if (ferror(e->e_dfp)) 20566974Seric { 205764718Seric syserr("putbody: %s: read error", e->e_df); 20586974Seric ExitStat = EX_IOERR; 20596974Seric } 20606974Seric } 20616974Seric 206259542Seric /* some mailers want extra blank line at end of message */ 206365870Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 206465870Seric buf[0] != '\0' && buf[0] != '\n') 206565870Seric putline("", mci); 206659542Seric 206765870Seric (void) fflush(mci->mci_out); 206865870Seric if (ferror(mci->mci_out) && errno != EPIPE) 20696974Seric { 20706974Seric syserr("putbody: write error"); 20716974Seric ExitStat = EX_IOERR; 20726974Seric } 20736974Seric errno = 0; 20746974Seric } 20756974Seric /* 2076294Seric ** MAILFILE -- Send a message to a file. 2077294Seric ** 20784327Seric ** If the file has the setuid/setgid bits set, but NO execute 20794327Seric ** bits, sendmail will try to become the owner of that file 20804327Seric ** rather than the real user. Obviously, this only works if 20814327Seric ** sendmail runs as root. 20824327Seric ** 20839370Seric ** This could be done as a subordinate mailer, except that it 20849370Seric ** is used implicitly to save messages in ~/dead.letter. We 20859370Seric ** view this as being sufficiently important as to include it 20869370Seric ** here. For example, if the system is dying, we shouldn't have 20879370Seric ** to create another process plus some pipes to save the message. 20889370Seric ** 2089294Seric ** Parameters: 2090294Seric ** filename -- the name of the file to send to. 20914397Seric ** ctladdr -- the controlling address header -- includes 20924397Seric ** the userid/groupid to be when sending. 2093294Seric ** 2094294Seric ** Returns: 2095294Seric ** The exit code associated with the operation. 2096294Seric ** 2097294Seric ** Side Effects: 2098294Seric ** none. 2099294Seric */ 2100294Seric 210154967Seric mailfile(filename, ctladdr, e) 2102294Seric char *filename; 21034397Seric ADDRESS *ctladdr; 210454967Seric register ENVELOPE *e; 2105294Seric { 2106294Seric register FILE *f; 21074214Seric register int pid; 210853751Seric int mode; 2109294Seric 211059267Seric if (tTd(11, 1)) 211159267Seric { 211259267Seric printf("mailfile %s\n ctladdr=", filename); 211359267Seric printaddr(ctladdr, FALSE); 211459267Seric } 211559267Seric 211663753Seric if (e->e_xfp != NULL) 211763753Seric fflush(e->e_xfp); 211863753Seric 21194214Seric /* 21204214Seric ** Fork so we can change permissions here. 21214214Seric ** Note that we MUST use fork, not vfork, because of 21224214Seric ** the complications of calling subroutines, etc. 21234214Seric */ 21244067Seric 21254214Seric DOFORK(fork); 21264214Seric 21274214Seric if (pid < 0) 21284214Seric return (EX_OSERR); 21294214Seric else if (pid == 0) 21304214Seric { 21314214Seric /* child -- actually write to file */ 21324327Seric struct stat stb; 213365870Seric MCI mcibuf; 21344327Seric 213564035Seric (void) setsignal(SIGINT, SIG_DFL); 213664035Seric (void) setsignal(SIGHUP, SIG_DFL); 213764035Seric (void) setsignal(SIGTERM, SIG_DFL); 213823102Seric (void) umask(OldUmask); 213952673Seric 21404327Seric if (stat(filename, &stb) < 0) 214159745Seric stb.st_mode = FileMode; 214253751Seric mode = stb.st_mode; 214352673Seric 214452673Seric /* limit the errors to those actually caused in the child */ 214552673Seric errno = 0; 214652673Seric ExitStat = EX_OK; 214752673Seric 21484327Seric if (bitset(0111, stb.st_mode)) 21494327Seric exit(EX_CANTCREAT); 215064823Seric if (ctladdr != NULL) 215153751Seric { 215253751Seric /* ignore setuid and setgid bits */ 215353751Seric mode &= ~(S_ISGID|S_ISUID); 215453751Seric } 215553751Seric 215640931Srick /* we have to open the dfile BEFORE setuid */ 215753751Seric if (e->e_dfp == NULL && e->e_df != NULL) 215840931Srick { 215940931Srick e->e_dfp = fopen(e->e_df, "r"); 216052673Seric if (e->e_dfp == NULL) 216152673Seric { 216240931Srick syserr("mailfile: Cannot open %s for %s from %s", 216364118Seric e->e_df, e->e_to, e->e_from.q_paddr); 216440931Srick } 216540931Srick } 216640931Srick 216753751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 21684417Seric { 216964823Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 217052673Seric { 217140972Sbostic (void) initgroups(DefUser, DefGid); 217252673Seric } 217352673Seric else 217452673Seric { 217553751Seric (void) initgroups(ctladdr->q_ruser ? 217653751Seric ctladdr->q_ruser : ctladdr->q_user, 217740972Sbostic ctladdr->q_gid); 217840972Sbostic } 21794417Seric } 218053751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 21814417Seric { 218264823Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 21834417Seric (void) setuid(DefUid); 21844417Seric else 21854417Seric (void) setuid(ctladdr->q_uid); 21864417Seric } 218752673Seric FileName = filename; 218852673Seric LineNumber = 0; 218959745Seric f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); 21904214Seric if (f == NULL) 219152673Seric { 219264387Seric message("554 cannot open: %s", errstring(errno)); 21934214Seric exit(EX_CANTCREAT); 219452673Seric } 21954214Seric 219665870Seric bzero(&mcibuf, sizeof mcibuf); 219765870Seric mcibuf.mci_mailer = FileMailer; 219865870Seric mcibuf.mci_out = f; 219965870Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 220065870Seric mcibuf.mci_flags |= MCIF_7BIT; 220165870Seric 220265870Seric putfromline(&mcibuf, e); 220365870Seric (*e->e_puthdr)(&mcibuf, e); 220465870Seric putline("\n", &mcibuf); 220565870Seric (*e->e_putbody)(&mcibuf, e, NULL); 220665870Seric putline("\n", &mcibuf); 220752673Seric if (ferror(f)) 220852673Seric { 220964387Seric message("451 I/O error: %s", errstring(errno)); 221052673Seric setstat(EX_IOERR); 221152673Seric } 221258680Seric (void) xfclose(f, "mailfile", filename); 22134214Seric (void) fflush(stdout); 22144417Seric 22156887Seric /* reset ISUID & ISGID bits for paranoid systems */ 22164621Seric (void) chmod(filename, (int) stb.st_mode); 221752673Seric exit(ExitStat); 22184315Seric /*NOTREACHED*/ 22194214Seric } 22204214Seric else 22214214Seric { 22224214Seric /* parent -- wait for exit status */ 22239370Seric int st; 22244214Seric 22259370Seric st = waitfor(pid); 222664379Seric if (WIFEXITED(st)) 222764379Seric return (WEXITSTATUS(st)); 222864379Seric else 222964387Seric { 223064387Seric syserr("child died on signal %d", st); 22319370Seric return (EX_UNAVAILABLE); 223264387Seric } 223340931Srick /*NOTREACHED*/ 22344214Seric } 2235294Seric } 22364550Seric /* 223757454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 223857454Seric ** 223957454Seric ** The signature describes how we are going to send this -- it 224057454Seric ** can be just the hostname (for non-Internet hosts) or can be 224157454Seric ** an ordered list of MX hosts. 224257454Seric ** 224357454Seric ** Parameters: 224457454Seric ** m -- the mailer describing this host. 224557454Seric ** host -- the host name. 224657454Seric ** e -- the current envelope. 224757454Seric ** 224857454Seric ** Returns: 224957454Seric ** The signature for this host. 225057454Seric ** 225157454Seric ** Side Effects: 225257454Seric ** Can tweak the symbol table. 225357454Seric */ 225457454Seric 225557454Seric char * 225657454Seric hostsignature(m, host, e) 225757454Seric register MAILER *m; 225857454Seric char *host; 225957454Seric ENVELOPE *e; 226057454Seric { 226157454Seric register char *p; 226257454Seric register STAB *s; 226357454Seric int i; 226457454Seric int len; 226557454Seric #ifdef NAMED_BIND 226657454Seric int nmx; 226757454Seric auto int rcode; 226859076Seric char *hp; 226959076Seric char *endp; 227059111Seric int oldoptions; 227157454Seric char *mxhosts[MAXMXHOSTS + 1]; 227257454Seric #endif 227357454Seric 227457454Seric /* 227557454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 227657454Seric */ 227757454Seric 227857454Seric p = m->m_mailer; 227957454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 228057454Seric { 228157454Seric /* just an ordinary mailer */ 228257454Seric return host; 228357454Seric } 228457454Seric 228557454Seric /* 228657454Seric ** Look it up in the symbol table. 228757454Seric */ 228857454Seric 228957454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 229057454Seric if (s->s_hostsig != NULL) 229157454Seric return s->s_hostsig; 229257454Seric 229357454Seric /* 229457454Seric ** Not already there -- create a signature. 229557454Seric */ 229657454Seric 229757454Seric #ifdef NAMED_BIND 229859111Seric if (ConfigLevel < 2) 229959111Seric { 230059111Seric oldoptions = _res.options; 230159111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 230259111Seric } 230359111Seric 230459076Seric for (hp = host; hp != NULL; hp = endp) 230557454Seric { 230659076Seric endp = strchr(hp, ':'); 230759076Seric if (endp != NULL) 230859076Seric *endp = '\0'; 230957454Seric 231059273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 231157454Seric 231259076Seric if (nmx <= 0) 231359076Seric { 231459076Seric register MCI *mci; 231557454Seric 231659076Seric /* update the connection info for this host */ 231759076Seric mci = mci_get(hp, m); 231859076Seric mci->mci_exitstat = rcode; 231959076Seric mci->mci_errno = errno; 232063753Seric #ifdef NAMED_BIND 232163753Seric mci->mci_herrno = h_errno; 232263753Seric #endif 232359076Seric 232459076Seric /* and return the original host name as the signature */ 232559076Seric nmx = 1; 232659076Seric mxhosts[0] = hp; 232759076Seric } 232859076Seric 232959076Seric len = 0; 233059076Seric for (i = 0; i < nmx; i++) 233159076Seric { 233259076Seric len += strlen(mxhosts[i]) + 1; 233359076Seric } 233459076Seric if (s->s_hostsig != NULL) 233559076Seric len += strlen(s->s_hostsig) + 1; 233659076Seric p = xalloc(len); 233759076Seric if (s->s_hostsig != NULL) 233859076Seric { 233959076Seric (void) strcpy(p, s->s_hostsig); 234059076Seric free(s->s_hostsig); 234159076Seric s->s_hostsig = p; 234259076Seric p += strlen(p); 234357454Seric *p++ = ':'; 234459076Seric } 234559076Seric else 234659076Seric s->s_hostsig = p; 234759076Seric for (i = 0; i < nmx; i++) 234859076Seric { 234959076Seric if (i != 0) 235059076Seric *p++ = ':'; 235159076Seric strcpy(p, mxhosts[i]); 235259076Seric p += strlen(p); 235359076Seric } 235459076Seric if (endp != NULL) 235559076Seric *endp++ = ':'; 235657454Seric } 235757454Seric makelower(s->s_hostsig); 235859111Seric if (ConfigLevel < 2) 235959111Seric _res.options = oldoptions; 236057454Seric #else 236157454Seric /* not using BIND -- the signature is just the host name */ 236257454Seric s->s_hostsig = host; 236357454Seric #endif 236457454Seric if (tTd(17, 1)) 236557454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 236657454Seric return s->s_hostsig; 236757454Seric } 2368