1c2aa98e2SPeter Wemm /* 2602a2b1bSGregory Neil Shapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 14c2aa98e2SPeter Wemm #ifndef lint 15602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.66 2001/02/25 23:30:35 gshapiro Exp $"; 1606f25ae9SGregory Neil Shapiro #endif /* ! lint */ 17c2aa98e2SPeter Wemm 1806f25ae9SGregory Neil Shapiro #include <sendmail.h> 1906f25ae9SGregory Neil Shapiro 20c2aa98e2SPeter Wemm 21c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT 22c2aa98e2SPeter Wemm # include <login_cap.h> 2306f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 2406f25ae9SGregory Neil Shapiro 2506f25ae9SGregory Neil Shapiro #if STARTTLS || (SASL && SFIO) 2606f25ae9SGregory Neil Shapiro # include "sfsasl.h" 2706f25ae9SGregory Neil Shapiro #endif /* STARTTLS || (SASL && SFIO) */ 2806f25ae9SGregory Neil Shapiro 2906f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *)); 3006f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 3106f25ae9SGregory Neil Shapiro static void mailfiletimeout __P((void)); 3206f25ae9SGregory Neil Shapiro static void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool)); 3306f25ae9SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *)); 3406f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int)); 3506f25ae9SGregory Neil Shapiro static char *hostsignature __P((MAILER *, char *)); 36c2aa98e2SPeter Wemm 37c2aa98e2SPeter Wemm #if SMTP 3806f25ae9SGregory Neil Shapiro # if STARTTLS 3906f25ae9SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *)); 4006f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 4106f25ae9SGregory Neil Shapiro #endif /* SMTP */ 42c2aa98e2SPeter Wemm 43c2aa98e2SPeter Wemm /* 44c2aa98e2SPeter Wemm ** SENDALL -- actually send all the messages. 45c2aa98e2SPeter Wemm ** 46c2aa98e2SPeter Wemm ** Parameters: 47c2aa98e2SPeter Wemm ** e -- the envelope to send. 48c2aa98e2SPeter Wemm ** mode -- the delivery mode to use. If SM_DEFAULT, use 49c2aa98e2SPeter Wemm ** the current e->e_sendmode. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** Returns: 52c2aa98e2SPeter Wemm ** none. 53c2aa98e2SPeter Wemm ** 54c2aa98e2SPeter Wemm ** Side Effects: 55c2aa98e2SPeter Wemm ** Scans the send lists and sends everything it finds. 56c2aa98e2SPeter Wemm ** Delivers any appropriate error messages. 57c2aa98e2SPeter Wemm ** If we are running in a non-interactive mode, takes the 58c2aa98e2SPeter Wemm ** appropriate action. 59c2aa98e2SPeter Wemm */ 60c2aa98e2SPeter Wemm 61c2aa98e2SPeter Wemm void 62c2aa98e2SPeter Wemm sendall(e, mode) 63c2aa98e2SPeter Wemm ENVELOPE *e; 64c2aa98e2SPeter Wemm int mode; 65c2aa98e2SPeter Wemm { 66c2aa98e2SPeter Wemm register ADDRESS *q; 67c2aa98e2SPeter Wemm char *owner; 68c2aa98e2SPeter Wemm int otherowners; 6906f25ae9SGregory Neil Shapiro int save_errno; 70c2aa98e2SPeter Wemm register ENVELOPE *ee; 71c2aa98e2SPeter Wemm ENVELOPE *splitenv = NULL; 72c2aa98e2SPeter Wemm int oldverbose = Verbose; 73c2aa98e2SPeter Wemm bool somedeliveries = FALSE, expensive = FALSE; 74c2aa98e2SPeter Wemm pid_t pid; 75c2aa98e2SPeter Wemm 76c2aa98e2SPeter Wemm /* 77c2aa98e2SPeter Wemm ** If this message is to be discarded, don't bother sending 78c2aa98e2SPeter Wemm ** the message at all. 79c2aa98e2SPeter Wemm */ 80c2aa98e2SPeter Wemm 81c2aa98e2SPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 82c2aa98e2SPeter Wemm { 83c2aa98e2SPeter Wemm if (tTd(13, 1)) 8406f25ae9SGregory Neil Shapiro dprintf("sendall: discarding id %s\n", e->e_id); 85c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 86c2aa98e2SPeter Wemm if (LogLevel > 4) 87c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "discarded"); 88c2aa98e2SPeter Wemm markstats(e, NULL, TRUE); 89c2aa98e2SPeter Wemm return; 90c2aa98e2SPeter Wemm } 91c2aa98e2SPeter Wemm 92c2aa98e2SPeter Wemm /* 93c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 94c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 95c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 96c2aa98e2SPeter Wemm ** addresses to be sent. 97c2aa98e2SPeter Wemm */ 98c2aa98e2SPeter Wemm 99c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 100c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 101c2aa98e2SPeter Wemm { 102c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 103c2aa98e2SPeter Wemm return; 104c2aa98e2SPeter Wemm } 105c2aa98e2SPeter Wemm 106c2aa98e2SPeter Wemm /* determine actual delivery mode */ 107c2aa98e2SPeter Wemm if (mode == SM_DEFAULT) 108c2aa98e2SPeter Wemm { 109c2aa98e2SPeter Wemm mode = e->e_sendmode; 110c2aa98e2SPeter Wemm if (mode != SM_VERIFY && mode != SM_DEFER && 111c2aa98e2SPeter Wemm shouldqueue(e->e_msgpriority, e->e_ctime)) 112c2aa98e2SPeter Wemm mode = SM_QUEUE; 113c2aa98e2SPeter Wemm } 114c2aa98e2SPeter Wemm 115c2aa98e2SPeter Wemm if (tTd(13, 1)) 116c2aa98e2SPeter Wemm { 11706f25ae9SGregory Neil Shapiro dprintf("\n===== SENDALL: mode %c, id %s, e_from ", 118c2aa98e2SPeter Wemm mode, e->e_id); 119c2aa98e2SPeter Wemm printaddr(&e->e_from, FALSE); 12006f25ae9SGregory Neil Shapiro dprintf("\te_flags = "); 121c2aa98e2SPeter Wemm printenvflags(e); 12206f25ae9SGregory Neil Shapiro dprintf("sendqueue:\n"); 123c2aa98e2SPeter Wemm printaddr(e->e_sendqueue, TRUE); 124c2aa98e2SPeter Wemm } 125c2aa98e2SPeter Wemm 126c2aa98e2SPeter Wemm /* 127c2aa98e2SPeter Wemm ** Do any preprocessing necessary for the mode we are running. 128c2aa98e2SPeter Wemm ** Check to make sure the hop count is reasonable. 129c2aa98e2SPeter Wemm ** Delete sends to the sender in mailing lists. 130c2aa98e2SPeter Wemm */ 131c2aa98e2SPeter Wemm 132c2aa98e2SPeter Wemm CurEnv = e; 133c2aa98e2SPeter Wemm if (tTd(62, 1)) 134c2aa98e2SPeter Wemm checkfds(NULL); 135c2aa98e2SPeter Wemm 136c2aa98e2SPeter Wemm if (e->e_hopcount > MaxHopCount) 137c2aa98e2SPeter Wemm { 138c2aa98e2SPeter Wemm errno = 0; 139c2aa98e2SPeter Wemm #if QUEUE 140c2aa98e2SPeter Wemm queueup(e, mode == SM_QUEUE || mode == SM_DEFER); 14106f25ae9SGregory Neil Shapiro #endif /* QUEUE */ 142c2aa98e2SPeter Wemm e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 14306f25ae9SGregory Neil Shapiro ExitStat = EX_UNAVAILABLE; 14406f25ae9SGregory Neil Shapiro syserr("554 5.0.0 Too many hops %d (%d max): from %s via %s, to %s", 145c2aa98e2SPeter Wemm e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 146c2aa98e2SPeter Wemm RealHostName == NULL ? "localhost" : RealHostName, 147c2aa98e2SPeter Wemm e->e_sendqueue->q_paddr); 14806f25ae9SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14906f25ae9SGregory Neil Shapiro { 15006f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 15106f25ae9SGregory Neil Shapiro continue; 15206f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 15306f25ae9SGregory Neil Shapiro q->q_status = "5.4.6"; 15406f25ae9SGregory Neil Shapiro } 155c2aa98e2SPeter Wemm return; 156c2aa98e2SPeter Wemm } 157c2aa98e2SPeter Wemm 158c2aa98e2SPeter Wemm /* 159c2aa98e2SPeter Wemm ** Do sender deletion. 160c2aa98e2SPeter Wemm ** 16106f25ae9SGregory Neil Shapiro ** If the sender should be queued up, skip this. 162c2aa98e2SPeter Wemm ** This can happen if the name server is hosed when you 163c2aa98e2SPeter Wemm ** are trying to send mail. The result is that the sender 164c2aa98e2SPeter Wemm ** is instantiated in the queue as a recipient. 165c2aa98e2SPeter Wemm */ 166c2aa98e2SPeter Wemm 167c2aa98e2SPeter Wemm if (!bitset(EF_METOO, e->e_flags) && 16806f25ae9SGregory Neil Shapiro !QS_IS_QUEUEUP(e->e_from.q_state)) 169c2aa98e2SPeter Wemm { 170c2aa98e2SPeter Wemm if (tTd(13, 5)) 171c2aa98e2SPeter Wemm { 17206f25ae9SGregory Neil Shapiro dprintf("sendall: QS_SENDER "); 173c2aa98e2SPeter Wemm printaddr(&e->e_from, FALSE); 174c2aa98e2SPeter Wemm } 17506f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 176c2aa98e2SPeter Wemm (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 177c2aa98e2SPeter Wemm } 178c2aa98e2SPeter Wemm 179c2aa98e2SPeter Wemm /* 180c2aa98e2SPeter Wemm ** Handle alias owners. 181c2aa98e2SPeter Wemm ** 182c2aa98e2SPeter Wemm ** We scan up the q_alias chain looking for owners. 183c2aa98e2SPeter Wemm ** We discard owners that are the same as the return path. 184c2aa98e2SPeter Wemm */ 185c2aa98e2SPeter Wemm 186c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 187c2aa98e2SPeter Wemm { 188c2aa98e2SPeter Wemm register struct address *a; 189c2aa98e2SPeter Wemm 190c2aa98e2SPeter Wemm for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 191c2aa98e2SPeter Wemm continue; 192c2aa98e2SPeter Wemm if (a != NULL) 193c2aa98e2SPeter Wemm q->q_owner = a->q_owner; 194c2aa98e2SPeter Wemm 195c2aa98e2SPeter Wemm if (q->q_owner != NULL && 19606f25ae9SGregory Neil Shapiro !QS_IS_DEAD(q->q_state) && 197c2aa98e2SPeter Wemm strcmp(q->q_owner, e->e_from.q_paddr) == 0) 198c2aa98e2SPeter Wemm q->q_owner = NULL; 199c2aa98e2SPeter Wemm } 200c2aa98e2SPeter Wemm 201c2aa98e2SPeter Wemm if (tTd(13, 25)) 202c2aa98e2SPeter Wemm { 20306f25ae9SGregory Neil Shapiro dprintf("\nAfter first owner pass, sendq =\n"); 204c2aa98e2SPeter Wemm printaddr(e->e_sendqueue, TRUE); 205c2aa98e2SPeter Wemm } 206c2aa98e2SPeter Wemm 207c2aa98e2SPeter Wemm owner = ""; 208c2aa98e2SPeter Wemm otherowners = 1; 209c2aa98e2SPeter Wemm while (owner != NULL && otherowners > 0) 210c2aa98e2SPeter Wemm { 211c2aa98e2SPeter Wemm if (tTd(13, 28)) 21206f25ae9SGregory Neil Shapiro dprintf("owner = \"%s\", otherowners = %d\n", 213c2aa98e2SPeter Wemm owner, otherowners); 214c2aa98e2SPeter Wemm owner = NULL; 215c2aa98e2SPeter Wemm otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; 216c2aa98e2SPeter Wemm 217c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 218c2aa98e2SPeter Wemm { 219c2aa98e2SPeter Wemm if (tTd(13, 30)) 220c2aa98e2SPeter Wemm { 22106f25ae9SGregory Neil Shapiro dprintf("Checking "); 222c2aa98e2SPeter Wemm printaddr(q, FALSE); 223c2aa98e2SPeter Wemm } 22406f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 225c2aa98e2SPeter Wemm { 226c2aa98e2SPeter Wemm if (tTd(13, 30)) 22706f25ae9SGregory Neil Shapiro dprintf(" ... QS_IS_DEAD\n"); 228c2aa98e2SPeter Wemm continue; 229c2aa98e2SPeter Wemm } 230c2aa98e2SPeter Wemm if (tTd(13, 29) && !tTd(13, 30)) 231c2aa98e2SPeter Wemm { 23206f25ae9SGregory Neil Shapiro dprintf("Checking "); 233c2aa98e2SPeter Wemm printaddr(q, FALSE); 234c2aa98e2SPeter Wemm } 235c2aa98e2SPeter Wemm 236c2aa98e2SPeter Wemm if (q->q_owner != NULL) 237c2aa98e2SPeter Wemm { 238c2aa98e2SPeter Wemm if (owner == NULL) 239c2aa98e2SPeter Wemm { 240c2aa98e2SPeter Wemm if (tTd(13, 40)) 24106f25ae9SGregory Neil Shapiro dprintf(" ... First owner = \"%s\"\n", 242c2aa98e2SPeter Wemm q->q_owner); 243c2aa98e2SPeter Wemm owner = q->q_owner; 244c2aa98e2SPeter Wemm } 245c2aa98e2SPeter Wemm else if (owner != q->q_owner) 246c2aa98e2SPeter Wemm { 247c2aa98e2SPeter Wemm if (strcmp(owner, q->q_owner) == 0) 248c2aa98e2SPeter Wemm { 249c2aa98e2SPeter Wemm if (tTd(13, 40)) 25006f25ae9SGregory Neil Shapiro dprintf(" ... Same owner = \"%s\"\n", 251c2aa98e2SPeter Wemm owner); 252c2aa98e2SPeter Wemm 253c2aa98e2SPeter Wemm /* make future comparisons cheap */ 254c2aa98e2SPeter Wemm q->q_owner = owner; 255c2aa98e2SPeter Wemm } 256c2aa98e2SPeter Wemm else 257c2aa98e2SPeter Wemm { 258c2aa98e2SPeter Wemm if (tTd(13, 40)) 25906f25ae9SGregory Neil Shapiro dprintf(" ... Another owner \"%s\"\n", 260c2aa98e2SPeter Wemm q->q_owner); 261c2aa98e2SPeter Wemm otherowners++; 262c2aa98e2SPeter Wemm } 263c2aa98e2SPeter Wemm owner = q->q_owner; 264c2aa98e2SPeter Wemm } 265c2aa98e2SPeter Wemm else if (tTd(13, 40)) 26606f25ae9SGregory Neil Shapiro dprintf(" ... Same owner = \"%s\"\n", 267c2aa98e2SPeter Wemm owner); 268c2aa98e2SPeter Wemm } 269c2aa98e2SPeter Wemm else 270c2aa98e2SPeter Wemm { 271c2aa98e2SPeter Wemm if (tTd(13, 40)) 27206f25ae9SGregory Neil Shapiro dprintf(" ... Null owner\n"); 273c2aa98e2SPeter Wemm otherowners++; 274c2aa98e2SPeter Wemm } 275c2aa98e2SPeter Wemm 27606f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(q->q_state)) 27706f25ae9SGregory Neil Shapiro { 27806f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 27906f25ae9SGregory Neil Shapiro dprintf(" ... QS_IS_BADADDR\n"); 28006f25ae9SGregory Neil Shapiro continue; 28106f25ae9SGregory Neil Shapiro } 28206f25ae9SGregory Neil Shapiro 28306f25ae9SGregory Neil Shapiro if (QS_IS_QUEUEUP(q->q_state)) 28406f25ae9SGregory Neil Shapiro { 28506f25ae9SGregory Neil Shapiro MAILER *m = q->q_mailer; 28606f25ae9SGregory Neil Shapiro 28706f25ae9SGregory Neil Shapiro /* 28806f25ae9SGregory Neil Shapiro ** If we have temporary address failures 28906f25ae9SGregory Neil Shapiro ** (e.g., dns failure) and a fallback MX is 29006f25ae9SGregory Neil Shapiro ** set, send directly to the fallback MX host. 29106f25ae9SGregory Neil Shapiro */ 29206f25ae9SGregory Neil Shapiro 29306f25ae9SGregory Neil Shapiro if (FallBackMX != NULL && 29406f25ae9SGregory Neil Shapiro !wordinclass(FallBackMX, 'w') && 29506f25ae9SGregory Neil Shapiro mode != SM_VERIFY && 29606f25ae9SGregory Neil Shapiro (strcmp(m->m_mailer, "[IPC]") == 0 || 29706f25ae9SGregory Neil Shapiro strcmp(m->m_mailer, "[TCP]") == 0) && 29806f25ae9SGregory Neil Shapiro m->m_argv[0] != NULL && 29906f25ae9SGregory Neil Shapiro (strcmp(m->m_argv[0], "TCP") == 0 || 30006f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "IPC") == 0)) 30106f25ae9SGregory Neil Shapiro { 30206f25ae9SGregory Neil Shapiro int len; 30306f25ae9SGregory Neil Shapiro char *p; 30406f25ae9SGregory Neil Shapiro 30506f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 30606f25ae9SGregory Neil Shapiro dprintf(" ... FallBackMX\n"); 30706f25ae9SGregory Neil Shapiro 30806f25ae9SGregory Neil Shapiro len = strlen(FallBackMX) + 3; 30906f25ae9SGregory Neil Shapiro p = xalloc(len); 31006f25ae9SGregory Neil Shapiro snprintf(p, len, "[%s]", FallBackMX); 31106f25ae9SGregory Neil Shapiro q->q_state = QS_OK; 31206f25ae9SGregory Neil Shapiro q->q_host = p; 31306f25ae9SGregory Neil Shapiro } 31406f25ae9SGregory Neil Shapiro else 31506f25ae9SGregory Neil Shapiro { 31606f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 31706f25ae9SGregory Neil Shapiro dprintf(" ... QS_IS_QUEUEUP\n"); 31806f25ae9SGregory Neil Shapiro continue; 31906f25ae9SGregory Neil Shapiro } 32006f25ae9SGregory Neil Shapiro } 32106f25ae9SGregory Neil Shapiro 322c2aa98e2SPeter Wemm /* 323c2aa98e2SPeter Wemm ** If this mailer is expensive, and if we don't 324c2aa98e2SPeter Wemm ** want to make connections now, just mark these 325c2aa98e2SPeter Wemm ** addresses and return. This is useful if we 326c2aa98e2SPeter Wemm ** want to batch connections to reduce load. This 327c2aa98e2SPeter Wemm ** will cause the messages to be queued up, and a 328c2aa98e2SPeter Wemm ** daemon will come along to send the messages later. 329c2aa98e2SPeter Wemm */ 330c2aa98e2SPeter Wemm 331c2aa98e2SPeter Wemm if (NoConnect && !Verbose && 332c2aa98e2SPeter Wemm bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 333c2aa98e2SPeter Wemm { 334c2aa98e2SPeter Wemm if (tTd(13, 30)) 33506f25ae9SGregory Neil Shapiro dprintf(" ... expensive\n"); 33606f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 33706f25ae9SGregory Neil Shapiro expensive = TRUE; 33806f25ae9SGregory Neil Shapiro } 33906f25ae9SGregory Neil Shapiro else if (bitnset(M_HOLD, q->q_mailer->m_flags) && 34006f25ae9SGregory Neil Shapiro QueueLimitId == NULL && 34106f25ae9SGregory Neil Shapiro QueueLimitSender == NULL && 34206f25ae9SGregory Neil Shapiro QueueLimitRecipient == NULL) 34306f25ae9SGregory Neil Shapiro { 34406f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 34506f25ae9SGregory Neil Shapiro dprintf(" ... hold\n"); 34606f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 347c2aa98e2SPeter Wemm expensive = TRUE; 348c2aa98e2SPeter Wemm } 349c2aa98e2SPeter Wemm else 350c2aa98e2SPeter Wemm { 351c2aa98e2SPeter Wemm if (tTd(13, 30)) 35206f25ae9SGregory Neil Shapiro dprintf(" ... deliverable\n"); 353c2aa98e2SPeter Wemm somedeliveries = TRUE; 354c2aa98e2SPeter Wemm } 355c2aa98e2SPeter Wemm } 356c2aa98e2SPeter Wemm 357c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0) 358c2aa98e2SPeter Wemm { 359c2aa98e2SPeter Wemm /* 360c2aa98e2SPeter Wemm ** Split this envelope into two. 361c2aa98e2SPeter Wemm */ 362c2aa98e2SPeter Wemm 36306f25ae9SGregory Neil Shapiro ee = (ENVELOPE *) xalloc(sizeof *ee); 364c2aa98e2SPeter Wemm *ee = *e; 36506f25ae9SGregory Neil Shapiro ee->e_message = NULL; 366c2aa98e2SPeter Wemm ee->e_id = NULL; 36706f25ae9SGregory Neil Shapiro assign_queueid(ee); 368c2aa98e2SPeter Wemm 369c2aa98e2SPeter Wemm if (tTd(13, 1)) 37006f25ae9SGregory Neil Shapiro dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 371c2aa98e2SPeter Wemm e->e_id, ee->e_id, owner, otherowners); 372c2aa98e2SPeter Wemm 373c2aa98e2SPeter Wemm ee->e_header = copyheader(e->e_header); 374c2aa98e2SPeter Wemm ee->e_sendqueue = copyqueue(e->e_sendqueue); 375c2aa98e2SPeter Wemm ee->e_errorqueue = copyqueue(e->e_errorqueue); 376c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 377c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT; 378c2aa98e2SPeter Wemm setsender(owner, ee, NULL, '\0', TRUE); 379c2aa98e2SPeter Wemm if (tTd(13, 5)) 380c2aa98e2SPeter Wemm { 38106f25ae9SGregory Neil Shapiro dprintf("sendall(split): QS_SENDER "); 382c2aa98e2SPeter Wemm printaddr(&ee->e_from, FALSE); 383c2aa98e2SPeter Wemm } 38406f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER; 385c2aa98e2SPeter Wemm ee->e_dfp = NULL; 38606f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL; 387c2aa98e2SPeter Wemm ee->e_xfp = NULL; 38806f25ae9SGregory Neil Shapiro ee->e_queuedir = e->e_queuedir; 389c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL; 390c2aa98e2SPeter Wemm ee->e_sibling = splitenv; 39106f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL; 392c2aa98e2SPeter Wemm splitenv = ee; 393c2aa98e2SPeter Wemm 394c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 395c2aa98e2SPeter Wemm { 396c2aa98e2SPeter Wemm if (q->q_owner == owner) 397c2aa98e2SPeter Wemm { 39806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 399c2aa98e2SPeter Wemm if (tTd(13, 6)) 40006f25ae9SGregory Neil Shapiro dprintf("\t... stripping %s from original envelope\n", 401c2aa98e2SPeter Wemm q->q_paddr); 402c2aa98e2SPeter Wemm } 403c2aa98e2SPeter Wemm } 404c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 405c2aa98e2SPeter Wemm { 406c2aa98e2SPeter Wemm if (q->q_owner != owner) 407c2aa98e2SPeter Wemm { 40806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 409c2aa98e2SPeter Wemm if (tTd(13, 6)) 41006f25ae9SGregory Neil Shapiro dprintf("\t... dropping %s from cloned envelope\n", 411c2aa98e2SPeter Wemm q->q_paddr); 412c2aa98e2SPeter Wemm } 413c2aa98e2SPeter Wemm else 414c2aa98e2SPeter Wemm { 415c2aa98e2SPeter Wemm /* clear DSN parameters */ 416c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 417c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 418c2aa98e2SPeter Wemm if (tTd(13, 6)) 41906f25ae9SGregory Neil Shapiro dprintf("\t... moving %s to cloned envelope\n", 420c2aa98e2SPeter Wemm q->q_paddr); 421c2aa98e2SPeter Wemm } 422c2aa98e2SPeter Wemm } 423c2aa98e2SPeter Wemm 424c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 425c2aa98e2SPeter Wemm dup_queue_file(e, ee, 'd'); 42606f25ae9SGregory Neil Shapiro 42706f25ae9SGregory Neil Shapiro /* 42806f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent 42906f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while 43006f25ae9SGregory Neil Shapiro ** processing the recipients (done before the 43106f25ae9SGregory Neil Shapiro ** envelope splitting). 43206f25ae9SGregory Neil Shapiro */ 43306f25ae9SGregory Neil Shapiro 43406f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL) 43506f25ae9SGregory Neil Shapiro ee->e_xfp = bfdup(e->e_xfp); 43606f25ae9SGregory Neil Shapiro 43706f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */ 43806f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL) 439c2aa98e2SPeter Wemm openxscript(ee); 44006f25ae9SGregory Neil Shapiro 441065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4) 442c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, ee->e_id, 443c2aa98e2SPeter Wemm "clone %s, owner=%s", 444c2aa98e2SPeter Wemm e->e_id, owner); 445c2aa98e2SPeter Wemm } 446c2aa98e2SPeter Wemm } 447c2aa98e2SPeter Wemm 448c2aa98e2SPeter Wemm if (owner != NULL) 449c2aa98e2SPeter Wemm { 450c2aa98e2SPeter Wemm setsender(owner, e, NULL, '\0', TRUE); 451c2aa98e2SPeter Wemm if (tTd(13, 5)) 452c2aa98e2SPeter Wemm { 45306f25ae9SGregory Neil Shapiro dprintf("sendall(owner): QS_SENDER "); 454c2aa98e2SPeter Wemm printaddr(&e->e_from, FALSE); 455c2aa98e2SPeter Wemm } 45606f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 457c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL; 458c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT; 459c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 460c2aa98e2SPeter Wemm } 461c2aa98e2SPeter Wemm 462c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */ 463c2aa98e2SPeter Wemm if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER && 464c2aa98e2SPeter Wemm mode != SM_VERIFY) 465c2aa98e2SPeter Wemm { 466193538b7SGregory Neil Shapiro time_t now = curtime(); 467193538b7SGregory Neil Shapiro 468c2aa98e2SPeter Wemm if (tTd(13, 29)) 46906f25ae9SGregory Neil Shapiro dprintf("No deliveries: auto-queuing\n"); 470c2aa98e2SPeter Wemm mode = SM_QUEUE; 471c2aa98e2SPeter Wemm 472c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */ 473193538b7SGregory Neil Shapiro e->e_dtime = now; 474c2aa98e2SPeter Wemm if (!expensive) 475c2aa98e2SPeter Wemm e->e_ntries++; 476c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 477c2aa98e2SPeter Wemm { 478193538b7SGregory Neil Shapiro ee->e_dtime = now; 479c2aa98e2SPeter Wemm if (!expensive) 480c2aa98e2SPeter Wemm ee->e_ntries++; 481c2aa98e2SPeter Wemm } 482c2aa98e2SPeter Wemm } 483c2aa98e2SPeter Wemm 484c2aa98e2SPeter Wemm #if QUEUE 485c2aa98e2SPeter Wemm if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK || 486c2aa98e2SPeter Wemm (mode != SM_VERIFY && SuperSafe)) && 487c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 488c2aa98e2SPeter Wemm { 48942e5d165SGregory Neil Shapiro /* 49042e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue. 49142e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes. 49242e5d165SGregory Neil Shapiro ** If the original were done first, we may lose 49342e5d165SGregory Neil Shapiro ** recipients. 49442e5d165SGregory Neil Shapiro */ 49542e5d165SGregory Neil Shapiro 496c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 497c2aa98e2SPeter Wemm queueup(ee, mode == SM_QUEUE || mode == SM_DEFER); 49842e5d165SGregory Neil Shapiro queueup(e, mode == SM_QUEUE || mode == SM_DEFER); 499c2aa98e2SPeter Wemm } 500c2aa98e2SPeter Wemm #endif /* QUEUE */ 501c2aa98e2SPeter Wemm 502c2aa98e2SPeter Wemm if (tTd(62, 10)) 503c2aa98e2SPeter Wemm checkfds("after envelope splitting"); 504c2aa98e2SPeter Wemm 505c2aa98e2SPeter Wemm /* 506c2aa98e2SPeter Wemm ** If we belong in background, fork now. 507c2aa98e2SPeter Wemm */ 508c2aa98e2SPeter Wemm 509c2aa98e2SPeter Wemm if (tTd(13, 20)) 510c2aa98e2SPeter Wemm { 51106f25ae9SGregory Neil Shapiro dprintf("sendall: final mode = %c\n", mode); 512c2aa98e2SPeter Wemm if (tTd(13, 21)) 513c2aa98e2SPeter Wemm { 51406f25ae9SGregory Neil Shapiro dprintf("\n================ Final Send Queue(s) =====================\n"); 51506f25ae9SGregory Neil Shapiro dprintf("\n *** Envelope %s, e_from=%s ***\n", 516c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr); 517c2aa98e2SPeter Wemm printaddr(e->e_sendqueue, TRUE); 518c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 519c2aa98e2SPeter Wemm { 52006f25ae9SGregory Neil Shapiro dprintf("\n *** Envelope %s, e_from=%s ***\n", 521c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr); 522c2aa98e2SPeter Wemm printaddr(ee->e_sendqueue, TRUE); 523c2aa98e2SPeter Wemm } 52406f25ae9SGregory Neil Shapiro dprintf("==========================================================\n\n"); 525c2aa98e2SPeter Wemm } 526c2aa98e2SPeter Wemm } 527c2aa98e2SPeter Wemm switch (mode) 528c2aa98e2SPeter Wemm { 529c2aa98e2SPeter Wemm case SM_VERIFY: 530c2aa98e2SPeter Wemm Verbose = 2; 531c2aa98e2SPeter Wemm break; 532c2aa98e2SPeter Wemm 533c2aa98e2SPeter Wemm case SM_QUEUE: 534c2aa98e2SPeter Wemm case SM_DEFER: 535c2aa98e2SPeter Wemm #if HASFLOCK 536c2aa98e2SPeter Wemm queueonly: 53706f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 538c2aa98e2SPeter Wemm if (e->e_nrcpts > 0) 539c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 540c2aa98e2SPeter Wemm dropenvelope(e, splitenv != NULL); 541c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 542c2aa98e2SPeter Wemm { 543c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0) 544c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 545c2aa98e2SPeter Wemm dropenvelope(ee, FALSE); 546c2aa98e2SPeter Wemm } 547c2aa98e2SPeter Wemm return; 548c2aa98e2SPeter Wemm 549c2aa98e2SPeter Wemm case SM_FORK: 550c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 551c2aa98e2SPeter Wemm (void) fflush(e->e_xfp); 552c2aa98e2SPeter Wemm 553c2aa98e2SPeter Wemm #if !HASFLOCK 554c2aa98e2SPeter Wemm /* 555c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that 556c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file 557c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and 558c2aa98e2SPeter Wemm ** then restart from scratch in the child. 559c2aa98e2SPeter Wemm */ 560c2aa98e2SPeter Wemm 561c2aa98e2SPeter Wemm { 562c2aa98e2SPeter Wemm /* save id for future use */ 563c2aa98e2SPeter Wemm char *qid = e->e_id; 564c2aa98e2SPeter Wemm 565c2aa98e2SPeter Wemm /* now drop the envelope in the parent */ 566c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 567c2aa98e2SPeter Wemm dropenvelope(e, splitenv != NULL); 568c2aa98e2SPeter Wemm 569c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */ 570c2aa98e2SPeter Wemm e->e_id = qid; 571c2aa98e2SPeter Wemm } 572c2aa98e2SPeter Wemm 573c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 574c2aa98e2SPeter Wemm { 575c2aa98e2SPeter Wemm /* save id for future use */ 576c2aa98e2SPeter Wemm char *qid = ee->e_id; 577c2aa98e2SPeter Wemm 578c2aa98e2SPeter Wemm /* drop envelope in parent */ 579c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 580c2aa98e2SPeter Wemm dropenvelope(ee, FALSE); 581c2aa98e2SPeter Wemm 582c2aa98e2SPeter Wemm /* and save qid for reacquisition */ 583c2aa98e2SPeter Wemm ee->e_id = qid; 584c2aa98e2SPeter Wemm } 585c2aa98e2SPeter Wemm 586c2aa98e2SPeter Wemm #endif /* !HASFLOCK */ 587c2aa98e2SPeter Wemm 58806f25ae9SGregory Neil Shapiro /* 58906f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent 59006f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby 59106f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore, 59206f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open 59306f25ae9SGregory Neil Shapiro ** them if necessary. 59406f25ae9SGregory Neil Shapiro */ 59506f25ae9SGregory Neil Shapiro 59606f25ae9SGregory Neil Shapiro closemaps(); 59706f25ae9SGregory Neil Shapiro 598c2aa98e2SPeter Wemm pid = fork(); 599c2aa98e2SPeter Wemm if (pid < 0) 600c2aa98e2SPeter Wemm { 60106f25ae9SGregory Neil Shapiro syserr("deliver: fork 1"); 602c2aa98e2SPeter Wemm #if HASFLOCK 603c2aa98e2SPeter Wemm goto queueonly; 60406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 605c2aa98e2SPeter Wemm e->e_id = NULL; 606c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 607c2aa98e2SPeter Wemm ee->e_id = NULL; 608c2aa98e2SPeter Wemm return; 609c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 610c2aa98e2SPeter Wemm } 611c2aa98e2SPeter Wemm else if (pid > 0) 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm #if HASFLOCK 614c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */ 615c2aa98e2SPeter Wemm /* close any random open files in the envelope */ 616c2aa98e2SPeter Wemm closexscript(e); 617c2aa98e2SPeter Wemm if (e->e_dfp != NULL) 61806f25ae9SGregory Neil Shapiro (void) bfclose(e->e_dfp); 619c2aa98e2SPeter Wemm e->e_dfp = NULL; 620c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF; 621c2aa98e2SPeter Wemm 622c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */ 623c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 62406f25ae9SGregory Neil Shapiro (void) fclose(e->e_lockfp); 62506f25ae9SGregory Neil Shapiro else 62606f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id); 627c2aa98e2SPeter Wemm e->e_lockfp = NULL; 62806f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 629c2aa98e2SPeter Wemm 630c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */ 631c2aa98e2SPeter Wemm e->e_id = NULL; 632c2aa98e2SPeter Wemm 633c2aa98e2SPeter Wemm /* catch intermediate zombie */ 634c2aa98e2SPeter Wemm (void) waitfor(pid); 635c2aa98e2SPeter Wemm return; 636c2aa98e2SPeter Wemm } 637c2aa98e2SPeter Wemm 63842e5d165SGregory Neil Shapiro /* 63942e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message, 64042e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler) 64142e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line 64242e5d165SGregory Neil Shapiro ** message submission. 64342e5d165SGregory Neil Shapiro */ 64442e5d165SGregory Neil Shapiro 64542e5d165SGregory Neil Shapiro (void) setsignal(SIGTERM, SIG_DFL); 64642e5d165SGregory Neil Shapiro 647c2aa98e2SPeter Wemm /* double fork to avoid zombies */ 648c2aa98e2SPeter Wemm pid = fork(); 649c2aa98e2SPeter Wemm if (pid > 0) 650c2aa98e2SPeter Wemm exit(EX_OK); 65106f25ae9SGregory Neil Shapiro save_errno = errno; 652c2aa98e2SPeter Wemm 653c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */ 654c2aa98e2SPeter Wemm disconnect(2, e); 65506f25ae9SGregory Neil Shapiro clearstats(); 656c2aa98e2SPeter Wemm 657c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */ 658c2aa98e2SPeter Wemm if (pid < 0) 659c2aa98e2SPeter Wemm { 66006f25ae9SGregory Neil Shapiro errno = save_errno; 66106f25ae9SGregory Neil Shapiro syserr("deliver: fork 2"); 662c2aa98e2SPeter Wemm #if HASFLOCK 663c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 66406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 665c2aa98e2SPeter Wemm e->e_id = NULL; 666c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 667065a643dSPeter Wemm finis(TRUE, ExitStat); 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm 670c2aa98e2SPeter Wemm /* be sure to give error messages in child */ 671c2aa98e2SPeter Wemm QuickAbort = FALSE; 672c2aa98e2SPeter Wemm 673c2aa98e2SPeter Wemm /* 674c2aa98e2SPeter Wemm ** Close any cached connections. 675c2aa98e2SPeter Wemm ** 676c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent 677c2aa98e2SPeter Wemm ** still knows about the connection. 678c2aa98e2SPeter Wemm ** 679c2aa98e2SPeter Wemm ** This should only happen when delivering an error 680c2aa98e2SPeter Wemm ** message. 681c2aa98e2SPeter Wemm */ 682c2aa98e2SPeter Wemm 683c2aa98e2SPeter Wemm mci_flush(FALSE, NULL); 684c2aa98e2SPeter Wemm 685c2aa98e2SPeter Wemm #if HASFLOCK 686c2aa98e2SPeter Wemm break; 68706f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 688c2aa98e2SPeter Wemm 689c2aa98e2SPeter Wemm /* 690c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files. 691c2aa98e2SPeter Wemm */ 692c2aa98e2SPeter Wemm 693c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 694c2aa98e2SPeter Wemm { 695c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling; 696c2aa98e2SPeter Wemm 69706f25ae9SGregory Neil Shapiro (void) dowork(ee->e_queuedir, ee->e_id, 69806f25ae9SGregory Neil Shapiro FALSE, FALSE, ee); 699c2aa98e2SPeter Wemm ee->e_sibling = sibling; 700c2aa98e2SPeter Wemm } 70106f25ae9SGregory Neil Shapiro (void) dowork(e->e_queuedir, e->e_id, 70206f25ae9SGregory Neil Shapiro FALSE, FALSE, e); 703065a643dSPeter Wemm finis(TRUE, ExitStat); 70406f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 705c2aa98e2SPeter Wemm } 706c2aa98e2SPeter Wemm 707c2aa98e2SPeter Wemm sendenvelope(e, mode); 708c2aa98e2SPeter Wemm dropenvelope(e, TRUE); 709c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 710c2aa98e2SPeter Wemm { 711c2aa98e2SPeter Wemm CurEnv = ee; 712c2aa98e2SPeter Wemm if (mode != SM_VERIFY) 713c2aa98e2SPeter Wemm openxscript(ee); 714c2aa98e2SPeter Wemm sendenvelope(ee, mode); 715c2aa98e2SPeter Wemm dropenvelope(ee, TRUE); 716c2aa98e2SPeter Wemm } 717c2aa98e2SPeter Wemm CurEnv = e; 718c2aa98e2SPeter Wemm 719c2aa98e2SPeter Wemm Verbose = oldverbose; 720c2aa98e2SPeter Wemm if (mode == SM_FORK) 721065a643dSPeter Wemm finis(TRUE, ExitStat); 722c2aa98e2SPeter Wemm } 723c2aa98e2SPeter Wemm 72406f25ae9SGregory Neil Shapiro static void 725c2aa98e2SPeter Wemm sendenvelope(e, mode) 726c2aa98e2SPeter Wemm register ENVELOPE *e; 727c2aa98e2SPeter Wemm int mode; 728c2aa98e2SPeter Wemm { 729c2aa98e2SPeter Wemm register ADDRESS *q; 730c2aa98e2SPeter Wemm bool didany; 731c2aa98e2SPeter Wemm 732c2aa98e2SPeter Wemm if (tTd(13, 10)) 73306f25ae9SGregory Neil Shapiro dprintf("sendenvelope(%s) e_flags=0x%lx\n", 734c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 735c2aa98e2SPeter Wemm e->e_flags); 736c2aa98e2SPeter Wemm if (LogLevel > 80) 737c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id, 73806f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx", 739c2aa98e2SPeter Wemm e->e_flags); 740c2aa98e2SPeter Wemm 741c2aa98e2SPeter Wemm /* 742c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 743c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 744c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 745c2aa98e2SPeter Wemm ** addresses to be sent. 746c2aa98e2SPeter Wemm */ 747c2aa98e2SPeter Wemm 748c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 749c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 750c2aa98e2SPeter Wemm { 751c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 752c2aa98e2SPeter Wemm return; 753c2aa98e2SPeter Wemm } 754c2aa98e2SPeter Wemm 75506f25ae9SGregory Neil Shapiro /* Don't attempt deliveries if we want to bounce now */ 75606f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) && 75706f25ae9SGregory Neil Shapiro TimeOuts.to_q_return[e->e_timeoutclass] == NOW) 75806f25ae9SGregory Neil Shapiro return; 75906f25ae9SGregory Neil Shapiro 760c2aa98e2SPeter Wemm /* 761c2aa98e2SPeter Wemm ** Run through the list and send everything. 762c2aa98e2SPeter Wemm ** 763c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery 764c2aa98e2SPeter Wemm ** result in returned mail. 765c2aa98e2SPeter Wemm */ 766c2aa98e2SPeter Wemm 767c2aa98e2SPeter Wemm e->e_nsent = 0; 768c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS; 76906f25ae9SGregory Neil Shapiro 770c2aa98e2SPeter Wemm define(macid("{envid}", NULL), e->e_envid, e); 771c2aa98e2SPeter Wemm define(macid("{bodytype}", NULL), e->e_bodytype, e); 772c2aa98e2SPeter Wemm didany = FALSE; 773c2aa98e2SPeter Wemm 774c2aa98e2SPeter Wemm /* now run through the queue */ 775c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 776c2aa98e2SPeter Wemm { 777c2aa98e2SPeter Wemm #if XDEBUG 778c2aa98e2SPeter Wemm char wbuf[MAXNAME + 20]; 779c2aa98e2SPeter Wemm 780c2aa98e2SPeter Wemm (void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)", 781c2aa98e2SPeter Wemm MAXNAME, q->q_paddr); 782c2aa98e2SPeter Wemm checkfd012(wbuf); 78306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 784c2aa98e2SPeter Wemm if (mode == SM_VERIFY) 785c2aa98e2SPeter Wemm { 786c2aa98e2SPeter Wemm e->e_to = q->q_paddr; 78706f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state)) 788c2aa98e2SPeter Wemm { 789c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0') 790c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s", 791c2aa98e2SPeter Wemm q->q_mailer->m_name, 792c2aa98e2SPeter Wemm q->q_host, 793c2aa98e2SPeter Wemm q->q_user); 794c2aa98e2SPeter Wemm else 795c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s", 796c2aa98e2SPeter Wemm q->q_mailer->m_name, 797c2aa98e2SPeter Wemm q->q_user); 798c2aa98e2SPeter Wemm } 799c2aa98e2SPeter Wemm } 80006f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state)) 801c2aa98e2SPeter Wemm { 802c2aa98e2SPeter Wemm #if QUEUE 803c2aa98e2SPeter Wemm /* 804c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses 805c2aa98e2SPeter Wemm */ 806c2aa98e2SPeter Wemm 80742e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && 80842e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval) 809c2aa98e2SPeter Wemm { 810c2aa98e2SPeter Wemm queueup(e, FALSE); 811c2aa98e2SPeter Wemm e->e_nsent = 0; 812c2aa98e2SPeter Wemm } 813c2aa98e2SPeter Wemm #endif /* QUEUE */ 814c2aa98e2SPeter Wemm (void) deliver(e, q); 815c2aa98e2SPeter Wemm didany = TRUE; 816c2aa98e2SPeter Wemm } 817c2aa98e2SPeter Wemm } 818c2aa98e2SPeter Wemm if (didany) 819c2aa98e2SPeter Wemm { 820c2aa98e2SPeter Wemm e->e_dtime = curtime(); 821c2aa98e2SPeter Wemm e->e_ntries++; 822c2aa98e2SPeter Wemm } 823c2aa98e2SPeter Wemm 824c2aa98e2SPeter Wemm #if XDEBUG 825c2aa98e2SPeter Wemm checkfd012("end of sendenvelope"); 82606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 827c2aa98e2SPeter Wemm } 828c2aa98e2SPeter Wemm /* 829c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 830c2aa98e2SPeter Wemm ** 831c2aa98e2SPeter Wemm ** Parameters: 832c2aa98e2SPeter Wemm ** e -- the existing envelope 833c2aa98e2SPeter Wemm ** ee -- the new envelope 834c2aa98e2SPeter Wemm ** type -- the queue file type (e.g., 'd') 835c2aa98e2SPeter Wemm ** 836c2aa98e2SPeter Wemm ** Returns: 837c2aa98e2SPeter Wemm ** none 838c2aa98e2SPeter Wemm */ 839c2aa98e2SPeter Wemm 84006f25ae9SGregory Neil Shapiro static void 841c2aa98e2SPeter Wemm dup_queue_file(e, ee, type) 842c2aa98e2SPeter Wemm struct envelope *e, *ee; 843c2aa98e2SPeter Wemm int type; 844c2aa98e2SPeter Wemm { 84506f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 846c2aa98e2SPeter Wemm 847c2aa98e2SPeter Wemm ee->e_dfp = NULL; 848c2aa98e2SPeter Wemm ee->e_xfp = NULL; 84906f25ae9SGregory Neil Shapiro 85006f25ae9SGregory Neil Shapiro /* 85106f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory. 85206f25ae9SGregory Neil Shapiro */ 85306f25ae9SGregory Neil Shapiro 854c2aa98e2SPeter Wemm snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type)); 855c2aa98e2SPeter Wemm snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type)); 856c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 857c2aa98e2SPeter Wemm { 85806f25ae9SGregory Neil Shapiro int save_errno = errno; 859c2aa98e2SPeter Wemm 860c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf); 86106f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 862c2aa98e2SPeter Wemm { 863c2aa98e2SPeter Wemm if (unlink(f2buf) < 0) 864c2aa98e2SPeter Wemm { 865c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent", 866c2aa98e2SPeter Wemm f2buf); 867c2aa98e2SPeter Wemm /* NOTREACHED */ 868c2aa98e2SPeter Wemm } 869c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 870c2aa98e2SPeter Wemm { 871c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent", 872c2aa98e2SPeter Wemm f1buf, f2buf); 873c2aa98e2SPeter Wemm /* NOTREACHED */ 874c2aa98e2SPeter Wemm } 875c2aa98e2SPeter Wemm } 876c2aa98e2SPeter Wemm } 877c2aa98e2SPeter Wemm } 878c2aa98e2SPeter Wemm /* 879c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure. 880c2aa98e2SPeter Wemm ** 881c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running 882c2aa98e2SPeter Wemm ** two processes on the same stack!!! 883c2aa98e2SPeter Wemm ** 884c2aa98e2SPeter Wemm ** Parameters: 885c2aa98e2SPeter Wemm ** none. 886c2aa98e2SPeter Wemm ** 887c2aa98e2SPeter Wemm ** Returns: 888c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding! 889c2aa98e2SPeter Wemm ** 890c2aa98e2SPeter Wemm ** Side Effects: 891c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving: 892c2aa98e2SPeter Wemm ** pid of child in parent, zero in child. 893c2aa98e2SPeter Wemm ** -1 on unrecoverable error. 894c2aa98e2SPeter Wemm ** 895c2aa98e2SPeter Wemm ** Notes: 896c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's 897c2aa98e2SPeter Wemm ** vfork for you..... 898c2aa98e2SPeter Wemm */ 899c2aa98e2SPeter Wemm 900c2aa98e2SPeter Wemm #define NFORKTRIES 5 901c2aa98e2SPeter Wemm 902c2aa98e2SPeter Wemm #ifndef FORK 903c2aa98e2SPeter Wemm # define FORK fork 90406f25ae9SGregory Neil Shapiro #endif /* ! FORK */ 905c2aa98e2SPeter Wemm 906c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \ 907c2aa98e2SPeter Wemm {\ 908c2aa98e2SPeter Wemm register int i;\ 909c2aa98e2SPeter Wemm \ 910c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\ 911c2aa98e2SPeter Wemm {\ 912c2aa98e2SPeter Wemm pid = fORKfN();\ 913c2aa98e2SPeter Wemm if (pid >= 0)\ 914c2aa98e2SPeter Wemm break;\ 915c2aa98e2SPeter Wemm if (i > 0)\ 91606f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\ 917c2aa98e2SPeter Wemm }\ 918c2aa98e2SPeter Wemm } 919c2aa98e2SPeter Wemm /* 920c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK. 921c2aa98e2SPeter Wemm ** 922c2aa98e2SPeter Wemm ** Parameters: 923c2aa98e2SPeter Wemm ** none. 924c2aa98e2SPeter Wemm ** 925c2aa98e2SPeter Wemm ** Returns: 926c2aa98e2SPeter Wemm ** pid of child in parent. 927c2aa98e2SPeter Wemm ** zero in child. 928c2aa98e2SPeter Wemm ** -1 on error. 929c2aa98e2SPeter Wemm ** 930c2aa98e2SPeter Wemm ** Side Effects: 931c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child. 932c2aa98e2SPeter Wemm */ 933c2aa98e2SPeter Wemm 934c2aa98e2SPeter Wemm int 935c2aa98e2SPeter Wemm dofork() 936c2aa98e2SPeter Wemm { 937c2aa98e2SPeter Wemm register pid_t pid = -1; 938c2aa98e2SPeter Wemm 939c2aa98e2SPeter Wemm DOFORK(fork); 94006f25ae9SGregory Neil Shapiro return pid; 941c2aa98e2SPeter Wemm } 942c2aa98e2SPeter Wemm /* 943c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses. 944c2aa98e2SPeter Wemm ** 945c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the 946c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers 947c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed 948c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so 949c2aa98e2SPeter Wemm ** deliver should be called once for each address on the 950c2aa98e2SPeter Wemm ** list. 951c2aa98e2SPeter Wemm ** 952c2aa98e2SPeter Wemm ** Parameters: 953c2aa98e2SPeter Wemm ** e -- the envelope to deliver. 954c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to. 955c2aa98e2SPeter Wemm ** 956c2aa98e2SPeter Wemm ** Returns: 957c2aa98e2SPeter Wemm ** zero -- successfully delivered. 958c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info. 959c2aa98e2SPeter Wemm ** 960c2aa98e2SPeter Wemm ** Side Effects: 961c2aa98e2SPeter Wemm ** The standard input is passed off to someone. 962c2aa98e2SPeter Wemm */ 963c2aa98e2SPeter Wemm 964c2aa98e2SPeter Wemm #ifndef NO_UID 965c2aa98e2SPeter Wemm # define NO_UID -1 96606f25ae9SGregory Neil Shapiro #endif /* ! NO_UID */ 967c2aa98e2SPeter Wemm #ifndef NO_GID 968c2aa98e2SPeter Wemm # define NO_GID -1 96906f25ae9SGregory Neil Shapiro #endif /* ! NO_GID */ 970c2aa98e2SPeter Wemm 97106f25ae9SGregory Neil Shapiro static int 972c2aa98e2SPeter Wemm deliver(e, firstto) 973c2aa98e2SPeter Wemm register ENVELOPE *e; 974c2aa98e2SPeter Wemm ADDRESS *firstto; 975c2aa98e2SPeter Wemm { 976c2aa98e2SPeter Wemm char *host; /* host being sent to */ 977c2aa98e2SPeter Wemm char *user; /* user being sent to */ 978c2aa98e2SPeter Wemm char **pvp; 979c2aa98e2SPeter Wemm register char **mvp; 980c2aa98e2SPeter Wemm register char *p; 981c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */ 982c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr; 983c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL; 984c2aa98e2SPeter Wemm register MCI *volatile mci; 985c2aa98e2SPeter Wemm register ADDRESS *to = firstto; 986c2aa98e2SPeter Wemm volatile bool clever = FALSE; /* running user smtp to this mailer */ 987c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 988c2aa98e2SPeter Wemm int rcode; /* response code */ 989c2aa98e2SPeter Wemm int lmtp_rcode = EX_OK; 99006f25ae9SGregory Neil Shapiro int nummxhosts = 0; /* number of MX hosts available */ 99106f25ae9SGregory Neil Shapiro int hostnum = 0; /* current MX host index */ 992c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */ 993c2aa98e2SPeter Wemm pid_t pid = -1; 994c2aa98e2SPeter Wemm char *volatile curhost; 995c2aa98e2SPeter Wemm register u_short port = 0; 99606f25ae9SGregory Neil Shapiro #if NETUNIX 99706f25ae9SGregory Neil Shapiro char *mux_path = NULL; /* path to UNIX domain socket */ 99806f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 999c2aa98e2SPeter Wemm time_t xstart; 1000c2aa98e2SPeter Wemm bool suidwarn; 1001c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */ 1002c2aa98e2SPeter Wemm bool goodmxfound = FALSE; /* at least one MX was OK */ 100306f25ae9SGregory Neil Shapiro bool ovr; 100406f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 100506f25ae9SGregory Neil Shapiro int strsize; 100606f25ae9SGregory Neil Shapiro int rcptcount; 100706f25ae9SGregory Neil Shapiro static int tobufsize = 0; 100806f25ae9SGregory Neil Shapiro static char *tobuf = NULL; 100906f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 101006f25ae9SGregory Neil Shapiro char tobuf[TOBUFSIZE]; /* text line of to people */ 101106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 1012c2aa98e2SPeter Wemm int mpvect[2]; 1013c2aa98e2SPeter Wemm int rpvect[2]; 101406f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1]; 1015c2aa98e2SPeter Wemm char *pv[MAXPV + 1]; 1016c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 1017c2aa98e2SPeter Wemm char rpathbuf[MAXNAME + 1]; /* translated return path */ 1018c2aa98e2SPeter Wemm 1019c2aa98e2SPeter Wemm errno = 0; 102006f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 102106f25ae9SGregory Neil Shapiro return 0; 1022c2aa98e2SPeter Wemm 1023c2aa98e2SPeter Wemm suidwarn = geteuid() == 0; 1024c2aa98e2SPeter Wemm 1025c2aa98e2SPeter Wemm m = to->q_mailer; 1026c2aa98e2SPeter Wemm host = to->q_host; 1027c2aa98e2SPeter Wemm CurEnv = e; /* just in case */ 1028c2aa98e2SPeter Wemm e->e_statmsg = NULL; 1029c2aa98e2SPeter Wemm #if SMTP 1030c2aa98e2SPeter Wemm SmtpError[0] = '\0'; 103106f25ae9SGregory Neil Shapiro #endif /* SMTP */ 1032c2aa98e2SPeter Wemm xstart = curtime(); 1033c2aa98e2SPeter Wemm 1034c2aa98e2SPeter Wemm if (tTd(10, 1)) 103506f25ae9SGregory Neil Shapiro dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 1036c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user); 1037c2aa98e2SPeter Wemm if (tTd(10, 100)) 1038c2aa98e2SPeter Wemm printopenfds(FALSE); 1039c2aa98e2SPeter Wemm 1040c2aa98e2SPeter Wemm /* 1041c2aa98e2SPeter Wemm ** Clear $&{client_*} macros if this is a bounce message to 1042c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset. 1043c2aa98e2SPeter Wemm */ 1044c2aa98e2SPeter Wemm 1045c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1046c2aa98e2SPeter Wemm { 1047c2aa98e2SPeter Wemm define(macid("{client_name}", NULL), "", e); 1048c2aa98e2SPeter Wemm define(macid("{client_addr}", NULL), "", e); 1049c2aa98e2SPeter Wemm define(macid("{client_port}", NULL), "", e); 1050c2aa98e2SPeter Wemm } 1051c2aa98e2SPeter Wemm 1052c2aa98e2SPeter Wemm /* 1053c2aa98e2SPeter Wemm ** Do initial argv setup. 1054c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is 1055c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has 1056c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This 1057c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a 1058c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV. 1059c2aa98e2SPeter Wemm ** The from address rewrite is expected to make 1060c2aa98e2SPeter Wemm ** the address relative to the other end. 1061c2aa98e2SPeter Wemm */ 1062c2aa98e2SPeter Wemm 1063c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */ 1064c2aa98e2SPeter Wemm rcode = EX_OK; 1065c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 1066c2aa98e2SPeter Wemm p = e->e_sender; 1067c2aa98e2SPeter Wemm else 1068c2aa98e2SPeter Wemm p = e->e_from.q_paddr; 1069c2aa98e2SPeter Wemm p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 1070c2aa98e2SPeter Wemm if (strlen(p) >= (SIZE_T) sizeof rpathbuf) 1071c2aa98e2SPeter Wemm { 1072c2aa98e2SPeter Wemm p = shortenstring(p, MAXSHORTSTR); 1073c2aa98e2SPeter Wemm syserr("remotename: huge return %s", p); 1074c2aa98e2SPeter Wemm } 1075c2aa98e2SPeter Wemm snprintf(rpathbuf, sizeof rpathbuf, "%s", p); 1076c2aa98e2SPeter Wemm define('g', rpathbuf, e); /* translated return path */ 1077c2aa98e2SPeter Wemm define('h', host, e); /* to host */ 1078c2aa98e2SPeter Wemm Errors = 0; 1079c2aa98e2SPeter Wemm pvp = pv; 1080c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0]; 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */ 108306f25ae9SGregory Neil Shapiro if (FromFlag && 108406f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) || 108506f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags))) 1086c2aa98e2SPeter Wemm { 1087c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags)) 1088c2aa98e2SPeter Wemm *pvp++ = "-f"; 1089c2aa98e2SPeter Wemm else 1090c2aa98e2SPeter Wemm *pvp++ = "-r"; 1091c2aa98e2SPeter Wemm *pvp++ = newstr(rpathbuf); 1092c2aa98e2SPeter Wemm } 1093c2aa98e2SPeter Wemm 1094c2aa98e2SPeter Wemm /* 1095c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run 1096c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only 1097c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots 1098c2aa98e2SPeter Wemm ** in the pv after it. 1099c2aa98e2SPeter Wemm */ 1100c2aa98e2SPeter Wemm 1101c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1102c2aa98e2SPeter Wemm { 1103c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */ 1104c2aa98e2SPeter Wemm while (*p != '\0') 1105c2aa98e2SPeter Wemm { 1106c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND) 1107c2aa98e2SPeter Wemm { 1108c2aa98e2SPeter Wemm if (*p == 'u') 1109c2aa98e2SPeter Wemm break; 1110c2aa98e2SPeter Wemm } 1111c2aa98e2SPeter Wemm } 1112c2aa98e2SPeter Wemm 1113c2aa98e2SPeter Wemm if (*p != '\0') 1114c2aa98e2SPeter Wemm break; 1115c2aa98e2SPeter Wemm 1116c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */ 1117c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 1118c2aa98e2SPeter Wemm *pvp++ = newstr(buf); 1119c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3]) 1120c2aa98e2SPeter Wemm { 112106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u", 112206f25ae9SGregory Neil Shapiro pv[0]); 112306f25ae9SGregory Neil Shapiro return -1; 1124c2aa98e2SPeter Wemm } 1125c2aa98e2SPeter Wemm } 1126c2aa98e2SPeter Wemm 1127c2aa98e2SPeter Wemm /* 1128c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument 1129c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and 1130c2aa98e2SPeter Wemm ** SMTP is the answer!! 1131c2aa98e2SPeter Wemm */ 1132c2aa98e2SPeter Wemm 1133c2aa98e2SPeter Wemm if (*mvp == NULL) 1134c2aa98e2SPeter Wemm { 1135602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */ 1136c2aa98e2SPeter Wemm #if SMTP 1137c2aa98e2SPeter Wemm clever = TRUE; 1138c2aa98e2SPeter Wemm *pvp = NULL; 1139c2aa98e2SPeter Wemm #else /* SMTP */ 1140c2aa98e2SPeter Wemm /* oops! we don't implement SMTP */ 114106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 SMTP style mailer not implemented"); 114206f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 1143c2aa98e2SPeter Wemm #endif /* SMTP */ 1144c2aa98e2SPeter Wemm } 1145602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags)) 1146602a2b1bSGregory Neil Shapiro { 1147602a2b1bSGregory Neil Shapiro /* not running LMTP */ 1148602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL, 1149602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off", 1150602a2b1bSGregory Neil Shapiro m->m_name); 1151602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags); 1152602a2b1bSGregory Neil Shapiro } 1153c2aa98e2SPeter Wemm 1154c2aa98e2SPeter Wemm /* 1155c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We 1156c2aa98e2SPeter Wemm ** run through our address list and append all the addresses 1157c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can 1158c2aa98e2SPeter Wemm ** always send another copy later. 1159c2aa98e2SPeter Wemm */ 1160c2aa98e2SPeter Wemm 116106f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 116206f25ae9SGregory Neil Shapiro e->e_to = NULL; 116306f25ae9SGregory Neil Shapiro strsize = 2; 116406f25ae9SGregory Neil Shapiro rcptcount = 0; 116506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 1166c2aa98e2SPeter Wemm tobuf[0] = '\0'; 1167c2aa98e2SPeter Wemm e->e_to = tobuf; 116806f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 116906f25ae9SGregory Neil Shapiro 1170c2aa98e2SPeter Wemm ctladdr = NULL; 117106f25ae9SGregory Neil Shapiro firstsig = hostsignature(firstto->q_mailer, firstto->q_host); 1172c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next) 1173c2aa98e2SPeter Wemm { 1174c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */ 117506f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 117606f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 117706f25ae9SGregory Neil Shapiro break; 117806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 1179c2aa98e2SPeter Wemm if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 1180c2aa98e2SPeter Wemm break; 118106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 1182c2aa98e2SPeter Wemm 1183c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */ 118406f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state) || 1185c2aa98e2SPeter Wemm to->q_mailer != firstto->q_mailer || 118606f25ae9SGregory Neil Shapiro strcmp(hostsignature(to->q_mailer, to->q_host), 118706f25ae9SGregory Neil Shapiro firstsig) != 0) 1188c2aa98e2SPeter Wemm continue; 1189c2aa98e2SPeter Wemm 1190c2aa98e2SPeter Wemm /* avoid overflowing tobuf */ 119106f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 119206f25ae9SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 119306f25ae9SGregory Neil Shapiro if (!clever && strsize > TOBUFSIZE) 119406f25ae9SGregory Neil Shapiro break; 119506f25ae9SGregory Neil Shapiro 119606f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt) 119706f25ae9SGregory Neil Shapiro break; 119806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 1199c2aa98e2SPeter Wemm if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 1200c2aa98e2SPeter Wemm break; 120106f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 1202c2aa98e2SPeter Wemm 1203c2aa98e2SPeter Wemm if (tTd(10, 1)) 1204c2aa98e2SPeter Wemm { 120506f25ae9SGregory Neil Shapiro dprintf("\nsend to "); 1206c2aa98e2SPeter Wemm printaddr(to, FALSE); 1207c2aa98e2SPeter Wemm } 1208c2aa98e2SPeter Wemm 1209c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */ 1210c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 1211c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to); 1212c2aa98e2SPeter Wemm 1213c2aa98e2SPeter Wemm if (tTd(10, 2)) 1214c2aa98e2SPeter Wemm { 121506f25ae9SGregory Neil Shapiro dprintf("ctladdr="); 1216c2aa98e2SPeter Wemm printaddr(ctladdr, FALSE); 1217c2aa98e2SPeter Wemm } 1218c2aa98e2SPeter Wemm 1219c2aa98e2SPeter Wemm user = to->q_user; 1220c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 1221c2aa98e2SPeter Wemm 1222c2aa98e2SPeter Wemm /* 1223c2aa98e2SPeter Wemm ** Check to see that these people are allowed to 1224c2aa98e2SPeter Wemm ** talk to each other. 122542e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize. 1226c2aa98e2SPeter Wemm */ 1227c2aa98e2SPeter Wemm 122842e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 && 122942e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 1230c2aa98e2SPeter Wemm { 1231c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 1232c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 1233c2aa98e2SPeter Wemm to->q_status = "5.2.3"; 1234c2aa98e2SPeter Wemm else 1235c2aa98e2SPeter Wemm to->q_status = "5.3.4"; 123606f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */ 123706f25ae9SGregory Neil Shapiro usrerrenh(to->q_status, 123806f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 123906f25ae9SGregory Neil Shapiro m->m_maxsize); 124006f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE); 124106f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m, 124206f25ae9SGregory Neil Shapiro NULL, ctladdr, xstart, e); 1243c2aa98e2SPeter Wemm continue; 1244c2aa98e2SPeter Wemm } 1245c2aa98e2SPeter Wemm #if NAMED_BIND 1246602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 124706f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1248c2aa98e2SPeter Wemm 124906f25ae9SGregory Neil Shapiro ovr = TRUE; 1250c2aa98e2SPeter Wemm /* do config file checking of compatibility */ 125106f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 1252193538b7SGregory Neil Shapiro e, TRUE, TRUE, 4, NULL); 1253c2aa98e2SPeter Wemm if (rcode == EX_OK) 1254c2aa98e2SPeter Wemm { 1255065a643dSPeter Wemm /* do in-code checking if not discarding */ 1256065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags)) 125706f25ae9SGregory Neil Shapiro { 1258c2aa98e2SPeter Wemm rcode = checkcompat(to, e); 125906f25ae9SGregory Neil Shapiro ovr = FALSE; 126006f25ae9SGregory Neil Shapiro } 1261c2aa98e2SPeter Wemm } 1262c2aa98e2SPeter Wemm if (rcode != EX_OK) 1263c2aa98e2SPeter Wemm { 126406f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr); 126506f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, 126606f25ae9SGregory Neil Shapiro NULL, ctladdr, xstart, e); 1267c2aa98e2SPeter Wemm continue; 1268c2aa98e2SPeter Wemm } 1269065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 1270065a643dSPeter Wemm { 1271065a643dSPeter Wemm if (tTd(10, 5)) 1272065a643dSPeter Wemm { 127306f25ae9SGregory Neil Shapiro dprintf("deliver: discarding recipient "); 1274065a643dSPeter Wemm printaddr(to, FALSE); 1275065a643dSPeter Wemm } 1276065a643dSPeter Wemm 127706f25ae9SGregory Neil Shapiro /* pretend the message was sent */ 127806f25ae9SGregory Neil Shapiro /* XXX should we log something here? */ 127906f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED; 128006f25ae9SGregory Neil Shapiro 1281065a643dSPeter Wemm /* 1282065a643dSPeter Wemm ** Remove discard bit to prevent discard of 128306f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the 128406f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before 128506f25ae9SGregory Neil Shapiro ** we get here. 1286065a643dSPeter Wemm */ 1287065a643dSPeter Wemm 128806f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD; 1289065a643dSPeter Wemm continue; 1290065a643dSPeter Wemm } 1291c2aa98e2SPeter Wemm 1292c2aa98e2SPeter Wemm /* 1293c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb 1294c2aa98e2SPeter Wemm ** about them. 1295c2aa98e2SPeter Wemm */ 1296c2aa98e2SPeter Wemm 1297c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags)) 1298c2aa98e2SPeter Wemm { 1299c2aa98e2SPeter Wemm stripquotes(user); 1300c2aa98e2SPeter Wemm stripquotes(host); 1301c2aa98e2SPeter Wemm } 1302c2aa98e2SPeter Wemm 1303c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */ 1304c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|') 1305c2aa98e2SPeter Wemm user++; 1306c2aa98e2SPeter Wemm 1307c2aa98e2SPeter Wemm /* 1308c2aa98e2SPeter Wemm ** If an error message has already been given, don't 1309c2aa98e2SPeter Wemm ** bother to send to this address. 1310c2aa98e2SPeter Wemm ** 1311c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer 1312c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that 1313c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail. 1314c2aa98e2SPeter Wemm */ 1315c2aa98e2SPeter Wemm 131606f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 1317c2aa98e2SPeter Wemm continue; 1318c2aa98e2SPeter Wemm 1319c2aa98e2SPeter Wemm /* 1320c2aa98e2SPeter Wemm ** See if this user name is "special". 1321c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this 1322c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note 1323c2aa98e2SPeter Wemm ** that this type of addresses is not processed along 1324c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person. 1325c2aa98e2SPeter Wemm */ 1326c2aa98e2SPeter Wemm 1327c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0) 1328c2aa98e2SPeter Wemm { 1329c2aa98e2SPeter Wemm define('u', user, e); /* to user */ 1330c2aa98e2SPeter Wemm p = to->q_home; 1331c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1332c2aa98e2SPeter Wemm p = ctladdr->q_home; 1333c2aa98e2SPeter Wemm define('z', p, e); /* user's home */ 1334c2aa98e2SPeter Wemm expand(m->m_argv[1], buf, sizeof buf, e); 1335c2aa98e2SPeter Wemm if (strlen(buf) > 0) 1336c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 1337c2aa98e2SPeter Wemm else 1338c2aa98e2SPeter Wemm { 1339c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s", 1340c2aa98e2SPeter Wemm m->m_name); 1341c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1342c2aa98e2SPeter Wemm } 134306f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL, 134406f25ae9SGregory Neil Shapiro ctladdr, xstart, e); 134506f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, TRUE); 1346c2aa98e2SPeter Wemm e->e_nsent++; 1347c2aa98e2SPeter Wemm if (rcode == EX_OK) 1348c2aa98e2SPeter Wemm { 134906f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 1350c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 1351c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 1352c2aa98e2SPeter Wemm { 1353c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 1354c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 1355c2aa98e2SPeter Wemm fprintf(e->e_xfp, "%s... Successfully delivered\n", 1356c2aa98e2SPeter Wemm to->q_paddr); 1357c2aa98e2SPeter Wemm } 1358c2aa98e2SPeter Wemm } 1359c2aa98e2SPeter Wemm to->q_statdate = curtime(); 1360c2aa98e2SPeter Wemm markstats(e, to, FALSE); 1361c2aa98e2SPeter Wemm continue; 1362c2aa98e2SPeter Wemm } 1363c2aa98e2SPeter Wemm 1364c2aa98e2SPeter Wemm /* 1365c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer 1366c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients. 1367c2aa98e2SPeter Wemm */ 1368c2aa98e2SPeter Wemm 1369c2aa98e2SPeter Wemm /* link together the chain of recipients */ 1370c2aa98e2SPeter Wemm to->q_tchain = tochain; 1371c2aa98e2SPeter Wemm tochain = to; 1372c2aa98e2SPeter Wemm 137306f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 137406f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]"; 137506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 1376c2aa98e2SPeter Wemm /* create list of users for error messages */ 137706f25ae9SGregory Neil Shapiro (void) strlcat(tobuf, ",", sizeof tobuf); 137806f25ae9SGregory Neil Shapiro (void) strlcat(tobuf, to->q_paddr, sizeof tobuf); 137906f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 138006f25ae9SGregory Neil Shapiro 1381c2aa98e2SPeter Wemm define('u', user, e); /* to user */ 1382c2aa98e2SPeter Wemm p = to->q_home; 1383c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1384c2aa98e2SPeter Wemm p = ctladdr->q_home; 1385c2aa98e2SPeter Wemm define('z', p, e); /* user's home */ 1386c2aa98e2SPeter Wemm 138706f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */ 138806f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags)) 138906f25ae9SGregory Neil Shapiro { 139006f25ae9SGregory Neil Shapiro char notify[MAXLINE]; 139106f25ae9SGregory Neil Shapiro 139206f25ae9SGregory Neil Shapiro notify[0] = '\0'; 139306f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags)) 139406f25ae9SGregory Neil Shapiro (void) strlcat(notify, "SUCCESS,", 139506f25ae9SGregory Neil Shapiro sizeof notify); 139606f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags)) 139706f25ae9SGregory Neil Shapiro (void) strlcat(notify, "FAILURE,", 139806f25ae9SGregory Neil Shapiro sizeof notify); 139906f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags)) 140006f25ae9SGregory Neil Shapiro (void) strlcat(notify, "DELAY,", sizeof notify); 140106f25ae9SGregory Neil Shapiro 140206f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */ 140306f25ae9SGregory Neil Shapiro if (notify[0] == '\0') 140406f25ae9SGregory Neil Shapiro (void) strlcat(notify, "NEVER", sizeof notify); 140506f25ae9SGregory Neil Shapiro else 140606f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0'; 140706f25ae9SGregory Neil Shapiro 140806f25ae9SGregory Neil Shapiro define(macid("{dsn_notify}", NULL), newstr(notify), e); 140906f25ae9SGregory Neil Shapiro } 141006f25ae9SGregory Neil Shapiro else 141106f25ae9SGregory Neil Shapiro define(macid("{dsn_notify}", NULL), NULL, e); 141206f25ae9SGregory Neil Shapiro 1413c2aa98e2SPeter Wemm /* 1414c2aa98e2SPeter Wemm ** Expand out this user into argument list. 1415c2aa98e2SPeter Wemm */ 1416c2aa98e2SPeter Wemm 1417c2aa98e2SPeter Wemm if (!clever) 1418c2aa98e2SPeter Wemm { 1419c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 1420c2aa98e2SPeter Wemm *pvp++ = newstr(buf); 1421c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2]) 1422c2aa98e2SPeter Wemm { 1423c2aa98e2SPeter Wemm /* allow some space for trailing parms */ 1424c2aa98e2SPeter Wemm break; 1425c2aa98e2SPeter Wemm } 1426c2aa98e2SPeter Wemm } 1427c2aa98e2SPeter Wemm } 1428c2aa98e2SPeter Wemm 1429c2aa98e2SPeter Wemm /* see if any addresses still exist */ 143006f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 143106f25ae9SGregory Neil Shapiro if (tochain == NULL) 143206f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 1433c2aa98e2SPeter Wemm if (tobuf[0] == '\0') 143406f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 1435c2aa98e2SPeter Wemm { 1436c2aa98e2SPeter Wemm define('g', (char *) NULL, e); 143706f25ae9SGregory Neil Shapiro e->e_to = NULL; 143806f25ae9SGregory Neil Shapiro return 0; 1439c2aa98e2SPeter Wemm } 1440c2aa98e2SPeter Wemm 1441c2aa98e2SPeter Wemm /* print out messages as full list */ 144206f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 144306f25ae9SGregory Neil Shapiro { 144406f25ae9SGregory Neil Shapiro int l = 1; 144506f25ae9SGregory Neil Shapiro char *tobufptr; 144606f25ae9SGregory Neil Shapiro 144706f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 144806f25ae9SGregory Neil Shapiro l += strlen(to->q_paddr) + 1; 144906f25ae9SGregory Neil Shapiro if (l < TOBUFSIZE) 145006f25ae9SGregory Neil Shapiro l = TOBUFSIZE; 145106f25ae9SGregory Neil Shapiro if (l > tobufsize) 145206f25ae9SGregory Neil Shapiro { 145306f25ae9SGregory Neil Shapiro if (tobuf != NULL) 145406f25ae9SGregory Neil Shapiro free(tobuf); 145506f25ae9SGregory Neil Shapiro tobufsize = l; 145606f25ae9SGregory Neil Shapiro tobuf = xalloc(tobufsize); 145706f25ae9SGregory Neil Shapiro } 145806f25ae9SGregory Neil Shapiro tobufptr = tobuf; 145906f25ae9SGregory Neil Shapiro *tobufptr = '\0'; 146006f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 146106f25ae9SGregory Neil Shapiro { 146206f25ae9SGregory Neil Shapiro snprintf(tobufptr, tobufsize - (tobufptr - tobuf), 146306f25ae9SGregory Neil Shapiro ",%s", to->q_paddr); 146406f25ae9SGregory Neil Shapiro tobufptr += strlen(tobufptr); 146506f25ae9SGregory Neil Shapiro } 146606f25ae9SGregory Neil Shapiro } 146706f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 1468c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 1469c2aa98e2SPeter Wemm 1470c2aa98e2SPeter Wemm /* 1471c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter. 1472c2aa98e2SPeter Wemm */ 1473c2aa98e2SPeter Wemm 1474c2aa98e2SPeter Wemm while (!clever && *++mvp != NULL) 1475c2aa98e2SPeter Wemm { 1476c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 1477c2aa98e2SPeter Wemm *pvp++ = newstr(buf); 1478c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV]) 147906f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s", 148006f25ae9SGregory Neil Shapiro pv[0]); 1481c2aa98e2SPeter Wemm } 1482c2aa98e2SPeter Wemm *pvp++ = NULL; 1483c2aa98e2SPeter Wemm 1484c2aa98e2SPeter Wemm /* 1485c2aa98e2SPeter Wemm ** Call the mailer. 1486c2aa98e2SPeter Wemm ** The argument vector gets built, pipes 1487c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as 1488c2aa98e2SPeter Wemm ** appropriate. 1489c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up. 1490c2aa98e2SPeter Wemm */ 1491c2aa98e2SPeter Wemm 1492c2aa98e2SPeter Wemm /* XXX this seems a bit wierd */ 1493c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 1494c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags)) 1495c2aa98e2SPeter Wemm ctladdr = &e->e_from; 1496c2aa98e2SPeter Wemm 1497c2aa98e2SPeter Wemm #if NAMED_BIND 1498c2aa98e2SPeter Wemm if (ConfigLevel < 2) 1499c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 150006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1501c2aa98e2SPeter Wemm 1502c2aa98e2SPeter Wemm if (tTd(11, 1)) 1503c2aa98e2SPeter Wemm { 150406f25ae9SGregory Neil Shapiro dprintf("openmailer:"); 1505c2aa98e2SPeter Wemm printav(pv); 1506c2aa98e2SPeter Wemm } 1507c2aa98e2SPeter Wemm errno = 0; 1508c2aa98e2SPeter Wemm #if NAMED_BIND 1509602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 151006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1511c2aa98e2SPeter Wemm 1512c2aa98e2SPeter Wemm CurHostName = NULL; 1513c2aa98e2SPeter Wemm 1514c2aa98e2SPeter Wemm /* 1515c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC 1516c2aa98e2SPeter Wemm ** connection. 1517c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be 1518c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a 1519c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC. 1520c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out. 1521c2aa98e2SPeter Wemm */ 1522c2aa98e2SPeter Wemm 1523c2aa98e2SPeter Wemm curhost = NULL; 1524c2aa98e2SPeter Wemm SmtpPhase = NULL; 1525c2aa98e2SPeter Wemm mci = NULL; 1526c2aa98e2SPeter Wemm 1527c2aa98e2SPeter Wemm #if XDEBUG 1528c2aa98e2SPeter Wemm { 1529c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 1530c2aa98e2SPeter Wemm 1531c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 1532c2aa98e2SPeter Wemm snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)", 1533c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 1534c2aa98e2SPeter Wemm checkfd012(wbuf); 1535c2aa98e2SPeter Wemm } 153606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1537c2aa98e2SPeter Wemm 1538c2aa98e2SPeter Wemm /* check for 8-bit available */ 1539c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 1540c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) && 1541c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 1542c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 1543c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 1544c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 1545c2aa98e2SPeter Wemm { 1546c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 154706f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 154806f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 154906f25ae9SGregory Neil Shapiro rcode = EX_DATAERR; 1550c2aa98e2SPeter Wemm goto give_up; 1551c2aa98e2SPeter Wemm } 1552c2aa98e2SPeter Wemm 1553c2aa98e2SPeter Wemm if (tTd(62, 8)) 1554c2aa98e2SPeter Wemm checkfds("before delivery"); 1555c2aa98e2SPeter Wemm 1556c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */ 1557c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0) 1558c2aa98e2SPeter Wemm { 1559c2aa98e2SPeter Wemm mci = (MCI *) xalloc(sizeof *mci); 156006f25ae9SGregory Neil Shapiro memset((char *) mci, '\0', sizeof *mci); 1561c2aa98e2SPeter Wemm mci->mci_in = stdin; 1562c2aa98e2SPeter Wemm mci->mci_out = stdout; 1563c2aa98e2SPeter Wemm mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 1564c2aa98e2SPeter Wemm mci->mci_mailer = m; 1565c2aa98e2SPeter Wemm } 1566c2aa98e2SPeter Wemm else if (strcmp(m->m_mailer, "[IPC]") == 0 || 1567c2aa98e2SPeter Wemm strcmp(m->m_mailer, "[TCP]") == 0) 1568c2aa98e2SPeter Wemm { 1569c2aa98e2SPeter Wemm #if DAEMON 1570c2aa98e2SPeter Wemm register int i; 1571c2aa98e2SPeter Wemm 1572c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1573c2aa98e2SPeter Wemm { 157406f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer); 1575c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1576c2aa98e2SPeter Wemm goto give_up; 1577c2aa98e2SPeter Wemm } 1578c2aa98e2SPeter Wemm 157906f25ae9SGregory Neil Shapiro # if NETUNIX 158006f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0) 158106f25ae9SGregory Neil Shapiro { 158206f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost"; 158306f25ae9SGregory Neil Shapiro mux_path = pv[1]; 158406f25ae9SGregory Neil Shapiro } 158506f25ae9SGregory Neil Shapiro else 158606f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 158706f25ae9SGregory Neil Shapiro { 1588c2aa98e2SPeter Wemm CurHostName = pv[1]; 158906f25ae9SGregory Neil Shapiro curhost = hostsignature(m, pv[1]); 159006f25ae9SGregory Neil Shapiro } 1591c2aa98e2SPeter Wemm 1592c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0') 1593c2aa98e2SPeter Wemm { 1594c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]); 1595c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1596c2aa98e2SPeter Wemm goto give_up; 1597c2aa98e2SPeter Wemm } 1598c2aa98e2SPeter Wemm 1599c2aa98e2SPeter Wemm if (!clever) 1600c2aa98e2SPeter Wemm { 160106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC"); 1602c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1603c2aa98e2SPeter Wemm goto give_up; 1604c2aa98e2SPeter Wemm } 160506f25ae9SGregory Neil Shapiro if (pv[2] != NULL 160606f25ae9SGregory Neil Shapiro # if NETUNIX 160706f25ae9SGregory Neil Shapiro && mux_path == NULL 160806f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 160906f25ae9SGregory Neil Shapiro ) 1610c2aa98e2SPeter Wemm { 161106f25ae9SGregory Neil Shapiro port = htons((u_short)atoi(pv[2])); 1612c2aa98e2SPeter Wemm if (port == 0) 1613c2aa98e2SPeter Wemm { 161406f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME 161506f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]); 161606f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */ 1617c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp"); 1618c2aa98e2SPeter Wemm 1619c2aa98e2SPeter Wemm if (sp == NULL) 1620c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]); 1621c2aa98e2SPeter Wemm else 1622c2aa98e2SPeter Wemm port = sp->s_port; 162306f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */ 1624c2aa98e2SPeter Wemm } 1625c2aa98e2SPeter Wemm } 1626c2aa98e2SPeter Wemm 162706f25ae9SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m); 162806f25ae9SGregory Neil Shapiro tryhost: 162906f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts) 163006f25ae9SGregory Neil Shapiro { 163106f25ae9SGregory Neil Shapiro char sep = ':'; 163206f25ae9SGregory Neil Shapiro char *endp; 163306f25ae9SGregory Neil Shapiro static char hostbuf[MAXNAME + 1]; 163406f25ae9SGregory Neil Shapiro 163506f25ae9SGregory Neil Shapiro # if NETINET6 163606f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '[') 163706f25ae9SGregory Neil Shapiro { 163806f25ae9SGregory Neil Shapiro endp = strchr(mxhosts[hostnum] + 1, ']'); 163906f25ae9SGregory Neil Shapiro if (endp != NULL) 164006f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 164106f25ae9SGregory Neil Shapiro } 164206f25ae9SGregory Neil Shapiro else 164306f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 164406f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 164506f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 164606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 164706f25ae9SGregory Neil Shapiro if (endp != NULL) 164806f25ae9SGregory Neil Shapiro { 164906f25ae9SGregory Neil Shapiro sep = *endp; 165006f25ae9SGregory Neil Shapiro *endp = '\0'; 165106f25ae9SGregory Neil Shapiro } 165206f25ae9SGregory Neil Shapiro 165306f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0') 1654c2aa98e2SPeter Wemm { 1655c2aa98e2SPeter Wemm syserr("deliver: null host name in signature"); 165606f25ae9SGregory Neil Shapiro hostnum++; 165706f25ae9SGregory Neil Shapiro if (endp != NULL) 165806f25ae9SGregory Neil Shapiro *endp = sep; 1659c2aa98e2SPeter Wemm continue; 1660c2aa98e2SPeter Wemm } 166106f25ae9SGregory Neil Shapiro (void) strlcpy(hostbuf, mxhosts[hostnum], 166206f25ae9SGregory Neil Shapiro sizeof hostbuf); 166306f25ae9SGregory Neil Shapiro hostnum++; 166406f25ae9SGregory Neil Shapiro if (endp != NULL) 166506f25ae9SGregory Neil Shapiro *endp = sep; 1666c2aa98e2SPeter Wemm 1667c2aa98e2SPeter Wemm /* see if we already know that this host is fried */ 1668c2aa98e2SPeter Wemm CurHostName = hostbuf; 1669c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m); 1670c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 1671c2aa98e2SPeter Wemm { 1672c2aa98e2SPeter Wemm if (tTd(11, 1)) 1673c2aa98e2SPeter Wemm { 167406f25ae9SGregory Neil Shapiro dprintf("openmailer: "); 1675c2aa98e2SPeter Wemm mci_dump(mci, FALSE); 1676c2aa98e2SPeter Wemm } 1677c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 1678c2aa98e2SPeter Wemm message("Using cached %sSMTP connection to %s via %s...", 1679c2aa98e2SPeter Wemm bitset(MCIF_ESMTP, mci->mci_flags) ? "E" : "", 1680c2aa98e2SPeter Wemm hostbuf, m->m_name); 168106f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 1682c2aa98e2SPeter Wemm break; 1683c2aa98e2SPeter Wemm } 1684c2aa98e2SPeter Wemm mci->mci_mailer = m; 1685c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK) 1686c2aa98e2SPeter Wemm { 1687c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL) 1688c2aa98e2SPeter Wemm goodmxfound = TRUE; 1689c2aa98e2SPeter Wemm continue; 1690c2aa98e2SPeter Wemm } 1691c2aa98e2SPeter Wemm 1692c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK) 1693c2aa98e2SPeter Wemm { 1694c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 1695c2aa98e2SPeter Wemm goodmxfound = TRUE; 1696c2aa98e2SPeter Wemm continue; 1697c2aa98e2SPeter Wemm } 1698c2aa98e2SPeter Wemm 1699c2aa98e2SPeter Wemm /* try the connection */ 170006f25ae9SGregory Neil Shapiro sm_setproctitle(TRUE, e, "%s %s: %s", 170106f25ae9SGregory Neil Shapiro qid_printname(e), 170206f25ae9SGregory Neil Shapiro hostbuf, "user open"); 170306f25ae9SGregory Neil Shapiro # if NETUNIX 170406f25ae9SGregory Neil Shapiro if (mux_path != NULL) 170506f25ae9SGregory Neil Shapiro { 170606f25ae9SGregory Neil Shapiro message("Connecting to %s via %s...", 170706f25ae9SGregory Neil Shapiro mux_path, m->m_name); 170806f25ae9SGregory Neil Shapiro i = makeconnection_ds(mux_path, mci); 170906f25ae9SGregory Neil Shapiro } 171006f25ae9SGregory Neil Shapiro else 171106f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 171206f25ae9SGregory Neil Shapiro { 1713c2aa98e2SPeter Wemm if (port == 0) 1714c2aa98e2SPeter Wemm message("Connecting to %s via %s...", 1715c2aa98e2SPeter Wemm hostbuf, m->m_name); 1716c2aa98e2SPeter Wemm else 1717c2aa98e2SPeter Wemm message("Connecting to %s port %d via %s...", 171806f25ae9SGregory Neil Shapiro hostbuf, ntohs(port), 171906f25ae9SGregory Neil Shapiro m->m_name); 1720c2aa98e2SPeter Wemm i = makeconnection(hostbuf, port, mci, e); 172106f25ae9SGregory Neil Shapiro } 1722c2aa98e2SPeter Wemm mci->mci_lastuse = curtime(); 172306f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0; 1724c2aa98e2SPeter Wemm mci->mci_exitstat = i; 1725c2aa98e2SPeter Wemm mci->mci_errno = errno; 1726c2aa98e2SPeter Wemm # if NAMED_BIND 1727c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 172806f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */ 1729c2aa98e2SPeter Wemm if (i == EX_OK) 1730c2aa98e2SPeter Wemm { 1731c2aa98e2SPeter Wemm goodmxfound = TRUE; 1732c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 1733c2aa98e2SPeter Wemm mci_cache(mci); 1734c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 1735c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "%05d === CONNECT %s\n", 1736c2aa98e2SPeter Wemm (int) getpid(), hostbuf); 1737c2aa98e2SPeter Wemm break; 1738c2aa98e2SPeter Wemm } 1739c2aa98e2SPeter Wemm else 1740c2aa98e2SPeter Wemm { 1741c2aa98e2SPeter Wemm if (tTd(11, 1)) 174206f25ae9SGregory Neil Shapiro dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 1743c2aa98e2SPeter Wemm i, errno); 1744c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL) 1745c2aa98e2SPeter Wemm goodmxfound = TRUE; 1746c2aa98e2SPeter Wemm mci_unlock_host(mci); 1747c2aa98e2SPeter Wemm } 1748c2aa98e2SPeter Wemm 1749c2aa98e2SPeter Wemm /* enter status of this host */ 1750c2aa98e2SPeter Wemm setstat(i); 1751c2aa98e2SPeter Wemm 1752c2aa98e2SPeter Wemm /* should print some message here for -v mode */ 1753c2aa98e2SPeter Wemm } 1754c2aa98e2SPeter Wemm if (mci == NULL) 1755c2aa98e2SPeter Wemm { 1756c2aa98e2SPeter Wemm syserr("deliver: no host name"); 1757c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 1758c2aa98e2SPeter Wemm goto give_up; 1759c2aa98e2SPeter Wemm } 1760c2aa98e2SPeter Wemm mci->mci_pid = 0; 176106f25ae9SGregory Neil Shapiro #else /* DAEMON */ 176206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 openmailer: no IPC"); 1763c2aa98e2SPeter Wemm if (tTd(11, 1)) 176406f25ae9SGregory Neil Shapiro dprintf("openmailer: NULL\n"); 1765c2aa98e2SPeter Wemm rcode = EX_UNAVAILABLE; 1766c2aa98e2SPeter Wemm goto give_up; 1767c2aa98e2SPeter Wemm #endif /* DAEMON */ 1768c2aa98e2SPeter Wemm } 1769c2aa98e2SPeter Wemm else 1770c2aa98e2SPeter Wemm { 1771c2aa98e2SPeter Wemm /* flush any expired connections */ 1772c2aa98e2SPeter Wemm (void) mci_scan(NULL); 1773c2aa98e2SPeter Wemm mci = NULL; 1774c2aa98e2SPeter Wemm 1775c2aa98e2SPeter Wemm #if SMTP 1776c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 1777c2aa98e2SPeter Wemm { 1778c2aa98e2SPeter Wemm /* try to get a cached connection */ 1779c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m); 1780c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 1781c2aa98e2SPeter Wemm mci->mci_host = m->m_name; 1782c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 1783c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 1784c2aa98e2SPeter Wemm { 1785c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...", 1786c2aa98e2SPeter Wemm m->m_name); 178706f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 1788c2aa98e2SPeter Wemm goto do_transfer; 1789c2aa98e2SPeter Wemm } 1790c2aa98e2SPeter Wemm } 179106f25ae9SGregory Neil Shapiro #endif /* SMTP */ 1792c2aa98e2SPeter Wemm 1793c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */ 1794c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0') 1795c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name); 1796c2aa98e2SPeter Wemm else 1797c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name); 1798c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 1799c2aa98e2SPeter Wemm { 1800c2aa98e2SPeter Wemm char **av; 1801c2aa98e2SPeter Wemm 1802c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid()); 1803c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 1804c2aa98e2SPeter Wemm fprintf(TrafficLogFile, " %s", *av); 1805c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "\n"); 1806c2aa98e2SPeter Wemm } 1807c2aa98e2SPeter Wemm 1808c2aa98e2SPeter Wemm #if XDEBUG 1809c2aa98e2SPeter Wemm checkfd012("before creating mail pipe"); 181006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1811c2aa98e2SPeter Wemm 1812c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */ 1813c2aa98e2SPeter Wemm if (pipe(mpvect) < 0) 1814c2aa98e2SPeter Wemm { 1815c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)", 1816c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 1817c2aa98e2SPeter Wemm if (tTd(11, 1)) 181806f25ae9SGregory Neil Shapiro dprintf("openmailer: NULL\n"); 1819c2aa98e2SPeter Wemm rcode = EX_OSERR; 1820c2aa98e2SPeter Wemm goto give_up; 1821c2aa98e2SPeter Wemm } 1822c2aa98e2SPeter Wemm 1823c2aa98e2SPeter Wemm #if XDEBUG 1824c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */ 1825c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3) 1826c2aa98e2SPeter Wemm { 1827c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d", 1828c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 1829c2aa98e2SPeter Wemm mpvect[0], mpvect[1]); 1830c2aa98e2SPeter Wemm printopenfds(TRUE); 1831c2aa98e2SPeter Wemm if (tTd(11, 1)) 183206f25ae9SGregory Neil Shapiro dprintf("openmailer: NULL\n"); 1833c2aa98e2SPeter Wemm rcode = EX_OSERR; 1834c2aa98e2SPeter Wemm goto give_up; 1835c2aa98e2SPeter Wemm } 1836c2aa98e2SPeter Wemm 1837c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */ 1838c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]"); 1839c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]"); 1840c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] || 1841c2aa98e2SPeter Wemm (e->e_lockfp != NULL && 1842c2aa98e2SPeter Wemm (mpvect[0] == fileno(e->e_lockfp) || 1843c2aa98e2SPeter Wemm mpvect[1] == fileno(e->e_lockfp)))) 1844c2aa98e2SPeter Wemm { 1845c2aa98e2SPeter Wemm if (e->e_lockfp == NULL) 1846c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d", 1847c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 1848c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]); 1849c2aa98e2SPeter Wemm else 1850c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 1851c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 1852c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1], 1853c2aa98e2SPeter Wemm fileno(e->e_lockfp)); 1854c2aa98e2SPeter Wemm } 185506f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1856c2aa98e2SPeter Wemm 185706f25ae9SGregory Neil Shapiro /* create a return pipe */ 1858c2aa98e2SPeter Wemm if (pipe(rpvect) < 0) 1859c2aa98e2SPeter Wemm { 1860c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)", 1861c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 1862c2aa98e2SPeter Wemm m->m_name); 1863c2aa98e2SPeter Wemm (void) close(mpvect[0]); 1864c2aa98e2SPeter Wemm (void) close(mpvect[1]); 1865c2aa98e2SPeter Wemm if (tTd(11, 1)) 186606f25ae9SGregory Neil Shapiro dprintf("openmailer: NULL\n"); 1867c2aa98e2SPeter Wemm rcode = EX_OSERR; 1868c2aa98e2SPeter Wemm goto give_up; 1869c2aa98e2SPeter Wemm } 1870c2aa98e2SPeter Wemm #if XDEBUG 1871c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]"); 1872c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]"); 187306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1874c2aa98e2SPeter Wemm 1875c2aa98e2SPeter Wemm /* 1876c2aa98e2SPeter Wemm ** Actually fork the mailer process. 1877c2aa98e2SPeter Wemm ** DOFORK is clever about retrying. 1878c2aa98e2SPeter Wemm ** 1879c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying 188006f25ae9SGregory Neil Shapiro ** around so that endmailer will get it. 1881c2aa98e2SPeter Wemm */ 1882c2aa98e2SPeter Wemm 1883c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 1884c2aa98e2SPeter Wemm (void) fflush(e->e_xfp); /* for debugging */ 1885c2aa98e2SPeter Wemm (void) fflush(stdout); 1886c2aa98e2SPeter Wemm (void) setsignal(SIGCHLD, SIG_DFL); 188706f25ae9SGregory Neil Shapiro 188806f25ae9SGregory Neil Shapiro 1889c2aa98e2SPeter Wemm DOFORK(FORK); 1890c2aa98e2SPeter Wemm /* pid is set by DOFORK */ 189106f25ae9SGregory Neil Shapiro 1892c2aa98e2SPeter Wemm if (pid < 0) 1893c2aa98e2SPeter Wemm { 1894c2aa98e2SPeter Wemm /* failure */ 1895c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork", 1896c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 1897c2aa98e2SPeter Wemm (void) close(mpvect[0]); 1898c2aa98e2SPeter Wemm (void) close(mpvect[1]); 1899c2aa98e2SPeter Wemm (void) close(rpvect[0]); 1900c2aa98e2SPeter Wemm (void) close(rpvect[1]); 1901c2aa98e2SPeter Wemm if (tTd(11, 1)) 190206f25ae9SGregory Neil Shapiro dprintf("openmailer: NULL\n"); 1903c2aa98e2SPeter Wemm rcode = EX_OSERR; 1904c2aa98e2SPeter Wemm goto give_up; 1905c2aa98e2SPeter Wemm } 1906c2aa98e2SPeter Wemm else if (pid == 0) 1907c2aa98e2SPeter Wemm { 1908c2aa98e2SPeter Wemm int i; 190906f25ae9SGregory Neil Shapiro int save_errno; 1910c2aa98e2SPeter Wemm int new_euid = NO_UID; 1911c2aa98e2SPeter Wemm int new_ruid = NO_UID; 1912c2aa98e2SPeter Wemm int new_gid = NO_GID; 1913c2aa98e2SPeter Wemm struct stat stb; 1914c2aa98e2SPeter Wemm extern int DtableSize; 1915c2aa98e2SPeter Wemm 1916c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 1917c2aa98e2SPeter Wemm (void) close(fileno(e->e_lockfp)); 1918c2aa98e2SPeter Wemm 1919c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */ 1920c2aa98e2SPeter Wemm (void) setsignal(SIGINT, SIG_IGN); 1921c2aa98e2SPeter Wemm (void) setsignal(SIGHUP, SIG_IGN); 1922c2aa98e2SPeter Wemm (void) setsignal(SIGTERM, SIG_DFL); 1923c2aa98e2SPeter Wemm 1924c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 1925c2aa98e2SPeter Wemm stb.st_mode = 0; 1926c2aa98e2SPeter Wemm 1927c2aa98e2SPeter Wemm # if HASSETUSERCONTEXT 1928c2aa98e2SPeter Wemm /* 1929c2aa98e2SPeter Wemm ** Set user resources. 1930c2aa98e2SPeter Wemm */ 1931c2aa98e2SPeter Wemm 1932c2aa98e2SPeter Wemm if (contextaddr != NULL) 1933c2aa98e2SPeter Wemm { 1934c2aa98e2SPeter Wemm struct passwd *pwd; 1935c2aa98e2SPeter Wemm 1936c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL) 1937c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser); 1938c2aa98e2SPeter Wemm else 1939c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user); 1940c2aa98e2SPeter Wemm if (pwd != NULL) 1941c2aa98e2SPeter Wemm (void) setusercontext(NULL, 1942c2aa98e2SPeter Wemm pwd, pwd->pw_uid, 1943c2aa98e2SPeter Wemm LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); 1944c2aa98e2SPeter Wemm } 194506f25ae9SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 1946c2aa98e2SPeter Wemm 1947c2aa98e2SPeter Wemm /* tweak niceness */ 1948c2aa98e2SPeter Wemm if (m->m_nice != 0) 194906f25ae9SGregory Neil Shapiro (void) nice(m->m_nice); 1950c2aa98e2SPeter Wemm 1951c2aa98e2SPeter Wemm /* reset group id */ 1952c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1953c2aa98e2SPeter Wemm new_gid = m->m_gid; 1954c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode)) 1955c2aa98e2SPeter Wemm new_gid = stb.st_gid; 1956c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0) 1957c2aa98e2SPeter Wemm { 1958c2aa98e2SPeter Wemm if (!DontInitGroups) 1959c2aa98e2SPeter Wemm { 1960c2aa98e2SPeter Wemm char *u = ctladdr->q_ruser; 1961c2aa98e2SPeter Wemm 1962c2aa98e2SPeter Wemm if (u == NULL) 1963c2aa98e2SPeter Wemm u = ctladdr->q_user; 1964c2aa98e2SPeter Wemm 1965c2aa98e2SPeter Wemm if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn) 196606f25ae9SGregory Neil Shapiro { 1967c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 1968c2aa98e2SPeter Wemm u, ctladdr->q_gid); 196906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 197006f25ae9SGregory Neil Shapiro } 1971c2aa98e2SPeter Wemm } 1972c2aa98e2SPeter Wemm else 1973c2aa98e2SPeter Wemm { 1974c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 1975c2aa98e2SPeter Wemm 1976c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid; 1977c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 197806f25ae9SGregory Neil Shapiro { 1979c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 198006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 198106f25ae9SGregory Neil Shapiro } 1982c2aa98e2SPeter Wemm } 1983c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid; 1984c2aa98e2SPeter Wemm } 1985c2aa98e2SPeter Wemm else 1986c2aa98e2SPeter Wemm { 1987c2aa98e2SPeter Wemm if (!DontInitGroups) 1988c2aa98e2SPeter Wemm { 1989c2aa98e2SPeter Wemm if (initgroups(DefUser, DefGid) == -1 && suidwarn) 199006f25ae9SGregory Neil Shapiro { 1991c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 1992c2aa98e2SPeter Wemm DefUser, DefGid); 199306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 199406f25ae9SGregory Neil Shapiro } 1995c2aa98e2SPeter Wemm } 1996c2aa98e2SPeter Wemm else 1997c2aa98e2SPeter Wemm { 1998c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 1999c2aa98e2SPeter Wemm 2000c2aa98e2SPeter Wemm gidset[0] = DefGid; 2001c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 200206f25ae9SGregory Neil Shapiro { 2003c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 200406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 200506f25ae9SGregory Neil Shapiro } 2006c2aa98e2SPeter Wemm } 2007c2aa98e2SPeter Wemm if (m->m_gid == 0) 2008c2aa98e2SPeter Wemm new_gid = DefGid; 2009c2aa98e2SPeter Wemm else 2010c2aa98e2SPeter Wemm new_gid = m->m_gid; 2011c2aa98e2SPeter Wemm } 201206f25ae9SGregory Neil Shapiro if (new_gid != NO_GID) 201306f25ae9SGregory Neil Shapiro { 201406f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 201506f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) && 201606f25ae9SGregory Neil Shapiro new_gid != getgid() && 201706f25ae9SGregory Neil Shapiro new_gid != getegid()) 201806f25ae9SGregory Neil Shapiro { 201906f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 202006f25ae9SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid"); 202106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 202206f25ae9SGregory Neil Shapiro } 202306f25ae9SGregory Neil Shapiro 202406f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn) 202506f25ae9SGregory Neil Shapiro { 2026c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed", 2027c2aa98e2SPeter Wemm (long) new_gid); 202806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 202906f25ae9SGregory Neil Shapiro } 203006f25ae9SGregory Neil Shapiro } 203106f25ae9SGregory Neil Shapiro 203206f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */ 203306f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL) 203406f25ae9SGregory Neil Shapiro { 203506f25ae9SGregory Neil Shapiro expand(m->m_rootdir, buf, sizeof buf, e); 203606f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 203706f25ae9SGregory Neil Shapiro dprintf("openmailer: chroot %s\n", 203806f25ae9SGregory Neil Shapiro buf); 203906f25ae9SGregory Neil Shapiro if (chroot(buf) < 0) 204006f25ae9SGregory Neil Shapiro { 204106f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)", 204206f25ae9SGregory Neil Shapiro buf); 204306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 204406f25ae9SGregory Neil Shapiro } 204506f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 204606f25ae9SGregory Neil Shapiro { 204706f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)"); 204806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 204906f25ae9SGregory Neil Shapiro } 205006f25ae9SGregory Neil Shapiro } 2051c2aa98e2SPeter Wemm 2052c2aa98e2SPeter Wemm /* reset user id */ 2053c2aa98e2SPeter Wemm endpwent(); 2054c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 2055c2aa98e2SPeter Wemm new_euid = m->m_uid; 2056c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode)) 2057c2aa98e2SPeter Wemm new_ruid = stb.st_uid; 2058c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 2059c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid; 2060c2aa98e2SPeter Wemm else if (m->m_uid != 0) 2061c2aa98e2SPeter Wemm new_ruid = m->m_uid; 2062c2aa98e2SPeter Wemm else 2063c2aa98e2SPeter Wemm new_ruid = DefUid; 2064c2aa98e2SPeter Wemm if (new_euid != NO_UID) 2065c2aa98e2SPeter Wemm { 206606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid) 206706f25ae9SGregory Neil Shapiro { 206806f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 206906f25ae9SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid"); 207006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 207106f25ae9SGregory Neil Shapiro } 207206f25ae9SGregory Neil Shapiro 2073c2aa98e2SPeter Wemm vendor_set_uid(new_euid); 207406f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 2075c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn) 207606f25ae9SGregory Neil Shapiro { 2077c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed", 2078c2aa98e2SPeter Wemm (long) new_euid); 207906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 208006f25ae9SGregory Neil Shapiro } 208106f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 208206f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 2083c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 208406f25ae9SGregory Neil Shapiro { 2085c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed", 2086c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid); 208706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 208806f25ae9SGregory Neil Shapiro } 208906f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 209006f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETUID 2091c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 209206f25ae9SGregory Neil Shapiro { 2093c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2094c2aa98e2SPeter Wemm (long) new_euid); 209506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 209606f25ae9SGregory Neil Shapiro } 209706f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETUID */ 2098c2aa98e2SPeter Wemm } 2099c2aa98e2SPeter Wemm else if (new_ruid != NO_UID) 2100c2aa98e2SPeter Wemm { 2101c2aa98e2SPeter Wemm vendor_set_uid(new_ruid); 2102c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn) 210306f25ae9SGregory Neil Shapiro { 2104c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2105c2aa98e2SPeter Wemm (long) new_ruid); 210606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 210706f25ae9SGregory Neil Shapiro } 2108c2aa98e2SPeter Wemm } 2109c2aa98e2SPeter Wemm 2110c2aa98e2SPeter Wemm if (tTd(11, 2)) 211106f25ae9SGregory Neil Shapiro dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", 211206f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 211306f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 2114c2aa98e2SPeter Wemm 2115c2aa98e2SPeter Wemm /* move into some "safe" directory */ 2116c2aa98e2SPeter Wemm if (m->m_execdir != NULL) 2117c2aa98e2SPeter Wemm { 2118c2aa98e2SPeter Wemm char *q; 2119c2aa98e2SPeter Wemm 2120c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q) 2121c2aa98e2SPeter Wemm { 2122c2aa98e2SPeter Wemm q = strchr(p, ':'); 2123c2aa98e2SPeter Wemm if (q != NULL) 2124c2aa98e2SPeter Wemm *q = '\0'; 2125c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 2126c2aa98e2SPeter Wemm if (q != NULL) 2127c2aa98e2SPeter Wemm *q++ = ':'; 2128c2aa98e2SPeter Wemm if (tTd(11, 20)) 212906f25ae9SGregory Neil Shapiro dprintf("openmailer: trydir %s\n", 2130c2aa98e2SPeter Wemm buf); 2131c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 2132c2aa98e2SPeter Wemm break; 2133c2aa98e2SPeter Wemm } 2134c2aa98e2SPeter Wemm } 2135c2aa98e2SPeter Wemm 2136c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */ 2137c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2138c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0) 2139c2aa98e2SPeter Wemm { 2140c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 2141c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2142c2aa98e2SPeter Wemm m->m_name, rpvect[1]); 2143c2aa98e2SPeter Wemm _exit(EX_OSERR); 2144c2aa98e2SPeter Wemm } 2145c2aa98e2SPeter Wemm (void) close(rpvect[1]); 214606f25ae9SGregory Neil Shapiro 2147c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 2148c2aa98e2SPeter Wemm { 2149c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr", 2150c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2151c2aa98e2SPeter Wemm m->m_name); 2152c2aa98e2SPeter Wemm _exit(EX_OSERR); 2153c2aa98e2SPeter Wemm } 2154c2aa98e2SPeter Wemm 2155c2aa98e2SPeter Wemm /* arrange to get standard input */ 2156c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2157c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0) 2158c2aa98e2SPeter Wemm { 2159c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 2160c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2161c2aa98e2SPeter Wemm m->m_name, mpvect[0]); 2162c2aa98e2SPeter Wemm _exit(EX_OSERR); 2163c2aa98e2SPeter Wemm } 2164c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2165c2aa98e2SPeter Wemm 2166c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2167c2aa98e2SPeter Wemm for (i = 3; i < DtableSize; i++) 2168c2aa98e2SPeter Wemm { 2169c2aa98e2SPeter Wemm register int j; 2170c2aa98e2SPeter Wemm 2171c2aa98e2SPeter Wemm if ((j = fcntl(i, F_GETFD, 0)) != -1) 217206f25ae9SGregory Neil Shapiro (void) fcntl(i, F_SETFD, 217306f25ae9SGregory Neil Shapiro j | FD_CLOEXEC); 2174c2aa98e2SPeter Wemm } 2175c2aa98e2SPeter Wemm 2176c2aa98e2SPeter Wemm /* run disconnected from terminal */ 2177c2aa98e2SPeter Wemm (void) setsid(); 2178c2aa98e2SPeter Wemm 2179c2aa98e2SPeter Wemm /* try to execute the mailer */ 218006f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv, 218106f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron); 218206f25ae9SGregory Neil Shapiro save_errno = errno; 2183c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer); 2184c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) || 218506f25ae9SGregory Neil Shapiro transienterror(save_errno)) 2186c2aa98e2SPeter Wemm _exit(EX_OSERR); 2187c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE); 2188c2aa98e2SPeter Wemm } 2189c2aa98e2SPeter Wemm 2190c2aa98e2SPeter Wemm /* 2191c2aa98e2SPeter Wemm ** Set up return value. 2192c2aa98e2SPeter Wemm */ 2193c2aa98e2SPeter Wemm 2194c2aa98e2SPeter Wemm if (mci == NULL) 2195c2aa98e2SPeter Wemm { 2196c2aa98e2SPeter Wemm mci = (MCI *) xalloc(sizeof *mci); 219706f25ae9SGregory Neil Shapiro memset((char *) mci, '\0', sizeof *mci); 2198c2aa98e2SPeter Wemm } 2199c2aa98e2SPeter Wemm mci->mci_mailer = m; 2200c2aa98e2SPeter Wemm if (clever) 2201c2aa98e2SPeter Wemm { 2202c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2203c2aa98e2SPeter Wemm mci_cache(mci); 2204c2aa98e2SPeter Wemm } 2205c2aa98e2SPeter Wemm else 2206c2aa98e2SPeter Wemm { 2207c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2208c2aa98e2SPeter Wemm } 2209c2aa98e2SPeter Wemm mci->mci_pid = pid; 2210c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2211c2aa98e2SPeter Wemm mci->mci_out = fdopen(mpvect[1], "w"); 2212c2aa98e2SPeter Wemm if (mci->mci_out == NULL) 2213c2aa98e2SPeter Wemm { 2214c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d", 2215c2aa98e2SPeter Wemm mpvect[1]); 2216c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2217c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2218c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2219c2aa98e2SPeter Wemm rcode = EX_OSERR; 2220c2aa98e2SPeter Wemm goto give_up; 2221c2aa98e2SPeter Wemm } 222206f25ae9SGregory Neil Shapiro 2223c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2224c2aa98e2SPeter Wemm mci->mci_in = fdopen(rpvect[0], "r"); 2225c2aa98e2SPeter Wemm if (mci->mci_in == NULL) 2226c2aa98e2SPeter Wemm { 2227c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d", 2228c2aa98e2SPeter Wemm mpvect[1]); 2229c2aa98e2SPeter Wemm (void) close(rpvect[0]); 223006f25ae9SGregory Neil Shapiro (void) fclose(mci->mci_out); 2231c2aa98e2SPeter Wemm mci->mci_out = NULL; 2232c2aa98e2SPeter Wemm rcode = EX_OSERR; 2233c2aa98e2SPeter Wemm goto give_up; 2234c2aa98e2SPeter Wemm } 223506f25ae9SGregory Neil Shapiro 223606f25ae9SGregory Neil Shapiro /* Don't cache non-clever connections */ 223706f25ae9SGregory Neil Shapiro if (!clever) 2238c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_TEMP; 2239c2aa98e2SPeter Wemm } 2240c2aa98e2SPeter Wemm 2241c2aa98e2SPeter Wemm /* 2242c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol. 2243c2aa98e2SPeter Wemm */ 2244c2aa98e2SPeter Wemm 2245c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) && 2246c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING)) 2247c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT; 2248c2aa98e2SPeter Wemm #if SMTP 2249c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED) 2250c2aa98e2SPeter Wemm { 225106f25ae9SGregory Neil Shapiro # if SASL && SFIO 2252193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 225306f25ae9SGregory Neil Shapiro # endif /* SASL && SFIO */ 225406f25ae9SGregory Neil Shapiro # if STARTTLS 2255193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 225606f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 2257193538b7SGregory Neil Shapiro # define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 2258193538b7SGregory Neil Shapiro # define SET_HELO(f) f |= MCIF_ONLY_EHLO 2259193538b7SGregory Neil Shapiro # define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 2260c2aa98e2SPeter Wemm 2261193538b7SGregory Neil Shapiro 226206f25ae9SGregory Neil Shapiro # if STARTTLS || (SASL && SFIO) 226306f25ae9SGregory Neil Shapiro reconnect: /* after switching to an authenticated connection */ 226406f25ae9SGregory Neil Shapiro # endif /* STARTTLS || (SASL && SFIO) */ 226506f25ae9SGregory Neil Shapiro 226606f25ae9SGregory Neil Shapiro # if SASL 226706f25ae9SGregory Neil Shapiro mci->mci_saslcap = NULL; 226806f25ae9SGregory Neil Shapiro # endif /* SASL */ 2269193538b7SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 2270193538b7SGregory Neil Shapiro CLR_HELO(mci->mci_flags); 227106f25ae9SGregory Neil Shapiro 227206f25ae9SGregory Neil Shapiro # if STARTTLS 227306f25ae9SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */ 2274193538b7SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 2275193538b7SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags)) 227606f25ae9SGregory Neil Shapiro { 227706f25ae9SGregory Neil Shapiro int olderrors; 2278602a2b1bSGregory Neil Shapiro int dotpos; 227906f25ae9SGregory Neil Shapiro bool usetls; 228006f25ae9SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 228106f25ae9SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 2282193538b7SGregory Neil Shapiro char *host = NULL; 228342e5d165SGregory Neil Shapiro # if _FFR_TLS_CLT1 228442e5d165SGregory Neil Shapiro char *p; 228542e5d165SGregory Neil Shapiro # endif /* _FFR_TLS_CLT1 */ 2286602a2b1bSGregory Neil Shapiro char *srvname; 228706f25ae9SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 228806f25ae9SGregory Neil Shapiro 228906f25ae9SGregory Neil Shapiro rcode = EX_OK; 229006f25ae9SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags); 229142e5d165SGregory Neil Shapiro # if _FFR_TLS_CLT1 229242e5d165SGregory Neil Shapiro if (usetls && 229342e5d165SGregory Neil Shapiro (p = macvalue(macid("{client_flags}", NULL), e)) 229442e5d165SGregory Neil Shapiro != NULL) 229542e5d165SGregory Neil Shapiro { 229642e5d165SGregory Neil Shapiro for (; *p != '\0'; p++) 229742e5d165SGregory Neil Shapiro { 229842e5d165SGregory Neil Shapiro /* look for just this one flag */ 229942e5d165SGregory Neil Shapiro if (*p == D_CLTNOTLS) 230042e5d165SGregory Neil Shapiro { 230142e5d165SGregory Neil Shapiro usetls = FALSE; 230242e5d165SGregory Neil Shapiro break; 230342e5d165SGregory Neil Shapiro } 230442e5d165SGregory Neil Shapiro } 230542e5d165SGregory Neil Shapiro } 230642e5d165SGregory Neil Shapiro # endif /* _FFR_TLS_CLT1 */ 230742e5d165SGregory Neil Shapiro 2308602a2b1bSGregory Neil Shapiro if (mci->mci_host != NULL) 2309602a2b1bSGregory Neil Shapiro { 2310602a2b1bSGregory Neil Shapiro srvname = mci->mci_host; 2311602a2b1bSGregory Neil Shapiro dotpos = strlen(srvname) - 1; 2312602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2313602a2b1bSGregory Neil Shapiro { 2314602a2b1bSGregory Neil Shapiro if (srvname[dotpos] == '.') 2315602a2b1bSGregory Neil Shapiro srvname[dotpos] = '\0'; 2316602a2b1bSGregory Neil Shapiro else 2317602a2b1bSGregory Neil Shapiro dotpos = -1; 2318602a2b1bSGregory Neil Shapiro } 2319602a2b1bSGregory Neil Shapiro } 2320602a2b1bSGregory Neil Shapiro else 2321602a2b1bSGregory Neil Shapiro { 2322602a2b1bSGregory Neil Shapiro srvname = ""; 2323602a2b1bSGregory Neil Shapiro dotpos = -1; 2324602a2b1bSGregory Neil Shapiro } 232506f25ae9SGregory Neil Shapiro define(macid("{server_name}", NULL), 2326602a2b1bSGregory Neil Shapiro newstr(srvname), e); 232706f25ae9SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0) 232806f25ae9SGregory Neil Shapiro define(macid("{server_addr}", NULL), 232906f25ae9SGregory Neil Shapiro newstr(anynet_ntoa(&CurHostAddr)), e); 233006f25ae9SGregory Neil Shapiro else 233106f25ae9SGregory Neil Shapiro define(macid("{server_addr}", NULL), NULL, e); 233206f25ae9SGregory Neil Shapiro if (usetls) 233306f25ae9SGregory Neil Shapiro { 2334193538b7SGregory Neil Shapiro host = macvalue(macid("{server_name}", NULL), 2335193538b7SGregory Neil Shapiro e); 2336193538b7SGregory Neil Shapiro # if _FFR_TLS_O_T 233706f25ae9SGregory Neil Shapiro olderrors = Errors; 233806f25ae9SGregory Neil Shapiro QuickAbort = FALSE; 233906f25ae9SGregory Neil Shapiro SuprErrs = TRUE; 2340602a2b1bSGregory Neil Shapiro if (rscheck("try_tls", srvname, NULL, 2341193538b7SGregory Neil Shapiro e, TRUE, FALSE, 8, host) != EX_OK 234206f25ae9SGregory Neil Shapiro || Errors > olderrors) 234306f25ae9SGregory Neil Shapiro usetls = FALSE; 234406f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 234506f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 234606f25ae9SGregory Neil Shapiro # endif /* _FFR_TLS_O_T */ 2347193538b7SGregory Neil Shapiro } 234806f25ae9SGregory Neil Shapiro 2349602a2b1bSGregory Neil Shapiro /* undo change of srvname */ 2350602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2351602a2b1bSGregory Neil Shapiro srvname[dotpos] = '.'; 235206f25ae9SGregory Neil Shapiro if (usetls) 235306f25ae9SGregory Neil Shapiro { 235406f25ae9SGregory Neil Shapiro if ((rcode = starttls(m, mci, e)) == EX_OK) 235506f25ae9SGregory Neil Shapiro { 235606f25ae9SGregory Neil Shapiro /* start again without STARTTLS */ 235706f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT; 235806f25ae9SGregory Neil Shapiro } 235906f25ae9SGregory Neil Shapiro else 236006f25ae9SGregory Neil Shapiro { 236106f25ae9SGregory Neil Shapiro char *s; 236206f25ae9SGregory Neil Shapiro 236306f25ae9SGregory Neil Shapiro /* 236406f25ae9SGregory Neil Shapiro ** TLS negotation failed, what to do? 236506f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection 236606f25ae9SGregory Neil Shapiro ** or abort? How to decide? 236706f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset. 236806f25ae9SGregory Neil Shapiro */ 236906f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS; 237006f25ae9SGregory Neil Shapiro switch (rcode) 237106f25ae9SGregory Neil Shapiro { 237206f25ae9SGregory Neil Shapiro case EX_TEMPFAIL: 237306f25ae9SGregory Neil Shapiro s = "TEMP"; 237406f25ae9SGregory Neil Shapiro break; 237506f25ae9SGregory Neil Shapiro case EX_USAGE: 237606f25ae9SGregory Neil Shapiro s = "USAGE"; 237706f25ae9SGregory Neil Shapiro break; 237806f25ae9SGregory Neil Shapiro case EX_PROTOCOL: 237906f25ae9SGregory Neil Shapiro s = "PROTOCOL"; 238006f25ae9SGregory Neil Shapiro break; 238106f25ae9SGregory Neil Shapiro case EX_SOFTWARE: 238206f25ae9SGregory Neil Shapiro s = "SOFTWARE"; 238306f25ae9SGregory Neil Shapiro break; 238406f25ae9SGregory Neil Shapiro 238506f25ae9SGregory Neil Shapiro /* everything else is a failure */ 238606f25ae9SGregory Neil Shapiro default: 238706f25ae9SGregory Neil Shapiro s = "FAILURE"; 238806f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL; 238906f25ae9SGregory Neil Shapiro } 239006f25ae9SGregory Neil Shapiro define(macid("{verify}", NULL), 239106f25ae9SGregory Neil Shapiro newstr(s), e); 239206f25ae9SGregory Neil Shapiro } 239306f25ae9SGregory Neil Shapiro } 2394193538b7SGregory Neil Shapiro else if (mci->mci_ssl != NULL) 2395193538b7SGregory Neil Shapiro { 2396193538b7SGregory Neil Shapiro /* active TLS connection, use that data */ 2397193538b7SGregory Neil Shapiro (void) tls_get_info(mci->mci_ssl, e, FALSE, 2398193538b7SGregory Neil Shapiro mci->mci_host, FALSE); 2399193538b7SGregory Neil Shapiro } 240006f25ae9SGregory Neil Shapiro else 240106f25ae9SGregory Neil Shapiro define(macid("{verify}", NULL), "NONE", e); 240206f25ae9SGregory Neil Shapiro olderrors = Errors; 240306f25ae9SGregory Neil Shapiro QuickAbort = FALSE; 240406f25ae9SGregory Neil Shapiro SuprErrs = TRUE; 240506f25ae9SGregory Neil Shapiro 240606f25ae9SGregory Neil Shapiro /* 240706f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special: 240806f25ae9SGregory Neil Shapiro ** the TLS negotation failed 240906f25ae9SGregory Neil Shapiro ** we have to drop the connection no matter what 241006f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance 241106f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate 241206f25ae9SGregory Neil Shapiro ** error code. 241306f25ae9SGregory Neil Shapiro */ 241406f25ae9SGregory Neil Shapiro if (rscheck("tls_server", 241506f25ae9SGregory Neil Shapiro macvalue(macid("{verify}", NULL), e), 2416193538b7SGregory Neil Shapiro NULL, e, TRUE, TRUE, 6, host) != EX_OK || 241706f25ae9SGregory Neil Shapiro Errors > olderrors || 241806f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE) 241906f25ae9SGregory Neil Shapiro { 242006f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN]; 242106f25ae9SGregory Neil Shapiro extern char MsgBuf[]; 242206f25ae9SGregory Neil Shapiro 242306f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) && 242406f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 242506f25ae9SGregory Neil Shapiro { 242606f25ae9SGregory Neil Shapiro p = newstr(MsgBuf); 242706f25ae9SGregory Neil Shapiro } 242806f25ae9SGregory Neil Shapiro else 242906f25ae9SGregory Neil Shapiro { 243006f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated."; 243106f25ae9SGregory Neil Shapiro (void) strlcpy(enhsc, "4.7.0", 243206f25ae9SGregory Neil Shapiro sizeof enhsc); 243306f25ae9SGregory Neil Shapiro } 243406f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 243506f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 243606f25ae9SGregory Neil Shapiro 243706f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE) 243806f25ae9SGregory Neil Shapiro { 243906f25ae9SGregory Neil Shapiro /* drop the connection */ 244006f25ae9SGregory Neil Shapiro mci->mci_state = MCIS_QUITING; 244106f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 244206f25ae9SGregory Neil Shapiro { 244306f25ae9SGregory Neil Shapiro (void) fclose(mci->mci_in); 244406f25ae9SGregory Neil Shapiro mci->mci_in = NULL; 244506f25ae9SGregory Neil Shapiro } 244606f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 244706f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv); 244806f25ae9SGregory Neil Shapiro } 244906f25ae9SGregory Neil Shapiro else 245006f25ae9SGregory Neil Shapiro { 245106f25ae9SGregory Neil Shapiro /* abort transfer */ 245206f25ae9SGregory Neil Shapiro smtpquit(m, mci, e); 245306f25ae9SGregory Neil Shapiro } 245406f25ae9SGregory Neil Shapiro 2455193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 2456193538b7SGregory Neil Shapiro mci->mci_errno = 0; 2457193538b7SGregory Neil Shapiro 245806f25ae9SGregory Neil Shapiro /* temp or permanent failure? */ 245906f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL 246006f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE; 246106f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, newstr(enhsc), p); 246206f25ae9SGregory Neil Shapiro 246306f25ae9SGregory Neil Shapiro /* 246406f25ae9SGregory Neil Shapiro ** hack to get the error message into 246506f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse()) 246606f25ae9SGregory Neil Shapiro */ 246706f25ae9SGregory Neil Shapiro (void) strlcpy(SmtpError, p, sizeof SmtpError); 246806f25ae9SGregory Neil Shapiro } 246906f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 247006f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 2471193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) && 2472193538b7SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED) 247306f25ae9SGregory Neil Shapiro { 2474193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 247506f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 247606f25ae9SGregory Neil Shapiro goto reconnect; 247706f25ae9SGregory Neil Shapiro } 247806f25ae9SGregory Neil Shapiro } 2479193538b7SGregory Neil Shapiro else if (mci->mci_ssl != NULL) 2480193538b7SGregory Neil Shapiro { 2481193538b7SGregory Neil Shapiro /* active TLS connection, use that data */ 2482193538b7SGregory Neil Shapiro (void) tls_get_info(mci->mci_ssl, e, FALSE, 2483193538b7SGregory Neil Shapiro mci->mci_host, FALSE); 2484193538b7SGregory Neil Shapiro } 248506f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 248606f25ae9SGregory Neil Shapiro # if SASL 248706f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */ 248806f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 248906f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL && 249006f25ae9SGregory Neil Shapiro # if SFIO 2491193538b7SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && 249206f25ae9SGregory Neil Shapiro # endif /* SFIO */ 249306f25ae9SGregory Neil Shapiro SASLInfo != NULL) 249406f25ae9SGregory Neil Shapiro { 249506f25ae9SGregory Neil Shapiro /* 249606f25ae9SGregory Neil Shapiro ** should we require some minimum authentication? 249706f25ae9SGregory Neil Shapiro ** XXX ignore result? 249806f25ae9SGregory Neil Shapiro */ 249906f25ae9SGregory Neil Shapiro if (smtpauth(m, mci, e) == EX_OK) 250006f25ae9SGregory Neil Shapiro { 250106f25ae9SGregory Neil Shapiro # if SFIO 250206f25ae9SGregory Neil Shapiro int result; 250306f25ae9SGregory Neil Shapiro sasl_ssf_t *ssf; 250406f25ae9SGregory Neil Shapiro 250506f25ae9SGregory Neil Shapiro /* get security strength (features) */ 250606f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF, 250706f25ae9SGregory Neil Shapiro (void **) &ssf); 250806f25ae9SGregory Neil Shapiro if (LogLevel > 9) 250906f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 251006f25ae9SGregory Neil Shapiro "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d", 251106f25ae9SGregory Neil Shapiro mci->mci_host, 251206f25ae9SGregory Neil Shapiro macvalue(macid("{auth_type}", 251306f25ae9SGregory Neil Shapiro NULL), e), 251406f25ae9SGregory Neil Shapiro *ssf); 251506f25ae9SGregory Neil Shapiro /* 251606f25ae9SGregory Neil Shapiro ** only switch to encrypted connection 251706f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated 251806f25ae9SGregory Neil Shapiro */ 251906f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0) 252006f25ae9SGregory Neil Shapiro { 252106f25ae9SGregory Neil Shapiro /* 252206f25ae9SGregory Neil Shapiro ** convert sfio stuff to use SASL 252306f25ae9SGregory Neil Shapiro ** check return values 252406f25ae9SGregory Neil Shapiro ** if the call fails, 252506f25ae9SGregory Neil Shapiro ** fall back to unencrypted version 252606f25ae9SGregory Neil Shapiro ** unless some cf option requires 252706f25ae9SGregory Neil Shapiro ** encryption then the connection must 252806f25ae9SGregory Neil Shapiro ** be aborted 252906f25ae9SGregory Neil Shapiro */ 253006f25ae9SGregory Neil Shapiro if (sfdcsasl(mci->mci_in, mci->mci_out, 253106f25ae9SGregory Neil Shapiro mci->mci_conn) == 0) 253206f25ae9SGregory Neil Shapiro { 2533193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 253406f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 253506f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 253606f25ae9SGregory Neil Shapiro goto reconnect; 253706f25ae9SGregory Neil Shapiro } 253806f25ae9SGregory Neil Shapiro syserr("SASL TLS switch failed in client"); 253906f25ae9SGregory Neil Shapiro } 254006f25ae9SGregory Neil Shapiro /* else? XXX */ 254106f25ae9SGregory Neil Shapiro # endif /* SFIO */ 254206f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 254306f25ae9SGregory Neil Shapiro 254406f25ae9SGregory Neil Shapiro } 254506f25ae9SGregory Neil Shapiro } 254606f25ae9SGregory Neil Shapiro # endif /* SASL */ 254706f25ae9SGregory Neil Shapiro } 254806f25ae9SGregory Neil Shapiro 254906f25ae9SGregory Neil Shapiro #endif /* SMTP */ 2550c2aa98e2SPeter Wemm 2551c2aa98e2SPeter Wemm do_transfer: 2552c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 2553c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 2554c2aa98e2SPeter Wemm 2555c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 2556c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 2557c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags)) 2558c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7; 2559c2aa98e2SPeter Wemm 2560c2aa98e2SPeter Wemm #if MIME7TO8 2561c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) && 2562c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) && 2563c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 2564c2aa98e2SPeter Wemm (strcasecmp(p, "quoted-printable") == 0 || 2565c2aa98e2SPeter Wemm strcasecmp(p, "base64") == 0) && 2566c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 2567c2aa98e2SPeter Wemm { 2568c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 2569c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 2570c2aa98e2SPeter Wemm if (strncasecmp(p, "text/plain", 10) == 0 && 2571c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 2572c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8; 2573c2aa98e2SPeter Wemm } 257406f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 2575c2aa98e2SPeter Wemm 2576c2aa98e2SPeter Wemm if (tTd(11, 1)) 2577c2aa98e2SPeter Wemm { 257806f25ae9SGregory Neil Shapiro dprintf("openmailer: "); 2579c2aa98e2SPeter Wemm mci_dump(mci, FALSE); 2580c2aa98e2SPeter Wemm } 2581c2aa98e2SPeter Wemm 2582c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 2583c2aa98e2SPeter Wemm { 2584c2aa98e2SPeter Wemm /* couldn't open the mailer */ 2585c2aa98e2SPeter Wemm rcode = mci->mci_exitstat; 2586c2aa98e2SPeter Wemm errno = mci->mci_errno; 2587c2aa98e2SPeter Wemm #if NAMED_BIND 2588602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno); 258906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 2590c2aa98e2SPeter Wemm if (rcode == EX_OK) 2591c2aa98e2SPeter Wemm { 2592c2aa98e2SPeter Wemm /* shouldn't happen */ 259306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 259406f25ae9SGregory Neil Shapiro (u_long) mci, rcode, errno, mci->mci_state, 2595c2aa98e2SPeter Wemm firstsig); 2596c2aa98e2SPeter Wemm mci_dump_all(TRUE); 2597c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 2598c2aa98e2SPeter Wemm } 2599c2aa98e2SPeter Wemm #if DAEMON 260006f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum) 2601c2aa98e2SPeter Wemm { 2602c2aa98e2SPeter Wemm /* try next MX site */ 2603c2aa98e2SPeter Wemm goto tryhost; 2604c2aa98e2SPeter Wemm } 260506f25ae9SGregory Neil Shapiro #endif /* DAEMON */ 2606c2aa98e2SPeter Wemm } 2607c2aa98e2SPeter Wemm else if (!clever) 2608c2aa98e2SPeter Wemm { 2609c2aa98e2SPeter Wemm /* 2610c2aa98e2SPeter Wemm ** Format and send message. 2611c2aa98e2SPeter Wemm */ 2612c2aa98e2SPeter Wemm 2613c2aa98e2SPeter Wemm putfromline(mci, e); 26142e43090eSPeter Wemm (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 2615c2aa98e2SPeter Wemm (*e->e_putbody)(mci, e, NULL); 2616c2aa98e2SPeter Wemm 2617c2aa98e2SPeter Wemm /* get the exit status */ 2618c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv); 2619602a2b1bSGregory Neil Shapiro if (rcode == EX_TEMPFAIL && 2620602a2b1bSGregory Neil Shapiro SmtpError[0] == '\0') 2621602a2b1bSGregory Neil Shapiro { 2622602a2b1bSGregory Neil Shapiro /* 2623602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display. 2624602a2b1bSGregory Neil Shapiro ** We set SmtpError as 2625602a2b1bSGregory Neil Shapiro */ 2626602a2b1bSGregory Neil Shapiro 2627602a2b1bSGregory Neil Shapiro snprintf(SmtpError, sizeof SmtpError, 2628602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL", 2629602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer); 2630602a2b1bSGregory Neil Shapiro } 2631c2aa98e2SPeter Wemm } 2632c2aa98e2SPeter Wemm else 2633c2aa98e2SPeter Wemm #if SMTP 2634c2aa98e2SPeter Wemm { 2635c2aa98e2SPeter Wemm /* 2636c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol 2637c2aa98e2SPeter Wemm */ 2638c2aa98e2SPeter Wemm 2639c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e); 2640c2aa98e2SPeter Wemm if (rcode == EX_OK) 2641c2aa98e2SPeter Wemm { 2642c2aa98e2SPeter Wemm register char *t = tobuf; 2643c2aa98e2SPeter Wemm register int i; 2644c2aa98e2SPeter Wemm 2645c2aa98e2SPeter Wemm /* send the recipient list */ 2646c2aa98e2SPeter Wemm tobuf[0] = '\0'; 264706f25ae9SGregory Neil Shapiro 2648c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 2649c2aa98e2SPeter Wemm { 2650c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 265106f25ae9SGregory Neil Shapiro #if !_FFR_DYNAMIC_TOBUF 265206f25ae9SGregory Neil Shapiro if (strlen(to->q_paddr) + 265306f25ae9SGregory Neil Shapiro (t - tobuf) + 2 > sizeof tobuf) 2654c2aa98e2SPeter Wemm { 2655c2aa98e2SPeter Wemm /* not enough room */ 2656c2aa98e2SPeter Wemm continue; 2657c2aa98e2SPeter Wemm } 265806f25ae9SGregory Neil Shapiro #endif /* !_FFR_DYNAMIC_TOBUF */ 265906f25ae9SGregory Neil Shapiro 266006f25ae9SGregory Neil Shapiro # if STARTTLS 266106f25ae9SGregory Neil Shapiro # if _FFR_TLS_RCPT 266206f25ae9SGregory Neil Shapiro i = rscheck("tls_rcpt", to->q_user, NULL, e, 2663193538b7SGregory Neil Shapiro TRUE, TRUE, 4, mci->mci_host); 266406f25ae9SGregory Neil Shapiro if (i != EX_OK) 2665c2aa98e2SPeter Wemm { 2666193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 2667193538b7SGregory Neil Shapiro errno = 0; 266806f25ae9SGregory Neil Shapiro markfailure(e, to, mci, i, FALSE); 266906f25ae9SGregory Neil Shapiro giveresponse(i, to->q_status, m, 267006f25ae9SGregory Neil Shapiro mci, ctladdr, xstart, e); 267106f25ae9SGregory Neil Shapiro continue; 267206f25ae9SGregory Neil Shapiro } 267306f25ae9SGregory Neil Shapiro # endif /* _FFR_TLS_RCPT */ 267406f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 267506f25ae9SGregory Neil Shapiro 267606f25ae9SGregory Neil Shapiro if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 267706f25ae9SGregory Neil Shapiro { 267806f25ae9SGregory Neil Shapiro markfailure(e, to, mci, i, FALSE); 267906f25ae9SGregory Neil Shapiro giveresponse(i, to->q_status, m, 268006f25ae9SGregory Neil Shapiro mci, ctladdr, xstart, e); 2681c2aa98e2SPeter Wemm } 2682c2aa98e2SPeter Wemm else 2683c2aa98e2SPeter Wemm { 2684c2aa98e2SPeter Wemm *t++ = ','; 2685c2aa98e2SPeter Wemm for (p = to->q_paddr; *p; *t++ = *p++) 2686c2aa98e2SPeter Wemm continue; 2687c2aa98e2SPeter Wemm *t = '\0'; 2688c2aa98e2SPeter Wemm } 2689c2aa98e2SPeter Wemm } 2690c2aa98e2SPeter Wemm 2691c2aa98e2SPeter Wemm /* now send the data */ 2692c2aa98e2SPeter Wemm if (tobuf[0] == '\0') 2693c2aa98e2SPeter Wemm { 2694c2aa98e2SPeter Wemm rcode = EX_OK; 2695c2aa98e2SPeter Wemm e->e_to = NULL; 2696c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 2697c2aa98e2SPeter Wemm smtprset(m, mci, e); 2698c2aa98e2SPeter Wemm } 2699c2aa98e2SPeter Wemm else 2700c2aa98e2SPeter Wemm { 2701c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 2702c2aa98e2SPeter Wemm rcode = smtpdata(m, mci, e); 2703c2aa98e2SPeter Wemm } 2704c2aa98e2SPeter Wemm } 2705c2aa98e2SPeter Wemm # if DAEMON 270606f25ae9SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 2707c2aa98e2SPeter Wemm { 2708c2aa98e2SPeter Wemm /* try next MX site */ 2709c2aa98e2SPeter Wemm goto tryhost; 2710c2aa98e2SPeter Wemm } 271106f25ae9SGregory Neil Shapiro # endif /* DAEMON */ 2712c2aa98e2SPeter Wemm } 271306f25ae9SGregory Neil Shapiro #else /* SMTP */ 2714c2aa98e2SPeter Wemm { 271506f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: need SMTP compiled to use clever mailer"); 2716c2aa98e2SPeter Wemm rcode = EX_CONFIG; 2717c2aa98e2SPeter Wemm goto give_up; 2718c2aa98e2SPeter Wemm } 2719c2aa98e2SPeter Wemm #endif /* SMTP */ 2720c2aa98e2SPeter Wemm #if NAMED_BIND 2721c2aa98e2SPeter Wemm if (ConfigLevel < 2) 2722c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 272306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 2724c2aa98e2SPeter Wemm 2725c2aa98e2SPeter Wemm if (tTd(62, 1)) 2726c2aa98e2SPeter Wemm checkfds("after delivery"); 2727c2aa98e2SPeter Wemm 2728c2aa98e2SPeter Wemm /* 2729c2aa98e2SPeter Wemm ** Do final status disposal. 2730c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case. 2731c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the 2732c2aa98e2SPeter Wemm ** addressees. 2733c2aa98e2SPeter Wemm */ 2734c2aa98e2SPeter Wemm 2735c2aa98e2SPeter Wemm give_up: 2736c2aa98e2SPeter Wemm #if SMTP 2737c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2738c2aa98e2SPeter Wemm { 2739c2aa98e2SPeter Wemm lmtp_rcode = rcode; 2740c2aa98e2SPeter Wemm tobuf[0] = '\0'; 2741c2aa98e2SPeter Wemm anyok = FALSE; 2742c2aa98e2SPeter Wemm } 2743c2aa98e2SPeter Wemm else 274406f25ae9SGregory Neil Shapiro #endif /* SMTP */ 2745c2aa98e2SPeter Wemm anyok = rcode == EX_OK; 2746c2aa98e2SPeter Wemm 2747c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 2748c2aa98e2SPeter Wemm { 2749c2aa98e2SPeter Wemm /* see if address already marked */ 275006f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 2751c2aa98e2SPeter Wemm continue; 2752c2aa98e2SPeter Wemm 2753c2aa98e2SPeter Wemm #if SMTP 2754c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */ 2755c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2756c2aa98e2SPeter Wemm { 2757c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK) 2758c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e); 2759c2aa98e2SPeter Wemm if (rcode == EX_OK) 2760c2aa98e2SPeter Wemm { 276142e5d165SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 276242e5d165SGregory Neil Shapiro (void) strlcat(tobuf, ",", tobufsize); 276342e5d165SGregory Neil Shapiro (void) strlcat(tobuf, to->q_paddr, tobufsize); 276442e5d165SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 276506f25ae9SGregory Neil Shapiro if (strlen(to->q_paddr) + 276606f25ae9SGregory Neil Shapiro strlen(tobuf) + 2 > sizeof tobuf) 2767c2aa98e2SPeter Wemm { 2768c2aa98e2SPeter Wemm syserr("LMTP tobuf overflow"); 2769c2aa98e2SPeter Wemm } 2770c2aa98e2SPeter Wemm else 2771c2aa98e2SPeter Wemm { 277206f25ae9SGregory Neil Shapiro (void) strlcat(tobuf, ",", 277306f25ae9SGregory Neil Shapiro sizeof tobuf); 277406f25ae9SGregory Neil Shapiro (void) strlcat(tobuf, to->q_paddr, 277506f25ae9SGregory Neil Shapiro sizeof tobuf); 2776c2aa98e2SPeter Wemm } 277742e5d165SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 2778c2aa98e2SPeter Wemm anyok = TRUE; 2779c2aa98e2SPeter Wemm } 2780c2aa98e2SPeter Wemm else 2781c2aa98e2SPeter Wemm { 2782c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 278306f25ae9SGregory Neil Shapiro markfailure(e, to, mci, rcode, TRUE); 278406f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci, 278506f25ae9SGregory Neil Shapiro ctladdr, xstart, e); 2786c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 2787c2aa98e2SPeter Wemm continue; 2788c2aa98e2SPeter Wemm } 2789c2aa98e2SPeter Wemm } 2790c2aa98e2SPeter Wemm else 279106f25ae9SGregory Neil Shapiro #endif /* SMTP */ 2792c2aa98e2SPeter Wemm { 2793c2aa98e2SPeter Wemm /* mark bad addresses */ 2794c2aa98e2SPeter Wemm if (rcode != EX_OK) 2795c2aa98e2SPeter Wemm { 2796c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST) 2797c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL; 279806f25ae9SGregory Neil Shapiro markfailure(e, to, mci, rcode, TRUE); 2799c2aa98e2SPeter Wemm continue; 2800c2aa98e2SPeter Wemm } 2801c2aa98e2SPeter Wemm } 2802c2aa98e2SPeter Wemm 2803c2aa98e2SPeter Wemm /* successful delivery */ 280406f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 2805c2aa98e2SPeter Wemm to->q_statdate = curtime(); 2806c2aa98e2SPeter Wemm e->e_nsent++; 280706f25ae9SGregory Neil Shapiro 280806f25ae9SGregory Neil Shapiro #if QUEUE 280906f25ae9SGregory Neil Shapiro /* 281006f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses 281106f25ae9SGregory Neil Shapiro */ 281206f25ae9SGregory Neil Shapiro 281342e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 281406f25ae9SGregory Neil Shapiro { 281506f25ae9SGregory Neil Shapiro queueup(e, FALSE); 281606f25ae9SGregory Neil Shapiro e->e_nsent = 0; 281706f25ae9SGregory Neil Shapiro } 281806f25ae9SGregory Neil Shapiro #endif /* QUEUE */ 281906f25ae9SGregory Neil Shapiro 2820c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 2821c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 2822c2aa98e2SPeter Wemm { 2823c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 2824c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 2825c2aa98e2SPeter Wemm fprintf(e->e_xfp, "%s... Successfully delivered\n", 2826c2aa98e2SPeter Wemm to->q_paddr); 2827c2aa98e2SPeter Wemm } 2828c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) && 2829c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) && 2830c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags)) 2831c2aa98e2SPeter Wemm { 2832c2aa98e2SPeter Wemm to->q_flags |= QRELAYED; 2833c2aa98e2SPeter Wemm fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 2834c2aa98e2SPeter Wemm to->q_paddr); 2835c2aa98e2SPeter Wemm } 2836c2aa98e2SPeter Wemm } 2837c2aa98e2SPeter Wemm 2838c2aa98e2SPeter Wemm #if SMTP 2839c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2840c2aa98e2SPeter Wemm { 2841c2aa98e2SPeter Wemm /* 2842c2aa98e2SPeter Wemm ** Global information applies to the last recipient only; 2843c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors. 2844c2aa98e2SPeter Wemm */ 2845c2aa98e2SPeter Wemm 2846c2aa98e2SPeter Wemm rcode = EX_OK; 2847c2aa98e2SPeter Wemm e->e_statmsg = NULL; 2848c2aa98e2SPeter Wemm 2849c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */ 2850c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_state == MCIS_ACTIVE) 2851c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2852c2aa98e2SPeter Wemm } 285306f25ae9SGregory Neil Shapiro #endif /* SMTP */ 2854c2aa98e2SPeter Wemm 2855c2aa98e2SPeter Wemm if (tobuf[0] != '\0') 285606f25ae9SGregory Neil Shapiro giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e); 2857c2aa98e2SPeter Wemm if (anyok) 2858c2aa98e2SPeter Wemm markstats(e, tochain, FALSE); 2859c2aa98e2SPeter Wemm mci_store_persistent(mci); 2860c2aa98e2SPeter Wemm 2861c2aa98e2SPeter Wemm #if SMTP 2862c2aa98e2SPeter Wemm /* now close the connection */ 2863c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 2864c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags)) 2865c2aa98e2SPeter Wemm smtpquit(m, mci, e); 286606f25ae9SGregory Neil Shapiro #endif /* SMTP */ 2867c2aa98e2SPeter Wemm 2868c2aa98e2SPeter Wemm /* 2869c2aa98e2SPeter Wemm ** Restore state and return. 2870c2aa98e2SPeter Wemm */ 2871c2aa98e2SPeter Wemm 2872c2aa98e2SPeter Wemm #if XDEBUG 2873c2aa98e2SPeter Wemm { 2874c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 2875c2aa98e2SPeter Wemm 2876c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 2877c2aa98e2SPeter Wemm snprintf(wbuf, sizeof wbuf, "%s... end of deliver(%s)", 2878c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST" 2879c2aa98e2SPeter Wemm : shortenstring(e->e_to, MAXSHORTSTR), 2880c2aa98e2SPeter Wemm m->m_name); 2881c2aa98e2SPeter Wemm checkfd012(wbuf); 2882c2aa98e2SPeter Wemm } 288306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2884c2aa98e2SPeter Wemm 2885c2aa98e2SPeter Wemm errno = 0; 2886c2aa98e2SPeter Wemm define('g', (char *) NULL, e); 288706f25ae9SGregory Neil Shapiro e->e_to = NULL; 288806f25ae9SGregory Neil Shapiro return rcode; 2889c2aa98e2SPeter Wemm } 289006f25ae9SGregory Neil Shapiro 2891c2aa98e2SPeter Wemm /* 2892c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address. 2893c2aa98e2SPeter Wemm ** 2894c2aa98e2SPeter Wemm ** Parameters: 2895c2aa98e2SPeter Wemm ** e -- the envelope we are sending. 2896c2aa98e2SPeter Wemm ** q -- the address to mark. 2897c2aa98e2SPeter Wemm ** mci -- mailer connection information. 2898c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure. 289906f25ae9SGregory Neil Shapiro ** ovr -- override an existing code? 2900c2aa98e2SPeter Wemm ** 2901c2aa98e2SPeter Wemm ** Returns: 2902c2aa98e2SPeter Wemm ** none. 2903c2aa98e2SPeter Wemm ** 2904c2aa98e2SPeter Wemm ** Side Effects: 2905c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the 2906c2aa98e2SPeter Wemm ** failure so that an error will be returned or 2907c2aa98e2SPeter Wemm ** the message will be queued, as appropriate. 2908c2aa98e2SPeter Wemm */ 2909c2aa98e2SPeter Wemm 291006f25ae9SGregory Neil Shapiro static void 291106f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr) 2912c2aa98e2SPeter Wemm register ENVELOPE *e; 2913c2aa98e2SPeter Wemm register ADDRESS *q; 2914c2aa98e2SPeter Wemm register MCI *mci; 2915c2aa98e2SPeter Wemm int rcode; 291606f25ae9SGregory Neil Shapiro bool ovr; 2917c2aa98e2SPeter Wemm { 291806f25ae9SGregory Neil Shapiro char *status = NULL; 291906f25ae9SGregory Neil Shapiro char *rstatus = NULL; 2920c2aa98e2SPeter Wemm 2921c2aa98e2SPeter Wemm switch (rcode) 2922c2aa98e2SPeter Wemm { 2923c2aa98e2SPeter Wemm case EX_OK: 2924c2aa98e2SPeter Wemm break; 2925c2aa98e2SPeter Wemm 2926c2aa98e2SPeter Wemm case EX_TEMPFAIL: 2927c2aa98e2SPeter Wemm case EX_IOERR: 2928c2aa98e2SPeter Wemm case EX_OSERR: 292906f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 2930c2aa98e2SPeter Wemm break; 2931c2aa98e2SPeter Wemm 2932c2aa98e2SPeter Wemm default: 293306f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 2934c2aa98e2SPeter Wemm break; 2935c2aa98e2SPeter Wemm } 2936c2aa98e2SPeter Wemm 2937c2aa98e2SPeter Wemm /* find most specific error code possible */ 2938c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL) 2939c2aa98e2SPeter Wemm { 294006f25ae9SGregory Neil Shapiro status = mci->mci_status; 2941c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 294206f25ae9SGregory Neil Shapiro rstatus = newstr(mci->mci_rstatus); 2943c2aa98e2SPeter Wemm else 294406f25ae9SGregory Neil Shapiro rstatus = NULL; 2945c2aa98e2SPeter Wemm } 2946c2aa98e2SPeter Wemm else if (e->e_status != NULL) 2947c2aa98e2SPeter Wemm { 294806f25ae9SGregory Neil Shapiro status = e->e_status; 294906f25ae9SGregory Neil Shapiro rstatus = NULL; 2950c2aa98e2SPeter Wemm } 2951c2aa98e2SPeter Wemm else 2952c2aa98e2SPeter Wemm { 2953c2aa98e2SPeter Wemm switch (rcode) 2954c2aa98e2SPeter Wemm { 2955c2aa98e2SPeter Wemm case EX_USAGE: 295606f25ae9SGregory Neil Shapiro status = "5.5.4"; 2957c2aa98e2SPeter Wemm break; 2958c2aa98e2SPeter Wemm 2959c2aa98e2SPeter Wemm case EX_DATAERR: 296006f25ae9SGregory Neil Shapiro status = "5.5.2"; 2961c2aa98e2SPeter Wemm break; 2962c2aa98e2SPeter Wemm 2963c2aa98e2SPeter Wemm case EX_NOUSER: 296406f25ae9SGregory Neil Shapiro status = "5.1.1"; 2965c2aa98e2SPeter Wemm break; 2966c2aa98e2SPeter Wemm 2967c2aa98e2SPeter Wemm case EX_NOHOST: 296806f25ae9SGregory Neil Shapiro status = "5.1.2"; 2969c2aa98e2SPeter Wemm break; 2970c2aa98e2SPeter Wemm 2971c2aa98e2SPeter Wemm case EX_NOINPUT: 2972c2aa98e2SPeter Wemm case EX_CANTCREAT: 2973c2aa98e2SPeter Wemm case EX_NOPERM: 297406f25ae9SGregory Neil Shapiro status = "5.3.0"; 2975c2aa98e2SPeter Wemm break; 2976c2aa98e2SPeter Wemm 2977c2aa98e2SPeter Wemm case EX_UNAVAILABLE: 2978c2aa98e2SPeter Wemm case EX_SOFTWARE: 2979c2aa98e2SPeter Wemm case EX_OSFILE: 2980c2aa98e2SPeter Wemm case EX_PROTOCOL: 2981c2aa98e2SPeter Wemm case EX_CONFIG: 298206f25ae9SGregory Neil Shapiro status = "5.5.0"; 2983c2aa98e2SPeter Wemm break; 2984c2aa98e2SPeter Wemm 2985c2aa98e2SPeter Wemm case EX_OSERR: 2986c2aa98e2SPeter Wemm case EX_IOERR: 298706f25ae9SGregory Neil Shapiro status = "4.5.0"; 2988c2aa98e2SPeter Wemm break; 2989c2aa98e2SPeter Wemm 2990c2aa98e2SPeter Wemm case EX_TEMPFAIL: 299106f25ae9SGregory Neil Shapiro status = "4.2.0"; 2992c2aa98e2SPeter Wemm break; 2993c2aa98e2SPeter Wemm } 2994c2aa98e2SPeter Wemm } 2995c2aa98e2SPeter Wemm 299606f25ae9SGregory Neil Shapiro /* new status? */ 299706f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 299806f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status)) 299906f25ae9SGregory Neil Shapiro { 300006f25ae9SGregory Neil Shapiro q->q_status = status; 300106f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus; 300206f25ae9SGregory Neil Shapiro } 3003c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL && 3004c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 300506f25ae9SGregory Neil Shapiro strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 3006c2aa98e2SPeter Wemm { 300706f25ae9SGregory Neil Shapiro char buf[16]; 3008c2aa98e2SPeter Wemm 3009c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "%d", rcode); 3010c2aa98e2SPeter Wemm q->q_rstatus = newstr(buf); 3011c2aa98e2SPeter Wemm } 301206f25ae9SGregory Neil Shapiro 301306f25ae9SGregory Neil Shapiro q->q_statdate = curtime(); 301406f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' && 301506f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 301606f25ae9SGregory Neil Shapiro q->q_statmta = newstr(CurHostName); 3017c2aa98e2SPeter Wemm } 3018c2aa98e2SPeter Wemm /* 3019c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate. 3020c2aa98e2SPeter Wemm ** 3021c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation 3022c2aa98e2SPeter Wemm ** violation), so we report those specially. For other 3023c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg), 3024c2aa98e2SPeter Wemm ** and if it represents an error, we print it. 3025c2aa98e2SPeter Wemm ** 3026c2aa98e2SPeter Wemm ** Parameters: 3027c2aa98e2SPeter Wemm ** pid -- pid of mailer. 3028c2aa98e2SPeter Wemm ** e -- the current envelope. 3029c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer 3030c2aa98e2SPeter Wemm ** (for error messages). 3031c2aa98e2SPeter Wemm ** 3032c2aa98e2SPeter Wemm ** Returns: 3033c2aa98e2SPeter Wemm ** exit code of mailer. 3034c2aa98e2SPeter Wemm ** 3035c2aa98e2SPeter Wemm ** Side Effects: 3036c2aa98e2SPeter Wemm ** none. 3037c2aa98e2SPeter Wemm */ 3038c2aa98e2SPeter Wemm 303906f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout; 304006f25ae9SGregory Neil Shapiro 304106f25ae9SGregory Neil Shapiro static void 304206f25ae9SGregory Neil Shapiro endwaittimeout() 304306f25ae9SGregory Neil Shapiro { 304406f25ae9SGregory Neil Shapiro errno = ETIMEDOUT; 304506f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1); 304606f25ae9SGregory Neil Shapiro } 304706f25ae9SGregory Neil Shapiro 3048c2aa98e2SPeter Wemm int 3049c2aa98e2SPeter Wemm endmailer(mci, e, pv) 3050c2aa98e2SPeter Wemm register MCI *mci; 3051c2aa98e2SPeter Wemm register ENVELOPE *e; 3052c2aa98e2SPeter Wemm char **pv; 3053c2aa98e2SPeter Wemm { 3054c2aa98e2SPeter Wemm int st; 305506f25ae9SGregory Neil Shapiro int save_errno = errno; 305606f25ae9SGregory Neil Shapiro char buf[MAXLINE]; 305706f25ae9SGregory Neil Shapiro EVENT *ev = NULL; 305806f25ae9SGregory Neil Shapiro 3059c2aa98e2SPeter Wemm 3060c2aa98e2SPeter Wemm mci_unlock_host(mci); 3061c2aa98e2SPeter Wemm 306206f25ae9SGregory Neil Shapiro #if SASL 306306f25ae9SGregory Neil Shapiro /* shutdown SASL */ 306406f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 306506f25ae9SGregory Neil Shapiro { 306606f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 306706f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT; 306806f25ae9SGregory Neil Shapiro } 306906f25ae9SGregory Neil Shapiro #endif /* SASL */ 307006f25ae9SGregory Neil Shapiro 307106f25ae9SGregory Neil Shapiro #if STARTTLS 307206f25ae9SGregory Neil Shapiro /* shutdown TLS */ 307306f25ae9SGregory Neil Shapiro (void) endtlsclt(mci); 307406f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 307506f25ae9SGregory Neil Shapiro 307606f25ae9SGregory Neil Shapiro /* close output to mailer */ 3077c2aa98e2SPeter Wemm if (mci->mci_out != NULL) 307806f25ae9SGregory Neil Shapiro (void) fclose(mci->mci_out); 307906f25ae9SGregory Neil Shapiro 308006f25ae9SGregory Neil Shapiro /* copy any remaining input to transcript */ 308106f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 308206f25ae9SGregory Neil Shapiro e->e_xfp != NULL) 308306f25ae9SGregory Neil Shapiro { 308406f25ae9SGregory Neil Shapiro while (sfgets(buf, sizeof buf, mci->mci_in, 308506f25ae9SGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL) 308606f25ae9SGregory Neil Shapiro (void) fputs(buf, e->e_xfp); 308706f25ae9SGregory Neil Shapiro } 308806f25ae9SGregory Neil Shapiro 308906f25ae9SGregory Neil Shapiro /* now close the input */ 309006f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 309106f25ae9SGregory Neil Shapiro (void) fclose(mci->mci_in); 3092c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 3093c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 3094c2aa98e2SPeter Wemm 309506f25ae9SGregory Neil Shapiro errno = save_errno; 309606f25ae9SGregory Neil Shapiro 3097c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */ 3098c2aa98e2SPeter Wemm if (mci->mci_pid == 0) 309906f25ae9SGregory Neil Shapiro return EX_OK; 3100c2aa98e2SPeter Wemm 310106f25ae9SGregory Neil Shapiro /* put a timeout around the wait */ 310206f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0) 310306f25ae9SGregory Neil Shapiro { 310406f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0) 310506f25ae9SGregory Neil Shapiro ev = setevent(mci->mci_mailer->m_wait, 310606f25ae9SGregory Neil Shapiro endwaittimeout, 0); 310706f25ae9SGregory Neil Shapiro else 310806f25ae9SGregory Neil Shapiro { 310942e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)", 311006f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, 311142e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait); 311206f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 311306f25ae9SGregory Neil Shapiro } 311406f25ae9SGregory Neil Shapiro } 3115c2aa98e2SPeter Wemm 311606f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */ 3117c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid); 311806f25ae9SGregory Neil Shapiro save_errno = errno; 311906f25ae9SGregory Neil Shapiro if (ev != NULL) 312006f25ae9SGregory Neil Shapiro clrevent(ev); 312106f25ae9SGregory Neil Shapiro errno = save_errno; 312206f25ae9SGregory Neil Shapiro 3123c2aa98e2SPeter Wemm if (st == -1) 3124c2aa98e2SPeter Wemm { 3125c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name); 312606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 3127c2aa98e2SPeter Wemm } 3128c2aa98e2SPeter Wemm 3129c2aa98e2SPeter Wemm if (WIFEXITED(st)) 3130c2aa98e2SPeter Wemm { 3131c2aa98e2SPeter Wemm /* normal death -- return status */ 3132c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 3133c2aa98e2SPeter Wemm } 3134c2aa98e2SPeter Wemm 3135c2aa98e2SPeter Wemm /* it died a horrid death */ 313606f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s", 313706f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st), 313806f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" : 313906f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : "")); 3140c2aa98e2SPeter Wemm 3141c2aa98e2SPeter Wemm /* log the arguments */ 3142c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL) 3143c2aa98e2SPeter Wemm { 3144c2aa98e2SPeter Wemm register char **av; 3145c2aa98e2SPeter Wemm 3146c2aa98e2SPeter Wemm fprintf(e->e_xfp, "Arguments:"); 3147c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 3148c2aa98e2SPeter Wemm fprintf(e->e_xfp, " %s", *av); 3149c2aa98e2SPeter Wemm fprintf(e->e_xfp, "\n"); 3150c2aa98e2SPeter Wemm } 3151c2aa98e2SPeter Wemm 3152c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL; 315306f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 3154c2aa98e2SPeter Wemm } 3155c2aa98e2SPeter Wemm /* 3156c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer 3157c2aa98e2SPeter Wemm ** 3158c2aa98e2SPeter Wemm ** Parameters: 315906f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte 3160c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of 3161c2aa98e2SPeter Wemm ** already). 316206f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any. 3163c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer. 3164c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 3165c2aa98e2SPeter Wemm ** response is given before the connection is made. 3166c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient 3167c2aa98e2SPeter Wemm ** address(es). 3168c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing 3169c2aa98e2SPeter Wemm ** transaction delays. 3170c2aa98e2SPeter Wemm ** e -- the current envelope. 3171c2aa98e2SPeter Wemm ** 3172c2aa98e2SPeter Wemm ** Returns: 3173c2aa98e2SPeter Wemm ** none. 3174c2aa98e2SPeter Wemm ** 3175c2aa98e2SPeter Wemm ** Side Effects: 3176c2aa98e2SPeter Wemm ** Errors may be incremented. 3177c2aa98e2SPeter Wemm ** ExitStat may be set. 3178c2aa98e2SPeter Wemm */ 3179c2aa98e2SPeter Wemm 3180c2aa98e2SPeter Wemm void 318106f25ae9SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e) 318206f25ae9SGregory Neil Shapiro int status; 318306f25ae9SGregory Neil Shapiro char *dsn; 3184c2aa98e2SPeter Wemm register MAILER *m; 3185c2aa98e2SPeter Wemm register MCI *mci; 3186c2aa98e2SPeter Wemm ADDRESS *ctladdr; 3187c2aa98e2SPeter Wemm time_t xstart; 3188c2aa98e2SPeter Wemm ENVELOPE *e; 3189c2aa98e2SPeter Wemm { 3190c2aa98e2SPeter Wemm register const char *statmsg; 3191c2aa98e2SPeter Wemm extern char *SysExMsg[]; 3192c2aa98e2SPeter Wemm register int i; 319306f25ae9SGregory Neil Shapiro int errnum = errno; 319406f25ae9SGregory Neil Shapiro int off = 4; 3195c2aa98e2SPeter Wemm extern int N_SysEx; 319606f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN]; 3197c2aa98e2SPeter Wemm char buf[MAXLINE]; 3198c2aa98e2SPeter Wemm 3199c2aa98e2SPeter Wemm if (e == NULL) 3200c2aa98e2SPeter Wemm syserr("giveresponse: null envelope"); 3201c2aa98e2SPeter Wemm 3202c2aa98e2SPeter Wemm /* 3203c2aa98e2SPeter Wemm ** Compute status message from code. 3204c2aa98e2SPeter Wemm */ 3205c2aa98e2SPeter Wemm 320606f25ae9SGregory Neil Shapiro i = status - EX__BASE; 320706f25ae9SGregory Neil Shapiro if (status == 0) 3208c2aa98e2SPeter Wemm { 320906f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent"; 3210c2aa98e2SPeter Wemm if (e->e_statmsg != NULL) 3211c2aa98e2SPeter Wemm { 3212c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "%s (%s)", 321306f25ae9SGregory Neil Shapiro statmsg, 321406f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 3215c2aa98e2SPeter Wemm statmsg = buf; 3216c2aa98e2SPeter Wemm } 3217c2aa98e2SPeter Wemm } 3218c2aa98e2SPeter Wemm else if (i < 0 || i >= N_SysEx) 3219c2aa98e2SPeter Wemm { 322006f25ae9SGregory Neil Shapiro (void) snprintf(buf, sizeof buf, 322106f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d", 322206f25ae9SGregory Neil Shapiro status); 322306f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE; 3224c2aa98e2SPeter Wemm statmsg = buf; 3225c2aa98e2SPeter Wemm } 322606f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL) 3227c2aa98e2SPeter Wemm { 3228c2aa98e2SPeter Wemm char *bp = buf; 3229c2aa98e2SPeter Wemm 3230c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s", SysExMsg[i] + 1); 3231c2aa98e2SPeter Wemm bp += strlen(bp); 3232c2aa98e2SPeter Wemm #if NAMED_BIND 3233c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN) 3234c2aa98e2SPeter Wemm statmsg = errstring(h_errno+E_DNSBASE); 3235c2aa98e2SPeter Wemm else 323606f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3237c2aa98e2SPeter Wemm { 323806f25ae9SGregory Neil Shapiro if (errnum != 0) 323906f25ae9SGregory Neil Shapiro statmsg = errstring(errnum); 3240c2aa98e2SPeter Wemm else 3241c2aa98e2SPeter Wemm { 3242c2aa98e2SPeter Wemm #if SMTP 3243c2aa98e2SPeter Wemm statmsg = SmtpError; 3244c2aa98e2SPeter Wemm #else /* SMTP */ 3245c2aa98e2SPeter Wemm statmsg = NULL; 3246c2aa98e2SPeter Wemm #endif /* SMTP */ 3247c2aa98e2SPeter Wemm } 3248c2aa98e2SPeter Wemm } 3249c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0') 325006f25ae9SGregory Neil Shapiro { 325106f25ae9SGregory Neil Shapiro switch (errnum) 325206f25ae9SGregory Neil Shapiro { 325306f25ae9SGregory Neil Shapiro #ifdef ENETDOWN 325406f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */ 325506f25ae9SGregory Neil Shapiro #endif /* ENETDOWN */ 325606f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH 325706f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */ 325806f25ae9SGregory Neil Shapiro #endif /* ENETUNREACH */ 325906f25ae9SGregory Neil Shapiro #ifdef ENETRESET 326006f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */ 326106f25ae9SGregory Neil Shapiro #endif /* ENETRESET */ 326206f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED 326306f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */ 326406f25ae9SGregory Neil Shapiro #endif /* ECONNABORTED */ 326506f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN 326606f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */ 326706f25ae9SGregory Neil Shapiro #endif /* EHOSTDOWN */ 326806f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH 326906f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */ 327006f25ae9SGregory Neil Shapiro #endif /* EHOSTUNREACH */ 327106f25ae9SGregory Neil Shapiro if (mci->mci_host != NULL) 327206f25ae9SGregory Neil Shapiro { 327306f25ae9SGregory Neil Shapiro snprintf(bp, SPACELEFT(buf, bp), 327406f25ae9SGregory Neil Shapiro ": %s", mci->mci_host); 327506f25ae9SGregory Neil Shapiro bp += strlen(bp); 327606f25ae9SGregory Neil Shapiro } 327706f25ae9SGregory Neil Shapiro break; 327806f25ae9SGregory Neil Shapiro } 3279c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ": %s", statmsg); 328006f25ae9SGregory Neil Shapiro } 3281c2aa98e2SPeter Wemm statmsg = buf; 3282c2aa98e2SPeter Wemm } 3283c2aa98e2SPeter Wemm #if NAMED_BIND 328406f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0) 3285c2aa98e2SPeter Wemm { 3286c2aa98e2SPeter Wemm statmsg = errstring(h_errno + E_DNSBASE); 3287c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "%s (%s)", 3288c2aa98e2SPeter Wemm SysExMsg[i] + 1, statmsg); 3289c2aa98e2SPeter Wemm statmsg = buf; 3290c2aa98e2SPeter Wemm } 329106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3292c2aa98e2SPeter Wemm else 3293c2aa98e2SPeter Wemm { 3294c2aa98e2SPeter Wemm statmsg = SysExMsg[i]; 329506f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0) 3296c2aa98e2SPeter Wemm { 3297c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "%s: %s", 329806f25ae9SGregory Neil Shapiro statmsg, errstring(errnum)); 3299c2aa98e2SPeter Wemm statmsg = buf; 3300c2aa98e2SPeter Wemm } 3301c2aa98e2SPeter Wemm } 3302c2aa98e2SPeter Wemm 3303c2aa98e2SPeter Wemm /* 3304c2aa98e2SPeter Wemm ** Print the message as appropriate 3305c2aa98e2SPeter Wemm */ 3306c2aa98e2SPeter Wemm 330706f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL) 3308c2aa98e2SPeter Wemm { 3309c2aa98e2SPeter Wemm extern char MsgBuf[]; 3310c2aa98e2SPeter Wemm 331106f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0) 331206f25ae9SGregory Neil Shapiro { 331306f25ae9SGregory Neil Shapiro if (dsn == NULL) 331406f25ae9SGregory Neil Shapiro { 331506f25ae9SGregory Neil Shapiro snprintf(dsnbuf, sizeof dsnbuf, 331606f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 331706f25ae9SGregory Neil Shapiro dsn = dsnbuf; 331806f25ae9SGregory Neil Shapiro } 331906f25ae9SGregory Neil Shapiro off += 5; 332006f25ae9SGregory Neil Shapiro } 332106f25ae9SGregory Neil Shapiro else 332206f25ae9SGregory Neil Shapiro { 332306f25ae9SGregory Neil Shapiro off = 4; 332406f25ae9SGregory Neil Shapiro } 332506f25ae9SGregory Neil Shapiro message("%s", statmsg + off); 332606f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL) 3327c2aa98e2SPeter Wemm fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 3328c2aa98e2SPeter Wemm } 3329c2aa98e2SPeter Wemm else 3330c2aa98e2SPeter Wemm { 333106f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4]; 3332c2aa98e2SPeter Wemm 3333c2aa98e2SPeter Wemm Errors++; 333406f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 333506f25ae9SGregory Neil Shapiro off < sizeof mbuf - 4) 333606f25ae9SGregory Neil Shapiro { 333706f25ae9SGregory Neil Shapiro if (dsn == NULL) 333806f25ae9SGregory Neil Shapiro { 333906f25ae9SGregory Neil Shapiro snprintf(dsnbuf, sizeof dsnbuf, 334006f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 334106f25ae9SGregory Neil Shapiro dsn = dsnbuf; 334206f25ae9SGregory Neil Shapiro } 334306f25ae9SGregory Neil Shapiro off += 5; 334406f25ae9SGregory Neil Shapiro (void) strlcpy(mbuf, statmsg, off); 334506f25ae9SGregory Neil Shapiro (void) strlcat(mbuf, " %s", sizeof mbuf); 334606f25ae9SGregory Neil Shapiro } 334706f25ae9SGregory Neil Shapiro else 334806f25ae9SGregory Neil Shapiro { 334906f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0'; 335006f25ae9SGregory Neil Shapiro (void) snprintf(mbuf, sizeof mbuf, "%.3s %%s", statmsg); 335106f25ae9SGregory Neil Shapiro off = 4; 335206f25ae9SGregory Neil Shapiro } 335306f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]); 3354c2aa98e2SPeter Wemm } 3355c2aa98e2SPeter Wemm 3356c2aa98e2SPeter Wemm /* 3357c2aa98e2SPeter Wemm ** Final cleanup. 3358c2aa98e2SPeter Wemm ** Log a record of the transaction. Compute the new 3359c2aa98e2SPeter Wemm ** ExitStat -- if we already had an error, stick with 3360c2aa98e2SPeter Wemm ** that. 3361c2aa98e2SPeter Wemm */ 3362c2aa98e2SPeter Wemm 3363c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 336406f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 336506f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 3366c2aa98e2SPeter Wemm 3367c2aa98e2SPeter Wemm if (tTd(11, 2)) 336806f25ae9SGregory Neil Shapiro dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s\n", 336906f25ae9SGregory Neil Shapiro status, 337006f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn, 337106f25ae9SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message); 3372c2aa98e2SPeter Wemm 337306f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL) 337406f25ae9SGregory Neil Shapiro setstat(status); 337506f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 3376c2aa98e2SPeter Wemm { 3377c2aa98e2SPeter Wemm if (e->e_message != NULL) 3378c2aa98e2SPeter Wemm free(e->e_message); 337906f25ae9SGregory Neil Shapiro e->e_message = newstr(statmsg + off); 3380c2aa98e2SPeter Wemm } 3381c2aa98e2SPeter Wemm errno = 0; 3382c2aa98e2SPeter Wemm #if NAMED_BIND 3383602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 338406f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3385c2aa98e2SPeter Wemm } 3386c2aa98e2SPeter Wemm /* 3387c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log 3388c2aa98e2SPeter Wemm ** 3389c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because 3390c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core 3391c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical. 3392c2aa98e2SPeter Wemm ** 3393c2aa98e2SPeter Wemm ** Parameters: 3394c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue. 3395c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 339606f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active. 339706f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status. 339806f25ae9SGregory Neil Shapiro ** status -- the message to print for the status. 3399c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list. 3400c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for 3401c2aa98e2SPeter Wemm ** computing transaction delay. 3402c2aa98e2SPeter Wemm ** e -- the current envelope. 3403c2aa98e2SPeter Wemm ** 3404c2aa98e2SPeter Wemm ** Returns: 3405c2aa98e2SPeter Wemm ** none 3406c2aa98e2SPeter Wemm ** 3407c2aa98e2SPeter Wemm ** Side Effects: 3408c2aa98e2SPeter Wemm ** none 3409c2aa98e2SPeter Wemm */ 3410c2aa98e2SPeter Wemm 3411c2aa98e2SPeter Wemm void 341206f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 3413c2aa98e2SPeter Wemm MAILER *m; 3414c2aa98e2SPeter Wemm register MCI *mci; 341506f25ae9SGregory Neil Shapiro char *dsn; 341606f25ae9SGregory Neil Shapiro const char *status; 3417c2aa98e2SPeter Wemm ADDRESS *ctladdr; 3418c2aa98e2SPeter Wemm time_t xstart; 3419c2aa98e2SPeter Wemm register ENVELOPE *e; 3420c2aa98e2SPeter Wemm { 3421c2aa98e2SPeter Wemm register char *bp; 3422c2aa98e2SPeter Wemm register char *p; 3423c2aa98e2SPeter Wemm int l; 3424193538b7SGregory Neil Shapiro time_t now; 3425c2aa98e2SPeter Wemm char buf[1024]; 3426c2aa98e2SPeter Wemm 3427c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 3428c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */ 3429c2aa98e2SPeter Wemm bp = buf; 3430c2aa98e2SPeter Wemm if (ctladdr != NULL) 3431c2aa98e2SPeter Wemm { 3432c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", ctladdr=%s", 3433c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 3434c2aa98e2SPeter Wemm bp += strlen(bp); 3435c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 3436c2aa98e2SPeter Wemm { 3437c2aa98e2SPeter Wemm (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 343806f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid, 343906f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid); 3440c2aa98e2SPeter Wemm bp += strlen(bp); 3441c2aa98e2SPeter Wemm } 3442c2aa98e2SPeter Wemm } 3443c2aa98e2SPeter Wemm 3444c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */ 3445193538b7SGregory Neil Shapiro now = curtime(); 3446c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", delay=%s", 3447193538b7SGregory Neil Shapiro pintvl(now - e->e_ctime, TRUE)); 3448c2aa98e2SPeter Wemm bp += strlen(bp); 3449c2aa98e2SPeter Wemm 3450c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 3451c2aa98e2SPeter Wemm { 3452c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s", 3453193538b7SGregory Neil Shapiro pintvl(now - xstart, TRUE)); 3454c2aa98e2SPeter Wemm bp += strlen(bp); 3455c2aa98e2SPeter Wemm } 3456c2aa98e2SPeter Wemm 3457c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 3458c2aa98e2SPeter Wemm if (m != NULL) 3459c2aa98e2SPeter Wemm { 3460c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name); 3461c2aa98e2SPeter Wemm bp += strlen(bp); 3462c2aa98e2SPeter Wemm } 3463c2aa98e2SPeter Wemm 346406f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */ 346506f25ae9SGregory Neil Shapiro snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", e->e_msgpriority); 346606f25ae9SGregory Neil Shapiro bp += strlen(bp); 346706f25ae9SGregory Neil Shapiro 3468c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */ 3469c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 3470c2aa98e2SPeter Wemm { 3471c2aa98e2SPeter Wemm # if DAEMON 3472c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 347306f25ae9SGregory Neil Shapiro # endif /* DAEMON */ 3474c2aa98e2SPeter Wemm 3475c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", relay=%s", 3476c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40)); 3477c2aa98e2SPeter Wemm bp += strlen(bp); 3478c2aa98e2SPeter Wemm 3479c2aa98e2SPeter Wemm # if DAEMON 3480c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 3481c2aa98e2SPeter Wemm { 3482c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), " [%s]", 3483c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 3484c2aa98e2SPeter Wemm } 348506f25ae9SGregory Neil Shapiro # endif /* DAEMON */ 3486c2aa98e2SPeter Wemm } 348706f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 3488c2aa98e2SPeter Wemm { 3489c2aa98e2SPeter Wemm p = macvalue('h', e); 3490c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 3491c2aa98e2SPeter Wemm { 3492c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", relay=%s", 3493c2aa98e2SPeter Wemm shortenstring(p, 40)); 3494c2aa98e2SPeter Wemm } 3495c2aa98e2SPeter Wemm } 3496c2aa98e2SPeter Wemm bp += strlen(bp); 3497c2aa98e2SPeter Wemm 349806f25ae9SGregory Neil Shapiro /* dsn */ 349906f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0') 350006f25ae9SGregory Neil Shapiro { 350106f25ae9SGregory Neil Shapiro snprintf(bp, SPACELEFT(buf, bp), ", dsn=%s", 350206f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN)); 350306f25ae9SGregory Neil Shapiro bp += strlen(bp); 350406f25ae9SGregory Neil Shapiro } 350506f25ae9SGregory Neil Shapiro 3506c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 3507c2aa98e2SPeter Wemm # if (STATLEN) < 63 3508c2aa98e2SPeter Wemm # undef STATLEN 3509c2aa98e2SPeter Wemm # define STATLEN 63 351006f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */ 3511c2aa98e2SPeter Wemm # if (STATLEN) > 203 3512c2aa98e2SPeter Wemm # undef STATLEN 3513c2aa98e2SPeter Wemm # define STATLEN 203 351406f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */ 3515c2aa98e2SPeter Wemm 3516c2aa98e2SPeter Wemm /* stat: max 210 bytes */ 3517c2aa98e2SPeter Wemm if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 3518c2aa98e2SPeter Wemm { 3519c2aa98e2SPeter Wemm /* desperation move -- truncate data */ 3520c2aa98e2SPeter Wemm bp = buf + sizeof buf - ((STATLEN) + 17); 352106f25ae9SGregory Neil Shapiro (void) strlcpy(bp, "...", SPACELEFT(buf, bp)); 3522c2aa98e2SPeter Wemm bp += 3; 3523c2aa98e2SPeter Wemm } 3524c2aa98e2SPeter Wemm 352506f25ae9SGregory Neil Shapiro (void) strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 3526c2aa98e2SPeter Wemm bp += strlen(bp); 3527c2aa98e2SPeter Wemm 352806f25ae9SGregory Neil Shapiro (void) strlcpy(bp, shortenstring(status, STATLEN), SPACELEFT(buf, bp)); 3529c2aa98e2SPeter Wemm 3530c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */ 3531c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf); 353206f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 3533c2aa98e2SPeter Wemm while (strlen(p) >= (SIZE_T) l) 3534c2aa98e2SPeter Wemm { 353506f25ae9SGregory Neil Shapiro register char *q; 3536c2aa98e2SPeter Wemm 353706f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 353806f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 353906f25ae9SGregory Neil Shapiro { 354006f25ae9SGregory Neil Shapiro if (*q == ',') 354106f25ae9SGregory Neil Shapiro break; 354206f25ae9SGregory Neil Shapiro } 354306f25ae9SGregory Neil Shapiro if (p == q) 354406f25ae9SGregory Neil Shapiro break; 354506f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 354606f25ae9SGregory Neil Shapiro q = strchr(p + l, ','); 3547c2aa98e2SPeter Wemm if (q == NULL) 3548c2aa98e2SPeter Wemm break; 354906f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 355006f25ae9SGregory Neil Shapiro 3551c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 3552c2aa98e2SPeter Wemm "to=%.*s [more]%s", 355342e5d165SGregory Neil Shapiro (int) (++q - p), p, buf); 3554c2aa98e2SPeter Wemm p = q; 3555c2aa98e2SPeter Wemm } 355606f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 355706f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 355806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 3559c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf); 356006f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 3561c2aa98e2SPeter Wemm 356206f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 3563c2aa98e2SPeter Wemm 3564c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85; 356506f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 3566c2aa98e2SPeter Wemm while (strlen(p) >= (SIZE_T) l) 3567c2aa98e2SPeter Wemm { 356806f25ae9SGregory Neil Shapiro register char *q; 3569c2aa98e2SPeter Wemm 357006f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 357106f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 357206f25ae9SGregory Neil Shapiro { 357306f25ae9SGregory Neil Shapiro if (*q == ',') 357406f25ae9SGregory Neil Shapiro break; 357506f25ae9SGregory Neil Shapiro } 357606f25ae9SGregory Neil Shapiro if (p == q) 357706f25ae9SGregory Neil Shapiro break; 357806f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 357906f25ae9SGregory Neil Shapiro q = strchr(p + l, ','); 3580c2aa98e2SPeter Wemm if (q == NULL) 3581c2aa98e2SPeter Wemm break; 358206f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 358306f25ae9SGregory Neil Shapiro 3584c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 3585c2aa98e2SPeter Wemm "to=%.*s [more]", 358642e5d165SGregory Neil Shapiro (int) (++q - p), p); 3587c2aa98e2SPeter Wemm p = q; 3588c2aa98e2SPeter Wemm } 358906f25ae9SGregory Neil Shapiro #if _FFR_DYNAMIC_TOBUF 359006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 359106f25ae9SGregory Neil Shapiro #else /* _FFR_DYNAMIC_TOBUF */ 3592c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "to=%s", p); 359306f25ae9SGregory Neil Shapiro #endif /* _FFR_DYNAMIC_TOBUF */ 3594c2aa98e2SPeter Wemm 3595c2aa98e2SPeter Wemm if (ctladdr != NULL) 3596c2aa98e2SPeter Wemm { 3597c2aa98e2SPeter Wemm bp = buf; 3598c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "ctladdr=%s", 3599c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 3600c2aa98e2SPeter Wemm bp += strlen(bp); 3601c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 3602c2aa98e2SPeter Wemm { 3603c2aa98e2SPeter Wemm (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 3604c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid); 3605c2aa98e2SPeter Wemm bp += strlen(bp); 3606c2aa98e2SPeter Wemm } 3607c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf); 3608c2aa98e2SPeter Wemm } 3609c2aa98e2SPeter Wemm bp = buf; 3610c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "delay=%s", 3611193538b7SGregory Neil Shapiro pintvl(now - e->e_ctime, TRUE)); 3612c2aa98e2SPeter Wemm bp += strlen(bp); 3613c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 3614c2aa98e2SPeter Wemm { 3615c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s", 3616193538b7SGregory Neil Shapiro pintvl(now - xstart, TRUE)); 3617c2aa98e2SPeter Wemm bp += strlen(bp); 3618c2aa98e2SPeter Wemm } 3619c2aa98e2SPeter Wemm 3620c2aa98e2SPeter Wemm if (m != NULL) 3621c2aa98e2SPeter Wemm { 3622c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name); 3623c2aa98e2SPeter Wemm bp += strlen(bp); 3624c2aa98e2SPeter Wemm } 3625c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 3626c2aa98e2SPeter Wemm 3627c2aa98e2SPeter Wemm buf[0] = '\0'; 3628c2aa98e2SPeter Wemm bp = buf; 3629c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 3630c2aa98e2SPeter Wemm { 3631c2aa98e2SPeter Wemm # if DAEMON 3632c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 363306f25ae9SGregory Neil Shapiro # endif /* DAEMON */ 3634c2aa98e2SPeter Wemm 3635c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host); 3636c2aa98e2SPeter Wemm bp += strlen(bp); 3637c2aa98e2SPeter Wemm 3638c2aa98e2SPeter Wemm # if DAEMON 3639c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 3640c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), " [%.100s]", 3641c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 364206f25ae9SGregory Neil Shapiro # endif /* DAEMON */ 3643c2aa98e2SPeter Wemm } 364406f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 3645c2aa98e2SPeter Wemm { 3646c2aa98e2SPeter Wemm p = macvalue('h', e); 3647c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 3648c2aa98e2SPeter Wemm snprintf(buf, sizeof buf, "relay=%.100s", p); 3649c2aa98e2SPeter Wemm } 3650c2aa98e2SPeter Wemm if (buf[0] != '\0') 3651c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 3652c2aa98e2SPeter Wemm 365306f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 365406f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 3655c2aa98e2SPeter Wemm } 3656c2aa98e2SPeter Wemm /* 3657c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 3658c2aa98e2SPeter Wemm ** 3659c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l 3660c2aa98e2SPeter Wemm ** 3661c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein: 3662c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why 3663c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with 3664c2aa98e2SPeter Wemm ** this kind of antique garbage???? 3665c2aa98e2SPeter Wemm ** 3666c2aa98e2SPeter Wemm ** Parameters: 3667c2aa98e2SPeter Wemm ** mci -- the connection information. 3668c2aa98e2SPeter Wemm ** e -- the envelope. 3669c2aa98e2SPeter Wemm ** 3670c2aa98e2SPeter Wemm ** Returns: 3671c2aa98e2SPeter Wemm ** none 3672c2aa98e2SPeter Wemm ** 3673c2aa98e2SPeter Wemm ** Side Effects: 3674c2aa98e2SPeter Wemm ** outputs some text to fp. 3675c2aa98e2SPeter Wemm */ 3676c2aa98e2SPeter Wemm 3677c2aa98e2SPeter Wemm void 3678c2aa98e2SPeter Wemm putfromline(mci, e) 3679c2aa98e2SPeter Wemm register MCI *mci; 3680c2aa98e2SPeter Wemm ENVELOPE *e; 3681c2aa98e2SPeter Wemm { 3682c2aa98e2SPeter Wemm char *template = UnixFromLine; 3683c2aa98e2SPeter Wemm char buf[MAXLINE]; 3684c2aa98e2SPeter Wemm char xbuf[MAXLINE]; 3685c2aa98e2SPeter Wemm 3686c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 3687c2aa98e2SPeter Wemm return; 3688c2aa98e2SPeter Wemm 3689c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 3690c2aa98e2SPeter Wemm 3691c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 3692c2aa98e2SPeter Wemm { 3693c2aa98e2SPeter Wemm char *bang; 3694c2aa98e2SPeter Wemm 3695c2aa98e2SPeter Wemm expand("\201g", buf, sizeof buf, e); 3696c2aa98e2SPeter Wemm bang = strchr(buf, '!'); 3697c2aa98e2SPeter Wemm if (bang == NULL) 3698c2aa98e2SPeter Wemm { 3699c2aa98e2SPeter Wemm char *at; 3700c2aa98e2SPeter Wemm char hname[MAXNAME]; 3701c2aa98e2SPeter Wemm 3702c2aa98e2SPeter Wemm /* 3703c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so 3704c2aa98e2SPeter Wemm */ 3705c2aa98e2SPeter Wemm 3706c2aa98e2SPeter Wemm at = strrchr(buf, '@'); 3707c2aa98e2SPeter Wemm if (at == NULL) 3708c2aa98e2SPeter Wemm { 3709c2aa98e2SPeter Wemm expand("\201k", hname, sizeof hname, e); 3710c2aa98e2SPeter Wemm at = hname; 3711c2aa98e2SPeter Wemm } 3712c2aa98e2SPeter Wemm else 3713c2aa98e2SPeter Wemm *at++ = '\0'; 3714c2aa98e2SPeter Wemm (void) snprintf(xbuf, sizeof xbuf, 3715c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 3716c2aa98e2SPeter Wemm buf, at); 3717c2aa98e2SPeter Wemm } 3718c2aa98e2SPeter Wemm else 3719c2aa98e2SPeter Wemm { 3720c2aa98e2SPeter Wemm *bang++ = '\0'; 3721c2aa98e2SPeter Wemm (void) snprintf(xbuf, sizeof xbuf, 3722c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 3723c2aa98e2SPeter Wemm bang, buf); 3724c2aa98e2SPeter Wemm template = xbuf; 3725c2aa98e2SPeter Wemm } 3726c2aa98e2SPeter Wemm } 3727c2aa98e2SPeter Wemm expand(template, buf, sizeof buf, e); 3728c2aa98e2SPeter Wemm putxline(buf, strlen(buf), mci, PXLF_HEADER); 3729c2aa98e2SPeter Wemm } 3730c2aa98e2SPeter Wemm /* 3731c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message. 3732c2aa98e2SPeter Wemm ** 3733c2aa98e2SPeter Wemm ** Parameters: 3734c2aa98e2SPeter Wemm ** mci -- the connection information. 3735c2aa98e2SPeter Wemm ** e -- the envelope to put out. 3736c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must 3737c2aa98e2SPeter Wemm ** not be permitted in the resulting message. 3738c2aa98e2SPeter Wemm ** 3739c2aa98e2SPeter Wemm ** Returns: 3740c2aa98e2SPeter Wemm ** none. 3741c2aa98e2SPeter Wemm ** 3742c2aa98e2SPeter Wemm ** Side Effects: 3743c2aa98e2SPeter Wemm ** The message is written onto fp. 3744c2aa98e2SPeter Wemm */ 3745c2aa98e2SPeter Wemm 3746c2aa98e2SPeter Wemm /* values for output state variable */ 3747c2aa98e2SPeter Wemm #define OS_HEAD 0 /* at beginning of line */ 3748c2aa98e2SPeter Wemm #define OS_CR 1 /* read a carriage return */ 3749c2aa98e2SPeter Wemm #define OS_INLINE 2 /* putting rest of line */ 3750c2aa98e2SPeter Wemm 3751c2aa98e2SPeter Wemm void 3752c2aa98e2SPeter Wemm putbody(mci, e, separator) 3753c2aa98e2SPeter Wemm register MCI *mci; 3754c2aa98e2SPeter Wemm register ENVELOPE *e; 3755c2aa98e2SPeter Wemm char *separator; 3756c2aa98e2SPeter Wemm { 375706f25ae9SGregory Neil Shapiro bool dead = FALSE; 3758c2aa98e2SPeter Wemm char buf[MAXLINE]; 3759065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1]; 3760c2aa98e2SPeter Wemm 3761c2aa98e2SPeter Wemm /* 3762c2aa98e2SPeter Wemm ** Output the body of the message 3763c2aa98e2SPeter Wemm */ 3764c2aa98e2SPeter Wemm 3765c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 3766c2aa98e2SPeter Wemm { 3767c2aa98e2SPeter Wemm char *df = queuename(e, 'd'); 3768c2aa98e2SPeter Wemm 3769c2aa98e2SPeter Wemm e->e_dfp = fopen(df, "r"); 3770c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 377106f25ae9SGregory Neil Shapiro { 377206f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s"; 377306f25ae9SGregory Neil Shapiro 377406f25ae9SGregory Neil Shapiro if (errno == ENOENT) 377506f25ae9SGregory Neil Shapiro msg++; 377606f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr); 377706f25ae9SGregory Neil Shapiro } 3778c2aa98e2SPeter Wemm } 3779c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 3780c2aa98e2SPeter Wemm { 3781c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 3782c2aa98e2SPeter Wemm { 3783c2aa98e2SPeter Wemm putline("", mci); 3784c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 3785c2aa98e2SPeter Wemm } 3786c2aa98e2SPeter Wemm putline("<<< No Message Collected >>>", mci); 3787c2aa98e2SPeter Wemm goto endofmessage; 3788c2aa98e2SPeter Wemm } 378906f25ae9SGregory Neil Shapiro 3790c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0) 3791c2aa98e2SPeter Wemm { 3792c2aa98e2SPeter Wemm struct stat stbuf; 3793c2aa98e2SPeter Wemm 3794c2aa98e2SPeter Wemm if (fstat(fileno(e->e_dfp), &stbuf) < 0) 3795c2aa98e2SPeter Wemm e->e_dfino = -1; 3796c2aa98e2SPeter Wemm else 3797c2aa98e2SPeter Wemm { 3798c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 3799c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 3800c2aa98e2SPeter Wemm } 3801c2aa98e2SPeter Wemm } 380206f25ae9SGregory Neil Shapiro 380306f25ae9SGregory Neil Shapiro /* paranoia: the df file should always be in a rewound state */ 380406f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 3805c2aa98e2SPeter Wemm 3806c2aa98e2SPeter Wemm #if MIME8TO7 3807c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 3808c2aa98e2SPeter Wemm { 3809c2aa98e2SPeter Wemm /* 3810c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion. 3811c2aa98e2SPeter Wemm */ 3812c2aa98e2SPeter Wemm 3813c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */ 3814c2aa98e2SPeter Wemm if (hvalue("MIME-Version", e->e_header) == NULL) 3815c2aa98e2SPeter Wemm putline("MIME-Version: 1.0", mci); 3816c2aa98e2SPeter Wemm 3817c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 3818c2aa98e2SPeter Wemm { 3819c2aa98e2SPeter Wemm snprintf(buf, sizeof buf, 3820c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 3821c2aa98e2SPeter Wemm defcharset(e)); 3822c2aa98e2SPeter Wemm putline(buf, mci); 3823c2aa98e2SPeter Wemm } 3824c2aa98e2SPeter Wemm 3825c2aa98e2SPeter Wemm /* now do the hard work */ 3826c2aa98e2SPeter Wemm boundaries[0] = NULL; 3827c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 382806f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 3829c2aa98e2SPeter Wemm } 3830c2aa98e2SPeter Wemm # if MIME7TO8 3831c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 3832c2aa98e2SPeter Wemm { 383306f25ae9SGregory Neil Shapiro (void) mime7to8(mci, e->e_header, e); 3834c2aa98e2SPeter Wemm } 383506f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */ 3836065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 3837065a643dSPeter Wemm { 383806f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs; 383906f25ae9SGregory Neil Shapiro 3840065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */ 3841065a643dSPeter Wemm boundaries[0] = NULL; 3842065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER; 384306f25ae9SGregory Neil Shapiro 384406f25ae9SGregory Neil Shapiro /* 384506f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message 384606f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose 384706f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call 384806f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security 384906f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors. 385006f25ae9SGregory Neil Shapiro */ 385106f25ae9SGregory Neil Shapiro 385206f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags)) 385306f25ae9SGregory Neil Shapiro SuprErrs = TRUE; 385406f25ae9SGregory Neil Shapiro 385506f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, 385606f25ae9SGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7); 385706f25ae9SGregory Neil Shapiro 385806f25ae9SGregory Neil Shapiro /* restore SuprErrs */ 385906f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs; 3860065a643dSPeter Wemm } 3861c2aa98e2SPeter Wemm else 386206f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */ 3863c2aa98e2SPeter Wemm { 3864c2aa98e2SPeter Wemm int ostate; 3865c2aa98e2SPeter Wemm register char *bp; 3866c2aa98e2SPeter Wemm register char *pbp; 3867c2aa98e2SPeter Wemm register int c; 3868c2aa98e2SPeter Wemm register char *xp; 3869c2aa98e2SPeter Wemm int padc; 3870c2aa98e2SPeter Wemm char *buflim; 3871c2aa98e2SPeter Wemm int pos = 0; 387206f25ae9SGregory Neil Shapiro char peekbuf[12]; 3873c2aa98e2SPeter Wemm 3874c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 3875c2aa98e2SPeter Wemm { 3876c2aa98e2SPeter Wemm putline("", mci); 3877c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 3878c2aa98e2SPeter Wemm } 3879c2aa98e2SPeter Wemm 3880c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */ 3881c2aa98e2SPeter Wemm buflim = &buf[sizeof buf - 1]; 3882c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 3883c2aa98e2SPeter Wemm mci->mci_mailer->m_linelimit < sizeof buf - 1) 3884c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 3885c2aa98e2SPeter Wemm 3886c2aa98e2SPeter Wemm /* copy temp file to output with mapping */ 3887c2aa98e2SPeter Wemm ostate = OS_HEAD; 3888c2aa98e2SPeter Wemm bp = buf; 3889c2aa98e2SPeter Wemm pbp = peekbuf; 389006f25ae9SGregory Neil Shapiro while (!ferror(mci->mci_out) && !dead) 3891c2aa98e2SPeter Wemm { 3892c2aa98e2SPeter Wemm if (pbp > peekbuf) 3893c2aa98e2SPeter Wemm c = *--pbp; 3894c2aa98e2SPeter Wemm else if ((c = getc(e->e_dfp)) == EOF) 3895c2aa98e2SPeter Wemm break; 3896c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags)) 3897c2aa98e2SPeter Wemm c &= 0x7f; 3898c2aa98e2SPeter Wemm switch (ostate) 3899c2aa98e2SPeter Wemm { 3900c2aa98e2SPeter Wemm case OS_HEAD: 3901c2aa98e2SPeter Wemm #if _FFR_NONULLS 3902c2aa98e2SPeter Wemm if (c == '\0' && 3903c2aa98e2SPeter Wemm bitnset(M_NONULLS, mci->mci_mailer->m_flags)) 3904c2aa98e2SPeter Wemm break; 390506f25ae9SGregory Neil Shapiro #endif /* _FFR_NONULLS */ 3906c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim) 3907c2aa98e2SPeter Wemm { 3908c2aa98e2SPeter Wemm *bp++ = c; 3909c2aa98e2SPeter Wemm break; 3910c2aa98e2SPeter Wemm } 3911c2aa98e2SPeter Wemm 3912c2aa98e2SPeter Wemm /* check beginning of line for special cases */ 3913c2aa98e2SPeter Wemm *bp = '\0'; 3914c2aa98e2SPeter Wemm pos = 0; 3915c2aa98e2SPeter Wemm padc = EOF; 3916c2aa98e2SPeter Wemm if (buf[0] == 'F' && 3917c2aa98e2SPeter Wemm bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 3918c2aa98e2SPeter Wemm strncmp(buf, "From ", 5) == 0) 3919c2aa98e2SPeter Wemm { 3920c2aa98e2SPeter Wemm padc = '>'; 3921c2aa98e2SPeter Wemm } 3922c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' && 3923c2aa98e2SPeter Wemm separator != NULL) 3924c2aa98e2SPeter Wemm { 3925c2aa98e2SPeter Wemm /* possible separator */ 3926c2aa98e2SPeter Wemm int sl = strlen(separator); 3927c2aa98e2SPeter Wemm 3928c2aa98e2SPeter Wemm if (strncmp(&buf[2], separator, sl) == 0) 3929c2aa98e2SPeter Wemm padc = ' '; 3930c2aa98e2SPeter Wemm } 3931c2aa98e2SPeter Wemm if (buf[0] == '.' && 3932c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 3933c2aa98e2SPeter Wemm { 3934c2aa98e2SPeter Wemm padc = '.'; 3935c2aa98e2SPeter Wemm } 3936c2aa98e2SPeter Wemm 3937c2aa98e2SPeter Wemm /* now copy out saved line */ 3938c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 3939c2aa98e2SPeter Wemm { 3940c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "%05d >>> ", 3941c2aa98e2SPeter Wemm (int) getpid()); 3942c2aa98e2SPeter Wemm if (padc != EOF) 394306f25ae9SGregory Neil Shapiro (void) putc(padc, 394406f25ae9SGregory Neil Shapiro TrafficLogFile); 3945c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 394606f25ae9SGregory Neil Shapiro (void) putc((unsigned char) *xp, 394706f25ae9SGregory Neil Shapiro TrafficLogFile); 3948c2aa98e2SPeter Wemm if (c == '\n') 394906f25ae9SGregory Neil Shapiro (void) fputs(mci->mci_mailer->m_eol, 3950c2aa98e2SPeter Wemm TrafficLogFile); 3951c2aa98e2SPeter Wemm } 3952c2aa98e2SPeter Wemm if (padc != EOF) 3953c2aa98e2SPeter Wemm { 395406f25ae9SGregory Neil Shapiro if (putc(padc, mci->mci_out) == EOF) 395506f25ae9SGregory Neil Shapiro { 395606f25ae9SGregory Neil Shapiro dead = TRUE; 395706f25ae9SGregory Neil Shapiro continue; 395806f25ae9SGregory Neil Shapiro } 3959193538b7SGregory Neil Shapiro else 3960193538b7SGregory Neil Shapiro { 3961193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 3962193538b7SGregory Neil Shapiro DataProgress = TRUE; 3963193538b7SGregory Neil Shapiro } 3964c2aa98e2SPeter Wemm pos++; 3965c2aa98e2SPeter Wemm } 3966c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 3967c2aa98e2SPeter Wemm { 396806f25ae9SGregory Neil Shapiro if (putc((unsigned char) *xp, 396906f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 397006f25ae9SGregory Neil Shapiro { 397106f25ae9SGregory Neil Shapiro dead = TRUE; 397206f25ae9SGregory Neil Shapiro break; 3973c2aa98e2SPeter Wemm } 3974193538b7SGregory Neil Shapiro else 3975193538b7SGregory Neil Shapiro { 397606f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 397706f25ae9SGregory Neil Shapiro DataProgress = TRUE; 397806f25ae9SGregory Neil Shapiro } 3979193538b7SGregory Neil Shapiro } 398006f25ae9SGregory Neil Shapiro if (dead) 398106f25ae9SGregory Neil Shapiro continue; 3982c2aa98e2SPeter Wemm if (c == '\n') 3983c2aa98e2SPeter Wemm { 398406f25ae9SGregory Neil Shapiro if (fputs(mci->mci_mailer->m_eol, 398506f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 398606f25ae9SGregory Neil Shapiro break; 3987193538b7SGregory Neil Shapiro else 3988193538b7SGregory Neil Shapiro { 3989193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 3990193538b7SGregory Neil Shapiro DataProgress = TRUE; 3991193538b7SGregory Neil Shapiro } 3992c2aa98e2SPeter Wemm pos = 0; 3993c2aa98e2SPeter Wemm } 3994c2aa98e2SPeter Wemm else 3995c2aa98e2SPeter Wemm { 3996c2aa98e2SPeter Wemm pos += bp - buf; 3997c2aa98e2SPeter Wemm if (c != '\r') 3998c2aa98e2SPeter Wemm *pbp++ = c; 3999c2aa98e2SPeter Wemm } 400006f25ae9SGregory Neil Shapiro 4001c2aa98e2SPeter Wemm bp = buf; 4002c2aa98e2SPeter Wemm 4003c2aa98e2SPeter Wemm /* determine next state */ 4004c2aa98e2SPeter Wemm if (c == '\n') 4005c2aa98e2SPeter Wemm ostate = OS_HEAD; 4006c2aa98e2SPeter Wemm else if (c == '\r') 4007c2aa98e2SPeter Wemm ostate = OS_CR; 4008c2aa98e2SPeter Wemm else 4009c2aa98e2SPeter Wemm ostate = OS_INLINE; 4010c2aa98e2SPeter Wemm continue; 4011c2aa98e2SPeter Wemm 4012c2aa98e2SPeter Wemm case OS_CR: 4013c2aa98e2SPeter Wemm if (c == '\n') 4014c2aa98e2SPeter Wemm { 4015c2aa98e2SPeter Wemm /* got CRLF */ 401606f25ae9SGregory Neil Shapiro if (fputs(mci->mci_mailer->m_eol, 401706f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 401806f25ae9SGregory Neil Shapiro continue; 4019193538b7SGregory Neil Shapiro else 4020193538b7SGregory Neil Shapiro { 402106f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 402206f25ae9SGregory Neil Shapiro DataProgress = TRUE; 4023193538b7SGregory Neil Shapiro } 402406f25ae9SGregory Neil Shapiro 4025c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4026c2aa98e2SPeter Wemm { 402706f25ae9SGregory Neil Shapiro (void) fputs(mci->mci_mailer->m_eol, 4028c2aa98e2SPeter Wemm TrafficLogFile); 4029c2aa98e2SPeter Wemm } 4030c2aa98e2SPeter Wemm ostate = OS_HEAD; 4031c2aa98e2SPeter Wemm continue; 4032c2aa98e2SPeter Wemm } 4033c2aa98e2SPeter Wemm 4034c2aa98e2SPeter Wemm /* had a naked carriage return */ 4035c2aa98e2SPeter Wemm *pbp++ = c; 4036c2aa98e2SPeter Wemm c = '\r'; 4037c2aa98e2SPeter Wemm ostate = OS_INLINE; 4038c2aa98e2SPeter Wemm goto putch; 4039c2aa98e2SPeter Wemm 4040c2aa98e2SPeter Wemm case OS_INLINE: 4041c2aa98e2SPeter Wemm if (c == '\r') 4042c2aa98e2SPeter Wemm { 4043c2aa98e2SPeter Wemm ostate = OS_CR; 4044c2aa98e2SPeter Wemm continue; 4045c2aa98e2SPeter Wemm } 4046c2aa98e2SPeter Wemm #if _FFR_NONULLS 4047c2aa98e2SPeter Wemm if (c == '\0' && 4048c2aa98e2SPeter Wemm bitnset(M_NONULLS, mci->mci_mailer->m_flags)) 4049c2aa98e2SPeter Wemm break; 405006f25ae9SGregory Neil Shapiro #endif /* _FFR_NONULLS */ 4051c2aa98e2SPeter Wemm putch: 4052c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 405306f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 && 4054c2aa98e2SPeter Wemm c != '\n') 4055c2aa98e2SPeter Wemm { 405606f25ae9SGregory Neil Shapiro int d; 405706f25ae9SGregory Neil Shapiro 405806f25ae9SGregory Neil Shapiro /* check next character for EOL */ 405906f25ae9SGregory Neil Shapiro if (pbp > peekbuf) 406006f25ae9SGregory Neil Shapiro d = *(pbp - 1); 406106f25ae9SGregory Neil Shapiro else if ((d = getc(e->e_dfp)) != EOF) 406206f25ae9SGregory Neil Shapiro *pbp++ = d; 406306f25ae9SGregory Neil Shapiro 406406f25ae9SGregory Neil Shapiro if (d == '\n' || d == EOF) 406506f25ae9SGregory Neil Shapiro { 406606f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL) 406706f25ae9SGregory Neil Shapiro (void) putc((unsigned char) c, 406806f25ae9SGregory Neil Shapiro TrafficLogFile); 406906f25ae9SGregory Neil Shapiro if (putc((unsigned char) c, 407006f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 407106f25ae9SGregory Neil Shapiro { 407206f25ae9SGregory Neil Shapiro dead = TRUE; 407306f25ae9SGregory Neil Shapiro continue; 407406f25ae9SGregory Neil Shapiro } 4075193538b7SGregory Neil Shapiro else 4076193538b7SGregory Neil Shapiro { 4077193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 4078193538b7SGregory Neil Shapiro DataProgress = TRUE; 4079193538b7SGregory Neil Shapiro } 408006f25ae9SGregory Neil Shapiro pos++; 408106f25ae9SGregory Neil Shapiro continue; 408206f25ae9SGregory Neil Shapiro } 408306f25ae9SGregory Neil Shapiro 408406f25ae9SGregory Neil Shapiro if (putc('!', mci->mci_out) == EOF || 408506f25ae9SGregory Neil Shapiro fputs(mci->mci_mailer->m_eol, 408606f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 408706f25ae9SGregory Neil Shapiro { 408806f25ae9SGregory Neil Shapiro dead = TRUE; 408906f25ae9SGregory Neil Shapiro continue; 409006f25ae9SGregory Neil Shapiro } 4091193538b7SGregory Neil Shapiro else 4092193538b7SGregory Neil Shapiro { 409306f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 409406f25ae9SGregory Neil Shapiro DataProgress = TRUE; 4095193538b7SGregory Neil Shapiro } 409606f25ae9SGregory Neil Shapiro 4097c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4098c2aa98e2SPeter Wemm { 4099c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "!%s", 4100c2aa98e2SPeter Wemm mci->mci_mailer->m_eol); 4101c2aa98e2SPeter Wemm } 4102c2aa98e2SPeter Wemm ostate = OS_HEAD; 4103c2aa98e2SPeter Wemm *pbp++ = c; 4104c2aa98e2SPeter Wemm continue; 4105c2aa98e2SPeter Wemm } 4106c2aa98e2SPeter Wemm if (c == '\n') 4107c2aa98e2SPeter Wemm { 4108c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 410906f25ae9SGregory Neil Shapiro (void) fputs(mci->mci_mailer->m_eol, 4110c2aa98e2SPeter Wemm TrafficLogFile); 411106f25ae9SGregory Neil Shapiro if (fputs(mci->mci_mailer->m_eol, 411206f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 411306f25ae9SGregory Neil Shapiro continue; 4114193538b7SGregory Neil Shapiro else 4115193538b7SGregory Neil Shapiro { 4116193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 4117193538b7SGregory Neil Shapiro DataProgress = TRUE; 4118193538b7SGregory Neil Shapiro } 4119c2aa98e2SPeter Wemm pos = 0; 4120c2aa98e2SPeter Wemm ostate = OS_HEAD; 4121c2aa98e2SPeter Wemm } 4122c2aa98e2SPeter Wemm else 4123c2aa98e2SPeter Wemm { 4124c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 412506f25ae9SGregory Neil Shapiro (void) putc((unsigned char) c, 412606f25ae9SGregory Neil Shapiro TrafficLogFile); 412706f25ae9SGregory Neil Shapiro if (putc((unsigned char) c, 412806f25ae9SGregory Neil Shapiro mci->mci_out) == EOF) 412906f25ae9SGregory Neil Shapiro { 413006f25ae9SGregory Neil Shapiro dead = TRUE; 413106f25ae9SGregory Neil Shapiro continue; 413206f25ae9SGregory Neil Shapiro } 4133193538b7SGregory Neil Shapiro else 4134193538b7SGregory Neil Shapiro { 4135193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 4136193538b7SGregory Neil Shapiro DataProgress = TRUE; 4137193538b7SGregory Neil Shapiro } 4138c2aa98e2SPeter Wemm pos++; 4139c2aa98e2SPeter Wemm ostate = OS_INLINE; 4140c2aa98e2SPeter Wemm } 4141c2aa98e2SPeter Wemm break; 4142c2aa98e2SPeter Wemm } 4143c2aa98e2SPeter Wemm } 4144c2aa98e2SPeter Wemm 4145c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */ 4146c2aa98e2SPeter Wemm if (bp > buf) 4147c2aa98e2SPeter Wemm { 4148c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4149c2aa98e2SPeter Wemm { 4150c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 415106f25ae9SGregory Neil Shapiro (void) putc((unsigned char) *xp, 415206f25ae9SGregory Neil Shapiro TrafficLogFile); 4153c2aa98e2SPeter Wemm } 4154c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4155c2aa98e2SPeter Wemm { 415606f25ae9SGregory Neil Shapiro if (putc((unsigned char) *xp, mci->mci_out) == 415706f25ae9SGregory Neil Shapiro EOF) 415806f25ae9SGregory Neil Shapiro { 415906f25ae9SGregory Neil Shapiro dead = TRUE; 416006f25ae9SGregory Neil Shapiro break; 416106f25ae9SGregory Neil Shapiro } 4162193538b7SGregory Neil Shapiro else 4163193538b7SGregory Neil Shapiro { 416406f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 416506f25ae9SGregory Neil Shapiro DataProgress = TRUE; 4166c2aa98e2SPeter Wemm } 4167193538b7SGregory Neil Shapiro } 4168c2aa98e2SPeter Wemm pos += bp - buf; 4169c2aa98e2SPeter Wemm } 417006f25ae9SGregory Neil Shapiro if (!dead && pos > 0) 4171c2aa98e2SPeter Wemm { 4172c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 417306f25ae9SGregory Neil Shapiro (void) fputs(mci->mci_mailer->m_eol, 417406f25ae9SGregory Neil Shapiro TrafficLogFile); 417506f25ae9SGregory Neil Shapiro (void) fputs(mci->mci_mailer->m_eol, mci->mci_out); 417606f25ae9SGregory Neil Shapiro 417706f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 417806f25ae9SGregory Neil Shapiro DataProgress = TRUE; 4179c2aa98e2SPeter Wemm } 4180c2aa98e2SPeter Wemm } 4181c2aa98e2SPeter Wemm 4182c2aa98e2SPeter Wemm if (ferror(e->e_dfp)) 4183c2aa98e2SPeter Wemm { 418406f25ae9SGregory Neil Shapiro syserr("putbody: %s/df%s: read error", 418506f25ae9SGregory Neil Shapiro qid_printqueue(e->e_queuedir), e->e_id); 4186c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4187c2aa98e2SPeter Wemm } 4188c2aa98e2SPeter Wemm 4189c2aa98e2SPeter Wemm endofmessage: 419006f25ae9SGregory Neil Shapiro /* 419106f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process, 419206f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the 419306f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel 419406f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared 419506f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital 419606f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the 419706f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell) 419806f25ae9SGregory Neil Shapiro ** offset to match. 419906f25ae9SGregory Neil Shapiro */ 420006f25ae9SGregory Neil Shapiro 420106f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) 420206f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 420306f25ae9SGregory Neil Shapiro 4204c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */ 420506f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 4206c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n') 4207c2aa98e2SPeter Wemm putline("", mci); 4208c2aa98e2SPeter Wemm 4209c2aa98e2SPeter Wemm (void) fflush(mci->mci_out); 4210c2aa98e2SPeter Wemm if (ferror(mci->mci_out) && errno != EPIPE) 4211c2aa98e2SPeter Wemm { 4212c2aa98e2SPeter Wemm syserr("putbody: write error"); 4213c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4214c2aa98e2SPeter Wemm } 421506f25ae9SGregory Neil Shapiro 4216c2aa98e2SPeter Wemm errno = 0; 4217c2aa98e2SPeter Wemm } 4218c2aa98e2SPeter Wemm /* 4219c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file. 4220c2aa98e2SPeter Wemm ** 4221c2aa98e2SPeter Wemm ** If the file has the setuid/setgid bits set, but NO execute 4222c2aa98e2SPeter Wemm ** bits, sendmail will try to become the owner of that file 4223c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if 4224c2aa98e2SPeter Wemm ** sendmail runs as root. 4225c2aa98e2SPeter Wemm ** 4226c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it 4227c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We 4228c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it 4229c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have 4230c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message. 4231c2aa98e2SPeter Wemm ** 4232c2aa98e2SPeter Wemm ** Parameters: 4233c2aa98e2SPeter Wemm ** filename -- the name of the file to send to. 4234c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL, 4235c2aa98e2SPeter Wemm ** use FileMailer. 4236c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes 4237c2aa98e2SPeter Wemm ** the userid/groupid to be when sending. 4238c2aa98e2SPeter Wemm ** sfflags -- flags for opening. 4239c2aa98e2SPeter Wemm ** e -- the current envelope. 4240c2aa98e2SPeter Wemm ** 4241c2aa98e2SPeter Wemm ** Returns: 4242c2aa98e2SPeter Wemm ** The exit code associated with the operation. 4243c2aa98e2SPeter Wemm ** 4244c2aa98e2SPeter Wemm ** Side Effects: 4245c2aa98e2SPeter Wemm ** none. 4246c2aa98e2SPeter Wemm */ 4247c2aa98e2SPeter Wemm 4248c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout; 4249c2aa98e2SPeter Wemm 4250c2aa98e2SPeter Wemm int 4251c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e) 4252c2aa98e2SPeter Wemm char *volatile filename; 4253c2aa98e2SPeter Wemm MAILER *volatile mailer; 4254c2aa98e2SPeter Wemm ADDRESS *ctladdr; 425506f25ae9SGregory Neil Shapiro volatile long sfflags; 4256c2aa98e2SPeter Wemm register ENVELOPE *e; 4257c2aa98e2SPeter Wemm { 4258c2aa98e2SPeter Wemm register FILE *f; 4259c2aa98e2SPeter Wemm register pid_t pid = -1; 426006f25ae9SGregory Neil Shapiro volatile int mode; 426106f25ae9SGregory Neil Shapiro int len; 426206f25ae9SGregory Neil Shapiro off_t curoff; 4263c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0; 4264c2aa98e2SPeter Wemm char *p; 426506f25ae9SGregory Neil Shapiro char *volatile realfile; 4266c2aa98e2SPeter Wemm EVENT *ev; 426706f25ae9SGregory Neil Shapiro char buf[MAXLINE + 1]; 426806f25ae9SGregory Neil Shapiro char targetfile[MAXPATHLEN + 1]; 4269c2aa98e2SPeter Wemm 4270c2aa98e2SPeter Wemm if (tTd(11, 1)) 4271c2aa98e2SPeter Wemm { 427206f25ae9SGregory Neil Shapiro dprintf("mailfile %s\n ctladdr=", filename); 4273c2aa98e2SPeter Wemm printaddr(ctladdr, FALSE); 4274c2aa98e2SPeter Wemm } 4275c2aa98e2SPeter Wemm 4276c2aa98e2SPeter Wemm if (mailer == NULL) 4277c2aa98e2SPeter Wemm mailer = FileMailer; 4278c2aa98e2SPeter Wemm 4279c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 428006f25ae9SGregory Neil Shapiro (void) fflush(e->e_xfp); 4281c2aa98e2SPeter Wemm 4282c2aa98e2SPeter Wemm /* 4283c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file 4284c2aa98e2SPeter Wemm ** delivery to regular files only. 4285c2aa98e2SPeter Wemm */ 4286c2aa98e2SPeter Wemm 4287c2aa98e2SPeter Wemm if (strcmp(filename, "/dev/null") == 0) 4288c2aa98e2SPeter Wemm return EX_OK; 4289c2aa98e2SPeter Wemm 4290c2aa98e2SPeter Wemm /* check for 8-bit available */ 4291c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 4292c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) && 4293c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 4294c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 4295c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 4296c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 4297c2aa98e2SPeter Wemm { 4298c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 429906f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 430006f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 430106f25ae9SGregory Neil Shapiro return EX_DATAERR; 430206f25ae9SGregory Neil Shapiro } 430306f25ae9SGregory Neil Shapiro 430406f25ae9SGregory Neil Shapiro /* Find the actual file */ 430506f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 430606f25ae9SGregory Neil Shapiro { 430706f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv); 430806f25ae9SGregory Neil Shapiro 430906f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0) 431006f25ae9SGregory Neil Shapiro filename += len; 431106f25ae9SGregory Neil Shapiro 431206f25ae9SGregory Neil Shapiro if (len + strlen(filename) + 1 > MAXPATHLEN) 431306f25ae9SGregory Neil Shapiro { 431406f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 431506f25ae9SGregory Neil Shapiro SafeFileEnv, filename); 431606f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 431706f25ae9SGregory Neil Shapiro } 431806f25ae9SGregory Neil Shapiro (void) strlcpy(targetfile, SafeFileEnv, sizeof targetfile); 431906f25ae9SGregory Neil Shapiro realfile = targetfile + len; 432006f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 432106f25ae9SGregory Neil Shapiro (void) strlcat(targetfile, "/", sizeof targetfile); 432206f25ae9SGregory Neil Shapiro if (*filename == '/') 432306f25ae9SGregory Neil Shapiro filename++; 432406f25ae9SGregory Neil Shapiro (void) strlcat(targetfile, filename, sizeof targetfile); 432506f25ae9SGregory Neil Shapiro } 432606f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL) 432706f25ae9SGregory Neil Shapiro { 432806f25ae9SGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof targetfile, e); 432906f25ae9SGregory Neil Shapiro len = strlen(targetfile); 433006f25ae9SGregory Neil Shapiro 433106f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0) 433206f25ae9SGregory Neil Shapiro filename += len; 433306f25ae9SGregory Neil Shapiro 433406f25ae9SGregory Neil Shapiro if (len + strlen(filename) + 1 > MAXPATHLEN) 433506f25ae9SGregory Neil Shapiro { 433606f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 433706f25ae9SGregory Neil Shapiro targetfile, filename); 433806f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 433906f25ae9SGregory Neil Shapiro } 434006f25ae9SGregory Neil Shapiro realfile = targetfile + len; 434106f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 434206f25ae9SGregory Neil Shapiro (void) strlcat(targetfile, "/", sizeof targetfile); 434306f25ae9SGregory Neil Shapiro if (*filename == '/') 434406f25ae9SGregory Neil Shapiro (void) strlcat(targetfile, filename + 1, 434506f25ae9SGregory Neil Shapiro sizeof targetfile); 434606f25ae9SGregory Neil Shapiro else 434706f25ae9SGregory Neil Shapiro (void) strlcat(targetfile, filename, sizeof targetfile); 434806f25ae9SGregory Neil Shapiro } 434906f25ae9SGregory Neil Shapiro else 435006f25ae9SGregory Neil Shapiro { 435106f25ae9SGregory Neil Shapiro if (strlen(filename) > MAXPATHLEN) 435206f25ae9SGregory Neil Shapiro { 435306f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename); 435406f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 435506f25ae9SGregory Neil Shapiro } 435606f25ae9SGregory Neil Shapiro (void) strlcpy(targetfile, filename, sizeof targetfile); 435706f25ae9SGregory Neil Shapiro realfile = targetfile; 4358c2aa98e2SPeter Wemm } 4359c2aa98e2SPeter Wemm 4360c2aa98e2SPeter Wemm /* 4361c2aa98e2SPeter Wemm ** Fork so we can change permissions here. 4362c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of 4363c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc. 4364c2aa98e2SPeter Wemm */ 4365c2aa98e2SPeter Wemm 4366c2aa98e2SPeter Wemm DOFORK(fork); 4367c2aa98e2SPeter Wemm 4368c2aa98e2SPeter Wemm if (pid < 0) 436906f25ae9SGregory Neil Shapiro return EX_OSERR; 4370c2aa98e2SPeter Wemm else if (pid == 0) 4371c2aa98e2SPeter Wemm { 4372c2aa98e2SPeter Wemm /* child -- actually write to file */ 4373c2aa98e2SPeter Wemm struct stat stb; 4374c2aa98e2SPeter Wemm MCI mcibuf; 4375065a643dSPeter Wemm int err; 4376c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND; 4377c2aa98e2SPeter Wemm 4378c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 4379c2aa98e2SPeter Wemm (void) close(fileno(e->e_lockfp)); 4380c2aa98e2SPeter Wemm 4381c2aa98e2SPeter Wemm (void) setsignal(SIGINT, SIG_DFL); 4382c2aa98e2SPeter Wemm (void) setsignal(SIGHUP, SIG_DFL); 4383c2aa98e2SPeter Wemm (void) setsignal(SIGTERM, SIG_DFL); 4384c2aa98e2SPeter Wemm (void) umask(OldUmask); 4385c2aa98e2SPeter Wemm e->e_to = filename; 4386c2aa98e2SPeter Wemm ExitStat = EX_OK; 4387c2aa98e2SPeter Wemm 4388c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0) 4389c2aa98e2SPeter Wemm { 4390c2aa98e2SPeter Wemm exit(EX_TEMPFAIL); 4391c2aa98e2SPeter Wemm } 4392c2aa98e2SPeter Wemm 4393c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0) 4394c2aa98e2SPeter Wemm ev = setevent(TimeOuts.to_fileopen, mailfiletimeout, 0); 4395c2aa98e2SPeter Wemm else 4396c2aa98e2SPeter Wemm ev = NULL; 4397c2aa98e2SPeter Wemm 439806f25ae9SGregory Neil Shapiro /* check file mode to see if setuid */ 439906f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0) 4400c2aa98e2SPeter Wemm mode = FileMode; 440106f25ae9SGregory Neil Shapiro else 4402c2aa98e2SPeter Wemm mode = stb.st_mode; 4403c2aa98e2SPeter Wemm 4404c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */ 4405c2aa98e2SPeter Wemm errno = 0; 4406c2aa98e2SPeter Wemm ExitStat = EX_OK; 4407c2aa98e2SPeter Wemm 440806f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */ 440906f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 441006f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags)) 4411c2aa98e2SPeter Wemm { 4412c2aa98e2SPeter Wemm /* ignore setuid and setgid bits */ 4413c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID); 441406f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 441506f25ae9SGregory Neil Shapiro dprintf("mailfile: ignoring setuid/setgid bits\n"); 4416c2aa98e2SPeter Wemm } 4417c2aa98e2SPeter Wemm 4418c2aa98e2SPeter Wemm /* we have to open the dfile BEFORE setuid */ 4419c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 4420c2aa98e2SPeter Wemm { 4421c2aa98e2SPeter Wemm char *df = queuename(e, 'd'); 4422c2aa98e2SPeter Wemm 4423c2aa98e2SPeter Wemm e->e_dfp = fopen(df, "r"); 4424c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 4425c2aa98e2SPeter Wemm { 4426c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s", 4427c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr); 4428c2aa98e2SPeter Wemm } 4429c2aa98e2SPeter Wemm } 4430c2aa98e2SPeter Wemm 4431c2aa98e2SPeter Wemm /* select a new user to run as */ 4432c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags)) 4433c2aa98e2SPeter Wemm { 4434c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 4435c2aa98e2SPeter Wemm { 4436c2aa98e2SPeter Wemm RealUserName = NULL; 4437c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 443806f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid) 443906f25ae9SGregory Neil Shapiro { 444006f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 444106f25ae9SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid"); 444206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 444306f25ae9SGregory Neil Shapiro } 4444c2aa98e2SPeter Wemm } 4445c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode)) 4446c2aa98e2SPeter Wemm { 4447c2aa98e2SPeter Wemm RealUserName = NULL; 4448c2aa98e2SPeter Wemm RealUid = stb.st_uid; 4449c2aa98e2SPeter Wemm } 4450c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 4451c2aa98e2SPeter Wemm { 4452c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL) 4453c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser; 4454c2aa98e2SPeter Wemm else 4455c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user; 4456c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid; 4457c2aa98e2SPeter Wemm } 4458c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_uid != 0) 4459c2aa98e2SPeter Wemm { 4460c2aa98e2SPeter Wemm RealUserName = DefUser; 4461c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 4462c2aa98e2SPeter Wemm } 4463c2aa98e2SPeter Wemm else 4464c2aa98e2SPeter Wemm { 4465c2aa98e2SPeter Wemm RealUserName = DefUser; 4466c2aa98e2SPeter Wemm RealUid = DefUid; 4467c2aa98e2SPeter Wemm } 4468c2aa98e2SPeter Wemm 4469c2aa98e2SPeter Wemm /* select a new group to run as */ 4470c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 447106f25ae9SGregory Neil Shapiro { 4472c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 447306f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 447406f25ae9SGregory Neil Shapiro (RealGid != getgid() || 447506f25ae9SGregory Neil Shapiro RealGid != getegid())) 447606f25ae9SGregory Neil Shapiro { 447706f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 447806f25ae9SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid"); 447906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 448006f25ae9SGregory Neil Shapiro } 448106f25ae9SGregory Neil Shapiro } 4482c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode)) 4483c2aa98e2SPeter Wemm RealGid = stb.st_gid; 448406f25ae9SGregory Neil Shapiro else if (ctladdr != NULL && 448506f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid && 448606f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0) 4487193538b7SGregory Neil Shapiro { 4488193538b7SGregory Neil Shapiro /* 4489193538b7SGregory Neil Shapiro ** Special case: This means it is an 4490193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser. 4491193538b7SGregory Neil Shapiro ** See alias()'s comments. 4492193538b7SGregory Neil Shapiro */ 4493193538b7SGregory Neil Shapiro 449406f25ae9SGregory Neil Shapiro RealGid = DefGid; 4495193538b7SGregory Neil Shapiro RealUserName = DefUser; 4496193538b7SGregory Neil Shapiro } 4497193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0) 4498193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid; 4499c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_gid != 0) 4500c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 4501c2aa98e2SPeter Wemm else 4502c2aa98e2SPeter Wemm RealGid = DefGid; 4503c2aa98e2SPeter Wemm } 4504c2aa98e2SPeter Wemm 4505c2aa98e2SPeter Wemm /* last ditch */ 4506c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags)) 4507c2aa98e2SPeter Wemm { 4508c2aa98e2SPeter Wemm if (RealUid == 0) 4509c2aa98e2SPeter Wemm RealUid = DefUid; 4510c2aa98e2SPeter Wemm if (RealGid == 0) 4511c2aa98e2SPeter Wemm RealGid = DefGid; 4512c2aa98e2SPeter Wemm } 4513c2aa98e2SPeter Wemm 4514c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */ 4515c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups) 4516c2aa98e2SPeter Wemm { 4517c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 451806f25ae9SGregory Neil Shapiro { 4519c2aa98e2SPeter Wemm syserr("mailfile: initgroups(%s, %d) failed", 4520c2aa98e2SPeter Wemm RealUserName, RealGid); 452106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 452206f25ae9SGregory Neil Shapiro } 4523c2aa98e2SPeter Wemm } 4524c2aa98e2SPeter Wemm else 4525c2aa98e2SPeter Wemm { 4526c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 4527c2aa98e2SPeter Wemm 4528c2aa98e2SPeter Wemm gidset[0] = RealGid; 4529c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 453006f25ae9SGregory Neil Shapiro { 4531c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed"); 453206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 453306f25ae9SGregory Neil Shapiro } 4534c2aa98e2SPeter Wemm } 4535c2aa98e2SPeter Wemm 453606f25ae9SGregory Neil Shapiro /* 453706f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it. 453806f25ae9SGregory Neil Shapiro */ 4539c2aa98e2SPeter Wemm 454006f25ae9SGregory Neil Shapiro if (realfile != targetfile) 454106f25ae9SGregory Neil Shapiro { 454206f25ae9SGregory Neil Shapiro *realfile = '\0'; 454306f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 454406f25ae9SGregory Neil Shapiro dprintf("mailfile: chroot %s\n", targetfile); 454506f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0) 4546c2aa98e2SPeter Wemm { 4547c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)", 454806f25ae9SGregory Neil Shapiro targetfile); 4549c2aa98e2SPeter Wemm exit(EX_CANTCREAT); 4550c2aa98e2SPeter Wemm } 455106f25ae9SGregory Neil Shapiro *realfile = '/'; 4552c2aa98e2SPeter Wemm } 455306f25ae9SGregory Neil Shapiro 455406f25ae9SGregory Neil Shapiro if (tTd(11, 40)) 455506f25ae9SGregory Neil Shapiro dprintf("mailfile: deliver to %s\n", realfile); 455606f25ae9SGregory Neil Shapiro 4557c2aa98e2SPeter Wemm if (chdir("/") < 0) 455806f25ae9SGregory Neil Shapiro { 4559c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)"); 456006f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 456106f25ae9SGregory Neil Shapiro } 4562c2aa98e2SPeter Wemm 4563c2aa98e2SPeter Wemm /* now reset the group and user ids */ 4564c2aa98e2SPeter Wemm endpwent(); 4565c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn) 456606f25ae9SGregory Neil Shapiro { 4567c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid); 456806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 456906f25ae9SGregory Neil Shapiro } 4570c2aa98e2SPeter Wemm vendor_set_uid(RealUid); 4571c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn) 457206f25ae9SGregory Neil Shapiro { 4573c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid); 457406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 457506f25ae9SGregory Neil Shapiro } 457606f25ae9SGregory Neil Shapiro 457706f25ae9SGregory Neil Shapiro if (tTd(11, 2)) 457806f25ae9SGregory Neil Shapiro dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 457906f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 458006f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 458106f25ae9SGregory Neil Shapiro 4582c2aa98e2SPeter Wemm 4583c2aa98e2SPeter Wemm /* move into some "safe" directory */ 4584c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL) 4585c2aa98e2SPeter Wemm { 4586c2aa98e2SPeter Wemm char *q; 4587c2aa98e2SPeter Wemm 4588c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q) 4589c2aa98e2SPeter Wemm { 4590c2aa98e2SPeter Wemm q = strchr(p, ':'); 4591c2aa98e2SPeter Wemm if (q != NULL) 4592c2aa98e2SPeter Wemm *q = '\0'; 4593c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 4594c2aa98e2SPeter Wemm if (q != NULL) 4595c2aa98e2SPeter Wemm *q++ = ':'; 4596c2aa98e2SPeter Wemm if (tTd(11, 20)) 459706f25ae9SGregory Neil Shapiro dprintf("mailfile: trydir %s\n", buf); 4598c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 4599c2aa98e2SPeter Wemm break; 4600c2aa98e2SPeter Wemm } 4601c2aa98e2SPeter Wemm } 4602c2aa98e2SPeter Wemm 460306f25ae9SGregory Neil Shapiro /* 460406f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the 460506f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as 460606f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running 460706f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats 460806f25ae9SGregory Neil Shapiro ** root as nobody. 460906f25ae9SGregory Neil Shapiro */ 461006f25ae9SGregory Neil Shapiro 461106f25ae9SGregory Neil Shapiro #if HASLSTAT 461206f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 461306f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 461406f25ae9SGregory Neil Shapiro else 461506f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb); 461606f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 461706f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 461806f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 461906f25ae9SGregory Neil Shapiro 462006f25ae9SGregory Neil Shapiro if (err < 0) 462106f25ae9SGregory Neil Shapiro { 462206f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE; 462306f25ae9SGregory Neil Shapiro mode = FileMode; 462406f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL; 462506f25ae9SGregory Neil Shapiro } 462606f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 462706f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 462806f25ae9SGregory Neil Shapiro DontBlameSendmail) && 462906f25ae9SGregory Neil Shapiro stb.st_nlink != 1) || 463006f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode))) 463106f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 463206f25ae9SGregory Neil Shapiro else 463306f25ae9SGregory Neil Shapiro mode = stb.st_mode; 463406f25ae9SGregory Neil Shapiro 463506f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 4636c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK; 463706f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 4638c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK; 4639c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT; 464006f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags); 4641c2aa98e2SPeter Wemm if (f == NULL) 4642c2aa98e2SPeter Wemm { 464306f25ae9SGregory Neil Shapiro if (transienterror(errno)) 464406f25ae9SGregory Neil Shapiro { 464506f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s", 464606f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 464706f25ae9SGregory Neil Shapiro errstring(errno)); 464806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 464906f25ae9SGregory Neil Shapiro } 465006f25ae9SGregory Neil Shapiro else 465106f25ae9SGregory Neil Shapiro { 465206f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s", 465306f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 4654c2aa98e2SPeter Wemm errstring(errno)); 4655c2aa98e2SPeter Wemm exit(EX_CANTCREAT); 4656c2aa98e2SPeter Wemm } 465706f25ae9SGregory Neil Shapiro } 465806f25ae9SGregory Neil Shapiro if (filechanged(realfile, fileno(f), &stb)) 4659c2aa98e2SPeter Wemm { 466006f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open"); 4661c2aa98e2SPeter Wemm exit(EX_CANTCREAT); 4662c2aa98e2SPeter Wemm } 4663c2aa98e2SPeter Wemm if (fstat(fileno(f), &stb) < 0) 4664c2aa98e2SPeter Wemm { 466506f25ae9SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s", errstring(errno)); 4666c2aa98e2SPeter Wemm exit(EX_CANTCREAT); 4667c2aa98e2SPeter Wemm } 4668c2aa98e2SPeter Wemm 466906f25ae9SGregory Neil Shapiro curoff = stb.st_size; 467006f25ae9SGregory Neil Shapiro 4671c2aa98e2SPeter Wemm if (ev != NULL) 4672c2aa98e2SPeter Wemm clrevent(ev); 4673c2aa98e2SPeter Wemm 467406f25ae9SGregory Neil Shapiro memset(&mcibuf, '\0', sizeof mcibuf); 4675c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer; 4676c2aa98e2SPeter Wemm mcibuf.mci_out = f; 4677c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags)) 4678c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT; 4679c2aa98e2SPeter Wemm 4680c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 4681c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 4682c2aa98e2SPeter Wemm 4683c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 4684c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 4685c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags)) 4686c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7; 4687c2aa98e2SPeter Wemm 4688c2aa98e2SPeter Wemm #if MIME7TO8 4689c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) && 4690c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) && 4691c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 4692c2aa98e2SPeter Wemm (strcasecmp(p, "quoted-printable") == 0 || 4693c2aa98e2SPeter Wemm strcasecmp(p, "base64") == 0) && 4694c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 4695c2aa98e2SPeter Wemm { 4696c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 4697c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 4698c2aa98e2SPeter Wemm if (strncasecmp(p, "text/plain", 10) == 0 && 4699c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 4700c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8; 4701c2aa98e2SPeter Wemm } 470206f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 4703c2aa98e2SPeter Wemm 4704c2aa98e2SPeter Wemm putfromline(&mcibuf, e); 47052e43090eSPeter Wemm (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER); 4706c2aa98e2SPeter Wemm (*e->e_putbody)(&mcibuf, e, NULL); 4707c2aa98e2SPeter Wemm putline("\n", &mcibuf); 470806f25ae9SGregory Neil Shapiro if (fflush(f) < 0 || 470906f25ae9SGregory Neil Shapiro (SuperSafe && fsync(fileno(f)) < 0) || 471006f25ae9SGregory Neil Shapiro ferror(f)) 4711c2aa98e2SPeter Wemm { 4712c2aa98e2SPeter Wemm setstat(EX_IOERR); 471306f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE 471406f25ae9SGregory Neil Shapiro (void) ftruncate(fileno(f), curoff); 471506f25ae9SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 4716c2aa98e2SPeter Wemm } 4717c2aa98e2SPeter Wemm 4718c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */ 4719c2aa98e2SPeter Wemm #if HASFCHMOD 472006f25ae9SGregory Neil Shapiro (void) fchmod(fileno(f), (MODE_T) mode); 472106f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */ 472206f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode); 472306f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */ 472406f25ae9SGregory Neil Shapiro if (fclose(f) < 0) 472506f25ae9SGregory Neil Shapiro setstat(EX_IOERR); 4726c2aa98e2SPeter Wemm (void) fflush(stdout); 472706f25ae9SGregory Neil Shapiro (void) setuid(RealUid); 4728c2aa98e2SPeter Wemm exit(ExitStat); 4729c2aa98e2SPeter Wemm /* NOTREACHED */ 4730c2aa98e2SPeter Wemm } 4731c2aa98e2SPeter Wemm else 4732c2aa98e2SPeter Wemm { 4733c2aa98e2SPeter Wemm /* parent -- wait for exit status */ 4734c2aa98e2SPeter Wemm int st; 4735c2aa98e2SPeter Wemm 4736c2aa98e2SPeter Wemm st = waitfor(pid); 4737c2aa98e2SPeter Wemm if (st == -1) 4738c2aa98e2SPeter Wemm { 4739c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name); 474006f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 4741c2aa98e2SPeter Wemm } 4742c2aa98e2SPeter Wemm if (WIFEXITED(st)) 4743c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 4744c2aa98e2SPeter Wemm else 4745c2aa98e2SPeter Wemm { 4746c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d", 4747c2aa98e2SPeter Wemm mailer->m_name, st); 474806f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE; 4749c2aa98e2SPeter Wemm } 4750c2aa98e2SPeter Wemm /* NOTREACHED */ 4751c2aa98e2SPeter Wemm } 4752c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 4753c2aa98e2SPeter Wemm } 4754c2aa98e2SPeter Wemm 4755c2aa98e2SPeter Wemm static void 4756c2aa98e2SPeter Wemm mailfiletimeout() 4757c2aa98e2SPeter Wemm { 4758c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1); 4759c2aa98e2SPeter Wemm } 4760c2aa98e2SPeter Wemm /* 4761c2aa98e2SPeter Wemm ** HOSTSIGNATURE -- return the "signature" for a host. 4762c2aa98e2SPeter Wemm ** 4763c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it 4764c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be 4765c2aa98e2SPeter Wemm ** an ordered list of MX hosts. 4766c2aa98e2SPeter Wemm ** 4767c2aa98e2SPeter Wemm ** Parameters: 4768c2aa98e2SPeter Wemm ** m -- the mailer describing this host. 4769c2aa98e2SPeter Wemm ** host -- the host name. 4770c2aa98e2SPeter Wemm ** 4771c2aa98e2SPeter Wemm ** Returns: 4772c2aa98e2SPeter Wemm ** The signature for this host. 4773c2aa98e2SPeter Wemm ** 4774c2aa98e2SPeter Wemm ** Side Effects: 4775c2aa98e2SPeter Wemm ** Can tweak the symbol table. 4776c2aa98e2SPeter Wemm */ 477706f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 4778c2aa98e2SPeter Wemm 477906f25ae9SGregory Neil Shapiro static char * 478006f25ae9SGregory Neil Shapiro hostsignature(m, host) 4781c2aa98e2SPeter Wemm register MAILER *m; 4782c2aa98e2SPeter Wemm char *host; 4783c2aa98e2SPeter Wemm { 4784c2aa98e2SPeter Wemm register char *p; 4785c2aa98e2SPeter Wemm register STAB *s; 478606f25ae9SGregory Neil Shapiro #if NAMED_BIND 478706f25ae9SGregory Neil Shapiro char sep = ':'; 478806f25ae9SGregory Neil Shapiro char prevsep = ':'; 4789c2aa98e2SPeter Wemm int i; 4790c2aa98e2SPeter Wemm int len; 4791c2aa98e2SPeter Wemm int nmx; 479206f25ae9SGregory Neil Shapiro int hl; 4793193538b7SGregory Neil Shapiro time_t now; 4794c2aa98e2SPeter Wemm char *hp; 4795c2aa98e2SPeter Wemm char *endp; 4796c2aa98e2SPeter Wemm int oldoptions = _res.options; 4797c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 479806f25ae9SGregory Neil Shapiro u_short mxprefs[MAXMXHOSTS + 1]; 479906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 480006f25ae9SGregory Neil Shapiro 480106f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 480206f25ae9SGregory Neil Shapiro dprintf("hostsignature(%s)\n", host); 480306f25ae9SGregory Neil Shapiro 480406f25ae9SGregory Neil Shapiro /* 480506f25ae9SGregory Neil Shapiro ** If local delivery, just return a constant. 480606f25ae9SGregory Neil Shapiro */ 480706f25ae9SGregory Neil Shapiro 480806f25ae9SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags)) 480906f25ae9SGregory Neil Shapiro return "localhost"; 4810c2aa98e2SPeter Wemm 4811c2aa98e2SPeter Wemm /* 4812c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records. 4813c2aa98e2SPeter Wemm */ 4814c2aa98e2SPeter Wemm 4815c2aa98e2SPeter Wemm p = m->m_mailer; 481606f25ae9SGregory Neil Shapiro if (strcmp(p, "[IPC]") != 0 && 481706f25ae9SGregory Neil Shapiro strcmp(p, "[TCP]") != 0) 4818c2aa98e2SPeter Wemm { 4819c2aa98e2SPeter Wemm /* just an ordinary mailer */ 4820c2aa98e2SPeter Wemm return host; 4821c2aa98e2SPeter Wemm } 482206f25ae9SGregory Neil Shapiro #if NETUNIX 482306f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL && 482406f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0) 482506f25ae9SGregory Neil Shapiro { 482606f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */ 482706f25ae9SGregory Neil Shapiro return host; 482806f25ae9SGregory Neil Shapiro } 482906f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 4830c2aa98e2SPeter Wemm 4831c2aa98e2SPeter Wemm /* 4832c2aa98e2SPeter Wemm ** Look it up in the symbol table. 4833c2aa98e2SPeter Wemm */ 4834c2aa98e2SPeter Wemm 4835c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER); 4836c2aa98e2SPeter Wemm if (s->s_hostsig != NULL) 483706f25ae9SGregory Neil Shapiro { 483806f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 483906f25ae9SGregory Neil Shapiro dprintf("hostsignature(): stab(%s) found %s\n", host, 484006f25ae9SGregory Neil Shapiro s->s_hostsig); 4841c2aa98e2SPeter Wemm return s->s_hostsig; 484206f25ae9SGregory Neil Shapiro } 4843c2aa98e2SPeter Wemm 4844c2aa98e2SPeter Wemm /* 4845c2aa98e2SPeter Wemm ** Not already there -- create a signature. 4846c2aa98e2SPeter Wemm */ 4847c2aa98e2SPeter Wemm 4848c2aa98e2SPeter Wemm #if NAMED_BIND 4849c2aa98e2SPeter Wemm if (ConfigLevel < 2) 4850c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 4851c2aa98e2SPeter Wemm 4852193538b7SGregory Neil Shapiro now = curtime(); 4853c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp) 4854c2aa98e2SPeter Wemm { 485506f25ae9SGregory Neil Shapiro #if NETINET6 485606f25ae9SGregory Neil Shapiro if (*hp == '[') 485706f25ae9SGregory Neil Shapiro { 485806f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 4859c2aa98e2SPeter Wemm if (endp != NULL) 486006f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 486106f25ae9SGregory Neil Shapiro } 486206f25ae9SGregory Neil Shapiro else 486306f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 486406f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 486506f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 486606f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 486706f25ae9SGregory Neil Shapiro if (endp != NULL) 486806f25ae9SGregory Neil Shapiro { 486906f25ae9SGregory Neil Shapiro sep = *endp; 4870c2aa98e2SPeter Wemm *endp = '\0'; 487106f25ae9SGregory Neil Shapiro } 4872c2aa98e2SPeter Wemm 4873c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags)) 4874c2aa98e2SPeter Wemm { 4875c2aa98e2SPeter Wemm /* skip MX lookups */ 4876c2aa98e2SPeter Wemm nmx = 1; 4877c2aa98e2SPeter Wemm mxhosts[0] = hp; 4878c2aa98e2SPeter Wemm } 4879c2aa98e2SPeter Wemm else 4880c2aa98e2SPeter Wemm { 4881c2aa98e2SPeter Wemm auto int rcode; 4882c2aa98e2SPeter Wemm 488306f25ae9SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs, TRUE, &rcode); 4884c2aa98e2SPeter Wemm if (nmx <= 0) 4885c2aa98e2SPeter Wemm { 4886c2aa98e2SPeter Wemm register MCI *mci; 4887c2aa98e2SPeter Wemm 4888c2aa98e2SPeter Wemm /* update the connection info for this host */ 4889c2aa98e2SPeter Wemm mci = mci_get(hp, m); 4890c2aa98e2SPeter Wemm mci->mci_errno = errno; 4891c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 4892193538b7SGregory Neil Shapiro mci->mci_lastuse = now; 489306f25ae9SGregory Neil Shapiro if (rcode == EX_NOHOST) 489406f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2", 489506f25ae9SGregory Neil Shapiro "550 Host unknown"); 489606f25ae9SGregory Neil Shapiro else 4897c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL); 4898c2aa98e2SPeter Wemm 4899c2aa98e2SPeter Wemm /* use the original host name as signature */ 4900c2aa98e2SPeter Wemm nmx = 1; 4901c2aa98e2SPeter Wemm mxhosts[0] = hp; 4902c2aa98e2SPeter Wemm } 490306f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 490406f25ae9SGregory Neil Shapiro dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 490506f25ae9SGregory Neil Shapiro nmx, mxhosts[0]); 4906c2aa98e2SPeter Wemm } 4907c2aa98e2SPeter Wemm 4908c2aa98e2SPeter Wemm len = 0; 4909c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 4910c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1; 4911c2aa98e2SPeter Wemm if (s->s_hostsig != NULL) 4912c2aa98e2SPeter Wemm len += strlen(s->s_hostsig) + 1; 491306f25ae9SGregory Neil Shapiro if (len >= MAXHOSTSIGNATURE) 491406f25ae9SGregory Neil Shapiro { 491506f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 491606f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len); 491706f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE; 491806f25ae9SGregory Neil Shapiro } 4919c2aa98e2SPeter Wemm p = xalloc(len); 4920c2aa98e2SPeter Wemm if (s->s_hostsig != NULL) 4921c2aa98e2SPeter Wemm { 492206f25ae9SGregory Neil Shapiro (void) strlcpy(p, s->s_hostsig, len); 4923c2aa98e2SPeter Wemm free(s->s_hostsig); 4924c2aa98e2SPeter Wemm s->s_hostsig = p; 492506f25ae9SGregory Neil Shapiro hl = strlen(p); 492606f25ae9SGregory Neil Shapiro p += hl; 492706f25ae9SGregory Neil Shapiro *p++ = prevsep; 492806f25ae9SGregory Neil Shapiro len -= hl + 1; 4929c2aa98e2SPeter Wemm } 4930c2aa98e2SPeter Wemm else 4931c2aa98e2SPeter Wemm s->s_hostsig = p; 4932c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 4933c2aa98e2SPeter Wemm { 493406f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]); 493506f25ae9SGregory Neil Shapiro if (len - 1 < hl || len <= 1) 493606f25ae9SGregory Neil Shapiro { 493706f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */ 493806f25ae9SGregory Neil Shapiro len = -1; 493906f25ae9SGregory Neil Shapiro break; 4940c2aa98e2SPeter Wemm } 494106f25ae9SGregory Neil Shapiro if (i != 0) 494206f25ae9SGregory Neil Shapiro { 494306f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1]) 494406f25ae9SGregory Neil Shapiro *p++ = ','; 494506f25ae9SGregory Neil Shapiro else 494606f25ae9SGregory Neil Shapiro *p++ = ':'; 494706f25ae9SGregory Neil Shapiro len--; 494806f25ae9SGregory Neil Shapiro } 494906f25ae9SGregory Neil Shapiro (void) strlcpy(p, mxhosts[i], len); 495006f25ae9SGregory Neil Shapiro p += hl; 495106f25ae9SGregory Neil Shapiro len -= hl; 495206f25ae9SGregory Neil Shapiro } 495306f25ae9SGregory Neil Shapiro 495406f25ae9SGregory Neil Shapiro /* 495506f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE 495606f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts 495706f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file). 495806f25ae9SGregory Neil Shapiro */ 495906f25ae9SGregory Neil Shapiro 496006f25ae9SGregory Neil Shapiro if (len < 0) 496106f25ae9SGregory Neil Shapiro break; 4962c2aa98e2SPeter Wemm if (endp != NULL) 496306f25ae9SGregory Neil Shapiro *endp++ = sep; 496406f25ae9SGregory Neil Shapiro prevsep = sep; 4965c2aa98e2SPeter Wemm } 4966c2aa98e2SPeter Wemm makelower(s->s_hostsig); 4967c2aa98e2SPeter Wemm if (ConfigLevel < 2) 4968c2aa98e2SPeter Wemm _res.options = oldoptions; 496906f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 4970c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */ 4971c2aa98e2SPeter Wemm s->s_hostsig = host; 497206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 4973c2aa98e2SPeter Wemm if (tTd(17, 1)) 497406f25ae9SGregory Neil Shapiro dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig); 4975c2aa98e2SPeter Wemm return s->s_hostsig; 4976c2aa98e2SPeter Wemm } 497706f25ae9SGregory Neil Shapiro /* 497806f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 497906f25ae9SGregory Neil Shapiro ** 498006f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it 498106f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be 498206f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal 498306f25ae9SGregory Neil Shapiro ** MX preference values. 498406f25ae9SGregory Neil Shapiro ** 498506f25ae9SGregory Neil Shapiro ** Parameters: 498606f25ae9SGregory Neil Shapiro ** sig -- the host signature. 498706f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate. 498806f25ae9SGregory Neil Shapiro ** 498906f25ae9SGregory Neil Shapiro ** Returns: 499006f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array. 499106f25ae9SGregory Neil Shapiro ** 499206f25ae9SGregory Neil Shapiro ** Side Effects: 499306f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts. 499406f25ae9SGregory Neil Shapiro */ 499506f25ae9SGregory Neil Shapiro 499606f25ae9SGregory Neil Shapiro static int 499706f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer) 499806f25ae9SGregory Neil Shapiro char *sig; 499906f25ae9SGregory Neil Shapiro char **mxhosts; 500006f25ae9SGregory Neil Shapiro MAILER *mailer; 500106f25ae9SGregory Neil Shapiro { 500206f25ae9SGregory Neil Shapiro int nmx = 0; 500306f25ae9SGregory Neil Shapiro int curpref = 0; 500406f25ae9SGregory Neil Shapiro int i, j; 500506f25ae9SGregory Neil Shapiro char *hp, *endp; 500606f25ae9SGregory Neil Shapiro u_short prefer[MAXMXHOSTS]; 500706f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS]; 500806f25ae9SGregory Neil Shapiro 500906f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp) 501006f25ae9SGregory Neil Shapiro { 501106f25ae9SGregory Neil Shapiro char sep = ':'; 501206f25ae9SGregory Neil Shapiro 501306f25ae9SGregory Neil Shapiro #if NETINET6 501406f25ae9SGregory Neil Shapiro if (*hp == '[') 501506f25ae9SGregory Neil Shapiro { 501606f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 501706f25ae9SGregory Neil Shapiro if (endp != NULL) 501806f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 501906f25ae9SGregory Neil Shapiro } 502006f25ae9SGregory Neil Shapiro else 502106f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 502206f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 502306f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 502406f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 502506f25ae9SGregory Neil Shapiro if (endp != NULL) 502606f25ae9SGregory Neil Shapiro { 502706f25ae9SGregory Neil Shapiro sep = *endp; 502806f25ae9SGregory Neil Shapiro *endp = '\0'; 502906f25ae9SGregory Neil Shapiro } 503006f25ae9SGregory Neil Shapiro 503106f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp; 503206f25ae9SGregory Neil Shapiro prefer[nmx] = curpref; 503306f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer)) 503406f25ae9SGregory Neil Shapiro rndm[nmx] = 0; 503506f25ae9SGregory Neil Shapiro else 503606f25ae9SGregory Neil Shapiro rndm[nmx] = get_random(); 503706f25ae9SGregory Neil Shapiro 503806f25ae9SGregory Neil Shapiro if (endp != NULL) 503906f25ae9SGregory Neil Shapiro { 504006f25ae9SGregory Neil Shapiro /* 504106f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs, 504206f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that 504306f25ae9SGregory Neil Shapiro ** means the preference for the next host will be 504406f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref. 504506f25ae9SGregory Neil Shapiro */ 504606f25ae9SGregory Neil Shapiro 504706f25ae9SGregory Neil Shapiro if (sep == ':') 504806f25ae9SGregory Neil Shapiro curpref++; 504906f25ae9SGregory Neil Shapiro 505006f25ae9SGregory Neil Shapiro *endp++ = sep; 505106f25ae9SGregory Neil Shapiro } 505206f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS) 505306f25ae9SGregory Neil Shapiro break; 505406f25ae9SGregory Neil Shapiro } 505506f25ae9SGregory Neil Shapiro 505606f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */ 505706f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++) 505806f25ae9SGregory Neil Shapiro { 505906f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++) 506006f25ae9SGregory Neil Shapiro { 506106f25ae9SGregory Neil Shapiro /* 506206f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only 506306f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records 506406f25ae9SGregory Neil Shapiro */ 506506f25ae9SGregory Neil Shapiro 506606f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j]) 506706f25ae9SGregory Neil Shapiro break; 506806f25ae9SGregory Neil Shapiro 506906f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] || 507006f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 507106f25ae9SGregory Neil Shapiro { 507206f25ae9SGregory Neil Shapiro register u_short tempp; 507306f25ae9SGregory Neil Shapiro register long tempr; 507406f25ae9SGregory Neil Shapiro register char *temp1; 507506f25ae9SGregory Neil Shapiro 507606f25ae9SGregory Neil Shapiro tempp = prefer[i]; 507706f25ae9SGregory Neil Shapiro prefer[i] = prefer[j]; 507806f25ae9SGregory Neil Shapiro prefer[j] = tempp; 507906f25ae9SGregory Neil Shapiro temp1 = mxhosts[i]; 508006f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j]; 508106f25ae9SGregory Neil Shapiro mxhosts[j] = temp1; 508206f25ae9SGregory Neil Shapiro tempr = rndm[i]; 508306f25ae9SGregory Neil Shapiro rndm[i] = rndm[j]; 508406f25ae9SGregory Neil Shapiro rndm[j] = tempr; 508506f25ae9SGregory Neil Shapiro } 508606f25ae9SGregory Neil Shapiro } 508706f25ae9SGregory Neil Shapiro } 508806f25ae9SGregory Neil Shapiro return nmx; 508906f25ae9SGregory Neil Shapiro } 509006f25ae9SGregory Neil Shapiro 509106f25ae9SGregory Neil Shapiro #if SMTP 509206f25ae9SGregory Neil Shapiro # if STARTTLS 509306f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL; 509406f25ae9SGregory Neil Shapiro 509506f25ae9SGregory Neil Shapiro /* 509606f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS 509706f25ae9SGregory Neil Shapiro ** 509806f25ae9SGregory Neil Shapiro ** Parameters: 509906f25ae9SGregory Neil Shapiro ** none. 510006f25ae9SGregory Neil Shapiro ** 510106f25ae9SGregory Neil Shapiro ** Returns: 510206f25ae9SGregory Neil Shapiro ** succeeded? 510306f25ae9SGregory Neil Shapiro */ 510406f25ae9SGregory Neil Shapiro 510506f25ae9SGregory Neil Shapiro bool 510606f25ae9SGregory Neil Shapiro initclttls() 510706f25ae9SGregory Neil Shapiro { 510806f25ae9SGregory Neil Shapiro if (clt_ctx != NULL) 510906f25ae9SGregory Neil Shapiro return TRUE; /* already done */ 511006f25ae9SGregory Neil Shapiro return inittls(&clt_ctx, TLS_I_CLT, FALSE, CltCERTfile, Cltkeyfile, 511106f25ae9SGregory Neil Shapiro CACERTpath, CACERTfile, DHParams); 511206f25ae9SGregory Neil Shapiro } 511306f25ae9SGregory Neil Shapiro 511406f25ae9SGregory Neil Shapiro /* 511506f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side) 511606f25ae9SGregory Neil Shapiro ** 511706f25ae9SGregory Neil Shapiro ** Parameters: 511806f25ae9SGregory Neil Shapiro ** m -- the mailer. 511906f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 512006f25ae9SGregory Neil Shapiro ** e -- the envelope. 512106f25ae9SGregory Neil Shapiro ** 512206f25ae9SGregory Neil Shapiro ** Returns: 512306f25ae9SGregory Neil Shapiro ** success? 512406f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_ 512506f25ae9SGregory Neil Shapiro ** that denotes which stage failed.) 512606f25ae9SGregory Neil Shapiro */ 512706f25ae9SGregory Neil Shapiro 512806f25ae9SGregory Neil Shapiro static int 512906f25ae9SGregory Neil Shapiro starttls(m, mci, e) 513006f25ae9SGregory Neil Shapiro MAILER *m; 513106f25ae9SGregory Neil Shapiro MCI *mci; 513206f25ae9SGregory Neil Shapiro ENVELOPE *e; 513306f25ae9SGregory Neil Shapiro { 513406f25ae9SGregory Neil Shapiro int smtpresult; 513542e5d165SGregory Neil Shapiro int result = 0; 513642e5d165SGregory Neil Shapiro int rfd, wfd; 513706f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL; 513806f25ae9SGregory Neil Shapiro 513942e5d165SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls()) 514042e5d165SGregory Neil Shapiro return EX_TEMPFAIL; 514106f25ae9SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci); 514206f25ae9SGregory Neil Shapiro 514306f25ae9SGregory Neil Shapiro /* get the reply */ 514406f25ae9SGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, NULL, NULL); 514506f25ae9SGregory Neil Shapiro /* which timeout? XXX */ 514606f25ae9SGregory Neil Shapiro 514706f25ae9SGregory Neil Shapiro /* check return code from server */ 514806f25ae9SGregory Neil Shapiro if (smtpresult == 454) 514906f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 515006f25ae9SGregory Neil Shapiro if (smtpresult == 501) 515106f25ae9SGregory Neil Shapiro return EX_USAGE; 515206f25ae9SGregory Neil Shapiro if (smtpresult == -1) 515306f25ae9SGregory Neil Shapiro return smtpresult; 515406f25ae9SGregory Neil Shapiro if (smtpresult != 220) 515506f25ae9SGregory Neil Shapiro return EX_PROTOCOL; 515606f25ae9SGregory Neil Shapiro 515706f25ae9SGregory Neil Shapiro if (LogLevel > 13) 515806f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "TLS: start client"); 515906f25ae9SGregory Neil Shapiro 516006f25ae9SGregory Neil Shapiro /* start connection */ 516106f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 516206f25ae9SGregory Neil Shapiro { 516306f25ae9SGregory Neil Shapiro if (LogLevel > 5) 516406f25ae9SGregory Neil Shapiro { 516506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 516606f25ae9SGregory Neil Shapiro "TLS: error: client: SSL_new failed"); 516706f25ae9SGregory Neil Shapiro if (LogLevel > 9) 516806f25ae9SGregory Neil Shapiro tlslogerr(); 516906f25ae9SGregory Neil Shapiro } 517006f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 517106f25ae9SGregory Neil Shapiro } 517206f25ae9SGregory Neil Shapiro 517342e5d165SGregory Neil Shapiro rfd = fileno(mci->mci_in); 517442e5d165SGregory Neil Shapiro wfd = fileno(mci->mci_out); 517542e5d165SGregory Neil Shapiro 517606f25ae9SGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */ 517742e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 || 517842e5d165SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) <= 0 || 517942e5d165SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) <= 0) 518006f25ae9SGregory Neil Shapiro { 518106f25ae9SGregory Neil Shapiro if (LogLevel > 5) 518206f25ae9SGregory Neil Shapiro { 518306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 518406f25ae9SGregory Neil Shapiro "TLS: error: SSL_set_xfd failed=%d", result); 518506f25ae9SGregory Neil Shapiro if (LogLevel > 9) 518606f25ae9SGregory Neil Shapiro tlslogerr(); 518706f25ae9SGregory Neil Shapiro } 518806f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 518906f25ae9SGregory Neil Shapiro } 519006f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl); 519106f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0) 519206f25ae9SGregory Neil Shapiro { 519306f25ae9SGregory Neil Shapiro int i; 519406f25ae9SGregory Neil Shapiro 519506f25ae9SGregory Neil Shapiro /* what to do in this case? */ 519606f25ae9SGregory Neil Shapiro i = SSL_get_error(clt_ssl, result); 519706f25ae9SGregory Neil Shapiro if (LogLevel > 5) 519806f25ae9SGregory Neil Shapiro { 519906f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 520006f25ae9SGregory Neil Shapiro "TLS: error: SSL_connect failed=%d (%d)", 520106f25ae9SGregory Neil Shapiro result, i); 520206f25ae9SGregory Neil Shapiro if (LogLevel > 9) 520306f25ae9SGregory Neil Shapiro tlslogerr(); 520406f25ae9SGregory Neil Shapiro } 520506f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 520606f25ae9SGregory Neil Shapiro clt_ssl = NULL; 520706f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 520806f25ae9SGregory Neil Shapiro } 520906f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl; 5210193538b7SGregory Neil Shapiro result = tls_get_info(clt_ssl, e, FALSE, mci->mci_host, TRUE); 521106f25ae9SGregory Neil Shapiro 521206f25ae9SGregory Neil Shapiro /* switch to use SSL... */ 521306f25ae9SGregory Neil Shapiro #if SFIO 521406f25ae9SGregory Neil Shapiro if (sfdctls(mci->mci_in, mci->mci_out, mci->mci_ssl) == 0) 521506f25ae9SGregory Neil Shapiro return EX_OK; 521606f25ae9SGregory Neil Shapiro #else /* SFIO */ 521706f25ae9SGregory Neil Shapiro # if _FFR_TLS_TOREK 521806f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 521906f25ae9SGregory Neil Shapiro return EX_OK; 522006f25ae9SGregory Neil Shapiro # endif /* _FFR_TLS_TOREK */ 522106f25ae9SGregory Neil Shapiro #endif /* SFIO */ 522206f25ae9SGregory Neil Shapiro 522306f25ae9SGregory Neil Shapiro /* failure */ 522406f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 522506f25ae9SGregory Neil Shapiro clt_ssl = NULL; 522606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 522706f25ae9SGregory Neil Shapiro } 522806f25ae9SGregory Neil Shapiro 522906f25ae9SGregory Neil Shapiro /* 523006f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side) 523106f25ae9SGregory Neil Shapiro ** 523206f25ae9SGregory Neil Shapiro ** Parameters: 523306f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 523406f25ae9SGregory Neil Shapiro ** 523506f25ae9SGregory Neil Shapiro ** Returns: 523606f25ae9SGregory Neil Shapiro ** success? 523706f25ae9SGregory Neil Shapiro */ 523806f25ae9SGregory Neil Shapiro int 523906f25ae9SGregory Neil Shapiro endtlsclt(mci) 524006f25ae9SGregory Neil Shapiro MCI *mci; 524106f25ae9SGregory Neil Shapiro { 524206f25ae9SGregory Neil Shapiro int r; 524306f25ae9SGregory Neil Shapiro 524406f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags)) 524506f25ae9SGregory Neil Shapiro return EX_OK; 524606f25ae9SGregory Neil Shapiro r = endtls(mci->mci_ssl, "client"); 524706f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 524806f25ae9SGregory Neil Shapiro return r; 524906f25ae9SGregory Neil Shapiro } 525006f25ae9SGregory Neil Shapiro /* 525106f25ae9SGregory Neil Shapiro ** ENDTLS -- shutdown secure connection 525206f25ae9SGregory Neil Shapiro ** 525306f25ae9SGregory Neil Shapiro ** Parameters: 525406f25ae9SGregory Neil Shapiro ** ssl -- SSL connection information. 525506f25ae9SGregory Neil Shapiro ** side -- srv/clt (for logging). 525606f25ae9SGregory Neil Shapiro ** 525706f25ae9SGregory Neil Shapiro ** Returns: 525806f25ae9SGregory Neil Shapiro ** success? 525906f25ae9SGregory Neil Shapiro */ 526006f25ae9SGregory Neil Shapiro 526106f25ae9SGregory Neil Shapiro int 526206f25ae9SGregory Neil Shapiro endtls(ssl, side) 526306f25ae9SGregory Neil Shapiro SSL *ssl; 526406f25ae9SGregory Neil Shapiro char *side; 526506f25ae9SGregory Neil Shapiro { 5266602a2b1bSGregory Neil Shapiro int ret = EX_OK; 5267602a2b1bSGregory Neil Shapiro 526806f25ae9SGregory Neil Shapiro if (ssl != NULL) 526906f25ae9SGregory Neil Shapiro { 527006f25ae9SGregory Neil Shapiro int r; 527106f25ae9SGregory Neil Shapiro 527206f25ae9SGregory Neil Shapiro if ((r = SSL_shutdown(ssl)) < 0) 527306f25ae9SGregory Neil Shapiro { 527406f25ae9SGregory Neil Shapiro if (LogLevel > 11) 527506f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 527606f25ae9SGregory Neil Shapiro "SSL_shutdown %s failed: %d", 527706f25ae9SGregory Neil Shapiro side, r); 5278602a2b1bSGregory Neil Shapiro ret = EX_SOFTWARE; 527906f25ae9SGregory Neil Shapiro } 528006f25ae9SGregory Neil Shapiro else if (r == 0) 528106f25ae9SGregory Neil Shapiro { 528206f25ae9SGregory Neil Shapiro if (LogLevel > 13) 528306f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 528406f25ae9SGregory Neil Shapiro "SSL_shutdown %s not done", 528506f25ae9SGregory Neil Shapiro side); 5286602a2b1bSGregory Neil Shapiro ret = EX_SOFTWARE; 528706f25ae9SGregory Neil Shapiro } 528806f25ae9SGregory Neil Shapiro SSL_free(ssl); 528906f25ae9SGregory Neil Shapiro ssl = NULL; 529006f25ae9SGregory Neil Shapiro } 5291602a2b1bSGregory Neil Shapiro return ret; 529206f25ae9SGregory Neil Shapiro } 529306f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 529406f25ae9SGregory Neil Shapiro #endif /* SMTP */ 5295