1c2aa98e2SPeter Wemm /* 240266059SGregory Neil Shapiro * Copyright (c) 1998-2002 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 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 1540266059SGregory Neil Shapiro #include <sys/time.h> 1606f25ae9SGregory Neil Shapiro 1740266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: deliver.c,v 8.928 2002/01/10 03:23:29 gshapiro Exp $") 18c2aa98e2SPeter Wemm 19c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT 20c2aa98e2SPeter Wemm # include <login_cap.h> 2106f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 2206f25ae9SGregory Neil Shapiro 2340266059SGregory Neil Shapiro #if STARTTLS || SASL 2406f25ae9SGregory Neil Shapiro # include "sfsasl.h" 2540266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */ 2606f25ae9SGregory Neil Shapiro 2740266059SGregory Neil Shapiro void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool)); 2806f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *)); 2906f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 3006f25ae9SGregory Neil Shapiro static void mailfiletimeout __P((void)); 3106f25ae9SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *)); 3206f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int)); 3340266059SGregory Neil Shapiro extern MCI *mci_new __P((SM_RPOOL_T *)); 3440266059SGregory Neil Shapiro static int coloncmp __P((const char *, const char *)); 35c2aa98e2SPeter Wemm 3606f25ae9SGregory Neil Shapiro #if STARTTLS 3706f25ae9SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *)); 3840266059SGregory Neil Shapiro static int endtlsclt __P((MCI *)); 3906f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 4040266059SGregory Neil Shapiro # if STARTTLS || SASL 4140266059SGregory Neil Shapiro static bool iscltflgset __P((ENVELOPE *, int)); 4240266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 43c2aa98e2SPeter Wemm 44c2aa98e2SPeter Wemm /* 45c2aa98e2SPeter Wemm ** SENDALL -- actually send all the messages. 46c2aa98e2SPeter Wemm ** 47c2aa98e2SPeter Wemm ** Parameters: 48c2aa98e2SPeter Wemm ** e -- the envelope to send. 49c2aa98e2SPeter Wemm ** mode -- the delivery mode to use. If SM_DEFAULT, use 50c2aa98e2SPeter Wemm ** the current e->e_sendmode. 51c2aa98e2SPeter Wemm ** 52c2aa98e2SPeter Wemm ** Returns: 53c2aa98e2SPeter Wemm ** none. 54c2aa98e2SPeter Wemm ** 55c2aa98e2SPeter Wemm ** Side Effects: 56c2aa98e2SPeter Wemm ** Scans the send lists and sends everything it finds. 57c2aa98e2SPeter Wemm ** Delivers any appropriate error messages. 58c2aa98e2SPeter Wemm ** If we are running in a non-interactive mode, takes the 59c2aa98e2SPeter Wemm ** appropriate action. 60c2aa98e2SPeter Wemm */ 61c2aa98e2SPeter Wemm 62c2aa98e2SPeter Wemm void 63c2aa98e2SPeter Wemm sendall(e, mode) 64c2aa98e2SPeter Wemm ENVELOPE *e; 65c2aa98e2SPeter Wemm int mode; 66c2aa98e2SPeter Wemm { 67c2aa98e2SPeter Wemm register ADDRESS *q; 68c2aa98e2SPeter Wemm char *owner; 69c2aa98e2SPeter Wemm int otherowners; 7006f25ae9SGregory Neil Shapiro int save_errno; 71c2aa98e2SPeter Wemm register ENVELOPE *ee; 72c2aa98e2SPeter Wemm ENVELOPE *splitenv = NULL; 73c2aa98e2SPeter Wemm int oldverbose = Verbose; 7440266059SGregory Neil Shapiro bool somedeliveries = false, expensive = false; 75c2aa98e2SPeter Wemm pid_t pid; 76c2aa98e2SPeter Wemm 77c2aa98e2SPeter Wemm /* 78c2aa98e2SPeter Wemm ** If this message is to be discarded, don't bother sending 79c2aa98e2SPeter Wemm ** the message at all. 80c2aa98e2SPeter Wemm */ 81c2aa98e2SPeter Wemm 82c2aa98e2SPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 83c2aa98e2SPeter Wemm { 84c2aa98e2SPeter Wemm if (tTd(13, 1)) 8540266059SGregory Neil Shapiro sm_dprintf("sendall: discarding id %s\n", e->e_id); 86c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 8740266059SGregory Neil Shapiro if (LogLevel > 9) 8840266059SGregory Neil Shapiro logundelrcpts(e, "discarded", 9, true); 8940266059SGregory Neil Shapiro else if (LogLevel > 4) 90c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "discarded"); 9140266059SGregory Neil Shapiro markstats(e, NULL, STATS_REJECT); 92c2aa98e2SPeter Wemm return; 93c2aa98e2SPeter Wemm } 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm /* 96c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 97c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 98c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 99c2aa98e2SPeter Wemm ** addresses to be sent. 100c2aa98e2SPeter Wemm */ 101c2aa98e2SPeter Wemm 102c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 103c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 104c2aa98e2SPeter Wemm { 105c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 106c2aa98e2SPeter Wemm return; 107c2aa98e2SPeter Wemm } 108c2aa98e2SPeter Wemm 109c2aa98e2SPeter Wemm /* determine actual delivery mode */ 110c2aa98e2SPeter Wemm if (mode == SM_DEFAULT) 111c2aa98e2SPeter Wemm { 112c2aa98e2SPeter Wemm mode = e->e_sendmode; 113c2aa98e2SPeter Wemm if (mode != SM_VERIFY && mode != SM_DEFER && 114c2aa98e2SPeter Wemm shouldqueue(e->e_msgpriority, e->e_ctime)) 115c2aa98e2SPeter Wemm mode = SM_QUEUE; 116c2aa98e2SPeter Wemm } 117c2aa98e2SPeter Wemm 118c2aa98e2SPeter Wemm if (tTd(13, 1)) 119c2aa98e2SPeter Wemm { 12040266059SGregory Neil Shapiro sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ", 121c2aa98e2SPeter Wemm mode, e->e_id); 12240266059SGregory Neil Shapiro printaddr(&e->e_from, false); 12340266059SGregory Neil Shapiro sm_dprintf("\te_flags = "); 124c2aa98e2SPeter Wemm printenvflags(e); 12540266059SGregory Neil Shapiro sm_dprintf("sendqueue:\n"); 12640266059SGregory Neil Shapiro printaddr(e->e_sendqueue, true); 127c2aa98e2SPeter Wemm } 128c2aa98e2SPeter Wemm 129c2aa98e2SPeter Wemm /* 130c2aa98e2SPeter Wemm ** Do any preprocessing necessary for the mode we are running. 131c2aa98e2SPeter Wemm ** Check to make sure the hop count is reasonable. 132c2aa98e2SPeter Wemm ** Delete sends to the sender in mailing lists. 133c2aa98e2SPeter Wemm */ 134c2aa98e2SPeter Wemm 135c2aa98e2SPeter Wemm CurEnv = e; 136c2aa98e2SPeter Wemm if (tTd(62, 1)) 137c2aa98e2SPeter Wemm checkfds(NULL); 138c2aa98e2SPeter Wemm 139c2aa98e2SPeter Wemm if (e->e_hopcount > MaxHopCount) 140c2aa98e2SPeter Wemm { 1418774250cSGregory Neil Shapiro char *recip; 1428774250cSGregory Neil Shapiro 1438774250cSGregory Neil Shapiro if (e->e_sendqueue != NULL && 1448774250cSGregory Neil Shapiro e->e_sendqueue->q_paddr != NULL) 1458774250cSGregory Neil Shapiro recip = e->e_sendqueue->q_paddr; 1468774250cSGregory Neil Shapiro else 1478774250cSGregory Neil Shapiro recip = "(nobody)"; 1488774250cSGregory Neil Shapiro 149c2aa98e2SPeter Wemm errno = 0; 15040266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), false); 151c2aa98e2SPeter Wemm e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 15206f25ae9SGregory Neil Shapiro ExitStat = EX_UNAVAILABLE; 1538774250cSGregory Neil Shapiro syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s", 154c2aa98e2SPeter Wemm e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 155c2aa98e2SPeter Wemm RealHostName == NULL ? "localhost" : RealHostName, 1568774250cSGregory Neil Shapiro recip); 15706f25ae9SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15806f25ae9SGregory Neil Shapiro { 15906f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 16006f25ae9SGregory Neil Shapiro continue; 16106f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 16206f25ae9SGregory Neil Shapiro q->q_status = "5.4.6"; 1638774250cSGregory Neil Shapiro q->q_rstatus = "554 5.4.6 Too many hops"; 16406f25ae9SGregory Neil Shapiro } 165c2aa98e2SPeter Wemm return; 166c2aa98e2SPeter Wemm } 167c2aa98e2SPeter Wemm 168c2aa98e2SPeter Wemm /* 169c2aa98e2SPeter Wemm ** Do sender deletion. 170c2aa98e2SPeter Wemm ** 17106f25ae9SGregory Neil Shapiro ** If the sender should be queued up, skip this. 172c2aa98e2SPeter Wemm ** This can happen if the name server is hosed when you 173c2aa98e2SPeter Wemm ** are trying to send mail. The result is that the sender 174c2aa98e2SPeter Wemm ** is instantiated in the queue as a recipient. 175c2aa98e2SPeter Wemm */ 176c2aa98e2SPeter Wemm 177c2aa98e2SPeter Wemm if (!bitset(EF_METOO, e->e_flags) && 17806f25ae9SGregory Neil Shapiro !QS_IS_QUEUEUP(e->e_from.q_state)) 179c2aa98e2SPeter Wemm { 180c2aa98e2SPeter Wemm if (tTd(13, 5)) 181c2aa98e2SPeter Wemm { 18240266059SGregory Neil Shapiro sm_dprintf("sendall: QS_SENDER "); 18340266059SGregory Neil Shapiro printaddr(&e->e_from, false); 184c2aa98e2SPeter Wemm } 18506f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 186c2aa98e2SPeter Wemm (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 187c2aa98e2SPeter Wemm } 188c2aa98e2SPeter Wemm 189c2aa98e2SPeter Wemm /* 190c2aa98e2SPeter Wemm ** Handle alias owners. 191c2aa98e2SPeter Wemm ** 192c2aa98e2SPeter Wemm ** We scan up the q_alias chain looking for owners. 193c2aa98e2SPeter Wemm ** We discard owners that are the same as the return path. 194c2aa98e2SPeter Wemm */ 195c2aa98e2SPeter Wemm 196c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 197c2aa98e2SPeter Wemm { 198c2aa98e2SPeter Wemm register struct address *a; 199c2aa98e2SPeter Wemm 200c2aa98e2SPeter Wemm for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 201c2aa98e2SPeter Wemm continue; 202c2aa98e2SPeter Wemm if (a != NULL) 203c2aa98e2SPeter Wemm q->q_owner = a->q_owner; 204c2aa98e2SPeter Wemm 205c2aa98e2SPeter Wemm if (q->q_owner != NULL && 20606f25ae9SGregory Neil Shapiro !QS_IS_DEAD(q->q_state) && 207c2aa98e2SPeter Wemm strcmp(q->q_owner, e->e_from.q_paddr) == 0) 208c2aa98e2SPeter Wemm q->q_owner = NULL; 209c2aa98e2SPeter Wemm } 210c2aa98e2SPeter Wemm 211c2aa98e2SPeter Wemm if (tTd(13, 25)) 212c2aa98e2SPeter Wemm { 21340266059SGregory Neil Shapiro sm_dprintf("\nAfter first owner pass, sendq =\n"); 21440266059SGregory Neil Shapiro printaddr(e->e_sendqueue, true); 215c2aa98e2SPeter Wemm } 216c2aa98e2SPeter Wemm 217c2aa98e2SPeter Wemm owner = ""; 218c2aa98e2SPeter Wemm otherowners = 1; 219c2aa98e2SPeter Wemm while (owner != NULL && otherowners > 0) 220c2aa98e2SPeter Wemm { 221c2aa98e2SPeter Wemm if (tTd(13, 28)) 22240266059SGregory Neil Shapiro sm_dprintf("owner = \"%s\", otherowners = %d\n", 223c2aa98e2SPeter Wemm owner, otherowners); 224c2aa98e2SPeter Wemm owner = NULL; 225c2aa98e2SPeter Wemm otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; 226c2aa98e2SPeter Wemm 227c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 228c2aa98e2SPeter Wemm { 229c2aa98e2SPeter Wemm if (tTd(13, 30)) 230c2aa98e2SPeter Wemm { 23140266059SGregory Neil Shapiro sm_dprintf("Checking "); 23240266059SGregory Neil Shapiro printaddr(q, false); 233c2aa98e2SPeter Wemm } 23406f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 235c2aa98e2SPeter Wemm { 236c2aa98e2SPeter Wemm if (tTd(13, 30)) 23740266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_DEAD\n"); 238c2aa98e2SPeter Wemm continue; 239c2aa98e2SPeter Wemm } 240c2aa98e2SPeter Wemm if (tTd(13, 29) && !tTd(13, 30)) 241c2aa98e2SPeter Wemm { 24240266059SGregory Neil Shapiro sm_dprintf("Checking "); 24340266059SGregory Neil Shapiro printaddr(q, false); 244c2aa98e2SPeter Wemm } 245c2aa98e2SPeter Wemm 246c2aa98e2SPeter Wemm if (q->q_owner != NULL) 247c2aa98e2SPeter Wemm { 248c2aa98e2SPeter Wemm if (owner == NULL) 249c2aa98e2SPeter Wemm { 250c2aa98e2SPeter Wemm if (tTd(13, 40)) 25140266059SGregory Neil Shapiro sm_dprintf(" ... First owner = \"%s\"\n", 252c2aa98e2SPeter Wemm q->q_owner); 253c2aa98e2SPeter Wemm owner = q->q_owner; 254c2aa98e2SPeter Wemm } 255c2aa98e2SPeter Wemm else if (owner != q->q_owner) 256c2aa98e2SPeter Wemm { 257c2aa98e2SPeter Wemm if (strcmp(owner, q->q_owner) == 0) 258c2aa98e2SPeter Wemm { 259c2aa98e2SPeter Wemm if (tTd(13, 40)) 26040266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 261c2aa98e2SPeter Wemm owner); 262c2aa98e2SPeter Wemm 263c2aa98e2SPeter Wemm /* make future comparisons cheap */ 264c2aa98e2SPeter Wemm q->q_owner = owner; 265c2aa98e2SPeter Wemm } 266c2aa98e2SPeter Wemm else 267c2aa98e2SPeter Wemm { 268c2aa98e2SPeter Wemm if (tTd(13, 40)) 26940266059SGregory Neil Shapiro sm_dprintf(" ... Another owner \"%s\"\n", 270c2aa98e2SPeter Wemm q->q_owner); 271c2aa98e2SPeter Wemm otherowners++; 272c2aa98e2SPeter Wemm } 273c2aa98e2SPeter Wemm owner = q->q_owner; 274c2aa98e2SPeter Wemm } 275c2aa98e2SPeter Wemm else if (tTd(13, 40)) 27640266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 277c2aa98e2SPeter Wemm owner); 278c2aa98e2SPeter Wemm } 279c2aa98e2SPeter Wemm else 280c2aa98e2SPeter Wemm { 281c2aa98e2SPeter Wemm if (tTd(13, 40)) 28240266059SGregory Neil Shapiro sm_dprintf(" ... Null owner\n"); 283c2aa98e2SPeter Wemm otherowners++; 284c2aa98e2SPeter Wemm } 285c2aa98e2SPeter Wemm 28606f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(q->q_state)) 28706f25ae9SGregory Neil Shapiro { 28806f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 28940266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_BADADDR\n"); 29006f25ae9SGregory Neil Shapiro continue; 29106f25ae9SGregory Neil Shapiro } 29206f25ae9SGregory Neil Shapiro 29306f25ae9SGregory Neil Shapiro if (QS_IS_QUEUEUP(q->q_state)) 29406f25ae9SGregory Neil Shapiro { 29506f25ae9SGregory Neil Shapiro MAILER *m = q->q_mailer; 29606f25ae9SGregory Neil Shapiro 29706f25ae9SGregory Neil Shapiro /* 29806f25ae9SGregory Neil Shapiro ** If we have temporary address failures 29906f25ae9SGregory Neil Shapiro ** (e.g., dns failure) and a fallback MX is 30006f25ae9SGregory Neil Shapiro ** set, send directly to the fallback MX host. 30106f25ae9SGregory Neil Shapiro */ 30206f25ae9SGregory Neil Shapiro 30306f25ae9SGregory Neil Shapiro if (FallBackMX != NULL && 30406f25ae9SGregory Neil Shapiro !wordinclass(FallBackMX, 'w') && 30506f25ae9SGregory Neil Shapiro mode != SM_VERIFY && 30640266059SGregory Neil Shapiro !bitnset(M_NOMX, m->m_flags) && 30740266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") == 0 && 30806f25ae9SGregory Neil Shapiro m->m_argv[0] != NULL && 30940266059SGregory Neil Shapiro strcmp(m->m_argv[0], "TCP") == 0) 31006f25ae9SGregory Neil Shapiro { 31106f25ae9SGregory Neil Shapiro int len; 31206f25ae9SGregory Neil Shapiro char *p; 31306f25ae9SGregory Neil Shapiro 31406f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 31540266059SGregory Neil Shapiro sm_dprintf(" ... FallBackMX\n"); 31606f25ae9SGregory Neil Shapiro 31740266059SGregory Neil Shapiro len = strlen(FallBackMX) + 1; 31840266059SGregory Neil Shapiro p = sm_rpool_malloc_x(e->e_rpool, len); 31940266059SGregory Neil Shapiro (void) sm_strlcpy(p, FallBackMX, len); 32006f25ae9SGregory Neil Shapiro q->q_state = QS_OK; 32106f25ae9SGregory Neil Shapiro q->q_host = p; 32206f25ae9SGregory Neil Shapiro } 32306f25ae9SGregory Neil Shapiro else 32406f25ae9SGregory Neil Shapiro { 32506f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 32640266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_QUEUEUP\n"); 32706f25ae9SGregory Neil Shapiro continue; 32806f25ae9SGregory Neil Shapiro } 32906f25ae9SGregory Neil Shapiro } 33006f25ae9SGregory Neil Shapiro 331c2aa98e2SPeter Wemm /* 332c2aa98e2SPeter Wemm ** If this mailer is expensive, and if we don't 333c2aa98e2SPeter Wemm ** want to make connections now, just mark these 334c2aa98e2SPeter Wemm ** addresses and return. This is useful if we 335c2aa98e2SPeter Wemm ** want to batch connections to reduce load. This 336c2aa98e2SPeter Wemm ** will cause the messages to be queued up, and a 337c2aa98e2SPeter Wemm ** daemon will come along to send the messages later. 338c2aa98e2SPeter Wemm */ 339c2aa98e2SPeter Wemm 340c2aa98e2SPeter Wemm if (NoConnect && !Verbose && 341c2aa98e2SPeter Wemm bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 342c2aa98e2SPeter Wemm { 343c2aa98e2SPeter Wemm if (tTd(13, 30)) 34440266059SGregory Neil Shapiro sm_dprintf(" ... expensive\n"); 34506f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 34640266059SGregory Neil Shapiro expensive = true; 34706f25ae9SGregory Neil Shapiro } 34806f25ae9SGregory Neil Shapiro else if (bitnset(M_HOLD, q->q_mailer->m_flags) && 34906f25ae9SGregory Neil Shapiro QueueLimitId == NULL && 35006f25ae9SGregory Neil Shapiro QueueLimitSender == NULL && 35106f25ae9SGregory Neil Shapiro QueueLimitRecipient == NULL) 35206f25ae9SGregory Neil Shapiro { 35306f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 35440266059SGregory Neil Shapiro sm_dprintf(" ... hold\n"); 35506f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 35640266059SGregory Neil Shapiro expensive = true; 357c2aa98e2SPeter Wemm } 35840266059SGregory Neil Shapiro #if _FFR_QUARANTINE 35940266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE && 36040266059SGregory Neil Shapiro e->e_quarmsg != NULL) 36140266059SGregory Neil Shapiro { 36240266059SGregory Neil Shapiro if (tTd(13, 30)) 36340266059SGregory Neil Shapiro sm_dprintf(" ... quarantine: %s\n", 36440266059SGregory Neil Shapiro e->e_quarmsg); 36540266059SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 36640266059SGregory Neil Shapiro expensive = true; 36740266059SGregory Neil Shapiro } 36840266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 369c2aa98e2SPeter Wemm else 370c2aa98e2SPeter Wemm { 371c2aa98e2SPeter Wemm if (tTd(13, 30)) 37240266059SGregory Neil Shapiro sm_dprintf(" ... deliverable\n"); 37340266059SGregory Neil Shapiro somedeliveries = true; 374c2aa98e2SPeter Wemm } 375c2aa98e2SPeter Wemm } 376c2aa98e2SPeter Wemm 377c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0) 378c2aa98e2SPeter Wemm { 379c2aa98e2SPeter Wemm /* 380c2aa98e2SPeter Wemm ** Split this envelope into two. 381c2aa98e2SPeter Wemm */ 382c2aa98e2SPeter Wemm 38340266059SGregory Neil Shapiro ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, 38440266059SGregory Neil Shapiro sizeof *ee); 38540266059SGregory Neil Shapiro STRUCTCOPY(*e, *ee); 38606f25ae9SGregory Neil Shapiro ee->e_message = NULL; 387c2aa98e2SPeter Wemm ee->e_id = NULL; 38806f25ae9SGregory Neil Shapiro assign_queueid(ee); 389c2aa98e2SPeter Wemm 390c2aa98e2SPeter Wemm if (tTd(13, 1)) 39140266059SGregory Neil Shapiro sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 39240266059SGregory Neil Shapiro e->e_id, ee->e_id, owner, 39340266059SGregory Neil Shapiro otherowners); 394c2aa98e2SPeter Wemm 39540266059SGregory Neil Shapiro ee->e_header = copyheader(e->e_header, ee->e_rpool); 39640266059SGregory Neil Shapiro ee->e_sendqueue = copyqueue(e->e_sendqueue, 39740266059SGregory Neil Shapiro ee->e_rpool); 39840266059SGregory Neil Shapiro ee->e_errorqueue = copyqueue(e->e_errorqueue, 39940266059SGregory Neil Shapiro ee->e_rpool); 400c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 401c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT; 40240266059SGregory Neil Shapiro setsender(owner, ee, NULL, '\0', true); 403c2aa98e2SPeter Wemm if (tTd(13, 5)) 404c2aa98e2SPeter Wemm { 40540266059SGregory Neil Shapiro sm_dprintf("sendall(split): QS_SENDER "); 40640266059SGregory Neil Shapiro printaddr(&ee->e_from, false); 407c2aa98e2SPeter Wemm } 40806f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER; 409c2aa98e2SPeter Wemm ee->e_dfp = NULL; 41006f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL; 411c2aa98e2SPeter Wemm ee->e_xfp = NULL; 41240266059SGregory Neil Shapiro ee->e_qgrp = e->e_qgrp; 41340266059SGregory Neil Shapiro ee->e_qdir = e->e_qdir; 414c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL; 415c2aa98e2SPeter Wemm ee->e_sibling = splitenv; 41606f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL; 41740266059SGregory Neil Shapiro #if _FFR_QUARANTINE 41840266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 41940266059SGregory Neil Shapiro ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 42040266059SGregory Neil Shapiro e->e_quarmsg); 42140266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 422c2aa98e2SPeter Wemm splitenv = ee; 423c2aa98e2SPeter Wemm 424c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 425c2aa98e2SPeter Wemm { 426c2aa98e2SPeter Wemm if (q->q_owner == owner) 427c2aa98e2SPeter Wemm { 42806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 429c2aa98e2SPeter Wemm if (tTd(13, 6)) 43040266059SGregory Neil Shapiro sm_dprintf("\t... stripping %s from original envelope\n", 431c2aa98e2SPeter Wemm q->q_paddr); 432c2aa98e2SPeter Wemm } 433c2aa98e2SPeter Wemm } 434c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 435c2aa98e2SPeter Wemm { 436c2aa98e2SPeter Wemm if (q->q_owner != owner) 437c2aa98e2SPeter Wemm { 43806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 439c2aa98e2SPeter Wemm if (tTd(13, 6)) 44040266059SGregory Neil Shapiro sm_dprintf("\t... dropping %s from cloned envelope\n", 441c2aa98e2SPeter Wemm q->q_paddr); 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm else 444c2aa98e2SPeter Wemm { 445c2aa98e2SPeter Wemm /* clear DSN parameters */ 446c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 447c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 448c2aa98e2SPeter Wemm if (tTd(13, 6)) 44940266059SGregory Neil Shapiro sm_dprintf("\t... moving %s to cloned envelope\n", 450c2aa98e2SPeter Wemm q->q_paddr); 451c2aa98e2SPeter Wemm } 452c2aa98e2SPeter Wemm } 453c2aa98e2SPeter Wemm 454c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 45540266059SGregory Neil Shapiro dup_queue_file(e, ee, DATAFL_LETTER); 45606f25ae9SGregory Neil Shapiro 45706f25ae9SGregory Neil Shapiro /* 45806f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent 45906f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while 46006f25ae9SGregory Neil Shapiro ** processing the recipients (done before the 46106f25ae9SGregory Neil Shapiro ** envelope splitting). 46206f25ae9SGregory Neil Shapiro */ 46306f25ae9SGregory Neil Shapiro 46406f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL) 46540266059SGregory Neil Shapiro ee->e_xfp = sm_io_dup(e->e_xfp); 46606f25ae9SGregory Neil Shapiro 46706f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */ 46806f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL) 469c2aa98e2SPeter Wemm openxscript(ee); 47006f25ae9SGregory Neil Shapiro 471065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4) 47240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 47340266059SGregory Neil Shapiro "%s: clone: owner=%s", 47440266059SGregory Neil Shapiro ee->e_id, owner); 475c2aa98e2SPeter Wemm } 476c2aa98e2SPeter Wemm } 477c2aa98e2SPeter Wemm 478c2aa98e2SPeter Wemm if (owner != NULL) 479c2aa98e2SPeter Wemm { 48040266059SGregory Neil Shapiro setsender(owner, e, NULL, '\0', true); 481c2aa98e2SPeter Wemm if (tTd(13, 5)) 482c2aa98e2SPeter Wemm { 48340266059SGregory Neil Shapiro sm_dprintf("sendall(owner): QS_SENDER "); 48440266059SGregory Neil Shapiro printaddr(&e->e_from, false); 485c2aa98e2SPeter Wemm } 48606f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 487c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL; 488c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT; 489c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 490c2aa98e2SPeter Wemm } 491c2aa98e2SPeter Wemm 492c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */ 49340266059SGregory Neil Shapiro if (!somedeliveries && !WILL_BE_QUEUED(mode) && 494c2aa98e2SPeter Wemm mode != SM_VERIFY) 495c2aa98e2SPeter Wemm { 49640266059SGregory Neil Shapiro time_t now; 497193538b7SGregory Neil Shapiro 498c2aa98e2SPeter Wemm if (tTd(13, 29)) 49940266059SGregory Neil Shapiro sm_dprintf("No deliveries: auto-queuing\n"); 500c2aa98e2SPeter Wemm mode = SM_QUEUE; 50140266059SGregory Neil Shapiro now = curtime(); 502c2aa98e2SPeter Wemm 503c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */ 504193538b7SGregory Neil Shapiro e->e_dtime = now; 505c2aa98e2SPeter Wemm if (!expensive) 506c2aa98e2SPeter Wemm e->e_ntries++; 507c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 508c2aa98e2SPeter Wemm { 509193538b7SGregory Neil Shapiro ee->e_dtime = now; 510c2aa98e2SPeter Wemm if (!expensive) 511c2aa98e2SPeter Wemm ee->e_ntries++; 512c2aa98e2SPeter Wemm } 513c2aa98e2SPeter Wemm } 514c2aa98e2SPeter Wemm 51540266059SGregory Neil Shapiro if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || 51640266059SGregory Neil Shapiro (mode != SM_VERIFY && SuperSafe == SAFE_REALLY)) && 517c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 518c2aa98e2SPeter Wemm { 51940266059SGregory Neil Shapiro bool msync; 52040266059SGregory Neil Shapiro 52142e5d165SGregory Neil Shapiro /* 52242e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue. 52342e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes. 52442e5d165SGregory Neil Shapiro ** If the original were done first, we may lose 52542e5d165SGregory Neil Shapiro ** recipients. 52642e5d165SGregory Neil Shapiro */ 52742e5d165SGregory Neil Shapiro 52840266059SGregory Neil Shapiro #if !HASFLOCK 52940266059SGregory Neil Shapiro msync = false; 53040266059SGregory Neil Shapiro #else /* !HASFLOCK */ 53140266059SGregory Neil Shapiro msync = mode == SM_FORK; 53240266059SGregory Neil Shapiro #endif /* !HASFLOCK */ 53340266059SGregory Neil Shapiro 534c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 53540266059SGregory Neil Shapiro queueup(ee, WILL_BE_QUEUED(mode), msync); 53640266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), msync); 537c2aa98e2SPeter Wemm } 538c2aa98e2SPeter Wemm 539c2aa98e2SPeter Wemm if (tTd(62, 10)) 540c2aa98e2SPeter Wemm checkfds("after envelope splitting"); 541c2aa98e2SPeter Wemm 542c2aa98e2SPeter Wemm /* 543c2aa98e2SPeter Wemm ** If we belong in background, fork now. 544c2aa98e2SPeter Wemm */ 545c2aa98e2SPeter Wemm 546c2aa98e2SPeter Wemm if (tTd(13, 20)) 547c2aa98e2SPeter Wemm { 54840266059SGregory Neil Shapiro sm_dprintf("sendall: final mode = %c\n", mode); 549c2aa98e2SPeter Wemm if (tTd(13, 21)) 550c2aa98e2SPeter Wemm { 55140266059SGregory Neil Shapiro sm_dprintf("\n================ Final Send Queue(s) =====================\n"); 55240266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 553c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr); 55440266059SGregory Neil Shapiro printaddr(e->e_sendqueue, true); 555c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 556c2aa98e2SPeter Wemm { 55740266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 558c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr); 55940266059SGregory Neil Shapiro printaddr(ee->e_sendqueue, true); 560c2aa98e2SPeter Wemm } 56140266059SGregory Neil Shapiro sm_dprintf("==========================================================\n\n"); 562c2aa98e2SPeter Wemm } 563c2aa98e2SPeter Wemm } 564c2aa98e2SPeter Wemm switch (mode) 565c2aa98e2SPeter Wemm { 566c2aa98e2SPeter Wemm case SM_VERIFY: 567c2aa98e2SPeter Wemm Verbose = 2; 568c2aa98e2SPeter Wemm break; 569c2aa98e2SPeter Wemm 570c2aa98e2SPeter Wemm case SM_QUEUE: 571c2aa98e2SPeter Wemm case SM_DEFER: 572c2aa98e2SPeter Wemm #if HASFLOCK 573c2aa98e2SPeter Wemm queueonly: 57406f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 575c2aa98e2SPeter Wemm if (e->e_nrcpts > 0) 576c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 57740266059SGregory Neil Shapiro dropenvelope(e, splitenv != NULL, true); 578c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 579c2aa98e2SPeter Wemm { 580c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0) 581c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 58240266059SGregory Neil Shapiro dropenvelope(ee, false, true); 583c2aa98e2SPeter Wemm } 584c2aa98e2SPeter Wemm return; 585c2aa98e2SPeter Wemm 586c2aa98e2SPeter Wemm case SM_FORK: 587c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 58840266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 589c2aa98e2SPeter Wemm 590c2aa98e2SPeter Wemm #if !HASFLOCK 591c2aa98e2SPeter Wemm /* 592c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that 593c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file 594c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and 595c2aa98e2SPeter Wemm ** then restart from scratch in the child. 596c2aa98e2SPeter Wemm */ 597c2aa98e2SPeter Wemm 598c2aa98e2SPeter Wemm { 599c2aa98e2SPeter Wemm /* save id for future use */ 600c2aa98e2SPeter Wemm char *qid = e->e_id; 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm /* now drop the envelope in the parent */ 603c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 60440266059SGregory Neil Shapiro dropenvelope(e, splitenv != NULL, false); 605c2aa98e2SPeter Wemm 606c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */ 607c2aa98e2SPeter Wemm e->e_id = qid; 608c2aa98e2SPeter Wemm } 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 611c2aa98e2SPeter Wemm { 612c2aa98e2SPeter Wemm /* save id for future use */ 613c2aa98e2SPeter Wemm char *qid = ee->e_id; 614c2aa98e2SPeter Wemm 615c2aa98e2SPeter Wemm /* drop envelope in parent */ 616c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 61740266059SGregory Neil Shapiro dropenvelope(ee, false, false); 618c2aa98e2SPeter Wemm 619c2aa98e2SPeter Wemm /* and save qid for reacquisition */ 620c2aa98e2SPeter Wemm ee->e_id = qid; 621c2aa98e2SPeter Wemm } 622c2aa98e2SPeter Wemm 623c2aa98e2SPeter Wemm #endif /* !HASFLOCK */ 624c2aa98e2SPeter Wemm 62506f25ae9SGregory Neil Shapiro /* 62606f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent 62706f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby 62806f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore, 62906f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open 63006f25ae9SGregory Neil Shapiro ** them if necessary. 63106f25ae9SGregory Neil Shapiro */ 63206f25ae9SGregory Neil Shapiro 63340266059SGregory Neil Shapiro closemaps(false); 63406f25ae9SGregory Neil Shapiro 635c2aa98e2SPeter Wemm pid = fork(); 636c2aa98e2SPeter Wemm if (pid < 0) 637c2aa98e2SPeter Wemm { 63806f25ae9SGregory Neil Shapiro syserr("deliver: fork 1"); 639c2aa98e2SPeter Wemm #if HASFLOCK 640c2aa98e2SPeter Wemm goto queueonly; 64106f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 642c2aa98e2SPeter Wemm e->e_id = NULL; 643c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 644c2aa98e2SPeter Wemm ee->e_id = NULL; 645c2aa98e2SPeter Wemm return; 646c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 647c2aa98e2SPeter Wemm } 648c2aa98e2SPeter Wemm else if (pid > 0) 649c2aa98e2SPeter Wemm { 650c2aa98e2SPeter Wemm #if HASFLOCK 651c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */ 652c2aa98e2SPeter Wemm /* close any random open files in the envelope */ 653c2aa98e2SPeter Wemm closexscript(e); 654c2aa98e2SPeter Wemm if (e->e_dfp != NULL) 65540266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 656c2aa98e2SPeter Wemm e->e_dfp = NULL; 657c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF; 658c2aa98e2SPeter Wemm 659c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */ 660c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 66140266059SGregory Neil Shapiro (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 66206f25ae9SGregory Neil Shapiro else 66306f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id); 664c2aa98e2SPeter Wemm e->e_lockfp = NULL; 66506f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 666c2aa98e2SPeter Wemm 667c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */ 668c2aa98e2SPeter Wemm e->e_id = NULL; 669c2aa98e2SPeter Wemm 67040266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 671c2aa98e2SPeter Wemm /* catch intermediate zombie */ 672c2aa98e2SPeter Wemm (void) waitfor(pid); 67340266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 674c2aa98e2SPeter Wemm return; 675c2aa98e2SPeter Wemm } 676c2aa98e2SPeter Wemm 6778774250cSGregory Neil Shapiro /* Reset global flags */ 6788774250cSGregory Neil Shapiro RestartRequest = NULL; 67940266059SGregory Neil Shapiro RestartWorkGroup = false; 6808774250cSGregory Neil Shapiro ShutdownRequest = NULL; 6818774250cSGregory Neil Shapiro PendingSignal = 0; 6828774250cSGregory Neil Shapiro 68342e5d165SGregory Neil Shapiro /* 68440266059SGregory Neil Shapiro ** Initialize exception stack and default exception 68540266059SGregory Neil Shapiro ** handler for child process. 68640266059SGregory Neil Shapiro */ 68740266059SGregory Neil Shapiro 68840266059SGregory Neil Shapiro sm_exc_newthread(fatal_error); 68940266059SGregory Neil Shapiro 69040266059SGregory Neil Shapiro /* 69142e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message, 69242e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler) 69342e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line 69442e5d165SGregory Neil Shapiro ** message submission. 69542e5d165SGregory Neil Shapiro */ 69642e5d165SGregory Neil Shapiro 69740266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 69842e5d165SGregory Neil Shapiro 69940266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 700c2aa98e2SPeter Wemm /* double fork to avoid zombies */ 701c2aa98e2SPeter Wemm pid = fork(); 702c2aa98e2SPeter Wemm if (pid > 0) 703c2aa98e2SPeter Wemm exit(EX_OK); 70406f25ae9SGregory Neil Shapiro save_errno = errno; 70540266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 70640266059SGregory Neil Shapiro 70740266059SGregory Neil Shapiro CurrentPid = getpid(); 708c2aa98e2SPeter Wemm 709c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */ 710c2aa98e2SPeter Wemm disconnect(2, e); 71106f25ae9SGregory Neil Shapiro clearstats(); 712c2aa98e2SPeter Wemm 713c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */ 714c2aa98e2SPeter Wemm if (pid < 0) 715c2aa98e2SPeter Wemm { 71606f25ae9SGregory Neil Shapiro errno = save_errno; 71706f25ae9SGregory Neil Shapiro syserr("deliver: fork 2"); 718c2aa98e2SPeter Wemm #if HASFLOCK 719c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 72006f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 721c2aa98e2SPeter Wemm e->e_id = NULL; 722c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 72340266059SGregory Neil Shapiro finis(true, true, ExitStat); 724c2aa98e2SPeter Wemm } 725c2aa98e2SPeter Wemm 726c2aa98e2SPeter Wemm /* be sure to give error messages in child */ 72740266059SGregory Neil Shapiro QuickAbort = false; 728c2aa98e2SPeter Wemm 729c2aa98e2SPeter Wemm /* 730c2aa98e2SPeter Wemm ** Close any cached connections. 731c2aa98e2SPeter Wemm ** 732c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent 733c2aa98e2SPeter Wemm ** still knows about the connection. 734c2aa98e2SPeter Wemm ** 735c2aa98e2SPeter Wemm ** This should only happen when delivering an error 736c2aa98e2SPeter Wemm ** message. 737c2aa98e2SPeter Wemm */ 738c2aa98e2SPeter Wemm 73940266059SGregory Neil Shapiro mci_flush(false, NULL); 740c2aa98e2SPeter Wemm 741c2aa98e2SPeter Wemm #if HASFLOCK 742c2aa98e2SPeter Wemm break; 74306f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 744c2aa98e2SPeter Wemm 745c2aa98e2SPeter Wemm /* 746c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files. 747c2aa98e2SPeter Wemm */ 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 750c2aa98e2SPeter Wemm { 751c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling; 752c2aa98e2SPeter Wemm 75340266059SGregory Neil Shapiro (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id, 75440266059SGregory Neil Shapiro false, false, ee); 755c2aa98e2SPeter Wemm ee->e_sibling = sibling; 756c2aa98e2SPeter Wemm } 75740266059SGregory Neil Shapiro (void) dowork(e->e_qgrp, e->e_qdir, e->e_id, 75840266059SGregory Neil Shapiro false, false, e); 75940266059SGregory Neil Shapiro finis(true, true, ExitStat); 76006f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 761c2aa98e2SPeter Wemm } 762c2aa98e2SPeter Wemm 763c2aa98e2SPeter Wemm sendenvelope(e, mode); 76440266059SGregory Neil Shapiro dropenvelope(e, true, true); 765c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 766c2aa98e2SPeter Wemm { 767c2aa98e2SPeter Wemm CurEnv = ee; 768c2aa98e2SPeter Wemm if (mode != SM_VERIFY) 769c2aa98e2SPeter Wemm openxscript(ee); 770c2aa98e2SPeter Wemm sendenvelope(ee, mode); 77140266059SGregory Neil Shapiro dropenvelope(ee, true, true); 772c2aa98e2SPeter Wemm } 773c2aa98e2SPeter Wemm CurEnv = e; 774c2aa98e2SPeter Wemm 775c2aa98e2SPeter Wemm Verbose = oldverbose; 776c2aa98e2SPeter Wemm if (mode == SM_FORK) 77740266059SGregory Neil Shapiro finis(true, true, ExitStat); 778c2aa98e2SPeter Wemm } 779c2aa98e2SPeter Wemm 78006f25ae9SGregory Neil Shapiro static void 781c2aa98e2SPeter Wemm sendenvelope(e, mode) 782c2aa98e2SPeter Wemm register ENVELOPE *e; 783c2aa98e2SPeter Wemm int mode; 784c2aa98e2SPeter Wemm { 785c2aa98e2SPeter Wemm register ADDRESS *q; 786c2aa98e2SPeter Wemm bool didany; 787c2aa98e2SPeter Wemm 788c2aa98e2SPeter Wemm if (tTd(13, 10)) 78940266059SGregory Neil Shapiro sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n", 790c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 791c2aa98e2SPeter Wemm e->e_flags); 792c2aa98e2SPeter Wemm if (LogLevel > 80) 793c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id, 79406f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx", 795c2aa98e2SPeter Wemm e->e_flags); 796c2aa98e2SPeter Wemm 797c2aa98e2SPeter Wemm /* 798c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 799c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 800c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 801c2aa98e2SPeter Wemm ** addresses to be sent. 802c2aa98e2SPeter Wemm */ 803c2aa98e2SPeter Wemm 804c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 805c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 806c2aa98e2SPeter Wemm { 807c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 808c2aa98e2SPeter Wemm return; 809c2aa98e2SPeter Wemm } 810c2aa98e2SPeter Wemm 81140266059SGregory Neil Shapiro /* 81240266059SGregory Neil Shapiro ** Don't attempt deliveries if we want to bounce now 81340266059SGregory Neil Shapiro ** or if deliver-by time is exceeded. 81440266059SGregory Neil Shapiro */ 81540266059SGregory Neil Shapiro 81606f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) && 81740266059SGregory Neil Shapiro (TimeOuts.to_q_return[e->e_timeoutclass] == NOW || 81840266059SGregory Neil Shapiro (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 && 81940266059SGregory Neil Shapiro curtime() > e->e_ctime + e->e_deliver_by))) 82006f25ae9SGregory Neil Shapiro return; 82106f25ae9SGregory Neil Shapiro 822c2aa98e2SPeter Wemm /* 823c2aa98e2SPeter Wemm ** Run through the list and send everything. 824c2aa98e2SPeter Wemm ** 825c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery 826c2aa98e2SPeter Wemm ** result in returned mail. 827c2aa98e2SPeter Wemm */ 828c2aa98e2SPeter Wemm 829c2aa98e2SPeter Wemm e->e_nsent = 0; 830c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS; 83106f25ae9SGregory Neil Shapiro 83240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid); 83340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype); 83440266059SGregory Neil Shapiro didany = false; 83540266059SGregory Neil Shapiro 83640266059SGregory Neil Shapiro if (!bitset(EF_SPLIT, e->e_flags)) 83740266059SGregory Neil Shapiro { 83840266059SGregory Neil Shapiro ENVELOPE *oldsib; 83940266059SGregory Neil Shapiro ENVELOPE *ee; 84040266059SGregory Neil Shapiro 84140266059SGregory Neil Shapiro /* 84240266059SGregory Neil Shapiro ** Save old sibling and set it to NULL to avoid 84340266059SGregory Neil Shapiro ** queueing up the same envelopes again. 84440266059SGregory Neil Shapiro ** This requires that envelopes in that list have 84540266059SGregory Neil Shapiro ** been take care of before (or at some other place). 84640266059SGregory Neil Shapiro */ 84740266059SGregory Neil Shapiro 84840266059SGregory Neil Shapiro oldsib = e->e_sibling; 84940266059SGregory Neil Shapiro e->e_sibling = NULL; 85040266059SGregory Neil Shapiro if (!split_by_recipient(e) && 85140266059SGregory Neil Shapiro bitset(EF_FATALERRS, e->e_flags)) 85240266059SGregory Neil Shapiro { 85340266059SGregory Neil Shapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 85440266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE; 85540266059SGregory Neil Shapiro return; 85640266059SGregory Neil Shapiro } 85740266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 85840266059SGregory Neil Shapiro queueup(ee, false, true); 85940266059SGregory Neil Shapiro 86040266059SGregory Neil Shapiro /* clean up */ 86140266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86240266059SGregory Neil Shapiro { 86340266059SGregory Neil Shapiro /* now unlock the job */ 86440266059SGregory Neil Shapiro closexscript(ee); 86540266059SGregory Neil Shapiro unlockqueue(ee); 86640266059SGregory Neil Shapiro 86740266059SGregory Neil Shapiro /* this envelope is marked unused */ 86840266059SGregory Neil Shapiro if (ee->e_dfp != NULL) 86940266059SGregory Neil Shapiro { 87040266059SGregory Neil Shapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 87140266059SGregory Neil Shapiro ee->e_dfp = NULL; 87240266059SGregory Neil Shapiro } 87340266059SGregory Neil Shapiro ee->e_id = NULL; 87440266059SGregory Neil Shapiro ee->e_flags &= ~EF_HAS_DF; 87540266059SGregory Neil Shapiro } 87640266059SGregory Neil Shapiro e->e_sibling = oldsib; 87740266059SGregory Neil Shapiro } 878c2aa98e2SPeter Wemm 879c2aa98e2SPeter Wemm /* now run through the queue */ 880c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 881c2aa98e2SPeter Wemm { 882c2aa98e2SPeter Wemm #if XDEBUG 883c2aa98e2SPeter Wemm char wbuf[MAXNAME + 20]; 884c2aa98e2SPeter Wemm 88540266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, "sendall(%.*s)", 886c2aa98e2SPeter Wemm MAXNAME, q->q_paddr); 887c2aa98e2SPeter Wemm checkfd012(wbuf); 88806f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 889c2aa98e2SPeter Wemm if (mode == SM_VERIFY) 890c2aa98e2SPeter Wemm { 891c2aa98e2SPeter Wemm e->e_to = q->q_paddr; 89206f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state)) 893c2aa98e2SPeter Wemm { 894c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0') 895c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s", 896c2aa98e2SPeter Wemm q->q_mailer->m_name, 897c2aa98e2SPeter Wemm q->q_host, 898c2aa98e2SPeter Wemm q->q_user); 899c2aa98e2SPeter Wemm else 900c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s", 901c2aa98e2SPeter Wemm q->q_mailer->m_name, 902c2aa98e2SPeter Wemm q->q_user); 903c2aa98e2SPeter Wemm } 904c2aa98e2SPeter Wemm } 90506f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state)) 906c2aa98e2SPeter Wemm { 907c2aa98e2SPeter Wemm /* 908c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses 909c2aa98e2SPeter Wemm */ 910c2aa98e2SPeter Wemm 91142e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && 91242e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval) 913c2aa98e2SPeter Wemm { 91440266059SGregory Neil Shapiro queueup(e, false, false); 915c2aa98e2SPeter Wemm e->e_nsent = 0; 916c2aa98e2SPeter Wemm } 917c2aa98e2SPeter Wemm (void) deliver(e, q); 91840266059SGregory Neil Shapiro didany = true; 919c2aa98e2SPeter Wemm } 920c2aa98e2SPeter Wemm } 921c2aa98e2SPeter Wemm if (didany) 922c2aa98e2SPeter Wemm { 923c2aa98e2SPeter Wemm e->e_dtime = curtime(); 924c2aa98e2SPeter Wemm e->e_ntries++; 925c2aa98e2SPeter Wemm } 926c2aa98e2SPeter Wemm 927c2aa98e2SPeter Wemm #if XDEBUG 928c2aa98e2SPeter Wemm checkfd012("end of sendenvelope"); 92906f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 930c2aa98e2SPeter Wemm } 93140266059SGregory Neil Shapiro 93240266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC 93340266059SGregory Neil Shapiro /* 93440266059SGregory Neil Shapiro ** SYNC_DIR -- fsync a directory based on a filename 93540266059SGregory Neil Shapiro ** 93640266059SGregory Neil Shapiro ** Parameters: 93740266059SGregory Neil Shapiro ** filename -- path of file 93840266059SGregory Neil Shapiro ** panic -- panic? 93940266059SGregory Neil Shapiro ** 94040266059SGregory Neil Shapiro ** Returns: 94140266059SGregory Neil Shapiro ** none 94240266059SGregory Neil Shapiro */ 94340266059SGregory Neil Shapiro 94440266059SGregory Neil Shapiro void 94540266059SGregory Neil Shapiro sync_dir(filename, panic) 94640266059SGregory Neil Shapiro char *filename; 94740266059SGregory Neil Shapiro bool panic; 94840266059SGregory Neil Shapiro { 94940266059SGregory Neil Shapiro int dirfd; 95040266059SGregory Neil Shapiro char *dirp; 95140266059SGregory Neil Shapiro char dir[MAXPATHLEN]; 95240266059SGregory Neil Shapiro 95340266059SGregory Neil Shapiro /* filesystems which require the directory be synced */ 95440266059SGregory Neil Shapiro dirp = strrchr(filename, '/'); 95540266059SGregory Neil Shapiro if (dirp != NULL) 95640266059SGregory Neil Shapiro { 95740266059SGregory Neil Shapiro if (sm_strlcpy(dir, filename, sizeof dir) >= sizeof dir) 95840266059SGregory Neil Shapiro return; 95940266059SGregory Neil Shapiro dir[dirp - filename] = '\0'; 96040266059SGregory Neil Shapiro dirp = dir; 96140266059SGregory Neil Shapiro } 96240266059SGregory Neil Shapiro else 96340266059SGregory Neil Shapiro dirp = "."; 96440266059SGregory Neil Shapiro dirfd = open(dirp, O_RDONLY, 0700); 96540266059SGregory Neil Shapiro if (tTd(40,32)) 96640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)", 96740266059SGregory Neil Shapiro dirp, dirfd); 96840266059SGregory Neil Shapiro if (dirfd >= 0) 96940266059SGregory Neil Shapiro { 97040266059SGregory Neil Shapiro if (fsync(dirfd) < 0) 97140266059SGregory Neil Shapiro { 97240266059SGregory Neil Shapiro if (panic) 97340266059SGregory Neil Shapiro syserr("!sync_dir: cannot fsync directory %s", 97440266059SGregory Neil Shapiro dirp); 97540266059SGregory Neil Shapiro else if (LogLevel > 1) 97640266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 97740266059SGregory Neil Shapiro "sync_dir: cannot fsync directory %s: %s", 97840266059SGregory Neil Shapiro dirp, sm_errstring(errno)); 97940266059SGregory Neil Shapiro } 98040266059SGregory Neil Shapiro (void) close(dirfd); 98140266059SGregory Neil Shapiro } 98240266059SGregory Neil Shapiro } 98340266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */ 98440266059SGregory Neil Shapiro /* 985c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 986c2aa98e2SPeter Wemm ** 987c2aa98e2SPeter Wemm ** Parameters: 988c2aa98e2SPeter Wemm ** e -- the existing envelope 989c2aa98e2SPeter Wemm ** ee -- the new envelope 99040266059SGregory Neil Shapiro ** type -- the queue file type (e.g., DATAFL_LETTER) 991c2aa98e2SPeter Wemm ** 992c2aa98e2SPeter Wemm ** Returns: 993c2aa98e2SPeter Wemm ** none 994c2aa98e2SPeter Wemm */ 995c2aa98e2SPeter Wemm 99606f25ae9SGregory Neil Shapiro static void 997c2aa98e2SPeter Wemm dup_queue_file(e, ee, type) 99840266059SGregory Neil Shapiro ENVELOPE *e, *ee; 999c2aa98e2SPeter Wemm int type; 1000c2aa98e2SPeter Wemm { 100106f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 1002c2aa98e2SPeter Wemm 1003c2aa98e2SPeter Wemm ee->e_dfp = NULL; 1004c2aa98e2SPeter Wemm ee->e_xfp = NULL; 100506f25ae9SGregory Neil Shapiro 100606f25ae9SGregory Neil Shapiro /* 100706f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory. 100806f25ae9SGregory Neil Shapiro */ 100906f25ae9SGregory Neil Shapiro 101040266059SGregory Neil Shapiro (void) sm_strlcpy(f1buf, queuename(e, type), sizeof f1buf); 101140266059SGregory Neil Shapiro (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof f2buf); 1012c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1013c2aa98e2SPeter Wemm { 101406f25ae9SGregory Neil Shapiro int save_errno = errno; 1015c2aa98e2SPeter Wemm 1016c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf); 101706f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 1018c2aa98e2SPeter Wemm { 1019c2aa98e2SPeter Wemm if (unlink(f2buf) < 0) 1020c2aa98e2SPeter Wemm { 1021c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent", 1022c2aa98e2SPeter Wemm f2buf); 1023c2aa98e2SPeter Wemm /* NOTREACHED */ 1024c2aa98e2SPeter Wemm } 1025c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1026c2aa98e2SPeter Wemm { 1027c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent", 1028c2aa98e2SPeter Wemm f1buf, f2buf); 1029c2aa98e2SPeter Wemm /* NOTREACHED */ 1030c2aa98e2SPeter Wemm } 1031c2aa98e2SPeter Wemm } 1032c2aa98e2SPeter Wemm } 103340266059SGregory Neil Shapiro SYNC_DIR(f2buf, true); 1034c2aa98e2SPeter Wemm } 103540266059SGregory Neil Shapiro /* 1036c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure. 1037c2aa98e2SPeter Wemm ** 1038c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running 1039c2aa98e2SPeter Wemm ** two processes on the same stack!!! 1040c2aa98e2SPeter Wemm ** 1041c2aa98e2SPeter Wemm ** Parameters: 1042c2aa98e2SPeter Wemm ** none. 1043c2aa98e2SPeter Wemm ** 1044c2aa98e2SPeter Wemm ** Returns: 1045c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding! 1046c2aa98e2SPeter Wemm ** 1047c2aa98e2SPeter Wemm ** Side Effects: 1048c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving: 1049c2aa98e2SPeter Wemm ** pid of child in parent, zero in child. 1050c2aa98e2SPeter Wemm ** -1 on unrecoverable error. 1051c2aa98e2SPeter Wemm ** 1052c2aa98e2SPeter Wemm ** Notes: 1053c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's 1054c2aa98e2SPeter Wemm ** vfork for you..... 1055c2aa98e2SPeter Wemm */ 1056c2aa98e2SPeter Wemm 1057c2aa98e2SPeter Wemm #define NFORKTRIES 5 1058c2aa98e2SPeter Wemm 1059c2aa98e2SPeter Wemm #ifndef FORK 1060c2aa98e2SPeter Wemm # define FORK fork 106106f25ae9SGregory Neil Shapiro #endif /* ! FORK */ 1062c2aa98e2SPeter Wemm 1063c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \ 1064c2aa98e2SPeter Wemm {\ 1065c2aa98e2SPeter Wemm register int i;\ 1066c2aa98e2SPeter Wemm \ 1067c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\ 1068c2aa98e2SPeter Wemm {\ 1069c2aa98e2SPeter Wemm pid = fORKfN();\ 1070c2aa98e2SPeter Wemm if (pid >= 0)\ 1071c2aa98e2SPeter Wemm break;\ 1072c2aa98e2SPeter Wemm if (i > 0)\ 107306f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\ 1074c2aa98e2SPeter Wemm }\ 1075c2aa98e2SPeter Wemm } 107640266059SGregory Neil Shapiro /* 1077c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK. 1078c2aa98e2SPeter Wemm ** 1079c2aa98e2SPeter Wemm ** Parameters: 1080c2aa98e2SPeter Wemm ** none. 1081c2aa98e2SPeter Wemm ** 1082c2aa98e2SPeter Wemm ** Returns: 1083c2aa98e2SPeter Wemm ** pid of child in parent. 1084c2aa98e2SPeter Wemm ** zero in child. 1085c2aa98e2SPeter Wemm ** -1 on error. 1086c2aa98e2SPeter Wemm ** 1087c2aa98e2SPeter Wemm ** Side Effects: 1088c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child. 1089c2aa98e2SPeter Wemm */ 1090c2aa98e2SPeter Wemm 10918774250cSGregory Neil Shapiro pid_t 1092c2aa98e2SPeter Wemm dofork() 1093c2aa98e2SPeter Wemm { 1094c2aa98e2SPeter Wemm register pid_t pid = -1; 1095c2aa98e2SPeter Wemm 1096c2aa98e2SPeter Wemm DOFORK(fork); 109706f25ae9SGregory Neil Shapiro return pid; 1098c2aa98e2SPeter Wemm } 109940266059SGregory Neil Shapiro 110040266059SGregory Neil Shapiro /* 110140266059SGregory Neil Shapiro ** COLONCMP -- compare host-signatures up to first ':' or EOS 110240266059SGregory Neil Shapiro ** 110340266059SGregory Neil Shapiro ** This takes two strings which happen to be host-signatures and 110440266059SGregory Neil Shapiro ** compares them. If the lowest preference portions of the MX-RR's 110540266059SGregory Neil Shapiro ** match (up to ':' or EOS, whichever is first), then we have 110640266059SGregory Neil Shapiro ** match. This is used for coattail-piggybacking messages during 110740266059SGregory Neil Shapiro ** message delivery. 110840266059SGregory Neil Shapiro ** If the signatures are the same up to the first ':' the remainder of 110940266059SGregory Neil Shapiro ** the signatures are then compared with a normal strcmp(). This saves 111040266059SGregory Neil Shapiro ** re-examining the first part of the signatures. 111140266059SGregory Neil Shapiro ** 111240266059SGregory Neil Shapiro ** Parameters: 111340266059SGregory Neil Shapiro ** a - first host-signature 111440266059SGregory Neil Shapiro ** b - second host-signature 111540266059SGregory Neil Shapiro ** 111640266059SGregory Neil Shapiro ** Returns: 111740266059SGregory Neil Shapiro ** HS_MATCH_NO -- no "match". 111840266059SGregory Neil Shapiro ** HS_MATCH_FIRST -- "match" for the first MX preference 111940266059SGregory Neil Shapiro ** (up to the first colon (':')). 112040266059SGregory Neil Shapiro ** HS_MATCH_FULL -- match for the entire MX record. 112140266059SGregory Neil Shapiro ** 112240266059SGregory Neil Shapiro ** Side Effects: 112340266059SGregory Neil Shapiro ** none. 112440266059SGregory Neil Shapiro */ 112540266059SGregory Neil Shapiro 112640266059SGregory Neil Shapiro #define HS_MATCH_NO 0 112740266059SGregory Neil Shapiro #define HS_MATCH_FIRST 1 112840266059SGregory Neil Shapiro #define HS_MATCH_FULL 2 112940266059SGregory Neil Shapiro 113040266059SGregory Neil Shapiro static int 113140266059SGregory Neil Shapiro coloncmp(a, b) 113240266059SGregory Neil Shapiro register const char *a; 113340266059SGregory Neil Shapiro register const char *b; 113440266059SGregory Neil Shapiro { 113540266059SGregory Neil Shapiro int ret = HS_MATCH_NO; 113640266059SGregory Neil Shapiro int braclev = 0; 113740266059SGregory Neil Shapiro 113840266059SGregory Neil Shapiro while (*a == *b++) 113940266059SGregory Neil Shapiro { 114040266059SGregory Neil Shapiro /* Need to account for IPv6 bracketed addresses */ 114140266059SGregory Neil Shapiro if (*a == '[') 114240266059SGregory Neil Shapiro braclev++; 114340266059SGregory Neil Shapiro else if (*a == '[' && braclev > 0) 114440266059SGregory Neil Shapiro braclev--; 114540266059SGregory Neil Shapiro else if (*a == ':' && braclev <= 0) 114640266059SGregory Neil Shapiro { 114740266059SGregory Neil Shapiro ret = HS_MATCH_FIRST; 114840266059SGregory Neil Shapiro a++; 114940266059SGregory Neil Shapiro break; 115040266059SGregory Neil Shapiro } 115140266059SGregory Neil Shapiro else if (*a == '\0') 115240266059SGregory Neil Shapiro return HS_MATCH_FULL; /* a full match */ 115340266059SGregory Neil Shapiro a++; 115440266059SGregory Neil Shapiro } 115540266059SGregory Neil Shapiro if (ret == HS_MATCH_NO && 115640266059SGregory Neil Shapiro braclev <= 0 && 115740266059SGregory Neil Shapiro ((*a == '\0' && *(b - 1) == ':') || 115840266059SGregory Neil Shapiro (*a == ':' && *(b - 1) == '\0'))) 115940266059SGregory Neil Shapiro return HS_MATCH_FIRST; 116040266059SGregory Neil Shapiro if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0) 116140266059SGregory Neil Shapiro return HS_MATCH_FULL; 116240266059SGregory Neil Shapiro 116340266059SGregory Neil Shapiro return ret; 116440266059SGregory Neil Shapiro } 116540266059SGregory Neil Shapiro /* 1166c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses. 1167c2aa98e2SPeter Wemm ** 1168c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the 1169c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers 1170c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed 1171c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so 1172c2aa98e2SPeter Wemm ** deliver should be called once for each address on the 1173c2aa98e2SPeter Wemm ** list. 117440266059SGregory Neil Shapiro ** Deliver tries to be as opportunistic as possible about piggybacking 117540266059SGregory Neil Shapiro ** messages. Some definitions to make understanding easier follow below. 117640266059SGregory Neil Shapiro ** Piggybacking occurs when an existing connection to a mail host can 117740266059SGregory Neil Shapiro ** be used to send the same message to more than one recipient at the 117840266059SGregory Neil Shapiro ** same time. So "no piggybacking" means one message for one recipient 117940266059SGregory Neil Shapiro ** per connection. "Intentional piggybacking" happens when the 118040266059SGregory Neil Shapiro ** recipients' host address (not the mail host address) is used to 118140266059SGregory Neil Shapiro ** attempt piggybacking. Recipients with the same host address 118240266059SGregory Neil Shapiro ** have the same mail host. "Coincidental piggybacking" relies on 118340266059SGregory Neil Shapiro ** piggybacking based on all the mail host addresses in the MX-RR. This 118440266059SGregory Neil Shapiro ** is "coincidental" in the fact it could not be predicted until the 118540266059SGregory Neil Shapiro ** MX Resource Records for the hosts were obtained and examined. For 118640266059SGregory Neil Shapiro ** example (preference order and equivalence is important, not values): 118740266059SGregory Neil Shapiro ** domain1 IN MX 10 mxhost-A 118840266059SGregory Neil Shapiro ** IN MX 20 mxhost-B 118940266059SGregory Neil Shapiro ** domain2 IN MX 4 mxhost-A 119040266059SGregory Neil Shapiro ** IN MX 8 mxhost-B 119140266059SGregory Neil Shapiro ** Domain1 and domain2 can piggyback the same message to mxhost-A or 119240266059SGregory Neil Shapiro ** mxhost-B (if mxhost-A cannot be reached). 119340266059SGregory Neil Shapiro ** "Coattail piggybacking" relaxes the strictness of "coincidental 119440266059SGregory Neil Shapiro ** piggybacking" in the hope that most significant (lowest value) 119540266059SGregory Neil Shapiro ** MX preference host(s) can create more piggybacking. For example 119640266059SGregory Neil Shapiro ** (again, preference order and equivalence is important, not values): 119740266059SGregory Neil Shapiro ** domain3 IN MX 100 mxhost-C 119840266059SGregory Neil Shapiro ** IN MX 100 mxhost-D 119940266059SGregory Neil Shapiro ** IN MX 200 mxhost-E 120040266059SGregory Neil Shapiro ** domain4 IN MX 50 mxhost-C 120140266059SGregory Neil Shapiro ** IN MX 50 mxhost-D 120240266059SGregory Neil Shapiro ** IN MX 80 mxhost-F 120340266059SGregory Neil Shapiro ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C 120440266059SGregory Neil Shapiro ** is available. Same with mxhost-D because in both RR's the preference 120540266059SGregory Neil Shapiro ** value is the same as mxhost-C, respectively. 120640266059SGregory Neil Shapiro ** So deliver attempts coattail piggybacking when possible. If the 120740266059SGregory Neil Shapiro ** first MX preference level hosts cannot be used then the piggybacking 120840266059SGregory Neil Shapiro ** reverts to coincidental piggybacking. Using the above example you 120940266059SGregory Neil Shapiro ** cannot deliver to mxhost-F for domain3 regardless of preference value. 121040266059SGregory Neil Shapiro ** ("Coattail" from "riding on the coattails of your predecessor" meaning 121140266059SGregory Neil Shapiro ** gaining benefit from a predecessor effort with no or little addition 121240266059SGregory Neil Shapiro ** effort. The predecessor here being the preceding MX RR). 1213c2aa98e2SPeter Wemm ** 1214c2aa98e2SPeter Wemm ** Parameters: 1215c2aa98e2SPeter Wemm ** e -- the envelope to deliver. 1216c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to. 1217c2aa98e2SPeter Wemm ** 1218c2aa98e2SPeter Wemm ** Returns: 1219c2aa98e2SPeter Wemm ** zero -- successfully delivered. 1220c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info. 1221c2aa98e2SPeter Wemm ** 1222c2aa98e2SPeter Wemm ** Side Effects: 1223c2aa98e2SPeter Wemm ** The standard input is passed off to someone. 1224c2aa98e2SPeter Wemm */ 1225c2aa98e2SPeter Wemm 1226c2aa98e2SPeter Wemm #ifndef NO_UID 1227c2aa98e2SPeter Wemm # define NO_UID -1 122806f25ae9SGregory Neil Shapiro #endif /* ! NO_UID */ 1229c2aa98e2SPeter Wemm #ifndef NO_GID 1230c2aa98e2SPeter Wemm # define NO_GID -1 123106f25ae9SGregory Neil Shapiro #endif /* ! NO_GID */ 1232c2aa98e2SPeter Wemm 123306f25ae9SGregory Neil Shapiro static int 1234c2aa98e2SPeter Wemm deliver(e, firstto) 1235c2aa98e2SPeter Wemm register ENVELOPE *e; 1236c2aa98e2SPeter Wemm ADDRESS *firstto; 1237c2aa98e2SPeter Wemm { 1238c2aa98e2SPeter Wemm char *host; /* host being sent to */ 1239c2aa98e2SPeter Wemm char *user; /* user being sent to */ 1240c2aa98e2SPeter Wemm char **pvp; 1241c2aa98e2SPeter Wemm register char **mvp; 1242c2aa98e2SPeter Wemm register char *p; 1243c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */ 1244c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr; 124540266059SGregory Neil Shapiro #if HASSETUSERCONTEXT 1246c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL; 124740266059SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 1248c2aa98e2SPeter Wemm register MCI *volatile mci; 124940266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE to = firstto; 125040266059SGregory Neil Shapiro volatile bool clever = false; /* running user smtp to this mailer */ 1251c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 1252c2aa98e2SPeter Wemm int rcode; /* response code */ 125340266059SGregory Neil Shapiro SM_NONVOLATILE int lmtp_rcode = EX_OK; 125440266059SGregory Neil Shapiro SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */ 125540266059SGregory Neil Shapiro SM_NONVOLATILE int hostnum = 0; /* current MX host index */ 1256c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */ 125740266059SGregory Neil Shapiro volatile pid_t pid = -1; 1258c2aa98e2SPeter Wemm char *volatile curhost; 125940266059SGregory Neil Shapiro SM_NONVOLATILE unsigned short port = 0; 126040266059SGregory Neil Shapiro SM_NONVOLATILE time_t enough = 0; 126106f25ae9SGregory Neil Shapiro #if NETUNIX 126240266059SGregory Neil Shapiro char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */ 126306f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 1264c2aa98e2SPeter Wemm time_t xstart; 1265c2aa98e2SPeter Wemm bool suidwarn; 1266c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */ 126740266059SGregory Neil Shapiro SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ 126806f25ae9SGregory Neil Shapiro bool ovr; 126940266059SGregory Neil Shapiro #if _FFR_QUARANTINE 127040266059SGregory Neil Shapiro bool quarantine; 127140266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 127206f25ae9SGregory Neil Shapiro int strsize; 127306f25ae9SGregory Neil Shapiro int rcptcount; 127440266059SGregory Neil Shapiro int ret; 127506f25ae9SGregory Neil Shapiro static int tobufsize = 0; 127606f25ae9SGregory Neil Shapiro static char *tobuf = NULL; 127740266059SGregory Neil Shapiro char *rpath; /* translated return path */ 1278c2aa98e2SPeter Wemm int mpvect[2]; 1279c2aa98e2SPeter Wemm int rpvect[2]; 128006f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1]; 1281c2aa98e2SPeter Wemm char *pv[MAXPV + 1]; 1282c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 1283c2aa98e2SPeter Wemm 1284c2aa98e2SPeter Wemm errno = 0; 128506f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 128606f25ae9SGregory Neil Shapiro return 0; 1287c2aa98e2SPeter Wemm 1288c2aa98e2SPeter Wemm suidwarn = geteuid() == 0; 1289c2aa98e2SPeter Wemm 1290c2aa98e2SPeter Wemm m = to->q_mailer; 1291c2aa98e2SPeter Wemm host = to->q_host; 1292c2aa98e2SPeter Wemm CurEnv = e; /* just in case */ 1293c2aa98e2SPeter Wemm e->e_statmsg = NULL; 1294c2aa98e2SPeter Wemm SmtpError[0] = '\0'; 1295c2aa98e2SPeter Wemm xstart = curtime(); 1296c2aa98e2SPeter Wemm 1297c2aa98e2SPeter Wemm if (tTd(10, 1)) 129840266059SGregory Neil Shapiro sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 1299c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user); 1300c2aa98e2SPeter Wemm if (tTd(10, 100)) 130140266059SGregory Neil Shapiro printopenfds(false); 1302c2aa98e2SPeter Wemm 1303c2aa98e2SPeter Wemm /* 130440266059SGregory Neil Shapiro ** Clear {client_*} macros if this is a bounce message to 1305c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset. 1306c2aa98e2SPeter Wemm */ 1307c2aa98e2SPeter Wemm 1308c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1309c2aa98e2SPeter Wemm { 131040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); 131140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); 131240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); 131340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); 1314c2aa98e2SPeter Wemm } 1315c2aa98e2SPeter Wemm 131640266059SGregory Neil Shapiro SM_TRY 131740266059SGregory Neil Shapiro { 131840266059SGregory Neil Shapiro ADDRESS *skip_back = NULL; 131940266059SGregory Neil Shapiro 1320c2aa98e2SPeter Wemm /* 1321c2aa98e2SPeter Wemm ** Do initial argv setup. 1322c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is 1323c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has 1324c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This 1325c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a 1326c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV. 1327c2aa98e2SPeter Wemm ** The from address rewrite is expected to make 1328c2aa98e2SPeter Wemm ** the address relative to the other end. 1329c2aa98e2SPeter Wemm */ 1330c2aa98e2SPeter Wemm 1331c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */ 1332c2aa98e2SPeter Wemm rcode = EX_OK; 1333c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 1334c2aa98e2SPeter Wemm p = e->e_sender; 1335c2aa98e2SPeter Wemm else 1336c2aa98e2SPeter Wemm p = e->e_from.q_paddr; 133740266059SGregory Neil Shapiro rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 133840266059SGregory Neil Shapiro if (strlen(rpath) > MAXSHORTSTR) 1339c2aa98e2SPeter Wemm { 134040266059SGregory Neil Shapiro rpath = shortenstring(rpath, MAXSHORTSTR); 134140266059SGregory Neil Shapiro 134240266059SGregory Neil Shapiro /* avoid bogus errno */ 134340266059SGregory Neil Shapiro errno = 0; 134440266059SGregory Neil Shapiro syserr("remotename: huge return path %s", rpath); 1345c2aa98e2SPeter Wemm } 134640266059SGregory Neil Shapiro rpath = sm_rpool_strdup_x(e->e_rpool, rpath); 134740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', rpath); 134840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', host); 1349c2aa98e2SPeter Wemm Errors = 0; 1350c2aa98e2SPeter Wemm pvp = pv; 1351c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0]; 1352c2aa98e2SPeter Wemm 1353c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */ 135406f25ae9SGregory Neil Shapiro if (FromFlag && 135506f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) || 135606f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags))) 1357c2aa98e2SPeter Wemm { 1358c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags)) 1359c2aa98e2SPeter Wemm *pvp++ = "-f"; 1360c2aa98e2SPeter Wemm else 1361c2aa98e2SPeter Wemm *pvp++ = "-r"; 136240266059SGregory Neil Shapiro *pvp++ = rpath; 1363c2aa98e2SPeter Wemm } 1364c2aa98e2SPeter Wemm 1365c2aa98e2SPeter Wemm /* 1366c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run 1367c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only 1368c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots 1369c2aa98e2SPeter Wemm ** in the pv after it. 1370c2aa98e2SPeter Wemm */ 1371c2aa98e2SPeter Wemm 1372c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1373c2aa98e2SPeter Wemm { 1374c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */ 1375c2aa98e2SPeter Wemm while (*p != '\0') 1376c2aa98e2SPeter Wemm { 1377c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND) 1378c2aa98e2SPeter Wemm { 1379c2aa98e2SPeter Wemm if (*p == 'u') 1380c2aa98e2SPeter Wemm break; 1381c2aa98e2SPeter Wemm } 1382c2aa98e2SPeter Wemm } 1383c2aa98e2SPeter Wemm 1384c2aa98e2SPeter Wemm if (*p != '\0') 1385c2aa98e2SPeter Wemm break; 1386c2aa98e2SPeter Wemm 1387c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */ 1388c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 138940266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1390c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3]) 1391c2aa98e2SPeter Wemm { 139206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u", 139306f25ae9SGregory Neil Shapiro pv[0]); 139440266059SGregory Neil Shapiro rcode = -1; 139540266059SGregory Neil Shapiro goto cleanup; 1396c2aa98e2SPeter Wemm } 1397c2aa98e2SPeter Wemm } 1398c2aa98e2SPeter Wemm 1399c2aa98e2SPeter Wemm /* 1400c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument 1401c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and 1402c2aa98e2SPeter Wemm ** SMTP is the answer!! 1403c2aa98e2SPeter Wemm */ 1404c2aa98e2SPeter Wemm 1405c2aa98e2SPeter Wemm if (*mvp == NULL) 1406c2aa98e2SPeter Wemm { 1407602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */ 140840266059SGregory Neil Shapiro clever = true; 1409c2aa98e2SPeter Wemm *pvp = NULL; 1410c2aa98e2SPeter Wemm } 1411602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags)) 1412602a2b1bSGregory Neil Shapiro { 1413602a2b1bSGregory Neil Shapiro /* not running LMTP */ 1414602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL, 1415602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off", 1416602a2b1bSGregory Neil Shapiro m->m_name); 1417602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags); 1418602a2b1bSGregory Neil Shapiro } 1419c2aa98e2SPeter Wemm 1420c2aa98e2SPeter Wemm /* 1421c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We 1422c2aa98e2SPeter Wemm ** run through our address list and append all the addresses 1423c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can 1424c2aa98e2SPeter Wemm ** always send another copy later. 1425c2aa98e2SPeter Wemm */ 1426c2aa98e2SPeter Wemm 142706f25ae9SGregory Neil Shapiro e->e_to = NULL; 142806f25ae9SGregory Neil Shapiro strsize = 2; 142906f25ae9SGregory Neil Shapiro rcptcount = 0; 1430c2aa98e2SPeter Wemm ctladdr = NULL; 143140266059SGregory Neil Shapiro if (firstto->q_signature == NULL) 143240266059SGregory Neil Shapiro firstto->q_signature = hostsignature(firstto->q_mailer, 143340266059SGregory Neil Shapiro firstto->q_host); 143440266059SGregory Neil Shapiro firstsig = firstto->q_signature; 143540266059SGregory Neil Shapiro 1436c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next) 1437c2aa98e2SPeter Wemm { 1438c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */ 143906f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 144006f25ae9SGregory Neil Shapiro break; 1441c2aa98e2SPeter Wemm 1442c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */ 144340266059SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) /* already sent; look at next */ 1444c2aa98e2SPeter Wemm continue; 1445c2aa98e2SPeter Wemm 144640266059SGregory Neil Shapiro /* 144740266059SGregory Neil Shapiro ** Must be same mailer to keep grouping rcpts. 144840266059SGregory Neil Shapiro ** If mailers don't match: continue; sendqueue is not 144940266059SGregory Neil Shapiro ** sorted by mailers, so don't break; 145040266059SGregory Neil Shapiro */ 145140266059SGregory Neil Shapiro 145240266059SGregory Neil Shapiro if (to->q_mailer != firstto->q_mailer) 145340266059SGregory Neil Shapiro continue; 145440266059SGregory Neil Shapiro 145540266059SGregory Neil Shapiro if (to->q_signature == NULL) /* for safety */ 145640266059SGregory Neil Shapiro to->q_signature = hostsignature(to->q_mailer, 145740266059SGregory Neil Shapiro to->q_host); 145840266059SGregory Neil Shapiro 145940266059SGregory Neil Shapiro /* 146040266059SGregory Neil Shapiro ** This is for coincidental and tailcoat piggybacking messages 146140266059SGregory Neil Shapiro ** to the same mail host. While the signatures are identical 146240266059SGregory Neil Shapiro ** (that's the MX-RR's are identical) we can do coincidental 146340266059SGregory Neil Shapiro ** piggybacking. We try hard for coattail piggybacking 146440266059SGregory Neil Shapiro ** with the same mail host when the next recipient has the 146540266059SGregory Neil Shapiro ** same host at lowest preference. It may be that this 146640266059SGregory Neil Shapiro ** won't work out, so 'skip_back' is maintained if a backup 146740266059SGregory Neil Shapiro ** to coincidental piggybacking or full signature must happen. 146840266059SGregory Neil Shapiro */ 146940266059SGregory Neil Shapiro 147040266059SGregory Neil Shapiro ret = firstto == to ? HS_MATCH_FULL : 147140266059SGregory Neil Shapiro coloncmp(to->q_signature, firstsig); 147240266059SGregory Neil Shapiro if (ret == HS_MATCH_FULL) 147340266059SGregory Neil Shapiro skip_back = to; 147440266059SGregory Neil Shapiro else if (ret == HS_MATCH_NO) 147506f25ae9SGregory Neil Shapiro break; 147606f25ae9SGregory Neil Shapiro 147740266059SGregory Neil Shapiro if (!clever) 147840266059SGregory Neil Shapiro { 147940266059SGregory Neil Shapiro /* avoid overflowing tobuf */ 148040266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 148140266059SGregory Neil Shapiro if (strsize > TOBUFSIZE) 148240266059SGregory Neil Shapiro break; 148340266059SGregory Neil Shapiro } 148440266059SGregory Neil Shapiro 148506f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt) 148606f25ae9SGregory Neil Shapiro break; 1487c2aa98e2SPeter Wemm 1488c2aa98e2SPeter Wemm if (tTd(10, 1)) 1489c2aa98e2SPeter Wemm { 149040266059SGregory Neil Shapiro sm_dprintf("\nsend to "); 149140266059SGregory Neil Shapiro printaddr(to, false); 1492c2aa98e2SPeter Wemm } 1493c2aa98e2SPeter Wemm 1494c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */ 1495c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 149640266059SGregory Neil Shapiro # if HASSETUSERCONTEXT 1497c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to); 149840266059SGregory Neil Shapiro # else /* HASSETUSERCONTEXT */ 149940266059SGregory Neil Shapiro ctladdr = getctladdr(to); 150040266059SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 1501c2aa98e2SPeter Wemm 1502c2aa98e2SPeter Wemm if (tTd(10, 2)) 1503c2aa98e2SPeter Wemm { 150440266059SGregory Neil Shapiro sm_dprintf("ctladdr="); 150540266059SGregory Neil Shapiro printaddr(ctladdr, false); 1506c2aa98e2SPeter Wemm } 1507c2aa98e2SPeter Wemm 1508c2aa98e2SPeter Wemm user = to->q_user; 1509c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 1510c2aa98e2SPeter Wemm 1511c2aa98e2SPeter Wemm /* 1512c2aa98e2SPeter Wemm ** Check to see that these people are allowed to 1513c2aa98e2SPeter Wemm ** talk to each other. 151442e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize. 1515c2aa98e2SPeter Wemm */ 1516c2aa98e2SPeter Wemm 151742e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 && 151842e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 1519c2aa98e2SPeter Wemm { 1520c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 1521c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 1522c2aa98e2SPeter Wemm to->q_status = "5.2.3"; 1523c2aa98e2SPeter Wemm else 1524c2aa98e2SPeter Wemm to->q_status = "5.3.4"; 152540266059SGregory Neil Shapiro 152606f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */ 152706f25ae9SGregory Neil Shapiro usrerrenh(to->q_status, 152806f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 152906f25ae9SGregory Neil Shapiro m->m_maxsize); 153040266059SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, false); 153106f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m, 153240266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1533c2aa98e2SPeter Wemm continue; 1534c2aa98e2SPeter Wemm } 1535602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 153640266059SGregory Neil Shapiro ovr = true; 1537c2aa98e2SPeter Wemm 1538c2aa98e2SPeter Wemm /* do config file checking of compatibility */ 153940266059SGregory Neil Shapiro #if _FFR_QUARANTINE 154040266059SGregory Neil Shapiro quarantine = (e->e_quarmsg != NULL); 154140266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 154206f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 154340266059SGregory Neil Shapiro e, true, true, 3, NULL, e->e_id); 1544c2aa98e2SPeter Wemm if (rcode == EX_OK) 1545c2aa98e2SPeter Wemm { 1546065a643dSPeter Wemm /* do in-code checking if not discarding */ 1547065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags)) 154806f25ae9SGregory Neil Shapiro { 1549c2aa98e2SPeter Wemm rcode = checkcompat(to, e); 155040266059SGregory Neil Shapiro ovr = false; 155106f25ae9SGregory Neil Shapiro } 1552c2aa98e2SPeter Wemm } 1553c2aa98e2SPeter Wemm if (rcode != EX_OK) 1554c2aa98e2SPeter Wemm { 155506f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr); 155606f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, 155740266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1558c2aa98e2SPeter Wemm continue; 1559c2aa98e2SPeter Wemm } 156040266059SGregory Neil Shapiro #if _FFR_QUARANTINE 156140266059SGregory Neil Shapiro if (!quarantine && e->e_quarmsg != NULL) 156240266059SGregory Neil Shapiro { 156340266059SGregory Neil Shapiro /* 156440266059SGregory Neil Shapiro ** check_compat or checkcompat() has tried 156540266059SGregory Neil Shapiro ** to quarantine but that isn't supported. 156640266059SGregory Neil Shapiro ** Revert the attempt. 156740266059SGregory Neil Shapiro */ 156840266059SGregory Neil Shapiro 156940266059SGregory Neil Shapiro e->e_quarmsg = NULL; 157040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 157140266059SGregory Neil Shapiro macid("{quarantine}"), ""); 157240266059SGregory Neil Shapiro } 157340266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 1574065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 1575065a643dSPeter Wemm { 1576065a643dSPeter Wemm if (tTd(10, 5)) 1577065a643dSPeter Wemm { 157840266059SGregory Neil Shapiro sm_dprintf("deliver: discarding recipient "); 157940266059SGregory Neil Shapiro printaddr(to, false); 1580065a643dSPeter Wemm } 1581065a643dSPeter Wemm 158206f25ae9SGregory Neil Shapiro /* pretend the message was sent */ 158306f25ae9SGregory Neil Shapiro /* XXX should we log something here? */ 158406f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED; 158506f25ae9SGregory Neil Shapiro 1586065a643dSPeter Wemm /* 1587065a643dSPeter Wemm ** Remove discard bit to prevent discard of 158806f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the 158906f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before 159006f25ae9SGregory Neil Shapiro ** we get here. 1591065a643dSPeter Wemm */ 1592065a643dSPeter Wemm 159306f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD; 1594065a643dSPeter Wemm continue; 1595065a643dSPeter Wemm } 1596c2aa98e2SPeter Wemm 1597c2aa98e2SPeter Wemm /* 1598c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb 1599c2aa98e2SPeter Wemm ** about them. 1600c2aa98e2SPeter Wemm */ 1601c2aa98e2SPeter Wemm 1602c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags)) 1603c2aa98e2SPeter Wemm { 1604c2aa98e2SPeter Wemm stripquotes(user); 1605c2aa98e2SPeter Wemm stripquotes(host); 1606c2aa98e2SPeter Wemm } 1607c2aa98e2SPeter Wemm 1608c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */ 1609c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|') 1610c2aa98e2SPeter Wemm user++; 1611c2aa98e2SPeter Wemm 1612c2aa98e2SPeter Wemm /* 1613c2aa98e2SPeter Wemm ** If an error message has already been given, don't 1614c2aa98e2SPeter Wemm ** bother to send to this address. 1615c2aa98e2SPeter Wemm ** 1616c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer 1617c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that 1618c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail. 1619c2aa98e2SPeter Wemm */ 1620c2aa98e2SPeter Wemm 162106f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 1622c2aa98e2SPeter Wemm continue; 1623c2aa98e2SPeter Wemm 1624c2aa98e2SPeter Wemm /* 1625c2aa98e2SPeter Wemm ** See if this user name is "special". 1626c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this 1627c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note 1628c2aa98e2SPeter Wemm ** that this type of addresses is not processed along 1629c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person. 1630c2aa98e2SPeter Wemm */ 1631c2aa98e2SPeter Wemm 1632c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0) 1633c2aa98e2SPeter Wemm { 163440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); 1635c2aa98e2SPeter Wemm p = to->q_home; 1636c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1637c2aa98e2SPeter Wemm p = ctladdr->q_home; 163840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); 1639c2aa98e2SPeter Wemm expand(m->m_argv[1], buf, sizeof buf, e); 1640c2aa98e2SPeter Wemm if (strlen(buf) > 0) 1641c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 1642c2aa98e2SPeter Wemm else 1643c2aa98e2SPeter Wemm { 1644c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s", 1645c2aa98e2SPeter Wemm m->m_name); 1646c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1647c2aa98e2SPeter Wemm } 164806f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL, 164940266059SGregory Neil Shapiro ctladdr, xstart, e, to); 165040266059SGregory Neil Shapiro markfailure(e, to, NULL, rcode, true); 1651c2aa98e2SPeter Wemm e->e_nsent++; 1652c2aa98e2SPeter Wemm if (rcode == EX_OK) 1653c2aa98e2SPeter Wemm { 165406f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 1655c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 1656c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 1657c2aa98e2SPeter Wemm { 1658c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 1659c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 166040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, 166140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 166240266059SGregory Neil Shapiro "%s... Successfully delivered\n", 1663c2aa98e2SPeter Wemm to->q_paddr); 1664c2aa98e2SPeter Wemm } 1665c2aa98e2SPeter Wemm } 1666c2aa98e2SPeter Wemm to->q_statdate = curtime(); 166740266059SGregory Neil Shapiro markstats(e, to, STATS_NORMAL); 1668c2aa98e2SPeter Wemm continue; 1669c2aa98e2SPeter Wemm } 1670c2aa98e2SPeter Wemm 1671c2aa98e2SPeter Wemm /* 1672c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer 1673c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients. 1674c2aa98e2SPeter Wemm */ 1675c2aa98e2SPeter Wemm 1676c2aa98e2SPeter Wemm /* link together the chain of recipients */ 1677c2aa98e2SPeter Wemm to->q_tchain = tochain; 1678c2aa98e2SPeter Wemm tochain = to; 167906f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]"; 168006f25ae9SGregory Neil Shapiro 168140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */ 1682c2aa98e2SPeter Wemm p = to->q_home; 1683c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1684c2aa98e2SPeter Wemm p = ctladdr->q_home; 168540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */ 1686c2aa98e2SPeter Wemm 168706f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */ 168806f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags)) 168906f25ae9SGregory Neil Shapiro { 169006f25ae9SGregory Neil Shapiro char notify[MAXLINE]; 169106f25ae9SGregory Neil Shapiro 169206f25ae9SGregory Neil Shapiro notify[0] = '\0'; 169306f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags)) 169440266059SGregory Neil Shapiro (void) sm_strlcat(notify, "SUCCESS,", 169506f25ae9SGregory Neil Shapiro sizeof notify); 169606f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags)) 169740266059SGregory Neil Shapiro (void) sm_strlcat(notify, "FAILURE,", 169806f25ae9SGregory Neil Shapiro sizeof notify); 169906f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags)) 170040266059SGregory Neil Shapiro (void) sm_strlcat(notify, "DELAY,", 170140266059SGregory Neil Shapiro sizeof notify); 170206f25ae9SGregory Neil Shapiro 170306f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */ 170406f25ae9SGregory Neil Shapiro if (notify[0] == '\0') 170540266059SGregory Neil Shapiro (void) sm_strlcat(notify, "NEVER", 170640266059SGregory Neil Shapiro sizeof notify); 170706f25ae9SGregory Neil Shapiro else 170806f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0'; 170906f25ae9SGregory Neil Shapiro 171040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 171140266059SGregory Neil Shapiro macid("{dsn_notify}"), notify); 171206f25ae9SGregory Neil Shapiro } 171306f25ae9SGregory Neil Shapiro else 171440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 171540266059SGregory Neil Shapiro macid("{dsn_notify}"), NULL); 171606f25ae9SGregory Neil Shapiro 1717c2aa98e2SPeter Wemm /* 1718c2aa98e2SPeter Wemm ** Expand out this user into argument list. 1719c2aa98e2SPeter Wemm */ 1720c2aa98e2SPeter Wemm 1721c2aa98e2SPeter Wemm if (!clever) 1722c2aa98e2SPeter Wemm { 1723c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 172440266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1725c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2]) 1726c2aa98e2SPeter Wemm { 1727c2aa98e2SPeter Wemm /* allow some space for trailing parms */ 1728c2aa98e2SPeter Wemm break; 1729c2aa98e2SPeter Wemm } 1730c2aa98e2SPeter Wemm } 1731c2aa98e2SPeter Wemm } 1732c2aa98e2SPeter Wemm 1733c2aa98e2SPeter Wemm /* see if any addresses still exist */ 173406f25ae9SGregory Neil Shapiro if (tochain == NULL) 1735c2aa98e2SPeter Wemm { 173640266059SGregory Neil Shapiro rcode = 0; 173740266059SGregory Neil Shapiro goto cleanup; 1738c2aa98e2SPeter Wemm } 1739c2aa98e2SPeter Wemm 1740c2aa98e2SPeter Wemm /* print out messages as full list */ 174140266059SGregory Neil Shapiro strsize = 1; 174206f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 174340266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 174440266059SGregory Neil Shapiro if (strsize < TOBUFSIZE) 174540266059SGregory Neil Shapiro strsize = TOBUFSIZE; 174640266059SGregory Neil Shapiro if (strsize > tobufsize) 174706f25ae9SGregory Neil Shapiro { 174840266059SGregory Neil Shapiro SM_FREE_CLR(tobuf); 174940266059SGregory Neil Shapiro tobuf = sm_pmalloc_x(strsize); 175040266059SGregory Neil Shapiro tobufsize = strsize; 175106f25ae9SGregory Neil Shapiro } 175240266059SGregory Neil Shapiro p = tobuf; 175340266059SGregory Neil Shapiro *p = '\0'; 175406f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 175506f25ae9SGregory Neil Shapiro { 175640266059SGregory Neil Shapiro (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2, 175740266059SGregory Neil Shapiro ",", to->q_paddr); 175840266059SGregory Neil Shapiro p += strlen(p); 175906f25ae9SGregory Neil Shapiro } 1760c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 1761c2aa98e2SPeter Wemm 1762c2aa98e2SPeter Wemm /* 1763c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter. 1764c2aa98e2SPeter Wemm */ 1765c2aa98e2SPeter Wemm 176640266059SGregory Neil Shapiro if (!clever) 176740266059SGregory Neil Shapiro { 176840266059SGregory Neil Shapiro while (*++mvp != NULL) 1769c2aa98e2SPeter Wemm { 1770c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 177140266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1772c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV]) 177306f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s", 177406f25ae9SGregory Neil Shapiro pv[0]); 1775c2aa98e2SPeter Wemm } 177640266059SGregory Neil Shapiro } 1777c2aa98e2SPeter Wemm *pvp++ = NULL; 1778c2aa98e2SPeter Wemm 1779c2aa98e2SPeter Wemm /* 1780c2aa98e2SPeter Wemm ** Call the mailer. 1781c2aa98e2SPeter Wemm ** The argument vector gets built, pipes 1782c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as 1783c2aa98e2SPeter Wemm ** appropriate. 1784c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up. 1785c2aa98e2SPeter Wemm */ 1786c2aa98e2SPeter Wemm 1787c2aa98e2SPeter Wemm /* XXX this seems a bit wierd */ 1788c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 1789c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags)) 1790c2aa98e2SPeter Wemm ctladdr = &e->e_from; 1791c2aa98e2SPeter Wemm 1792c2aa98e2SPeter Wemm #if NAMED_BIND 1793c2aa98e2SPeter Wemm if (ConfigLevel < 2) 1794c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 179506f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1796c2aa98e2SPeter Wemm 1797c2aa98e2SPeter Wemm if (tTd(11, 1)) 1798c2aa98e2SPeter Wemm { 179940266059SGregory Neil Shapiro sm_dprintf("openmailer:"); 1800c2aa98e2SPeter Wemm printav(pv); 1801c2aa98e2SPeter Wemm } 1802c2aa98e2SPeter Wemm errno = 0; 1803602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 1804c2aa98e2SPeter Wemm CurHostName = NULL; 1805c2aa98e2SPeter Wemm 1806c2aa98e2SPeter Wemm /* 1807c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC 1808c2aa98e2SPeter Wemm ** connection. 1809c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be 1810c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a 1811c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC. 1812c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out. 1813c2aa98e2SPeter Wemm */ 1814c2aa98e2SPeter Wemm 1815c2aa98e2SPeter Wemm curhost = NULL; 1816c2aa98e2SPeter Wemm SmtpPhase = NULL; 1817c2aa98e2SPeter Wemm mci = NULL; 1818c2aa98e2SPeter Wemm 1819c2aa98e2SPeter Wemm #if XDEBUG 1820c2aa98e2SPeter Wemm { 1821c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 1822c2aa98e2SPeter Wemm 1823c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 182440266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)", 182540266059SGregory Neil Shapiro shortenstring(e->e_to, MAXSHORTSTR), 182640266059SGregory Neil Shapiro m->m_name); 1827c2aa98e2SPeter Wemm checkfd012(wbuf); 1828c2aa98e2SPeter Wemm } 182906f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1830c2aa98e2SPeter Wemm 1831c2aa98e2SPeter Wemm /* check for 8-bit available */ 1832c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 1833c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) && 1834c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 1835c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 1836c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 1837c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 1838c2aa98e2SPeter Wemm { 1839c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 184006f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 184106f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 184206f25ae9SGregory Neil Shapiro rcode = EX_DATAERR; 1843c2aa98e2SPeter Wemm goto give_up; 1844c2aa98e2SPeter Wemm } 1845c2aa98e2SPeter Wemm 1846c2aa98e2SPeter Wemm if (tTd(62, 8)) 1847c2aa98e2SPeter Wemm checkfds("before delivery"); 1848c2aa98e2SPeter Wemm 1849c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */ 1850c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0) 1851c2aa98e2SPeter Wemm { 185240266059SGregory Neil Shapiro #if _FFR_CACHE_LPC 185340266059SGregory Neil Shapiro if (clever) 185440266059SGregory Neil Shapiro { 185540266059SGregory Neil Shapiro /* flush any expired connections */ 185640266059SGregory Neil Shapiro (void) mci_scan(NULL); 185740266059SGregory Neil Shapiro 185840266059SGregory Neil Shapiro /* try to get a cached connection or just a slot */ 185940266059SGregory Neil Shapiro mci = mci_get(m->m_name, m); 186040266059SGregory Neil Shapiro if (mci->mci_host == NULL) 186140266059SGregory Neil Shapiro mci->mci_host = m->m_name; 186240266059SGregory Neil Shapiro CurHostName = mci->mci_host; 186340266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED) 186440266059SGregory Neil Shapiro { 186540266059SGregory Neil Shapiro message("Using cached SMTP/LPC connection for %s...", 186640266059SGregory Neil Shapiro m->m_name); 186740266059SGregory Neil Shapiro mci->mci_deliveries++; 186840266059SGregory Neil Shapiro goto do_transfer; 186940266059SGregory Neil Shapiro } 187040266059SGregory Neil Shapiro } 187140266059SGregory Neil Shapiro else 187240266059SGregory Neil Shapiro { 187340266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 187440266059SGregory Neil Shapiro } 187540266059SGregory Neil Shapiro mci->mci_in = smioin; 187640266059SGregory Neil Shapiro mci->mci_out = smioout; 187740266059SGregory Neil Shapiro mci->mci_mailer = m; 187840266059SGregory Neil Shapiro mci->mci_host = m->m_name; 187940266059SGregory Neil Shapiro if (clever) 188040266059SGregory Neil Shapiro { 188140266059SGregory Neil Shapiro mci->mci_state = MCIS_OPENING; 188240266059SGregory Neil Shapiro mci_cache(mci); 188340266059SGregory Neil Shapiro } 188440266059SGregory Neil Shapiro else 188540266059SGregory Neil Shapiro mci->mci_state = MCIS_OPEN; 188640266059SGregory Neil Shapiro #else /* _FFR_CACHE_LPC */ 188740266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 188840266059SGregory Neil Shapiro mci->mci_in = smioin; 188940266059SGregory Neil Shapiro mci->mci_out = smioout; 1890c2aa98e2SPeter Wemm mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 1891c2aa98e2SPeter Wemm mci->mci_mailer = m; 189240266059SGregory Neil Shapiro #endif /* _FFR_CACHE_LPC */ 1893c2aa98e2SPeter Wemm } 189440266059SGregory Neil Shapiro else if (strcmp(m->m_mailer, "[IPC]") == 0) 1895c2aa98e2SPeter Wemm { 1896c2aa98e2SPeter Wemm register int i; 1897c2aa98e2SPeter Wemm 1898c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1899c2aa98e2SPeter Wemm { 190006f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer); 1901c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1902c2aa98e2SPeter Wemm goto give_up; 1903c2aa98e2SPeter Wemm } 1904c2aa98e2SPeter Wemm 190506f25ae9SGregory Neil Shapiro # if NETUNIX 190606f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0) 190706f25ae9SGregory Neil Shapiro { 190806f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost"; 190906f25ae9SGregory Neil Shapiro mux_path = pv[1]; 191006f25ae9SGregory Neil Shapiro } 191106f25ae9SGregory Neil Shapiro else 191206f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 191306f25ae9SGregory Neil Shapiro { 1914c2aa98e2SPeter Wemm CurHostName = pv[1]; 191506f25ae9SGregory Neil Shapiro curhost = hostsignature(m, pv[1]); 191606f25ae9SGregory Neil Shapiro } 1917c2aa98e2SPeter Wemm 1918c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0') 1919c2aa98e2SPeter Wemm { 1920c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]); 1921c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1922c2aa98e2SPeter Wemm goto give_up; 1923c2aa98e2SPeter Wemm } 1924c2aa98e2SPeter Wemm 1925c2aa98e2SPeter Wemm if (!clever) 1926c2aa98e2SPeter Wemm { 192706f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC"); 1928c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1929c2aa98e2SPeter Wemm goto give_up; 1930c2aa98e2SPeter Wemm } 193106f25ae9SGregory Neil Shapiro if (pv[2] != NULL 193206f25ae9SGregory Neil Shapiro # if NETUNIX 193306f25ae9SGregory Neil Shapiro && mux_path == NULL 193406f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 193506f25ae9SGregory Neil Shapiro ) 1936c2aa98e2SPeter Wemm { 193740266059SGregory Neil Shapiro port = htons((unsigned short) atoi(pv[2])); 1938c2aa98e2SPeter Wemm if (port == 0) 1939c2aa98e2SPeter Wemm { 194006f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME 194106f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]); 194206f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */ 1943c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp"); 1944c2aa98e2SPeter Wemm 1945c2aa98e2SPeter Wemm if (sp == NULL) 1946c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]); 1947c2aa98e2SPeter Wemm else 1948c2aa98e2SPeter Wemm port = sp->s_port; 194906f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */ 1950c2aa98e2SPeter Wemm } 1951c2aa98e2SPeter Wemm } 1952c2aa98e2SPeter Wemm 195306f25ae9SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m); 195440266059SGregory Neil Shapiro if (TimeOuts.to_aconnect > 0) 195540266059SGregory Neil Shapiro enough = curtime() + TimeOuts.to_aconnect; 195606f25ae9SGregory Neil Shapiro tryhost: 195706f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts) 195806f25ae9SGregory Neil Shapiro { 195906f25ae9SGregory Neil Shapiro char sep = ':'; 196006f25ae9SGregory Neil Shapiro char *endp; 196106f25ae9SGregory Neil Shapiro static char hostbuf[MAXNAME + 1]; 196206f25ae9SGregory Neil Shapiro 196306f25ae9SGregory Neil Shapiro # if NETINET6 196406f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '[') 196506f25ae9SGregory Neil Shapiro { 196606f25ae9SGregory Neil Shapiro endp = strchr(mxhosts[hostnum] + 1, ']'); 196706f25ae9SGregory Neil Shapiro if (endp != NULL) 196806f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 196906f25ae9SGregory Neil Shapiro } 197006f25ae9SGregory Neil Shapiro else 197106f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 197206f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 197306f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 197406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 197506f25ae9SGregory Neil Shapiro if (endp != NULL) 197606f25ae9SGregory Neil Shapiro { 197706f25ae9SGregory Neil Shapiro sep = *endp; 197806f25ae9SGregory Neil Shapiro *endp = '\0'; 197906f25ae9SGregory Neil Shapiro } 198006f25ae9SGregory Neil Shapiro 198140266059SGregory Neil Shapiro if (hostnum == 1 && skip_back != NULL) 198240266059SGregory Neil Shapiro { 198340266059SGregory Neil Shapiro /* 198440266059SGregory Neil Shapiro ** Coattail piggybacking is no longer an 198540266059SGregory Neil Shapiro ** option with the mail host next to be tried 198640266059SGregory Neil Shapiro ** no longer the lowest MX preference 198740266059SGregory Neil Shapiro ** (hostnum == 1 meaning we're on the second 198840266059SGregory Neil Shapiro ** preference). We do not try to coattail 198940266059SGregory Neil Shapiro ** piggyback more than the first MX preference. 199040266059SGregory Neil Shapiro ** Revert 'tochain' to last location for 199140266059SGregory Neil Shapiro ** coincidental piggybacking. This works this 199240266059SGregory Neil Shapiro ** easily because the q_tchain kept getting 199340266059SGregory Neil Shapiro ** added to the top of the linked list. 199440266059SGregory Neil Shapiro */ 199540266059SGregory Neil Shapiro 199640266059SGregory Neil Shapiro tochain = skip_back; 199740266059SGregory Neil Shapiro } 199840266059SGregory Neil Shapiro 199906f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0') 2000c2aa98e2SPeter Wemm { 2001c2aa98e2SPeter Wemm syserr("deliver: null host name in signature"); 200206f25ae9SGregory Neil Shapiro hostnum++; 200306f25ae9SGregory Neil Shapiro if (endp != NULL) 200406f25ae9SGregory Neil Shapiro *endp = sep; 2005c2aa98e2SPeter Wemm continue; 2006c2aa98e2SPeter Wemm } 200740266059SGregory Neil Shapiro (void) sm_strlcpy(hostbuf, mxhosts[hostnum], 200806f25ae9SGregory Neil Shapiro sizeof hostbuf); 200906f25ae9SGregory Neil Shapiro hostnum++; 201006f25ae9SGregory Neil Shapiro if (endp != NULL) 201106f25ae9SGregory Neil Shapiro *endp = sep; 2012c2aa98e2SPeter Wemm 2013c2aa98e2SPeter Wemm /* see if we already know that this host is fried */ 2014c2aa98e2SPeter Wemm CurHostName = hostbuf; 2015c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m); 2016c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2017c2aa98e2SPeter Wemm { 201840266059SGregory Neil Shapiro char *type; 201940266059SGregory Neil Shapiro 2020c2aa98e2SPeter Wemm if (tTd(11, 1)) 2021c2aa98e2SPeter Wemm { 202240266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 202340266059SGregory Neil Shapiro mci_dump(mci, false); 2024c2aa98e2SPeter Wemm } 2025c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 202640266059SGregory Neil Shapiro if (bitnset(M_LMTP, m->m_flags)) 202740266059SGregory Neil Shapiro type = "L"; 202840266059SGregory Neil Shapiro else if (bitset(MCIF_ESMTP, mci->mci_flags)) 202940266059SGregory Neil Shapiro type = "ES"; 203040266059SGregory Neil Shapiro else 203140266059SGregory Neil Shapiro type = "S"; 203240266059SGregory Neil Shapiro message("Using cached %sMTP connection to %s via %s...", 203340266059SGregory Neil Shapiro type, hostbuf, m->m_name); 203406f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2035c2aa98e2SPeter Wemm break; 2036c2aa98e2SPeter Wemm } 2037c2aa98e2SPeter Wemm mci->mci_mailer = m; 2038c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK) 2039c2aa98e2SPeter Wemm { 2040c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL) 204140266059SGregory Neil Shapiro goodmxfound = true; 2042c2aa98e2SPeter Wemm continue; 2043c2aa98e2SPeter Wemm } 2044c2aa98e2SPeter Wemm 2045c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK) 2046c2aa98e2SPeter Wemm { 2047c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 204840266059SGregory Neil Shapiro goodmxfound = true; 2049c2aa98e2SPeter Wemm continue; 2050c2aa98e2SPeter Wemm } 2051c2aa98e2SPeter Wemm 2052c2aa98e2SPeter Wemm /* try the connection */ 205340266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %s", 205406f25ae9SGregory Neil Shapiro qid_printname(e), 205506f25ae9SGregory Neil Shapiro hostbuf, "user open"); 205606f25ae9SGregory Neil Shapiro # if NETUNIX 205706f25ae9SGregory Neil Shapiro if (mux_path != NULL) 205806f25ae9SGregory Neil Shapiro { 205906f25ae9SGregory Neil Shapiro message("Connecting to %s via %s...", 206006f25ae9SGregory Neil Shapiro mux_path, m->m_name); 206140266059SGregory Neil Shapiro i = makeconnection_ds((char *) mux_path, mci); 206206f25ae9SGregory Neil Shapiro } 206306f25ae9SGregory Neil Shapiro else 206406f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 206506f25ae9SGregory Neil Shapiro { 2066c2aa98e2SPeter Wemm if (port == 0) 2067c2aa98e2SPeter Wemm message("Connecting to %s via %s...", 2068c2aa98e2SPeter Wemm hostbuf, m->m_name); 2069c2aa98e2SPeter Wemm else 2070c2aa98e2SPeter Wemm message("Connecting to %s port %d via %s...", 207106f25ae9SGregory Neil Shapiro hostbuf, ntohs(port), 207206f25ae9SGregory Neil Shapiro m->m_name); 207340266059SGregory Neil Shapiro i = makeconnection(hostbuf, port, mci, e, 207440266059SGregory Neil Shapiro enough); 207506f25ae9SGregory Neil Shapiro } 20768774250cSGregory Neil Shapiro mci->mci_errno = errno; 2077c2aa98e2SPeter Wemm mci->mci_lastuse = curtime(); 207806f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0; 2079c2aa98e2SPeter Wemm mci->mci_exitstat = i; 2080c2aa98e2SPeter Wemm # if NAMED_BIND 2081c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 208206f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */ 208340266059SGregory Neil Shapiro 208440266059SGregory Neil Shapiro /* 208540266059SGregory Neil Shapiro ** Have we tried long enough to get a connection? 208640266059SGregory Neil Shapiro ** If yes, skip to the fallback MX hosts 208740266059SGregory Neil Shapiro ** (if existent). 208840266059SGregory Neil Shapiro */ 208940266059SGregory Neil Shapiro 209040266059SGregory Neil Shapiro if (enough > 0 && mci->mci_lastuse >= enough) 209140266059SGregory Neil Shapiro { 209240266059SGregory Neil Shapiro int h; 209340266059SGregory Neil Shapiro # if NAMED_BIND 209440266059SGregory Neil Shapiro extern int NumFallBackMXHosts; 209540266059SGregory Neil Shapiro # else /* NAMED_BIND */ 209640266059SGregory Neil Shapiro const int NumFallBackMXHosts = 0; 209740266059SGregory Neil Shapiro # endif /* NAMED_BIND */ 209840266059SGregory Neil Shapiro 209940266059SGregory Neil Shapiro if (hostnum < nummxhosts && LogLevel > 9) 210040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 210140266059SGregory Neil Shapiro "Timeout.to_aconnect occurred before exhausting all addresses"); 210240266059SGregory Neil Shapiro 210340266059SGregory Neil Shapiro /* turn off timeout if fallback available */ 210440266059SGregory Neil Shapiro if (NumFallBackMXHosts > 0) 210540266059SGregory Neil Shapiro enough = 0; 210640266059SGregory Neil Shapiro 210740266059SGregory Neil Shapiro /* skip to a fallback MX host */ 210840266059SGregory Neil Shapiro h = nummxhosts - NumFallBackMXHosts; 210940266059SGregory Neil Shapiro if (hostnum < h) 211040266059SGregory Neil Shapiro hostnum = h; 211140266059SGregory Neil Shapiro } 2112c2aa98e2SPeter Wemm if (i == EX_OK) 2113c2aa98e2SPeter Wemm { 211440266059SGregory Neil Shapiro goodmxfound = true; 2115c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2116c2aa98e2SPeter Wemm mci_cache(mci); 2117c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 211840266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 211940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 212040266059SGregory Neil Shapiro "%05d === CONNECT %s\n", 212140266059SGregory Neil Shapiro (int) CurrentPid, 212240266059SGregory Neil Shapiro hostbuf); 2123c2aa98e2SPeter Wemm break; 2124c2aa98e2SPeter Wemm } 2125c2aa98e2SPeter Wemm else 2126c2aa98e2SPeter Wemm { 2127c2aa98e2SPeter Wemm if (tTd(11, 1)) 212840266059SGregory Neil Shapiro sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 2129c2aa98e2SPeter Wemm i, errno); 2130c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL) 213140266059SGregory Neil Shapiro goodmxfound = true; 2132c2aa98e2SPeter Wemm mci_unlock_host(mci); 2133c2aa98e2SPeter Wemm } 2134c2aa98e2SPeter Wemm 2135c2aa98e2SPeter Wemm /* enter status of this host */ 2136c2aa98e2SPeter Wemm setstat(i); 2137c2aa98e2SPeter Wemm 2138c2aa98e2SPeter Wemm /* should print some message here for -v mode */ 2139c2aa98e2SPeter Wemm } 2140c2aa98e2SPeter Wemm if (mci == NULL) 2141c2aa98e2SPeter Wemm { 2142c2aa98e2SPeter Wemm syserr("deliver: no host name"); 2143c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 2144c2aa98e2SPeter Wemm goto give_up; 2145c2aa98e2SPeter Wemm } 2146c2aa98e2SPeter Wemm mci->mci_pid = 0; 2147c2aa98e2SPeter Wemm } 2148c2aa98e2SPeter Wemm else 2149c2aa98e2SPeter Wemm { 2150c2aa98e2SPeter Wemm /* flush any expired connections */ 2151c2aa98e2SPeter Wemm (void) mci_scan(NULL); 2152c2aa98e2SPeter Wemm mci = NULL; 2153c2aa98e2SPeter Wemm 2154c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2155c2aa98e2SPeter Wemm { 2156c2aa98e2SPeter Wemm /* try to get a cached connection */ 2157c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m); 2158c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 2159c2aa98e2SPeter Wemm mci->mci_host = m->m_name; 2160c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 2161c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2162c2aa98e2SPeter Wemm { 2163c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...", 2164c2aa98e2SPeter Wemm m->m_name); 216506f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2166c2aa98e2SPeter Wemm goto do_transfer; 2167c2aa98e2SPeter Wemm } 2168c2aa98e2SPeter Wemm } 2169c2aa98e2SPeter Wemm 2170c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */ 2171c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0') 2172c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name); 2173c2aa98e2SPeter Wemm else 2174c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name); 2175c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 2176c2aa98e2SPeter Wemm { 2177c2aa98e2SPeter Wemm char **av; 2178c2aa98e2SPeter Wemm 217940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 218040266059SGregory Neil Shapiro "%05d === EXEC", (int) CurrentPid); 2181c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 218240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 218340266059SGregory Neil Shapiro SM_TIME_DEFAULT, " %s", 218440266059SGregory Neil Shapiro *av); 218540266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 218640266059SGregory Neil Shapiro "\n"); 2187c2aa98e2SPeter Wemm } 2188c2aa98e2SPeter Wemm 2189c2aa98e2SPeter Wemm #if XDEBUG 2190c2aa98e2SPeter Wemm checkfd012("before creating mail pipe"); 219106f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2192c2aa98e2SPeter Wemm 2193c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */ 2194c2aa98e2SPeter Wemm if (pipe(mpvect) < 0) 2195c2aa98e2SPeter Wemm { 2196c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)", 2197c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2198c2aa98e2SPeter Wemm if (tTd(11, 1)) 219940266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2200c2aa98e2SPeter Wemm rcode = EX_OSERR; 2201c2aa98e2SPeter Wemm goto give_up; 2202c2aa98e2SPeter Wemm } 2203c2aa98e2SPeter Wemm 2204c2aa98e2SPeter Wemm #if XDEBUG 2205c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */ 2206c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3) 2207c2aa98e2SPeter Wemm { 2208c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d", 2209c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 2210c2aa98e2SPeter Wemm mpvect[0], mpvect[1]); 221140266059SGregory Neil Shapiro printopenfds(true); 2212c2aa98e2SPeter Wemm if (tTd(11, 1)) 221340266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2214c2aa98e2SPeter Wemm rcode = EX_OSERR; 2215c2aa98e2SPeter Wemm goto give_up; 2216c2aa98e2SPeter Wemm } 2217c2aa98e2SPeter Wemm 2218c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */ 2219c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]"); 2220c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]"); 2221c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] || 2222c2aa98e2SPeter Wemm (e->e_lockfp != NULL && 222340266059SGregory Neil Shapiro (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 222440266059SGregory Neil Shapiro NULL) || 222540266059SGregory Neil Shapiro mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 222640266059SGregory Neil Shapiro NULL)))) 2227c2aa98e2SPeter Wemm { 2228c2aa98e2SPeter Wemm if (e->e_lockfp == NULL) 2229c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d", 2230c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2231c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]); 2232c2aa98e2SPeter Wemm else 2233c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 2234c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2235c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1], 223640266059SGregory Neil Shapiro sm_io_getinfo(e->e_lockfp, 223740266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL)); 2238c2aa98e2SPeter Wemm } 223906f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2240c2aa98e2SPeter Wemm 224106f25ae9SGregory Neil Shapiro /* create a return pipe */ 2242c2aa98e2SPeter Wemm if (pipe(rpvect) < 0) 2243c2aa98e2SPeter Wemm { 2244c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)", 2245c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2246c2aa98e2SPeter Wemm m->m_name); 2247c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2248c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2249c2aa98e2SPeter Wemm if (tTd(11, 1)) 225040266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2251c2aa98e2SPeter Wemm rcode = EX_OSERR; 2252c2aa98e2SPeter Wemm goto give_up; 2253c2aa98e2SPeter Wemm } 2254c2aa98e2SPeter Wemm #if XDEBUG 2255c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]"); 2256c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]"); 225706f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2258c2aa98e2SPeter Wemm 2259c2aa98e2SPeter Wemm /* 2260c2aa98e2SPeter Wemm ** Actually fork the mailer process. 2261c2aa98e2SPeter Wemm ** DOFORK is clever about retrying. 2262c2aa98e2SPeter Wemm ** 2263c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying 226406f25ae9SGregory Neil Shapiro ** around so that endmailer will get it. 2265c2aa98e2SPeter Wemm */ 2266c2aa98e2SPeter Wemm 226740266059SGregory Neil Shapiro if (e->e_xfp != NULL) /* for debugging */ 226840266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 226940266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 227040266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 227106f25ae9SGregory Neil Shapiro 227206f25ae9SGregory Neil Shapiro 2273c2aa98e2SPeter Wemm DOFORK(FORK); 2274c2aa98e2SPeter Wemm /* pid is set by DOFORK */ 227506f25ae9SGregory Neil Shapiro 2276c2aa98e2SPeter Wemm if (pid < 0) 2277c2aa98e2SPeter Wemm { 2278c2aa98e2SPeter Wemm /* failure */ 2279c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork", 2280c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2281c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2282c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2283c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2284c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2285c2aa98e2SPeter Wemm if (tTd(11, 1)) 228640266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2287c2aa98e2SPeter Wemm rcode = EX_OSERR; 2288c2aa98e2SPeter Wemm goto give_up; 2289c2aa98e2SPeter Wemm } 2290c2aa98e2SPeter Wemm else if (pid == 0) 2291c2aa98e2SPeter Wemm { 2292c2aa98e2SPeter Wemm int i; 229306f25ae9SGregory Neil Shapiro int save_errno; 229440266059SGregory Neil Shapiro int sff; 2295c2aa98e2SPeter Wemm int new_euid = NO_UID; 2296c2aa98e2SPeter Wemm int new_ruid = NO_UID; 2297c2aa98e2SPeter Wemm int new_gid = NO_GID; 229840266059SGregory Neil Shapiro char *user = NULL; 2299c2aa98e2SPeter Wemm struct stat stb; 2300c2aa98e2SPeter Wemm extern int DtableSize; 2301c2aa98e2SPeter Wemm 230240266059SGregory Neil Shapiro CurrentPid = getpid(); 230340266059SGregory Neil Shapiro 230413058a91SGregory Neil Shapiro /* clear the events to turn off SIGALRMs */ 230540266059SGregory Neil Shapiro sm_clear_events(); 230613058a91SGregory Neil Shapiro 23078774250cSGregory Neil Shapiro /* Reset global flags */ 23088774250cSGregory Neil Shapiro RestartRequest = NULL; 230940266059SGregory Neil Shapiro RestartWorkGroup = false; 23108774250cSGregory Neil Shapiro ShutdownRequest = NULL; 23118774250cSGregory Neil Shapiro PendingSignal = 0; 23128774250cSGregory Neil Shapiro 2313c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 231440266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, 231540266059SGregory Neil Shapiro SM_IO_WHAT_FD, 231640266059SGregory Neil Shapiro NULL)); 2317c2aa98e2SPeter Wemm 2318c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */ 231940266059SGregory Neil Shapiro (void) sm_signal(SIGALRM, sm_signal_noop); 232040266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 232140266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_IGN); 232240266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_IGN); 232340266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 232413058a91SGregory Neil Shapiro # ifdef SIGUSR1 232540266059SGregory Neil Shapiro (void) sm_signal(SIGUSR1, sm_signal_noop); 232613058a91SGregory Neil Shapiro # endif /* SIGUSR1 */ 2327c2aa98e2SPeter Wemm 2328c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 2329c2aa98e2SPeter Wemm stb.st_mode = 0; 2330c2aa98e2SPeter Wemm 2331c2aa98e2SPeter Wemm # if HASSETUSERCONTEXT 2332c2aa98e2SPeter Wemm /* 2333c2aa98e2SPeter Wemm ** Set user resources. 2334c2aa98e2SPeter Wemm */ 2335c2aa98e2SPeter Wemm 2336c2aa98e2SPeter Wemm if (contextaddr != NULL) 2337c2aa98e2SPeter Wemm { 2338c2aa98e2SPeter Wemm struct passwd *pwd; 2339c2aa98e2SPeter Wemm 2340c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL) 2341c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser); 2342c2aa98e2SPeter Wemm else 2343c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user); 2344c2aa98e2SPeter Wemm if (pwd != NULL) 2345c2aa98e2SPeter Wemm (void) setusercontext(NULL, 2346c2aa98e2SPeter Wemm pwd, pwd->pw_uid, 2347c2aa98e2SPeter Wemm LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); 2348c2aa98e2SPeter Wemm } 234906f25ae9SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 2350c2aa98e2SPeter Wemm 235140266059SGregory Neil Shapiro #if HASNICE 2352c2aa98e2SPeter Wemm /* tweak niceness */ 2353c2aa98e2SPeter Wemm if (m->m_nice != 0) 235406f25ae9SGregory Neil Shapiro (void) nice(m->m_nice); 235540266059SGregory Neil Shapiro #endif /* HASNICE */ 2356c2aa98e2SPeter Wemm 2357c2aa98e2SPeter Wemm /* reset group id */ 2358c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 2359c2aa98e2SPeter Wemm new_gid = m->m_gid; 2360c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode)) 2361c2aa98e2SPeter Wemm new_gid = stb.st_gid; 2362c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0) 2363c2aa98e2SPeter Wemm { 2364c2aa98e2SPeter Wemm if (!DontInitGroups) 2365c2aa98e2SPeter Wemm { 236640266059SGregory Neil Shapiro user = ctladdr->q_ruser; 236740266059SGregory Neil Shapiro if (user == NULL) 236840266059SGregory Neil Shapiro user = ctladdr->q_user; 2369c2aa98e2SPeter Wemm 237040266059SGregory Neil Shapiro if (initgroups(user, 237140266059SGregory Neil Shapiro ctladdr->q_gid) == -1 237240266059SGregory Neil Shapiro && suidwarn) 237306f25ae9SGregory Neil Shapiro { 2374c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 237540266059SGregory Neil Shapiro user, ctladdr->q_gid); 237606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 237706f25ae9SGregory Neil Shapiro } 2378c2aa98e2SPeter Wemm } 2379c2aa98e2SPeter Wemm else 2380c2aa98e2SPeter Wemm { 2381c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2382c2aa98e2SPeter Wemm 2383c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid; 238440266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 238540266059SGregory Neil Shapiro && suidwarn) 238606f25ae9SGregory Neil Shapiro { 2387c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 238806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 238906f25ae9SGregory Neil Shapiro } 2390c2aa98e2SPeter Wemm } 2391c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid; 2392c2aa98e2SPeter Wemm } 2393c2aa98e2SPeter Wemm else 2394c2aa98e2SPeter Wemm { 2395c2aa98e2SPeter Wemm if (!DontInitGroups) 2396c2aa98e2SPeter Wemm { 239740266059SGregory Neil Shapiro user = DefUser; 239840266059SGregory Neil Shapiro if (initgroups(DefUser, DefGid) == -1 && 239940266059SGregory Neil Shapiro suidwarn) 240006f25ae9SGregory Neil Shapiro { 2401c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 2402c2aa98e2SPeter Wemm DefUser, DefGid); 240306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 240406f25ae9SGregory Neil Shapiro } 2405c2aa98e2SPeter Wemm } 2406c2aa98e2SPeter Wemm else 2407c2aa98e2SPeter Wemm { 2408c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2409c2aa98e2SPeter Wemm 2410c2aa98e2SPeter Wemm gidset[0] = DefGid; 241140266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 241240266059SGregory Neil Shapiro && suidwarn) 241306f25ae9SGregory Neil Shapiro { 2414c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 241506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 241606f25ae9SGregory Neil Shapiro } 2417c2aa98e2SPeter Wemm } 2418c2aa98e2SPeter Wemm if (m->m_gid == 0) 2419c2aa98e2SPeter Wemm new_gid = DefGid; 2420c2aa98e2SPeter Wemm else 2421c2aa98e2SPeter Wemm new_gid = m->m_gid; 2422c2aa98e2SPeter Wemm } 242306f25ae9SGregory Neil Shapiro if (new_gid != NO_GID) 242406f25ae9SGregory Neil Shapiro { 242506f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 242606f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) && 242706f25ae9SGregory Neil Shapiro new_gid != getgid() && 242806f25ae9SGregory Neil Shapiro new_gid != getegid()) 242906f25ae9SGregory Neil Shapiro { 243006f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 243140266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d", 243240266059SGregory Neil Shapiro (int) RunAsUid, (int) new_gid, 243340266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 243406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 243506f25ae9SGregory Neil Shapiro } 243606f25ae9SGregory Neil Shapiro 243706f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn) 243806f25ae9SGregory Neil Shapiro { 2439c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed", 2440c2aa98e2SPeter Wemm (long) new_gid); 244106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 244206f25ae9SGregory Neil Shapiro } 244306f25ae9SGregory Neil Shapiro } 244406f25ae9SGregory Neil Shapiro 244506f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */ 244606f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL) 244706f25ae9SGregory Neil Shapiro { 244806f25ae9SGregory Neil Shapiro expand(m->m_rootdir, buf, sizeof buf, e); 244906f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 245040266059SGregory Neil Shapiro sm_dprintf("openmailer: chroot %s\n", 245106f25ae9SGregory Neil Shapiro buf); 245206f25ae9SGregory Neil Shapiro if (chroot(buf) < 0) 245306f25ae9SGregory Neil Shapiro { 245406f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)", 245506f25ae9SGregory Neil Shapiro buf); 245606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 245706f25ae9SGregory Neil Shapiro } 245806f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 245906f25ae9SGregory Neil Shapiro { 246006f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)"); 246106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 246206f25ae9SGregory Neil Shapiro } 246306f25ae9SGregory Neil Shapiro } 2464c2aa98e2SPeter Wemm 2465c2aa98e2SPeter Wemm /* reset user id */ 2466c2aa98e2SPeter Wemm endpwent(); 246740266059SGregory Neil Shapiro sm_mbdb_terminate(); 2468c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 246913058a91SGregory Neil Shapiro { 2470c2aa98e2SPeter Wemm new_euid = m->m_uid; 247113058a91SGregory Neil Shapiro 247213058a91SGregory Neil Shapiro /* 247313058a91SGregory Neil Shapiro ** Undo the effects of the uid change in main 247413058a91SGregory Neil Shapiro ** for signal handling. The real uid may 247513058a91SGregory Neil Shapiro ** be used by mailer in adding a "From " 247613058a91SGregory Neil Shapiro ** line. 247713058a91SGregory Neil Shapiro */ 247813058a91SGregory Neil Shapiro 247913058a91SGregory Neil Shapiro if (RealUid != 0 && RealUid != getuid()) 248040266059SGregory Neil Shapiro { 248140266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 248240266059SGregory Neil Shapiro # if HASSETREUID 248340266059SGregory Neil Shapiro if (setreuid(RealUid, geteuid()) < 0) 248440266059SGregory Neil Shapiro { 248540266059SGregory Neil Shapiro syserr("openmailer: setreuid(%d, %d) failed", 248640266059SGregory Neil Shapiro (int) RealUid, (int) geteuid()); 248740266059SGregory Neil Shapiro exit(EX_OSERR); 248840266059SGregory Neil Shapiro } 248940266059SGregory Neil Shapiro # endif /* HASSETREUID */ 249040266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 249140266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 249213058a91SGregory Neil Shapiro new_ruid = RealUid; 249340266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 249440266059SGregory Neil Shapiro } 249513058a91SGregory Neil Shapiro } 2496c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode)) 2497c2aa98e2SPeter Wemm new_ruid = stb.st_uid; 2498c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 2499c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid; 2500c2aa98e2SPeter Wemm else if (m->m_uid != 0) 2501c2aa98e2SPeter Wemm new_ruid = m->m_uid; 2502c2aa98e2SPeter Wemm else 2503c2aa98e2SPeter Wemm new_ruid = DefUid; 2504c2aa98e2SPeter Wemm if (new_euid != NO_UID) 2505c2aa98e2SPeter Wemm { 250606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid) 250706f25ae9SGregory Neil Shapiro { 250806f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 250940266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d", 251040266059SGregory Neil Shapiro (int) new_euid, (int) RunAsUid); 251106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 251206f25ae9SGregory Neil Shapiro } 251306f25ae9SGregory Neil Shapiro 2514c2aa98e2SPeter Wemm vendor_set_uid(new_euid); 251506f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 2516c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn) 251706f25ae9SGregory Neil Shapiro { 2518c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed", 2519c2aa98e2SPeter Wemm (long) new_euid); 252006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 252106f25ae9SGregory Neil Shapiro } 252206f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 252306f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 2524c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 252506f25ae9SGregory Neil Shapiro { 2526c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed", 2527c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid); 252806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 252906f25ae9SGregory Neil Shapiro } 253006f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 253106f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETUID 2532c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 253306f25ae9SGregory Neil Shapiro { 2534c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2535c2aa98e2SPeter Wemm (long) new_euid); 253606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 253706f25ae9SGregory Neil Shapiro } 253806f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETUID */ 2539c2aa98e2SPeter Wemm } 2540c2aa98e2SPeter Wemm else if (new_ruid != NO_UID) 2541c2aa98e2SPeter Wemm { 2542c2aa98e2SPeter Wemm vendor_set_uid(new_ruid); 2543c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn) 254406f25ae9SGregory Neil Shapiro { 2545c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2546c2aa98e2SPeter Wemm (long) new_ruid); 254706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 254806f25ae9SGregory Neil Shapiro } 2549c2aa98e2SPeter Wemm } 2550c2aa98e2SPeter Wemm 2551c2aa98e2SPeter Wemm if (tTd(11, 2)) 255240266059SGregory Neil Shapiro sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", 255306f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 255406f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 2555c2aa98e2SPeter Wemm 2556c2aa98e2SPeter Wemm /* move into some "safe" directory */ 2557c2aa98e2SPeter Wemm if (m->m_execdir != NULL) 2558c2aa98e2SPeter Wemm { 2559c2aa98e2SPeter Wemm char *q; 2560c2aa98e2SPeter Wemm 2561c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q) 2562c2aa98e2SPeter Wemm { 2563c2aa98e2SPeter Wemm q = strchr(p, ':'); 2564c2aa98e2SPeter Wemm if (q != NULL) 2565c2aa98e2SPeter Wemm *q = '\0'; 2566c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 2567c2aa98e2SPeter Wemm if (q != NULL) 2568c2aa98e2SPeter Wemm *q++ = ':'; 2569c2aa98e2SPeter Wemm if (tTd(11, 20)) 257040266059SGregory Neil Shapiro sm_dprintf("openmailer: trydir %s\n", 2571c2aa98e2SPeter Wemm buf); 2572c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 2573c2aa98e2SPeter Wemm break; 2574c2aa98e2SPeter Wemm } 2575c2aa98e2SPeter Wemm } 2576c2aa98e2SPeter Wemm 257740266059SGregory Neil Shapiro /* Check safety of program to be run */ 257840266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK; 257940266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, 258040266059SGregory Neil Shapiro DontBlameSendmail)) 258140266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 258240266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, 258340266059SGregory Neil Shapiro DontBlameSendmail)) 258440266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK; 258540266059SGregory Neil Shapiro else 258640266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH; 258740266059SGregory Neil Shapiro ret = safefile(m->m_mailer, getuid(), getgid(), 258840266059SGregory Neil Shapiro user, sff, 0, NULL); 258940266059SGregory Neil Shapiro if (ret != 0) 259040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 259140266059SGregory Neil Shapiro "Warning: program %s unsafe: %s", 259240266059SGregory Neil Shapiro m->m_mailer, sm_errstring(ret)); 259340266059SGregory Neil Shapiro 2594c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */ 2595c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2596c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0) 2597c2aa98e2SPeter Wemm { 2598c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 2599c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2600c2aa98e2SPeter Wemm m->m_name, rpvect[1]); 2601c2aa98e2SPeter Wemm _exit(EX_OSERR); 2602c2aa98e2SPeter Wemm } 2603c2aa98e2SPeter Wemm (void) close(rpvect[1]); 260406f25ae9SGregory Neil Shapiro 2605c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 2606c2aa98e2SPeter Wemm { 2607c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr", 2608c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2609c2aa98e2SPeter Wemm m->m_name); 2610c2aa98e2SPeter Wemm _exit(EX_OSERR); 2611c2aa98e2SPeter Wemm } 2612c2aa98e2SPeter Wemm 2613c2aa98e2SPeter Wemm /* arrange to get standard input */ 2614c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2615c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0) 2616c2aa98e2SPeter Wemm { 2617c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 2618c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2619c2aa98e2SPeter Wemm m->m_name, mpvect[0]); 2620c2aa98e2SPeter Wemm _exit(EX_OSERR); 2621c2aa98e2SPeter Wemm } 2622c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2623c2aa98e2SPeter Wemm 2624c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2625c2aa98e2SPeter Wemm for (i = 3; i < DtableSize; i++) 2626c2aa98e2SPeter Wemm { 2627c2aa98e2SPeter Wemm register int j; 2628c2aa98e2SPeter Wemm 2629c2aa98e2SPeter Wemm if ((j = fcntl(i, F_GETFD, 0)) != -1) 263006f25ae9SGregory Neil Shapiro (void) fcntl(i, F_SETFD, 263106f25ae9SGregory Neil Shapiro j | FD_CLOEXEC); 2632c2aa98e2SPeter Wemm } 2633c2aa98e2SPeter Wemm 2634c2aa98e2SPeter Wemm /* run disconnected from terminal */ 2635c2aa98e2SPeter Wemm (void) setsid(); 2636c2aa98e2SPeter Wemm 2637c2aa98e2SPeter Wemm /* try to execute the mailer */ 263806f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv, 263906f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron); 264006f25ae9SGregory Neil Shapiro save_errno = errno; 2641c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer); 2642c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) || 264306f25ae9SGregory Neil Shapiro transienterror(save_errno)) 2644c2aa98e2SPeter Wemm _exit(EX_OSERR); 2645c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE); 2646c2aa98e2SPeter Wemm } 2647c2aa98e2SPeter Wemm 2648c2aa98e2SPeter Wemm /* 2649c2aa98e2SPeter Wemm ** Set up return value. 2650c2aa98e2SPeter Wemm */ 2651c2aa98e2SPeter Wemm 2652c2aa98e2SPeter Wemm if (mci == NULL) 2653c2aa98e2SPeter Wemm { 265440266059SGregory Neil Shapiro if (clever) 265540266059SGregory Neil Shapiro { 265640266059SGregory Neil Shapiro /* 265740266059SGregory Neil Shapiro ** Allocate from general heap, not 265840266059SGregory Neil Shapiro ** envelope rpool, because this mci 265940266059SGregory Neil Shapiro ** is going to be cached. 266040266059SGregory Neil Shapiro */ 266140266059SGregory Neil Shapiro 266240266059SGregory Neil Shapiro mci = mci_new(NULL); 266340266059SGregory Neil Shapiro } 266440266059SGregory Neil Shapiro else 266540266059SGregory Neil Shapiro { 266640266059SGregory Neil Shapiro /* 266740266059SGregory Neil Shapiro ** Prevent a storage leak by allocating 266840266059SGregory Neil Shapiro ** this from the envelope rpool. 266940266059SGregory Neil Shapiro */ 267040266059SGregory Neil Shapiro 267140266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 267240266059SGregory Neil Shapiro } 2673c2aa98e2SPeter Wemm } 2674c2aa98e2SPeter Wemm mci->mci_mailer = m; 2675c2aa98e2SPeter Wemm if (clever) 2676c2aa98e2SPeter Wemm { 2677c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2678c2aa98e2SPeter Wemm mci_cache(mci); 2679c2aa98e2SPeter Wemm } 2680c2aa98e2SPeter Wemm else 2681c2aa98e2SPeter Wemm { 2682c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2683c2aa98e2SPeter Wemm } 2684c2aa98e2SPeter Wemm mci->mci_pid = pid; 2685c2aa98e2SPeter Wemm (void) close(mpvect[0]); 268640266059SGregory Neil Shapiro mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 268740266059SGregory Neil Shapiro (void *) &(mpvect[1]), SM_IO_WRONLY, 268840266059SGregory Neil Shapiro NULL); 2689c2aa98e2SPeter Wemm if (mci->mci_out == NULL) 2690c2aa98e2SPeter Wemm { 2691c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d", 2692c2aa98e2SPeter Wemm mpvect[1]); 2693c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2694c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2695c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2696c2aa98e2SPeter Wemm rcode = EX_OSERR; 2697c2aa98e2SPeter Wemm goto give_up; 2698c2aa98e2SPeter Wemm } 269906f25ae9SGregory Neil Shapiro 2700c2aa98e2SPeter Wemm (void) close(rpvect[1]); 270140266059SGregory Neil Shapiro mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 270240266059SGregory Neil Shapiro (void *) &(rpvect[0]), SM_IO_RDONLY, 270340266059SGregory Neil Shapiro NULL); 2704c2aa98e2SPeter Wemm if (mci->mci_in == NULL) 2705c2aa98e2SPeter Wemm { 2706c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d", 2707c2aa98e2SPeter Wemm mpvect[1]); 2708c2aa98e2SPeter Wemm (void) close(rpvect[0]); 270940266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 2710c2aa98e2SPeter Wemm mci->mci_out = NULL; 2711c2aa98e2SPeter Wemm rcode = EX_OSERR; 2712c2aa98e2SPeter Wemm goto give_up; 2713c2aa98e2SPeter Wemm } 2714c2aa98e2SPeter Wemm } 2715c2aa98e2SPeter Wemm 2716c2aa98e2SPeter Wemm /* 2717c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol. 2718c2aa98e2SPeter Wemm */ 2719c2aa98e2SPeter Wemm 2720c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) && 2721c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING)) 2722c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT; 2723c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED) 2724c2aa98e2SPeter Wemm { 272540266059SGregory Neil Shapiro # if STARTTLS || SASL 272640266059SGregory Neil Shapiro int dotpos; 272740266059SGregory Neil Shapiro char *srvname; 272840266059SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 272940266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 273040266059SGregory Neil Shapiro 273140266059SGregory Neil Shapiro # if SASL 2732193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 273340266059SGregory Neil Shapiro # endif /* SASL */ 273406f25ae9SGregory Neil Shapiro # if STARTTLS 2735193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 273606f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 2737193538b7SGregory Neil Shapiro # define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 2738193538b7SGregory Neil Shapiro # define SET_HELO(f) f |= MCIF_ONLY_EHLO 2739193538b7SGregory Neil Shapiro # define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 2740c2aa98e2SPeter Wemm 274140266059SGregory Neil Shapiro # if STARTTLS || SASL 274240266059SGregory Neil Shapiro /* don't use CurHostName, it is changed in many places */ 2743602a2b1bSGregory Neil Shapiro if (mci->mci_host != NULL) 2744602a2b1bSGregory Neil Shapiro { 2745602a2b1bSGregory Neil Shapiro srvname = mci->mci_host; 2746602a2b1bSGregory Neil Shapiro dotpos = strlen(srvname) - 1; 2747602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2748602a2b1bSGregory Neil Shapiro { 2749602a2b1bSGregory Neil Shapiro if (srvname[dotpos] == '.') 2750602a2b1bSGregory Neil Shapiro srvname[dotpos] = '\0'; 2751602a2b1bSGregory Neil Shapiro else 2752602a2b1bSGregory Neil Shapiro dotpos = -1; 2753602a2b1bSGregory Neil Shapiro } 2754602a2b1bSGregory Neil Shapiro } 275540266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 2756602a2b1bSGregory Neil Shapiro { 275740266059SGregory Neil Shapiro srvname = mci->mci_mailer->m_name; 2758602a2b1bSGregory Neil Shapiro dotpos = -1; 2759602a2b1bSGregory Neil Shapiro } 276006f25ae9SGregory Neil Shapiro else 276106f25ae9SGregory Neil Shapiro { 276240266059SGregory Neil Shapiro srvname = "local"; 276340266059SGregory Neil Shapiro dotpos = -1; 2764193538b7SGregory Neil Shapiro } 276506f25ae9SGregory Neil Shapiro 276640266059SGregory Neil Shapiro /* don't set {server_name} to NULL or "": see getauth() */ 276740266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"), 276840266059SGregory Neil Shapiro srvname); 276940266059SGregory Neil Shapiro 277040266059SGregory Neil Shapiro /* CurHostAddr is set by makeconnection() and mci_get() */ 277140266059SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0) 277240266059SGregory Neil Shapiro { 277340266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, 277440266059SGregory Neil Shapiro macid("{server_addr}"), 277540266059SGregory Neil Shapiro anynet_ntoa(&CurHostAddr)); 277640266059SGregory Neil Shapiro } 277740266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 277840266059SGregory Neil Shapiro { 277940266059SGregory Neil Shapiro /* mailer name is unique, use it as address */ 278040266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 278140266059SGregory Neil Shapiro macid("{server_addr}"), 278240266059SGregory Neil Shapiro mci->mci_mailer->m_name); 278340266059SGregory Neil Shapiro } 278440266059SGregory Neil Shapiro else 278540266059SGregory Neil Shapiro { 278640266059SGregory Neil Shapiro /* don't set it to NULL or "": see getauth() */ 278740266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 278840266059SGregory Neil Shapiro macid("{server_addr}"), "0"); 278940266059SGregory Neil Shapiro } 279040266059SGregory Neil Shapiro 279140266059SGregory Neil Shapiro /* undo change of srvname (mci->mci_host) */ 2792602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2793602a2b1bSGregory Neil Shapiro srvname[dotpos] = '.'; 279440266059SGregory Neil Shapiro 279540266059SGregory Neil Shapiro reconnect: /* after switching to an encrypted connection */ 279640266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 279740266059SGregory Neil Shapiro 279840266059SGregory Neil Shapiro /* set the current connection information */ 279940266059SGregory Neil Shapiro e->e_mci = mci; 280040266059SGregory Neil Shapiro # if SASL 280140266059SGregory Neil Shapiro mci->mci_saslcap = NULL; 280240266059SGregory Neil Shapiro # endif /* SASL */ 280340266059SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 280440266059SGregory Neil Shapiro CLR_HELO(mci->mci_flags); 280540266059SGregory Neil Shapiro 280640266059SGregory Neil Shapiro if (IS_DLVR_RETURN(e)) 280740266059SGregory Neil Shapiro { 280840266059SGregory Neil Shapiro /* 280940266059SGregory Neil Shapiro ** Check whether other side can deliver e-mail 281040266059SGregory Neil Shapiro ** fast enough 281140266059SGregory Neil Shapiro */ 281240266059SGregory Neil Shapiro 281340266059SGregory Neil Shapiro if (!bitset(MCIF_DLVR_BY, mci->mci_flags)) 281440266059SGregory Neil Shapiro { 281540266059SGregory Neil Shapiro e->e_status = "5.4.7"; 281640266059SGregory Neil Shapiro usrerrenh(e->e_status, 281740266059SGregory Neil Shapiro "554 Server does not support Deliver By"); 281840266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 281940266059SGregory Neil Shapiro goto give_up; 282040266059SGregory Neil Shapiro } 282140266059SGregory Neil Shapiro if (e->e_deliver_by > 0 && 282240266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime) < 282340266059SGregory Neil Shapiro mci->mci_min_by) 282440266059SGregory Neil Shapiro { 282540266059SGregory Neil Shapiro e->e_status = "5.4.7"; 282640266059SGregory Neil Shapiro usrerrenh(e->e_status, 282740266059SGregory Neil Shapiro "554 Message can't be delivered in time; %ld < %ld", 282840266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime), 282940266059SGregory Neil Shapiro mci->mci_min_by); 283040266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 283140266059SGregory Neil Shapiro goto give_up; 283240266059SGregory Neil Shapiro } 283340266059SGregory Neil Shapiro } 283440266059SGregory Neil Shapiro 283540266059SGregory Neil Shapiro # if STARTTLS 283640266059SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */ 283740266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 283840266059SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags)) 283940266059SGregory Neil Shapiro { 284040266059SGregory Neil Shapiro int olderrors; 284140266059SGregory Neil Shapiro bool usetls; 284240266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 284340266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 284440266059SGregory Neil Shapiro char *host = NULL; 284540266059SGregory Neil Shapiro 284640266059SGregory Neil Shapiro rcode = EX_OK; 284740266059SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags); 284840266059SGregory Neil Shapiro if (usetls) 284940266059SGregory Neil Shapiro usetls = !iscltflgset(e, D_NOTLS); 285040266059SGregory Neil Shapiro 285140266059SGregory Neil Shapiro if (usetls) 285240266059SGregory Neil Shapiro { 285340266059SGregory Neil Shapiro host = macvalue(macid("{server_name}"), e); 285440266059SGregory Neil Shapiro olderrors = Errors; 285540266059SGregory Neil Shapiro QuickAbort = false; 285640266059SGregory Neil Shapiro SuprErrs = true; 285740266059SGregory Neil Shapiro if (rscheck("try_tls", host, NULL, e, true, 285840266059SGregory Neil Shapiro false, 7, host, NOQID) != EX_OK 285940266059SGregory Neil Shapiro || Errors > olderrors) 286040266059SGregory Neil Shapiro usetls = false; 286140266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 286240266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 286340266059SGregory Neil Shapiro } 286440266059SGregory Neil Shapiro 286506f25ae9SGregory Neil Shapiro if (usetls) 286606f25ae9SGregory Neil Shapiro { 286706f25ae9SGregory Neil Shapiro if ((rcode = starttls(m, mci, e)) == EX_OK) 286806f25ae9SGregory Neil Shapiro { 286906f25ae9SGregory Neil Shapiro /* start again without STARTTLS */ 287006f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT; 287106f25ae9SGregory Neil Shapiro } 287206f25ae9SGregory Neil Shapiro else 287306f25ae9SGregory Neil Shapiro { 287406f25ae9SGregory Neil Shapiro char *s; 287506f25ae9SGregory Neil Shapiro 287606f25ae9SGregory Neil Shapiro /* 287706f25ae9SGregory Neil Shapiro ** TLS negotation failed, what to do? 287806f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection 287906f25ae9SGregory Neil Shapiro ** or abort? How to decide? 288006f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset. 288106f25ae9SGregory Neil Shapiro */ 288240266059SGregory Neil Shapiro 288306f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS; 288406f25ae9SGregory Neil Shapiro switch (rcode) 288506f25ae9SGregory Neil Shapiro { 288606f25ae9SGregory Neil Shapiro case EX_TEMPFAIL: 288706f25ae9SGregory Neil Shapiro s = "TEMP"; 288806f25ae9SGregory Neil Shapiro break; 288906f25ae9SGregory Neil Shapiro case EX_USAGE: 289006f25ae9SGregory Neil Shapiro s = "USAGE"; 289106f25ae9SGregory Neil Shapiro break; 289206f25ae9SGregory Neil Shapiro case EX_PROTOCOL: 289306f25ae9SGregory Neil Shapiro s = "PROTOCOL"; 289406f25ae9SGregory Neil Shapiro break; 289506f25ae9SGregory Neil Shapiro case EX_SOFTWARE: 289606f25ae9SGregory Neil Shapiro s = "SOFTWARE"; 289706f25ae9SGregory Neil Shapiro break; 289806f25ae9SGregory Neil Shapiro 289906f25ae9SGregory Neil Shapiro /* everything else is a failure */ 290006f25ae9SGregory Neil Shapiro default: 290106f25ae9SGregory Neil Shapiro s = "FAILURE"; 290206f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL; 290306f25ae9SGregory Neil Shapiro } 290440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 290540266059SGregory Neil Shapiro macid("{verify}"), s); 290606f25ae9SGregory Neil Shapiro } 290706f25ae9SGregory Neil Shapiro } 290806f25ae9SGregory Neil Shapiro else 290940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 291040266059SGregory Neil Shapiro macid("{verify}"), "NONE"); 291106f25ae9SGregory Neil Shapiro olderrors = Errors; 291240266059SGregory Neil Shapiro QuickAbort = false; 291340266059SGregory Neil Shapiro SuprErrs = true; 291406f25ae9SGregory Neil Shapiro 291506f25ae9SGregory Neil Shapiro /* 291606f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special: 291706f25ae9SGregory Neil Shapiro ** the TLS negotation failed 291806f25ae9SGregory Neil Shapiro ** we have to drop the connection no matter what 291906f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance 292006f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate 292106f25ae9SGregory Neil Shapiro ** error code. 292206f25ae9SGregory Neil Shapiro */ 292340266059SGregory Neil Shapiro 292406f25ae9SGregory Neil Shapiro if (rscheck("tls_server", 292540266059SGregory Neil Shapiro macvalue(macid("{verify}"), e), 292640266059SGregory Neil Shapiro NULL, e, true, true, 5, host, 292740266059SGregory Neil Shapiro NOQID) != EX_OK || 292806f25ae9SGregory Neil Shapiro Errors > olderrors || 292906f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE) 293006f25ae9SGregory Neil Shapiro { 293106f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN]; 293206f25ae9SGregory Neil Shapiro extern char MsgBuf[]; 293306f25ae9SGregory Neil Shapiro 293406f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) && 293506f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 293606f25ae9SGregory Neil Shapiro { 293740266059SGregory Neil Shapiro p = sm_rpool_strdup_x(e->e_rpool, 293840266059SGregory Neil Shapiro MsgBuf); 293906f25ae9SGregory Neil Shapiro } 294006f25ae9SGregory Neil Shapiro else 294106f25ae9SGregory Neil Shapiro { 294206f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated."; 294340266059SGregory Neil Shapiro (void) sm_strlcpy(enhsc, "4.7.0", 294406f25ae9SGregory Neil Shapiro sizeof enhsc); 294506f25ae9SGregory Neil Shapiro } 294606f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 294706f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 294806f25ae9SGregory Neil Shapiro 294906f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE) 295006f25ae9SGregory Neil Shapiro { 295106f25ae9SGregory Neil Shapiro /* drop the connection */ 295206f25ae9SGregory Neil Shapiro mci->mci_state = MCIS_QUITING; 295306f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 295406f25ae9SGregory Neil Shapiro { 295540266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, 295640266059SGregory Neil Shapiro SM_TIME_DEFAULT); 295706f25ae9SGregory Neil Shapiro mci->mci_in = NULL; 295806f25ae9SGregory Neil Shapiro } 295906f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 296006f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv); 296106f25ae9SGregory Neil Shapiro } 296206f25ae9SGregory Neil Shapiro else 296306f25ae9SGregory Neil Shapiro { 296406f25ae9SGregory Neil Shapiro /* abort transfer */ 296506f25ae9SGregory Neil Shapiro smtpquit(m, mci, e); 296606f25ae9SGregory Neil Shapiro } 296706f25ae9SGregory Neil Shapiro 2968193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 2969193538b7SGregory Neil Shapiro mci->mci_errno = 0; 2970193538b7SGregory Neil Shapiro 297106f25ae9SGregory Neil Shapiro /* temp or permanent failure? */ 297206f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL 297306f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE; 297440266059SGregory Neil Shapiro mci_setstat(mci, rcode, enhsc, p); 297506f25ae9SGregory Neil Shapiro 297606f25ae9SGregory Neil Shapiro /* 297706f25ae9SGregory Neil Shapiro ** hack to get the error message into 297806f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse()) 297906f25ae9SGregory Neil Shapiro */ 298040266059SGregory Neil Shapiro 298140266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, p, 298240266059SGregory Neil Shapiro sizeof SmtpError); 298306f25ae9SGregory Neil Shapiro } 298406f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 298506f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 2986193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) && 2987193538b7SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED) 298806f25ae9SGregory Neil Shapiro { 2989193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 299006f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 299106f25ae9SGregory Neil Shapiro goto reconnect; 299206f25ae9SGregory Neil Shapiro } 299306f25ae9SGregory Neil Shapiro } 299406f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 299506f25ae9SGregory Neil Shapiro # if SASL 299606f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */ 299706f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 299806f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL && 299940266059SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH)) 300006f25ae9SGregory Neil Shapiro { 300140266059SGregory Neil Shapiro /* Should we require some minimum authentication? */ 300240266059SGregory Neil Shapiro if ((ret = smtpauth(m, mci, e)) == EX_OK) 300306f25ae9SGregory Neil Shapiro { 300406f25ae9SGregory Neil Shapiro int result; 300540266059SGregory Neil Shapiro sasl_ssf_t *ssf = NULL; 300606f25ae9SGregory Neil Shapiro 300740266059SGregory Neil Shapiro /* Get security strength (features) */ 300806f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF, 300906f25ae9SGregory Neil Shapiro (void **) &ssf); 301040266059SGregory Neil Shapiro 301140266059SGregory Neil Shapiro /* XXX authid? */ 301206f25ae9SGregory Neil Shapiro if (LogLevel > 9) 301306f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 301440266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, mech=%.16s, bits=%d", 301506f25ae9SGregory Neil Shapiro mci->mci_host, 301640266059SGregory Neil Shapiro macvalue(macid("{auth_type}"), e), 301740266059SGregory Neil Shapiro result == SASL_OK ? *ssf : 0); 30188774250cSGregory Neil Shapiro 301906f25ae9SGregory Neil Shapiro /* 302040266059SGregory Neil Shapiro ** Only switch to encrypted connection 302106f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated 302206f25ae9SGregory Neil Shapiro */ 302340266059SGregory Neil Shapiro 302406f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0) 302506f25ae9SGregory Neil Shapiro { 302606f25ae9SGregory Neil Shapiro /* 302740266059SGregory Neil Shapiro ** Convert I/O layer to use SASL. 302840266059SGregory Neil Shapiro ** If the call fails, the connection 302940266059SGregory Neil Shapiro ** is aborted. 303006f25ae9SGregory Neil Shapiro */ 303140266059SGregory Neil Shapiro 303240266059SGregory Neil Shapiro if (sfdcsasl(&mci->mci_in, 303340266059SGregory Neil Shapiro &mci->mci_out, 303406f25ae9SGregory Neil Shapiro mci->mci_conn) == 0) 303506f25ae9SGregory Neil Shapiro { 303606f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 303740266059SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT| 303840266059SGregory Neil Shapiro MCIF_ONLY_EHLO; 303906f25ae9SGregory Neil Shapiro goto reconnect; 304006f25ae9SGregory Neil Shapiro } 304140266059SGregory Neil Shapiro syserr("AUTH TLS switch failed in client"); 304206f25ae9SGregory Neil Shapiro } 304306f25ae9SGregory Neil Shapiro /* else? XXX */ 304406f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 304506f25ae9SGregory Neil Shapiro 304606f25ae9SGregory Neil Shapiro } 304740266059SGregory Neil Shapiro else if (ret == EX_TEMPFAIL) 304840266059SGregory Neil Shapiro { 304940266059SGregory Neil Shapiro if (LogLevel > 8) 305040266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 305140266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, temporary failure, connection abort", 305240266059SGregory Neil Shapiro mci->mci_host); 305340266059SGregory Neil Shapiro smtpquit(m, mci, e); 305440266059SGregory Neil Shapiro 305540266059SGregory Neil Shapiro /* avoid bogus error msg */ 305640266059SGregory Neil Shapiro mci->mci_errno = 0; 305740266059SGregory Neil Shapiro rcode = EX_TEMPFAIL; 305840266059SGregory Neil Shapiro mci_setstat(mci, rcode, "4.7.1", p); 305940266059SGregory Neil Shapiro 306040266059SGregory Neil Shapiro /* 306140266059SGregory Neil Shapiro ** hack to get the error message into 306240266059SGregory Neil Shapiro ** the envelope (done in giveresponse()) 306340266059SGregory Neil Shapiro */ 306440266059SGregory Neil Shapiro 306540266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, 306640266059SGregory Neil Shapiro "Temporary AUTH failure", 306740266059SGregory Neil Shapiro sizeof SmtpError); 306840266059SGregory Neil Shapiro } 306906f25ae9SGregory Neil Shapiro } 307006f25ae9SGregory Neil Shapiro # endif /* SASL */ 307106f25ae9SGregory Neil Shapiro } 307206f25ae9SGregory Neil Shapiro 3073c2aa98e2SPeter Wemm 3074c2aa98e2SPeter Wemm do_transfer: 3075c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 3076c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 3077c2aa98e2SPeter Wemm 3078c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 3079c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 3080c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags)) 3081c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7; 3082c2aa98e2SPeter Wemm 3083c2aa98e2SPeter Wemm #if MIME7TO8 3084c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) && 3085c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) && 3086c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 308740266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 308840266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 3089c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 3090c2aa98e2SPeter Wemm { 3091c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 3092c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 309340266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 3094c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 3095c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8; 3096c2aa98e2SPeter Wemm } 309706f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 3098c2aa98e2SPeter Wemm 3099c2aa98e2SPeter Wemm if (tTd(11, 1)) 3100c2aa98e2SPeter Wemm { 310140266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 310240266059SGregory Neil Shapiro mci_dump(mci, false); 3103c2aa98e2SPeter Wemm } 3104c2aa98e2SPeter Wemm 310540266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE 310640266059SGregory Neil Shapiro /* 310740266059SGregory Neil Shapiro ** See if we know the maximum size and 310840266059SGregory Neil Shapiro ** abort if the message is too big. 310940266059SGregory Neil Shapiro ** 311040266059SGregory Neil Shapiro ** NOTE: _FFR_CLIENT_SIZE is untested. 311140266059SGregory Neil Shapiro */ 311240266059SGregory Neil Shapiro 311340266059SGregory Neil Shapiro if (bitset(MCIF_SIZE, mci->mci_flags) && 311440266059SGregory Neil Shapiro mci->mci_maxsize > 0 && 311540266059SGregory Neil Shapiro e->e_msgsize > mci->mci_maxsize) 311640266059SGregory Neil Shapiro { 311740266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 311840266059SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags)) 311940266059SGregory Neil Shapiro e->e_status = "5.2.3"; 312040266059SGregory Neil Shapiro else 312140266059SGregory Neil Shapiro e->e_status = "5.3.4"; 312240266059SGregory Neil Shapiro 312340266059SGregory Neil Shapiro usrerrenh(e->e_status, 312440266059SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 312540266059SGregory Neil Shapiro mci->mci_maxsize); 312640266059SGregory Neil Shapiro rcode = EX_DATAERR; 312740266059SGregory Neil Shapiro 312840266059SGregory Neil Shapiro /* Need an e_message for error */ 312940266059SGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof SmtpError, 313040266059SGregory Neil Shapiro "Message is too large; %ld bytes max", 313140266059SGregory Neil Shapiro mci->mci_maxsize); 313240266059SGregory Neil Shapiro goto give_up; 313340266059SGregory Neil Shapiro } 313440266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */ 313540266059SGregory Neil Shapiro 3136c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 3137c2aa98e2SPeter Wemm { 3138c2aa98e2SPeter Wemm /* couldn't open the mailer */ 3139c2aa98e2SPeter Wemm rcode = mci->mci_exitstat; 3140c2aa98e2SPeter Wemm errno = mci->mci_errno; 3141602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno); 3142c2aa98e2SPeter Wemm if (rcode == EX_OK) 3143c2aa98e2SPeter Wemm { 3144c2aa98e2SPeter Wemm /* shouldn't happen */ 314506f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 314640266059SGregory Neil Shapiro (unsigned long) mci, rcode, errno, 314740266059SGregory Neil Shapiro mci->mci_state, firstsig); 314840266059SGregory Neil Shapiro mci_dump_all(true); 3149c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 3150c2aa98e2SPeter Wemm } 315106f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum) 3152c2aa98e2SPeter Wemm { 3153c2aa98e2SPeter Wemm /* try next MX site */ 3154c2aa98e2SPeter Wemm goto tryhost; 3155c2aa98e2SPeter Wemm } 3156c2aa98e2SPeter Wemm } 3157c2aa98e2SPeter Wemm else if (!clever) 3158c2aa98e2SPeter Wemm { 3159c2aa98e2SPeter Wemm /* 3160c2aa98e2SPeter Wemm ** Format and send message. 3161c2aa98e2SPeter Wemm */ 3162c2aa98e2SPeter Wemm 3163c2aa98e2SPeter Wemm putfromline(mci, e); 31642e43090eSPeter Wemm (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 3165c2aa98e2SPeter Wemm (*e->e_putbody)(mci, e, NULL); 3166c2aa98e2SPeter Wemm 3167c2aa98e2SPeter Wemm /* get the exit status */ 3168c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv); 316940266059SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 3170602a2b1bSGregory Neil Shapiro { 3171602a2b1bSGregory Neil Shapiro /* 3172602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display. 3173602a2b1bSGregory Neil Shapiro ** We set SmtpError as 3174602a2b1bSGregory Neil Shapiro */ 3175602a2b1bSGregory Neil Shapiro 317640266059SGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof SmtpError, 3177602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL", 3178602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer); 3179602a2b1bSGregory Neil Shapiro } 3180c2aa98e2SPeter Wemm } 3181c2aa98e2SPeter Wemm else 3182c2aa98e2SPeter Wemm { 3183c2aa98e2SPeter Wemm /* 3184c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol 3185c2aa98e2SPeter Wemm */ 3186c2aa98e2SPeter Wemm 318740266059SGregory Neil Shapiro /* XXX this isn't pipelined... */ 3188c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e); 3189c2aa98e2SPeter Wemm if (rcode == EX_OK) 3190c2aa98e2SPeter Wemm { 3191c2aa98e2SPeter Wemm register int i; 319240266059SGregory Neil Shapiro # if PIPELINING 319340266059SGregory Neil Shapiro ADDRESS *volatile pchain; 319440266059SGregory Neil Shapiro # endif /* PIPELINING */ 3195c2aa98e2SPeter Wemm 3196c2aa98e2SPeter Wemm /* send the recipient list */ 3197c2aa98e2SPeter Wemm tobuf[0] = '\0'; 319840266059SGregory Neil Shapiro mci->mci_retryrcpt = false; 319940266059SGregory Neil Shapiro mci->mci_tolist = tobuf; 320040266059SGregory Neil Shapiro # if PIPELINING 320140266059SGregory Neil Shapiro pchain = NULL; 320240266059SGregory Neil Shapiro mci->mci_nextaddr = NULL; 320340266059SGregory Neil Shapiro # endif /* PIPELINING */ 320406f25ae9SGregory Neil Shapiro 3205c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3206c2aa98e2SPeter Wemm { 320740266059SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state)) 3208c2aa98e2SPeter Wemm continue; 320906f25ae9SGregory Neil Shapiro 321040266059SGregory Neil Shapiro /* mark recipient state as "ok so far" */ 321140266059SGregory Neil Shapiro to->q_state = QS_OK; 321240266059SGregory Neil Shapiro e->e_to = to->q_paddr; 321306f25ae9SGregory Neil Shapiro # if STARTTLS 321406f25ae9SGregory Neil Shapiro i = rscheck("tls_rcpt", to->q_user, NULL, e, 321540266059SGregory Neil Shapiro true, true, 3, mci->mci_host, 321640266059SGregory Neil Shapiro e->e_id); 321706f25ae9SGregory Neil Shapiro if (i != EX_OK) 3218c2aa98e2SPeter Wemm { 321940266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 322040266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 322140266059SGregory Neil Shapiro ctladdr, xstart, e, to); 322240266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 322340266059SGregory Neil Shapiro { 322440266059SGregory Neil Shapiro mci->mci_retryrcpt = true; 322540266059SGregory Neil Shapiro to->q_state = QS_RETRY; 322640266059SGregory Neil Shapiro } 322706f25ae9SGregory Neil Shapiro continue; 322806f25ae9SGregory Neil Shapiro } 322906f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 323006f25ae9SGregory Neil Shapiro 323140266059SGregory Neil Shapiro i = smtprcpt(to, m, mci, e, ctladdr, xstart); 323240266059SGregory Neil Shapiro # if PIPELINING 323340266059SGregory Neil Shapiro if (i == EX_OK && 323440266059SGregory Neil Shapiro bitset(MCIF_PIPELINED, mci->mci_flags)) 323506f25ae9SGregory Neil Shapiro { 323640266059SGregory Neil Shapiro /* 323740266059SGregory Neil Shapiro ** Add new element to list of 323840266059SGregory Neil Shapiro ** recipients for pipelining. 323940266059SGregory Neil Shapiro */ 324040266059SGregory Neil Shapiro 324140266059SGregory Neil Shapiro to->q_pchain = NULL; 324240266059SGregory Neil Shapiro if (mci->mci_nextaddr == NULL) 324340266059SGregory Neil Shapiro mci->mci_nextaddr = to; 324440266059SGregory Neil Shapiro if (pchain == NULL) 324540266059SGregory Neil Shapiro pchain = to; 3246c2aa98e2SPeter Wemm else 3247c2aa98e2SPeter Wemm { 324840266059SGregory Neil Shapiro pchain->q_pchain = to; 324940266059SGregory Neil Shapiro pchain = pchain->q_pchain; 325040266059SGregory Neil Shapiro } 325140266059SGregory Neil Shapiro } 325240266059SGregory Neil Shapiro # endif /* PIPELINING */ 325340266059SGregory Neil Shapiro if (i != EX_OK) 325440266059SGregory Neil Shapiro { 325540266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 325640266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 325740266059SGregory Neil Shapiro ctladdr, xstart, e, to); 325840266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 325940266059SGregory Neil Shapiro to->q_state = QS_RETRY; 3260c2aa98e2SPeter Wemm } 3261c2aa98e2SPeter Wemm } 3262c2aa98e2SPeter Wemm 326340266059SGregory Neil Shapiro /* No recipients in list and no missing responses? */ 326440266059SGregory Neil Shapiro if (tobuf[0] == '\0' 326540266059SGregory Neil Shapiro # if PIPELINING 326640266059SGregory Neil Shapiro && mci->mci_nextaddr == NULL 326740266059SGregory Neil Shapiro # endif /* PIPELINING */ 326840266059SGregory Neil Shapiro ) 3269c2aa98e2SPeter Wemm { 3270c2aa98e2SPeter Wemm rcode = EX_OK; 3271c2aa98e2SPeter Wemm e->e_to = NULL; 3272c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 3273c2aa98e2SPeter Wemm smtprset(m, mci, e); 3274c2aa98e2SPeter Wemm } 3275c2aa98e2SPeter Wemm else 3276c2aa98e2SPeter Wemm { 3277c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 327840266059SGregory Neil Shapiro rcode = smtpdata(m, mci, e, ctladdr, xstart); 3279c2aa98e2SPeter Wemm } 3280c2aa98e2SPeter Wemm } 328106f25ae9SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 3282c2aa98e2SPeter Wemm { 3283c2aa98e2SPeter Wemm /* try next MX site */ 3284c2aa98e2SPeter Wemm goto tryhost; 3285c2aa98e2SPeter Wemm } 3286c2aa98e2SPeter Wemm } 3287c2aa98e2SPeter Wemm #if NAMED_BIND 3288c2aa98e2SPeter Wemm if (ConfigLevel < 2) 3289c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 329006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3291c2aa98e2SPeter Wemm 3292c2aa98e2SPeter Wemm if (tTd(62, 1)) 3293c2aa98e2SPeter Wemm checkfds("after delivery"); 3294c2aa98e2SPeter Wemm 3295c2aa98e2SPeter Wemm /* 3296c2aa98e2SPeter Wemm ** Do final status disposal. 3297c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case. 3298c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the 3299c2aa98e2SPeter Wemm ** addressees. 3300c2aa98e2SPeter Wemm */ 3301c2aa98e2SPeter Wemm 3302c2aa98e2SPeter Wemm give_up: 3303c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3304c2aa98e2SPeter Wemm { 3305c2aa98e2SPeter Wemm lmtp_rcode = rcode; 3306c2aa98e2SPeter Wemm tobuf[0] = '\0'; 330740266059SGregory Neil Shapiro anyok = false; 330840266059SGregory Neil Shapiro strsize = 0; 3309c2aa98e2SPeter Wemm } 3310c2aa98e2SPeter Wemm else 3311c2aa98e2SPeter Wemm anyok = rcode == EX_OK; 3312c2aa98e2SPeter Wemm 3313c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3314c2aa98e2SPeter Wemm { 3315c2aa98e2SPeter Wemm /* see if address already marked */ 331606f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 3317c2aa98e2SPeter Wemm continue; 3318c2aa98e2SPeter Wemm 3319c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */ 3320c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3321c2aa98e2SPeter Wemm { 3322c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK) 3323c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e); 3324c2aa98e2SPeter Wemm if (rcode == EX_OK) 3325c2aa98e2SPeter Wemm { 332640266059SGregory Neil Shapiro strsize += sm_strlcat2(tobuf + strsize, ",", 332740266059SGregory Neil Shapiro to->q_paddr, 332840266059SGregory Neil Shapiro tobufsize - strsize); 332940266059SGregory Neil Shapiro SM_ASSERT(strsize < tobufsize); 333040266059SGregory Neil Shapiro anyok = true; 3331c2aa98e2SPeter Wemm } 3332c2aa98e2SPeter Wemm else 3333c2aa98e2SPeter Wemm { 3334c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 333540266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 333606f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci, 333740266059SGregory Neil Shapiro ctladdr, xstart, e, to); 3338c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 3339c2aa98e2SPeter Wemm continue; 3340c2aa98e2SPeter Wemm } 3341c2aa98e2SPeter Wemm } 3342c2aa98e2SPeter Wemm else 3343c2aa98e2SPeter Wemm { 3344c2aa98e2SPeter Wemm /* mark bad addresses */ 3345c2aa98e2SPeter Wemm if (rcode != EX_OK) 3346c2aa98e2SPeter Wemm { 3347c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST) 3348c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL; 334940266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 3350c2aa98e2SPeter Wemm continue; 3351c2aa98e2SPeter Wemm } 3352c2aa98e2SPeter Wemm } 3353c2aa98e2SPeter Wemm 3354c2aa98e2SPeter Wemm /* successful delivery */ 335506f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 3356c2aa98e2SPeter Wemm to->q_statdate = curtime(); 3357c2aa98e2SPeter Wemm e->e_nsent++; 335806f25ae9SGregory Neil Shapiro 335906f25ae9SGregory Neil Shapiro /* 336006f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses 336106f25ae9SGregory Neil Shapiro */ 336206f25ae9SGregory Neil Shapiro 336342e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 336406f25ae9SGregory Neil Shapiro { 336540266059SGregory Neil Shapiro queueup(e, false, false); 336606f25ae9SGregory Neil Shapiro e->e_nsent = 0; 336706f25ae9SGregory Neil Shapiro } 336806f25ae9SGregory Neil Shapiro 3369c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 3370c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 3371c2aa98e2SPeter Wemm { 3372c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 3373c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 337440266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 337540266059SGregory Neil Shapiro "%s... Successfully delivered\n", 3376c2aa98e2SPeter Wemm to->q_paddr); 3377c2aa98e2SPeter Wemm } 3378c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) && 3379c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) && 3380c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags)) 3381c2aa98e2SPeter Wemm { 3382c2aa98e2SPeter Wemm to->q_flags |= QRELAYED; 338340266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 338440266059SGregory Neil Shapiro "%s... relayed; expect no further notifications\n", 338540266059SGregory Neil Shapiro to->q_paddr); 338640266059SGregory Neil Shapiro } 338740266059SGregory Neil Shapiro else if (IS_DLVR_NOTIFY(e) && 338840266059SGregory Neil Shapiro !bitset(MCIF_DLVR_BY, mci->mci_flags) && 338940266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags) && 339040266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 339140266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 339240266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 339340266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags))) 339440266059SGregory Neil Shapiro { 339540266059SGregory Neil Shapiro /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 339640266059SGregory Neil Shapiro to->q_flags |= QBYNRELAY; 339740266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 339840266059SGregory Neil Shapiro "%s... Deliver-by notify: relayed\n", 339940266059SGregory Neil Shapiro to->q_paddr); 340040266059SGregory Neil Shapiro } 340140266059SGregory Neil Shapiro else if (IS_DLVR_TRACE(e) && 340240266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 340340266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 340440266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 340540266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)) && 340640266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags)) 340740266059SGregory Neil Shapiro { 340840266059SGregory Neil Shapiro /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 340940266059SGregory Neil Shapiro to->q_flags |= QBYTRACE; 341040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 341140266059SGregory Neil Shapiro "%s... Deliver-By trace: relayed\n", 3412c2aa98e2SPeter Wemm to->q_paddr); 3413c2aa98e2SPeter Wemm } 3414c2aa98e2SPeter Wemm } 3415c2aa98e2SPeter Wemm 3416c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3417c2aa98e2SPeter Wemm { 3418c2aa98e2SPeter Wemm /* 3419c2aa98e2SPeter Wemm ** Global information applies to the last recipient only; 3420c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors. 3421c2aa98e2SPeter Wemm */ 3422c2aa98e2SPeter Wemm 3423c2aa98e2SPeter Wemm rcode = EX_OK; 3424c2aa98e2SPeter Wemm e->e_statmsg = NULL; 3425c2aa98e2SPeter Wemm 3426c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */ 342740266059SGregory Neil Shapiro if (mci != NULL && 342840266059SGregory Neil Shapiro (mci->mci_state == MCIS_MAIL || 342940266059SGregory Neil Shapiro mci->mci_state == MCIS_RCPT || 343040266059SGregory Neil Shapiro mci->mci_state == MCIS_DATA)) 3431c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 3432c2aa98e2SPeter Wemm } 3433c2aa98e2SPeter Wemm 3434c2aa98e2SPeter Wemm if (tobuf[0] != '\0') 343540266059SGregory Neil Shapiro { 343640266059SGregory Neil Shapiro giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); 343740266059SGregory Neil Shapiro #if 0 343840266059SGregory Neil Shapiro /* 343940266059SGregory Neil Shapiro ** This code is disabled for now because I am not 344040266059SGregory Neil Shapiro ** sure that copying status from the first recipient 344140266059SGregory Neil Shapiro ** to all non-status'ed recipients is a good idea. 344240266059SGregory Neil Shapiro */ 344340266059SGregory Neil Shapiro 344440266059SGregory Neil Shapiro if (tochain->q_message != NULL && 344540266059SGregory Neil Shapiro !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 344640266059SGregory Neil Shapiro { 344740266059SGregory Neil Shapiro for (to = tochain->q_tchain; to != NULL; 344840266059SGregory Neil Shapiro to = to->q_tchain) 344940266059SGregory Neil Shapiro { 345040266059SGregory Neil Shapiro /* see if address already marked */ 345140266059SGregory Neil Shapiro if (QS_IS_QUEUEUP(to->q_state) && 345240266059SGregory Neil Shapiro to->q_message == NULL) 345340266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 345440266059SGregory Neil Shapiro tochain->q_message); 345540266059SGregory Neil Shapiro } 345640266059SGregory Neil Shapiro } 345740266059SGregory Neil Shapiro #endif /* 0 */ 345840266059SGregory Neil Shapiro } 3459c2aa98e2SPeter Wemm if (anyok) 346040266059SGregory Neil Shapiro markstats(e, tochain, STATS_NORMAL); 3461c2aa98e2SPeter Wemm mci_store_persistent(mci); 3462c2aa98e2SPeter Wemm 346340266059SGregory Neil Shapiro /* Some recipients were tempfailed, try them on the next host */ 346440266059SGregory Neil Shapiro if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 346540266059SGregory Neil Shapiro { 346640266059SGregory Neil Shapiro /* try next MX site */ 346740266059SGregory Neil Shapiro goto tryhost; 346840266059SGregory Neil Shapiro } 346940266059SGregory Neil Shapiro 3470c2aa98e2SPeter Wemm /* now close the connection */ 3471c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 3472c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags)) 3473c2aa98e2SPeter Wemm smtpquit(m, mci, e); 3474c2aa98e2SPeter Wemm 347540266059SGregory Neil Shapiro cleanup: ; 347640266059SGregory Neil Shapiro } 347740266059SGregory Neil Shapiro SM_FINALLY 347840266059SGregory Neil Shapiro { 3479c2aa98e2SPeter Wemm /* 3480c2aa98e2SPeter Wemm ** Restore state and return. 3481c2aa98e2SPeter Wemm */ 3482c2aa98e2SPeter Wemm #if XDEBUG 3483c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 3484c2aa98e2SPeter Wemm 3485c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 348640266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, 348740266059SGregory Neil Shapiro "%s... end of deliver(%s)", 3488c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST" 348940266059SGregory Neil Shapiro : shortenstring(e->e_to, 349040266059SGregory Neil Shapiro MAXSHORTSTR), 3491c2aa98e2SPeter Wemm m->m_name); 3492c2aa98e2SPeter Wemm checkfd012(wbuf); 349306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 3494c2aa98e2SPeter Wemm 3495c2aa98e2SPeter Wemm errno = 0; 349640266059SGregory Neil Shapiro 349740266059SGregory Neil Shapiro /* 349840266059SGregory Neil Shapiro ** It was originally necessary to set macro 'g' to NULL 349940266059SGregory Neil Shapiro ** because it previously pointed to an auto buffer. 350040266059SGregory Neil Shapiro ** We don't do this any more, so this may be unnecessary. 350140266059SGregory Neil Shapiro */ 350240266059SGregory Neil Shapiro 350340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 350406f25ae9SGregory Neil Shapiro e->e_to = NULL; 350540266059SGregory Neil Shapiro } 350640266059SGregory Neil Shapiro SM_END_TRY 350706f25ae9SGregory Neil Shapiro return rcode; 3508c2aa98e2SPeter Wemm } 350906f25ae9SGregory Neil Shapiro 351040266059SGregory Neil Shapiro /* 3511c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address. 3512c2aa98e2SPeter Wemm ** 3513c2aa98e2SPeter Wemm ** Parameters: 3514c2aa98e2SPeter Wemm ** e -- the envelope we are sending. 3515c2aa98e2SPeter Wemm ** q -- the address to mark. 3516c2aa98e2SPeter Wemm ** mci -- mailer connection information. 3517c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure. 351806f25ae9SGregory Neil Shapiro ** ovr -- override an existing code? 3519c2aa98e2SPeter Wemm ** 3520c2aa98e2SPeter Wemm ** Returns: 3521c2aa98e2SPeter Wemm ** none. 3522c2aa98e2SPeter Wemm ** 3523c2aa98e2SPeter Wemm ** Side Effects: 3524c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the 3525c2aa98e2SPeter Wemm ** failure so that an error will be returned or 3526c2aa98e2SPeter Wemm ** the message will be queued, as appropriate. 3527c2aa98e2SPeter Wemm */ 3528c2aa98e2SPeter Wemm 352940266059SGregory Neil Shapiro void 353006f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr) 3531c2aa98e2SPeter Wemm register ENVELOPE *e; 3532c2aa98e2SPeter Wemm register ADDRESS *q; 3533c2aa98e2SPeter Wemm register MCI *mci; 3534c2aa98e2SPeter Wemm int rcode; 353506f25ae9SGregory Neil Shapiro bool ovr; 3536c2aa98e2SPeter Wemm { 353740266059SGregory Neil Shapiro int save_errno = errno; 353806f25ae9SGregory Neil Shapiro char *status = NULL; 353906f25ae9SGregory Neil Shapiro char *rstatus = NULL; 3540c2aa98e2SPeter Wemm 3541c2aa98e2SPeter Wemm switch (rcode) 3542c2aa98e2SPeter Wemm { 3543c2aa98e2SPeter Wemm case EX_OK: 3544c2aa98e2SPeter Wemm break; 3545c2aa98e2SPeter Wemm 3546c2aa98e2SPeter Wemm case EX_TEMPFAIL: 3547c2aa98e2SPeter Wemm case EX_IOERR: 3548c2aa98e2SPeter Wemm case EX_OSERR: 354906f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 3550c2aa98e2SPeter Wemm break; 3551c2aa98e2SPeter Wemm 3552c2aa98e2SPeter Wemm default: 355306f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 3554c2aa98e2SPeter Wemm break; 3555c2aa98e2SPeter Wemm } 3556c2aa98e2SPeter Wemm 3557c2aa98e2SPeter Wemm /* find most specific error code possible */ 3558c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL) 3559c2aa98e2SPeter Wemm { 356040266059SGregory Neil Shapiro status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 3561c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 356240266059SGregory Neil Shapiro rstatus = sm_rpool_strdup_x(e->e_rpool, 356340266059SGregory Neil Shapiro mci->mci_rstatus); 3564c2aa98e2SPeter Wemm else 356506f25ae9SGregory Neil Shapiro rstatus = NULL; 3566c2aa98e2SPeter Wemm } 3567c2aa98e2SPeter Wemm else if (e->e_status != NULL) 3568c2aa98e2SPeter Wemm { 356906f25ae9SGregory Neil Shapiro status = e->e_status; 357006f25ae9SGregory Neil Shapiro rstatus = NULL; 3571c2aa98e2SPeter Wemm } 3572c2aa98e2SPeter Wemm else 3573c2aa98e2SPeter Wemm { 3574c2aa98e2SPeter Wemm switch (rcode) 3575c2aa98e2SPeter Wemm { 3576c2aa98e2SPeter Wemm case EX_USAGE: 357706f25ae9SGregory Neil Shapiro status = "5.5.4"; 3578c2aa98e2SPeter Wemm break; 3579c2aa98e2SPeter Wemm 3580c2aa98e2SPeter Wemm case EX_DATAERR: 358106f25ae9SGregory Neil Shapiro status = "5.5.2"; 3582c2aa98e2SPeter Wemm break; 3583c2aa98e2SPeter Wemm 3584c2aa98e2SPeter Wemm case EX_NOUSER: 358506f25ae9SGregory Neil Shapiro status = "5.1.1"; 3586c2aa98e2SPeter Wemm break; 3587c2aa98e2SPeter Wemm 3588c2aa98e2SPeter Wemm case EX_NOHOST: 358906f25ae9SGregory Neil Shapiro status = "5.1.2"; 3590c2aa98e2SPeter Wemm break; 3591c2aa98e2SPeter Wemm 3592c2aa98e2SPeter Wemm case EX_NOINPUT: 3593c2aa98e2SPeter Wemm case EX_CANTCREAT: 3594c2aa98e2SPeter Wemm case EX_NOPERM: 359506f25ae9SGregory Neil Shapiro status = "5.3.0"; 3596c2aa98e2SPeter Wemm break; 3597c2aa98e2SPeter Wemm 3598c2aa98e2SPeter Wemm case EX_UNAVAILABLE: 3599c2aa98e2SPeter Wemm case EX_SOFTWARE: 3600c2aa98e2SPeter Wemm case EX_OSFILE: 3601c2aa98e2SPeter Wemm case EX_PROTOCOL: 3602c2aa98e2SPeter Wemm case EX_CONFIG: 360306f25ae9SGregory Neil Shapiro status = "5.5.0"; 3604c2aa98e2SPeter Wemm break; 3605c2aa98e2SPeter Wemm 3606c2aa98e2SPeter Wemm case EX_OSERR: 3607c2aa98e2SPeter Wemm case EX_IOERR: 360806f25ae9SGregory Neil Shapiro status = "4.5.0"; 3609c2aa98e2SPeter Wemm break; 3610c2aa98e2SPeter Wemm 3611c2aa98e2SPeter Wemm case EX_TEMPFAIL: 361206f25ae9SGregory Neil Shapiro status = "4.2.0"; 3613c2aa98e2SPeter Wemm break; 3614c2aa98e2SPeter Wemm } 3615c2aa98e2SPeter Wemm } 3616c2aa98e2SPeter Wemm 361706f25ae9SGregory Neil Shapiro /* new status? */ 361806f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 361906f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status)) 362006f25ae9SGregory Neil Shapiro { 362106f25ae9SGregory Neil Shapiro q->q_status = status; 362206f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus; 362306f25ae9SGregory Neil Shapiro } 3624c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL && 3625c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 362640266059SGregory Neil Shapiro sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 3627c2aa98e2SPeter Wemm { 362806f25ae9SGregory Neil Shapiro char buf[16]; 3629c2aa98e2SPeter Wemm 363040266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%d", rcode); 363140266059SGregory Neil Shapiro q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 3632c2aa98e2SPeter Wemm } 363306f25ae9SGregory Neil Shapiro 363406f25ae9SGregory Neil Shapiro q->q_statdate = curtime(); 363506f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' && 363606f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 363740266059SGregory Neil Shapiro q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 363840266059SGregory Neil Shapiro 363940266059SGregory Neil Shapiro /* restore errno */ 364040266059SGregory Neil Shapiro errno = save_errno; 3641c2aa98e2SPeter Wemm } 364240266059SGregory Neil Shapiro /* 3643c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate. 3644c2aa98e2SPeter Wemm ** 3645c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation 3646c2aa98e2SPeter Wemm ** violation), so we report those specially. For other 3647c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg), 3648c2aa98e2SPeter Wemm ** and if it represents an error, we print it. 3649c2aa98e2SPeter Wemm ** 3650c2aa98e2SPeter Wemm ** Parameters: 365113058a91SGregory Neil Shapiro ** mci -- the mailer connection info. 3652c2aa98e2SPeter Wemm ** e -- the current envelope. 3653c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer 3654c2aa98e2SPeter Wemm ** (for error messages). 3655c2aa98e2SPeter Wemm ** 3656c2aa98e2SPeter Wemm ** Returns: 3657c2aa98e2SPeter Wemm ** exit code of mailer. 3658c2aa98e2SPeter Wemm ** 3659c2aa98e2SPeter Wemm ** Side Effects: 3660c2aa98e2SPeter Wemm ** none. 3661c2aa98e2SPeter Wemm */ 3662c2aa98e2SPeter Wemm 366306f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout; 366406f25ae9SGregory Neil Shapiro 366506f25ae9SGregory Neil Shapiro static void 366606f25ae9SGregory Neil Shapiro endwaittimeout() 366706f25ae9SGregory Neil Shapiro { 36688774250cSGregory Neil Shapiro /* 36698774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 36708774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 36718774250cSGregory Neil Shapiro ** DOING. 36728774250cSGregory Neil Shapiro */ 36738774250cSGregory Neil Shapiro 367406f25ae9SGregory Neil Shapiro errno = ETIMEDOUT; 367506f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1); 367606f25ae9SGregory Neil Shapiro } 367706f25ae9SGregory Neil Shapiro 3678c2aa98e2SPeter Wemm int 3679c2aa98e2SPeter Wemm endmailer(mci, e, pv) 3680c2aa98e2SPeter Wemm register MCI *mci; 3681c2aa98e2SPeter Wemm register ENVELOPE *e; 3682c2aa98e2SPeter Wemm char **pv; 3683c2aa98e2SPeter Wemm { 3684c2aa98e2SPeter Wemm int st; 368506f25ae9SGregory Neil Shapiro int save_errno = errno; 368606f25ae9SGregory Neil Shapiro char buf[MAXLINE]; 368740266059SGregory Neil Shapiro SM_EVENT *ev = NULL; 368806f25ae9SGregory Neil Shapiro 3689c2aa98e2SPeter Wemm 3690c2aa98e2SPeter Wemm mci_unlock_host(mci); 3691c2aa98e2SPeter Wemm 36928774250cSGregory Neil Shapiro /* close output to mailer */ 36938774250cSGregory Neil Shapiro if (mci->mci_out != NULL) 369440266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 36958774250cSGregory Neil Shapiro 36968774250cSGregory Neil Shapiro /* copy any remaining input to transcript */ 36978774250cSGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 36988774250cSGregory Neil Shapiro e->e_xfp != NULL) 36998774250cSGregory Neil Shapiro { 37008774250cSGregory Neil Shapiro while (sfgets(buf, sizeof buf, mci->mci_in, 37018774250cSGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL) 370240266059SGregory Neil Shapiro (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 37038774250cSGregory Neil Shapiro } 37048774250cSGregory Neil Shapiro 370506f25ae9SGregory Neil Shapiro #if SASL 370640266059SGregory Neil Shapiro /* close SASL connection */ 370706f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 370806f25ae9SGregory Neil Shapiro { 370906f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 371006f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT; 371106f25ae9SGregory Neil Shapiro } 371206f25ae9SGregory Neil Shapiro #endif /* SASL */ 371306f25ae9SGregory Neil Shapiro 371406f25ae9SGregory Neil Shapiro #if STARTTLS 371506f25ae9SGregory Neil Shapiro /* shutdown TLS */ 371606f25ae9SGregory Neil Shapiro (void) endtlsclt(mci); 371706f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 371806f25ae9SGregory Neil Shapiro 371906f25ae9SGregory Neil Shapiro /* now close the input */ 372006f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 372140266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 3722c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 3723c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 3724c2aa98e2SPeter Wemm 372506f25ae9SGregory Neil Shapiro errno = save_errno; 372606f25ae9SGregory Neil Shapiro 3727c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */ 3728c2aa98e2SPeter Wemm if (mci->mci_pid == 0) 372906f25ae9SGregory Neil Shapiro return EX_OK; 3730c2aa98e2SPeter Wemm 373106f25ae9SGregory Neil Shapiro /* put a timeout around the wait */ 373206f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0) 373306f25ae9SGregory Neil Shapiro { 373406f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0) 373540266059SGregory Neil Shapiro ev = sm_setevent(mci->mci_mailer->m_wait, 373606f25ae9SGregory Neil Shapiro endwaittimeout, 0); 373706f25ae9SGregory Neil Shapiro else 373806f25ae9SGregory Neil Shapiro { 373942e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)", 374006f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, 374142e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait); 374206f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 374306f25ae9SGregory Neil Shapiro } 374406f25ae9SGregory Neil Shapiro } 3745c2aa98e2SPeter Wemm 374606f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */ 3747c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid); 374806f25ae9SGregory Neil Shapiro save_errno = errno; 374906f25ae9SGregory Neil Shapiro if (ev != NULL) 375040266059SGregory Neil Shapiro sm_clrevent(ev); 375106f25ae9SGregory Neil Shapiro errno = save_errno; 375206f25ae9SGregory Neil Shapiro 3753c2aa98e2SPeter Wemm if (st == -1) 3754c2aa98e2SPeter Wemm { 3755c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name); 375606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 3757c2aa98e2SPeter Wemm } 3758c2aa98e2SPeter Wemm 3759c2aa98e2SPeter Wemm if (WIFEXITED(st)) 3760c2aa98e2SPeter Wemm { 3761c2aa98e2SPeter Wemm /* normal death -- return status */ 3762c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 3763c2aa98e2SPeter Wemm } 3764c2aa98e2SPeter Wemm 3765c2aa98e2SPeter Wemm /* it died a horrid death */ 376606f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s", 376706f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st), 376806f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" : 376906f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : "")); 3770c2aa98e2SPeter Wemm 3771c2aa98e2SPeter Wemm /* log the arguments */ 3772c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL) 3773c2aa98e2SPeter Wemm { 3774c2aa98e2SPeter Wemm register char **av; 3775c2aa98e2SPeter Wemm 377640266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 3777c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 377840266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 377940266059SGregory Neil Shapiro *av); 378040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 3781c2aa98e2SPeter Wemm } 3782c2aa98e2SPeter Wemm 3783c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL; 378406f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 3785c2aa98e2SPeter Wemm } 378640266059SGregory Neil Shapiro /* 3787c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer 3788c2aa98e2SPeter Wemm ** 3789c2aa98e2SPeter Wemm ** Parameters: 379006f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte 3791c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of 3792c2aa98e2SPeter Wemm ** already). 379306f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any. 3794c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer. 3795c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 3796c2aa98e2SPeter Wemm ** response is given before the connection is made. 3797c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient 3798c2aa98e2SPeter Wemm ** address(es). 3799c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing 3800c2aa98e2SPeter Wemm ** transaction delays. 3801c2aa98e2SPeter Wemm ** e -- the current envelope. 380240266059SGregory Neil Shapiro ** to -- the current recipient (NULL if none). 3803c2aa98e2SPeter Wemm ** 3804c2aa98e2SPeter Wemm ** Returns: 3805c2aa98e2SPeter Wemm ** none. 3806c2aa98e2SPeter Wemm ** 3807c2aa98e2SPeter Wemm ** Side Effects: 3808c2aa98e2SPeter Wemm ** Errors may be incremented. 3809c2aa98e2SPeter Wemm ** ExitStat may be set. 3810c2aa98e2SPeter Wemm */ 3811c2aa98e2SPeter Wemm 3812c2aa98e2SPeter Wemm void 381340266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 381406f25ae9SGregory Neil Shapiro int status; 381506f25ae9SGregory Neil Shapiro char *dsn; 3816c2aa98e2SPeter Wemm register MAILER *m; 3817c2aa98e2SPeter Wemm register MCI *mci; 3818c2aa98e2SPeter Wemm ADDRESS *ctladdr; 3819c2aa98e2SPeter Wemm time_t xstart; 3820c2aa98e2SPeter Wemm ENVELOPE *e; 382140266059SGregory Neil Shapiro ADDRESS *to; 3822c2aa98e2SPeter Wemm { 3823c2aa98e2SPeter Wemm register const char *statmsg; 382406f25ae9SGregory Neil Shapiro int errnum = errno; 382506f25ae9SGregory Neil Shapiro int off = 4; 382640266059SGregory Neil Shapiro bool usestat = false; 382706f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN]; 3828c2aa98e2SPeter Wemm char buf[MAXLINE]; 382940266059SGregory Neil Shapiro char *exmsg; 3830c2aa98e2SPeter Wemm 3831c2aa98e2SPeter Wemm if (e == NULL) 3832c2aa98e2SPeter Wemm syserr("giveresponse: null envelope"); 3833c2aa98e2SPeter Wemm 3834c2aa98e2SPeter Wemm /* 3835c2aa98e2SPeter Wemm ** Compute status message from code. 3836c2aa98e2SPeter Wemm */ 3837c2aa98e2SPeter Wemm 383840266059SGregory Neil Shapiro exmsg = sm_sysexmsg(status); 383906f25ae9SGregory Neil Shapiro if (status == 0) 3840c2aa98e2SPeter Wemm { 384106f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent"; 3842c2aa98e2SPeter Wemm if (e->e_statmsg != NULL) 3843c2aa98e2SPeter Wemm { 384440266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s (%s)", 384506f25ae9SGregory Neil Shapiro statmsg, 384606f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 3847c2aa98e2SPeter Wemm statmsg = buf; 3848c2aa98e2SPeter Wemm } 3849c2aa98e2SPeter Wemm } 385040266059SGregory Neil Shapiro else if (exmsg == NULL) 3851c2aa98e2SPeter Wemm { 385240266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, 385306f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d", 385406f25ae9SGregory Neil Shapiro status); 385506f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE; 3856c2aa98e2SPeter Wemm statmsg = buf; 385740266059SGregory Neil Shapiro usestat = true; 3858c2aa98e2SPeter Wemm } 385906f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL) 3860c2aa98e2SPeter Wemm { 3861c2aa98e2SPeter Wemm char *bp = buf; 3862c2aa98e2SPeter Wemm 386340266059SGregory Neil Shapiro (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 3864c2aa98e2SPeter Wemm bp += strlen(bp); 3865c2aa98e2SPeter Wemm #if NAMED_BIND 3866c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN) 386740266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 3868c2aa98e2SPeter Wemm else 386906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3870c2aa98e2SPeter Wemm { 387106f25ae9SGregory Neil Shapiro if (errnum != 0) 387240266059SGregory Neil Shapiro statmsg = sm_errstring(errnum); 3873c2aa98e2SPeter Wemm else 3874c2aa98e2SPeter Wemm statmsg = SmtpError; 3875c2aa98e2SPeter Wemm } 3876c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0') 387706f25ae9SGregory Neil Shapiro { 387806f25ae9SGregory Neil Shapiro switch (errnum) 387906f25ae9SGregory Neil Shapiro { 388006f25ae9SGregory Neil Shapiro #ifdef ENETDOWN 388106f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */ 388206f25ae9SGregory Neil Shapiro #endif /* ENETDOWN */ 388306f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH 388406f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */ 388506f25ae9SGregory Neil Shapiro #endif /* ENETUNREACH */ 388606f25ae9SGregory Neil Shapiro #ifdef ENETRESET 388706f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */ 388806f25ae9SGregory Neil Shapiro #endif /* ENETRESET */ 388906f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED 389006f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */ 389106f25ae9SGregory Neil Shapiro #endif /* ECONNABORTED */ 389206f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN 389306f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */ 389406f25ae9SGregory Neil Shapiro #endif /* EHOSTDOWN */ 389506f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH 389606f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */ 389706f25ae9SGregory Neil Shapiro #endif /* EHOSTUNREACH */ 389806f25ae9SGregory Neil Shapiro if (mci->mci_host != NULL) 389906f25ae9SGregory Neil Shapiro { 390040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, 390140266059SGregory Neil Shapiro SPACELEFT(buf, bp), 390240266059SGregory Neil Shapiro 2, ": ", 390340266059SGregory Neil Shapiro mci->mci_host); 390406f25ae9SGregory Neil Shapiro bp += strlen(bp); 390506f25ae9SGregory Neil Shapiro } 390606f25ae9SGregory Neil Shapiro break; 390706f25ae9SGregory Neil Shapiro } 390840266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 390940266059SGregory Neil Shapiro statmsg); 391040266059SGregory Neil Shapiro usestat = true; 391106f25ae9SGregory Neil Shapiro } 3912c2aa98e2SPeter Wemm statmsg = buf; 3913c2aa98e2SPeter Wemm } 3914c2aa98e2SPeter Wemm #if NAMED_BIND 391506f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0) 3916c2aa98e2SPeter Wemm { 391740266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 391840266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1, 391940266059SGregory Neil Shapiro statmsg); 3920c2aa98e2SPeter Wemm statmsg = buf; 392140266059SGregory Neil Shapiro usestat = true; 3922c2aa98e2SPeter Wemm } 392306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3924c2aa98e2SPeter Wemm else 3925c2aa98e2SPeter Wemm { 392640266059SGregory Neil Shapiro statmsg = exmsg; 392706f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0) 3928c2aa98e2SPeter Wemm { 392940266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg, 393040266059SGregory Neil Shapiro sm_errstring(errnum)); 3931c2aa98e2SPeter Wemm statmsg = buf; 393240266059SGregory Neil Shapiro usestat = true; 3933c2aa98e2SPeter Wemm } 3934c2aa98e2SPeter Wemm } 3935c2aa98e2SPeter Wemm 3936c2aa98e2SPeter Wemm /* 3937c2aa98e2SPeter Wemm ** Print the message as appropriate 3938c2aa98e2SPeter Wemm */ 3939c2aa98e2SPeter Wemm 394006f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL) 3941c2aa98e2SPeter Wemm { 3942c2aa98e2SPeter Wemm extern char MsgBuf[]; 3943c2aa98e2SPeter Wemm 394406f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0) 394506f25ae9SGregory Neil Shapiro { 394606f25ae9SGregory Neil Shapiro if (dsn == NULL) 394706f25ae9SGregory Neil Shapiro { 394840266059SGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 394906f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 395006f25ae9SGregory Neil Shapiro dsn = dsnbuf; 395106f25ae9SGregory Neil Shapiro } 395206f25ae9SGregory Neil Shapiro off += 5; 395306f25ae9SGregory Neil Shapiro } 395406f25ae9SGregory Neil Shapiro else 395506f25ae9SGregory Neil Shapiro { 395606f25ae9SGregory Neil Shapiro off = 4; 395706f25ae9SGregory Neil Shapiro } 395806f25ae9SGregory Neil Shapiro message("%s", statmsg + off); 395906f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL) 396040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 396140266059SGregory Neil Shapiro &MsgBuf[4]); 3962c2aa98e2SPeter Wemm } 3963c2aa98e2SPeter Wemm else 3964c2aa98e2SPeter Wemm { 396506f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4]; 3966c2aa98e2SPeter Wemm 3967c2aa98e2SPeter Wemm Errors++; 396806f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 396906f25ae9SGregory Neil Shapiro off < sizeof mbuf - 4) 397006f25ae9SGregory Neil Shapiro { 397106f25ae9SGregory Neil Shapiro if (dsn == NULL) 397206f25ae9SGregory Neil Shapiro { 397340266059SGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 397406f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 397506f25ae9SGregory Neil Shapiro dsn = dsnbuf; 397606f25ae9SGregory Neil Shapiro } 397706f25ae9SGregory Neil Shapiro off += 5; 397840266059SGregory Neil Shapiro 397940266059SGregory Neil Shapiro /* copy only part of statmsg to mbuf */ 398040266059SGregory Neil Shapiro (void) sm_strlcpy(mbuf, statmsg, off); 398140266059SGregory Neil Shapiro (void) sm_strlcat(mbuf, " %s", sizeof mbuf); 398206f25ae9SGregory Neil Shapiro } 398306f25ae9SGregory Neil Shapiro else 398406f25ae9SGregory Neil Shapiro { 398506f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0'; 398640266059SGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s", 398740266059SGregory Neil Shapiro statmsg); 398806f25ae9SGregory Neil Shapiro off = 4; 398906f25ae9SGregory Neil Shapiro } 399006f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]); 3991c2aa98e2SPeter Wemm } 3992c2aa98e2SPeter Wemm 3993c2aa98e2SPeter Wemm /* 3994c2aa98e2SPeter Wemm ** Final cleanup. 3995c2aa98e2SPeter Wemm ** Log a record of the transaction. Compute the new 3996c2aa98e2SPeter Wemm ** ExitStat -- if we already had an error, stick with 3997c2aa98e2SPeter Wemm ** that. 3998c2aa98e2SPeter Wemm */ 3999c2aa98e2SPeter Wemm 4000c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 400106f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 400206f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 4003c2aa98e2SPeter Wemm 4004c2aa98e2SPeter Wemm if (tTd(11, 2)) 400540266059SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 400606f25ae9SGregory Neil Shapiro status, 400706f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn, 400840266059SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message, 400940266059SGregory Neil Shapiro errnum); 4010c2aa98e2SPeter Wemm 401106f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL) 401206f25ae9SGregory Neil Shapiro setstat(status); 401306f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 401440266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 401540266059SGregory Neil Shapiro if (status != EX_OK && to != NULL && to->q_message == NULL) 4016c2aa98e2SPeter Wemm { 401740266059SGregory Neil Shapiro if (!usestat && e->e_message != NULL) 401840266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 401940266059SGregory Neil Shapiro e->e_message); 402040266059SGregory Neil Shapiro else 402140266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 402240266059SGregory Neil Shapiro statmsg + off); 4023c2aa98e2SPeter Wemm } 4024c2aa98e2SPeter Wemm errno = 0; 4025602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 4026c2aa98e2SPeter Wemm } 402740266059SGregory Neil Shapiro /* 4028c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log 4029c2aa98e2SPeter Wemm ** 4030c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because 4031c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core 4032c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical. 4033c2aa98e2SPeter Wemm ** 4034c2aa98e2SPeter Wemm ** Parameters: 4035c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue. 4036c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 403706f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active. 403806f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status. 403906f25ae9SGregory Neil Shapiro ** status -- the message to print for the status. 4040c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list. 4041c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for 4042c2aa98e2SPeter Wemm ** computing transaction delay. 4043c2aa98e2SPeter Wemm ** e -- the current envelope. 4044c2aa98e2SPeter Wemm ** 4045c2aa98e2SPeter Wemm ** Returns: 4046c2aa98e2SPeter Wemm ** none 4047c2aa98e2SPeter Wemm ** 4048c2aa98e2SPeter Wemm ** Side Effects: 4049c2aa98e2SPeter Wemm ** none 4050c2aa98e2SPeter Wemm */ 4051c2aa98e2SPeter Wemm 4052c2aa98e2SPeter Wemm void 405306f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 4054c2aa98e2SPeter Wemm MAILER *m; 4055c2aa98e2SPeter Wemm register MCI *mci; 405606f25ae9SGregory Neil Shapiro char *dsn; 405706f25ae9SGregory Neil Shapiro const char *status; 4058c2aa98e2SPeter Wemm ADDRESS *ctladdr; 4059c2aa98e2SPeter Wemm time_t xstart; 4060c2aa98e2SPeter Wemm register ENVELOPE *e; 4061c2aa98e2SPeter Wemm { 4062c2aa98e2SPeter Wemm register char *bp; 4063c2aa98e2SPeter Wemm register char *p; 4064c2aa98e2SPeter Wemm int l; 406540266059SGregory Neil Shapiro time_t now = curtime(); 4066c2aa98e2SPeter Wemm char buf[1024]; 4067c2aa98e2SPeter Wemm 4068c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 4069c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */ 4070c2aa98e2SPeter Wemm bp = buf; 4071c2aa98e2SPeter Wemm if (ctladdr != NULL) 4072c2aa98e2SPeter Wemm { 407340266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 4074c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4075c2aa98e2SPeter Wemm bp += strlen(bp); 4076c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4077c2aa98e2SPeter Wemm { 407840266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 407906f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid, 408006f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid); 4081c2aa98e2SPeter Wemm bp += strlen(bp); 4082c2aa98e2SPeter Wemm } 4083c2aa98e2SPeter Wemm } 4084c2aa98e2SPeter Wemm 4085c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */ 408640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 408740266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4088c2aa98e2SPeter Wemm bp += strlen(bp); 4089c2aa98e2SPeter Wemm 4090c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4091c2aa98e2SPeter Wemm { 409240266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 409340266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4094c2aa98e2SPeter Wemm bp += strlen(bp); 4095c2aa98e2SPeter Wemm } 4096c2aa98e2SPeter Wemm 4097c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 4098c2aa98e2SPeter Wemm if (m != NULL) 4099c2aa98e2SPeter Wemm { 410040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 410140266059SGregory Neil Shapiro m->m_name); 4102c2aa98e2SPeter Wemm bp += strlen(bp); 4103c2aa98e2SPeter Wemm } 4104c2aa98e2SPeter Wemm 410506f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */ 410640266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 410740266059SGregory Neil Shapiro e->e_msgpriority); 410806f25ae9SGregory Neil Shapiro bp += strlen(bp); 410906f25ae9SGregory Neil Shapiro 4110c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */ 4111c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4112c2aa98e2SPeter Wemm { 4113c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4114c2aa98e2SPeter Wemm 411540266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 4116c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40)); 4117c2aa98e2SPeter Wemm bp += strlen(bp); 4118c2aa98e2SPeter Wemm 4119c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 4120c2aa98e2SPeter Wemm { 412140266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 4122c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4123c2aa98e2SPeter Wemm } 4124c2aa98e2SPeter Wemm } 412540266059SGregory Neil Shapiro #if _FFR_QUARANTINE 412640266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 412740266059SGregory Neil Shapiro { 412840266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 412940266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 413040266059SGregory Neil Shapiro ", quarantine=%s", 413140266059SGregory Neil Shapiro shortenstring(e->e_quarmsg, 40)); 413240266059SGregory Neil Shapiro } 413340266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 413406f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4135c2aa98e2SPeter Wemm { 4136c2aa98e2SPeter Wemm p = macvalue('h', e); 4137c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4138c2aa98e2SPeter Wemm { 413940266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 414040266059SGregory Neil Shapiro ", relay=%s", shortenstring(p, 40)); 4141c2aa98e2SPeter Wemm } 4142c2aa98e2SPeter Wemm } 4143c2aa98e2SPeter Wemm bp += strlen(bp); 4144c2aa98e2SPeter Wemm 414506f25ae9SGregory Neil Shapiro /* dsn */ 414606f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0') 414706f25ae9SGregory Neil Shapiro { 414840266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 414906f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN)); 415006f25ae9SGregory Neil Shapiro bp += strlen(bp); 415106f25ae9SGregory Neil Shapiro } 415206f25ae9SGregory Neil Shapiro 4153c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 4154c2aa98e2SPeter Wemm # if (STATLEN) < 63 4155c2aa98e2SPeter Wemm # undef STATLEN 4156c2aa98e2SPeter Wemm # define STATLEN 63 415706f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */ 4158c2aa98e2SPeter Wemm # if (STATLEN) > 203 4159c2aa98e2SPeter Wemm # undef STATLEN 4160c2aa98e2SPeter Wemm # define STATLEN 203 416106f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */ 4162c2aa98e2SPeter Wemm 4163c2aa98e2SPeter Wemm /* stat: max 210 bytes */ 4164c2aa98e2SPeter Wemm if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 4165c2aa98e2SPeter Wemm { 4166c2aa98e2SPeter Wemm /* desperation move -- truncate data */ 4167c2aa98e2SPeter Wemm bp = buf + sizeof buf - ((STATLEN) + 17); 416840266059SGregory Neil Shapiro (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 4169c2aa98e2SPeter Wemm bp += 3; 4170c2aa98e2SPeter Wemm } 4171c2aa98e2SPeter Wemm 417240266059SGregory Neil Shapiro (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 4173c2aa98e2SPeter Wemm bp += strlen(bp); 4174c2aa98e2SPeter Wemm 417540266059SGregory Neil Shapiro (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 417640266059SGregory Neil Shapiro SPACELEFT(buf, bp)); 4177c2aa98e2SPeter Wemm 4178c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */ 4179c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf); 418040266059SGregory Neil Shapiro if (l < 0) 418140266059SGregory Neil Shapiro l = 0; 418206f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 418340266059SGregory Neil Shapiro while (strlen(p) >= l) 4184c2aa98e2SPeter Wemm { 418506f25ae9SGregory Neil Shapiro register char *q; 4186c2aa98e2SPeter Wemm 418706f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 418806f25ae9SGregory Neil Shapiro { 418906f25ae9SGregory Neil Shapiro if (*q == ',') 419006f25ae9SGregory Neil Shapiro break; 419106f25ae9SGregory Neil Shapiro } 419206f25ae9SGregory Neil Shapiro if (p == q) 419306f25ae9SGregory Neil Shapiro break; 419440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 419542e5d165SGregory Neil Shapiro (int) (++q - p), p, buf); 4196c2aa98e2SPeter Wemm p = q; 4197c2aa98e2SPeter Wemm } 419806f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 4199c2aa98e2SPeter Wemm 420006f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 4201c2aa98e2SPeter Wemm 4202c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85; 420340266059SGregory Neil Shapiro if (l < 0) 420440266059SGregory Neil Shapiro l = 0; 420506f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 420640266059SGregory Neil Shapiro while (strlen(p) >= l) 4207c2aa98e2SPeter Wemm { 420806f25ae9SGregory Neil Shapiro register char *q; 4209c2aa98e2SPeter Wemm 421006f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 421106f25ae9SGregory Neil Shapiro { 421206f25ae9SGregory Neil Shapiro if (*q == ',') 421306f25ae9SGregory Neil Shapiro break; 421406f25ae9SGregory Neil Shapiro } 421506f25ae9SGregory Neil Shapiro if (p == q) 421606f25ae9SGregory Neil Shapiro break; 421706f25ae9SGregory Neil Shapiro 421840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 421942e5d165SGregory Neil Shapiro (int) (++q - p), p); 4220c2aa98e2SPeter Wemm p = q; 4221c2aa98e2SPeter Wemm } 422206f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 4223c2aa98e2SPeter Wemm 4224c2aa98e2SPeter Wemm if (ctladdr != NULL) 4225c2aa98e2SPeter Wemm { 4226c2aa98e2SPeter Wemm bp = buf; 422740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 4228c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4229c2aa98e2SPeter Wemm bp += strlen(bp); 4230c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4231c2aa98e2SPeter Wemm { 423240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 4233c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid); 4234c2aa98e2SPeter Wemm bp += strlen(bp); 4235c2aa98e2SPeter Wemm } 4236c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf); 4237c2aa98e2SPeter Wemm } 4238c2aa98e2SPeter Wemm bp = buf; 423940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 424040266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4241c2aa98e2SPeter Wemm bp += strlen(bp); 4242c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4243c2aa98e2SPeter Wemm { 424440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 424540266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4246c2aa98e2SPeter Wemm bp += strlen(bp); 4247c2aa98e2SPeter Wemm } 4248c2aa98e2SPeter Wemm 4249c2aa98e2SPeter Wemm if (m != NULL) 4250c2aa98e2SPeter Wemm { 425140266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 425240266059SGregory Neil Shapiro m->m_name); 4253c2aa98e2SPeter Wemm bp += strlen(bp); 4254c2aa98e2SPeter Wemm } 4255c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4256c2aa98e2SPeter Wemm 4257c2aa98e2SPeter Wemm buf[0] = '\0'; 4258c2aa98e2SPeter Wemm bp = buf; 4259c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4260c2aa98e2SPeter Wemm { 4261c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4262c2aa98e2SPeter Wemm 426340266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 426440266059SGregory Neil Shapiro mci->mci_host); 4265c2aa98e2SPeter Wemm bp += strlen(bp); 4266c2aa98e2SPeter Wemm 4267c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 426840266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 426940266059SGregory Neil Shapiro " [%.100s]", 4270c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4271c2aa98e2SPeter Wemm } 427240266059SGregory Neil Shapiro #if _FFR_QUARANTINE 427340266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 427440266059SGregory Neil Shapiro { 427540266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 427640266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 427740266059SGregory Neil Shapiro ", quarantine=%.100s", 427840266059SGregory Neil Shapiro e->e_quarmsg); 427940266059SGregory Neil Shapiro } 428040266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 428106f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4282c2aa98e2SPeter Wemm { 4283c2aa98e2SPeter Wemm p = macvalue('h', e); 4284c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 428540266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p); 4286c2aa98e2SPeter Wemm } 4287c2aa98e2SPeter Wemm if (buf[0] != '\0') 4288c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4289c2aa98e2SPeter Wemm 429006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 429106f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 4292c2aa98e2SPeter Wemm } 429340266059SGregory Neil Shapiro /* 4294c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 4295c2aa98e2SPeter Wemm ** 4296c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l 4297c2aa98e2SPeter Wemm ** 4298c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein: 4299c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why 4300c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with 4301c2aa98e2SPeter Wemm ** this kind of antique garbage???? 4302c2aa98e2SPeter Wemm ** 4303c2aa98e2SPeter Wemm ** Parameters: 4304c2aa98e2SPeter Wemm ** mci -- the connection information. 4305c2aa98e2SPeter Wemm ** e -- the envelope. 4306c2aa98e2SPeter Wemm ** 4307c2aa98e2SPeter Wemm ** Returns: 4308c2aa98e2SPeter Wemm ** none 4309c2aa98e2SPeter Wemm ** 4310c2aa98e2SPeter Wemm ** Side Effects: 4311c2aa98e2SPeter Wemm ** outputs some text to fp. 4312c2aa98e2SPeter Wemm */ 4313c2aa98e2SPeter Wemm 4314c2aa98e2SPeter Wemm void 4315c2aa98e2SPeter Wemm putfromline(mci, e) 4316c2aa98e2SPeter Wemm register MCI *mci; 4317c2aa98e2SPeter Wemm ENVELOPE *e; 4318c2aa98e2SPeter Wemm { 4319c2aa98e2SPeter Wemm char *template = UnixFromLine; 4320c2aa98e2SPeter Wemm char buf[MAXLINE]; 4321c2aa98e2SPeter Wemm char xbuf[MAXLINE]; 4322c2aa98e2SPeter Wemm 4323c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 4324c2aa98e2SPeter Wemm return; 4325c2aa98e2SPeter Wemm 4326c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4327c2aa98e2SPeter Wemm 4328c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 4329c2aa98e2SPeter Wemm { 4330c2aa98e2SPeter Wemm char *bang; 4331c2aa98e2SPeter Wemm 4332c2aa98e2SPeter Wemm expand("\201g", buf, sizeof buf, e); 4333c2aa98e2SPeter Wemm bang = strchr(buf, '!'); 4334c2aa98e2SPeter Wemm if (bang == NULL) 4335c2aa98e2SPeter Wemm { 4336c2aa98e2SPeter Wemm char *at; 4337c2aa98e2SPeter Wemm char hname[MAXNAME]; 4338c2aa98e2SPeter Wemm 4339c2aa98e2SPeter Wemm /* 4340c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so 4341c2aa98e2SPeter Wemm */ 4342c2aa98e2SPeter Wemm 4343c2aa98e2SPeter Wemm at = strrchr(buf, '@'); 4344c2aa98e2SPeter Wemm if (at == NULL) 4345c2aa98e2SPeter Wemm { 4346c2aa98e2SPeter Wemm expand("\201k", hname, sizeof hname, e); 4347c2aa98e2SPeter Wemm at = hname; 4348c2aa98e2SPeter Wemm } 4349c2aa98e2SPeter Wemm else 4350c2aa98e2SPeter Wemm *at++ = '\0'; 435140266059SGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof xbuf, 4352c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4353c2aa98e2SPeter Wemm buf, at); 4354c2aa98e2SPeter Wemm } 4355c2aa98e2SPeter Wemm else 4356c2aa98e2SPeter Wemm { 4357c2aa98e2SPeter Wemm *bang++ = '\0'; 435840266059SGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof xbuf, 4359c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4360c2aa98e2SPeter Wemm bang, buf); 4361c2aa98e2SPeter Wemm template = xbuf; 4362c2aa98e2SPeter Wemm } 4363c2aa98e2SPeter Wemm } 4364c2aa98e2SPeter Wemm expand(template, buf, sizeof buf, e); 4365c2aa98e2SPeter Wemm putxline(buf, strlen(buf), mci, PXLF_HEADER); 4366c2aa98e2SPeter Wemm } 436740266059SGregory Neil Shapiro /* 4368c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message. 4369c2aa98e2SPeter Wemm ** 4370c2aa98e2SPeter Wemm ** Parameters: 4371c2aa98e2SPeter Wemm ** mci -- the connection information. 4372c2aa98e2SPeter Wemm ** e -- the envelope to put out. 4373c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must 4374c2aa98e2SPeter Wemm ** not be permitted in the resulting message. 4375c2aa98e2SPeter Wemm ** 4376c2aa98e2SPeter Wemm ** Returns: 4377c2aa98e2SPeter Wemm ** none. 4378c2aa98e2SPeter Wemm ** 4379c2aa98e2SPeter Wemm ** Side Effects: 4380c2aa98e2SPeter Wemm ** The message is written onto fp. 4381c2aa98e2SPeter Wemm */ 4382c2aa98e2SPeter Wemm 4383c2aa98e2SPeter Wemm /* values for output state variable */ 4384c2aa98e2SPeter Wemm #define OS_HEAD 0 /* at beginning of line */ 4385c2aa98e2SPeter Wemm #define OS_CR 1 /* read a carriage return */ 4386c2aa98e2SPeter Wemm #define OS_INLINE 2 /* putting rest of line */ 4387c2aa98e2SPeter Wemm 4388c2aa98e2SPeter Wemm void 4389c2aa98e2SPeter Wemm putbody(mci, e, separator) 4390c2aa98e2SPeter Wemm register MCI *mci; 4391c2aa98e2SPeter Wemm register ENVELOPE *e; 4392c2aa98e2SPeter Wemm char *separator; 4393c2aa98e2SPeter Wemm { 439440266059SGregory Neil Shapiro bool dead = false; 4395c2aa98e2SPeter Wemm char buf[MAXLINE]; 439640266059SGregory Neil Shapiro #if MIME8TO7 4397065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1]; 439840266059SGregory Neil Shapiro #endif /* MIME8TO7 */ 4399c2aa98e2SPeter Wemm 4400c2aa98e2SPeter Wemm /* 4401c2aa98e2SPeter Wemm ** Output the body of the message 4402c2aa98e2SPeter Wemm */ 4403c2aa98e2SPeter Wemm 4404c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 4405c2aa98e2SPeter Wemm { 440640266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 4407c2aa98e2SPeter Wemm 440840266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 440940266059SGregory Neil Shapiro SM_IO_RDONLY, NULL); 4410c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 441106f25ae9SGregory Neil Shapiro { 441206f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s"; 441306f25ae9SGregory Neil Shapiro 441406f25ae9SGregory Neil Shapiro if (errno == ENOENT) 441506f25ae9SGregory Neil Shapiro msg++; 441606f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr); 441706f25ae9SGregory Neil Shapiro } 441840266059SGregory Neil Shapiro 4419c2aa98e2SPeter Wemm } 4420c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 4421c2aa98e2SPeter Wemm { 4422c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4423c2aa98e2SPeter Wemm { 4424c2aa98e2SPeter Wemm putline("", mci); 4425c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4426c2aa98e2SPeter Wemm } 4427c2aa98e2SPeter Wemm putline("<<< No Message Collected >>>", mci); 4428c2aa98e2SPeter Wemm goto endofmessage; 4429c2aa98e2SPeter Wemm } 443006f25ae9SGregory Neil Shapiro 4431c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0) 4432c2aa98e2SPeter Wemm { 4433c2aa98e2SPeter Wemm struct stat stbuf; 4434c2aa98e2SPeter Wemm 443540266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 443640266059SGregory Neil Shapiro < 0) 4437c2aa98e2SPeter Wemm e->e_dfino = -1; 4438c2aa98e2SPeter Wemm else 4439c2aa98e2SPeter Wemm { 4440c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 4441c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 4442c2aa98e2SPeter Wemm } 4443c2aa98e2SPeter Wemm } 444406f25ae9SGregory Neil Shapiro 444540266059SGregory Neil Shapiro /* paranoia: the data file should always be in a rewound state */ 444606f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 4447c2aa98e2SPeter Wemm 4448c2aa98e2SPeter Wemm #if MIME8TO7 4449c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 4450c2aa98e2SPeter Wemm { 4451c2aa98e2SPeter Wemm /* 4452c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion. 4453c2aa98e2SPeter Wemm */ 4454c2aa98e2SPeter Wemm 4455c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */ 4456c2aa98e2SPeter Wemm if (hvalue("MIME-Version", e->e_header) == NULL) 4457c2aa98e2SPeter Wemm putline("MIME-Version: 1.0", mci); 4458c2aa98e2SPeter Wemm 4459c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 4460c2aa98e2SPeter Wemm { 446140266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, 4462c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 4463c2aa98e2SPeter Wemm defcharset(e)); 4464c2aa98e2SPeter Wemm putline(buf, mci); 4465c2aa98e2SPeter Wemm } 4466c2aa98e2SPeter Wemm 4467c2aa98e2SPeter Wemm /* now do the hard work */ 4468c2aa98e2SPeter Wemm boundaries[0] = NULL; 4469c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 447006f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 4471c2aa98e2SPeter Wemm } 4472c2aa98e2SPeter Wemm # if MIME7TO8 4473c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 4474c2aa98e2SPeter Wemm { 447506f25ae9SGregory Neil Shapiro (void) mime7to8(mci, e->e_header, e); 4476c2aa98e2SPeter Wemm } 447706f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */ 4478065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 4479065a643dSPeter Wemm { 448006f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs; 448106f25ae9SGregory Neil Shapiro 4482065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */ 4483065a643dSPeter Wemm boundaries[0] = NULL; 4484065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER; 448506f25ae9SGregory Neil Shapiro 448606f25ae9SGregory Neil Shapiro /* 448706f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message 448806f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose 448906f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call 449006f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security 449106f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors. 449206f25ae9SGregory Neil Shapiro */ 449306f25ae9SGregory Neil Shapiro 449406f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags)) 449540266059SGregory Neil Shapiro SuprErrs = true; 449606f25ae9SGregory Neil Shapiro 449706f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, 449806f25ae9SGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7); 449906f25ae9SGregory Neil Shapiro 450006f25ae9SGregory Neil Shapiro /* restore SuprErrs */ 450106f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs; 4502065a643dSPeter Wemm } 4503c2aa98e2SPeter Wemm else 450406f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */ 4505c2aa98e2SPeter Wemm { 4506c2aa98e2SPeter Wemm int ostate; 4507c2aa98e2SPeter Wemm register char *bp; 4508c2aa98e2SPeter Wemm register char *pbp; 4509c2aa98e2SPeter Wemm register int c; 4510c2aa98e2SPeter Wemm register char *xp; 4511c2aa98e2SPeter Wemm int padc; 4512c2aa98e2SPeter Wemm char *buflim; 4513c2aa98e2SPeter Wemm int pos = 0; 451406f25ae9SGregory Neil Shapiro char peekbuf[12]; 4515c2aa98e2SPeter Wemm 4516c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4517c2aa98e2SPeter Wemm { 4518c2aa98e2SPeter Wemm putline("", mci); 4519c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4520c2aa98e2SPeter Wemm } 4521c2aa98e2SPeter Wemm 4522c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */ 4523c2aa98e2SPeter Wemm buflim = &buf[sizeof buf - 1]; 4524c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 4525c2aa98e2SPeter Wemm mci->mci_mailer->m_linelimit < sizeof buf - 1) 4526c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 4527c2aa98e2SPeter Wemm 4528c2aa98e2SPeter Wemm /* copy temp file to output with mapping */ 4529c2aa98e2SPeter Wemm ostate = OS_HEAD; 4530c2aa98e2SPeter Wemm bp = buf; 4531c2aa98e2SPeter Wemm pbp = peekbuf; 453240266059SGregory Neil Shapiro while (!sm_io_error(mci->mci_out) && !dead) 4533c2aa98e2SPeter Wemm { 4534c2aa98e2SPeter Wemm if (pbp > peekbuf) 4535c2aa98e2SPeter Wemm c = *--pbp; 453640266059SGregory Neil Shapiro else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 453740266059SGregory Neil Shapiro == SM_IO_EOF) 4538c2aa98e2SPeter Wemm break; 4539c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags)) 4540c2aa98e2SPeter Wemm c &= 0x7f; 4541c2aa98e2SPeter Wemm switch (ostate) 4542c2aa98e2SPeter Wemm { 4543c2aa98e2SPeter Wemm case OS_HEAD: 4544c2aa98e2SPeter Wemm if (c == '\0' && 454540266059SGregory Neil Shapiro bitnset(M_NONULLS, 454640266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4547c2aa98e2SPeter Wemm break; 4548c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim) 4549c2aa98e2SPeter Wemm { 4550c2aa98e2SPeter Wemm *bp++ = c; 4551c2aa98e2SPeter Wemm break; 4552c2aa98e2SPeter Wemm } 4553c2aa98e2SPeter Wemm 4554c2aa98e2SPeter Wemm /* check beginning of line for special cases */ 4555c2aa98e2SPeter Wemm *bp = '\0'; 4556c2aa98e2SPeter Wemm pos = 0; 455740266059SGregory Neil Shapiro padc = SM_IO_EOF; 4558c2aa98e2SPeter Wemm if (buf[0] == 'F' && 455940266059SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 456040266059SGregory Neil Shapiro && strncmp(buf, "From ", 5) == 0) 4561c2aa98e2SPeter Wemm { 4562c2aa98e2SPeter Wemm padc = '>'; 4563c2aa98e2SPeter Wemm } 4564c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' && 4565c2aa98e2SPeter Wemm separator != NULL) 4566c2aa98e2SPeter Wemm { 4567c2aa98e2SPeter Wemm /* possible separator */ 4568c2aa98e2SPeter Wemm int sl = strlen(separator); 4569c2aa98e2SPeter Wemm 457040266059SGregory Neil Shapiro if (strncmp(&buf[2], separator, sl) 457140266059SGregory Neil Shapiro == 0) 4572c2aa98e2SPeter Wemm padc = ' '; 4573c2aa98e2SPeter Wemm } 4574c2aa98e2SPeter Wemm if (buf[0] == '.' && 4575c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 4576c2aa98e2SPeter Wemm { 4577c2aa98e2SPeter Wemm padc = '.'; 4578c2aa98e2SPeter Wemm } 4579c2aa98e2SPeter Wemm 4580c2aa98e2SPeter Wemm /* now copy out saved line */ 4581c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4582c2aa98e2SPeter Wemm { 458340266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 458440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 458540266059SGregory Neil Shapiro "%05d >>> ", 458640266059SGregory Neil Shapiro (int) CurrentPid); 458740266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 458840266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 458940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 459040266059SGregory Neil Shapiro padc); 4591c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 459240266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 459340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 459440266059SGregory Neil Shapiro (unsigned char) *xp); 4595c2aa98e2SPeter Wemm if (c == '\n') 459640266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 459740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 459840266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4599c2aa98e2SPeter Wemm } 460040266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 4601c2aa98e2SPeter Wemm { 460240266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 460340266059SGregory Neil Shapiro SM_TIME_DEFAULT, padc) 460440266059SGregory Neil Shapiro == SM_IO_EOF) 460506f25ae9SGregory Neil Shapiro { 460640266059SGregory Neil Shapiro dead = true; 460706f25ae9SGregory Neil Shapiro continue; 460806f25ae9SGregory Neil Shapiro } 4609193538b7SGregory Neil Shapiro else 4610193538b7SGregory Neil Shapiro { 4611193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 461240266059SGregory Neil Shapiro DataProgress = true; 4613193538b7SGregory Neil Shapiro } 4614c2aa98e2SPeter Wemm pos++; 4615c2aa98e2SPeter Wemm } 4616c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4617c2aa98e2SPeter Wemm { 461840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 461940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 462040266059SGregory Neil Shapiro (unsigned char) *xp) 462140266059SGregory Neil Shapiro == SM_IO_EOF) 462206f25ae9SGregory Neil Shapiro { 462340266059SGregory Neil Shapiro dead = true; 462406f25ae9SGregory Neil Shapiro break; 4625c2aa98e2SPeter Wemm } 4626193538b7SGregory Neil Shapiro else 4627193538b7SGregory Neil Shapiro { 462806f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 462940266059SGregory Neil Shapiro DataProgress = true; 463006f25ae9SGregory Neil Shapiro } 4631193538b7SGregory Neil Shapiro } 463206f25ae9SGregory Neil Shapiro if (dead) 463306f25ae9SGregory Neil Shapiro continue; 4634c2aa98e2SPeter Wemm if (c == '\n') 4635c2aa98e2SPeter Wemm { 463640266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 463740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 463840266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 463940266059SGregory Neil Shapiro == SM_IO_EOF) 464006f25ae9SGregory Neil Shapiro break; 4641193538b7SGregory Neil Shapiro else 4642193538b7SGregory Neil Shapiro { 4643193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 464440266059SGregory Neil Shapiro DataProgress = true; 4645193538b7SGregory Neil Shapiro } 4646c2aa98e2SPeter Wemm pos = 0; 4647c2aa98e2SPeter Wemm } 4648c2aa98e2SPeter Wemm else 4649c2aa98e2SPeter Wemm { 4650c2aa98e2SPeter Wemm pos += bp - buf; 4651c2aa98e2SPeter Wemm if (c != '\r') 4652c2aa98e2SPeter Wemm *pbp++ = c; 4653c2aa98e2SPeter Wemm } 465406f25ae9SGregory Neil Shapiro 4655c2aa98e2SPeter Wemm bp = buf; 4656c2aa98e2SPeter Wemm 4657c2aa98e2SPeter Wemm /* determine next state */ 4658c2aa98e2SPeter Wemm if (c == '\n') 4659c2aa98e2SPeter Wemm ostate = OS_HEAD; 4660c2aa98e2SPeter Wemm else if (c == '\r') 4661c2aa98e2SPeter Wemm ostate = OS_CR; 4662c2aa98e2SPeter Wemm else 4663c2aa98e2SPeter Wemm ostate = OS_INLINE; 4664c2aa98e2SPeter Wemm continue; 4665c2aa98e2SPeter Wemm 4666c2aa98e2SPeter Wemm case OS_CR: 4667c2aa98e2SPeter Wemm if (c == '\n') 4668c2aa98e2SPeter Wemm { 4669c2aa98e2SPeter Wemm /* got CRLF */ 467040266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 467140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 467240266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 467340266059SGregory Neil Shapiro == SM_IO_EOF) 467406f25ae9SGregory Neil Shapiro continue; 4675193538b7SGregory Neil Shapiro else 4676193538b7SGregory Neil Shapiro { 467706f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 467840266059SGregory Neil Shapiro DataProgress = true; 4679193538b7SGregory Neil Shapiro } 468006f25ae9SGregory Neil Shapiro 4681c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4682c2aa98e2SPeter Wemm { 468340266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 468440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 468540266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4686c2aa98e2SPeter Wemm } 4687c2aa98e2SPeter Wemm ostate = OS_HEAD; 4688c2aa98e2SPeter Wemm continue; 4689c2aa98e2SPeter Wemm } 4690c2aa98e2SPeter Wemm 4691c2aa98e2SPeter Wemm /* had a naked carriage return */ 4692c2aa98e2SPeter Wemm *pbp++ = c; 4693c2aa98e2SPeter Wemm c = '\r'; 4694c2aa98e2SPeter Wemm ostate = OS_INLINE; 4695c2aa98e2SPeter Wemm goto putch; 4696c2aa98e2SPeter Wemm 4697c2aa98e2SPeter Wemm case OS_INLINE: 4698c2aa98e2SPeter Wemm if (c == '\r') 4699c2aa98e2SPeter Wemm { 4700c2aa98e2SPeter Wemm ostate = OS_CR; 4701c2aa98e2SPeter Wemm continue; 4702c2aa98e2SPeter Wemm } 4703c2aa98e2SPeter Wemm if (c == '\0' && 470440266059SGregory Neil Shapiro bitnset(M_NONULLS, 470540266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4706c2aa98e2SPeter Wemm break; 4707c2aa98e2SPeter Wemm putch: 4708c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 470906f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 && 4710c2aa98e2SPeter Wemm c != '\n') 4711c2aa98e2SPeter Wemm { 471206f25ae9SGregory Neil Shapiro int d; 471306f25ae9SGregory Neil Shapiro 471406f25ae9SGregory Neil Shapiro /* check next character for EOL */ 471506f25ae9SGregory Neil Shapiro if (pbp > peekbuf) 471606f25ae9SGregory Neil Shapiro d = *(pbp - 1); 471740266059SGregory Neil Shapiro else if ((d = sm_io_getc(e->e_dfp, 471840266059SGregory Neil Shapiro SM_TIME_DEFAULT)) 471940266059SGregory Neil Shapiro != SM_IO_EOF) 472006f25ae9SGregory Neil Shapiro *pbp++ = d; 472106f25ae9SGregory Neil Shapiro 472240266059SGregory Neil Shapiro if (d == '\n' || d == SM_IO_EOF) 472306f25ae9SGregory Neil Shapiro { 472406f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL) 472540266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 472640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 472740266059SGregory Neil Shapiro (unsigned char) c); 472840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 472940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 473040266059SGregory Neil Shapiro (unsigned char) c) 473140266059SGregory Neil Shapiro == SM_IO_EOF) 473206f25ae9SGregory Neil Shapiro { 473340266059SGregory Neil Shapiro dead = true; 473406f25ae9SGregory Neil Shapiro continue; 473506f25ae9SGregory Neil Shapiro } 4736193538b7SGregory Neil Shapiro else 4737193538b7SGregory Neil Shapiro { 4738193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 473940266059SGregory Neil Shapiro DataProgress = true; 4740193538b7SGregory Neil Shapiro } 474106f25ae9SGregory Neil Shapiro pos++; 474206f25ae9SGregory Neil Shapiro continue; 474306f25ae9SGregory Neil Shapiro } 474406f25ae9SGregory Neil Shapiro 474540266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 474640266059SGregory Neil Shapiro SM_TIME_DEFAULT, '!') 474740266059SGregory Neil Shapiro == SM_IO_EOF || 474840266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out, 474940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 475040266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 475140266059SGregory Neil Shapiro == SM_IO_EOF) 475206f25ae9SGregory Neil Shapiro { 475340266059SGregory Neil Shapiro dead = true; 475406f25ae9SGregory Neil Shapiro continue; 475506f25ae9SGregory Neil Shapiro } 4756193538b7SGregory Neil Shapiro else 4757193538b7SGregory Neil Shapiro { 475806f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 475940266059SGregory Neil Shapiro DataProgress = true; 4760193538b7SGregory Neil Shapiro } 476106f25ae9SGregory Neil Shapiro 4762c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4763c2aa98e2SPeter Wemm { 476440266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 476540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 476640266059SGregory Neil Shapiro "!%s", 4767c2aa98e2SPeter Wemm mci->mci_mailer->m_eol); 4768c2aa98e2SPeter Wemm } 4769c2aa98e2SPeter Wemm ostate = OS_HEAD; 4770c2aa98e2SPeter Wemm *pbp++ = c; 4771c2aa98e2SPeter Wemm continue; 4772c2aa98e2SPeter Wemm } 4773c2aa98e2SPeter Wemm if (c == '\n') 4774c2aa98e2SPeter Wemm { 4775c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 477640266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 477740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 477840266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 477940266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 478040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 478140266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 478240266059SGregory Neil Shapiro == SM_IO_EOF) 478306f25ae9SGregory Neil Shapiro continue; 4784193538b7SGregory Neil Shapiro else 4785193538b7SGregory Neil Shapiro { 4786193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 478740266059SGregory Neil Shapiro DataProgress = true; 4788193538b7SGregory Neil Shapiro } 4789c2aa98e2SPeter Wemm pos = 0; 4790c2aa98e2SPeter Wemm ostate = OS_HEAD; 4791c2aa98e2SPeter Wemm } 4792c2aa98e2SPeter Wemm else 4793c2aa98e2SPeter Wemm { 4794c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 479540266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 479640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 479740266059SGregory Neil Shapiro (unsigned char) c); 479840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 479940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 480040266059SGregory Neil Shapiro (unsigned char) c) 480140266059SGregory Neil Shapiro == SM_IO_EOF) 480206f25ae9SGregory Neil Shapiro { 480340266059SGregory Neil Shapiro dead = true; 480406f25ae9SGregory Neil Shapiro continue; 480506f25ae9SGregory Neil Shapiro } 4806193538b7SGregory Neil Shapiro else 4807193538b7SGregory Neil Shapiro { 4808193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 480940266059SGregory Neil Shapiro DataProgress = true; 4810193538b7SGregory Neil Shapiro } 4811c2aa98e2SPeter Wemm pos++; 4812c2aa98e2SPeter Wemm ostate = OS_INLINE; 4813c2aa98e2SPeter Wemm } 4814c2aa98e2SPeter Wemm break; 4815c2aa98e2SPeter Wemm } 4816c2aa98e2SPeter Wemm } 4817c2aa98e2SPeter Wemm 4818c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */ 4819c2aa98e2SPeter Wemm if (bp > buf) 4820c2aa98e2SPeter Wemm { 4821c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4822c2aa98e2SPeter Wemm { 4823c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 482440266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 482540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 482640266059SGregory Neil Shapiro (unsigned char) *xp); 4827c2aa98e2SPeter Wemm } 4828c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4829c2aa98e2SPeter Wemm { 483040266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 483140266059SGregory Neil Shapiro (unsigned char) *xp) 483240266059SGregory Neil Shapiro == SM_IO_EOF) 483306f25ae9SGregory Neil Shapiro { 483440266059SGregory Neil Shapiro dead = true; 483506f25ae9SGregory Neil Shapiro break; 483606f25ae9SGregory Neil Shapiro } 4837193538b7SGregory Neil Shapiro else 4838193538b7SGregory Neil Shapiro { 483906f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 484040266059SGregory Neil Shapiro DataProgress = true; 4841c2aa98e2SPeter Wemm } 4842193538b7SGregory Neil Shapiro } 4843c2aa98e2SPeter Wemm pos += bp - buf; 4844c2aa98e2SPeter Wemm } 484506f25ae9SGregory Neil Shapiro if (!dead && pos > 0) 4846c2aa98e2SPeter Wemm { 4847c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 484840266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 484940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 485040266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 485140266059SGregory Neil Shapiro (void) sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 485240266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 485306f25ae9SGregory Neil Shapiro 485406f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 485540266059SGregory Neil Shapiro DataProgress = true; 4856c2aa98e2SPeter Wemm } 4857c2aa98e2SPeter Wemm } 4858c2aa98e2SPeter Wemm 485940266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp)) 4860c2aa98e2SPeter Wemm { 486140266059SGregory Neil Shapiro syserr("putbody: %s/%cf%s: read error", 486240266059SGregory Neil Shapiro qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 486340266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 4864c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4865c2aa98e2SPeter Wemm } 4866c2aa98e2SPeter Wemm 4867c2aa98e2SPeter Wemm endofmessage: 486806f25ae9SGregory Neil Shapiro /* 486906f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process, 487006f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the 487106f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel 487206f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared 487306f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital 487406f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the 487506f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell) 487606f25ae9SGregory Neil Shapiro ** offset to match. 487706f25ae9SGregory Neil Shapiro */ 487806f25ae9SGregory Neil Shapiro 487906f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) 488006f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 488106f25ae9SGregory Neil Shapiro 4882c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */ 488306f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 4884c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n') 4885c2aa98e2SPeter Wemm putline("", mci); 4886c2aa98e2SPeter Wemm 488740266059SGregory Neil Shapiro (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 488840266059SGregory Neil Shapiro if (sm_io_error(mci->mci_out) && errno != EPIPE) 4889c2aa98e2SPeter Wemm { 4890c2aa98e2SPeter Wemm syserr("putbody: write error"); 4891c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4892c2aa98e2SPeter Wemm } 489306f25ae9SGregory Neil Shapiro 4894c2aa98e2SPeter Wemm errno = 0; 4895c2aa98e2SPeter Wemm } 489640266059SGregory Neil Shapiro /* 4897c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file. 4898c2aa98e2SPeter Wemm ** 489940266059SGregory Neil Shapiro ** If the file has the set-user-ID/set-group-ID bits set, but NO 490040266059SGregory Neil Shapiro ** execute bits, sendmail will try to become the owner of that file 4901c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if 4902c2aa98e2SPeter Wemm ** sendmail runs as root. 4903c2aa98e2SPeter Wemm ** 4904c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it 4905c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We 4906c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it 4907c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have 4908c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message. 4909c2aa98e2SPeter Wemm ** 4910c2aa98e2SPeter Wemm ** Parameters: 4911c2aa98e2SPeter Wemm ** filename -- the name of the file to send to. 4912c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL, 4913c2aa98e2SPeter Wemm ** use FileMailer. 4914c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes 4915c2aa98e2SPeter Wemm ** the userid/groupid to be when sending. 4916c2aa98e2SPeter Wemm ** sfflags -- flags for opening. 4917c2aa98e2SPeter Wemm ** e -- the current envelope. 4918c2aa98e2SPeter Wemm ** 4919c2aa98e2SPeter Wemm ** Returns: 4920c2aa98e2SPeter Wemm ** The exit code associated with the operation. 4921c2aa98e2SPeter Wemm ** 4922c2aa98e2SPeter Wemm ** Side Effects: 4923c2aa98e2SPeter Wemm ** none. 4924c2aa98e2SPeter Wemm */ 4925c2aa98e2SPeter Wemm 492640266059SGregory Neil Shapiro # define RETURN(st) exit(st); 492740266059SGregory Neil Shapiro 4928c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout; 4929c2aa98e2SPeter Wemm 4930c2aa98e2SPeter Wemm int 4931c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e) 4932c2aa98e2SPeter Wemm char *volatile filename; 4933c2aa98e2SPeter Wemm MAILER *volatile mailer; 4934c2aa98e2SPeter Wemm ADDRESS *ctladdr; 493506f25ae9SGregory Neil Shapiro volatile long sfflags; 4936c2aa98e2SPeter Wemm register ENVELOPE *e; 4937c2aa98e2SPeter Wemm { 493840266059SGregory Neil Shapiro register SM_FILE_T *f; 4939c2aa98e2SPeter Wemm register pid_t pid = -1; 494006f25ae9SGregory Neil Shapiro volatile int mode; 494106f25ae9SGregory Neil Shapiro int len; 494206f25ae9SGregory Neil Shapiro off_t curoff; 4943c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0; 4944c2aa98e2SPeter Wemm char *p; 494506f25ae9SGregory Neil Shapiro char *volatile realfile; 494640266059SGregory Neil Shapiro SM_EVENT *ev; 494706f25ae9SGregory Neil Shapiro char buf[MAXLINE + 1]; 494806f25ae9SGregory Neil Shapiro char targetfile[MAXPATHLEN + 1]; 4949c2aa98e2SPeter Wemm 4950c2aa98e2SPeter Wemm if (tTd(11, 1)) 4951c2aa98e2SPeter Wemm { 495240266059SGregory Neil Shapiro sm_dprintf("mailfile %s\n ctladdr=", filename); 495340266059SGregory Neil Shapiro printaddr(ctladdr, false); 4954c2aa98e2SPeter Wemm } 4955c2aa98e2SPeter Wemm 4956c2aa98e2SPeter Wemm if (mailer == NULL) 4957c2aa98e2SPeter Wemm mailer = FileMailer; 4958c2aa98e2SPeter Wemm 4959c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 496040266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 4961c2aa98e2SPeter Wemm 4962c2aa98e2SPeter Wemm /* 4963c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file 4964c2aa98e2SPeter Wemm ** delivery to regular files only. 4965c2aa98e2SPeter Wemm */ 4966c2aa98e2SPeter Wemm 496740266059SGregory Neil Shapiro if (sm_path_isdevnull(filename)) 4968c2aa98e2SPeter Wemm return EX_OK; 4969c2aa98e2SPeter Wemm 4970c2aa98e2SPeter Wemm /* check for 8-bit available */ 4971c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 4972c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) && 4973c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 4974c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 4975c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 4976c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 4977c2aa98e2SPeter Wemm { 4978c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 497906f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 498006f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 498140266059SGregory Neil Shapiro errno = 0; 498206f25ae9SGregory Neil Shapiro return EX_DATAERR; 498306f25ae9SGregory Neil Shapiro } 498406f25ae9SGregory Neil Shapiro 498506f25ae9SGregory Neil Shapiro /* Find the actual file */ 498606f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 498706f25ae9SGregory Neil Shapiro { 498806f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv); 498906f25ae9SGregory Neil Shapiro 499006f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0) 499106f25ae9SGregory Neil Shapiro filename += len; 499206f25ae9SGregory Neil Shapiro 499340266059SGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof targetfile) 499406f25ae9SGregory Neil Shapiro { 499506f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 499606f25ae9SGregory Neil Shapiro SafeFileEnv, filename); 499706f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 499806f25ae9SGregory Neil Shapiro } 499940266059SGregory Neil Shapiro (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile); 500006f25ae9SGregory Neil Shapiro realfile = targetfile + len; 500106f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 500240266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof targetfile); 500306f25ae9SGregory Neil Shapiro if (*filename == '/') 500406f25ae9SGregory Neil Shapiro filename++; 500540266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, sizeof targetfile); 500606f25ae9SGregory Neil Shapiro } 500706f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL) 500806f25ae9SGregory Neil Shapiro { 500906f25ae9SGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof targetfile, e); 501006f25ae9SGregory Neil Shapiro len = strlen(targetfile); 501106f25ae9SGregory Neil Shapiro 501206f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0) 501306f25ae9SGregory Neil Shapiro filename += len; 501406f25ae9SGregory Neil Shapiro 501540266059SGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof targetfile) 501606f25ae9SGregory Neil Shapiro { 501706f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 501806f25ae9SGregory Neil Shapiro targetfile, filename); 501906f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 502006f25ae9SGregory Neil Shapiro } 502106f25ae9SGregory Neil Shapiro realfile = targetfile + len; 502206f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 502340266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof targetfile); 502406f25ae9SGregory Neil Shapiro if (*filename == '/') 502540266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename + 1, 502606f25ae9SGregory Neil Shapiro sizeof targetfile); 502706f25ae9SGregory Neil Shapiro else 502840266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 502940266059SGregory Neil Shapiro sizeof targetfile); 503006f25ae9SGregory Neil Shapiro } 503106f25ae9SGregory Neil Shapiro else 503206f25ae9SGregory Neil Shapiro { 503340266059SGregory Neil Shapiro if (sm_strlcpy(targetfile, filename, sizeof targetfile) >= 503440266059SGregory Neil Shapiro sizeof targetfile) 503506f25ae9SGregory Neil Shapiro { 503606f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename); 503706f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 503806f25ae9SGregory Neil Shapiro } 503906f25ae9SGregory Neil Shapiro realfile = targetfile; 5040c2aa98e2SPeter Wemm } 5041c2aa98e2SPeter Wemm 5042c2aa98e2SPeter Wemm /* 5043c2aa98e2SPeter Wemm ** Fork so we can change permissions here. 5044c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of 5045c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc. 5046c2aa98e2SPeter Wemm */ 5047c2aa98e2SPeter Wemm 5048c2aa98e2SPeter Wemm DOFORK(fork); 5049c2aa98e2SPeter Wemm 5050c2aa98e2SPeter Wemm if (pid < 0) 505106f25ae9SGregory Neil Shapiro return EX_OSERR; 5052c2aa98e2SPeter Wemm else if (pid == 0) 5053c2aa98e2SPeter Wemm { 5054c2aa98e2SPeter Wemm /* child -- actually write to file */ 5055c2aa98e2SPeter Wemm struct stat stb; 5056c2aa98e2SPeter Wemm MCI mcibuf; 5057065a643dSPeter Wemm int err; 5058c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND; 5059c2aa98e2SPeter Wemm 50608774250cSGregory Neil Shapiro /* Reset global flags */ 50618774250cSGregory Neil Shapiro RestartRequest = NULL; 506240266059SGregory Neil Shapiro RestartWorkGroup = false; 50638774250cSGregory Neil Shapiro ShutdownRequest = NULL; 50648774250cSGregory Neil Shapiro PendingSignal = 0; 506540266059SGregory Neil Shapiro CurrentPid = getpid(); 50668774250cSGregory Neil Shapiro 5067c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 506840266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 506940266059SGregory Neil Shapiro NULL)); 5070c2aa98e2SPeter Wemm 507140266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_DFL); 507240266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_DFL); 507340266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 5074c2aa98e2SPeter Wemm (void) umask(OldUmask); 5075c2aa98e2SPeter Wemm e->e_to = filename; 5076c2aa98e2SPeter Wemm ExitStat = EX_OK; 5077c2aa98e2SPeter Wemm 5078c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0) 5079c2aa98e2SPeter Wemm { 508040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 5081c2aa98e2SPeter Wemm } 5082c2aa98e2SPeter Wemm 5083c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0) 508440266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 508540266059SGregory Neil Shapiro 0); 5086c2aa98e2SPeter Wemm else 5087c2aa98e2SPeter Wemm ev = NULL; 5088c2aa98e2SPeter Wemm 508940266059SGregory Neil Shapiro /* check file mode to see if set-user-ID */ 509006f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0) 5091c2aa98e2SPeter Wemm mode = FileMode; 509206f25ae9SGregory Neil Shapiro else 5093c2aa98e2SPeter Wemm mode = stb.st_mode; 5094c2aa98e2SPeter Wemm 5095c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */ 5096c2aa98e2SPeter Wemm errno = 0; 5097c2aa98e2SPeter Wemm ExitStat = EX_OK; 5098c2aa98e2SPeter Wemm 509906f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */ 510006f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 510106f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags)) 5102c2aa98e2SPeter Wemm { 510340266059SGregory Neil Shapiro /* ignore set-user-ID and set-group-ID bits */ 5104c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID); 510506f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 510640266059SGregory Neil Shapiro sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 5107c2aa98e2SPeter Wemm } 5108c2aa98e2SPeter Wemm 510940266059SGregory Neil Shapiro /* we have to open the data file BEFORE setuid() */ 5110c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 5111c2aa98e2SPeter Wemm { 511240266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 5113c2aa98e2SPeter Wemm 511440266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 511540266059SGregory Neil Shapiro SM_IO_RDONLY, NULL); 5116c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 5117c2aa98e2SPeter Wemm { 5118c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s", 5119c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr); 5120c2aa98e2SPeter Wemm } 5121c2aa98e2SPeter Wemm } 5122c2aa98e2SPeter Wemm 5123c2aa98e2SPeter Wemm /* select a new user to run as */ 5124c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags)) 5125c2aa98e2SPeter Wemm { 5126c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 5127c2aa98e2SPeter Wemm { 5128c2aa98e2SPeter Wemm RealUserName = NULL; 5129c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 513006f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid) 513106f25ae9SGregory Neil Shapiro { 513206f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 513340266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", 513440266059SGregory Neil Shapiro (int) RunAsUid, (int) RealUid); 513540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 513606f25ae9SGregory Neil Shapiro } 5137c2aa98e2SPeter Wemm } 5138c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode)) 5139c2aa98e2SPeter Wemm { 5140c2aa98e2SPeter Wemm RealUserName = NULL; 5141c2aa98e2SPeter Wemm RealUid = stb.st_uid; 5142c2aa98e2SPeter Wemm } 5143c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 5144c2aa98e2SPeter Wemm { 5145c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL) 5146c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser; 5147c2aa98e2SPeter Wemm else 5148c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user; 5149c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid; 5150c2aa98e2SPeter Wemm } 5151c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_uid != 0) 5152c2aa98e2SPeter Wemm { 5153c2aa98e2SPeter Wemm RealUserName = DefUser; 5154c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 5155c2aa98e2SPeter Wemm } 5156c2aa98e2SPeter Wemm else 5157c2aa98e2SPeter Wemm { 5158c2aa98e2SPeter Wemm RealUserName = DefUser; 5159c2aa98e2SPeter Wemm RealUid = DefUid; 5160c2aa98e2SPeter Wemm } 5161c2aa98e2SPeter Wemm 5162c2aa98e2SPeter Wemm /* select a new group to run as */ 5163c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 516406f25ae9SGregory Neil Shapiro { 5165c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 516606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 516706f25ae9SGregory Neil Shapiro (RealGid != getgid() || 516806f25ae9SGregory Neil Shapiro RealGid != getegid())) 516906f25ae9SGregory Neil Shapiro { 517006f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 517140266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", 517240266059SGregory Neil Shapiro (int) RealGid, (int) RunAsUid, 517340266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 517440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 517506f25ae9SGregory Neil Shapiro } 517606f25ae9SGregory Neil Shapiro } 5177c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode)) 5178c2aa98e2SPeter Wemm RealGid = stb.st_gid; 517906f25ae9SGregory Neil Shapiro else if (ctladdr != NULL && 518006f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid && 518106f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0) 5182193538b7SGregory Neil Shapiro { 5183193538b7SGregory Neil Shapiro /* 5184193538b7SGregory Neil Shapiro ** Special case: This means it is an 5185193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser. 5186193538b7SGregory Neil Shapiro ** See alias()'s comments. 5187193538b7SGregory Neil Shapiro */ 5188193538b7SGregory Neil Shapiro 518906f25ae9SGregory Neil Shapiro RealGid = DefGid; 5190193538b7SGregory Neil Shapiro RealUserName = DefUser; 5191193538b7SGregory Neil Shapiro } 5192193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0) 5193193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid; 5194c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_gid != 0) 5195c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 5196c2aa98e2SPeter Wemm else 5197c2aa98e2SPeter Wemm RealGid = DefGid; 5198c2aa98e2SPeter Wemm } 5199c2aa98e2SPeter Wemm 5200c2aa98e2SPeter Wemm /* last ditch */ 5201c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags)) 5202c2aa98e2SPeter Wemm { 5203c2aa98e2SPeter Wemm if (RealUid == 0) 5204c2aa98e2SPeter Wemm RealUid = DefUid; 5205c2aa98e2SPeter Wemm if (RealGid == 0) 5206c2aa98e2SPeter Wemm RealGid = DefGid; 5207c2aa98e2SPeter Wemm } 5208c2aa98e2SPeter Wemm 5209c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */ 5210c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups) 5211c2aa98e2SPeter Wemm { 5212c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 521306f25ae9SGregory Neil Shapiro { 5214c2aa98e2SPeter Wemm syserr("mailfile: initgroups(%s, %d) failed", 5215c2aa98e2SPeter Wemm RealUserName, RealGid); 521640266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 521706f25ae9SGregory Neil Shapiro } 5218c2aa98e2SPeter Wemm } 5219c2aa98e2SPeter Wemm else 5220c2aa98e2SPeter Wemm { 5221c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 5222c2aa98e2SPeter Wemm 5223c2aa98e2SPeter Wemm gidset[0] = RealGid; 5224c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 522506f25ae9SGregory Neil Shapiro { 5226c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed"); 522740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 522806f25ae9SGregory Neil Shapiro } 5229c2aa98e2SPeter Wemm } 5230c2aa98e2SPeter Wemm 523106f25ae9SGregory Neil Shapiro /* 523206f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it. 523306f25ae9SGregory Neil Shapiro */ 5234c2aa98e2SPeter Wemm 523506f25ae9SGregory Neil Shapiro if (realfile != targetfile) 523606f25ae9SGregory Neil Shapiro { 523706f25ae9SGregory Neil Shapiro *realfile = '\0'; 523806f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 523940266059SGregory Neil Shapiro sm_dprintf("mailfile: chroot %s\n", targetfile); 524006f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0) 5241c2aa98e2SPeter Wemm { 5242c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)", 524306f25ae9SGregory Neil Shapiro targetfile); 524440266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5245c2aa98e2SPeter Wemm } 524606f25ae9SGregory Neil Shapiro *realfile = '/'; 5247c2aa98e2SPeter Wemm } 524806f25ae9SGregory Neil Shapiro 524906f25ae9SGregory Neil Shapiro if (tTd(11, 40)) 525040266059SGregory Neil Shapiro sm_dprintf("mailfile: deliver to %s\n", realfile); 525106f25ae9SGregory Neil Shapiro 5252c2aa98e2SPeter Wemm if (chdir("/") < 0) 525306f25ae9SGregory Neil Shapiro { 5254c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)"); 525540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 525606f25ae9SGregory Neil Shapiro } 5257c2aa98e2SPeter Wemm 5258c2aa98e2SPeter Wemm /* now reset the group and user ids */ 5259c2aa98e2SPeter Wemm endpwent(); 526040266059SGregory Neil Shapiro sm_mbdb_terminate(); 5261c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn) 526206f25ae9SGregory Neil Shapiro { 5263c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid); 526440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 526506f25ae9SGregory Neil Shapiro } 5266c2aa98e2SPeter Wemm vendor_set_uid(RealUid); 5267c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn) 526806f25ae9SGregory Neil Shapiro { 5269c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid); 527040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 527106f25ae9SGregory Neil Shapiro } 527206f25ae9SGregory Neil Shapiro 527306f25ae9SGregory Neil Shapiro if (tTd(11, 2)) 527440266059SGregory Neil Shapiro sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 527506f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 527606f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 527706f25ae9SGregory Neil Shapiro 5278c2aa98e2SPeter Wemm 5279c2aa98e2SPeter Wemm /* move into some "safe" directory */ 5280c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL) 5281c2aa98e2SPeter Wemm { 5282c2aa98e2SPeter Wemm char *q; 5283c2aa98e2SPeter Wemm 5284c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q) 5285c2aa98e2SPeter Wemm { 5286c2aa98e2SPeter Wemm q = strchr(p, ':'); 5287c2aa98e2SPeter Wemm if (q != NULL) 5288c2aa98e2SPeter Wemm *q = '\0'; 5289c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 5290c2aa98e2SPeter Wemm if (q != NULL) 5291c2aa98e2SPeter Wemm *q++ = ':'; 5292c2aa98e2SPeter Wemm if (tTd(11, 20)) 529340266059SGregory Neil Shapiro sm_dprintf("mailfile: trydir %s\n", 529440266059SGregory Neil Shapiro buf); 5295c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 5296c2aa98e2SPeter Wemm break; 5297c2aa98e2SPeter Wemm } 5298c2aa98e2SPeter Wemm } 5299c2aa98e2SPeter Wemm 530006f25ae9SGregory Neil Shapiro /* 530106f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the 530206f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as 530306f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running 530406f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats 530506f25ae9SGregory Neil Shapiro ** root as nobody. 530606f25ae9SGregory Neil Shapiro */ 530706f25ae9SGregory Neil Shapiro 530806f25ae9SGregory Neil Shapiro #if HASLSTAT 530906f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 531006f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 531106f25ae9SGregory Neil Shapiro else 531206f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb); 531306f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 531406f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 531506f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 531606f25ae9SGregory Neil Shapiro 531706f25ae9SGregory Neil Shapiro if (err < 0) 531806f25ae9SGregory Neil Shapiro { 531906f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE; 532006f25ae9SGregory Neil Shapiro mode = FileMode; 532106f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL; 532206f25ae9SGregory Neil Shapiro } 532306f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 532406f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 532506f25ae9SGregory Neil Shapiro DontBlameSendmail) && 532606f25ae9SGregory Neil Shapiro stb.st_nlink != 1) || 532706f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode))) 532806f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 532906f25ae9SGregory Neil Shapiro else 533006f25ae9SGregory Neil Shapiro mode = stb.st_mode; 533106f25ae9SGregory Neil Shapiro 533206f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 5333c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK; 533406f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 5335c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK; 5336c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT; 533706f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags); 5338c2aa98e2SPeter Wemm if (f == NULL) 5339c2aa98e2SPeter Wemm { 534006f25ae9SGregory Neil Shapiro if (transienterror(errno)) 534106f25ae9SGregory Neil Shapiro { 534206f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s", 534306f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 534440266059SGregory Neil Shapiro sm_errstring(errno)); 534540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 534606f25ae9SGregory Neil Shapiro } 534706f25ae9SGregory Neil Shapiro else 534806f25ae9SGregory Neil Shapiro { 534906f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s", 535006f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 535140266059SGregory Neil Shapiro sm_errstring(errno)); 535240266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5353c2aa98e2SPeter Wemm } 535406f25ae9SGregory Neil Shapiro } 535540266059SGregory Neil Shapiro if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 535640266059SGregory Neil Shapiro &stb)) 5357c2aa98e2SPeter Wemm { 535806f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open"); 535940266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5360c2aa98e2SPeter Wemm } 536140266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 5362c2aa98e2SPeter Wemm { 536340266059SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s", 536440266059SGregory Neil Shapiro sm_errstring(errno)); 536540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5366c2aa98e2SPeter Wemm } 5367c2aa98e2SPeter Wemm 536806f25ae9SGregory Neil Shapiro curoff = stb.st_size; 536906f25ae9SGregory Neil Shapiro 5370c2aa98e2SPeter Wemm if (ev != NULL) 537140266059SGregory Neil Shapiro sm_clrevent(ev); 5372c2aa98e2SPeter Wemm 537306f25ae9SGregory Neil Shapiro memset(&mcibuf, '\0', sizeof mcibuf); 5374c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer; 5375c2aa98e2SPeter Wemm mcibuf.mci_out = f; 5376c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags)) 5377c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT; 5378c2aa98e2SPeter Wemm 5379c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 5380c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 5381c2aa98e2SPeter Wemm 5382c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5383c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 5384c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags)) 5385c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7; 5386c2aa98e2SPeter Wemm 5387c2aa98e2SPeter Wemm #if MIME7TO8 5388c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) && 5389c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) && 5390c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 539140266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 539240266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 5393c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 5394c2aa98e2SPeter Wemm { 5395c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 5396c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 539740266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 5398c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 5399c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8; 5400c2aa98e2SPeter Wemm } 540106f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 5402c2aa98e2SPeter Wemm 5403c2aa98e2SPeter Wemm putfromline(&mcibuf, e); 54042e43090eSPeter Wemm (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER); 5405c2aa98e2SPeter Wemm (*e->e_putbody)(&mcibuf, e, NULL); 5406c2aa98e2SPeter Wemm putline("\n", &mcibuf); 540740266059SGregory Neil Shapiro if (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 540840266059SGregory Neil Shapiro (SuperSafe != SAFE_NO && 540940266059SGregory Neil Shapiro fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 541040266059SGregory Neil Shapiro sm_io_error(f)) 5411c2aa98e2SPeter Wemm { 5412c2aa98e2SPeter Wemm setstat(EX_IOERR); 541306f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE 541440266059SGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 541540266059SGregory Neil Shapiro curoff); 541606f25ae9SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 5417c2aa98e2SPeter Wemm } 5418c2aa98e2SPeter Wemm 5419c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */ 5420c2aa98e2SPeter Wemm #if HASFCHMOD 542140266059SGregory Neil Shapiro (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 542240266059SGregory Neil Shapiro (MODE_T) mode); 542306f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */ 542406f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode); 542506f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */ 542640266059SGregory Neil Shapiro if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 542706f25ae9SGregory Neil Shapiro setstat(EX_IOERR); 542840266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 542906f25ae9SGregory Neil Shapiro (void) setuid(RealUid); 5430c2aa98e2SPeter Wemm exit(ExitStat); 5431c2aa98e2SPeter Wemm /* NOTREACHED */ 5432c2aa98e2SPeter Wemm } 5433c2aa98e2SPeter Wemm else 5434c2aa98e2SPeter Wemm { 5435c2aa98e2SPeter Wemm /* parent -- wait for exit status */ 5436c2aa98e2SPeter Wemm int st; 5437c2aa98e2SPeter Wemm 5438c2aa98e2SPeter Wemm st = waitfor(pid); 5439c2aa98e2SPeter Wemm if (st == -1) 5440c2aa98e2SPeter Wemm { 5441c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name); 544206f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 5443c2aa98e2SPeter Wemm } 5444c2aa98e2SPeter Wemm if (WIFEXITED(st)) 544540266059SGregory Neil Shapiro { 544640266059SGregory Neil Shapiro errno = 0; 5447c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 544840266059SGregory Neil Shapiro } 5449c2aa98e2SPeter Wemm else 5450c2aa98e2SPeter Wemm { 5451c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d", 5452c2aa98e2SPeter Wemm mailer->m_name, st); 545306f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE; 5454c2aa98e2SPeter Wemm } 5455c2aa98e2SPeter Wemm /* NOTREACHED */ 5456c2aa98e2SPeter Wemm } 5457c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 5458c2aa98e2SPeter Wemm } 5459c2aa98e2SPeter Wemm 5460c2aa98e2SPeter Wemm static void 5461c2aa98e2SPeter Wemm mailfiletimeout() 5462c2aa98e2SPeter Wemm { 54638774250cSGregory Neil Shapiro /* 54648774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 54658774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 54668774250cSGregory Neil Shapiro ** DOING. 54678774250cSGregory Neil Shapiro */ 54688774250cSGregory Neil Shapiro 54698774250cSGregory Neil Shapiro errno = ETIMEDOUT; 5470c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1); 5471c2aa98e2SPeter Wemm } 547240266059SGregory Neil Shapiro /* 5473c2aa98e2SPeter Wemm ** HOSTSIGNATURE -- return the "signature" for a host. 5474c2aa98e2SPeter Wemm ** 5475c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it 5476c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be 5477c2aa98e2SPeter Wemm ** an ordered list of MX hosts. 5478c2aa98e2SPeter Wemm ** 5479c2aa98e2SPeter Wemm ** Parameters: 5480c2aa98e2SPeter Wemm ** m -- the mailer describing this host. 5481c2aa98e2SPeter Wemm ** host -- the host name. 5482c2aa98e2SPeter Wemm ** 5483c2aa98e2SPeter Wemm ** Returns: 5484c2aa98e2SPeter Wemm ** The signature for this host. 5485c2aa98e2SPeter Wemm ** 5486c2aa98e2SPeter Wemm ** Side Effects: 5487c2aa98e2SPeter Wemm ** Can tweak the symbol table. 5488c2aa98e2SPeter Wemm */ 548940266059SGregory Neil Shapiro 549006f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 5491c2aa98e2SPeter Wemm 549240266059SGregory Neil Shapiro char * 549306f25ae9SGregory Neil Shapiro hostsignature(m, host) 5494c2aa98e2SPeter Wemm register MAILER *m; 5495c2aa98e2SPeter Wemm char *host; 5496c2aa98e2SPeter Wemm { 5497c2aa98e2SPeter Wemm register char *p; 5498c2aa98e2SPeter Wemm register STAB *s; 549940266059SGregory Neil Shapiro time_t now; 550006f25ae9SGregory Neil Shapiro #if NAMED_BIND 550106f25ae9SGregory Neil Shapiro char sep = ':'; 550206f25ae9SGregory Neil Shapiro char prevsep = ':'; 5503c2aa98e2SPeter Wemm int i; 5504c2aa98e2SPeter Wemm int len; 5505c2aa98e2SPeter Wemm int nmx; 550606f25ae9SGregory Neil Shapiro int hl; 5507c2aa98e2SPeter Wemm char *hp; 5508c2aa98e2SPeter Wemm char *endp; 5509c2aa98e2SPeter Wemm int oldoptions = _res.options; 5510c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 551140266059SGregory Neil Shapiro unsigned short mxprefs[MAXMXHOSTS + 1]; 551206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 551306f25ae9SGregory Neil Shapiro 551406f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 551540266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s)\n", host); 551606f25ae9SGregory Neil Shapiro 551706f25ae9SGregory Neil Shapiro /* 55188774250cSGregory Neil Shapiro ** If local delivery (and not remote), just return a constant. 551906f25ae9SGregory Neil Shapiro */ 552006f25ae9SGregory Neil Shapiro 55218774250cSGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags) && 552240266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") != 0 && 552340266059SGregory Neil Shapiro !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 552406f25ae9SGregory Neil Shapiro return "localhost"; 5525c2aa98e2SPeter Wemm 5526c2aa98e2SPeter Wemm /* 5527c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records. 5528c2aa98e2SPeter Wemm */ 5529c2aa98e2SPeter Wemm 553040266059SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") != 0 || 553140266059SGregory Neil Shapiro CurEnv->e_sendmode == SM_DEFER) 5532c2aa98e2SPeter Wemm { 553340266059SGregory Neil Shapiro /* just an ordinary mailer or deferred mode */ 5534c2aa98e2SPeter Wemm return host; 5535c2aa98e2SPeter Wemm } 553606f25ae9SGregory Neil Shapiro #if NETUNIX 553706f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL && 553806f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0) 553906f25ae9SGregory Neil Shapiro { 554006f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */ 554106f25ae9SGregory Neil Shapiro return host; 554206f25ae9SGregory Neil Shapiro } 554306f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 5544c2aa98e2SPeter Wemm 5545c2aa98e2SPeter Wemm /* 5546c2aa98e2SPeter Wemm ** Look it up in the symbol table. 5547c2aa98e2SPeter Wemm */ 5548c2aa98e2SPeter Wemm 554940266059SGregory Neil Shapiro now = curtime(); 5550c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER); 555140266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 555240266059SGregory Neil Shapiro { 555340266059SGregory Neil Shapiro if (s->s_hostsig.hs_exp >= now) 555406f25ae9SGregory Neil Shapiro { 555506f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 555640266059SGregory Neil Shapiro sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 555740266059SGregory Neil Shapiro s->s_hostsig.hs_sig); 555840266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 555906f25ae9SGregory Neil Shapiro } 5560c2aa98e2SPeter Wemm 556140266059SGregory Neil Shapiro /* signature is expired: clear it */ 556240266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); 556340266059SGregory Neil Shapiro s->s_hostsig.hs_sig = NULL; 556440266059SGregory Neil Shapiro } 556540266059SGregory Neil Shapiro 556640266059SGregory Neil Shapiro /* set default TTL */ 556740266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 556840266059SGregory Neil Shapiro 5569c2aa98e2SPeter Wemm /* 557040266059SGregory Neil Shapiro ** Not already there or expired -- create a signature. 5571c2aa98e2SPeter Wemm */ 5572c2aa98e2SPeter Wemm 5573c2aa98e2SPeter Wemm #if NAMED_BIND 5574c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5575c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 5576c2aa98e2SPeter Wemm 5577c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp) 5578c2aa98e2SPeter Wemm { 557906f25ae9SGregory Neil Shapiro #if NETINET6 558006f25ae9SGregory Neil Shapiro if (*hp == '[') 558106f25ae9SGregory Neil Shapiro { 558206f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 5583c2aa98e2SPeter Wemm if (endp != NULL) 558406f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 558506f25ae9SGregory Neil Shapiro } 558606f25ae9SGregory Neil Shapiro else 558706f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 558806f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 558906f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 559006f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 559106f25ae9SGregory Neil Shapiro if (endp != NULL) 559206f25ae9SGregory Neil Shapiro { 559306f25ae9SGregory Neil Shapiro sep = *endp; 5594c2aa98e2SPeter Wemm *endp = '\0'; 559506f25ae9SGregory Neil Shapiro } 5596c2aa98e2SPeter Wemm 5597c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags)) 5598c2aa98e2SPeter Wemm { 5599c2aa98e2SPeter Wemm /* skip MX lookups */ 5600c2aa98e2SPeter Wemm nmx = 1; 5601c2aa98e2SPeter Wemm mxhosts[0] = hp; 5602c2aa98e2SPeter Wemm } 5603c2aa98e2SPeter Wemm else 5604c2aa98e2SPeter Wemm { 5605c2aa98e2SPeter Wemm auto int rcode; 560640266059SGregory Neil Shapiro int ttl; 5607c2aa98e2SPeter Wemm 560840266059SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true, 560940266059SGregory Neil Shapiro &ttl); 5610c2aa98e2SPeter Wemm if (nmx <= 0) 5611c2aa98e2SPeter Wemm { 561213058a91SGregory Neil Shapiro int save_errno; 5613c2aa98e2SPeter Wemm register MCI *mci; 5614c2aa98e2SPeter Wemm 5615c2aa98e2SPeter Wemm /* update the connection info for this host */ 561613058a91SGregory Neil Shapiro save_errno = errno; 5617c2aa98e2SPeter Wemm mci = mci_get(hp, m); 561813058a91SGregory Neil Shapiro mci->mci_errno = save_errno; 5619c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 5620193538b7SGregory Neil Shapiro mci->mci_lastuse = now; 562106f25ae9SGregory Neil Shapiro if (rcode == EX_NOHOST) 562206f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2", 562306f25ae9SGregory Neil Shapiro "550 Host unknown"); 562406f25ae9SGregory Neil Shapiro else 5625c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL); 5626c2aa98e2SPeter Wemm 5627c2aa98e2SPeter Wemm /* use the original host name as signature */ 5628c2aa98e2SPeter Wemm nmx = 1; 5629c2aa98e2SPeter Wemm mxhosts[0] = hp; 5630c2aa98e2SPeter Wemm } 563106f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 563240266059SGregory Neil Shapiro sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 563306f25ae9SGregory Neil Shapiro nmx, mxhosts[0]); 563440266059SGregory Neil Shapiro 563540266059SGregory Neil Shapiro /* 563640266059SGregory Neil Shapiro ** Set new TTL: we use only one! 563740266059SGregory Neil Shapiro ** We could try to use the minimum instead. 563840266059SGregory Neil Shapiro */ 563940266059SGregory Neil Shapiro 564040266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 5641c2aa98e2SPeter Wemm } 5642c2aa98e2SPeter Wemm 5643c2aa98e2SPeter Wemm len = 0; 5644c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5645c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1; 564640266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 564740266059SGregory Neil Shapiro len += strlen(s->s_hostsig.hs_sig) + 1; 564840266059SGregory Neil Shapiro if (len < 0 || len >= MAXHOSTSIGNATURE) 564906f25ae9SGregory Neil Shapiro { 565006f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 565106f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len); 565206f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE; 565306f25ae9SGregory Neil Shapiro } 565440266059SGregory Neil Shapiro p = sm_pmalloc_x(len); 565540266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 5656c2aa98e2SPeter Wemm { 565740266059SGregory Neil Shapiro (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 565840266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); /* XXX */ 565940266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 566006f25ae9SGregory Neil Shapiro hl = strlen(p); 566106f25ae9SGregory Neil Shapiro p += hl; 566206f25ae9SGregory Neil Shapiro *p++ = prevsep; 566306f25ae9SGregory Neil Shapiro len -= hl + 1; 5664c2aa98e2SPeter Wemm } 5665c2aa98e2SPeter Wemm else 566640266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 5667c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5668c2aa98e2SPeter Wemm { 566906f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]); 567006f25ae9SGregory Neil Shapiro if (len - 1 < hl || len <= 1) 567106f25ae9SGregory Neil Shapiro { 567206f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */ 567306f25ae9SGregory Neil Shapiro len = -1; 567406f25ae9SGregory Neil Shapiro break; 5675c2aa98e2SPeter Wemm } 567606f25ae9SGregory Neil Shapiro if (i != 0) 567706f25ae9SGregory Neil Shapiro { 567806f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1]) 567906f25ae9SGregory Neil Shapiro *p++ = ','; 568006f25ae9SGregory Neil Shapiro else 568106f25ae9SGregory Neil Shapiro *p++ = ':'; 568206f25ae9SGregory Neil Shapiro len--; 568306f25ae9SGregory Neil Shapiro } 568440266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], len); 568506f25ae9SGregory Neil Shapiro p += hl; 568606f25ae9SGregory Neil Shapiro len -= hl; 568706f25ae9SGregory Neil Shapiro } 568806f25ae9SGregory Neil Shapiro 568906f25ae9SGregory Neil Shapiro /* 569006f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE 569106f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts 569206f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file). 569306f25ae9SGregory Neil Shapiro */ 569406f25ae9SGregory Neil Shapiro 569506f25ae9SGregory Neil Shapiro if (len < 0) 569606f25ae9SGregory Neil Shapiro break; 5697c2aa98e2SPeter Wemm if (endp != NULL) 569806f25ae9SGregory Neil Shapiro *endp++ = sep; 569906f25ae9SGregory Neil Shapiro prevsep = sep; 5700c2aa98e2SPeter Wemm } 570140266059SGregory Neil Shapiro makelower(s->s_hostsig.hs_sig); 5702c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5703c2aa98e2SPeter Wemm _res.options = oldoptions; 570406f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 5705c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */ 570640266059SGregory Neil Shapiro /* 570740266059SGregory Neil Shapiro ** 'host' points to storage that will be freed after we are 570840266059SGregory Neil Shapiro ** done processing the current envelope, so we copy it. 570940266059SGregory Neil Shapiro */ 571040266059SGregory Neil Shapiro s->s_hostsig.hs_sig = sm_pstrdup_x(host); 571106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 5712c2aa98e2SPeter Wemm if (tTd(17, 1)) 571340266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 571440266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 5715c2aa98e2SPeter Wemm } 571640266059SGregory Neil Shapiro /* 571706f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 571806f25ae9SGregory Neil Shapiro ** 571906f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it 572006f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be 572106f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal 572206f25ae9SGregory Neil Shapiro ** MX preference values. 572306f25ae9SGregory Neil Shapiro ** 572406f25ae9SGregory Neil Shapiro ** Parameters: 572506f25ae9SGregory Neil Shapiro ** sig -- the host signature. 572606f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate. 572740266059SGregory Neil Shapiro ** mailer -- mailer. 572806f25ae9SGregory Neil Shapiro ** 572906f25ae9SGregory Neil Shapiro ** Returns: 573006f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array. 573106f25ae9SGregory Neil Shapiro ** 573206f25ae9SGregory Neil Shapiro ** Side Effects: 573306f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts. 573406f25ae9SGregory Neil Shapiro */ 573506f25ae9SGregory Neil Shapiro 573606f25ae9SGregory Neil Shapiro static int 573706f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer) 573806f25ae9SGregory Neil Shapiro char *sig; 573906f25ae9SGregory Neil Shapiro char **mxhosts; 574006f25ae9SGregory Neil Shapiro MAILER *mailer; 574106f25ae9SGregory Neil Shapiro { 574240266059SGregory Neil Shapiro unsigned short curpref = 0; 574340266059SGregory Neil Shapiro int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 574406f25ae9SGregory Neil Shapiro char *hp, *endp; 574540266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 574606f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS]; 574706f25ae9SGregory Neil Shapiro 574806f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp) 574906f25ae9SGregory Neil Shapiro { 575006f25ae9SGregory Neil Shapiro char sep = ':'; 575106f25ae9SGregory Neil Shapiro 575206f25ae9SGregory Neil Shapiro #if NETINET6 575306f25ae9SGregory Neil Shapiro if (*hp == '[') 575406f25ae9SGregory Neil Shapiro { 575506f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 575606f25ae9SGregory Neil Shapiro if (endp != NULL) 575706f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 575806f25ae9SGregory Neil Shapiro } 575906f25ae9SGregory Neil Shapiro else 576006f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 576106f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 576206f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 576306f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 576406f25ae9SGregory Neil Shapiro if (endp != NULL) 576506f25ae9SGregory Neil Shapiro { 576606f25ae9SGregory Neil Shapiro sep = *endp; 576706f25ae9SGregory Neil Shapiro *endp = '\0'; 576806f25ae9SGregory Neil Shapiro } 576906f25ae9SGregory Neil Shapiro 577006f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp; 577106f25ae9SGregory Neil Shapiro prefer[nmx] = curpref; 577206f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer)) 577306f25ae9SGregory Neil Shapiro rndm[nmx] = 0; 577406f25ae9SGregory Neil Shapiro else 577506f25ae9SGregory Neil Shapiro rndm[nmx] = get_random(); 577606f25ae9SGregory Neil Shapiro 577706f25ae9SGregory Neil Shapiro if (endp != NULL) 577806f25ae9SGregory Neil Shapiro { 577906f25ae9SGregory Neil Shapiro /* 578006f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs, 578106f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that 578206f25ae9SGregory Neil Shapiro ** means the preference for the next host will be 578306f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref. 578406f25ae9SGregory Neil Shapiro */ 578506f25ae9SGregory Neil Shapiro 578606f25ae9SGregory Neil Shapiro if (sep == ':') 578706f25ae9SGregory Neil Shapiro curpref++; 578806f25ae9SGregory Neil Shapiro 578906f25ae9SGregory Neil Shapiro *endp++ = sep; 579006f25ae9SGregory Neil Shapiro } 579106f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS) 579206f25ae9SGregory Neil Shapiro break; 579306f25ae9SGregory Neil Shapiro } 579406f25ae9SGregory Neil Shapiro 579506f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */ 579606f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++) 579706f25ae9SGregory Neil Shapiro { 579806f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++) 579906f25ae9SGregory Neil Shapiro { 580006f25ae9SGregory Neil Shapiro /* 580106f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only 580206f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records 580306f25ae9SGregory Neil Shapiro */ 580406f25ae9SGregory Neil Shapiro 580506f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j]) 580606f25ae9SGregory Neil Shapiro break; 580706f25ae9SGregory Neil Shapiro 580806f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] || 580906f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 581006f25ae9SGregory Neil Shapiro { 581140266059SGregory Neil Shapiro register unsigned short tempp; 581206f25ae9SGregory Neil Shapiro register long tempr; 581306f25ae9SGregory Neil Shapiro register char *temp1; 581406f25ae9SGregory Neil Shapiro 581506f25ae9SGregory Neil Shapiro tempp = prefer[i]; 581606f25ae9SGregory Neil Shapiro prefer[i] = prefer[j]; 581706f25ae9SGregory Neil Shapiro prefer[j] = tempp; 581806f25ae9SGregory Neil Shapiro temp1 = mxhosts[i]; 581906f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j]; 582006f25ae9SGregory Neil Shapiro mxhosts[j] = temp1; 582106f25ae9SGregory Neil Shapiro tempr = rndm[i]; 582206f25ae9SGregory Neil Shapiro rndm[i] = rndm[j]; 582306f25ae9SGregory Neil Shapiro rndm[j] = tempr; 582406f25ae9SGregory Neil Shapiro } 582506f25ae9SGregory Neil Shapiro } 582606f25ae9SGregory Neil Shapiro } 582706f25ae9SGregory Neil Shapiro return nmx; 582806f25ae9SGregory Neil Shapiro } 582906f25ae9SGregory Neil Shapiro 583006f25ae9SGregory Neil Shapiro # if STARTTLS 583106f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL; 583240266059SGregory Neil Shapiro static bool tls_ok_clt = true; 583306f25ae9SGregory Neil Shapiro 583440266059SGregory Neil Shapiro /* 583540266059SGregory Neil Shapiro ** SETCLTTLS -- client side TLS: allow/disallow. 583640266059SGregory Neil Shapiro ** 583740266059SGregory Neil Shapiro ** Parameters: 583840266059SGregory Neil Shapiro ** tls_ok -- should tls be done? 583940266059SGregory Neil Shapiro ** 584040266059SGregory Neil Shapiro ** Returns: 584140266059SGregory Neil Shapiro ** none. 584240266059SGregory Neil Shapiro ** 584340266059SGregory Neil Shapiro ** Side Effects: 584440266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 584540266059SGregory Neil Shapiro */ 584640266059SGregory Neil Shapiro 584740266059SGregory Neil Shapiro void 584840266059SGregory Neil Shapiro setclttls(tls_ok) 584940266059SGregory Neil Shapiro bool tls_ok; 585040266059SGregory Neil Shapiro { 585140266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 585240266059SGregory Neil Shapiro return; 585340266059SGregory Neil Shapiro } 585440266059SGregory Neil Shapiro /* 585506f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS 585606f25ae9SGregory Neil Shapiro ** 585706f25ae9SGregory Neil Shapiro ** Parameters: 585840266059SGregory Neil Shapiro ** tls_ok -- should tls initialization be done? 585906f25ae9SGregory Neil Shapiro ** 586006f25ae9SGregory Neil Shapiro ** Returns: 586106f25ae9SGregory Neil Shapiro ** succeeded? 586240266059SGregory Neil Shapiro ** 586340266059SGregory Neil Shapiro ** Side Effects: 586440266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 586506f25ae9SGregory Neil Shapiro */ 586606f25ae9SGregory Neil Shapiro 586706f25ae9SGregory Neil Shapiro bool 586840266059SGregory Neil Shapiro initclttls(tls_ok) 586940266059SGregory Neil Shapiro bool tls_ok; 587006f25ae9SGregory Neil Shapiro { 587140266059SGregory Neil Shapiro if (!tls_ok_clt) 587240266059SGregory Neil Shapiro return false; 587340266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 587440266059SGregory Neil Shapiro if (!tls_ok_clt) 587540266059SGregory Neil Shapiro return false; 587606f25ae9SGregory Neil Shapiro if (clt_ctx != NULL) 587740266059SGregory Neil Shapiro return true; /* already done */ 587840266059SGregory Neil Shapiro tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCERTfile, 587940266059SGregory Neil Shapiro Cltkeyfile, CACERTpath, CACERTfile, DHParams); 588040266059SGregory Neil Shapiro return tls_ok_clt; 588106f25ae9SGregory Neil Shapiro } 588206f25ae9SGregory Neil Shapiro 588340266059SGregory Neil Shapiro /* 588406f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side) 588506f25ae9SGregory Neil Shapiro ** 588606f25ae9SGregory Neil Shapiro ** Parameters: 588706f25ae9SGregory Neil Shapiro ** m -- the mailer. 588806f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 588906f25ae9SGregory Neil Shapiro ** e -- the envelope. 589006f25ae9SGregory Neil Shapiro ** 589106f25ae9SGregory Neil Shapiro ** Returns: 589206f25ae9SGregory Neil Shapiro ** success? 589306f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_ 589406f25ae9SGregory Neil Shapiro ** that denotes which stage failed.) 589506f25ae9SGregory Neil Shapiro */ 589606f25ae9SGregory Neil Shapiro 589706f25ae9SGregory Neil Shapiro static int 589806f25ae9SGregory Neil Shapiro starttls(m, mci, e) 589906f25ae9SGregory Neil Shapiro MAILER *m; 590006f25ae9SGregory Neil Shapiro MCI *mci; 590106f25ae9SGregory Neil Shapiro ENVELOPE *e; 590206f25ae9SGregory Neil Shapiro { 590306f25ae9SGregory Neil Shapiro int smtpresult; 590442e5d165SGregory Neil Shapiro int result = 0; 590542e5d165SGregory Neil Shapiro int rfd, wfd; 590606f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL; 590740266059SGregory Neil Shapiro time_t tlsstart; 590806f25ae9SGregory Neil Shapiro 590940266059SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls(true)) 591042e5d165SGregory Neil Shapiro return EX_TEMPFAIL; 591106f25ae9SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci); 591206f25ae9SGregory Neil Shapiro 591306f25ae9SGregory Neil Shapiro /* get the reply */ 591440266059SGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL); 591506f25ae9SGregory Neil Shapiro 591606f25ae9SGregory Neil Shapiro /* check return code from server */ 591706f25ae9SGregory Neil Shapiro if (smtpresult == 454) 591806f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 591906f25ae9SGregory Neil Shapiro if (smtpresult == 501) 592006f25ae9SGregory Neil Shapiro return EX_USAGE; 592106f25ae9SGregory Neil Shapiro if (smtpresult == -1) 592206f25ae9SGregory Neil Shapiro return smtpresult; 592306f25ae9SGregory Neil Shapiro if (smtpresult != 220) 592406f25ae9SGregory Neil Shapiro return EX_PROTOCOL; 592506f25ae9SGregory Neil Shapiro 592606f25ae9SGregory Neil Shapiro if (LogLevel > 13) 592740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 592806f25ae9SGregory Neil Shapiro 592906f25ae9SGregory Neil Shapiro /* start connection */ 593006f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 593106f25ae9SGregory Neil Shapiro { 593206f25ae9SGregory Neil Shapiro if (LogLevel > 5) 593306f25ae9SGregory Neil Shapiro { 593440266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 593540266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_new failed"); 593606f25ae9SGregory Neil Shapiro if (LogLevel > 9) 593740266059SGregory Neil Shapiro tlslogerr("client"); 593806f25ae9SGregory Neil Shapiro } 593906f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 594006f25ae9SGregory Neil Shapiro } 594106f25ae9SGregory Neil Shapiro 594240266059SGregory Neil Shapiro rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 594340266059SGregory Neil Shapiro wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 594442e5d165SGregory Neil Shapiro 594506f25ae9SGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */ 594642e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 || 594740266059SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 594840266059SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 594906f25ae9SGregory Neil Shapiro { 595006f25ae9SGregory Neil Shapiro if (LogLevel > 5) 595106f25ae9SGregory Neil Shapiro { 595240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 595340266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_xfd failed=%d", 595440266059SGregory Neil Shapiro result); 595506f25ae9SGregory Neil Shapiro if (LogLevel > 9) 595640266059SGregory Neil Shapiro tlslogerr("client"); 595706f25ae9SGregory Neil Shapiro } 595806f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 595906f25ae9SGregory Neil Shapiro } 596006f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl); 596140266059SGregory Neil Shapiro tlsstart = curtime(); 596240266059SGregory Neil Shapiro 596340266059SGregory Neil Shapiro ssl_retry: 596406f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0) 596506f25ae9SGregory Neil Shapiro { 596606f25ae9SGregory Neil Shapiro int i; 596740266059SGregory Neil Shapiro bool timedout; 596840266059SGregory Neil Shapiro time_t left; 596940266059SGregory Neil Shapiro time_t now = curtime(); 597040266059SGregory Neil Shapiro struct timeval tv; 597106f25ae9SGregory Neil Shapiro 597206f25ae9SGregory Neil Shapiro /* what to do in this case? */ 597306f25ae9SGregory Neil Shapiro i = SSL_get_error(clt_ssl, result); 597440266059SGregory Neil Shapiro 597540266059SGregory Neil Shapiro /* 597640266059SGregory Neil Shapiro ** For SSL_ERROR_WANT_{READ,WRITE}: 597740266059SGregory Neil Shapiro ** There is not a complete SSL record available yet 597840266059SGregory Neil Shapiro ** or there is only a partial SSL record removed from 597940266059SGregory Neil Shapiro ** the network (socket) buffer into the SSL buffer. 598040266059SGregory Neil Shapiro ** The SSL_connect will only succeed when a full 598140266059SGregory Neil Shapiro ** SSL record is available (assuming a "real" error 598240266059SGregory Neil Shapiro ** doesn't happen). To handle when a "real" error 598340266059SGregory Neil Shapiro ** does happen the select is set for exceptions too. 598440266059SGregory Neil Shapiro ** The connection may be re-negotiated during this time 598540266059SGregory Neil Shapiro ** so both read and write "want errors" need to be handled. 598640266059SGregory Neil Shapiro ** A select() exception loops back so that a proper SSL 598740266059SGregory Neil Shapiro ** error message can be gotten. 598840266059SGregory Neil Shapiro */ 598940266059SGregory Neil Shapiro 599040266059SGregory Neil Shapiro left = TimeOuts.to_starttls - (now - tlsstart); 599140266059SGregory Neil Shapiro timedout = left <= 0; 599240266059SGregory Neil Shapiro if (!timedout) 599340266059SGregory Neil Shapiro { 599440266059SGregory Neil Shapiro tv.tv_sec = left; 599540266059SGregory Neil Shapiro tv.tv_usec = 0; 599640266059SGregory Neil Shapiro } 599740266059SGregory Neil Shapiro 599840266059SGregory Neil Shapiro if (!timedout && i == SSL_ERROR_WANT_READ) 599940266059SGregory Neil Shapiro { 600040266059SGregory Neil Shapiro fd_set ssl_maskr, ssl_maskx; 600140266059SGregory Neil Shapiro 600240266059SGregory Neil Shapiro FD_ZERO(&ssl_maskr); 600340266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskr); 600440266059SGregory Neil Shapiro FD_ZERO(&ssl_maskx); 600540266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 600640266059SGregory Neil Shapiro if (select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, &tv) 600740266059SGregory Neil Shapiro > 0) 600840266059SGregory Neil Shapiro goto ssl_retry; 600940266059SGregory Neil Shapiro } 601040266059SGregory Neil Shapiro if (!timedout && i == SSL_ERROR_WANT_WRITE) 601140266059SGregory Neil Shapiro { 601240266059SGregory Neil Shapiro fd_set ssl_maskw, ssl_maskx; 601340266059SGregory Neil Shapiro 601440266059SGregory Neil Shapiro FD_ZERO(&ssl_maskw); 601540266059SGregory Neil Shapiro FD_SET(wfd, &ssl_maskw); 601640266059SGregory Neil Shapiro FD_ZERO(&ssl_maskx); 601740266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 601840266059SGregory Neil Shapiro if (select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, &tv) 601940266059SGregory Neil Shapiro > 0) 602040266059SGregory Neil Shapiro goto ssl_retry; 602140266059SGregory Neil Shapiro } 602206f25ae9SGregory Neil Shapiro if (LogLevel > 5) 602306f25ae9SGregory Neil Shapiro { 602406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 602540266059SGregory Neil Shapiro "STARTTLS=client, error: connect failed=%d, SSL_error=%d, timedout=%d", 602640266059SGregory Neil Shapiro result, i, (int) timedout); 602740266059SGregory Neil Shapiro if (LogLevel > 8) 602840266059SGregory Neil Shapiro tlslogerr("client"); 602906f25ae9SGregory Neil Shapiro } 603006f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 603106f25ae9SGregory Neil Shapiro clt_ssl = NULL; 603206f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 603306f25ae9SGregory Neil Shapiro } 603406f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl; 603540266059SGregory Neil Shapiro result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 603640266059SGregory Neil Shapiro &mci->mci_macro, true); 603706f25ae9SGregory Neil Shapiro 603840266059SGregory Neil Shapiro /* switch to use TLS... */ 603906f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 604006f25ae9SGregory Neil Shapiro return EX_OK; 604106f25ae9SGregory Neil Shapiro 604206f25ae9SGregory Neil Shapiro /* failure */ 604306f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 604406f25ae9SGregory Neil Shapiro clt_ssl = NULL; 604506f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 604606f25ae9SGregory Neil Shapiro } 604740266059SGregory Neil Shapiro /* 604806f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side) 604906f25ae9SGregory Neil Shapiro ** 605006f25ae9SGregory Neil Shapiro ** Parameters: 605106f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 605206f25ae9SGregory Neil Shapiro ** 605306f25ae9SGregory Neil Shapiro ** Returns: 605406f25ae9SGregory Neil Shapiro ** success? 605506f25ae9SGregory Neil Shapiro */ 605640266059SGregory Neil Shapiro 605740266059SGregory Neil Shapiro static int 605806f25ae9SGregory Neil Shapiro endtlsclt(mci) 605906f25ae9SGregory Neil Shapiro MCI *mci; 606006f25ae9SGregory Neil Shapiro { 606106f25ae9SGregory Neil Shapiro int r; 606206f25ae9SGregory Neil Shapiro 606306f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags)) 606406f25ae9SGregory Neil Shapiro return EX_OK; 606506f25ae9SGregory Neil Shapiro r = endtls(mci->mci_ssl, "client"); 606606f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 606706f25ae9SGregory Neil Shapiro return r; 606806f25ae9SGregory Neil Shapiro } 606940266059SGregory Neil Shapiro # endif /* STARTTLS */ 607040266059SGregory Neil Shapiro # if STARTTLS || SASL 607140266059SGregory Neil Shapiro /* 607240266059SGregory Neil Shapiro ** ISCLTFLGSET -- check whether client flag is set. 607306f25ae9SGregory Neil Shapiro ** 607406f25ae9SGregory Neil Shapiro ** Parameters: 607540266059SGregory Neil Shapiro ** e -- envelope. 607640266059SGregory Neil Shapiro ** flag -- flag to check in {client_flags} 607706f25ae9SGregory Neil Shapiro ** 607806f25ae9SGregory Neil Shapiro ** Returns: 607940266059SGregory Neil Shapiro ** true iff flag is set. 608006f25ae9SGregory Neil Shapiro */ 608106f25ae9SGregory Neil Shapiro 608240266059SGregory Neil Shapiro static bool 608340266059SGregory Neil Shapiro iscltflgset(e, flag) 608440266059SGregory Neil Shapiro ENVELOPE *e; 608540266059SGregory Neil Shapiro int flag; 608606f25ae9SGregory Neil Shapiro { 608740266059SGregory Neil Shapiro char *p; 6088602a2b1bSGregory Neil Shapiro 608940266059SGregory Neil Shapiro p = macvalue(macid("{client_flags}"), e); 609040266059SGregory Neil Shapiro if (p == NULL) 609140266059SGregory Neil Shapiro return false; 609240266059SGregory Neil Shapiro for (; *p != '\0'; p++) 609306f25ae9SGregory Neil Shapiro { 609440266059SGregory Neil Shapiro /* look for just this one flag */ 609540266059SGregory Neil Shapiro if (*p == (char) flag) 609640266059SGregory Neil Shapiro return true; 609706f25ae9SGregory Neil Shapiro } 609840266059SGregory Neil Shapiro return false; 609906f25ae9SGregory Neil Shapiro } 610040266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 6101