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*65008Seric static char sccsid[] = "@(#)deliver.c 8.47 (Berkeley) 12/01/93"; 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 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 4158820Seric sendall(e, mode) 4258820Seric ENVELOPE *e; 4358820Seric char mode; 4458820Seric { 4558820Seric register ADDRESS *q; 4658820Seric char *owner; 4758820Seric int otherowners; 4858820Seric register ENVELOPE *ee; 4958820Seric ENVELOPE *splitenv = NULL; 5058929Seric bool announcequeueup; 5158820Seric 5263839Seric /* 5363839Seric ** If we have had global, fatal errors, don't bother sending 5463839Seric ** the message at all if we are in SMTP mode. Local errors 5563839Seric ** (e.g., a single address failing) will still cause the other 5663839Seric ** addresses to be sent. 5763839Seric */ 5863839Seric 5963839Seric if (bitset(EF_FATALERRS, e->e_flags) && OpMode == MD_SMTP) 6061092Seric { 6161092Seric e->e_flags |= EF_CLRQUEUE; 6261092Seric return; 6361092Seric } 6461092Seric 6558820Seric /* determine actual delivery mode */ 6664826Seric CurrentLA = getla(); 6758820Seric if (mode == SM_DEFAULT) 6858820Seric { 6958820Seric mode = e->e_sendmode; 7058820Seric if (mode != SM_VERIFY && 7158820Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 7258820Seric mode = SM_QUEUE; 7358929Seric announcequeueup = mode == SM_QUEUE; 7458820Seric } 7558929Seric else 7658929Seric announcequeueup = FALSE; 7758820Seric 7858820Seric if (tTd(13, 1)) 7958820Seric { 8064310Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 8164310Seric mode, e->e_id); 8258820Seric printaddr(&e->e_from, FALSE); 8358820Seric printf("sendqueue:\n"); 8458820Seric printaddr(e->e_sendqueue, TRUE); 8558820Seric } 8658820Seric 8758820Seric /* 8858820Seric ** Do any preprocessing necessary for the mode we are running. 8958820Seric ** Check to make sure the hop count is reasonable. 9058820Seric ** Delete sends to the sender in mailing lists. 9158820Seric */ 9258820Seric 9358820Seric CurEnv = e; 9458820Seric 9558820Seric if (e->e_hopcount > MaxHopCount) 9658820Seric { 9758820Seric errno = 0; 9864495Seric syserr("554 too many hops %d (%d max): from %s via %s, to %s", 9958820Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 10064495Seric RealHostName, e->e_sendqueue->q_paddr); 10158820Seric return; 10258820Seric } 10358820Seric 10459435Seric /* 10559435Seric ** Do sender deletion. 10659435Seric ** 10759435Seric ** If the sender has the QQUEUEUP flag set, skip this. 10859435Seric ** This can happen if the name server is hosed when you 10959435Seric ** are trying to send mail. The result is that the sender 11059435Seric ** is instantiated in the queue as a recipient. 11159435Seric */ 11259435Seric 11364118Seric if (!bitset(EF_METOO, e->e_flags) && 11464118Seric !bitset(QQUEUEUP, e->e_from.q_flags)) 11558820Seric { 11658820Seric if (tTd(13, 5)) 11758820Seric { 11858820Seric printf("sendall: QDONTSEND "); 11958820Seric printaddr(&e->e_from, FALSE); 12058820Seric } 12158820Seric e->e_from.q_flags |= QDONTSEND; 12258820Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 12358820Seric } 12458820Seric 12558820Seric /* 12658820Seric ** Handle alias owners. 12758820Seric ** 12858820Seric ** We scan up the q_alias chain looking for owners. 12958820Seric ** We discard owners that are the same as the return path. 13058820Seric */ 13158820Seric 13258820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13358820Seric { 13458820Seric register struct address *a; 13558820Seric 13658820Seric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 13758820Seric continue; 13858820Seric if (a != NULL) 13958820Seric q->q_owner = a->q_owner; 14058820Seric 14158820Seric if (q->q_owner != NULL && 14258820Seric !bitset(QDONTSEND, q->q_flags) && 14358820Seric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 14458820Seric q->q_owner = NULL; 14558820Seric } 14658820Seric 14758820Seric owner = ""; 14858820Seric otherowners = 1; 14958820Seric while (owner != NULL && otherowners > 0) 15058820Seric { 15158820Seric owner = NULL; 15258820Seric otherowners = 0; 15358820Seric 15458820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15558820Seric { 15658820Seric if (bitset(QDONTSEND, q->q_flags)) 15758820Seric continue; 15858820Seric 15958820Seric if (q->q_owner != NULL) 16058820Seric { 16158820Seric if (owner == NULL) 16258820Seric owner = q->q_owner; 16358820Seric else if (owner != q->q_owner) 16458820Seric { 16558820Seric if (strcmp(owner, q->q_owner) == 0) 16658820Seric { 16758820Seric /* make future comparisons cheap */ 16858820Seric q->q_owner = owner; 16958820Seric } 17058820Seric else 17158820Seric { 17258820Seric otherowners++; 17358820Seric } 17458820Seric owner = q->q_owner; 17558820Seric } 17658820Seric } 17758820Seric else 17858820Seric { 17958820Seric otherowners++; 18058820Seric } 18158820Seric } 18258820Seric 18358820Seric if (owner != NULL && otherowners > 0) 18458820Seric { 18558820Seric extern HDR *copyheader(); 18658820Seric extern ADDRESS *copyqueue(); 18758820Seric 18858820Seric /* 18958820Seric ** Split this envelope into two. 19058820Seric */ 19158820Seric 19258820Seric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 19358820Seric *ee = *e; 19458820Seric ee->e_id = NULL; 19558820Seric (void) queuename(ee, '\0'); 19658820Seric 19758820Seric if (tTd(13, 1)) 19858820Seric printf("sendall: split %s into %s\n", 19958820Seric e->e_id, ee->e_id); 20058820Seric 20158820Seric ee->e_header = copyheader(e->e_header); 20258820Seric ee->e_sendqueue = copyqueue(e->e_sendqueue); 20358820Seric ee->e_errorqueue = copyqueue(e->e_errorqueue); 20458916Seric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); 20558820Seric setsender(owner, ee, NULL, TRUE); 20658820Seric if (tTd(13, 5)) 20758820Seric { 20858820Seric printf("sendall(split): QDONTSEND "); 20958820Seric printaddr(&ee->e_from, FALSE); 21058820Seric } 21158820Seric ee->e_from.q_flags |= QDONTSEND; 21258820Seric ee->e_dfp = NULL; 21358820Seric ee->e_xfp = NULL; 21458820Seric ee->e_df = NULL; 21558820Seric ee->e_errormode = EM_MAIL; 21658820Seric ee->e_sibling = splitenv; 21758820Seric splitenv = ee; 21858820Seric 21958820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 22058820Seric if (q->q_owner == owner) 22158820Seric q->q_flags |= QDONTSEND; 22258820Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 22358820Seric if (q->q_owner != owner) 22458820Seric q->q_flags |= QDONTSEND; 22558820Seric 22658820Seric if (e->e_df != NULL && mode != SM_VERIFY) 22758820Seric { 22858820Seric ee->e_dfp = NULL; 22964086Seric ee->e_df = queuename(ee, 'd'); 23064086Seric ee->e_df = newstr(ee->e_df); 23158820Seric if (link(e->e_df, ee->e_df) < 0) 23258820Seric { 23358820Seric syserr("sendall: link(%s, %s)", 23458820Seric e->e_df, ee->e_df); 23558820Seric } 23658820Seric } 23758820Seric 23858820Seric if (mode != SM_VERIFY) 23958820Seric openxscript(ee); 24058820Seric #ifdef LOG 24158820Seric if (LogLevel > 4) 24258820Seric syslog(LOG_INFO, "%s: clone %s", 24358820Seric ee->e_id, e->e_id); 24458820Seric #endif 24558820Seric } 24658820Seric } 24758820Seric 24858820Seric if (owner != NULL) 24958820Seric { 25058820Seric setsender(owner, e, NULL, TRUE); 25158820Seric if (tTd(13, 5)) 25258820Seric { 25358820Seric printf("sendall(owner): QDONTSEND "); 25458820Seric printaddr(&e->e_from, FALSE); 25558820Seric } 25658820Seric e->e_from.q_flags |= QDONTSEND; 25758820Seric e->e_errormode = EM_MAIL; 25858820Seric } 25958820Seric 26058916Seric # ifdef QUEUE 26158916Seric if ((mode == SM_QUEUE || mode == SM_FORK || 26258916Seric (mode != SM_VERIFY && SuperSafe)) && 26358916Seric !bitset(EF_INQUEUE, e->e_flags)) 26458916Seric { 26558916Seric /* be sure everything is instantiated in the queue */ 26658929Seric queueup(e, TRUE, announcequeueup); 26758916Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 26858929Seric queueup(ee, TRUE, announcequeueup); 26958916Seric } 27058916Seric #endif /* QUEUE */ 27158916Seric 27258820Seric if (splitenv != NULL) 27358820Seric { 27458820Seric if (tTd(13, 1)) 27558820Seric { 27658820Seric printf("\nsendall: Split queue; remaining queue:\n"); 27758820Seric printaddr(e->e_sendqueue, TRUE); 27858820Seric } 27958820Seric 28058820Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 28158820Seric { 28258820Seric CurEnv = ee; 28358820Seric sendenvelope(ee, mode); 28458820Seric } 28558820Seric 28658820Seric CurEnv = e; 28758820Seric } 28858820Seric sendenvelope(e, mode); 28958820Seric 29058820Seric for (; splitenv != NULL; splitenv = splitenv->e_sibling) 29158820Seric dropenvelope(splitenv); 29258820Seric } 29358820Seric 29458820Seric sendenvelope(e, mode) 29558820Seric register ENVELOPE *e; 29658820Seric char mode; 29758820Seric { 29858916Seric bool oldverbose; 29958916Seric int pid; 30058820Seric register ADDRESS *q; 30164296Seric char *qf; 30264296Seric char *id; 30358820Seric 30463839Seric /* 30563839Seric ** If we have had global, fatal errors, don't bother sending 30663839Seric ** the message at all if we are in SMTP mode. Local errors 30763839Seric ** (e.g., a single address failing) will still cause the other 30863839Seric ** addresses to be sent. 30963839Seric */ 31063839Seric 31163839Seric if (bitset(EF_FATALERRS, e->e_flags) && OpMode == MD_SMTP) 31263839Seric { 31363839Seric e->e_flags |= EF_CLRQUEUE; 31463839Seric return; 31563839Seric } 31663839Seric 31758916Seric oldverbose = Verbose; 31858916Seric switch (mode) 31958916Seric { 32058916Seric case SM_VERIFY: 32158916Seric Verbose = TRUE; 32258916Seric break; 32358916Seric 32458916Seric case SM_QUEUE: 32558916Seric queueonly: 32658916Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 32758916Seric return; 32858916Seric 32958916Seric case SM_FORK: 33058916Seric if (e->e_xfp != NULL) 33158916Seric (void) fflush(e->e_xfp); 33258916Seric 33364035Seric # ifndef HASFLOCK 33458916Seric /* 33564296Seric ** Since fcntl locking has the interesting semantic that 33664296Seric ** the lock is owned by a process, not by an open file 33764296Seric ** descriptor, we have to flush this to the queue, and 33864296Seric ** then restart from scratch in the child. 33958916Seric */ 34058916Seric 34164296Seric /* save id for future use */ 34264296Seric id = e->e_id; 34358916Seric 34464296Seric /* now drop the envelope in the parent */ 34564296Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 34664296Seric dropenvelope(e); 34764296Seric 34864296Seric /* and reacquire in the child */ 34964296Seric (void) dowork(id, TRUE, FALSE, e); 35064296Seric 35164296Seric return; 35264296Seric 35364296Seric # else /* HASFLOCK */ 35464296Seric 35558916Seric pid = fork(); 35658916Seric if (pid < 0) 35758916Seric { 35858916Seric goto queueonly; 35958916Seric } 36058916Seric else if (pid > 0) 36158916Seric { 36264310Seric /* be sure we leave the temp files to our child */ 36364310Seric /* can't call unlockqueue to avoid unlink of xfp */ 36464310Seric if (e->e_lockfp != NULL) 36564310Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 36664310Seric e->e_lockfp = NULL; 36764310Seric 36864310Seric /* close any random open files in the envelope */ 36964310Seric closexscript(e); 37064310Seric if (e->e_dfp != NULL) 37164310Seric (void) xfclose(e->e_dfp, "sendenvelope", e->e_df); 37264310Seric e->e_dfp = NULL; 37364310Seric e->e_id = e->e_df = NULL; 37458916Seric return; 37558916Seric } 37658916Seric 37758916Seric /* double fork to avoid zombies */ 37858916Seric if (fork() > 0) 37958916Seric exit(EX_OK); 38058916Seric 38158916Seric /* be sure we are immune from the terminal */ 38263839Seric disconnect(1, e); 38358916Seric 38458916Seric /* 38558916Seric ** Close any cached connections. 38658916Seric ** 38758916Seric ** We don't send the QUIT protocol because the parent 38858916Seric ** still knows about the connection. 38958916Seric ** 39058916Seric ** This should only happen when delivering an error 39158916Seric ** message. 39258916Seric */ 39358916Seric 39458916Seric mci_flush(FALSE, NULL); 39558916Seric 39664296Seric # endif /* HASFLOCK */ 39764296Seric 39858916Seric break; 39958916Seric } 40058916Seric 40158820Seric /* 40258820Seric ** Run through the list and send everything. 40363965Seric ** 40463965Seric ** Set EF_GLOBALERRS so that error messages during delivery 40563965Seric ** result in returned mail. 40658820Seric */ 40758820Seric 40858820Seric e->e_nsent = 0; 40963965Seric e->e_flags |= EF_GLOBALERRS; 41064696Seric 41164696Seric /* now run through the queue */ 41258820Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 41358820Seric { 41464441Seric #ifdef XDEBUG 41564441Seric char wbuf[MAXNAME + 20]; 41664441Seric 41764441Seric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 41864441Seric checkfd012(wbuf); 41964441Seric #endif 42058820Seric if (mode == SM_VERIFY) 42158820Seric { 42258820Seric e->e_to = q->q_paddr; 42358820Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 42460173Seric { 42564942Seric if (q->q_host != NULL && q->q_host[0] != '\0') 42664942Seric message("deliverable: mailer %s, host %s, user %s", 42764942Seric q->q_mailer->m_name, 42864942Seric q->q_host, 42964942Seric q->q_user); 43064942Seric else 43164942Seric message("deliverable: mailer %s, user %s", 43264942Seric q->q_mailer->m_name, 43364942Seric q->q_user); 43460173Seric } 43558820Seric } 43658820Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 43758820Seric { 43858820Seric # ifdef QUEUE 43958820Seric /* 44058820Seric ** Checkpoint the send list every few addresses 44158820Seric */ 44258820Seric 44358820Seric if (e->e_nsent >= CheckpointInterval) 44458820Seric { 44558820Seric queueup(e, TRUE, FALSE); 44658820Seric e->e_nsent = 0; 44758820Seric } 44858820Seric # endif /* QUEUE */ 44958820Seric (void) deliver(e, q); 45058820Seric } 45158820Seric } 45258820Seric Verbose = oldverbose; 45358820Seric 45464441Seric #ifdef XDEBUG 45564441Seric checkfd012("end of sendenvelope"); 45664441Seric #endif 45764441Seric 45858820Seric if (mode == SM_FORK) 45958820Seric finis(); 46058820Seric } 46158820Seric /* 46258820Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 46358820Seric ** 46458820Seric ** This MUST be a macro, since after a vfork we are running 46558820Seric ** two processes on the same stack!!! 46658820Seric ** 46758820Seric ** Parameters: 46858820Seric ** none. 46958820Seric ** 47058820Seric ** Returns: 47158820Seric ** From a macro??? You've got to be kidding! 47258820Seric ** 47358820Seric ** Side Effects: 47458820Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 47558820Seric ** pid of child in parent, zero in child. 47658820Seric ** -1 on unrecoverable error. 47758820Seric ** 47858820Seric ** Notes: 47958820Seric ** I'm awfully sorry this looks so awful. That's 48058820Seric ** vfork for you..... 48158820Seric */ 48258820Seric 48358820Seric # define NFORKTRIES 5 48458820Seric 48558820Seric # ifndef FORK 48658820Seric # define FORK fork 48758820Seric # endif 48858820Seric 48958820Seric # define DOFORK(fORKfN) \ 49058820Seric {\ 49158820Seric register int i;\ 49258820Seric \ 49358820Seric for (i = NFORKTRIES; --i >= 0; )\ 49458820Seric {\ 49558820Seric pid = fORKfN();\ 49658820Seric if (pid >= 0)\ 49758820Seric break;\ 49858820Seric if (i > 0)\ 49958820Seric sleep((unsigned) NFORKTRIES - i);\ 50058820Seric }\ 50158820Seric } 50258820Seric /* 50358820Seric ** DOFORK -- simple fork interface to DOFORK. 50458820Seric ** 50558820Seric ** Parameters: 50658820Seric ** none. 50758820Seric ** 50858820Seric ** Returns: 50958820Seric ** pid of child in parent. 51058820Seric ** zero in child. 51158820Seric ** -1 on error. 51258820Seric ** 51358820Seric ** Side Effects: 51458820Seric ** returns twice, once in parent and once in child. 51558820Seric */ 51658820Seric 51758820Seric dofork() 51858820Seric { 51958820Seric register int pid; 52058820Seric 52158820Seric DOFORK(fork); 52258820Seric return (pid); 52358820Seric } 52458820Seric /* 5254315Seric ** DELIVER -- Deliver a message to a list of addresses. 526294Seric ** 5274315Seric ** This routine delivers to everyone on the same host as the 5284315Seric ** user on the head of the list. It is clever about mailers 5294315Seric ** that don't handle multiple users. It is NOT guaranteed 5304315Seric ** that it will deliver to all these addresses however -- so 5314315Seric ** deliver should be called once for each address on the 5324315Seric ** list. 5334315Seric ** 534294Seric ** Parameters: 5359370Seric ** e -- the envelope to deliver. 5364621Seric ** firstto -- head of the address list to deliver to. 537294Seric ** 538294Seric ** Returns: 539294Seric ** zero -- successfully delivered. 540294Seric ** else -- some failure, see ExitStat for more info. 541294Seric ** 542294Seric ** Side Effects: 543294Seric ** The standard input is passed off to someone. 544294Seric */ 545294Seric 5469370Seric deliver(e, firstto) 5479370Seric register ENVELOPE *e; 5484621Seric ADDRESS *firstto; 549294Seric { 5504452Seric char *host; /* host being sent to */ 5514452Seric char *user; /* user being sent to */ 552294Seric char **pvp; 5533233Seric register char **mvp; 5543233Seric register char *p; 55510306Seric register MAILER *m; /* mailer for this recipient */ 5564397Seric ADDRESS *ctladdr; 55754967Seric register MCI *mci; 5584621Seric register ADDRESS *to = firstto; 5594863Seric bool clever = FALSE; /* running user smtp to this mailer */ 5605032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 56151951Seric int rcode; /* response code */ 56257454Seric char *firstsig; /* signature of firstto */ 56358820Seric int pid; 56458820Seric char *curhost; 56558820Seric int mpvect[2]; 56658820Seric int rpvect[2]; 56710306Seric char *pv[MAXPV+1]; 56858704Seric char tobuf[TOBUFSIZE]; /* text line of to people */ 56910306Seric char buf[MAXNAME]; 57051951Seric char rpathbuf[MAXNAME]; /* translated return path */ 57157441Seric extern int checkcompat(); 57264718Seric extern char SmtpError[]; 573294Seric 5744488Seric errno = 0; 57558680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 5763233Seric return (0); 577294Seric 57835651Seric #ifdef NAMED_BIND 57934022Sbostic /* unless interactive, try twice, over a minute */ 58034022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 58134022Sbostic _res.retrans = 30; 58234022Sbostic _res.retry = 2; 58334022Sbostic } 58436788Sbostic #endif 58534022Sbostic 5866974Seric m = to->q_mailer; 5876974Seric host = to->q_host; 58858803Seric CurEnv = e; /* just in case */ 58959044Seric e->e_statmsg = NULL; 59064718Seric SmtpError[0] = '\0'; 5916974Seric 5927672Seric if (tTd(10, 1)) 5933233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 5946974Seric m->m_mno, host, to->q_user); 59564725Seric if (tTd(10, 100)) 59664725Seric printopenfds(FALSE); 597294Seric 598294Seric /* 5995903Seric ** If this mailer is expensive, and if we don't want to make 6005903Seric ** connections now, just mark these addresses and return. 6015903Seric ** This is useful if we want to batch connections to 6025903Seric ** reduce load. This will cause the messages to be 6035903Seric ** queued up, and a daemon will come along to send the 6045903Seric ** messages later. 6055903Seric ** This should be on a per-mailer basis. 6065903Seric */ 6075903Seric 60864658Seric if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 6095903Seric { 6105903Seric for (; to != NULL; to = to->q_next) 6118431Seric { 61258680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 61358247Seric to->q_mailer != m) 6148431Seric continue; 61563853Seric to->q_flags |= QQUEUEUP; 6169370Seric e->e_to = to->q_paddr; 61758151Seric message("queued"); 61858020Seric if (LogLevel > 8) 61964771Seric logdelivery(m, NULL, "queued", NULL, e); 6208431Seric } 6219370Seric e->e_to = NULL; 6225903Seric return (0); 6235903Seric } 6245903Seric 6255903Seric /* 6263233Seric ** Do initial argv setup. 6273233Seric ** Insert the mailer name. Notice that $x expansion is 6283233Seric ** NOT done on the mailer name. Then, if the mailer has 6293233Seric ** a picky -f flag, we insert it as appropriate. This 6303233Seric ** code does not check for 'pv' overflow; this places a 6313233Seric ** manifest lower limit of 4 for MAXPV. 6328062Seric ** The from address rewrite is expected to make 6338062Seric ** the address relative to the other end. 6342968Seric */ 6352968Seric 6364452Seric /* rewrite from address, using rewriting rules */ 63759163Seric rcode = EX_OK; 63859163Seric (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, 63959163Seric RF_SENDERADDR|RF_CANONICAL, 64059163Seric &rcode, e)); 64158680Seric define('g', rpathbuf, e); /* translated return path */ 6429370Seric define('h', host, e); /* to host */ 6433233Seric Errors = 0; 6443233Seric pvp = pv; 6453233Seric *pvp++ = m->m_argv[0]; 6462968Seric 6473233Seric /* insert -f or -r flag as appropriate */ 64810682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6493233Seric { 65010682Seric if (bitnset(M_FOPT, m->m_flags)) 6513233Seric *pvp++ = "-f"; 6523233Seric else 6533233Seric *pvp++ = "-r"; 65451951Seric *pvp++ = newstr(rpathbuf); 6553233Seric } 656294Seric 657294Seric /* 6583233Seric ** Append the other fixed parts of the argv. These run 6593233Seric ** up to the first entry containing "$u". There can only 6603233Seric ** be one of these, and there are only a few more slots 6613233Seric ** in the pv after it. 662294Seric */ 663294Seric 6643233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 665294Seric { 66658050Seric /* can't use strchr here because of sign extension problems */ 66758050Seric while (*p != '\0') 66858050Seric { 66958050Seric if ((*p++ & 0377) == MACROEXPAND) 67058050Seric { 67158050Seric if (*p == 'u') 67258050Seric break; 67358050Seric } 67458050Seric } 67558050Seric 67658050Seric if (*p != '\0') 6773233Seric break; 6783233Seric 6793233Seric /* this entry is safe -- go ahead and process it */ 6809370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 6813233Seric *pvp++ = newstr(buf); 6823233Seric if (pvp >= &pv[MAXPV - 3]) 6833233Seric { 68458151Seric syserr("554 Too many parameters to %s before $u", pv[0]); 6853233Seric return (-1); 6863233Seric } 687294Seric } 6884863Seric 6896038Seric /* 6906038Seric ** If we have no substitution for the user name in the argument 6916038Seric ** list, we know that we must supply the names otherwise -- and 6926038Seric ** SMTP is the answer!! 6936038Seric */ 6946038Seric 6953233Seric if (*mvp == NULL) 6964863Seric { 6974863Seric /* running SMTP */ 6985179Seric # ifdef SMTP 6994863Seric clever = TRUE; 7004863Seric *pvp = NULL; 70156795Seric # else /* SMTP */ 7026038Seric /* oops! we don't implement SMTP */ 70364718Seric syserr("554 SMTP style mailer not implemented"); 7045179Seric return (EX_SOFTWARE); 70556795Seric # endif /* SMTP */ 7064863Seric } 707294Seric 708294Seric /* 7093233Seric ** At this point *mvp points to the argument with $u. We 7103233Seric ** run through our address list and append all the addresses 7113233Seric ** we can. If we run out of space, do not fret! We can 7123233Seric ** always send another copy later. 713294Seric */ 714294Seric 7153233Seric tobuf[0] = '\0'; 7169370Seric e->e_to = tobuf; 7174397Seric ctladdr = NULL; 71857454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7193233Seric for (; to != NULL; to = to->q_next) 720294Seric { 7213233Seric /* avoid sending multiple recipients to dumb mailers */ 72210682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7233233Seric break; 7243233Seric 7253233Seric /* if already sent or not for this host, don't send */ 72658680Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 72757454Seric to->q_mailer != firstto->q_mailer || 72857454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7293233Seric continue; 7304397Seric 7318225Seric /* avoid overflowing tobuf */ 73242462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7338225Seric break; 7348225Seric 7357672Seric if (tTd(10, 1)) 7365032Seric { 7375032Seric printf("\nsend to "); 7385032Seric printaddr(to, FALSE); 7395032Seric } 7405032Seric 7414397Seric /* compute effective uid/gid when sending */ 7424596Seric if (to->q_mailer == ProgMailer) 7434397Seric ctladdr = getctladdr(to); 7444397Seric 7453233Seric user = to->q_user; 7469370Seric e->e_to = to->q_paddr; 74757731Seric if (tTd(10, 5)) 74857731Seric { 74957731Seric printf("deliver: QDONTSEND "); 75057731Seric printaddr(to, FALSE); 75157731Seric } 75258680Seric to->q_flags |= QDONTSEND; 7533233Seric 7543233Seric /* 7553233Seric ** Check to see that these people are allowed to 7563233Seric ** talk to each other. 7573233Seric */ 7583233Seric 75910699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 76010699Seric { 76129914Seric NoReturn = TRUE; 76258151Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 76364771Seric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, e); 76410699Seric continue; 76510699Seric } 76657441Seric rcode = checkcompat(to, e); 76757459Seric if (rcode != EX_OK) 768294Seric { 76963787Seric markfailure(e, to, rcode); 77064771Seric giveresponse(rcode, m, NULL, ctladdr, e); 7713233Seric continue; 772294Seric } 7733233Seric 7743233Seric /* 7754099Seric ** Strip quote bits from names if the mailer is dumb 7764099Seric ** about them. 7773233Seric */ 7783233Seric 77910682Seric if (bitnset(M_STRIPQ, m->m_flags)) 780294Seric { 78154983Seric stripquotes(user); 78254983Seric stripquotes(host); 7833233Seric } 7843233Seric 7859206Seric /* hack attack -- delivermail compatibility */ 7869206Seric if (m == ProgMailer && *user == '|') 7879206Seric user++; 7889206Seric 7893233Seric /* 7904161Seric ** If an error message has already been given, don't 7914161Seric ** bother to send to this address. 7924161Seric ** 7934161Seric ** >>>>>>>>>> This clause assumes that the local mailer 7944161Seric ** >> NOTE >> cannot do any further aliasing; that 7954161Seric ** >>>>>>>>>> function is subsumed by sendmail. 7964161Seric */ 7974161Seric 7987293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 7994161Seric continue; 8004161Seric 8014283Seric /* save statistics.... */ 8029370Seric markstats(e, to); 8034283Seric 8044161Seric /* 8053233Seric ** See if this user name is "special". 8063233Seric ** If the user name has a slash in it, assume that this 8076974Seric ** is a file -- send it off without further ado. Note 8086974Seric ** that this type of addresses is not processed along 8096974Seric ** with the others, so we fudge on the To person. 8103233Seric */ 8113233Seric 81257402Seric if (m == FileMailer) 8133233Seric { 81464771Seric ADDRESS *caddr = getctladdr(to); 81564771Seric 81664771Seric rcode = mailfile(user, caddr, e); 81764771Seric giveresponse(rcode, m, NULL, caddr, e); 81857402Seric if (rcode == EX_OK) 81957402Seric to->q_flags |= QSENT; 82057402Seric continue; 821294Seric } 8223233Seric 8234315Seric /* 8244315Seric ** Address is verified -- add this user to mailer 8254315Seric ** argv, and add it to the print list of recipients. 8264315Seric */ 8274315Seric 8286059Seric /* link together the chain of recipients */ 8296272Seric to->q_tchain = tochain; 8306272Seric tochain = to; 8316059Seric 8323233Seric /* create list of users for error messages */ 8339388Seric (void) strcat(tobuf, ","); 8344082Seric (void) strcat(tobuf, to->q_paddr); 8359370Seric define('u', user, e); /* to user */ 83664694Seric p = to->q_home; 83764694Seric if (p == NULL && ctladdr != NULL) 83864694Seric p = ctladdr->q_home; 83964694Seric define('z', p, e); /* user's home */ 8403233Seric 8414863Seric /* 8426059Seric ** Expand out this user into argument list. 8434863Seric */ 8444863Seric 8456059Seric if (!clever) 8463233Seric { 8479370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8484863Seric *pvp++ = newstr(buf); 8494863Seric if (pvp >= &pv[MAXPV - 2]) 8504863Seric { 8514863Seric /* allow some space for trailing parms */ 8524863Seric break; 8534863Seric } 8544863Seric } 855294Seric } 856294Seric 8574067Seric /* see if any addresses still exist */ 8584067Seric if (tobuf[0] == '\0') 8594863Seric { 8609370Seric define('g', (char *) NULL, e); 8614067Seric return (0); 8624863Seric } 8634067Seric 8643233Seric /* print out messages as full list */ 8659388Seric e->e_to = tobuf + 1; 8663233Seric 867294Seric /* 8683233Seric ** Fill out any parameters after the $u parameter. 869294Seric */ 870294Seric 8714863Seric while (!clever && *++mvp != NULL) 872294Seric { 8739370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8743233Seric *pvp++ = newstr(buf); 8753233Seric if (pvp >= &pv[MAXPV]) 87658151Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 877294Seric } 8783233Seric *pvp++ = NULL; 879294Seric 880294Seric /* 881294Seric ** Call the mailer. 8822898Seric ** The argument vector gets built, pipes 883294Seric ** are created as necessary, and we fork & exec as 8842898Seric ** appropriate. 8854863Seric ** If we are running SMTP, we just need to clean up. 886294Seric */ 887294Seric 88858309Seric if (ctladdr == NULL && m != ProgMailer) 88941050Seric ctladdr = &e->e_from; 89035651Seric #ifdef NAMED_BIND 89151313Seric if (ConfigLevel < 2) 89251313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 89335651Seric #endif 89454967Seric 8957672Seric if (tTd(11, 1)) 896294Seric { 8978178Seric printf("openmailer:"); 89858820Seric printav(pv); 899294Seric } 9004488Seric errno = 0; 9013233Seric 90225050Seric CurHostName = m->m_mailer; 90325050Seric 9046038Seric /* 9056038Seric ** Deal with the special case of mail handled through an IPC 9066038Seric ** connection. 9076038Seric ** In this case we don't actually fork. We must be 9086038Seric ** running SMTP for this to work. We will return a 9096038Seric ** zero pid to indicate that we are running IPC. 91011160Seric ** We also handle a debug version that just talks to stdin/out. 9116038Seric */ 9126038Seric 91358820Seric curhost = NULL; 91464334Seric SmtpPhase = NULL; 91564718Seric mci = NULL; 91658820Seric 91764401Seric #ifdef XDEBUG 91864401Seric { 91964401Seric char wbuf[MAXLINE]; 92064401Seric 92164401Seric /* make absolutely certain 0, 1, and 2 are in use */ 92264401Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 92364401Seric checkfd012(wbuf); 92464401Seric } 92564401Seric #endif 92664401Seric 92711160Seric /* check for Local Person Communication -- not for mortals!!! */ 92811160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 92911160Seric { 93054967Seric mci = (MCI *) xalloc(sizeof *mci); 93154993Seric bzero((char *) mci, sizeof *mci); 93253738Seric mci->mci_in = stdin; 93353738Seric mci->mci_out = stdout; 93454967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 93553751Seric mci->mci_mailer = m; 93611160Seric } 93754967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 93854967Seric strcmp(m->m_mailer, "[TCP]") == 0) 9396038Seric { 94052107Seric #ifdef DAEMON 94157454Seric register int i; 9427285Seric register u_short port; 9436038Seric 94464844Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 94564844Seric { 94664844Seric syserr("null host name for %s mailer", m->m_mailer); 94764844Seric rcode = EX_CONFIG; 94864844Seric goto give_up; 94964844Seric } 95064844Seric 95158820Seric CurHostName = pv[1]; 95258820Seric curhost = hostsignature(m, pv[1], e); 95354967Seric 95458479Seric if (curhost == NULL || curhost[0] == '\0') 95558479Seric { 95664844Seric syserr("null host signature for %s", pv[1]); 95758820Seric rcode = EX_OSERR; 95858820Seric goto give_up; 95958479Seric } 96058479Seric 9616038Seric if (!clever) 96258479Seric { 96358151Seric syserr("554 non-clever IPC"); 96464718Seric rcode = EX_CONFIG; 96558820Seric goto give_up; 96658479Seric } 96758820Seric if (pv[2] != NULL) 96858820Seric port = atoi(pv[2]); 9696632Seric else 9707285Seric port = 0; 97158820Seric tryhost: 97257454Seric while (*curhost != '\0') 97329433Sbloom { 97457454Seric register char *p; 97558664Seric static char hostbuf[MAXNAME]; 97657454Seric 97757454Seric /* pull the next host from the signature */ 97857454Seric p = strchr(curhost, ':'); 97957454Seric if (p == NULL) 98057454Seric p = &curhost[strlen(curhost)]; 98164718Seric if (p == curhost) 98264718Seric { 98364718Seric syserr("deliver: null host name in signature"); 98464726Seric curhost++; 98564718Seric continue; 98664718Seric } 98757454Seric strncpy(hostbuf, curhost, p - curhost); 98857454Seric hostbuf[p - curhost] = '\0'; 98957454Seric if (*p != '\0') 99057454Seric p++; 99157454Seric curhost = p; 99257454Seric 99353738Seric /* see if we already know that this host is fried */ 99457454Seric CurHostName = hostbuf; 99557454Seric mci = mci_get(hostbuf, m); 99654967Seric if (mci->mci_state != MCIS_CLOSED) 99757387Seric { 99857387Seric if (tTd(11, 1)) 99957387Seric { 100057387Seric printf("openmailer: "); 100164731Seric mci_dump(mci, FALSE); 100257387Seric } 100357943Seric CurHostName = mci->mci_host; 100458820Seric break; 100557387Seric } 100653751Seric mci->mci_mailer = m; 100754967Seric if (mci->mci_exitstat != EX_OK) 100854967Seric continue; 100954967Seric 101054967Seric /* try the connection */ 101157454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 101258151Seric message("Connecting to %s (%s)...", 101357454Seric hostbuf, m->m_name); 101457454Seric i = makeconnection(hostbuf, port, mci, 101554967Seric bitnset(M_SECURE_PORT, m->m_flags)); 101654967Seric mci->mci_exitstat = i; 101754967Seric mci->mci_errno = errno; 101863753Seric #ifdef NAMED_BIND 101963753Seric mci->mci_herrno = h_errno; 102063753Seric #endif 102154967Seric if (i == EX_OK) 102252106Seric { 102354967Seric mci->mci_state = MCIS_OPENING; 102454967Seric mci_cache(mci); 102563753Seric if (TrafficLogFile != NULL) 102663753Seric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 102763753Seric getpid(), hostbuf); 102854967Seric break; 102934022Sbostic } 103054967Seric else if (tTd(11, 1)) 103154967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 103254967Seric i, errno); 103353738Seric 103453738Seric /* enter status of this host */ 103553738Seric setstat(i); 103664718Seric 103764718Seric /* should print some message here for -v mode */ 10386047Seric } 103964718Seric if (mci == NULL) 104064718Seric { 104164718Seric syserr("deliver: no host name"); 104264718Seric rcode = EX_OSERR; 104364718Seric goto give_up; 104464718Seric } 104554993Seric mci->mci_pid = 0; 104654967Seric #else /* no DAEMON */ 104758151Seric syserr("554 openmailer: no IPC"); 104857387Seric if (tTd(11, 1)) 104957387Seric printf("openmailer: NULL\n"); 105064718Seric rcode = EX_UNAVAILABLE; 105164718Seric goto give_up; 105254967Seric #endif /* DAEMON */ 10536038Seric } 105454967Seric else 1055294Seric { 105663753Seric if (TrafficLogFile != NULL) 105758852Seric { 105863753Seric char **av; 105958925Seric 106063753Seric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 106163753Seric for (av = pv; *av != NULL; av++) 106263753Seric fprintf(TrafficLogFile, " %s", *av); 106363753Seric fprintf(TrafficLogFile, "\n"); 106458852Seric } 106558852Seric 106654967Seric /* create a pipe to shove the mail through */ 106754967Seric if (pipe(mpvect) < 0) 106854967Seric { 106958925Seric syserr("%s... openmailer(%s): pipe (to mailer)", 107058925Seric e->e_to, m->m_name); 107157387Seric if (tTd(11, 1)) 107257387Seric printf("openmailer: NULL\n"); 107358820Seric rcode = EX_OSERR; 107458820Seric goto give_up; 107554967Seric } 10764863Seric 107754967Seric /* if this mailer speaks smtp, create a return pipe */ 107854967Seric if (clever && pipe(rpvect) < 0) 107954967Seric { 108058925Seric syserr("%s... openmailer(%s): pipe (from mailer)", 108158925Seric e->e_to, m->m_name); 108254967Seric (void) close(mpvect[0]); 108354967Seric (void) close(mpvect[1]); 108457387Seric if (tTd(11, 1)) 108557387Seric printf("openmailer: NULL\n"); 108658820Seric rcode = EX_OSERR; 108758820Seric goto give_up; 108854967Seric } 10894863Seric 109054967Seric /* 109154967Seric ** Actually fork the mailer process. 109254967Seric ** DOFORK is clever about retrying. 109354967Seric ** 109454967Seric ** Dispose of SIGCHLD signal catchers that may be laying 109554967Seric ** around so that endmail will get it. 109654967Seric */ 10976038Seric 109854967Seric if (e->e_xfp != NULL) 109954967Seric (void) fflush(e->e_xfp); /* for debugging */ 110054967Seric (void) fflush(stdout); 110126434Seric # ifdef SIGCHLD 110264035Seric (void) setsignal(SIGCHLD, SIG_DFL); 110356795Seric # endif /* SIGCHLD */ 110454967Seric DOFORK(FORK); 110554967Seric /* pid is set by DOFORK */ 110654967Seric if (pid < 0) 11074863Seric { 110854967Seric /* failure */ 110958925Seric syserr("%s... openmailer(%s): cannot fork", 111058925Seric e->e_to, m->m_name); 111154967Seric (void) close(mpvect[0]); 111254967Seric (void) close(mpvect[1]); 111354967Seric if (clever) 111454967Seric { 111554967Seric (void) close(rpvect[0]); 111654967Seric (void) close(rpvect[1]); 111754967Seric } 111857387Seric if (tTd(11, 1)) 111957387Seric printf("openmailer: NULL\n"); 112058820Seric rcode = EX_OSERR; 112158820Seric goto give_up; 11224863Seric } 112354967Seric else if (pid == 0) 112454967Seric { 112554967Seric int i; 112656678Seric int saveerrno; 112758675Seric char **ep; 112858675Seric char *env[MAXUSERENVIRON]; 112958675Seric extern char **environ; 113054967Seric extern int DtableSize; 113115772Seric 113254967Seric /* child -- set up input & exec mailer */ 113364035Seric (void) setsignal(SIGINT, SIG_IGN); 113464035Seric (void) setsignal(SIGHUP, SIG_IGN); 113564035Seric (void) setsignal(SIGTERM, SIG_DFL); 11364709Seric 113764145Seric /* reset user and group */ 113864145Seric if (!bitnset(M_RESTR, m->m_flags)) 113964145Seric { 114064145Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 114164145Seric { 114264145Seric (void) initgroups(DefUser, DefGid); 114364837Seric (void) setgid(DefGid); 114464145Seric (void) setuid(DefUid); 114564145Seric } 114664145Seric else 114764145Seric { 114864145Seric (void) initgroups(ctladdr->q_ruser? 114964145Seric ctladdr->q_ruser: ctladdr->q_user, 115064145Seric ctladdr->q_gid); 115164970Seric (void) setgid(ctladdr->q_gid); 115264145Seric (void) setuid(ctladdr->q_uid); 115364145Seric } 115464145Seric } 115564145Seric 115664145Seric if (tTd(11, 2)) 115764145Seric printf("openmailer: running as r/euid=%d/%d\n", 115864145Seric getuid(), geteuid()); 115964145Seric 116058935Seric /* move into some "safe" directory */ 116158935Seric if (m->m_execdir != NULL) 116258935Seric { 116358935Seric char *p, *q; 116458935Seric char buf[MAXLINE]; 116558935Seric 116658935Seric for (p = m->m_execdir; p != NULL; p = q) 116758935Seric { 116858935Seric q = strchr(p, ':'); 116958935Seric if (q != NULL) 117058935Seric *q = '\0'; 117158935Seric expand(p, buf, &buf[sizeof buf] - 1, e); 117258935Seric if (q != NULL) 117358935Seric *q++ = ':'; 117458935Seric if (tTd(11, 20)) 117558935Seric printf("openmailer: trydir %s\n", 117658935Seric buf); 117758935Seric if (buf[0] != '\0' && chdir(buf) >= 0) 117858935Seric break; 117958935Seric } 118058935Seric } 118158935Seric 118254967Seric /* arrange to filter std & diag output of command */ 118354967Seric if (clever) 118454967Seric { 118554967Seric (void) close(rpvect[0]); 118658852Seric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 118758852Seric { 118858925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 118958925Seric e->e_to, m->m_name, rpvect[1]); 119058852Seric _exit(EX_OSERR); 119158852Seric } 119254967Seric (void) close(rpvect[1]); 119354967Seric } 119454967Seric else if (OpMode == MD_SMTP || HoldErrs) 119554967Seric { 119654967Seric /* put mailer output in transcript */ 119758852Seric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 119858852Seric { 119958925Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 120058925Seric e->e_to, m->m_name, 120158852Seric fileno(e->e_xfp)); 120258852Seric _exit(EX_OSERR); 120358852Seric } 120454967Seric } 120558852Seric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 120658852Seric { 120758925Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 120858925Seric e->e_to, m->m_name); 120958852Seric _exit(EX_OSERR); 121058852Seric } 12114709Seric 121254967Seric /* arrange to get standard input */ 121354967Seric (void) close(mpvect[1]); 121458731Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 12154417Seric { 121658925Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 121758925Seric e->e_to, m->m_name, mpvect[0]); 121854967Seric _exit(EX_OSERR); 12194417Seric } 122054967Seric (void) close(mpvect[0]); 12219370Seric 122254967Seric /* arrange for all the files to be closed */ 122354967Seric for (i = 3; i < DtableSize; i++) 122454967Seric { 122554967Seric register int j; 122664145Seric 122754967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 122864145Seric (void) fcntl(i, F_SETFD, j | 1); 122954967Seric } 12302774Seric 123158675Seric /* set up the mailer environment */ 123258675Seric i = 0; 123358675Seric env[i++] = "AGENT=sendmail"; 123458675Seric for (ep = environ; *ep != NULL; ep++) 123558675Seric { 123658675Seric if (strncmp(*ep, "TZ=", 3) == 0) 123758675Seric env[i++] = *ep; 123858675Seric } 123958675Seric env[i++] = NULL; 124058675Seric 124154967Seric /* try to execute the mailer */ 124258820Seric execve(m->m_mailer, pv, env); 124356678Seric saveerrno = errno; 124454967Seric syserr("Cannot exec %s", m->m_mailer); 124560008Seric if (m == LocalMailer || transienterror(saveerrno)) 124660008Seric _exit(EX_OSERR); 124754967Seric _exit(EX_UNAVAILABLE); 124851835Seric } 124954967Seric 125054967Seric /* 125154967Seric ** Set up return value. 125254967Seric */ 125354967Seric 125454967Seric mci = (MCI *) xalloc(sizeof *mci); 125554993Seric bzero((char *) mci, sizeof *mci); 125654967Seric mci->mci_mailer = m; 125754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 125854993Seric mci->mci_pid = pid; 125954967Seric (void) close(mpvect[0]); 126054967Seric mci->mci_out = fdopen(mpvect[1], "w"); 126164724Seric if (mci->mci_out == NULL) 126264724Seric { 126364724Seric syserr("deliver: cannot create mailer output channel, fd=%d", 126464724Seric mpvect[1]); 126564724Seric (void) close(mpvect[1]); 126664724Seric if (clever) 126764724Seric { 126864724Seric (void) close(rpvect[0]); 126964724Seric (void) close(rpvect[1]); 127064724Seric } 127164724Seric rcode = EX_OSERR; 127264724Seric goto give_up; 127364724Seric } 127454967Seric if (clever) 127554967Seric { 127654967Seric (void) close(rpvect[1]); 127754967Seric mci->mci_in = fdopen(rpvect[0], "r"); 127864724Seric if (mci->mci_in == NULL) 127964724Seric { 128064724Seric syserr("deliver: cannot create mailer input channel, fd=%d", 128164724Seric mpvect[1]); 128264724Seric (void) close(rpvect[0]); 128364724Seric fclose(mci->mci_out); 128464724Seric mci->mci_out = NULL; 128564724Seric rcode = EX_OSERR; 128664724Seric goto give_up; 128764724Seric } 128854967Seric } 128954967Seric else 129054967Seric { 129154967Seric mci->mci_flags |= MCIF_TEMP; 129254967Seric mci->mci_in = NULL; 129354967Seric } 1294294Seric } 1295294Seric 12964709Seric /* 129754967Seric ** If we are in SMTP opening state, send initial protocol. 12984709Seric */ 12994709Seric 130054967Seric if (clever && mci->mci_state != MCIS_CLOSED) 13014863Seric { 130254967Seric smtpinit(m, mci, e); 130353738Seric } 130457387Seric if (tTd(11, 1)) 130557387Seric { 130657387Seric printf("openmailer: "); 130764731Seric mci_dump(mci, FALSE); 130857387Seric } 1309294Seric 131058820Seric if (mci->mci_state != MCIS_OPEN) 131158820Seric { 131258820Seric /* couldn't open the mailer */ 131358820Seric rcode = mci->mci_exitstat; 131458820Seric errno = mci->mci_errno; 131563753Seric #ifdef NAMED_BIND 131663753Seric h_errno = mci->mci_herrno; 131763753Seric #endif 131858820Seric if (rcode == EX_OK) 131958820Seric { 132058820Seric /* shouldn't happen */ 132158820Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 132258820Seric rcode, mci->mci_state, firstsig); 132358820Seric rcode = EX_SOFTWARE; 132458820Seric } 132564922Seric else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') 132659958Seric { 132759958Seric /* try next MX site */ 132859958Seric goto tryhost; 132959958Seric } 133058820Seric } 133158820Seric else if (!clever) 133258820Seric { 133358820Seric /* 133458820Seric ** Format and send message. 133558820Seric */ 133658820Seric 133758820Seric putfromline(mci->mci_out, m, e); 133858820Seric (*e->e_puthdr)(mci->mci_out, m, e); 133958820Seric putline("\n", mci->mci_out, m); 134059730Seric (*e->e_putbody)(mci->mci_out, m, e, NULL); 134158820Seric 134258820Seric /* get the exit status */ 134358820Seric rcode = endmailer(mci, e, pv); 134458820Seric } 134558820Seric else 134658820Seric #ifdef SMTP 134758820Seric { 134858820Seric /* 134958820Seric ** Send the MAIL FROM: protocol 135058820Seric */ 135158820Seric 135258820Seric rcode = smtpmailfrom(m, mci, e); 135358820Seric if (rcode == EX_OK) 135458820Seric { 135558820Seric register char *t = tobuf; 135658820Seric register int i; 135758820Seric 135858820Seric /* send the recipient list */ 135958820Seric tobuf[0] = '\0'; 136058820Seric for (to = tochain; to != NULL; to = to->q_tchain) 136158820Seric { 136258820Seric e->e_to = to->q_paddr; 136358820Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 136458820Seric { 136558820Seric markfailure(e, to, i); 136664771Seric giveresponse(i, m, mci, ctladdr, e); 136758820Seric } 136858820Seric else 136958820Seric { 137058820Seric *t++ = ','; 137158820Seric for (p = to->q_paddr; *p; *t++ = *p++) 137258820Seric continue; 137364372Seric *t = '\0'; 137458820Seric } 137558820Seric } 137658820Seric 137758820Seric /* now send the data */ 137858820Seric if (tobuf[0] == '\0') 137958820Seric { 138058820Seric rcode = EX_OK; 138158820Seric e->e_to = NULL; 138258820Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 138358820Seric smtprset(m, mci, e); 138458820Seric } 138558820Seric else 138658820Seric { 138758820Seric e->e_to = tobuf + 1; 138858820Seric rcode = smtpdata(m, mci, e); 138958820Seric } 139058820Seric 139158820Seric /* now close the connection */ 139258820Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 139358820Seric smtpquit(m, mci, e); 139458820Seric } 139564922Seric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 139658820Seric { 139758820Seric /* try next MX site */ 139858820Seric goto tryhost; 139958820Seric } 140058820Seric } 140158820Seric #else /* not SMTP */ 140258820Seric { 140358820Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 140458820Seric rcode = EX_CONFIG; 140558820Seric goto give_up; 140658820Seric } 140758820Seric #endif /* SMTP */ 140858820Seric #ifdef NAMED_BIND 140958820Seric if (ConfigLevel < 2) 141058820Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 141158820Seric #endif 141258820Seric 141358820Seric /* arrange a return receipt if requested */ 141464718Seric if (rcode == EX_OK && e->e_receiptto != NULL && 141564718Seric bitnset(M_LOCALMAILER, m->m_flags)) 141658820Seric { 141758820Seric e->e_flags |= EF_SENDRECEIPT; 141858820Seric /* do we want to send back more info? */ 141958820Seric } 142058820Seric 142158820Seric /* 142258820Seric ** Do final status disposal. 142358820Seric ** We check for something in tobuf for the SMTP case. 142458820Seric ** If we got a temporary failure, arrange to queue the 142558820Seric ** addressees. 142658820Seric */ 142758820Seric 142858820Seric give_up: 142958820Seric if (tobuf[0] != '\0') 143064771Seric giveresponse(rcode, m, mci, ctladdr, e); 143158820Seric for (to = tochain; to != NULL; to = to->q_tchain) 143258820Seric { 143358820Seric if (rcode != EX_OK) 143458820Seric markfailure(e, to, rcode); 143558820Seric else 143658820Seric { 143758820Seric to->q_flags |= QSENT; 143858820Seric e->e_nsent++; 143964718Seric if (e->e_receiptto != NULL && 144064718Seric bitnset(M_LOCALMAILER, m->m_flags)) 144164718Seric { 144264718Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 144364718Seric to->q_paddr); 144464718Seric } 144558820Seric } 144658820Seric } 144758820Seric 144858820Seric /* 144958820Seric ** Restore state and return. 145058820Seric */ 145158820Seric 145264401Seric #ifdef XDEBUG 145364401Seric { 145464401Seric char wbuf[MAXLINE]; 145564401Seric 145664401Seric /* make absolutely certain 0, 1, and 2 are in use */ 145764554Seric sprintf(wbuf, "%s... end of deliver(%s)", 145864554Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 145964554Seric m->m_name); 146064401Seric checkfd012(wbuf); 146164401Seric } 146264401Seric #endif 146364401Seric 146458820Seric errno = 0; 146558820Seric define('g', (char *) NULL, e); 146658820Seric return (rcode); 1467294Seric } 1468294Seric /* 146958820Seric ** MARKFAILURE -- mark a failure on a specific address. 147058820Seric ** 147158820Seric ** Parameters: 147258820Seric ** e -- the envelope we are sending. 147358820Seric ** q -- the address to mark. 147458820Seric ** rcode -- the code signifying the particular failure. 147558820Seric ** 147658820Seric ** Returns: 147758820Seric ** none. 147858820Seric ** 147958820Seric ** Side Effects: 148058820Seric ** marks the address (and possibly the envelope) with the 148158820Seric ** failure so that an error will be returned or 148258820Seric ** the message will be queued, as appropriate. 148358820Seric */ 148458820Seric 148558820Seric markfailure(e, q, rcode) 148658820Seric register ENVELOPE *e; 148758820Seric register ADDRESS *q; 148858820Seric int rcode; 148958820Seric { 149058820Seric char buf[MAXLINE]; 149158820Seric 149258820Seric if (rcode == EX_OK) 149358820Seric return; 149463753Seric else if (rcode == EX_TEMPFAIL) 149563753Seric q->q_flags |= QQUEUEUP; 149663753Seric else if (rcode != EX_IOERR && rcode != EX_OSERR) 149758820Seric q->q_flags |= QBADADDR; 149858820Seric } 149958820Seric /* 150058820Seric ** ENDMAILER -- Wait for mailer to terminate. 150158820Seric ** 150258820Seric ** We should never get fatal errors (e.g., segmentation 150358820Seric ** violation), so we report those specially. For other 150458820Seric ** errors, we choose a status message (into statmsg), 150558820Seric ** and if it represents an error, we print it. 150658820Seric ** 150758820Seric ** Parameters: 150858820Seric ** pid -- pid of mailer. 150958820Seric ** e -- the current envelope. 151058820Seric ** pv -- the parameter vector that invoked the mailer 151158820Seric ** (for error messages). 151258820Seric ** 151358820Seric ** Returns: 151458820Seric ** exit code of mailer. 151558820Seric ** 151658820Seric ** Side Effects: 151758820Seric ** none. 151858820Seric */ 151958820Seric 152058820Seric endmailer(mci, e, pv) 152158820Seric register MCI *mci; 152258820Seric register ENVELOPE *e; 152358820Seric char **pv; 152458820Seric { 152558820Seric int st; 152658820Seric 152758820Seric /* close any connections */ 152858820Seric if (mci->mci_in != NULL) 152958820Seric (void) xfclose(mci->mci_in, pv[0], "mci_in"); 153058820Seric if (mci->mci_out != NULL) 153158820Seric (void) xfclose(mci->mci_out, pv[0], "mci_out"); 153258820Seric mci->mci_in = mci->mci_out = NULL; 153358820Seric mci->mci_state = MCIS_CLOSED; 153458820Seric 153558820Seric /* in the IPC case there is nothing to wait for */ 153658820Seric if (mci->mci_pid == 0) 153758820Seric return (EX_OK); 153858820Seric 153958820Seric /* wait for the mailer process to die and collect status */ 154058820Seric st = waitfor(mci->mci_pid); 154158820Seric if (st == -1) 154258820Seric { 154358820Seric syserr("endmailer %s: wait", pv[0]); 154458820Seric return (EX_SOFTWARE); 154558820Seric } 154658820Seric 154764379Seric if (WIFEXITED(st)) 154858820Seric { 154964379Seric /* normal death -- return status */ 155064379Seric return (WEXITSTATUS(st)); 155164379Seric } 155258820Seric 155364379Seric /* it died a horrid death */ 155464379Seric syserr("mailer %s died with signal %o", pv[0], st); 155558820Seric 155664379Seric /* log the arguments */ 155764379Seric if (e->e_xfp != NULL) 155864379Seric { 155964379Seric register char **av; 156058820Seric 156164379Seric fprintf(e->e_xfp, "Arguments:"); 156264379Seric for (av = pv; *av != NULL; av++) 156364379Seric fprintf(e->e_xfp, " %s", *av); 156464379Seric fprintf(e->e_xfp, "\n"); 156558820Seric } 156658820Seric 156764379Seric ExitStat = EX_TEMPFAIL; 156864379Seric return (EX_TEMPFAIL); 156958820Seric } 157058820Seric /* 1571294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1572294Seric ** 1573294Seric ** Parameters: 1574294Seric ** stat -- the status code from the mailer (high byte 1575294Seric ** only; core dumps must have been taken care of 1576294Seric ** already). 157758337Seric ** m -- the mailer info for this mailer. 157858337Seric ** mci -- the mailer connection info -- can be NULL if the 157958337Seric ** response is given before the connection is made. 158064771Seric ** ctladdr -- the controlling address for the recipient 158164771Seric ** address(es). 158258337Seric ** e -- the current envelope. 1583294Seric ** 1584294Seric ** Returns: 15854082Seric ** none. 1586294Seric ** 1587294Seric ** Side Effects: 15881518Seric ** Errors may be incremented. 1589294Seric ** ExitStat may be set. 1590294Seric */ 1591294Seric 159264771Seric giveresponse(stat, m, mci, ctladdr, e) 1593294Seric int stat; 15949370Seric register MAILER *m; 159558337Seric register MCI *mci; 159664771Seric ADDRESS *ctladdr; 159710105Seric ENVELOPE *e; 1598294Seric { 159960094Seric register const char *statmsg; 1600294Seric extern char *SysExMsg[]; 1601294Seric register int i; 160236788Sbostic extern int N_SysEx; 160310105Seric char buf[MAXLINE]; 1604294Seric 16054315Seric /* 16064315Seric ** Compute status message from code. 16074315Seric */ 16084315Seric 1609294Seric i = stat - EX__BASE; 16109370Seric if (stat == 0) 161158852Seric { 16129370Seric statmsg = "250 Sent"; 161358916Seric if (e->e_statmsg != NULL) 161458852Seric { 161558916Seric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 161658852Seric statmsg = buf; 161758852Seric } 161858852Seric } 16199370Seric else if (i < 0 || i > N_SysEx) 16209370Seric { 16219370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 16229370Seric stat = EX_UNAVAILABLE; 16239370Seric statmsg = buf; 16249370Seric } 162510105Seric else if (stat == EX_TEMPFAIL) 162610105Seric { 162758664Seric (void) strcpy(buf, SysExMsg[i] + 1); 162836788Sbostic #ifdef NAMED_BIND 162925527Smiriam if (h_errno == TRY_AGAIN) 163063993Seric statmsg = errstring(h_errno+E_DNSBASE); 163121061Seric else 163236788Sbostic #endif 163321061Seric { 163425527Smiriam if (errno != 0) 163525527Smiriam statmsg = errstring(errno); 163625527Smiriam else 163725527Smiriam { 163821061Seric #ifdef SMTP 163925527Smiriam extern char SmtpError[]; 164021061Seric 164125527Smiriam statmsg = SmtpError; 164256795Seric #else /* SMTP */ 164325527Smiriam statmsg = NULL; 164456795Seric #endif /* SMTP */ 164525527Smiriam } 164621061Seric } 164721061Seric if (statmsg != NULL && statmsg[0] != '\0') 164821061Seric { 164910124Seric (void) strcat(buf, ": "); 165021061Seric (void) strcat(buf, statmsg); 165110105Seric } 165210105Seric statmsg = buf; 165310105Seric } 165463753Seric #ifdef NAMED_BIND 165563753Seric else if (stat == EX_NOHOST && h_errno != 0) 165663753Seric { 165763993Seric statmsg = errstring(h_errno + E_DNSBASE); 165863753Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i], statmsg); 165963753Seric statmsg = buf; 166063753Seric } 166163753Seric #endif 1662294Seric else 166321061Seric { 1664294Seric statmsg = SysExMsg[i]; 166558664Seric if (*statmsg++ == ':') 166658664Seric { 166758664Seric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 166858664Seric statmsg = buf; 166958664Seric } 167021061Seric } 16719370Seric 16729370Seric /* 16739370Seric ** Print the message as appropriate 16749370Seric */ 16759370Seric 167610105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 167764718Seric { 167864718Seric extern char MsgBuf[]; 167964718Seric 168058524Seric message(&statmsg[4], errstring(errno)); 168164718Seric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 168264718Seric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 168364718Seric } 1684294Seric else 1685294Seric { 16861518Seric Errors++; 168758524Seric usrerr(statmsg, errstring(errno)); 1688294Seric } 1689294Seric 1690294Seric /* 1691294Seric ** Final cleanup. 1692294Seric ** Log a record of the transaction. Compute the new 1693294Seric ** ExitStat -- if we already had an error, stick with 1694294Seric ** that. 1695294Seric */ 1696294Seric 169758020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 169864771Seric logdelivery(m, mci, &statmsg[4], ctladdr, e); 16997858Seric 17004621Seric if (stat != EX_TEMPFAIL) 17014621Seric setstat(stat); 170264952Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 170310105Seric { 170410105Seric if (e->e_message != NULL) 170510105Seric free(e->e_message); 170610105Seric e->e_message = newstr(&statmsg[4]); 170710105Seric } 170810124Seric errno = 0; 170936788Sbostic #ifdef NAMED_BIND 171025527Smiriam h_errno = 0; 171136788Sbostic #endif 1712294Seric } 1713294Seric /* 17148496Seric ** LOGDELIVERY -- log the delivery in the system log 17158496Seric ** 171664969Seric ** Care is taken to avoid logging lines that are too long, because 171764969Seric ** some versions of syslog have an unfortunate proclivity for core 171864969Seric ** dumping. This is a hack, to be sure, that is at best empirical. 171964969Seric ** 17208496Seric ** Parameters: 172158337Seric ** m -- the mailer info. Can be NULL for initial queue. 172258337Seric ** mci -- the mailer connection info -- can be NULL if the 172358337Seric ** log is occuring when no connection is active. 172458337Seric ** stat -- the message to print for the status. 172564771Seric ** ctladdr -- the controlling address for the to list. 172658337Seric ** e -- the current envelope. 17278496Seric ** 17288496Seric ** Returns: 17298496Seric ** none 17308496Seric ** 17318496Seric ** Side Effects: 17328496Seric ** none 17338496Seric */ 17348496Seric 173564969Seric #ifndef SYSLOG_BUFSIZE 173664969Seric # define SYSLOG_BUFSIZE 1024 173764969Seric #endif 173864969Seric 173964771Seric logdelivery(m, mci, stat, ctladdr, e) 174058337Seric MAILER *m; 174158337Seric register MCI *mci; 17428496Seric char *stat; 174364771Seric ADDRESS *ctladdr; 174454967Seric register ENVELOPE *e; 17458496Seric { 174658343Seric # ifdef LOG 174764771Seric register char *bp; 174864969Seric register char *p; 174964969Seric int l; 175058418Seric char buf[512]; 17518496Seric 175264771Seric bp = buf; 175364771Seric if (ctladdr != NULL) 175464771Seric { 175564771Seric strcpy(bp, ", ctladdr="); 175664969Seric l = strlen(ctladdr->q_paddr); 175764969Seric if (l > 83) 175864969Seric sprintf(bp, "%.40s...%s", 175964969Seric ctladdr->q_paddr, ctladdr->q_paddr + l - 40); 176064969Seric else 176164969Seric strcat(bp, ctladdr->q_paddr); 176264771Seric bp += strlen(bp); 176364771Seric if (bitset(QGOODUID, ctladdr->q_flags)) 176464771Seric { 176564771Seric (void) sprintf(bp, " (%d/%d)", 176664771Seric ctladdr->q_uid, ctladdr->q_gid); 176764771Seric bp += strlen(bp); 176864771Seric } 176964771Seric } 177058337Seric 177164771Seric (void) sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 177264771Seric bp += strlen(bp); 177364771Seric 177458513Seric if (m != NULL) 177558305Seric { 177664771Seric (void) strcpy(bp, ", mailer="); 177764771Seric (void) strcat(bp, m->m_name); 177864771Seric bp += strlen(bp); 177958305Seric } 178058513Seric 178158513Seric if (mci != NULL && mci->mci_host != NULL) 178258305Seric { 178358305Seric # ifdef DAEMON 178458755Seric extern SOCKADDR CurHostAddr; 178558513Seric # endif 178658305Seric 178764771Seric (void) strcpy(bp, ", relay="); 178864771Seric (void) strcat(bp, mci->mci_host); 178958513Seric 179058513Seric # ifdef DAEMON 179164771Seric (void) strcat(bp, " ("); 179264771Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 179364771Seric (void) strcat(bp, ")"); 179458305Seric # endif 179558305Seric } 179658343Seric else 179758513Seric { 179858513Seric char *p = macvalue('h', e); 179958343Seric 180058513Seric if (p != NULL && p[0] != '\0') 180158513Seric { 180264771Seric (void) strcpy(bp, ", relay="); 180364771Seric (void) strcat(bp, p); 180458513Seric } 180558513Seric } 180664922Seric bp += strlen(bp); 180764969Seric 180864969Seric if ((bp - buf) > (sizeof buf - 220)) 180964969Seric { 181064969Seric /* desperation move -- truncate data */ 181164969Seric bp = buf + sizeof buf - 217; 181264969Seric strcpy(bp, "..."); 181364969Seric bp += 3; 181464969Seric } 181564969Seric 181664969Seric (void) strcpy(bp, ", stat="); 181764969Seric bp += strlen(bp); 181864969Seric l = strlen(stat); 181964969Seric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 8) 182064969Seric #if (STATLEN) < 30 182164969Seric # undef STATLEN 182264969Seric # define STATLEN 30 182364969Seric #endif 182464969Seric #if (STATLEN) > 100 182564969Seric # undef STATLEN 182664969Seric # define STATLEN 100 182764969Seric #endif 182864969Seric if (l > (STATLEN * 2 + 3)) 182964969Seric sprintf(bp, "%.*s...%s", STATLEN, stat, stat + l - STATLEN); 183064969Seric else 183164969Seric (void) strcpy(bp, stat); 183258418Seric 183364969Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 183464969Seric p = e->e_to; 183564969Seric while (strlen(p) >= l) 183664969Seric { 183764969Seric register char *q = strchr(p + l, ','); 183864969Seric 1839*65008Seric if (q == NULL) 184064969Seric break; 184164969Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 184264969Seric e->e_id, ++q - p, p, buf); 184364969Seric p = q; 184464969Seric } 184564969Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 184656795Seric # endif /* LOG */ 18478496Seric } 18488496Seric /* 18496974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1850294Seric ** 18516974Seric ** This can be made an arbitrary message separator by changing $l 1852294Seric ** 185316150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 185416150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 185516150Seric ** does a well-meaning programmer such as myself have to deal with 185616150Seric ** this kind of antique garbage???? 18576974Seric ** 1858294Seric ** Parameters: 18596974Seric ** fp -- the file to output to. 18606974Seric ** m -- the mailer describing this entry. 1861294Seric ** 1862294Seric ** Returns: 18636974Seric ** none 1864294Seric ** 1865294Seric ** Side Effects: 18666974Seric ** outputs some text to fp. 1867294Seric */ 1868294Seric 186954967Seric putfromline(fp, m, e) 18706974Seric register FILE *fp; 18716974Seric register MAILER *m; 187254967Seric ENVELOPE *e; 1873294Seric { 187458050Seric char *template = "\201l\n"; 18756974Seric char buf[MAXLINE]; 1876294Seric 187710682Seric if (bitnset(M_NHDR, m->m_flags)) 18786974Seric return; 18794315Seric 18806974Seric # ifdef UGLYUUCP 188110682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 18824205Seric { 188312223Seric char *bang; 188412223Seric char xbuf[MAXLINE]; 18856041Seric 188658680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 188756795Seric bang = strchr(buf, '!'); 18886974Seric if (bang == NULL) 188964370Seric { 189064370Seric errno = 0; 189164370Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 189264370Seric } 18935099Seric else 18949370Seric { 189512223Seric *bang++ = '\0'; 189658050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 189712223Seric template = xbuf; 18989370Seric } 18996974Seric } 190056795Seric # endif /* UGLYUUCP */ 190154967Seric expand(template, buf, &buf[sizeof buf - 1], e); 190210168Seric putline(buf, fp, m); 19035981Seric } 19045981Seric /* 19056974Seric ** PUTBODY -- put the body of a message. 19066974Seric ** 19076974Seric ** Parameters: 19086974Seric ** fp -- file to output onto. 190910168Seric ** m -- a mailer descriptor to control output format. 19109538Seric ** e -- the envelope to put out. 191159730Seric ** separator -- if non-NULL, a message separator that must 191259730Seric ** not be permitted in the resulting message. 19136974Seric ** 19146974Seric ** Returns: 19156974Seric ** none. 19166974Seric ** 19176974Seric ** Side Effects: 19186974Seric ** The message is written onto fp. 19196974Seric */ 19206974Seric 192159730Seric putbody(fp, m, e, separator) 19226974Seric FILE *fp; 19239370Seric MAILER *m; 19249538Seric register ENVELOPE *e; 192559730Seric char *separator; 19266974Seric { 192710168Seric char buf[MAXLINE]; 19286974Seric 19296974Seric /* 19306974Seric ** Output the body of the message 19316974Seric */ 19326974Seric 19339538Seric if (e->e_dfp == NULL) 19346974Seric { 19359538Seric if (e->e_df != NULL) 19369538Seric { 19379538Seric e->e_dfp = fopen(e->e_df, "r"); 19389538Seric if (e->e_dfp == NULL) 193940931Srick syserr("putbody: Cannot open %s for %s from %s", 194064118Seric e->e_df, e->e_to, e->e_from.q_paddr); 19419538Seric } 19429538Seric else 194310168Seric putline("<<< No Message Collected >>>", fp, m); 19449538Seric } 19459538Seric if (e->e_dfp != NULL) 19469538Seric { 19479538Seric rewind(e->e_dfp); 194810168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 194916875Seric { 195016875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 195140995Sbostic strncmp(buf, "From ", 5) == 0) 195223102Seric (void) putc('>', fp); 195359730Seric if (buf[0] == '-' && buf[1] == '-' && separator != NULL) 195459730Seric { 195559730Seric /* possible separator */ 195659730Seric int sl = strlen(separator); 195759730Seric 195859730Seric if (strncmp(&buf[2], separator, sl) == 0) 195959730Seric (void) putc(' ', fp); 196059730Seric } 196110168Seric putline(buf, fp, m); 196216875Seric } 19636974Seric 19649538Seric if (ferror(e->e_dfp)) 19656974Seric { 196664718Seric syserr("putbody: %s: read error", e->e_df); 19676974Seric ExitStat = EX_IOERR; 19686974Seric } 19696974Seric } 19706974Seric 197159542Seric /* some mailers want extra blank line at end of message */ 197259542Seric if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n') 197359542Seric putline("", fp, m); 197459542Seric 19756974Seric (void) fflush(fp); 19766974Seric if (ferror(fp) && errno != EPIPE) 19776974Seric { 19786974Seric syserr("putbody: write error"); 19796974Seric ExitStat = EX_IOERR; 19806974Seric } 19816974Seric errno = 0; 19826974Seric } 19836974Seric /* 1984294Seric ** MAILFILE -- Send a message to a file. 1985294Seric ** 19864327Seric ** If the file has the setuid/setgid bits set, but NO execute 19874327Seric ** bits, sendmail will try to become the owner of that file 19884327Seric ** rather than the real user. Obviously, this only works if 19894327Seric ** sendmail runs as root. 19904327Seric ** 19919370Seric ** This could be done as a subordinate mailer, except that it 19929370Seric ** is used implicitly to save messages in ~/dead.letter. We 19939370Seric ** view this as being sufficiently important as to include it 19949370Seric ** here. For example, if the system is dying, we shouldn't have 19959370Seric ** to create another process plus some pipes to save the message. 19969370Seric ** 1997294Seric ** Parameters: 1998294Seric ** filename -- the name of the file to send to. 19994397Seric ** ctladdr -- the controlling address header -- includes 20004397Seric ** the userid/groupid to be when sending. 2001294Seric ** 2002294Seric ** Returns: 2003294Seric ** The exit code associated with the operation. 2004294Seric ** 2005294Seric ** Side Effects: 2006294Seric ** none. 2007294Seric */ 2008294Seric 200954967Seric mailfile(filename, ctladdr, e) 2010294Seric char *filename; 20114397Seric ADDRESS *ctladdr; 201254967Seric register ENVELOPE *e; 2013294Seric { 2014294Seric register FILE *f; 20154214Seric register int pid; 201653751Seric int mode; 2017294Seric 201859267Seric if (tTd(11, 1)) 201959267Seric { 202059267Seric printf("mailfile %s\n ctladdr=", filename); 202159267Seric printaddr(ctladdr, FALSE); 202259267Seric } 202359267Seric 202463753Seric if (e->e_xfp != NULL) 202563753Seric fflush(e->e_xfp); 202663753Seric 20274214Seric /* 20284214Seric ** Fork so we can change permissions here. 20294214Seric ** Note that we MUST use fork, not vfork, because of 20304214Seric ** the complications of calling subroutines, etc. 20314214Seric */ 20324067Seric 20334214Seric DOFORK(fork); 20344214Seric 20354214Seric if (pid < 0) 20364214Seric return (EX_OSERR); 20374214Seric else if (pid == 0) 20384214Seric { 20394214Seric /* child -- actually write to file */ 20404327Seric struct stat stb; 20414327Seric 204264035Seric (void) setsignal(SIGINT, SIG_DFL); 204364035Seric (void) setsignal(SIGHUP, SIG_DFL); 204464035Seric (void) setsignal(SIGTERM, SIG_DFL); 204523102Seric (void) umask(OldUmask); 204652673Seric 20474327Seric if (stat(filename, &stb) < 0) 204859745Seric stb.st_mode = FileMode; 204953751Seric mode = stb.st_mode; 205052673Seric 205152673Seric /* limit the errors to those actually caused in the child */ 205252673Seric errno = 0; 205352673Seric ExitStat = EX_OK; 205452673Seric 20554327Seric if (bitset(0111, stb.st_mode)) 20564327Seric exit(EX_CANTCREAT); 205764823Seric if (ctladdr != NULL) 205853751Seric { 205953751Seric /* ignore setuid and setgid bits */ 206053751Seric mode &= ~(S_ISGID|S_ISUID); 206153751Seric } 206253751Seric 206340931Srick /* we have to open the dfile BEFORE setuid */ 206453751Seric if (e->e_dfp == NULL && e->e_df != NULL) 206540931Srick { 206640931Srick e->e_dfp = fopen(e->e_df, "r"); 206752673Seric if (e->e_dfp == NULL) 206852673Seric { 206940931Srick syserr("mailfile: Cannot open %s for %s from %s", 207064118Seric e->e_df, e->e_to, e->e_from.q_paddr); 207140931Srick } 207240931Srick } 207340931Srick 207453751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 20754417Seric { 207664823Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 207752673Seric { 207840972Sbostic (void) initgroups(DefUser, DefGid); 207952673Seric } 208052673Seric else 208152673Seric { 208253751Seric (void) initgroups(ctladdr->q_ruser ? 208353751Seric ctladdr->q_ruser : ctladdr->q_user, 208440972Sbostic ctladdr->q_gid); 208540972Sbostic } 20864417Seric } 208753751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 20884417Seric { 208964823Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 20904417Seric (void) setuid(DefUid); 20914417Seric else 20924417Seric (void) setuid(ctladdr->q_uid); 20934417Seric } 209452673Seric FileName = filename; 209552673Seric LineNumber = 0; 209659745Seric f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); 20974214Seric if (f == NULL) 209852673Seric { 209964387Seric message("554 cannot open: %s", errstring(errno)); 21004214Seric exit(EX_CANTCREAT); 210152673Seric } 21024214Seric 210359275Seric putfromline(f, FileMailer, e); 210459275Seric (*e->e_puthdr)(f, FileMailer, e); 210559275Seric putline("\n", f, FileMailer); 210659730Seric (*e->e_putbody)(f, FileMailer, e, NULL); 210759275Seric putline("\n", f, FileMailer); 210852673Seric if (ferror(f)) 210952673Seric { 211064387Seric message("451 I/O error: %s", errstring(errno)); 211152673Seric setstat(EX_IOERR); 211252673Seric } 211358680Seric (void) xfclose(f, "mailfile", filename); 21144214Seric (void) fflush(stdout); 21154417Seric 21166887Seric /* reset ISUID & ISGID bits for paranoid systems */ 21174621Seric (void) chmod(filename, (int) stb.st_mode); 211852673Seric exit(ExitStat); 21194315Seric /*NOTREACHED*/ 21204214Seric } 21214214Seric else 21224214Seric { 21234214Seric /* parent -- wait for exit status */ 21249370Seric int st; 21254214Seric 21269370Seric st = waitfor(pid); 212764379Seric if (WIFEXITED(st)) 212864379Seric return (WEXITSTATUS(st)); 212964379Seric else 213064387Seric { 213164387Seric syserr("child died on signal %d", st); 21329370Seric return (EX_UNAVAILABLE); 213364387Seric } 213440931Srick /*NOTREACHED*/ 21354214Seric } 2136294Seric } 21374550Seric /* 213857454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 213957454Seric ** 214057454Seric ** The signature describes how we are going to send this -- it 214157454Seric ** can be just the hostname (for non-Internet hosts) or can be 214257454Seric ** an ordered list of MX hosts. 214357454Seric ** 214457454Seric ** Parameters: 214557454Seric ** m -- the mailer describing this host. 214657454Seric ** host -- the host name. 214757454Seric ** e -- the current envelope. 214857454Seric ** 214957454Seric ** Returns: 215057454Seric ** The signature for this host. 215157454Seric ** 215257454Seric ** Side Effects: 215357454Seric ** Can tweak the symbol table. 215457454Seric */ 215557454Seric 215657454Seric char * 215757454Seric hostsignature(m, host, e) 215857454Seric register MAILER *m; 215957454Seric char *host; 216057454Seric ENVELOPE *e; 216157454Seric { 216257454Seric register char *p; 216357454Seric register STAB *s; 216457454Seric int i; 216557454Seric int len; 216657454Seric #ifdef NAMED_BIND 216757454Seric int nmx; 216857454Seric auto int rcode; 216959076Seric char *hp; 217059076Seric char *endp; 217159111Seric int oldoptions; 217257454Seric char *mxhosts[MAXMXHOSTS + 1]; 217357454Seric #endif 217457454Seric 217557454Seric /* 217657454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 217757454Seric */ 217857454Seric 217957454Seric p = m->m_mailer; 218057454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 218157454Seric { 218257454Seric /* just an ordinary mailer */ 218357454Seric return host; 218457454Seric } 218557454Seric 218657454Seric /* 218757454Seric ** Look it up in the symbol table. 218857454Seric */ 218957454Seric 219057454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 219157454Seric if (s->s_hostsig != NULL) 219257454Seric return s->s_hostsig; 219357454Seric 219457454Seric /* 219557454Seric ** Not already there -- create a signature. 219657454Seric */ 219757454Seric 219857454Seric #ifdef NAMED_BIND 219959111Seric if (ConfigLevel < 2) 220059111Seric { 220159111Seric oldoptions = _res.options; 220259111Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 220359111Seric } 220459111Seric 220559076Seric for (hp = host; hp != NULL; hp = endp) 220657454Seric { 220759076Seric endp = strchr(hp, ':'); 220859076Seric if (endp != NULL) 220959076Seric *endp = '\0'; 221057454Seric 221159273Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 221257454Seric 221359076Seric if (nmx <= 0) 221459076Seric { 221559076Seric register MCI *mci; 221657454Seric 221759076Seric /* update the connection info for this host */ 221859076Seric mci = mci_get(hp, m); 221959076Seric mci->mci_exitstat = rcode; 222059076Seric mci->mci_errno = errno; 222163753Seric #ifdef NAMED_BIND 222263753Seric mci->mci_herrno = h_errno; 222363753Seric #endif 222459076Seric 222559076Seric /* and return the original host name as the signature */ 222659076Seric nmx = 1; 222759076Seric mxhosts[0] = hp; 222859076Seric } 222959076Seric 223059076Seric len = 0; 223159076Seric for (i = 0; i < nmx; i++) 223259076Seric { 223359076Seric len += strlen(mxhosts[i]) + 1; 223459076Seric } 223559076Seric if (s->s_hostsig != NULL) 223659076Seric len += strlen(s->s_hostsig) + 1; 223759076Seric p = xalloc(len); 223859076Seric if (s->s_hostsig != NULL) 223959076Seric { 224059076Seric (void) strcpy(p, s->s_hostsig); 224159076Seric free(s->s_hostsig); 224259076Seric s->s_hostsig = p; 224359076Seric p += strlen(p); 224457454Seric *p++ = ':'; 224559076Seric } 224659076Seric else 224759076Seric s->s_hostsig = p; 224859076Seric for (i = 0; i < nmx; i++) 224959076Seric { 225059076Seric if (i != 0) 225159076Seric *p++ = ':'; 225259076Seric strcpy(p, mxhosts[i]); 225359076Seric p += strlen(p); 225459076Seric } 225559076Seric if (endp != NULL) 225659076Seric *endp++ = ':'; 225757454Seric } 225857454Seric makelower(s->s_hostsig); 225959111Seric if (ConfigLevel < 2) 226059111Seric _res.options = oldoptions; 226157454Seric #else 226257454Seric /* not using BIND -- the signature is just the host name */ 226357454Seric s->s_hostsig = host; 226457454Seric #endif 226557454Seric if (tTd(17, 1)) 226657454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 226757454Seric return s->s_hostsig; 226857454Seric } 2269