1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2010, 2012 Proofpoint, 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> 154e4196cbSGregory Neil Shapiro #include <sm/time.h> 1606f25ae9SGregory Neil Shapiro 174313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: deliver.c,v 8.1030 2013-11-22 20:51:55 ca Exp $") 18c2aa98e2SPeter Wemm 19c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT 20c2aa98e2SPeter Wemm # include <login_cap.h> 21*5b0945b5SGregory Neil Shapiro #endif 2206f25ae9SGregory Neil Shapiro 23605302a5SGregory Neil Shapiro #if NETINET || NETINET6 24605302a5SGregory Neil Shapiro # include <arpa/inet.h> 25*5b0945b5SGregory Neil Shapiro #endif 26605302a5SGregory Neil Shapiro 2740266059SGregory Neil Shapiro #if STARTTLS || SASL 2806f25ae9SGregory Neil Shapiro # include "sfsasl.h" 29*5b0945b5SGregory Neil Shapiro # include "tls.h" 30*5b0945b5SGregory Neil Shapiro #endif 3106f25ae9SGregory Neil Shapiro 3206f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *)); 3306f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 34b6bacd31SGregory Neil Shapiro static void mailfiletimeout __P((int)); 35b6bacd31SGregory Neil Shapiro static void endwaittimeout __P((int)); 3606f25ae9SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *)); 3706f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int)); 3840266059SGregory Neil Shapiro static int coloncmp __P((const char *, const char *)); 39c2aa98e2SPeter Wemm 4006f25ae9SGregory Neil Shapiro #if STARTTLS 41ba00ec3dSGregory Neil Shapiro # include <openssl/err.h> 42*5b0945b5SGregory Neil Shapiro # if DANE 43*5b0945b5SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *, dane_vrfy_ctx_P)); 44*5b0945b5SGregory Neil Shapiro # else 4506f25ae9SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *)); 46*5b0945b5SGregory Neil Shapiro # endif 4740266059SGregory Neil Shapiro static int endtlsclt __P((MCI *)); 4806f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 4940266059SGregory Neil Shapiro #if STARTTLS || SASL 5040266059SGregory Neil Shapiro static bool iscltflgset __P((ENVELOPE *, int)); 51*5b0945b5SGregory Neil Shapiro #endif 52*5b0945b5SGregory Neil Shapiro 53*5b0945b5SGregory Neil Shapiro #if _FFR_OCC 54*5b0945b5SGregory Neil Shapiro # include <ratectrl.h> 55*5b0945b5SGregory Neil Shapiro #endif 56c2aa98e2SPeter Wemm 57c2aa98e2SPeter Wemm /* 58c2aa98e2SPeter Wemm ** SENDALL -- actually send all the messages. 59c2aa98e2SPeter Wemm ** 60c2aa98e2SPeter Wemm ** Parameters: 61c2aa98e2SPeter Wemm ** e -- the envelope to send. 62c2aa98e2SPeter Wemm ** mode -- the delivery mode to use. If SM_DEFAULT, use 63c2aa98e2SPeter Wemm ** the current e->e_sendmode. 64c2aa98e2SPeter Wemm ** 65c2aa98e2SPeter Wemm ** Returns: 66c2aa98e2SPeter Wemm ** none. 67c2aa98e2SPeter Wemm ** 68c2aa98e2SPeter Wemm ** Side Effects: 69c2aa98e2SPeter Wemm ** Scans the send lists and sends everything it finds. 70c2aa98e2SPeter Wemm ** Delivers any appropriate error messages. 71c2aa98e2SPeter Wemm ** If we are running in a non-interactive mode, takes the 72c2aa98e2SPeter Wemm ** appropriate action. 73c2aa98e2SPeter Wemm */ 74c2aa98e2SPeter Wemm 75c2aa98e2SPeter Wemm void 76c2aa98e2SPeter Wemm sendall(e, mode) 77c2aa98e2SPeter Wemm ENVELOPE *e; 78c2aa98e2SPeter Wemm int mode; 79c2aa98e2SPeter Wemm { 80c2aa98e2SPeter Wemm register ADDRESS *q; 81c2aa98e2SPeter Wemm char *owner; 82c2aa98e2SPeter Wemm int otherowners; 8306f25ae9SGregory Neil Shapiro int save_errno; 84c2aa98e2SPeter Wemm register ENVELOPE *ee; 85c2aa98e2SPeter Wemm ENVELOPE *splitenv = NULL; 86c2aa98e2SPeter Wemm int oldverbose = Verbose; 8740266059SGregory Neil Shapiro bool somedeliveries = false, expensive = false; 88c2aa98e2SPeter Wemm pid_t pid; 89c2aa98e2SPeter Wemm 90c2aa98e2SPeter Wemm /* 91c2aa98e2SPeter Wemm ** If this message is to be discarded, don't bother sending 92c2aa98e2SPeter Wemm ** the message at all. 93c2aa98e2SPeter Wemm */ 94c2aa98e2SPeter Wemm 95c2aa98e2SPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 96c2aa98e2SPeter Wemm { 97c2aa98e2SPeter Wemm if (tTd(13, 1)) 9840266059SGregory Neil Shapiro sm_dprintf("sendall: discarding id %s\n", e->e_id); 99c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 10040266059SGregory Neil Shapiro if (LogLevel > 9) 10140266059SGregory Neil Shapiro logundelrcpts(e, "discarded", 9, true); 10240266059SGregory Neil Shapiro else if (LogLevel > 4) 103c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "discarded"); 10440266059SGregory Neil Shapiro markstats(e, NULL, STATS_REJECT); 105c2aa98e2SPeter Wemm return; 106c2aa98e2SPeter Wemm } 107c2aa98e2SPeter Wemm 108c2aa98e2SPeter Wemm /* 109c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 110c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 111c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 112c2aa98e2SPeter Wemm ** addresses to be sent. 113c2aa98e2SPeter Wemm */ 114c2aa98e2SPeter Wemm 115c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 116c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 117c2aa98e2SPeter Wemm { 118c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 119c2aa98e2SPeter Wemm return; 120c2aa98e2SPeter Wemm } 121c2aa98e2SPeter Wemm 122c2aa98e2SPeter Wemm /* determine actual delivery mode */ 123c2aa98e2SPeter Wemm if (mode == SM_DEFAULT) 124c2aa98e2SPeter Wemm { 125c2aa98e2SPeter Wemm mode = e->e_sendmode; 126c2aa98e2SPeter Wemm if (mode != SM_VERIFY && mode != SM_DEFER && 127c2aa98e2SPeter Wemm shouldqueue(e->e_msgpriority, e->e_ctime)) 128c2aa98e2SPeter Wemm mode = SM_QUEUE; 129c2aa98e2SPeter Wemm } 130c2aa98e2SPeter Wemm 131c2aa98e2SPeter Wemm if (tTd(13, 1)) 132c2aa98e2SPeter Wemm { 13340266059SGregory Neil Shapiro sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ", 134c2aa98e2SPeter Wemm mode, e->e_id); 135e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 13640266059SGregory Neil Shapiro sm_dprintf("\te_flags = "); 137c2aa98e2SPeter Wemm printenvflags(e); 13840266059SGregory Neil Shapiro sm_dprintf("sendqueue:\n"); 139e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 140c2aa98e2SPeter Wemm } 141c2aa98e2SPeter Wemm 142c2aa98e2SPeter Wemm /* 143c2aa98e2SPeter Wemm ** Do any preprocessing necessary for the mode we are running. 144c2aa98e2SPeter Wemm ** Check to make sure the hop count is reasonable. 145c2aa98e2SPeter Wemm ** Delete sends to the sender in mailing lists. 146c2aa98e2SPeter Wemm */ 147c2aa98e2SPeter Wemm 148c2aa98e2SPeter Wemm CurEnv = e; 149c2aa98e2SPeter Wemm if (tTd(62, 1)) 150c2aa98e2SPeter Wemm checkfds(NULL); 151c2aa98e2SPeter Wemm 152c2aa98e2SPeter Wemm if (e->e_hopcount > MaxHopCount) 153c2aa98e2SPeter Wemm { 1548774250cSGregory Neil Shapiro char *recip; 1558774250cSGregory Neil Shapiro 1568774250cSGregory Neil Shapiro if (e->e_sendqueue != NULL && 1578774250cSGregory Neil Shapiro e->e_sendqueue->q_paddr != NULL) 1588774250cSGregory Neil Shapiro recip = e->e_sendqueue->q_paddr; 1598774250cSGregory Neil Shapiro else 1608774250cSGregory Neil Shapiro recip = "(nobody)"; 1618774250cSGregory Neil Shapiro 162c2aa98e2SPeter Wemm errno = 0; 16340266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), false); 164c2aa98e2SPeter Wemm e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 16506f25ae9SGregory Neil Shapiro ExitStat = EX_UNAVAILABLE; 1668774250cSGregory Neil Shapiro syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s", 167c2aa98e2SPeter Wemm e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 168c2aa98e2SPeter Wemm RealHostName == NULL ? "localhost" : RealHostName, 1698774250cSGregory Neil Shapiro recip); 17006f25ae9SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 17106f25ae9SGregory Neil Shapiro { 17206f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 17306f25ae9SGregory Neil Shapiro continue; 17406f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 17506f25ae9SGregory Neil Shapiro q->q_status = "5.4.6"; 1768774250cSGregory Neil Shapiro q->q_rstatus = "554 5.4.6 Too many hops"; 17706f25ae9SGregory Neil Shapiro } 178c2aa98e2SPeter Wemm return; 179c2aa98e2SPeter Wemm } 180c2aa98e2SPeter Wemm 181c2aa98e2SPeter Wemm /* 182c2aa98e2SPeter Wemm ** Do sender deletion. 183c2aa98e2SPeter Wemm ** 18406f25ae9SGregory Neil Shapiro ** If the sender should be queued up, skip this. 185c2aa98e2SPeter Wemm ** This can happen if the name server is hosed when you 186c2aa98e2SPeter Wemm ** are trying to send mail. The result is that the sender 187c2aa98e2SPeter Wemm ** is instantiated in the queue as a recipient. 188c2aa98e2SPeter Wemm */ 189c2aa98e2SPeter Wemm 190c2aa98e2SPeter Wemm if (!bitset(EF_METOO, e->e_flags) && 19106f25ae9SGregory Neil Shapiro !QS_IS_QUEUEUP(e->e_from.q_state)) 192c2aa98e2SPeter Wemm { 193c2aa98e2SPeter Wemm if (tTd(13, 5)) 194c2aa98e2SPeter Wemm { 19540266059SGregory Neil Shapiro sm_dprintf("sendall: QS_SENDER "); 196e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 197c2aa98e2SPeter Wemm } 19806f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 199c2aa98e2SPeter Wemm (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 200c2aa98e2SPeter Wemm } 201c2aa98e2SPeter Wemm 202c2aa98e2SPeter Wemm /* 203c2aa98e2SPeter Wemm ** Handle alias owners. 204c2aa98e2SPeter Wemm ** 205c2aa98e2SPeter Wemm ** We scan up the q_alias chain looking for owners. 206c2aa98e2SPeter Wemm ** We discard owners that are the same as the return path. 207c2aa98e2SPeter Wemm */ 208c2aa98e2SPeter Wemm 209c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 210c2aa98e2SPeter Wemm { 211c2aa98e2SPeter Wemm register struct address *a; 212c2aa98e2SPeter Wemm 213c2aa98e2SPeter Wemm for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 214c2aa98e2SPeter Wemm continue; 215c2aa98e2SPeter Wemm if (a != NULL) 216c2aa98e2SPeter Wemm q->q_owner = a->q_owner; 217c2aa98e2SPeter Wemm 218c2aa98e2SPeter Wemm if (q->q_owner != NULL && 21906f25ae9SGregory Neil Shapiro !QS_IS_DEAD(q->q_state) && 220c2aa98e2SPeter Wemm strcmp(q->q_owner, e->e_from.q_paddr) == 0) 221c2aa98e2SPeter Wemm q->q_owner = NULL; 222c2aa98e2SPeter Wemm } 223c2aa98e2SPeter Wemm 224c2aa98e2SPeter Wemm if (tTd(13, 25)) 225c2aa98e2SPeter Wemm { 22640266059SGregory Neil Shapiro sm_dprintf("\nAfter first owner pass, sendq =\n"); 227e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 228c2aa98e2SPeter Wemm } 229c2aa98e2SPeter Wemm 230c2aa98e2SPeter Wemm owner = ""; 231c2aa98e2SPeter Wemm otherowners = 1; 232c2aa98e2SPeter Wemm while (owner != NULL && otherowners > 0) 233c2aa98e2SPeter Wemm { 234c2aa98e2SPeter Wemm if (tTd(13, 28)) 23540266059SGregory Neil Shapiro sm_dprintf("owner = \"%s\", otherowners = %d\n", 236c2aa98e2SPeter Wemm owner, otherowners); 237c2aa98e2SPeter Wemm owner = NULL; 238c2aa98e2SPeter Wemm otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; 239c2aa98e2SPeter Wemm 240c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 241c2aa98e2SPeter Wemm { 242c2aa98e2SPeter Wemm if (tTd(13, 30)) 243c2aa98e2SPeter Wemm { 24440266059SGregory Neil Shapiro sm_dprintf("Checking "); 245e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false); 246c2aa98e2SPeter Wemm } 24706f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 248c2aa98e2SPeter Wemm { 249c2aa98e2SPeter Wemm if (tTd(13, 30)) 25040266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_DEAD\n"); 251c2aa98e2SPeter Wemm continue; 252c2aa98e2SPeter Wemm } 253c2aa98e2SPeter Wemm if (tTd(13, 29) && !tTd(13, 30)) 254c2aa98e2SPeter Wemm { 25540266059SGregory Neil Shapiro sm_dprintf("Checking "); 256e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false); 257c2aa98e2SPeter Wemm } 258c2aa98e2SPeter Wemm 259c2aa98e2SPeter Wemm if (q->q_owner != NULL) 260c2aa98e2SPeter Wemm { 261c2aa98e2SPeter Wemm if (owner == NULL) 262c2aa98e2SPeter Wemm { 263c2aa98e2SPeter Wemm if (tTd(13, 40)) 26440266059SGregory Neil Shapiro sm_dprintf(" ... First owner = \"%s\"\n", 265c2aa98e2SPeter Wemm q->q_owner); 266c2aa98e2SPeter Wemm owner = q->q_owner; 267c2aa98e2SPeter Wemm } 268c2aa98e2SPeter Wemm else if (owner != q->q_owner) 269c2aa98e2SPeter Wemm { 270c2aa98e2SPeter Wemm if (strcmp(owner, q->q_owner) == 0) 271c2aa98e2SPeter Wemm { 272c2aa98e2SPeter Wemm if (tTd(13, 40)) 27340266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 274c2aa98e2SPeter Wemm owner); 275c2aa98e2SPeter Wemm 276c2aa98e2SPeter Wemm /* make future comparisons cheap */ 277c2aa98e2SPeter Wemm q->q_owner = owner; 278c2aa98e2SPeter Wemm } 279c2aa98e2SPeter Wemm else 280c2aa98e2SPeter Wemm { 281c2aa98e2SPeter Wemm if (tTd(13, 40)) 28240266059SGregory Neil Shapiro sm_dprintf(" ... Another owner \"%s\"\n", 283c2aa98e2SPeter Wemm q->q_owner); 284c2aa98e2SPeter Wemm otherowners++; 285c2aa98e2SPeter Wemm } 286c2aa98e2SPeter Wemm owner = q->q_owner; 287c2aa98e2SPeter Wemm } 288c2aa98e2SPeter Wemm else if (tTd(13, 40)) 28940266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 290c2aa98e2SPeter Wemm owner); 291c2aa98e2SPeter Wemm } 292c2aa98e2SPeter Wemm else 293c2aa98e2SPeter Wemm { 294c2aa98e2SPeter Wemm if (tTd(13, 40)) 29540266059SGregory Neil Shapiro sm_dprintf(" ... Null owner\n"); 296c2aa98e2SPeter Wemm otherowners++; 297c2aa98e2SPeter Wemm } 298c2aa98e2SPeter Wemm 29906f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(q->q_state)) 30006f25ae9SGregory Neil Shapiro { 30106f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 30240266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_BADADDR\n"); 30306f25ae9SGregory Neil Shapiro continue; 30406f25ae9SGregory Neil Shapiro } 30506f25ae9SGregory Neil Shapiro 30606f25ae9SGregory Neil Shapiro if (QS_IS_QUEUEUP(q->q_state)) 30706f25ae9SGregory Neil Shapiro { 30806f25ae9SGregory Neil Shapiro MAILER *m = q->q_mailer; 30906f25ae9SGregory Neil Shapiro 31006f25ae9SGregory Neil Shapiro /* 31106f25ae9SGregory Neil Shapiro ** If we have temporary address failures 31206f25ae9SGregory Neil Shapiro ** (e.g., dns failure) and a fallback MX is 31306f25ae9SGregory Neil Shapiro ** set, send directly to the fallback MX host. 31406f25ae9SGregory Neil Shapiro */ 31506f25ae9SGregory Neil Shapiro 316e92d3f3fSGregory Neil Shapiro if (FallbackMX != NULL && 317e92d3f3fSGregory Neil Shapiro !wordinclass(FallbackMX, 'w') && 31806f25ae9SGregory Neil Shapiro mode != SM_VERIFY && 31940266059SGregory Neil Shapiro !bitnset(M_NOMX, m->m_flags) && 32040266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") == 0 && 32106f25ae9SGregory Neil Shapiro m->m_argv[0] != NULL && 32240266059SGregory Neil Shapiro strcmp(m->m_argv[0], "TCP") == 0) 32306f25ae9SGregory Neil Shapiro { 32406f25ae9SGregory Neil Shapiro int len; 32506f25ae9SGregory Neil Shapiro char *p; 32606f25ae9SGregory Neil Shapiro 32706f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 328e92d3f3fSGregory Neil Shapiro sm_dprintf(" ... FallbackMX\n"); 32906f25ae9SGregory Neil Shapiro 330e92d3f3fSGregory Neil Shapiro len = strlen(FallbackMX) + 1; 33140266059SGregory Neil Shapiro p = sm_rpool_malloc_x(e->e_rpool, len); 332e92d3f3fSGregory Neil Shapiro (void) sm_strlcpy(p, FallbackMX, len); 33306f25ae9SGregory Neil Shapiro q->q_state = QS_OK; 33406f25ae9SGregory Neil Shapiro q->q_host = p; 33506f25ae9SGregory Neil Shapiro } 33606f25ae9SGregory Neil Shapiro else 33706f25ae9SGregory Neil Shapiro { 33806f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 33940266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_QUEUEUP\n"); 34006f25ae9SGregory Neil Shapiro continue; 34106f25ae9SGregory Neil Shapiro } 34206f25ae9SGregory Neil Shapiro } 34306f25ae9SGregory Neil Shapiro 344c2aa98e2SPeter Wemm /* 345c2aa98e2SPeter Wemm ** If this mailer is expensive, and if we don't 346c2aa98e2SPeter Wemm ** want to make connections now, just mark these 347c2aa98e2SPeter Wemm ** addresses and return. This is useful if we 348c2aa98e2SPeter Wemm ** want to batch connections to reduce load. This 349c2aa98e2SPeter Wemm ** will cause the messages to be queued up, and a 350c2aa98e2SPeter Wemm ** daemon will come along to send the messages later. 351c2aa98e2SPeter Wemm */ 352c2aa98e2SPeter Wemm 353c2aa98e2SPeter Wemm if (NoConnect && !Verbose && 354c2aa98e2SPeter Wemm bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 355c2aa98e2SPeter Wemm { 356c2aa98e2SPeter Wemm if (tTd(13, 30)) 35740266059SGregory Neil Shapiro sm_dprintf(" ... expensive\n"); 35806f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 35940266059SGregory Neil Shapiro expensive = true; 36006f25ae9SGregory Neil Shapiro } 36106f25ae9SGregory Neil Shapiro else if (bitnset(M_HOLD, q->q_mailer->m_flags) && 36206f25ae9SGregory Neil Shapiro QueueLimitId == NULL && 36306f25ae9SGregory Neil Shapiro QueueLimitSender == NULL && 36406f25ae9SGregory Neil Shapiro QueueLimitRecipient == NULL) 36506f25ae9SGregory Neil Shapiro { 36606f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 36740266059SGregory Neil Shapiro sm_dprintf(" ... hold\n"); 36806f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 36940266059SGregory Neil Shapiro expensive = true; 370c2aa98e2SPeter Wemm } 37140266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE && 37240266059SGregory Neil Shapiro e->e_quarmsg != NULL) 37340266059SGregory Neil Shapiro { 37440266059SGregory Neil Shapiro if (tTd(13, 30)) 37540266059SGregory Neil Shapiro sm_dprintf(" ... quarantine: %s\n", 37640266059SGregory Neil Shapiro e->e_quarmsg); 37740266059SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 37840266059SGregory Neil Shapiro expensive = true; 37940266059SGregory Neil Shapiro } 380c2aa98e2SPeter Wemm else 381c2aa98e2SPeter Wemm { 382c2aa98e2SPeter Wemm if (tTd(13, 30)) 38340266059SGregory Neil Shapiro sm_dprintf(" ... deliverable\n"); 38440266059SGregory Neil Shapiro somedeliveries = true; 385c2aa98e2SPeter Wemm } 386c2aa98e2SPeter Wemm } 387c2aa98e2SPeter Wemm 388c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0) 389c2aa98e2SPeter Wemm { 390c2aa98e2SPeter Wemm /* 391c2aa98e2SPeter Wemm ** Split this envelope into two. 392c2aa98e2SPeter Wemm */ 393c2aa98e2SPeter Wemm 39440266059SGregory Neil Shapiro ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, 395d0cef73dSGregory Neil Shapiro sizeof(*ee)); 39640266059SGregory Neil Shapiro STRUCTCOPY(*e, *ee); 39706f25ae9SGregory Neil Shapiro ee->e_message = NULL; 398c2aa98e2SPeter Wemm ee->e_id = NULL; 39906f25ae9SGregory Neil Shapiro assign_queueid(ee); 400c2aa98e2SPeter Wemm 401c2aa98e2SPeter Wemm if (tTd(13, 1)) 40240266059SGregory Neil Shapiro sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 40340266059SGregory Neil Shapiro e->e_id, ee->e_id, owner, 40440266059SGregory Neil Shapiro otherowners); 405c2aa98e2SPeter Wemm 40640266059SGregory Neil Shapiro ee->e_header = copyheader(e->e_header, ee->e_rpool); 40740266059SGregory Neil Shapiro ee->e_sendqueue = copyqueue(e->e_sendqueue, 40840266059SGregory Neil Shapiro ee->e_rpool); 40940266059SGregory Neil Shapiro ee->e_errorqueue = copyqueue(e->e_errorqueue, 41040266059SGregory Neil Shapiro ee->e_rpool); 411c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 412c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT; 41340266059SGregory Neil Shapiro setsender(owner, ee, NULL, '\0', true); 414c2aa98e2SPeter Wemm if (tTd(13, 5)) 415c2aa98e2SPeter Wemm { 41640266059SGregory Neil Shapiro sm_dprintf("sendall(split): QS_SENDER "); 417e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &ee->e_from, false); 418c2aa98e2SPeter Wemm } 41906f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER; 420c2aa98e2SPeter Wemm ee->e_dfp = NULL; 42106f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL; 422c2aa98e2SPeter Wemm ee->e_xfp = NULL; 42340266059SGregory Neil Shapiro ee->e_qgrp = e->e_qgrp; 42440266059SGregory Neil Shapiro ee->e_qdir = e->e_qdir; 425c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL; 426c2aa98e2SPeter Wemm ee->e_sibling = splitenv; 42706f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL; 42840266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 42940266059SGregory Neil Shapiro ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 43040266059SGregory Neil Shapiro e->e_quarmsg); 431c2aa98e2SPeter Wemm splitenv = ee; 432c2aa98e2SPeter Wemm 433c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 434c2aa98e2SPeter Wemm { 435c2aa98e2SPeter Wemm if (q->q_owner == owner) 436c2aa98e2SPeter Wemm { 43706f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 438c2aa98e2SPeter Wemm if (tTd(13, 6)) 43940266059SGregory Neil Shapiro sm_dprintf("\t... stripping %s from original envelope\n", 440c2aa98e2SPeter Wemm q->q_paddr); 441c2aa98e2SPeter Wemm } 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 444c2aa98e2SPeter Wemm { 445c2aa98e2SPeter Wemm if (q->q_owner != owner) 446c2aa98e2SPeter Wemm { 44706f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 448c2aa98e2SPeter Wemm if (tTd(13, 6)) 44940266059SGregory Neil Shapiro sm_dprintf("\t... dropping %s from cloned envelope\n", 450c2aa98e2SPeter Wemm q->q_paddr); 451c2aa98e2SPeter Wemm } 452c2aa98e2SPeter Wemm else 453c2aa98e2SPeter Wemm { 454c2aa98e2SPeter Wemm /* clear DSN parameters */ 455c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 456c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 457c2aa98e2SPeter Wemm if (tTd(13, 6)) 45840266059SGregory Neil Shapiro sm_dprintf("\t... moving %s to cloned envelope\n", 459c2aa98e2SPeter Wemm q->q_paddr); 460c2aa98e2SPeter Wemm } 461c2aa98e2SPeter Wemm } 462c2aa98e2SPeter Wemm 463c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 46440266059SGregory Neil Shapiro dup_queue_file(e, ee, DATAFL_LETTER); 46506f25ae9SGregory Neil Shapiro 46606f25ae9SGregory Neil Shapiro /* 46706f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent 46806f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while 46906f25ae9SGregory Neil Shapiro ** processing the recipients (done before the 47006f25ae9SGregory Neil Shapiro ** envelope splitting). 47106f25ae9SGregory Neil Shapiro */ 47206f25ae9SGregory Neil Shapiro 47306f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL) 47440266059SGregory Neil Shapiro ee->e_xfp = sm_io_dup(e->e_xfp); 47506f25ae9SGregory Neil Shapiro 47606f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */ 47706f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL) 478c2aa98e2SPeter Wemm openxscript(ee); 47906f25ae9SGregory Neil Shapiro 480065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4) 48140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 48240266059SGregory Neil Shapiro "%s: clone: owner=%s", 48340266059SGregory Neil Shapiro ee->e_id, owner); 484c2aa98e2SPeter Wemm } 485c2aa98e2SPeter Wemm } 486c2aa98e2SPeter Wemm 487c2aa98e2SPeter Wemm if (owner != NULL) 488c2aa98e2SPeter Wemm { 48940266059SGregory Neil Shapiro setsender(owner, e, NULL, '\0', true); 490c2aa98e2SPeter Wemm if (tTd(13, 5)) 491c2aa98e2SPeter Wemm { 49240266059SGregory Neil Shapiro sm_dprintf("sendall(owner): QS_SENDER "); 493e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 494c2aa98e2SPeter Wemm } 49506f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 496c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL; 497c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT; 498c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 499c2aa98e2SPeter Wemm } 500c2aa98e2SPeter Wemm 501c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */ 50240266059SGregory Neil Shapiro if (!somedeliveries && !WILL_BE_QUEUED(mode) && 503c2aa98e2SPeter Wemm mode != SM_VERIFY) 504c2aa98e2SPeter Wemm { 50540266059SGregory Neil Shapiro time_t now; 506193538b7SGregory Neil Shapiro 507c2aa98e2SPeter Wemm if (tTd(13, 29)) 508ffb83623SGregory Neil Shapiro sm_dprintf("No deliveries: auto-queueing\n"); 509c2aa98e2SPeter Wemm mode = SM_QUEUE; 51040266059SGregory Neil Shapiro now = curtime(); 511c2aa98e2SPeter Wemm 512c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */ 513193538b7SGregory Neil Shapiro e->e_dtime = now; 514c2aa98e2SPeter Wemm if (!expensive) 515c2aa98e2SPeter Wemm e->e_ntries++; 516c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 517c2aa98e2SPeter Wemm { 518193538b7SGregory Neil Shapiro ee->e_dtime = now; 519c2aa98e2SPeter Wemm if (!expensive) 520c2aa98e2SPeter Wemm ee->e_ntries++; 521c2aa98e2SPeter Wemm } 522c2aa98e2SPeter Wemm } 523c2aa98e2SPeter Wemm 52440266059SGregory Neil Shapiro if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || 525e92d3f3fSGregory Neil Shapiro (mode != SM_VERIFY && 526e92d3f3fSGregory Neil Shapiro (SuperSafe == SAFE_REALLY || 527e92d3f3fSGregory Neil Shapiro SuperSafe == SAFE_REALLY_POSTMILTER))) && 528c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 529c2aa98e2SPeter Wemm { 53040266059SGregory Neil Shapiro bool msync; 53140266059SGregory Neil Shapiro 53242e5d165SGregory Neil Shapiro /* 53342e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue. 53442e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes. 53542e5d165SGregory Neil Shapiro ** If the original were done first, we may lose 53642e5d165SGregory Neil Shapiro ** recipients. 53742e5d165SGregory Neil Shapiro */ 53842e5d165SGregory Neil Shapiro 53940266059SGregory Neil Shapiro #if !HASFLOCK 54040266059SGregory Neil Shapiro msync = false; 541*5b0945b5SGregory Neil Shapiro #else 54240266059SGregory Neil Shapiro msync = mode == SM_FORK; 543*5b0945b5SGregory Neil Shapiro #endif 54440266059SGregory Neil Shapiro 545c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 54640266059SGregory Neil Shapiro queueup(ee, WILL_BE_QUEUED(mode), msync); 54740266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), msync); 548c2aa98e2SPeter Wemm } 549c2aa98e2SPeter Wemm 550c2aa98e2SPeter Wemm if (tTd(62, 10)) 551c2aa98e2SPeter Wemm checkfds("after envelope splitting"); 552c2aa98e2SPeter Wemm 553c2aa98e2SPeter Wemm /* 554c2aa98e2SPeter Wemm ** If we belong in background, fork now. 555c2aa98e2SPeter Wemm */ 556c2aa98e2SPeter Wemm 557c2aa98e2SPeter Wemm if (tTd(13, 20)) 558c2aa98e2SPeter Wemm { 55940266059SGregory Neil Shapiro sm_dprintf("sendall: final mode = %c\n", mode); 560c2aa98e2SPeter Wemm if (tTd(13, 21)) 561c2aa98e2SPeter Wemm { 56240266059SGregory Neil Shapiro sm_dprintf("\n================ Final Send Queue(s) =====================\n"); 56340266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 564c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr); 565e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 566c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 567c2aa98e2SPeter Wemm { 56840266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 569c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr); 570e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ee->e_sendqueue, true); 571c2aa98e2SPeter Wemm } 57240266059SGregory Neil Shapiro sm_dprintf("==========================================================\n\n"); 573c2aa98e2SPeter Wemm } 574c2aa98e2SPeter Wemm } 575c2aa98e2SPeter Wemm switch (mode) 576c2aa98e2SPeter Wemm { 577c2aa98e2SPeter Wemm case SM_VERIFY: 578c2aa98e2SPeter Wemm Verbose = 2; 579c2aa98e2SPeter Wemm break; 580c2aa98e2SPeter Wemm 581c2aa98e2SPeter Wemm case SM_QUEUE: 582c2aa98e2SPeter Wemm case SM_DEFER: 583c2aa98e2SPeter Wemm #if HASFLOCK 584c2aa98e2SPeter Wemm queueonly: 585*5b0945b5SGregory Neil Shapiro #endif 586c2aa98e2SPeter Wemm if (e->e_nrcpts > 0) 587c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 5889bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, true); 589c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 590c2aa98e2SPeter Wemm { 591c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0) 592c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 5939bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, true); 594c2aa98e2SPeter Wemm } 595c2aa98e2SPeter Wemm return; 596c2aa98e2SPeter Wemm 597c2aa98e2SPeter Wemm case SM_FORK: 598c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 59940266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 600c2aa98e2SPeter Wemm 601c2aa98e2SPeter Wemm #if !HASFLOCK 602c2aa98e2SPeter Wemm /* 603c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that 604c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file 605c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and 606c2aa98e2SPeter Wemm ** then restart from scratch in the child. 607c2aa98e2SPeter Wemm */ 608c2aa98e2SPeter Wemm 609c2aa98e2SPeter Wemm { 610c2aa98e2SPeter Wemm /* save id for future use */ 611c2aa98e2SPeter Wemm char *qid = e->e_id; 612c2aa98e2SPeter Wemm 613c2aa98e2SPeter Wemm /* now drop the envelope in the parent */ 614c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 6159bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, false); 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */ 618c2aa98e2SPeter Wemm e->e_id = qid; 619c2aa98e2SPeter Wemm } 620c2aa98e2SPeter Wemm 621c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 622c2aa98e2SPeter Wemm { 623c2aa98e2SPeter Wemm /* save id for future use */ 624c2aa98e2SPeter Wemm char *qid = ee->e_id; 625c2aa98e2SPeter Wemm 626c2aa98e2SPeter Wemm /* drop envelope in parent */ 627c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 6289bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, false); 629c2aa98e2SPeter Wemm 630c2aa98e2SPeter Wemm /* and save qid for reacquisition */ 631c2aa98e2SPeter Wemm ee->e_id = qid; 632c2aa98e2SPeter Wemm } 633e92d3f3fSGregory Neil Shapiro 634c2aa98e2SPeter Wemm #endif /* !HASFLOCK */ 635c2aa98e2SPeter Wemm 63606f25ae9SGregory Neil Shapiro /* 63706f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent 63806f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby 63906f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore, 64006f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open 64106f25ae9SGregory Neil Shapiro ** them if necessary. 64206f25ae9SGregory Neil Shapiro */ 64306f25ae9SGregory Neil Shapiro 64440266059SGregory Neil Shapiro closemaps(false); 64506f25ae9SGregory Neil Shapiro 646c2aa98e2SPeter Wemm pid = fork(); 647c2aa98e2SPeter Wemm if (pid < 0) 648c2aa98e2SPeter Wemm { 64906f25ae9SGregory Neil Shapiro syserr("deliver: fork 1"); 650c2aa98e2SPeter Wemm #if HASFLOCK 651c2aa98e2SPeter Wemm goto queueonly; 65206f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 653c2aa98e2SPeter Wemm e->e_id = NULL; 654c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 655c2aa98e2SPeter Wemm ee->e_id = NULL; 656c2aa98e2SPeter Wemm return; 657c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 658c2aa98e2SPeter Wemm } 659c2aa98e2SPeter Wemm else if (pid > 0) 660c2aa98e2SPeter Wemm { 661c2aa98e2SPeter Wemm #if HASFLOCK 662c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */ 663c2aa98e2SPeter Wemm /* close any random open files in the envelope */ 664c2aa98e2SPeter Wemm closexscript(e); 665c2aa98e2SPeter Wemm if (e->e_dfp != NULL) 66640266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 667c2aa98e2SPeter Wemm e->e_dfp = NULL; 668c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF; 669c2aa98e2SPeter Wemm 670c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */ 671c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 67240266059SGregory Neil Shapiro (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 67306f25ae9SGregory Neil Shapiro else 67406f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id); 675c2aa98e2SPeter Wemm e->e_lockfp = NULL; 67606f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 677c2aa98e2SPeter Wemm 678c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */ 679c2aa98e2SPeter Wemm e->e_id = NULL; 680c2aa98e2SPeter Wemm 68140266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 682c2aa98e2SPeter Wemm /* catch intermediate zombie */ 683c2aa98e2SPeter Wemm (void) waitfor(pid); 684*5b0945b5SGregory Neil Shapiro #endif 685c2aa98e2SPeter Wemm return; 686c2aa98e2SPeter Wemm } 687c2aa98e2SPeter Wemm 6888774250cSGregory Neil Shapiro /* Reset global flags */ 6898774250cSGregory Neil Shapiro RestartRequest = NULL; 69040266059SGregory Neil Shapiro RestartWorkGroup = false; 6918774250cSGregory Neil Shapiro ShutdownRequest = NULL; 6928774250cSGregory Neil Shapiro PendingSignal = 0; 6938774250cSGregory Neil Shapiro 69442e5d165SGregory Neil Shapiro /* 69540266059SGregory Neil Shapiro ** Initialize exception stack and default exception 69640266059SGregory Neil Shapiro ** handler for child process. 69740266059SGregory Neil Shapiro */ 69840266059SGregory Neil Shapiro 69940266059SGregory Neil Shapiro sm_exc_newthread(fatal_error); 70040266059SGregory Neil Shapiro 70140266059SGregory Neil Shapiro /* 70242e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message, 70342e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler) 70442e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line 70542e5d165SGregory Neil Shapiro ** message submission. 70642e5d165SGregory Neil Shapiro */ 70742e5d165SGregory Neil Shapiro 70840266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 70942e5d165SGregory Neil Shapiro 71040266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 711c2aa98e2SPeter Wemm /* double fork to avoid zombies */ 712c2aa98e2SPeter Wemm pid = fork(); 713c2aa98e2SPeter Wemm if (pid > 0) 714c2aa98e2SPeter Wemm exit(EX_OK); 71506f25ae9SGregory Neil Shapiro save_errno = errno; 71640266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 71740266059SGregory Neil Shapiro 71840266059SGregory Neil Shapiro CurrentPid = getpid(); 719c2aa98e2SPeter Wemm 720c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */ 721c2aa98e2SPeter Wemm disconnect(2, e); 72206f25ae9SGregory Neil Shapiro clearstats(); 723c2aa98e2SPeter Wemm 724c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */ 725c2aa98e2SPeter Wemm if (pid < 0) 726c2aa98e2SPeter Wemm { 72706f25ae9SGregory Neil Shapiro errno = save_errno; 72806f25ae9SGregory Neil Shapiro syserr("deliver: fork 2"); 729c2aa98e2SPeter Wemm #if HASFLOCK 730c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 731*5b0945b5SGregory Neil Shapiro #else 732c2aa98e2SPeter Wemm e->e_id = NULL; 733*5b0945b5SGregory Neil Shapiro #endif 73440266059SGregory Neil Shapiro finis(true, true, ExitStat); 735c2aa98e2SPeter Wemm } 736c2aa98e2SPeter Wemm 737c2aa98e2SPeter Wemm /* be sure to give error messages in child */ 73840266059SGregory Neil Shapiro QuickAbort = false; 739c2aa98e2SPeter Wemm 740c2aa98e2SPeter Wemm /* 741c2aa98e2SPeter Wemm ** Close any cached connections. 742c2aa98e2SPeter Wemm ** 743c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent 744c2aa98e2SPeter Wemm ** still knows about the connection. 745c2aa98e2SPeter Wemm ** 746c2aa98e2SPeter Wemm ** This should only happen when delivering an error 747c2aa98e2SPeter Wemm ** message. 748c2aa98e2SPeter Wemm */ 749c2aa98e2SPeter Wemm 75040266059SGregory Neil Shapiro mci_flush(false, NULL); 751c2aa98e2SPeter Wemm 752c2aa98e2SPeter Wemm #if HASFLOCK 753c2aa98e2SPeter Wemm break; 75406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 755c2aa98e2SPeter Wemm 756c2aa98e2SPeter Wemm /* 757c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files. 758c2aa98e2SPeter Wemm */ 759c2aa98e2SPeter Wemm 760c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 761c2aa98e2SPeter Wemm { 762c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling; 763c2aa98e2SPeter Wemm 76440266059SGregory Neil Shapiro (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id, 76540266059SGregory Neil Shapiro false, false, ee); 766c2aa98e2SPeter Wemm ee->e_sibling = sibling; 767c2aa98e2SPeter Wemm } 76840266059SGregory Neil Shapiro (void) dowork(e->e_qgrp, e->e_qdir, e->e_id, 76940266059SGregory Neil Shapiro false, false, e); 77040266059SGregory Neil Shapiro finis(true, true, ExitStat); 77106f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 772c2aa98e2SPeter Wemm } 773c2aa98e2SPeter Wemm 774c2aa98e2SPeter Wemm sendenvelope(e, mode); 7759bd497b8SGregory Neil Shapiro (void) dropenvelope(e, true, true); 776c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 777c2aa98e2SPeter Wemm { 778c2aa98e2SPeter Wemm CurEnv = ee; 779c2aa98e2SPeter Wemm if (mode != SM_VERIFY) 780c2aa98e2SPeter Wemm openxscript(ee); 781c2aa98e2SPeter Wemm sendenvelope(ee, mode); 7829bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, true, true); 783c2aa98e2SPeter Wemm } 784c2aa98e2SPeter Wemm CurEnv = e; 785c2aa98e2SPeter Wemm 786c2aa98e2SPeter Wemm Verbose = oldverbose; 787c2aa98e2SPeter Wemm if (mode == SM_FORK) 78840266059SGregory Neil Shapiro finis(true, true, ExitStat); 789c2aa98e2SPeter Wemm } 790c2aa98e2SPeter Wemm 79106f25ae9SGregory Neil Shapiro static void 792c2aa98e2SPeter Wemm sendenvelope(e, mode) 793c2aa98e2SPeter Wemm register ENVELOPE *e; 794c2aa98e2SPeter Wemm int mode; 795c2aa98e2SPeter Wemm { 796c2aa98e2SPeter Wemm register ADDRESS *q; 797c2aa98e2SPeter Wemm bool didany; 798c2aa98e2SPeter Wemm 799c2aa98e2SPeter Wemm if (tTd(13, 10)) 80040266059SGregory Neil Shapiro sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n", 801c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 802c2aa98e2SPeter Wemm e->e_flags); 803c2aa98e2SPeter Wemm if (LogLevel > 80) 804c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id, 80506f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx", 806c2aa98e2SPeter Wemm e->e_flags); 807c2aa98e2SPeter Wemm 808c2aa98e2SPeter Wemm /* 809c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 810c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 811c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 812c2aa98e2SPeter Wemm ** addresses to be sent. 813c2aa98e2SPeter Wemm */ 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 816c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 817c2aa98e2SPeter Wemm { 818c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 819c2aa98e2SPeter Wemm return; 820c2aa98e2SPeter Wemm } 821c2aa98e2SPeter Wemm 82240266059SGregory Neil Shapiro /* 82340266059SGregory Neil Shapiro ** Don't attempt deliveries if we want to bounce now 82440266059SGregory Neil Shapiro ** or if deliver-by time is exceeded. 82540266059SGregory Neil Shapiro */ 82640266059SGregory Neil Shapiro 82706f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) && 82840266059SGregory Neil Shapiro (TimeOuts.to_q_return[e->e_timeoutclass] == NOW || 82940266059SGregory Neil Shapiro (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 && 83040266059SGregory Neil Shapiro curtime() > e->e_ctime + e->e_deliver_by))) 83106f25ae9SGregory Neil Shapiro return; 83206f25ae9SGregory Neil Shapiro 833c2aa98e2SPeter Wemm /* 834c2aa98e2SPeter Wemm ** Run through the list and send everything. 835c2aa98e2SPeter Wemm ** 836c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery 837c2aa98e2SPeter Wemm ** result in returned mail. 838c2aa98e2SPeter Wemm */ 839c2aa98e2SPeter Wemm 840c2aa98e2SPeter Wemm e->e_nsent = 0; 841c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS; 84206f25ae9SGregory Neil Shapiro 84340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid); 84440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype); 84540266059SGregory Neil Shapiro didany = false; 84640266059SGregory Neil Shapiro 84740266059SGregory Neil Shapiro if (!bitset(EF_SPLIT, e->e_flags)) 84840266059SGregory Neil Shapiro { 84940266059SGregory Neil Shapiro ENVELOPE *oldsib; 85040266059SGregory Neil Shapiro ENVELOPE *ee; 85140266059SGregory Neil Shapiro 85240266059SGregory Neil Shapiro /* 85340266059SGregory Neil Shapiro ** Save old sibling and set it to NULL to avoid 85440266059SGregory Neil Shapiro ** queueing up the same envelopes again. 85540266059SGregory Neil Shapiro ** This requires that envelopes in that list have 85640266059SGregory Neil Shapiro ** been take care of before (or at some other place). 85740266059SGregory Neil Shapiro */ 85840266059SGregory Neil Shapiro 85940266059SGregory Neil Shapiro oldsib = e->e_sibling; 86040266059SGregory Neil Shapiro e->e_sibling = NULL; 86140266059SGregory Neil Shapiro if (!split_by_recipient(e) && 86240266059SGregory Neil Shapiro bitset(EF_FATALERRS, e->e_flags)) 86340266059SGregory Neil Shapiro { 86440266059SGregory Neil Shapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 86540266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE; 86640266059SGregory Neil Shapiro return; 86740266059SGregory Neil Shapiro } 86840266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86940266059SGregory Neil Shapiro queueup(ee, false, true); 87040266059SGregory Neil Shapiro 87140266059SGregory Neil Shapiro /* clean up */ 87240266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 87340266059SGregory Neil Shapiro { 87440266059SGregory Neil Shapiro /* now unlock the job */ 87540266059SGregory Neil Shapiro closexscript(ee); 87640266059SGregory Neil Shapiro unlockqueue(ee); 87740266059SGregory Neil Shapiro 87840266059SGregory Neil Shapiro /* this envelope is marked unused */ 87940266059SGregory Neil Shapiro if (ee->e_dfp != NULL) 88040266059SGregory Neil Shapiro { 88140266059SGregory Neil Shapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 88240266059SGregory Neil Shapiro ee->e_dfp = NULL; 88340266059SGregory Neil Shapiro } 88440266059SGregory Neil Shapiro ee->e_id = NULL; 88540266059SGregory Neil Shapiro ee->e_flags &= ~EF_HAS_DF; 88640266059SGregory Neil Shapiro } 88740266059SGregory Neil Shapiro e->e_sibling = oldsib; 88840266059SGregory Neil Shapiro } 889c2aa98e2SPeter Wemm 890c2aa98e2SPeter Wemm /* now run through the queue */ 891c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 892c2aa98e2SPeter Wemm { 893c2aa98e2SPeter Wemm #if XDEBUG 894c2aa98e2SPeter Wemm char wbuf[MAXNAME + 20]; 895c2aa98e2SPeter Wemm 896d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "sendall(%.*s)", 897c2aa98e2SPeter Wemm MAXNAME, q->q_paddr); 898c2aa98e2SPeter Wemm checkfd012(wbuf); 89906f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 900c2aa98e2SPeter Wemm if (mode == SM_VERIFY) 901c2aa98e2SPeter Wemm { 902c2aa98e2SPeter Wemm e->e_to = q->q_paddr; 90306f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state)) 904c2aa98e2SPeter Wemm { 905c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0') 906c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s", 907c2aa98e2SPeter Wemm q->q_mailer->m_name, 908c2aa98e2SPeter Wemm q->q_host, 909c2aa98e2SPeter Wemm q->q_user); 910c2aa98e2SPeter Wemm else 911c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s", 912c2aa98e2SPeter Wemm q->q_mailer->m_name, 913c2aa98e2SPeter Wemm q->q_user); 914c2aa98e2SPeter Wemm } 915c2aa98e2SPeter Wemm } 91606f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state)) 917c2aa98e2SPeter Wemm { 918c2aa98e2SPeter Wemm /* 919c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses 920c2aa98e2SPeter Wemm */ 921c2aa98e2SPeter Wemm 92242e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && 92342e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval) 924c2aa98e2SPeter Wemm { 92540266059SGregory Neil Shapiro queueup(e, false, false); 926c2aa98e2SPeter Wemm e->e_nsent = 0; 927c2aa98e2SPeter Wemm } 928c2aa98e2SPeter Wemm (void) deliver(e, q); 92940266059SGregory Neil Shapiro didany = true; 930c2aa98e2SPeter Wemm } 931c2aa98e2SPeter Wemm } 932c2aa98e2SPeter Wemm if (didany) 933c2aa98e2SPeter Wemm { 934c2aa98e2SPeter Wemm e->e_dtime = curtime(); 935c2aa98e2SPeter Wemm e->e_ntries++; 936c2aa98e2SPeter Wemm } 937c2aa98e2SPeter Wemm 938c2aa98e2SPeter Wemm #if XDEBUG 939c2aa98e2SPeter Wemm checkfd012("end of sendenvelope"); 940*5b0945b5SGregory Neil Shapiro #endif 941c2aa98e2SPeter Wemm } 94240266059SGregory Neil Shapiro 94340266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC 94440266059SGregory Neil Shapiro /* 94540266059SGregory Neil Shapiro ** SYNC_DIR -- fsync a directory based on a filename 94640266059SGregory Neil Shapiro ** 94740266059SGregory Neil Shapiro ** Parameters: 94840266059SGregory Neil Shapiro ** filename -- path of file 94940266059SGregory Neil Shapiro ** panic -- panic? 95040266059SGregory Neil Shapiro ** 95140266059SGregory Neil Shapiro ** Returns: 95240266059SGregory Neil Shapiro ** none 95340266059SGregory Neil Shapiro */ 95440266059SGregory Neil Shapiro 95540266059SGregory Neil Shapiro void 95640266059SGregory Neil Shapiro sync_dir(filename, panic) 95740266059SGregory Neil Shapiro char *filename; 95840266059SGregory Neil Shapiro bool panic; 95940266059SGregory Neil Shapiro { 96040266059SGregory Neil Shapiro int dirfd; 96140266059SGregory Neil Shapiro char *dirp; 96240266059SGregory Neil Shapiro char dir[MAXPATHLEN]; 96340266059SGregory Neil Shapiro 96413bd1963SGregory Neil Shapiro if (!RequiresDirfsync) 96513bd1963SGregory Neil Shapiro return; 96613bd1963SGregory Neil Shapiro 96740266059SGregory Neil Shapiro /* filesystems which require the directory be synced */ 96840266059SGregory Neil Shapiro dirp = strrchr(filename, '/'); 96940266059SGregory Neil Shapiro if (dirp != NULL) 97040266059SGregory Neil Shapiro { 971d0cef73dSGregory Neil Shapiro if (sm_strlcpy(dir, filename, sizeof(dir)) >= sizeof(dir)) 97240266059SGregory Neil Shapiro return; 97340266059SGregory Neil Shapiro dir[dirp - filename] = '\0'; 97440266059SGregory Neil Shapiro dirp = dir; 97540266059SGregory Neil Shapiro } 97640266059SGregory Neil Shapiro else 97740266059SGregory Neil Shapiro dirp = "."; 97840266059SGregory Neil Shapiro dirfd = open(dirp, O_RDONLY, 0700); 97940266059SGregory Neil Shapiro if (tTd(40,32)) 98040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)", 98140266059SGregory Neil Shapiro dirp, dirfd); 98240266059SGregory Neil Shapiro if (dirfd >= 0) 98340266059SGregory Neil Shapiro { 98440266059SGregory Neil Shapiro if (fsync(dirfd) < 0) 98540266059SGregory Neil Shapiro { 98640266059SGregory Neil Shapiro if (panic) 98740266059SGregory Neil Shapiro syserr("!sync_dir: cannot fsync directory %s", 98840266059SGregory Neil Shapiro dirp); 98940266059SGregory Neil Shapiro else if (LogLevel > 1) 99040266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 99140266059SGregory Neil Shapiro "sync_dir: cannot fsync directory %s: %s", 99240266059SGregory Neil Shapiro dirp, sm_errstring(errno)); 99340266059SGregory Neil Shapiro } 99440266059SGregory Neil Shapiro (void) close(dirfd); 99540266059SGregory Neil Shapiro } 99640266059SGregory Neil Shapiro } 99740266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */ 99840266059SGregory Neil Shapiro /* 999c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 1000c2aa98e2SPeter Wemm ** 1001c2aa98e2SPeter Wemm ** Parameters: 1002c2aa98e2SPeter Wemm ** e -- the existing envelope 1003c2aa98e2SPeter Wemm ** ee -- the new envelope 100440266059SGregory Neil Shapiro ** type -- the queue file type (e.g., DATAFL_LETTER) 1005c2aa98e2SPeter Wemm ** 1006c2aa98e2SPeter Wemm ** Returns: 1007c2aa98e2SPeter Wemm ** none 1008c2aa98e2SPeter Wemm */ 1009c2aa98e2SPeter Wemm 101006f25ae9SGregory Neil Shapiro static void 1011c2aa98e2SPeter Wemm dup_queue_file(e, ee, type) 101240266059SGregory Neil Shapiro ENVELOPE *e, *ee; 1013c2aa98e2SPeter Wemm int type; 1014c2aa98e2SPeter Wemm { 101506f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 1016c2aa98e2SPeter Wemm 1017c2aa98e2SPeter Wemm ee->e_dfp = NULL; 1018c2aa98e2SPeter Wemm ee->e_xfp = NULL; 101906f25ae9SGregory Neil Shapiro 102006f25ae9SGregory Neil Shapiro /* 102106f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory. 102206f25ae9SGregory Neil Shapiro */ 102306f25ae9SGregory Neil Shapiro 1024d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f1buf, queuename(e, type), sizeof(f1buf)); 1025d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof(f2buf)); 1026959366dcSGregory Neil Shapiro 1027959366dcSGregory Neil Shapiro /* Force the df to disk if it's not there yet */ 1028959366dcSGregory Neil Shapiro if (type == DATAFL_LETTER && e->e_dfp != NULL && 1029959366dcSGregory Neil Shapiro sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 1030959366dcSGregory Neil Shapiro errno != EINVAL) 1031959366dcSGregory Neil Shapiro { 1032959366dcSGregory Neil Shapiro syserr("!dup_queue_file: can't commit %s", f1buf); 1033959366dcSGregory Neil Shapiro /* NOTREACHED */ 1034959366dcSGregory Neil Shapiro } 1035959366dcSGregory Neil Shapiro 1036c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1037c2aa98e2SPeter Wemm { 103806f25ae9SGregory Neil Shapiro int save_errno = errno; 1039c2aa98e2SPeter Wemm 1040c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf); 104106f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 1042c2aa98e2SPeter Wemm { 1043c2aa98e2SPeter Wemm if (unlink(f2buf) < 0) 1044c2aa98e2SPeter Wemm { 1045c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent", 1046c2aa98e2SPeter Wemm f2buf); 1047c2aa98e2SPeter Wemm /* NOTREACHED */ 1048c2aa98e2SPeter Wemm } 1049c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1050c2aa98e2SPeter Wemm { 1051c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent", 1052c2aa98e2SPeter Wemm f1buf, f2buf); 1053c2aa98e2SPeter Wemm /* NOTREACHED */ 1054c2aa98e2SPeter Wemm } 1055c2aa98e2SPeter Wemm } 1056c2aa98e2SPeter Wemm } 105740266059SGregory Neil Shapiro SYNC_DIR(f2buf, true); 1058c2aa98e2SPeter Wemm } 105940266059SGregory Neil Shapiro /* 1060c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure. 1061c2aa98e2SPeter Wemm ** 1062c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running 1063c2aa98e2SPeter Wemm ** two processes on the same stack!!! 1064c2aa98e2SPeter Wemm ** 1065c2aa98e2SPeter Wemm ** Parameters: 1066c2aa98e2SPeter Wemm ** none. 1067c2aa98e2SPeter Wemm ** 1068c2aa98e2SPeter Wemm ** Returns: 1069c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding! 1070c2aa98e2SPeter Wemm ** 1071c2aa98e2SPeter Wemm ** Side Effects: 1072c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving: 1073c2aa98e2SPeter Wemm ** pid of child in parent, zero in child. 1074c2aa98e2SPeter Wemm ** -1 on unrecoverable error. 1075c2aa98e2SPeter Wemm ** 1076c2aa98e2SPeter Wemm ** Notes: 1077c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's 1078c2aa98e2SPeter Wemm ** vfork for you..... 1079c2aa98e2SPeter Wemm */ 1080c2aa98e2SPeter Wemm 1081c2aa98e2SPeter Wemm #define NFORKTRIES 5 1082c2aa98e2SPeter Wemm 1083c2aa98e2SPeter Wemm #ifndef FORK 1084c2aa98e2SPeter Wemm # define FORK fork 1085*5b0945b5SGregory Neil Shapiro #endif 1086c2aa98e2SPeter Wemm 1087c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \ 1088c2aa98e2SPeter Wemm {\ 1089c2aa98e2SPeter Wemm register int i;\ 1090c2aa98e2SPeter Wemm \ 1091c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\ 1092c2aa98e2SPeter Wemm {\ 1093c2aa98e2SPeter Wemm pid = fORKfN();\ 1094c2aa98e2SPeter Wemm if (pid >= 0)\ 1095c2aa98e2SPeter Wemm break;\ 1096c2aa98e2SPeter Wemm if (i > 0)\ 109706f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\ 1098c2aa98e2SPeter Wemm }\ 1099c2aa98e2SPeter Wemm } 110040266059SGregory Neil Shapiro /* 1101c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK. 1102c2aa98e2SPeter Wemm ** 1103c2aa98e2SPeter Wemm ** Parameters: 1104c2aa98e2SPeter Wemm ** none. 1105c2aa98e2SPeter Wemm ** 1106c2aa98e2SPeter Wemm ** Returns: 1107c2aa98e2SPeter Wemm ** pid of child in parent. 1108c2aa98e2SPeter Wemm ** zero in child. 1109c2aa98e2SPeter Wemm ** -1 on error. 1110c2aa98e2SPeter Wemm ** 1111c2aa98e2SPeter Wemm ** Side Effects: 1112c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child. 1113c2aa98e2SPeter Wemm */ 1114c2aa98e2SPeter Wemm 11158774250cSGregory Neil Shapiro pid_t 1116c2aa98e2SPeter Wemm dofork() 1117c2aa98e2SPeter Wemm { 1118c2aa98e2SPeter Wemm register pid_t pid = -1; 1119c2aa98e2SPeter Wemm 1120c2aa98e2SPeter Wemm DOFORK(fork); 112106f25ae9SGregory Neil Shapiro return pid; 1122c2aa98e2SPeter Wemm } 112340266059SGregory Neil Shapiro 112440266059SGregory Neil Shapiro /* 112540266059SGregory Neil Shapiro ** COLONCMP -- compare host-signatures up to first ':' or EOS 112640266059SGregory Neil Shapiro ** 112740266059SGregory Neil Shapiro ** This takes two strings which happen to be host-signatures and 112840266059SGregory Neil Shapiro ** compares them. If the lowest preference portions of the MX-RR's 112940266059SGregory Neil Shapiro ** match (up to ':' or EOS, whichever is first), then we have 113040266059SGregory Neil Shapiro ** match. This is used for coattail-piggybacking messages during 113140266059SGregory Neil Shapiro ** message delivery. 113240266059SGregory Neil Shapiro ** If the signatures are the same up to the first ':' the remainder of 113340266059SGregory Neil Shapiro ** the signatures are then compared with a normal strcmp(). This saves 113440266059SGregory Neil Shapiro ** re-examining the first part of the signatures. 113540266059SGregory Neil Shapiro ** 113640266059SGregory Neil Shapiro ** Parameters: 113740266059SGregory Neil Shapiro ** a - first host-signature 113840266059SGregory Neil Shapiro ** b - second host-signature 113940266059SGregory Neil Shapiro ** 114040266059SGregory Neil Shapiro ** Returns: 114140266059SGregory Neil Shapiro ** HS_MATCH_NO -- no "match". 114240266059SGregory Neil Shapiro ** HS_MATCH_FIRST -- "match" for the first MX preference 114340266059SGregory Neil Shapiro ** (up to the first colon (':')). 114440266059SGregory Neil Shapiro ** HS_MATCH_FULL -- match for the entire MX record. 114540266059SGregory Neil Shapiro ** 114640266059SGregory Neil Shapiro ** Side Effects: 114740266059SGregory Neil Shapiro ** none. 114840266059SGregory Neil Shapiro */ 114940266059SGregory Neil Shapiro 115040266059SGregory Neil Shapiro #define HS_MATCH_NO 0 115140266059SGregory Neil Shapiro #define HS_MATCH_FIRST 1 115240266059SGregory Neil Shapiro #define HS_MATCH_FULL 2 115340266059SGregory Neil Shapiro 115440266059SGregory Neil Shapiro static int 115540266059SGregory Neil Shapiro coloncmp(a, b) 115640266059SGregory Neil Shapiro register const char *a; 115740266059SGregory Neil Shapiro register const char *b; 115840266059SGregory Neil Shapiro { 115940266059SGregory Neil Shapiro int ret = HS_MATCH_NO; 116040266059SGregory Neil Shapiro int braclev = 0; 116140266059SGregory Neil Shapiro 116240266059SGregory Neil Shapiro while (*a == *b++) 116340266059SGregory Neil Shapiro { 116440266059SGregory Neil Shapiro /* Need to account for IPv6 bracketed addresses */ 116540266059SGregory Neil Shapiro if (*a == '[') 116640266059SGregory Neil Shapiro braclev++; 11675ef517c0SGregory Neil Shapiro else if (*a == ']' && braclev > 0) 116840266059SGregory Neil Shapiro braclev--; 116940266059SGregory Neil Shapiro else if (*a == ':' && braclev <= 0) 117040266059SGregory Neil Shapiro { 117140266059SGregory Neil Shapiro ret = HS_MATCH_FIRST; 117240266059SGregory Neil Shapiro a++; 117340266059SGregory Neil Shapiro break; 117440266059SGregory Neil Shapiro } 117540266059SGregory Neil Shapiro else if (*a == '\0') 117640266059SGregory Neil Shapiro return HS_MATCH_FULL; /* a full match */ 117740266059SGregory Neil Shapiro a++; 117840266059SGregory Neil Shapiro } 117940266059SGregory Neil Shapiro if (ret == HS_MATCH_NO && 118040266059SGregory Neil Shapiro braclev <= 0 && 118140266059SGregory Neil Shapiro ((*a == '\0' && *(b - 1) == ':') || 118240266059SGregory Neil Shapiro (*a == ':' && *(b - 1) == '\0'))) 118340266059SGregory Neil Shapiro return HS_MATCH_FIRST; 118440266059SGregory Neil Shapiro if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0) 118540266059SGregory Neil Shapiro return HS_MATCH_FULL; 118640266059SGregory Neil Shapiro 118740266059SGregory Neil Shapiro return ret; 118840266059SGregory Neil Shapiro } 1189e92d3f3fSGregory Neil Shapiro 1190e92d3f3fSGregory Neil Shapiro /* 1191e92d3f3fSGregory Neil Shapiro ** SHOULD_TRY_FBSH -- Should try FallbackSmartHost? 1192e92d3f3fSGregory Neil Shapiro ** 1193e92d3f3fSGregory Neil Shapiro ** Parameters: 1194e92d3f3fSGregory Neil Shapiro ** e -- envelope 1195e92d3f3fSGregory Neil Shapiro ** tried_fallbacksmarthost -- has been tried already? (in/out) 1196e92d3f3fSGregory Neil Shapiro ** hostbuf -- buffer for hostname (expand FallbackSmartHost) (out) 1197e92d3f3fSGregory Neil Shapiro ** hbsz -- size of hostbuf 1198e92d3f3fSGregory Neil Shapiro ** status -- current delivery status 1199e92d3f3fSGregory Neil Shapiro ** 1200e92d3f3fSGregory Neil Shapiro ** Returns: 1201e92d3f3fSGregory Neil Shapiro ** true iff FallbackSmartHost should be tried. 1202e92d3f3fSGregory Neil Shapiro */ 1203e92d3f3fSGregory Neil Shapiro 1204d0cef73dSGregory Neil Shapiro static bool should_try_fbsh __P((ENVELOPE *, bool *, char *, size_t, int)); 1205d0cef73dSGregory Neil Shapiro 1206e92d3f3fSGregory Neil Shapiro static bool 1207e92d3f3fSGregory Neil Shapiro should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status) 1208e92d3f3fSGregory Neil Shapiro ENVELOPE *e; 1209e92d3f3fSGregory Neil Shapiro bool *tried_fallbacksmarthost; 1210e92d3f3fSGregory Neil Shapiro char *hostbuf; 1211e92d3f3fSGregory Neil Shapiro size_t hbsz; 1212e92d3f3fSGregory Neil Shapiro int status; 1213e92d3f3fSGregory Neil Shapiro { 1214e92d3f3fSGregory Neil Shapiro /* 12154e4196cbSGregory Neil Shapiro ** If the host was not found or a temporary failure occurred 12164e4196cbSGregory Neil Shapiro ** and a FallbackSmartHost is defined (and we have not yet 12174e4196cbSGregory Neil Shapiro ** tried it), then make one last try with it as the host. 1218e92d3f3fSGregory Neil Shapiro */ 1219e92d3f3fSGregory Neil Shapiro 12204e4196cbSGregory Neil Shapiro if ((status == EX_NOHOST || status == EX_TEMPFAIL) && 12214e4196cbSGregory Neil Shapiro FallbackSmartHost != NULL && !*tried_fallbacksmarthost) 1222e92d3f3fSGregory Neil Shapiro { 1223e92d3f3fSGregory Neil Shapiro *tried_fallbacksmarthost = true; 1224e92d3f3fSGregory Neil Shapiro expand(FallbackSmartHost, hostbuf, hbsz, e); 1225e92d3f3fSGregory Neil Shapiro if (!wordinclass(hostbuf, 'w')) 1226e92d3f3fSGregory Neil Shapiro { 1227e92d3f3fSGregory Neil Shapiro if (tTd(11, 1)) 1228e92d3f3fSGregory Neil Shapiro sm_dprintf("one last try with FallbackSmartHost %s\n", 1229e92d3f3fSGregory Neil Shapiro hostbuf); 1230e92d3f3fSGregory Neil Shapiro return true; 1231e92d3f3fSGregory Neil Shapiro } 1232e92d3f3fSGregory Neil Shapiro } 1233e92d3f3fSGregory Neil Shapiro return false; 1234e92d3f3fSGregory Neil Shapiro } 1235da7d7b9cSGregory Neil Shapiro 123640266059SGregory Neil Shapiro /* 1237c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses. 1238c2aa98e2SPeter Wemm ** 1239c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the 1240c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers 1241c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed 1242c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so 1243*5b0945b5SGregory Neil Shapiro ** deliver should be called once for each address on the list. 124440266059SGregory Neil Shapiro ** Deliver tries to be as opportunistic as possible about piggybacking 124540266059SGregory Neil Shapiro ** messages. Some definitions to make understanding easier follow below. 124640266059SGregory Neil Shapiro ** Piggybacking occurs when an existing connection to a mail host can 124740266059SGregory Neil Shapiro ** be used to send the same message to more than one recipient at the 124840266059SGregory Neil Shapiro ** same time. So "no piggybacking" means one message for one recipient 124940266059SGregory Neil Shapiro ** per connection. "Intentional piggybacking" happens when the 125040266059SGregory Neil Shapiro ** recipients' host address (not the mail host address) is used to 125140266059SGregory Neil Shapiro ** attempt piggybacking. Recipients with the same host address 125240266059SGregory Neil Shapiro ** have the same mail host. "Coincidental piggybacking" relies on 125340266059SGregory Neil Shapiro ** piggybacking based on all the mail host addresses in the MX-RR. This 125440266059SGregory Neil Shapiro ** is "coincidental" in the fact it could not be predicted until the 125540266059SGregory Neil Shapiro ** MX Resource Records for the hosts were obtained and examined. For 125640266059SGregory Neil Shapiro ** example (preference order and equivalence is important, not values): 125740266059SGregory Neil Shapiro ** domain1 IN MX 10 mxhost-A 125840266059SGregory Neil Shapiro ** IN MX 20 mxhost-B 125940266059SGregory Neil Shapiro ** domain2 IN MX 4 mxhost-A 126040266059SGregory Neil Shapiro ** IN MX 8 mxhost-B 126140266059SGregory Neil Shapiro ** Domain1 and domain2 can piggyback the same message to mxhost-A or 126240266059SGregory Neil Shapiro ** mxhost-B (if mxhost-A cannot be reached). 126340266059SGregory Neil Shapiro ** "Coattail piggybacking" relaxes the strictness of "coincidental 126440266059SGregory Neil Shapiro ** piggybacking" in the hope that most significant (lowest value) 126540266059SGregory Neil Shapiro ** MX preference host(s) can create more piggybacking. For example 126640266059SGregory Neil Shapiro ** (again, preference order and equivalence is important, not values): 126740266059SGregory Neil Shapiro ** domain3 IN MX 100 mxhost-C 126840266059SGregory Neil Shapiro ** IN MX 100 mxhost-D 126940266059SGregory Neil Shapiro ** IN MX 200 mxhost-E 127040266059SGregory Neil Shapiro ** domain4 IN MX 50 mxhost-C 127140266059SGregory Neil Shapiro ** IN MX 50 mxhost-D 127240266059SGregory Neil Shapiro ** IN MX 80 mxhost-F 127340266059SGregory Neil Shapiro ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C 127440266059SGregory Neil Shapiro ** is available. Same with mxhost-D because in both RR's the preference 127540266059SGregory Neil Shapiro ** value is the same as mxhost-C, respectively. 127640266059SGregory Neil Shapiro ** So deliver attempts coattail piggybacking when possible. If the 127740266059SGregory Neil Shapiro ** first MX preference level hosts cannot be used then the piggybacking 127840266059SGregory Neil Shapiro ** reverts to coincidental piggybacking. Using the above example you 127940266059SGregory Neil Shapiro ** cannot deliver to mxhost-F for domain3 regardless of preference value. 128040266059SGregory Neil Shapiro ** ("Coattail" from "riding on the coattails of your predecessor" meaning 128140266059SGregory Neil Shapiro ** gaining benefit from a predecessor effort with no or little addition 128240266059SGregory Neil Shapiro ** effort. The predecessor here being the preceding MX RR). 1283c2aa98e2SPeter Wemm ** 1284c2aa98e2SPeter Wemm ** Parameters: 1285c2aa98e2SPeter Wemm ** e -- the envelope to deliver. 1286c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to. 1287c2aa98e2SPeter Wemm ** 1288c2aa98e2SPeter Wemm ** Returns: 1289c2aa98e2SPeter Wemm ** zero -- successfully delivered. 1290c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info. 1291c2aa98e2SPeter Wemm ** 1292c2aa98e2SPeter Wemm ** Side Effects: 1293c2aa98e2SPeter Wemm ** The standard input is passed off to someone. 1294c2aa98e2SPeter Wemm */ 1295c2aa98e2SPeter Wemm 129606f25ae9SGregory Neil Shapiro static int 1297c2aa98e2SPeter Wemm deliver(e, firstto) 1298c2aa98e2SPeter Wemm register ENVELOPE *e; 1299c2aa98e2SPeter Wemm ADDRESS *firstto; 1300c2aa98e2SPeter Wemm { 1301c2aa98e2SPeter Wemm char *host; /* host being sent to */ 1302c2aa98e2SPeter Wemm char *user; /* user being sent to */ 1303c2aa98e2SPeter Wemm char **pvp; 1304c2aa98e2SPeter Wemm register char **mvp; 1305c2aa98e2SPeter Wemm register char *p; 1306c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */ 1307c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr; 130840266059SGregory Neil Shapiro #if HASSETUSERCONTEXT 1309c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL; 1310*5b0945b5SGregory Neil Shapiro #endif 1311c2aa98e2SPeter Wemm register MCI *volatile mci; 131240266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE to = firstto; 131340266059SGregory Neil Shapiro volatile bool clever = false; /* running user smtp to this mailer */ 1314c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 1315c2aa98e2SPeter Wemm int rcode; /* response code */ 131640266059SGregory Neil Shapiro SM_NONVOLATILE int lmtp_rcode = EX_OK; 131740266059SGregory Neil Shapiro SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */ 131840266059SGregory Neil Shapiro SM_NONVOLATILE int hostnum = 0; /* current MX host index */ 1319c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */ 132040266059SGregory Neil Shapiro volatile pid_t pid = -1; 1321c2aa98e2SPeter Wemm char *volatile curhost; 132240266059SGregory Neil Shapiro SM_NONVOLATILE unsigned short port = 0; 132340266059SGregory Neil Shapiro SM_NONVOLATILE time_t enough = 0; 132406f25ae9SGregory Neil Shapiro #if NETUNIX 132540266059SGregory Neil Shapiro char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */ 1326*5b0945b5SGregory Neil Shapiro #endif 1327c2aa98e2SPeter Wemm time_t xstart; 1328c2aa98e2SPeter Wemm bool suidwarn; 1329c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */ 133040266059SGregory Neil Shapiro SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ 133106f25ae9SGregory Neil Shapiro bool ovr; 133240266059SGregory Neil Shapiro bool quarantine; 1333*5b0945b5SGregory Neil Shapiro #if STARTTLS 1334*5b0945b5SGregory Neil Shapiro /* 0: try TLS, 1: try without TLS again, >1: don't try again */ 1335*5b0945b5SGregory Neil Shapiro int tlsstate; 1336*5b0945b5SGregory Neil Shapiro # if DANE 1337*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx_T dane_vrfy_ctx; 1338*5b0945b5SGregory Neil Shapiro STAB *ste; 1339*5b0945b5SGregory Neil Shapiro # endif 1340*5b0945b5SGregory Neil Shapiro #endif 1341*5b0945b5SGregory Neil Shapiro #if STARTTLS || SASL 1342*5b0945b5SGregory Neil Shapiro int dotpos; 1343*5b0945b5SGregory Neil Shapiro 1344*5b0945b5SGregory Neil Shapiro # define RM_TRAIL_DOT(name) \ 1345*5b0945b5SGregory Neil Shapiro do { \ 1346*5b0945b5SGregory Neil Shapiro dotpos = strlen(name) - 1; \ 1347*5b0945b5SGregory Neil Shapiro if (dotpos >= 0) \ 1348*5b0945b5SGregory Neil Shapiro { \ 1349*5b0945b5SGregory Neil Shapiro if (name[dotpos] == '.') \ 1350*5b0945b5SGregory Neil Shapiro name[dotpos] = '\0'; \ 1351*5b0945b5SGregory Neil Shapiro else \ 1352*5b0945b5SGregory Neil Shapiro dotpos = -1; \ 1353*5b0945b5SGregory Neil Shapiro } \ 1354*5b0945b5SGregory Neil Shapiro } while (0) 1355*5b0945b5SGregory Neil Shapiro 1356*5b0945b5SGregory Neil Shapiro # define FIX_TRAIL_DOT(name) \ 1357*5b0945b5SGregory Neil Shapiro do { \ 1358*5b0945b5SGregory Neil Shapiro if (dotpos >= 0) \ 1359*5b0945b5SGregory Neil Shapiro name[dotpos] = '.'; \ 1360*5b0945b5SGregory Neil Shapiro } while (0) 1361*5b0945b5SGregory Neil Shapiro 1362*5b0945b5SGregory Neil Shapiro #endif 136306f25ae9SGregory Neil Shapiro int strsize; 136406f25ae9SGregory Neil Shapiro int rcptcount; 136540266059SGregory Neil Shapiro int ret; 136606f25ae9SGregory Neil Shapiro static int tobufsize = 0; 136706f25ae9SGregory Neil Shapiro static char *tobuf = NULL; 136840266059SGregory Neil Shapiro char *rpath; /* translated return path */ 1369c2aa98e2SPeter Wemm int mpvect[2]; 1370c2aa98e2SPeter Wemm int rpvect[2]; 137106f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1]; 1372c2aa98e2SPeter Wemm char *pv[MAXPV + 1]; 1373c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 137494c01205SGregory Neil Shapiro char cbuf[MAXPATHLEN]; 1375c2aa98e2SPeter Wemm 1376c2aa98e2SPeter Wemm errno = 0; 1377d0cef73dSGregory Neil Shapiro SM_REQUIRE(firstto != NULL); /* same as to */ 137806f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 137906f25ae9SGregory Neil Shapiro return 0; 1380c2aa98e2SPeter Wemm 1381c2aa98e2SPeter Wemm suidwarn = geteuid() == 0; 1382c2aa98e2SPeter Wemm 1383d0cef73dSGregory Neil Shapiro SM_REQUIRE(e != NULL); 1384c2aa98e2SPeter Wemm m = to->q_mailer; 1385c2aa98e2SPeter Wemm host = to->q_host; 1386c2aa98e2SPeter Wemm CurEnv = e; /* just in case */ 1387c2aa98e2SPeter Wemm e->e_statmsg = NULL; 1388c2aa98e2SPeter Wemm SmtpError[0] = '\0'; 1389c2aa98e2SPeter Wemm xstart = curtime(); 1390*5b0945b5SGregory Neil Shapiro #if STARTTLS 1391*5b0945b5SGregory Neil Shapiro tlsstate = 0; 1392*5b0945b5SGregory Neil Shapiro # if DANE 1393*5b0945b5SGregory Neil Shapiro memset(&dane_vrfy_ctx, '\0', sizeof(dane_vrfy_ctx)); 1394*5b0945b5SGregory Neil Shapiro ste = NULL; 1395*5b0945b5SGregory Neil Shapiro # endif 1396*5b0945b5SGregory Neil Shapiro #endif 1397c2aa98e2SPeter Wemm 1398c2aa98e2SPeter Wemm if (tTd(10, 1)) 139940266059SGregory Neil Shapiro sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 1400c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user); 1401c2aa98e2SPeter Wemm if (tTd(10, 100)) 140240266059SGregory Neil Shapiro printopenfds(false); 1403c2aa98e2SPeter Wemm 1404c2aa98e2SPeter Wemm /* 140540266059SGregory Neil Shapiro ** Clear {client_*} macros if this is a bounce message to 1406c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset. 1407c2aa98e2SPeter Wemm */ 1408c2aa98e2SPeter Wemm 1409c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1410c2aa98e2SPeter Wemm { 141140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); 1412e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), ""); 141340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); 141440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); 141540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); 1416c2aa98e2SPeter Wemm } 1417c2aa98e2SPeter Wemm 141840266059SGregory Neil Shapiro SM_TRY 141940266059SGregory Neil Shapiro { 142040266059SGregory Neil Shapiro ADDRESS *skip_back = NULL; 142140266059SGregory Neil Shapiro 1422c2aa98e2SPeter Wemm /* 1423c2aa98e2SPeter Wemm ** Do initial argv setup. 1424c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is 1425c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has 1426c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This 1427c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a 1428c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV. 1429c2aa98e2SPeter Wemm ** The from address rewrite is expected to make 1430c2aa98e2SPeter Wemm ** the address relative to the other end. 1431c2aa98e2SPeter Wemm */ 1432c2aa98e2SPeter Wemm 1433c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */ 1434c2aa98e2SPeter Wemm rcode = EX_OK; 1435d0cef73dSGregory Neil Shapiro SM_ASSERT(e->e_from.q_mailer != NULL); 1436c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 1437c2aa98e2SPeter Wemm p = e->e_sender; 1438c2aa98e2SPeter Wemm else 1439c2aa98e2SPeter Wemm p = e->e_from.q_paddr; 144040266059SGregory Neil Shapiro rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 1441da7d7b9cSGregory Neil Shapiro if (rcode != EX_OK && bitnset(M_xSMTP, m->m_flags)) 1442da7d7b9cSGregory Neil Shapiro goto cleanup; 14439bd497b8SGregory Neil Shapiro if (strlen(rpath) > MAXNAME) 1444c2aa98e2SPeter Wemm { 144540266059SGregory Neil Shapiro rpath = shortenstring(rpath, MAXSHORTSTR); 144640266059SGregory Neil Shapiro 144740266059SGregory Neil Shapiro /* avoid bogus errno */ 144840266059SGregory Neil Shapiro errno = 0; 144940266059SGregory Neil Shapiro syserr("remotename: huge return path %s", rpath); 1450c2aa98e2SPeter Wemm } 145140266059SGregory Neil Shapiro rpath = sm_rpool_strdup_x(e->e_rpool, rpath); 145240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', rpath); 145340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', host); 1454c2aa98e2SPeter Wemm Errors = 0; 1455c2aa98e2SPeter Wemm pvp = pv; 1456c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0]; 1457c2aa98e2SPeter Wemm 1458e92d3f3fSGregory Neil Shapiro /* ignore long term host status information if mailer flag W is set */ 1459e92d3f3fSGregory Neil Shapiro if (bitnset(M_NOHOSTSTAT, m->m_flags)) 1460e92d3f3fSGregory Neil Shapiro IgnoreHostStatus = true; 1461e92d3f3fSGregory Neil Shapiro 1462c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */ 146306f25ae9SGregory Neil Shapiro if (FromFlag && 146406f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) || 146506f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags))) 1466c2aa98e2SPeter Wemm { 1467c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags)) 1468c2aa98e2SPeter Wemm *pvp++ = "-f"; 1469c2aa98e2SPeter Wemm else 1470c2aa98e2SPeter Wemm *pvp++ = "-r"; 147140266059SGregory Neil Shapiro *pvp++ = rpath; 1472c2aa98e2SPeter Wemm } 1473c2aa98e2SPeter Wemm 1474c2aa98e2SPeter Wemm /* 1475c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run 1476c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only 1477c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots 1478c2aa98e2SPeter Wemm ** in the pv after it. 1479c2aa98e2SPeter Wemm */ 1480c2aa98e2SPeter Wemm 1481c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1482c2aa98e2SPeter Wemm { 1483c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */ 1484c2aa98e2SPeter Wemm while (*p != '\0') 1485c2aa98e2SPeter Wemm { 1486c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND) 1487c2aa98e2SPeter Wemm { 1488c2aa98e2SPeter Wemm if (*p == 'u') 1489c2aa98e2SPeter Wemm break; 1490c2aa98e2SPeter Wemm } 1491c2aa98e2SPeter Wemm } 1492c2aa98e2SPeter Wemm 1493c2aa98e2SPeter Wemm if (*p != '\0') 1494c2aa98e2SPeter Wemm break; 1495c2aa98e2SPeter Wemm 1496c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */ 1497d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 149840266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1499c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3]) 1500c2aa98e2SPeter Wemm { 150106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u", 150206f25ae9SGregory Neil Shapiro pv[0]); 150340266059SGregory Neil Shapiro rcode = -1; 150440266059SGregory Neil Shapiro goto cleanup; 1505c2aa98e2SPeter Wemm } 1506c2aa98e2SPeter Wemm } 1507c2aa98e2SPeter Wemm 1508c2aa98e2SPeter Wemm /* 1509c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument 1510c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and 1511c2aa98e2SPeter Wemm ** SMTP is the answer!! 1512c2aa98e2SPeter Wemm */ 1513c2aa98e2SPeter Wemm 1514c2aa98e2SPeter Wemm if (*mvp == NULL) 1515c2aa98e2SPeter Wemm { 1516602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */ 151740266059SGregory Neil Shapiro clever = true; 1518c2aa98e2SPeter Wemm *pvp = NULL; 1519da7d7b9cSGregory Neil Shapiro setbitn(M_xSMTP, m->m_flags); 1520c2aa98e2SPeter Wemm } 1521602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags)) 1522602a2b1bSGregory Neil Shapiro { 1523602a2b1bSGregory Neil Shapiro /* not running LMTP */ 1524602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL, 1525602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off", 1526602a2b1bSGregory Neil Shapiro m->m_name); 1527602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags); 1528602a2b1bSGregory Neil Shapiro } 1529c2aa98e2SPeter Wemm 1530c2aa98e2SPeter Wemm /* 1531c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We 1532c2aa98e2SPeter Wemm ** run through our address list and append all the addresses 1533c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can 1534c2aa98e2SPeter Wemm ** always send another copy later. 1535c2aa98e2SPeter Wemm */ 1536c2aa98e2SPeter Wemm 153706f25ae9SGregory Neil Shapiro e->e_to = NULL; 153806f25ae9SGregory Neil Shapiro strsize = 2; 153906f25ae9SGregory Neil Shapiro rcptcount = 0; 1540c2aa98e2SPeter Wemm ctladdr = NULL; 154140266059SGregory Neil Shapiro if (firstto->q_signature == NULL) 154240266059SGregory Neil Shapiro firstto->q_signature = hostsignature(firstto->q_mailer, 1543*5b0945b5SGregory Neil Shapiro firstto->q_host, 1544*5b0945b5SGregory Neil Shapiro firstto->q_flags & QSECURE); 154540266059SGregory Neil Shapiro firstsig = firstto->q_signature; 154640266059SGregory Neil Shapiro 1547c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next) 1548c2aa98e2SPeter Wemm { 1549c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */ 155006f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 155106f25ae9SGregory Neil Shapiro break; 1552c2aa98e2SPeter Wemm 1553c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */ 155440266059SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) /* already sent; look at next */ 1555c2aa98e2SPeter Wemm continue; 1556c2aa98e2SPeter Wemm 155740266059SGregory Neil Shapiro /* 155840266059SGregory Neil Shapiro ** Must be same mailer to keep grouping rcpts. 155940266059SGregory Neil Shapiro ** If mailers don't match: continue; sendqueue is not 156040266059SGregory Neil Shapiro ** sorted by mailers, so don't break; 156140266059SGregory Neil Shapiro */ 156240266059SGregory Neil Shapiro 156340266059SGregory Neil Shapiro if (to->q_mailer != firstto->q_mailer) 156440266059SGregory Neil Shapiro continue; 156540266059SGregory Neil Shapiro 156640266059SGregory Neil Shapiro if (to->q_signature == NULL) /* for safety */ 156740266059SGregory Neil Shapiro to->q_signature = hostsignature(to->q_mailer, 1568*5b0945b5SGregory Neil Shapiro to->q_host, 1569*5b0945b5SGregory Neil Shapiro to->q_flags & QSECURE); 157040266059SGregory Neil Shapiro 157140266059SGregory Neil Shapiro /* 157240266059SGregory Neil Shapiro ** This is for coincidental and tailcoat piggybacking messages 157340266059SGregory Neil Shapiro ** to the same mail host. While the signatures are identical 157440266059SGregory Neil Shapiro ** (that's the MX-RR's are identical) we can do coincidental 157540266059SGregory Neil Shapiro ** piggybacking. We try hard for coattail piggybacking 157640266059SGregory Neil Shapiro ** with the same mail host when the next recipient has the 157740266059SGregory Neil Shapiro ** same host at lowest preference. It may be that this 157840266059SGregory Neil Shapiro ** won't work out, so 'skip_back' is maintained if a backup 157940266059SGregory Neil Shapiro ** to coincidental piggybacking or full signature must happen. 158040266059SGregory Neil Shapiro */ 158140266059SGregory Neil Shapiro 158240266059SGregory Neil Shapiro ret = firstto == to ? HS_MATCH_FULL : 158340266059SGregory Neil Shapiro coloncmp(to->q_signature, firstsig); 158440266059SGregory Neil Shapiro if (ret == HS_MATCH_FULL) 158540266059SGregory Neil Shapiro skip_back = to; 158640266059SGregory Neil Shapiro else if (ret == HS_MATCH_NO) 158706f25ae9SGregory Neil Shapiro break; 158806f25ae9SGregory Neil Shapiro 158940266059SGregory Neil Shapiro if (!clever) 159040266059SGregory Neil Shapiro { 159140266059SGregory Neil Shapiro /* avoid overflowing tobuf */ 159240266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 159340266059SGregory Neil Shapiro if (strsize > TOBUFSIZE) 159440266059SGregory Neil Shapiro break; 159540266059SGregory Neil Shapiro } 159640266059SGregory Neil Shapiro 159706f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt) 159806f25ae9SGregory Neil Shapiro break; 1599c2aa98e2SPeter Wemm 1600c2aa98e2SPeter Wemm if (tTd(10, 1)) 1601c2aa98e2SPeter Wemm { 160240266059SGregory Neil Shapiro sm_dprintf("\nsend to "); 1603e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false); 1604c2aa98e2SPeter Wemm } 1605c2aa98e2SPeter Wemm 1606c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */ 1607c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 160840266059SGregory Neil Shapiro #if HASSETUSERCONTEXT 1609c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to); 1610*5b0945b5SGregory Neil Shapiro #else 161140266059SGregory Neil Shapiro ctladdr = getctladdr(to); 1612*5b0945b5SGregory Neil Shapiro #endif 1613c2aa98e2SPeter Wemm 1614c2aa98e2SPeter Wemm if (tTd(10, 2)) 1615c2aa98e2SPeter Wemm { 161640266059SGregory Neil Shapiro sm_dprintf("ctladdr="); 1617e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false); 1618c2aa98e2SPeter Wemm } 1619c2aa98e2SPeter Wemm 1620c2aa98e2SPeter Wemm user = to->q_user; 1621c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 1622c2aa98e2SPeter Wemm 1623c2aa98e2SPeter Wemm /* 1624c2aa98e2SPeter Wemm ** Check to see that these people are allowed to 1625c2aa98e2SPeter Wemm ** talk to each other. 162642e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize. 1627c2aa98e2SPeter Wemm */ 1628c2aa98e2SPeter Wemm 162942e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 && 163042e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 1631c2aa98e2SPeter Wemm { 1632c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 1633c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 1634c2aa98e2SPeter Wemm to->q_status = "5.2.3"; 1635c2aa98e2SPeter Wemm else 1636c2aa98e2SPeter Wemm to->q_status = "5.3.4"; 163740266059SGregory Neil Shapiro 163806f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */ 163906f25ae9SGregory Neil Shapiro usrerrenh(to->q_status, 164006f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 164106f25ae9SGregory Neil Shapiro m->m_maxsize); 164240266059SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, false); 164306f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m, 164440266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1645c2aa98e2SPeter Wemm continue; 1646c2aa98e2SPeter Wemm } 1647602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 164840266059SGregory Neil Shapiro ovr = true; 1649c2aa98e2SPeter Wemm 1650c2aa98e2SPeter Wemm /* do config file checking of compatibility */ 165140266059SGregory Neil Shapiro quarantine = (e->e_quarmsg != NULL); 165206f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 1653959366dcSGregory Neil Shapiro e, RSF_RMCOMM|RSF_COUNT, 3, NULL, 1654da7d7b9cSGregory Neil Shapiro e->e_id, NULL, NULL); 1655c2aa98e2SPeter Wemm if (rcode == EX_OK) 1656c2aa98e2SPeter Wemm { 1657065a643dSPeter Wemm /* do in-code checking if not discarding */ 1658065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags)) 165906f25ae9SGregory Neil Shapiro { 1660c2aa98e2SPeter Wemm rcode = checkcompat(to, e); 166140266059SGregory Neil Shapiro ovr = false; 166206f25ae9SGregory Neil Shapiro } 1663c2aa98e2SPeter Wemm } 1664c2aa98e2SPeter Wemm if (rcode != EX_OK) 1665c2aa98e2SPeter Wemm { 166606f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr); 166706f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, 166840266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1669c2aa98e2SPeter Wemm continue; 1670c2aa98e2SPeter Wemm } 167140266059SGregory Neil Shapiro if (!quarantine && e->e_quarmsg != NULL) 167240266059SGregory Neil Shapiro { 167340266059SGregory Neil Shapiro /* 167440266059SGregory Neil Shapiro ** check_compat or checkcompat() has tried 167540266059SGregory Neil Shapiro ** to quarantine but that isn't supported. 167640266059SGregory Neil Shapiro ** Revert the attempt. 167740266059SGregory Neil Shapiro */ 167840266059SGregory Neil Shapiro 167940266059SGregory Neil Shapiro e->e_quarmsg = NULL; 168040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 168140266059SGregory Neil Shapiro macid("{quarantine}"), ""); 168240266059SGregory Neil Shapiro } 1683065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 1684065a643dSPeter Wemm { 1685065a643dSPeter Wemm if (tTd(10, 5)) 1686065a643dSPeter Wemm { 168740266059SGregory Neil Shapiro sm_dprintf("deliver: discarding recipient "); 1688e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false); 1689065a643dSPeter Wemm } 1690065a643dSPeter Wemm 169106f25ae9SGregory Neil Shapiro /* pretend the message was sent */ 169206f25ae9SGregory Neil Shapiro /* XXX should we log something here? */ 169306f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED; 169406f25ae9SGregory Neil Shapiro 1695065a643dSPeter Wemm /* 1696065a643dSPeter Wemm ** Remove discard bit to prevent discard of 169706f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the 169806f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before 169906f25ae9SGregory Neil Shapiro ** we get here. 1700065a643dSPeter Wemm */ 1701065a643dSPeter Wemm 170206f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD; 1703065a643dSPeter Wemm continue; 1704065a643dSPeter Wemm } 1705c2aa98e2SPeter Wemm 1706c2aa98e2SPeter Wemm /* 1707c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb 1708c2aa98e2SPeter Wemm ** about them. 1709c2aa98e2SPeter Wemm */ 1710c2aa98e2SPeter Wemm 1711c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags)) 1712c2aa98e2SPeter Wemm { 1713c2aa98e2SPeter Wemm stripquotes(user); 1714c2aa98e2SPeter Wemm stripquotes(host); 1715c2aa98e2SPeter Wemm } 1716e92d3f3fSGregory Neil Shapiro 171713bd1963SGregory Neil Shapiro /* 1718b6bacd31SGregory Neil Shapiro ** Strip all leading backslashes if requested and the 171913bd1963SGregory Neil Shapiro ** next character is alphanumerical (the latter can 172013bd1963SGregory Neil Shapiro ** probably relaxed a bit, see RFC2821). 172113bd1963SGregory Neil Shapiro */ 172213bd1963SGregory Neil Shapiro 172313bd1963SGregory Neil Shapiro if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\') 172413bd1963SGregory Neil Shapiro stripbackslash(user); 1725c2aa98e2SPeter Wemm 1726c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */ 1727c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|') 1728c2aa98e2SPeter Wemm user++; 1729c2aa98e2SPeter Wemm 1730c2aa98e2SPeter Wemm /* 1731c2aa98e2SPeter Wemm ** If an error message has already been given, don't 1732c2aa98e2SPeter Wemm ** bother to send to this address. 1733c2aa98e2SPeter Wemm ** 1734c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer 1735c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that 1736c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail. 1737c2aa98e2SPeter Wemm */ 1738c2aa98e2SPeter Wemm 173906f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 1740c2aa98e2SPeter Wemm continue; 1741c2aa98e2SPeter Wemm 1742c2aa98e2SPeter Wemm /* 1743c2aa98e2SPeter Wemm ** See if this user name is "special". 1744c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this 1745c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note 1746c2aa98e2SPeter Wemm ** that this type of addresses is not processed along 1747c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person. 1748c2aa98e2SPeter Wemm */ 1749c2aa98e2SPeter Wemm 1750c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0) 1751c2aa98e2SPeter Wemm { 175240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); 1753c2aa98e2SPeter Wemm p = to->q_home; 1754c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1755c2aa98e2SPeter Wemm p = ctladdr->q_home; 175640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); 1757d0cef73dSGregory Neil Shapiro expand(m->m_argv[1], buf, sizeof(buf), e); 1758c2aa98e2SPeter Wemm if (strlen(buf) > 0) 1759c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 1760c2aa98e2SPeter Wemm else 1761c2aa98e2SPeter Wemm { 1762c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s", 1763c2aa98e2SPeter Wemm m->m_name); 1764c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1765c2aa98e2SPeter Wemm } 176606f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL, 176740266059SGregory Neil Shapiro ctladdr, xstart, e, to); 176840266059SGregory Neil Shapiro markfailure(e, to, NULL, rcode, true); 1769c2aa98e2SPeter Wemm e->e_nsent++; 1770c2aa98e2SPeter Wemm if (rcode == EX_OK) 1771c2aa98e2SPeter Wemm { 177206f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 1773c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 1774c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 1775c2aa98e2SPeter Wemm { 1776c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 1777c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 177840266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, 177940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 178040266059SGregory Neil Shapiro "%s... Successfully delivered\n", 1781c2aa98e2SPeter Wemm to->q_paddr); 1782c2aa98e2SPeter Wemm } 1783c2aa98e2SPeter Wemm } 1784c2aa98e2SPeter Wemm to->q_statdate = curtime(); 178540266059SGregory Neil Shapiro markstats(e, to, STATS_NORMAL); 1786c2aa98e2SPeter Wemm continue; 1787c2aa98e2SPeter Wemm } 1788c2aa98e2SPeter Wemm 1789c2aa98e2SPeter Wemm /* 1790c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer 1791c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients. 1792c2aa98e2SPeter Wemm */ 1793c2aa98e2SPeter Wemm 1794c2aa98e2SPeter Wemm /* link together the chain of recipients */ 1795c2aa98e2SPeter Wemm to->q_tchain = tochain; 1796c2aa98e2SPeter Wemm tochain = to; 179706f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]"; 179806f25ae9SGregory Neil Shapiro 179940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */ 1800c2aa98e2SPeter Wemm p = to->q_home; 1801c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1802c2aa98e2SPeter Wemm p = ctladdr->q_home; 180340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */ 1804c2aa98e2SPeter Wemm 180506f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */ 180606f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags)) 180706f25ae9SGregory Neil Shapiro { 180806f25ae9SGregory Neil Shapiro char notify[MAXLINE]; 180906f25ae9SGregory Neil Shapiro 181006f25ae9SGregory Neil Shapiro notify[0] = '\0'; 181106f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags)) 181240266059SGregory Neil Shapiro (void) sm_strlcat(notify, "SUCCESS,", 1813d0cef73dSGregory Neil Shapiro sizeof(notify)); 181406f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags)) 181540266059SGregory Neil Shapiro (void) sm_strlcat(notify, "FAILURE,", 1816d0cef73dSGregory Neil Shapiro sizeof(notify)); 181706f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags)) 181840266059SGregory Neil Shapiro (void) sm_strlcat(notify, "DELAY,", 1819d0cef73dSGregory Neil Shapiro sizeof(notify)); 182006f25ae9SGregory Neil Shapiro 182106f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */ 182206f25ae9SGregory Neil Shapiro if (notify[0] == '\0') 182340266059SGregory Neil Shapiro (void) sm_strlcat(notify, "NEVER", 1824d0cef73dSGregory Neil Shapiro sizeof(notify)); 182506f25ae9SGregory Neil Shapiro else 182606f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0'; 182706f25ae9SGregory Neil Shapiro 182840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 182940266059SGregory Neil Shapiro macid("{dsn_notify}"), notify); 183006f25ae9SGregory Neil Shapiro } 183106f25ae9SGregory Neil Shapiro else 183240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 183340266059SGregory Neil Shapiro macid("{dsn_notify}"), NULL); 183406f25ae9SGregory Neil Shapiro 1835c2aa98e2SPeter Wemm /* 1836c2aa98e2SPeter Wemm ** Expand out this user into argument list. 1837c2aa98e2SPeter Wemm */ 1838c2aa98e2SPeter Wemm 1839c2aa98e2SPeter Wemm if (!clever) 1840c2aa98e2SPeter Wemm { 1841d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 184240266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1843c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2]) 1844c2aa98e2SPeter Wemm { 1845c2aa98e2SPeter Wemm /* allow some space for trailing parms */ 1846c2aa98e2SPeter Wemm break; 1847c2aa98e2SPeter Wemm } 1848c2aa98e2SPeter Wemm } 1849c2aa98e2SPeter Wemm } 1850c2aa98e2SPeter Wemm 1851c2aa98e2SPeter Wemm /* see if any addresses still exist */ 185206f25ae9SGregory Neil Shapiro if (tochain == NULL) 1853c2aa98e2SPeter Wemm { 185440266059SGregory Neil Shapiro rcode = 0; 185540266059SGregory Neil Shapiro goto cleanup; 1856c2aa98e2SPeter Wemm } 1857c2aa98e2SPeter Wemm 1858c2aa98e2SPeter Wemm /* print out messages as full list */ 185940266059SGregory Neil Shapiro strsize = 1; 186006f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 186140266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 186240266059SGregory Neil Shapiro if (strsize < TOBUFSIZE) 186340266059SGregory Neil Shapiro strsize = TOBUFSIZE; 186440266059SGregory Neil Shapiro if (strsize > tobufsize) 186506f25ae9SGregory Neil Shapiro { 1866*5b0945b5SGregory Neil Shapiro SM_FREE(tobuf); 186740266059SGregory Neil Shapiro tobuf = sm_pmalloc_x(strsize); 186840266059SGregory Neil Shapiro tobufsize = strsize; 186906f25ae9SGregory Neil Shapiro } 187040266059SGregory Neil Shapiro p = tobuf; 187140266059SGregory Neil Shapiro *p = '\0'; 187206f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 187306f25ae9SGregory Neil Shapiro { 187440266059SGregory Neil Shapiro (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2, 187540266059SGregory Neil Shapiro ",", to->q_paddr); 187640266059SGregory Neil Shapiro p += strlen(p); 187706f25ae9SGregory Neil Shapiro } 1878c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 1879c2aa98e2SPeter Wemm 1880c2aa98e2SPeter Wemm /* 1881c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter. 1882c2aa98e2SPeter Wemm */ 1883c2aa98e2SPeter Wemm 188440266059SGregory Neil Shapiro if (!clever) 188540266059SGregory Neil Shapiro { 188640266059SGregory Neil Shapiro while (*++mvp != NULL) 1887c2aa98e2SPeter Wemm { 1888d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 188940266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1890c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV]) 189106f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s", 189206f25ae9SGregory Neil Shapiro pv[0]); 1893c2aa98e2SPeter Wemm } 189440266059SGregory Neil Shapiro } 1895c2aa98e2SPeter Wemm *pvp++ = NULL; 1896c2aa98e2SPeter Wemm 1897c2aa98e2SPeter Wemm /* 1898c2aa98e2SPeter Wemm ** Call the mailer. 1899c2aa98e2SPeter Wemm ** The argument vector gets built, pipes 1900c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as 1901c2aa98e2SPeter Wemm ** appropriate. 1902c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up. 1903c2aa98e2SPeter Wemm */ 1904c2aa98e2SPeter Wemm 19056f9c8e5bSGregory Neil Shapiro /* XXX this seems a bit weird */ 1906c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 1907c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags)) 1908c2aa98e2SPeter Wemm ctladdr = &e->e_from; 1909c2aa98e2SPeter Wemm 1910c2aa98e2SPeter Wemm #if NAMED_BIND 1911c2aa98e2SPeter Wemm if (ConfigLevel < 2) 1912c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 1913*5b0945b5SGregory Neil Shapiro #endif 1914c2aa98e2SPeter Wemm 1915c2aa98e2SPeter Wemm if (tTd(11, 1)) 1916c2aa98e2SPeter Wemm { 191740266059SGregory Neil Shapiro sm_dprintf("openmailer:"); 1918e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pv); 1919c2aa98e2SPeter Wemm } 1920c2aa98e2SPeter Wemm errno = 0; 1921602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 1922c2aa98e2SPeter Wemm CurHostName = NULL; 1923c2aa98e2SPeter Wemm 1924c2aa98e2SPeter Wemm /* 1925c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC 1926c2aa98e2SPeter Wemm ** connection. 1927c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be 1928c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a 1929c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC. 1930c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out. 1931c2aa98e2SPeter Wemm */ 1932c2aa98e2SPeter Wemm 1933c2aa98e2SPeter Wemm curhost = NULL; 1934c2aa98e2SPeter Wemm SmtpPhase = NULL; 1935c2aa98e2SPeter Wemm mci = NULL; 1936c2aa98e2SPeter Wemm 1937c2aa98e2SPeter Wemm #if XDEBUG 1938c2aa98e2SPeter Wemm { 1939c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 1940c2aa98e2SPeter Wemm 1941c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 1942d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "%s... openmailer(%s)", 194340266059SGregory Neil Shapiro shortenstring(e->e_to, MAXSHORTSTR), 194440266059SGregory Neil Shapiro m->m_name); 1945c2aa98e2SPeter Wemm checkfd012(wbuf); 1946c2aa98e2SPeter Wemm } 194706f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1948c2aa98e2SPeter Wemm 1949c2aa98e2SPeter Wemm /* check for 8-bit available */ 1950c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 1951c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) && 1952c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 1953c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 1954c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 1955c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 1956c2aa98e2SPeter Wemm { 1957c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 195806f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 195906f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 196006f25ae9SGregory Neil Shapiro rcode = EX_DATAERR; 1961c2aa98e2SPeter Wemm goto give_up; 1962c2aa98e2SPeter Wemm } 1963c2aa98e2SPeter Wemm 1964c2aa98e2SPeter Wemm if (tTd(62, 8)) 1965c2aa98e2SPeter Wemm checkfds("before delivery"); 1966c2aa98e2SPeter Wemm 1967c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */ 1968c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0) 1969c2aa98e2SPeter Wemm { 197040266059SGregory Neil Shapiro if (clever) 197140266059SGregory Neil Shapiro { 197240266059SGregory Neil Shapiro /* flush any expired connections */ 197340266059SGregory Neil Shapiro (void) mci_scan(NULL); 197440266059SGregory Neil Shapiro 197540266059SGregory Neil Shapiro /* try to get a cached connection or just a slot */ 197640266059SGregory Neil Shapiro mci = mci_get(m->m_name, m); 197740266059SGregory Neil Shapiro if (mci->mci_host == NULL) 197840266059SGregory Neil Shapiro mci->mci_host = m->m_name; 197940266059SGregory Neil Shapiro CurHostName = mci->mci_host; 198040266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED) 198140266059SGregory Neil Shapiro { 198240266059SGregory Neil Shapiro message("Using cached SMTP/LPC connection for %s...", 198340266059SGregory Neil Shapiro m->m_name); 198440266059SGregory Neil Shapiro mci->mci_deliveries++; 198540266059SGregory Neil Shapiro goto do_transfer; 198640266059SGregory Neil Shapiro } 198740266059SGregory Neil Shapiro } 198840266059SGregory Neil Shapiro else 198940266059SGregory Neil Shapiro { 199040266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 199140266059SGregory Neil Shapiro } 199240266059SGregory Neil Shapiro mci->mci_in = smioin; 199340266059SGregory Neil Shapiro mci->mci_out = smioout; 199440266059SGregory Neil Shapiro mci->mci_mailer = m; 199540266059SGregory Neil Shapiro mci->mci_host = m->m_name; 199640266059SGregory Neil Shapiro if (clever) 199740266059SGregory Neil Shapiro { 199840266059SGregory Neil Shapiro mci->mci_state = MCIS_OPENING; 199940266059SGregory Neil Shapiro mci_cache(mci); 200040266059SGregory Neil Shapiro } 200140266059SGregory Neil Shapiro else 200240266059SGregory Neil Shapiro mci->mci_state = MCIS_OPEN; 2003c2aa98e2SPeter Wemm } 200440266059SGregory Neil Shapiro else if (strcmp(m->m_mailer, "[IPC]") == 0) 2005c2aa98e2SPeter Wemm { 2006c2aa98e2SPeter Wemm register int i; 2007c2aa98e2SPeter Wemm 2008c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 2009c2aa98e2SPeter Wemm { 201006f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer); 2011c2aa98e2SPeter Wemm rcode = EX_CONFIG; 2012c2aa98e2SPeter Wemm goto give_up; 2013c2aa98e2SPeter Wemm } 2014c2aa98e2SPeter Wemm 201506f25ae9SGregory Neil Shapiro #if NETUNIX 201606f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0) 201706f25ae9SGregory Neil Shapiro { 201806f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost"; 201906f25ae9SGregory Neil Shapiro mux_path = pv[1]; 202006f25ae9SGregory Neil Shapiro } 202106f25ae9SGregory Neil Shapiro else 202206f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 202306f25ae9SGregory Neil Shapiro { 2024c2aa98e2SPeter Wemm CurHostName = pv[1]; 2025*5b0945b5SGregory Neil Shapiro /* XXX ??? */ 2026*5b0945b5SGregory Neil Shapiro curhost = hostsignature(m, pv[1], firstto->q_flags & QSECURE); 202706f25ae9SGregory Neil Shapiro } 2028c2aa98e2SPeter Wemm 2029c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0') 2030c2aa98e2SPeter Wemm { 2031c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]); 2032c2aa98e2SPeter Wemm rcode = EX_CONFIG; 2033c2aa98e2SPeter Wemm goto give_up; 2034c2aa98e2SPeter Wemm } 2035c2aa98e2SPeter Wemm 2036c2aa98e2SPeter Wemm if (!clever) 2037c2aa98e2SPeter Wemm { 203806f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC"); 2039c2aa98e2SPeter Wemm rcode = EX_CONFIG; 2040c2aa98e2SPeter Wemm goto give_up; 2041c2aa98e2SPeter Wemm } 204206f25ae9SGregory Neil Shapiro if (pv[2] != NULL 204306f25ae9SGregory Neil Shapiro #if NETUNIX 204406f25ae9SGregory Neil Shapiro && mux_path == NULL 2045*5b0945b5SGregory Neil Shapiro #endif 204606f25ae9SGregory Neil Shapiro ) 2047c2aa98e2SPeter Wemm { 204840266059SGregory Neil Shapiro port = htons((unsigned short) atoi(pv[2])); 2049c2aa98e2SPeter Wemm if (port == 0) 2050c2aa98e2SPeter Wemm { 205106f25ae9SGregory Neil Shapiro #ifdef NO_GETSERVBYNAME 205206f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]); 205306f25ae9SGregory Neil Shapiro #else /* NO_GETSERVBYNAME */ 2054c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp"); 2055c2aa98e2SPeter Wemm 2056c2aa98e2SPeter Wemm if (sp == NULL) 2057c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]); 2058c2aa98e2SPeter Wemm else 2059c2aa98e2SPeter Wemm port = sp->s_port; 206006f25ae9SGregory Neil Shapiro #endif /* NO_GETSERVBYNAME */ 2061c2aa98e2SPeter Wemm } 2062c2aa98e2SPeter Wemm } 2063c2aa98e2SPeter Wemm 206406f25ae9SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m); 206540266059SGregory Neil Shapiro if (TimeOuts.to_aconnect > 0) 206640266059SGregory Neil Shapiro enough = curtime() + TimeOuts.to_aconnect; 206706f25ae9SGregory Neil Shapiro tryhost: 206806f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts) 206906f25ae9SGregory Neil Shapiro { 207006f25ae9SGregory Neil Shapiro char sep = ':'; 207106f25ae9SGregory Neil Shapiro char *endp; 207206f25ae9SGregory Neil Shapiro static char hostbuf[MAXNAME + 1]; 2073e92d3f3fSGregory Neil Shapiro bool tried_fallbacksmarthost = false; 2074*5b0945b5SGregory Neil Shapiro #if DANE 2075*5b0945b5SGregory Neil Shapiro unsigned long tlsa_flags; 207606f25ae9SGregory Neil Shapiro 2077*5b0945b5SGregory Neil Shapiro ste = NULL; 2078*5b0945b5SGregory Neil Shapiro tlsa_flags = 0; 2079*5b0945b5SGregory Neil Shapiro #endif 208006f25ae9SGregory Neil Shapiro #if NETINET6 208106f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '[') 208206f25ae9SGregory Neil Shapiro { 208306f25ae9SGregory Neil Shapiro endp = strchr(mxhosts[hostnum] + 1, ']'); 208406f25ae9SGregory Neil Shapiro if (endp != NULL) 208506f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 208606f25ae9SGregory Neil Shapiro } 208706f25ae9SGregory Neil Shapiro else 208806f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 208906f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 209006f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 209106f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 209206f25ae9SGregory Neil Shapiro if (endp != NULL) 209306f25ae9SGregory Neil Shapiro { 209406f25ae9SGregory Neil Shapiro sep = *endp; 209506f25ae9SGregory Neil Shapiro *endp = '\0'; 209606f25ae9SGregory Neil Shapiro } 209706f25ae9SGregory Neil Shapiro 209840266059SGregory Neil Shapiro if (hostnum == 1 && skip_back != NULL) 209940266059SGregory Neil Shapiro { 210040266059SGregory Neil Shapiro /* 210140266059SGregory Neil Shapiro ** Coattail piggybacking is no longer an 210240266059SGregory Neil Shapiro ** option with the mail host next to be tried 210340266059SGregory Neil Shapiro ** no longer the lowest MX preference 210440266059SGregory Neil Shapiro ** (hostnum == 1 meaning we're on the second 210540266059SGregory Neil Shapiro ** preference). We do not try to coattail 210640266059SGregory Neil Shapiro ** piggyback more than the first MX preference. 210740266059SGregory Neil Shapiro ** Revert 'tochain' to last location for 210840266059SGregory Neil Shapiro ** coincidental piggybacking. This works this 210940266059SGregory Neil Shapiro ** easily because the q_tchain kept getting 211040266059SGregory Neil Shapiro ** added to the top of the linked list. 211140266059SGregory Neil Shapiro */ 211240266059SGregory Neil Shapiro 211340266059SGregory Neil Shapiro tochain = skip_back; 211440266059SGregory Neil Shapiro } 211540266059SGregory Neil Shapiro 211606f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0') 2117c2aa98e2SPeter Wemm { 2118c2aa98e2SPeter Wemm syserr("deliver: null host name in signature"); 211906f25ae9SGregory Neil Shapiro hostnum++; 212006f25ae9SGregory Neil Shapiro if (endp != NULL) 212106f25ae9SGregory Neil Shapiro *endp = sep; 2122c2aa98e2SPeter Wemm continue; 2123c2aa98e2SPeter Wemm } 212440266059SGregory Neil Shapiro (void) sm_strlcpy(hostbuf, mxhosts[hostnum], 2125d0cef73dSGregory Neil Shapiro sizeof(hostbuf)); 212606f25ae9SGregory Neil Shapiro hostnum++; 212706f25ae9SGregory Neil Shapiro if (endp != NULL) 212806f25ae9SGregory Neil Shapiro *endp = sep; 2129*5b0945b5SGregory Neil Shapiro #if STARTTLS 2130*5b0945b5SGregory Neil Shapiro tlsstate = 0; 2131*5b0945b5SGregory Neil Shapiro #endif 2132c2aa98e2SPeter Wemm 2133e92d3f3fSGregory Neil Shapiro one_last_try: 2134c2aa98e2SPeter Wemm /* see if we already know that this host is fried */ 2135c2aa98e2SPeter Wemm CurHostName = hostbuf; 2136c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m); 2137c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2138c2aa98e2SPeter Wemm { 213940266059SGregory Neil Shapiro char *type; 214040266059SGregory Neil Shapiro 2141c2aa98e2SPeter Wemm if (tTd(11, 1)) 2142c2aa98e2SPeter Wemm { 214340266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 2144e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 2145c2aa98e2SPeter Wemm } 2146c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 214740266059SGregory Neil Shapiro if (bitnset(M_LMTP, m->m_flags)) 214840266059SGregory Neil Shapiro type = "L"; 214940266059SGregory Neil Shapiro else if (bitset(MCIF_ESMTP, mci->mci_flags)) 215040266059SGregory Neil Shapiro type = "ES"; 215140266059SGregory Neil Shapiro else 215240266059SGregory Neil Shapiro type = "S"; 215340266059SGregory Neil Shapiro message("Using cached %sMTP connection to %s via %s...", 215440266059SGregory Neil Shapiro type, hostbuf, m->m_name); 215506f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2156c2aa98e2SPeter Wemm break; 2157c2aa98e2SPeter Wemm } 2158c2aa98e2SPeter Wemm mci->mci_mailer = m; 2159*5b0945b5SGregory Neil Shapiro #if DANE 2160*5b0945b5SGregory Neil Shapiro tlsa_flags = 0; 2161*5b0945b5SGregory Neil Shapiro if (CHK_DANE(Dane)) 2162*5b0945b5SGregory Neil Shapiro (void) GETTLSA(hostbuf, &ste, m->m_port); 2163*5b0945b5SGregory Neil Shapiro 2164*5b0945b5SGregory Neil Shapiro /* XXX: check expiration! */ 2165*5b0945b5SGregory Neil Shapiro if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa)) 2166*5b0945b5SGregory Neil Shapiro { 2167*5b0945b5SGregory Neil Shapiro if (tTd(11, 1)) 2168*5b0945b5SGregory Neil Shapiro sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n" 2169*5b0945b5SGregory Neil Shapiro , hostbuf 2170*5b0945b5SGregory Neil Shapiro , ste->s_tlsa->dane_tlsa_dnsrc); 2171*5b0945b5SGregory Neil Shapiro 2172*5b0945b5SGregory Neil Shapiro tlsa_flags |= TLSAFLTEMP; 2173*5b0945b5SGregory Neil Shapiro } 2174*5b0945b5SGregory Neil Shapiro #endif /* DANE */ 2175*5b0945b5SGregory Neil Shapiro 2176c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK) 2177c2aa98e2SPeter Wemm { 2178c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL) 217940266059SGregory Neil Shapiro goodmxfound = true; 2180e92d3f3fSGregory Neil Shapiro 2181e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */ 2182e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost, 2183d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf), 2184e92d3f3fSGregory Neil Shapiro mci->mci_exitstat)) 2185e92d3f3fSGregory Neil Shapiro goto one_last_try; 2186e92d3f3fSGregory Neil Shapiro 2187c2aa98e2SPeter Wemm continue; 2188c2aa98e2SPeter Wemm } 2189c2aa98e2SPeter Wemm 2190c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK) 2191c2aa98e2SPeter Wemm { 2192c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 219340266059SGregory Neil Shapiro goodmxfound = true; 2194c2aa98e2SPeter Wemm continue; 2195c2aa98e2SPeter Wemm } 2196c2aa98e2SPeter Wemm 2197c2aa98e2SPeter Wemm /* try the connection */ 219840266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %s", 219906f25ae9SGregory Neil Shapiro qid_printname(e), 220006f25ae9SGregory Neil Shapiro hostbuf, "user open"); 220106f25ae9SGregory Neil Shapiro #if NETUNIX 220206f25ae9SGregory Neil Shapiro if (mux_path != NULL) 220306f25ae9SGregory Neil Shapiro { 220406f25ae9SGregory Neil Shapiro message("Connecting to %s via %s...", 220506f25ae9SGregory Neil Shapiro mux_path, m->m_name); 220640266059SGregory Neil Shapiro i = makeconnection_ds((char *) mux_path, mci); 220706f25ae9SGregory Neil Shapiro } 220806f25ae9SGregory Neil Shapiro else 220906f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 221006f25ae9SGregory Neil Shapiro { 2211c2aa98e2SPeter Wemm if (port == 0) 2212c2aa98e2SPeter Wemm message("Connecting to %s via %s...", 2213c2aa98e2SPeter Wemm hostbuf, m->m_name); 2214c2aa98e2SPeter Wemm else 2215c2aa98e2SPeter Wemm message("Connecting to %s port %d via %s...", 221606f25ae9SGregory Neil Shapiro hostbuf, ntohs(port), 221706f25ae9SGregory Neil Shapiro m->m_name); 2218*5b0945b5SGregory Neil Shapiro #if DANE 2219*5b0945b5SGregory Neil Shapiro tlsa_flags |= (ste != NULL) ? Dane : DANE_NEVER; 2220*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags; 2221*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_port = m->m_port; 2222*5b0945b5SGregory Neil Shapiro if (tTd(11, 11)) 2223*5b0945b5SGregory Neil Shapiro sm_dprintf("makeconnection: before: chk=%d, mode=%lX\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags); 2224*5b0945b5SGregory Neil Shapiro #endif 222540266059SGregory Neil Shapiro i = makeconnection(hostbuf, port, mci, e, 2226*5b0945b5SGregory Neil Shapiro enough 2227*5b0945b5SGregory Neil Shapiro #if DANE 2228*5b0945b5SGregory Neil Shapiro , &tlsa_flags 2229*5b0945b5SGregory Neil Shapiro #endif 2230*5b0945b5SGregory Neil Shapiro ); 2231*5b0945b5SGregory Neil Shapiro #if DANE 2232*5b0945b5SGregory Neil Shapiro if (tTd(11, 11)) 2233*5b0945b5SGregory Neil Shapiro sm_dprintf("makeconnection: after: chk=%d, mode=%lX\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags); 2234*5b0945b5SGregory Neil Shapiro if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS) 2235*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags); 2236*5b0945b5SGregory Neil Shapiro if (EX_TEMPFAIL == i && 2237*5b0945b5SGregory Neil Shapiro ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) == 2238*5b0945b5SGregory Neil Shapiro (TLSAFLTEMP|DANE_SECURE))) 2239*5b0945b5SGregory Neil Shapiro { 2240*5b0945b5SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, 2241*5b0945b5SGregory Neil Shapiro " for TLSA RR", 2242*5b0945b5SGregory Neil Shapiro sizeof(SmtpError)); 2243*5b0945b5SGregory Neil Shapiro # if NAMED_BIND 2244*5b0945b5SGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN); 2245*5b0945b5SGregory Neil Shapiro # endif 2246*5b0945b5SGregory Neil Shapiro } 2247*5b0945b5SGregory Neil Shapiro #endif 224806f25ae9SGregory Neil Shapiro } 22498774250cSGregory Neil Shapiro mci->mci_errno = errno; 2250c2aa98e2SPeter Wemm mci->mci_lastuse = curtime(); 225106f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0; 2252c2aa98e2SPeter Wemm mci->mci_exitstat = i; 22536f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 2254c2aa98e2SPeter Wemm #if NAMED_BIND 2255c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 2256*5b0945b5SGregory Neil Shapiro #endif 225740266059SGregory Neil Shapiro 225840266059SGregory Neil Shapiro /* 225940266059SGregory Neil Shapiro ** Have we tried long enough to get a connection? 226040266059SGregory Neil Shapiro ** If yes, skip to the fallback MX hosts 226140266059SGregory Neil Shapiro ** (if existent). 226240266059SGregory Neil Shapiro */ 226340266059SGregory Neil Shapiro 226440266059SGregory Neil Shapiro if (enough > 0 && mci->mci_lastuse >= enough) 226540266059SGregory Neil Shapiro { 226640266059SGregory Neil Shapiro int h; 226740266059SGregory Neil Shapiro #if NAMED_BIND 2268e92d3f3fSGregory Neil Shapiro extern int NumFallbackMXHosts; 2269*5b0945b5SGregory Neil Shapiro #else 2270e92d3f3fSGregory Neil Shapiro const int NumFallbackMXHosts = 0; 2271*5b0945b5SGregory Neil Shapiro #endif 227240266059SGregory Neil Shapiro 227340266059SGregory Neil Shapiro if (hostnum < nummxhosts && LogLevel > 9) 227440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 227540266059SGregory Neil Shapiro "Timeout.to_aconnect occurred before exhausting all addresses"); 227640266059SGregory Neil Shapiro 227740266059SGregory Neil Shapiro /* turn off timeout if fallback available */ 2278e92d3f3fSGregory Neil Shapiro if (NumFallbackMXHosts > 0) 227940266059SGregory Neil Shapiro enough = 0; 228040266059SGregory Neil Shapiro 228140266059SGregory Neil Shapiro /* skip to a fallback MX host */ 2282e92d3f3fSGregory Neil Shapiro h = nummxhosts - NumFallbackMXHosts; 228340266059SGregory Neil Shapiro if (hostnum < h) 228440266059SGregory Neil Shapiro hostnum = h; 228540266059SGregory Neil Shapiro } 2286c2aa98e2SPeter Wemm if (i == EX_OK) 2287c2aa98e2SPeter Wemm { 228840266059SGregory Neil Shapiro goodmxfound = true; 2289605302a5SGregory Neil Shapiro markstats(e, firstto, STATS_CONNECT); 2290c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2291c2aa98e2SPeter Wemm mci_cache(mci); 2292c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 229340266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 229440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 229540266059SGregory Neil Shapiro "%05d === CONNECT %s\n", 229640266059SGregory Neil Shapiro (int) CurrentPid, 229740266059SGregory Neil Shapiro hostbuf); 2298c2aa98e2SPeter Wemm break; 2299c2aa98e2SPeter Wemm } 2300c2aa98e2SPeter Wemm else 2301c2aa98e2SPeter Wemm { 2302e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */ 2303e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost, 2304d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf), i)) 2305e92d3f3fSGregory Neil Shapiro goto one_last_try; 2306e92d3f3fSGregory Neil Shapiro 2307c2aa98e2SPeter Wemm if (tTd(11, 1)) 230840266059SGregory Neil Shapiro sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 2309c2aa98e2SPeter Wemm i, errno); 2310c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL) 231140266059SGregory Neil Shapiro goodmxfound = true; 2312c2aa98e2SPeter Wemm mci_unlock_host(mci); 2313c2aa98e2SPeter Wemm } 2314c2aa98e2SPeter Wemm 2315c2aa98e2SPeter Wemm /* enter status of this host */ 2316c2aa98e2SPeter Wemm setstat(i); 2317c2aa98e2SPeter Wemm 2318c2aa98e2SPeter Wemm /* should print some message here for -v mode */ 2319c2aa98e2SPeter Wemm } 2320c2aa98e2SPeter Wemm if (mci == NULL) 2321c2aa98e2SPeter Wemm { 2322c2aa98e2SPeter Wemm syserr("deliver: no host name"); 2323c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 2324c2aa98e2SPeter Wemm goto give_up; 2325c2aa98e2SPeter Wemm } 2326c2aa98e2SPeter Wemm mci->mci_pid = 0; 2327c2aa98e2SPeter Wemm } 2328c2aa98e2SPeter Wemm else 2329c2aa98e2SPeter Wemm { 2330c2aa98e2SPeter Wemm /* flush any expired connections */ 2331c2aa98e2SPeter Wemm (void) mci_scan(NULL); 2332c2aa98e2SPeter Wemm mci = NULL; 2333c2aa98e2SPeter Wemm 2334c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2335c2aa98e2SPeter Wemm { 2336c2aa98e2SPeter Wemm /* try to get a cached connection */ 2337c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m); 2338c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 2339c2aa98e2SPeter Wemm mci->mci_host = m->m_name; 2340c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 2341c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2342c2aa98e2SPeter Wemm { 2343c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...", 2344c2aa98e2SPeter Wemm m->m_name); 234506f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2346c2aa98e2SPeter Wemm goto do_transfer; 2347c2aa98e2SPeter Wemm } 2348c2aa98e2SPeter Wemm } 2349c2aa98e2SPeter Wemm 2350c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */ 2351c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0') 2352c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name); 2353c2aa98e2SPeter Wemm else 2354c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name); 2355c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 2356c2aa98e2SPeter Wemm { 2357c2aa98e2SPeter Wemm char **av; 2358c2aa98e2SPeter Wemm 235940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 236040266059SGregory Neil Shapiro "%05d === EXEC", (int) CurrentPid); 2361c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 236240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 236340266059SGregory Neil Shapiro SM_TIME_DEFAULT, " %s", 236440266059SGregory Neil Shapiro *av); 236540266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 236640266059SGregory Neil Shapiro "\n"); 2367c2aa98e2SPeter Wemm } 2368c2aa98e2SPeter Wemm 2369c2aa98e2SPeter Wemm #if XDEBUG 2370c2aa98e2SPeter Wemm checkfd012("before creating mail pipe"); 2371*5b0945b5SGregory Neil Shapiro #endif 2372c2aa98e2SPeter Wemm 2373c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */ 2374c2aa98e2SPeter Wemm if (pipe(mpvect) < 0) 2375c2aa98e2SPeter Wemm { 2376c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)", 2377c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2378c2aa98e2SPeter Wemm if (tTd(11, 1)) 237940266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2380c2aa98e2SPeter Wemm rcode = EX_OSERR; 2381c2aa98e2SPeter Wemm goto give_up; 2382c2aa98e2SPeter Wemm } 2383c2aa98e2SPeter Wemm 2384c2aa98e2SPeter Wemm #if XDEBUG 2385c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */ 2386c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3) 2387c2aa98e2SPeter Wemm { 2388c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d", 2389c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 2390c2aa98e2SPeter Wemm mpvect[0], mpvect[1]); 239140266059SGregory Neil Shapiro printopenfds(true); 2392c2aa98e2SPeter Wemm if (tTd(11, 1)) 239340266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2394c2aa98e2SPeter Wemm rcode = EX_OSERR; 2395c2aa98e2SPeter Wemm goto give_up; 2396c2aa98e2SPeter Wemm } 2397c2aa98e2SPeter Wemm 2398c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */ 2399c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]"); 2400c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]"); 2401c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] || 2402c2aa98e2SPeter Wemm (e->e_lockfp != NULL && 240340266059SGregory Neil Shapiro (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 240440266059SGregory Neil Shapiro NULL) || 240540266059SGregory Neil Shapiro mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 240640266059SGregory Neil Shapiro NULL)))) 2407c2aa98e2SPeter Wemm { 2408c2aa98e2SPeter Wemm if (e->e_lockfp == NULL) 2409c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d", 2410c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2411c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]); 2412c2aa98e2SPeter Wemm else 2413c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 2414c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2415c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1], 241640266059SGregory Neil Shapiro sm_io_getinfo(e->e_lockfp, 241740266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL)); 2418c2aa98e2SPeter Wemm } 241906f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2420c2aa98e2SPeter Wemm 242106f25ae9SGregory Neil Shapiro /* create a return pipe */ 2422c2aa98e2SPeter Wemm if (pipe(rpvect) < 0) 2423c2aa98e2SPeter Wemm { 2424c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)", 2425c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2426c2aa98e2SPeter Wemm m->m_name); 2427c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2428c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2429c2aa98e2SPeter Wemm if (tTd(11, 1)) 243040266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2431c2aa98e2SPeter Wemm rcode = EX_OSERR; 2432c2aa98e2SPeter Wemm goto give_up; 2433c2aa98e2SPeter Wemm } 2434c2aa98e2SPeter Wemm #if XDEBUG 2435c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]"); 2436c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]"); 2437*5b0945b5SGregory Neil Shapiro #endif 2438c2aa98e2SPeter Wemm 2439c2aa98e2SPeter Wemm /* 2440c2aa98e2SPeter Wemm ** Actually fork the mailer process. 2441c2aa98e2SPeter Wemm ** DOFORK is clever about retrying. 2442c2aa98e2SPeter Wemm ** 2443c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying 244406f25ae9SGregory Neil Shapiro ** around so that endmailer will get it. 2445c2aa98e2SPeter Wemm */ 2446c2aa98e2SPeter Wemm 244740266059SGregory Neil Shapiro if (e->e_xfp != NULL) /* for debugging */ 244840266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 244940266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 245040266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 245106f25ae9SGregory Neil Shapiro 245206f25ae9SGregory Neil Shapiro 2453c2aa98e2SPeter Wemm DOFORK(FORK); 2454c2aa98e2SPeter Wemm /* pid is set by DOFORK */ 245506f25ae9SGregory Neil Shapiro 2456c2aa98e2SPeter Wemm if (pid < 0) 2457c2aa98e2SPeter Wemm { 2458c2aa98e2SPeter Wemm /* failure */ 2459c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork", 2460c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2461c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2462c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2463c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2464c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2465c2aa98e2SPeter Wemm if (tTd(11, 1)) 246640266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2467c2aa98e2SPeter Wemm rcode = EX_OSERR; 2468c2aa98e2SPeter Wemm goto give_up; 2469c2aa98e2SPeter Wemm } 2470c2aa98e2SPeter Wemm else if (pid == 0) 2471c2aa98e2SPeter Wemm { 247206f25ae9SGregory Neil Shapiro int save_errno; 247340266059SGregory Neil Shapiro int sff; 2474c2aa98e2SPeter Wemm int new_euid = NO_UID; 2475c2aa98e2SPeter Wemm int new_ruid = NO_UID; 2476c2aa98e2SPeter Wemm int new_gid = NO_GID; 247740266059SGregory Neil Shapiro char *user = NULL; 2478c2aa98e2SPeter Wemm struct stat stb; 2479c2aa98e2SPeter Wemm extern int DtableSize; 2480c2aa98e2SPeter Wemm 248140266059SGregory Neil Shapiro CurrentPid = getpid(); 248240266059SGregory Neil Shapiro 248313058a91SGregory Neil Shapiro /* clear the events to turn off SIGALRMs */ 248440266059SGregory Neil Shapiro sm_clear_events(); 248513058a91SGregory Neil Shapiro 24868774250cSGregory Neil Shapiro /* Reset global flags */ 24878774250cSGregory Neil Shapiro RestartRequest = NULL; 248840266059SGregory Neil Shapiro RestartWorkGroup = false; 24898774250cSGregory Neil Shapiro ShutdownRequest = NULL; 24908774250cSGregory Neil Shapiro PendingSignal = 0; 24918774250cSGregory Neil Shapiro 2492c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 249340266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, 249440266059SGregory Neil Shapiro SM_IO_WHAT_FD, 249540266059SGregory Neil Shapiro NULL)); 2496c2aa98e2SPeter Wemm 2497c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */ 249840266059SGregory Neil Shapiro (void) sm_signal(SIGALRM, sm_signal_noop); 249940266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 250040266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_IGN); 250140266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_IGN); 250240266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 250313058a91SGregory Neil Shapiro #ifdef SIGUSR1 250440266059SGregory Neil Shapiro (void) sm_signal(SIGUSR1, sm_signal_noop); 2505*5b0945b5SGregory Neil Shapiro #endif 2506c2aa98e2SPeter Wemm 2507c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 2508c2aa98e2SPeter Wemm stb.st_mode = 0; 2509c2aa98e2SPeter Wemm 2510c2aa98e2SPeter Wemm #if HASSETUSERCONTEXT 2511c2aa98e2SPeter Wemm /* 2512c2aa98e2SPeter Wemm ** Set user resources. 2513c2aa98e2SPeter Wemm */ 2514c2aa98e2SPeter Wemm 2515c2aa98e2SPeter Wemm if (contextaddr != NULL) 2516c2aa98e2SPeter Wemm { 251713bd1963SGregory Neil Shapiro int sucflags; 2518c2aa98e2SPeter Wemm struct passwd *pwd; 2519c2aa98e2SPeter Wemm 2520c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL) 2521c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser); 2522c2aa98e2SPeter Wemm else 2523c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user); 252413bd1963SGregory Neil Shapiro sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; 2525906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETCPUMASK 2526906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETCPUMASK; 2527*5b0945b5SGregory Neil Shapiro # endif 2528906a940eSEdward Tomasz Napierala # ifdef LOGIN_SETLOGINCLASS 2529906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETLOGINCLASS; 2530*5b0945b5SGregory Neil Shapiro # endif 253113bd1963SGregory Neil Shapiro # ifdef LOGIN_SETMAC 253213bd1963SGregory Neil Shapiro sucflags |= LOGIN_SETMAC; 2533*5b0945b5SGregory Neil Shapiro # endif 2534959366dcSGregory Neil Shapiro if (pwd != NULL && 2535959366dcSGregory Neil Shapiro setusercontext(NULL, pwd, pwd->pw_uid, 253613bd1963SGregory Neil Shapiro sucflags) == -1 && 2537959366dcSGregory Neil Shapiro suidwarn) 2538959366dcSGregory Neil Shapiro { 2539959366dcSGregory Neil Shapiro syserr("openmailer: setusercontext() failed"); 2540959366dcSGregory Neil Shapiro exit(EX_TEMPFAIL); 2541959366dcSGregory Neil Shapiro } 2542c2aa98e2SPeter Wemm } 254306f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 2544c2aa98e2SPeter Wemm 254540266059SGregory Neil Shapiro #if HASNICE 2546c2aa98e2SPeter Wemm /* tweak niceness */ 2547c2aa98e2SPeter Wemm if (m->m_nice != 0) 254806f25ae9SGregory Neil Shapiro (void) nice(m->m_nice); 254940266059SGregory Neil Shapiro #endif /* HASNICE */ 2550c2aa98e2SPeter Wemm 2551c2aa98e2SPeter Wemm /* reset group id */ 2552c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 2553e92d3f3fSGregory Neil Shapiro { 2554e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID) 2555e92d3f3fSGregory Neil Shapiro new_gid = RunAsGid; 2556e92d3f3fSGregory Neil Shapiro else 2557c2aa98e2SPeter Wemm new_gid = m->m_gid; 2558e92d3f3fSGregory Neil Shapiro } 2559c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode)) 2560c2aa98e2SPeter Wemm new_gid = stb.st_gid; 2561c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0) 2562c2aa98e2SPeter Wemm { 2563c2aa98e2SPeter Wemm if (!DontInitGroups) 2564c2aa98e2SPeter Wemm { 256540266059SGregory Neil Shapiro user = ctladdr->q_ruser; 256640266059SGregory Neil Shapiro if (user == NULL) 256740266059SGregory Neil Shapiro user = ctladdr->q_user; 2568c2aa98e2SPeter Wemm 256940266059SGregory Neil Shapiro if (initgroups(user, 257040266059SGregory Neil Shapiro ctladdr->q_gid) == -1 257140266059SGregory Neil Shapiro && suidwarn) 257206f25ae9SGregory Neil Shapiro { 2573da7d7b9cSGregory Neil Shapiro syserr("openmailer: initgroups(%s, %ld) failed", 2574da7d7b9cSGregory Neil Shapiro user, (long) ctladdr->q_gid); 257506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 257606f25ae9SGregory Neil Shapiro } 2577c2aa98e2SPeter Wemm } 2578c2aa98e2SPeter Wemm else 2579c2aa98e2SPeter Wemm { 2580c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2581c2aa98e2SPeter Wemm 2582c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid; 258340266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 258440266059SGregory Neil Shapiro && suidwarn) 258506f25ae9SGregory Neil Shapiro { 2586c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 258706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 258806f25ae9SGregory Neil Shapiro } 2589c2aa98e2SPeter Wemm } 2590c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid; 2591c2aa98e2SPeter Wemm } 2592c2aa98e2SPeter Wemm else 2593c2aa98e2SPeter Wemm { 2594c2aa98e2SPeter Wemm if (!DontInitGroups) 2595c2aa98e2SPeter Wemm { 259640266059SGregory Neil Shapiro user = DefUser; 259740266059SGregory Neil Shapiro if (initgroups(DefUser, DefGid) == -1 && 259840266059SGregory Neil Shapiro suidwarn) 259906f25ae9SGregory Neil Shapiro { 2600da7d7b9cSGregory Neil Shapiro syserr("openmailer: initgroups(%s, %ld) failed", 2601da7d7b9cSGregory Neil Shapiro DefUser, (long) DefGid); 260206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 260306f25ae9SGregory Neil Shapiro } 2604c2aa98e2SPeter Wemm } 2605c2aa98e2SPeter Wemm else 2606c2aa98e2SPeter Wemm { 2607c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2608c2aa98e2SPeter Wemm 2609c2aa98e2SPeter Wemm gidset[0] = DefGid; 261040266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 261140266059SGregory Neil Shapiro && suidwarn) 261206f25ae9SGregory Neil Shapiro { 2613c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 261406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 261506f25ae9SGregory Neil Shapiro } 2616c2aa98e2SPeter Wemm } 2617e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID) 2618c2aa98e2SPeter Wemm new_gid = DefGid; 2619c2aa98e2SPeter Wemm else 2620c2aa98e2SPeter Wemm new_gid = m->m_gid; 2621c2aa98e2SPeter Wemm } 262206f25ae9SGregory Neil Shapiro if (new_gid != NO_GID) 262306f25ae9SGregory Neil Shapiro { 262406f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 262506f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) && 262606f25ae9SGregory Neil Shapiro new_gid != getgid() && 262706f25ae9SGregory Neil Shapiro new_gid != getegid()) 262806f25ae9SGregory Neil Shapiro { 262906f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 2630da7d7b9cSGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid, RunAsUid=%ld, new_gid=%ld, gid=%ld, egid=%ld", 2631da7d7b9cSGregory Neil Shapiro (long) RunAsUid, (long) new_gid, 2632da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid()); 263306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 263406f25ae9SGregory Neil Shapiro } 263506f25ae9SGregory Neil Shapiro 263606f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn) 263706f25ae9SGregory Neil Shapiro { 2638c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed", 2639c2aa98e2SPeter Wemm (long) new_gid); 264006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 264106f25ae9SGregory Neil Shapiro } 264206f25ae9SGregory Neil Shapiro } 264306f25ae9SGregory Neil Shapiro 264406f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */ 264506f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL) 264606f25ae9SGregory Neil Shapiro { 2647d0cef73dSGregory Neil Shapiro expand(m->m_rootdir, cbuf, sizeof(cbuf), e); 264806f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 264940266059SGregory Neil Shapiro sm_dprintf("openmailer: chroot %s\n", 265094c01205SGregory Neil Shapiro cbuf); 265194c01205SGregory Neil Shapiro if (chroot(cbuf) < 0) 265206f25ae9SGregory Neil Shapiro { 265306f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)", 265494c01205SGregory Neil Shapiro cbuf); 265506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 265606f25ae9SGregory Neil Shapiro } 265706f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 265806f25ae9SGregory Neil Shapiro { 265906f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)"); 266006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 266106f25ae9SGregory Neil Shapiro } 266206f25ae9SGregory Neil Shapiro } 2663c2aa98e2SPeter Wemm 2664c2aa98e2SPeter Wemm /* reset user id */ 2665c2aa98e2SPeter Wemm endpwent(); 266640266059SGregory Neil Shapiro sm_mbdb_terminate(); 2667c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 266813058a91SGregory Neil Shapiro { 2669e92d3f3fSGregory Neil Shapiro if (m->m_uid == NO_UID) 2670e92d3f3fSGregory Neil Shapiro new_euid = RunAsUid; 2671e92d3f3fSGregory Neil Shapiro else 2672c2aa98e2SPeter Wemm new_euid = m->m_uid; 267313058a91SGregory Neil Shapiro 267413058a91SGregory Neil Shapiro /* 267513058a91SGregory Neil Shapiro ** Undo the effects of the uid change in main 267613058a91SGregory Neil Shapiro ** for signal handling. The real uid may 267713058a91SGregory Neil Shapiro ** be used by mailer in adding a "From " 267813058a91SGregory Neil Shapiro ** line. 267913058a91SGregory Neil Shapiro */ 268013058a91SGregory Neil Shapiro 268113058a91SGregory Neil Shapiro if (RealUid != 0 && RealUid != getuid()) 268240266059SGregory Neil Shapiro { 268340266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID 268440266059SGregory Neil Shapiro # if HASSETREUID 268540266059SGregory Neil Shapiro if (setreuid(RealUid, geteuid()) < 0) 268640266059SGregory Neil Shapiro { 268740266059SGregory Neil Shapiro syserr("openmailer: setreuid(%d, %d) failed", 268840266059SGregory Neil Shapiro (int) RealUid, (int) geteuid()); 268940266059SGregory Neil Shapiro exit(EX_OSERR); 269040266059SGregory Neil Shapiro } 269140266059SGregory Neil Shapiro # endif /* HASSETREUID */ 269240266059SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 269340266059SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID 269413058a91SGregory Neil Shapiro new_ruid = RealUid; 2695*5b0945b5SGregory Neil Shapiro #endif 269640266059SGregory Neil Shapiro } 269713058a91SGregory Neil Shapiro } 2698c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode)) 2699c2aa98e2SPeter Wemm new_ruid = stb.st_uid; 2700c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 2701c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid; 2702e92d3f3fSGregory Neil Shapiro else if (m->m_uid != NO_UID) 2703c2aa98e2SPeter Wemm new_ruid = m->m_uid; 2704c2aa98e2SPeter Wemm else 2705c2aa98e2SPeter Wemm new_ruid = DefUid; 2706605302a5SGregory Neil Shapiro 2707605302a5SGregory Neil Shapiro #if _FFR_USE_SETLOGIN 2708605302a5SGregory Neil Shapiro /* run disconnected from terminal and set login name */ 2709605302a5SGregory Neil Shapiro if (setsid() >= 0 && 2710605302a5SGregory Neil Shapiro ctladdr != NULL && ctladdr->q_uid != 0 && 2711605302a5SGregory Neil Shapiro new_euid == ctladdr->q_uid) 2712605302a5SGregory Neil Shapiro { 2713605302a5SGregory Neil Shapiro struct passwd *pwd; 2714605302a5SGregory Neil Shapiro 2715605302a5SGregory Neil Shapiro pwd = sm_getpwuid(ctladdr->q_uid); 2716605302a5SGregory Neil Shapiro if (pwd != NULL && suidwarn) 2717605302a5SGregory Neil Shapiro (void) setlogin(pwd->pw_name); 2718605302a5SGregory Neil Shapiro endpwent(); 2719605302a5SGregory Neil Shapiro } 2720605302a5SGregory Neil Shapiro #endif /* _FFR_USE_SETLOGIN */ 2721605302a5SGregory Neil Shapiro 2722c2aa98e2SPeter Wemm if (new_euid != NO_UID) 2723c2aa98e2SPeter Wemm { 272406f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid) 272506f25ae9SGregory Neil Shapiro { 272606f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 2727da7d7b9cSGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid, new_euid=%ld, RunAsUid=%ld", 2728da7d7b9cSGregory Neil Shapiro (long) new_euid, (long) RunAsUid); 272906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 273006f25ae9SGregory Neil Shapiro } 273106f25ae9SGregory Neil Shapiro 2732c2aa98e2SPeter Wemm vendor_set_uid(new_euid); 273306f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETEUID 2734c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn) 273506f25ae9SGregory Neil Shapiro { 2736c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed", 2737c2aa98e2SPeter Wemm (long) new_euid); 273806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 273906f25ae9SGregory Neil Shapiro } 274006f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 274106f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETREUID 2742c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 274306f25ae9SGregory Neil Shapiro { 2744c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed", 2745c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid); 274606f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 274706f25ae9SGregory Neil Shapiro } 274806f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 274906f25ae9SGregory Neil Shapiro #if MAILER_SETUID_METHOD == USE_SETUID 2750c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 275106f25ae9SGregory Neil Shapiro { 2752c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2753c2aa98e2SPeter Wemm (long) new_euid); 275406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 275506f25ae9SGregory Neil Shapiro } 275606f25ae9SGregory Neil Shapiro #endif /* MAILER_SETUID_METHOD == USE_SETUID */ 2757c2aa98e2SPeter Wemm } 2758c2aa98e2SPeter Wemm else if (new_ruid != NO_UID) 2759c2aa98e2SPeter Wemm { 2760c2aa98e2SPeter Wemm vendor_set_uid(new_ruid); 2761c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn) 276206f25ae9SGregory Neil Shapiro { 2763c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2764c2aa98e2SPeter Wemm (long) new_ruid); 276506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 276606f25ae9SGregory Neil Shapiro } 2767c2aa98e2SPeter Wemm } 2768c2aa98e2SPeter Wemm 2769c2aa98e2SPeter Wemm if (tTd(11, 2)) 2770da7d7b9cSGregory Neil Shapiro sm_dprintf("openmailer: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n", 2771da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid(), 2772da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid()); 2773c2aa98e2SPeter Wemm 2774c2aa98e2SPeter Wemm /* move into some "safe" directory */ 2775c2aa98e2SPeter Wemm if (m->m_execdir != NULL) 2776c2aa98e2SPeter Wemm { 2777c2aa98e2SPeter Wemm char *q; 2778c2aa98e2SPeter Wemm 2779c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q) 2780c2aa98e2SPeter Wemm { 2781c2aa98e2SPeter Wemm q = strchr(p, ':'); 2782c2aa98e2SPeter Wemm if (q != NULL) 2783c2aa98e2SPeter Wemm *q = '\0'; 2784d0cef73dSGregory Neil Shapiro expand(p, cbuf, sizeof(cbuf), e); 2785c2aa98e2SPeter Wemm if (q != NULL) 2786c2aa98e2SPeter Wemm *q++ = ':'; 2787c2aa98e2SPeter Wemm if (tTd(11, 20)) 278840266059SGregory Neil Shapiro sm_dprintf("openmailer: trydir %s\n", 278994c01205SGregory Neil Shapiro cbuf); 279094c01205SGregory Neil Shapiro if (cbuf[0] != '\0' && 279194c01205SGregory Neil Shapiro chdir(cbuf) >= 0) 2792c2aa98e2SPeter Wemm break; 2793c2aa98e2SPeter Wemm } 2794c2aa98e2SPeter Wemm } 2795c2aa98e2SPeter Wemm 279640266059SGregory Neil Shapiro /* Check safety of program to be run */ 279740266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK; 279840266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, 279940266059SGregory Neil Shapiro DontBlameSendmail)) 280040266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 280140266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, 280240266059SGregory Neil Shapiro DontBlameSendmail)) 280340266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK; 280440266059SGregory Neil Shapiro else 280540266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH; 280640266059SGregory Neil Shapiro ret = safefile(m->m_mailer, getuid(), getgid(), 280740266059SGregory Neil Shapiro user, sff, 0, NULL); 280840266059SGregory Neil Shapiro if (ret != 0) 280940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 281040266059SGregory Neil Shapiro "Warning: program %s unsafe: %s", 281140266059SGregory Neil Shapiro m->m_mailer, sm_errstring(ret)); 281240266059SGregory Neil Shapiro 2813c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */ 2814c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2815c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0) 2816c2aa98e2SPeter Wemm { 2817c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 2818c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2819c2aa98e2SPeter Wemm m->m_name, rpvect[1]); 2820c2aa98e2SPeter Wemm _exit(EX_OSERR); 2821c2aa98e2SPeter Wemm } 2822c2aa98e2SPeter Wemm (void) close(rpvect[1]); 282306f25ae9SGregory Neil Shapiro 2824c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 2825c2aa98e2SPeter Wemm { 2826c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr", 2827c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2828c2aa98e2SPeter Wemm m->m_name); 2829c2aa98e2SPeter Wemm _exit(EX_OSERR); 2830c2aa98e2SPeter Wemm } 2831c2aa98e2SPeter Wemm 2832c2aa98e2SPeter Wemm /* arrange to get standard input */ 2833c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2834c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0) 2835c2aa98e2SPeter Wemm { 2836c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 2837c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2838c2aa98e2SPeter Wemm m->m_name, mpvect[0]); 2839c2aa98e2SPeter Wemm _exit(EX_OSERR); 2840c2aa98e2SPeter Wemm } 2841c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2842c2aa98e2SPeter Wemm 2843c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2844e92d3f3fSGregory Neil Shapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 2845c2aa98e2SPeter Wemm 2846605302a5SGregory Neil Shapiro #if !_FFR_USE_SETLOGIN 2847c2aa98e2SPeter Wemm /* run disconnected from terminal */ 2848c2aa98e2SPeter Wemm (void) setsid(); 2849*5b0945b5SGregory Neil Shapiro #endif 2850c2aa98e2SPeter Wemm 2851c2aa98e2SPeter Wemm /* try to execute the mailer */ 285206f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv, 285306f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron); 285406f25ae9SGregory Neil Shapiro save_errno = errno; 2855c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer); 2856c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) || 285706f25ae9SGregory Neil Shapiro transienterror(save_errno)) 2858c2aa98e2SPeter Wemm _exit(EX_OSERR); 2859c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE); 2860c2aa98e2SPeter Wemm } 2861c2aa98e2SPeter Wemm 2862c2aa98e2SPeter Wemm /* 2863c2aa98e2SPeter Wemm ** Set up return value. 2864c2aa98e2SPeter Wemm */ 2865c2aa98e2SPeter Wemm 2866c2aa98e2SPeter Wemm if (mci == NULL) 2867c2aa98e2SPeter Wemm { 286840266059SGregory Neil Shapiro if (clever) 286940266059SGregory Neil Shapiro { 287040266059SGregory Neil Shapiro /* 287140266059SGregory Neil Shapiro ** Allocate from general heap, not 287240266059SGregory Neil Shapiro ** envelope rpool, because this mci 287340266059SGregory Neil Shapiro ** is going to be cached. 287440266059SGregory Neil Shapiro */ 287540266059SGregory Neil Shapiro 287640266059SGregory Neil Shapiro mci = mci_new(NULL); 287740266059SGregory Neil Shapiro } 287840266059SGregory Neil Shapiro else 287940266059SGregory Neil Shapiro { 288040266059SGregory Neil Shapiro /* 288140266059SGregory Neil Shapiro ** Prevent a storage leak by allocating 288240266059SGregory Neil Shapiro ** this from the envelope rpool. 288340266059SGregory Neil Shapiro */ 288440266059SGregory Neil Shapiro 288540266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 288640266059SGregory Neil Shapiro } 2887c2aa98e2SPeter Wemm } 2888c2aa98e2SPeter Wemm mci->mci_mailer = m; 2889c2aa98e2SPeter Wemm if (clever) 2890c2aa98e2SPeter Wemm { 2891c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2892c2aa98e2SPeter Wemm mci_cache(mci); 2893c2aa98e2SPeter Wemm } 2894c2aa98e2SPeter Wemm else 2895c2aa98e2SPeter Wemm { 2896c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2897c2aa98e2SPeter Wemm } 2898c2aa98e2SPeter Wemm mci->mci_pid = pid; 2899c2aa98e2SPeter Wemm (void) close(mpvect[0]); 290040266059SGregory Neil Shapiro mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2901e92d3f3fSGregory Neil Shapiro (void *) &(mpvect[1]), SM_IO_WRONLY_B, 290240266059SGregory Neil Shapiro NULL); 2903c2aa98e2SPeter Wemm if (mci->mci_out == NULL) 2904c2aa98e2SPeter Wemm { 2905c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d", 2906c2aa98e2SPeter Wemm mpvect[1]); 2907c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2908c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2909c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2910c2aa98e2SPeter Wemm rcode = EX_OSERR; 2911c2aa98e2SPeter Wemm goto give_up; 2912c2aa98e2SPeter Wemm } 291306f25ae9SGregory Neil Shapiro 2914c2aa98e2SPeter Wemm (void) close(rpvect[1]); 291540266059SGregory Neil Shapiro mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2916e92d3f3fSGregory Neil Shapiro (void *) &(rpvect[0]), SM_IO_RDONLY_B, 291740266059SGregory Neil Shapiro NULL); 2918c2aa98e2SPeter Wemm if (mci->mci_in == NULL) 2919c2aa98e2SPeter Wemm { 2920c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d", 2921c2aa98e2SPeter Wemm mpvect[1]); 2922c2aa98e2SPeter Wemm (void) close(rpvect[0]); 292340266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 2924c2aa98e2SPeter Wemm mci->mci_out = NULL; 2925c2aa98e2SPeter Wemm rcode = EX_OSERR; 2926c2aa98e2SPeter Wemm goto give_up; 2927c2aa98e2SPeter Wemm } 2928c2aa98e2SPeter Wemm } 2929c2aa98e2SPeter Wemm 2930c2aa98e2SPeter Wemm /* 2931c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol. 2932c2aa98e2SPeter Wemm */ 2933c2aa98e2SPeter Wemm 2934c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) && 2935c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING)) 2936c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT; 2937c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED) 2938c2aa98e2SPeter Wemm { 293940266059SGregory Neil Shapiro #if STARTTLS || SASL 294040266059SGregory Neil Shapiro char *srvname; 294140266059SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 294240266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */ 294340266059SGregory Neil Shapiro 294440266059SGregory Neil Shapiro #if SASL 2945193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 2946*5b0945b5SGregory Neil Shapiro #endif 294706f25ae9SGregory Neil Shapiro #if STARTTLS 2948193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 2949*5b0945b5SGregory Neil Shapiro #endif 2950193538b7SGregory Neil Shapiro #define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 2951193538b7SGregory Neil Shapiro #define SET_HELO(f) f |= MCIF_ONLY_EHLO 2952193538b7SGregory Neil Shapiro #define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 2953c2aa98e2SPeter Wemm 295440266059SGregory Neil Shapiro #if STARTTLS || SASL 295540266059SGregory Neil Shapiro /* don't use CurHostName, it is changed in many places */ 2956602a2b1bSGregory Neil Shapiro if (mci->mci_host != NULL) 2957602a2b1bSGregory Neil Shapiro { 2958602a2b1bSGregory Neil Shapiro srvname = mci->mci_host; 2959*5b0945b5SGregory Neil Shapiro RM_TRAIL_DOT(srvname); 2960602a2b1bSGregory Neil Shapiro } 296140266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 2962602a2b1bSGregory Neil Shapiro { 296340266059SGregory Neil Shapiro srvname = mci->mci_mailer->m_name; 2964602a2b1bSGregory Neil Shapiro dotpos = -1; 2965602a2b1bSGregory Neil Shapiro } 296606f25ae9SGregory Neil Shapiro else 296706f25ae9SGregory Neil Shapiro { 296840266059SGregory Neil Shapiro srvname = "local"; 296940266059SGregory Neil Shapiro dotpos = -1; 2970193538b7SGregory Neil Shapiro } 297106f25ae9SGregory Neil Shapiro 297240266059SGregory Neil Shapiro /* don't set {server_name} to NULL or "": see getauth() */ 297340266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"), 297440266059SGregory Neil Shapiro srvname); 297540266059SGregory Neil Shapiro 297640266059SGregory Neil Shapiro /* CurHostAddr is set by makeconnection() and mci_get() */ 297740266059SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0) 297840266059SGregory Neil Shapiro { 297940266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, 298040266059SGregory Neil Shapiro macid("{server_addr}"), 298140266059SGregory Neil Shapiro anynet_ntoa(&CurHostAddr)); 298240266059SGregory Neil Shapiro } 298340266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 298440266059SGregory Neil Shapiro { 298540266059SGregory Neil Shapiro /* mailer name is unique, use it as address */ 298640266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 298740266059SGregory Neil Shapiro macid("{server_addr}"), 298840266059SGregory Neil Shapiro mci->mci_mailer->m_name); 298940266059SGregory Neil Shapiro } 299040266059SGregory Neil Shapiro else 299140266059SGregory Neil Shapiro { 299240266059SGregory Neil Shapiro /* don't set it to NULL or "": see getauth() */ 299340266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 299440266059SGregory Neil Shapiro macid("{server_addr}"), "0"); 299540266059SGregory Neil Shapiro } 299640266059SGregory Neil Shapiro 2997*5b0945b5SGregory Neil Shapiro # if DANE 2998*5b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_host); 2999*5b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_sni); 3000*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_fp[0] = '\0'; 3001*5b0945b5SGregory Neil Shapiro if (ste != NULL && ste->s_tlsa != NULL && 3002*5b0945b5SGregory Neil Shapiro ste->s_tlsa->dane_tlsa_sni != NULL) 3003*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_sni = sm_strdup(ste->s_tlsa->dane_tlsa_sni); 3004*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname); 3005*5b0945b5SGregory Neil Shapiro # endif 3006*5b0945b5SGregory Neil Shapiro 300740266059SGregory Neil Shapiro /* undo change of srvname (mci->mci_host) */ 3008*5b0945b5SGregory Neil Shapiro FIX_TRAIL_DOT(srvname); 300940266059SGregory Neil Shapiro 301040266059SGregory Neil Shapiro reconnect: /* after switching to an encrypted connection */ 3011*5b0945b5SGregory Neil Shapiro # if DANE 3012*5b0945b5SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags)) 3013*5b0945b5SGregory Neil Shapiro { 3014*5b0945b5SGregory Neil Shapiro /* use a "reset" function? */ 3015*5b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_host); 3016*5b0945b5SGregory Neil Shapiro SM_FREE(dane_vrfy_ctx.dane_vrfy_sni); 3017*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_fp[0] = '\0'; 3018*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx.dane_vrfy_res = 0; 3019*5b0945b5SGregory Neil Shapiro } 3020*5b0945b5SGregory Neil Shapiro # endif 3021*5b0945b5SGregory Neil Shapiro 302240266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */ 302340266059SGregory Neil Shapiro 302440266059SGregory Neil Shapiro /* set the current connection information */ 302540266059SGregory Neil Shapiro e->e_mci = mci; 302640266059SGregory Neil Shapiro #if SASL 302740266059SGregory Neil Shapiro mci->mci_saslcap = NULL; 3028*5b0945b5SGregory Neil Shapiro #endif 302940266059SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 303040266059SGregory Neil Shapiro CLR_HELO(mci->mci_flags); 303140266059SGregory Neil Shapiro 303240266059SGregory Neil Shapiro if (IS_DLVR_RETURN(e)) 303340266059SGregory Neil Shapiro { 303440266059SGregory Neil Shapiro /* 303540266059SGregory Neil Shapiro ** Check whether other side can deliver e-mail 303640266059SGregory Neil Shapiro ** fast enough 303740266059SGregory Neil Shapiro */ 303840266059SGregory Neil Shapiro 303940266059SGregory Neil Shapiro if (!bitset(MCIF_DLVR_BY, mci->mci_flags)) 304040266059SGregory Neil Shapiro { 304140266059SGregory Neil Shapiro e->e_status = "5.4.7"; 304240266059SGregory Neil Shapiro usrerrenh(e->e_status, 304340266059SGregory Neil Shapiro "554 Server does not support Deliver By"); 304440266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 304540266059SGregory Neil Shapiro goto give_up; 304640266059SGregory Neil Shapiro } 304740266059SGregory Neil Shapiro if (e->e_deliver_by > 0 && 304840266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime) < 304940266059SGregory Neil Shapiro mci->mci_min_by) 305040266059SGregory Neil Shapiro { 305140266059SGregory Neil Shapiro e->e_status = "5.4.7"; 305240266059SGregory Neil Shapiro usrerrenh(e->e_status, 305340266059SGregory Neil Shapiro "554 Message can't be delivered in time; %ld < %ld", 3054*5b0945b5SGregory Neil Shapiro e->e_deliver_by - (long) (curtime() - 3055*5b0945b5SGregory Neil Shapiro e->e_ctime), 305640266059SGregory Neil Shapiro mci->mci_min_by); 305740266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 305840266059SGregory Neil Shapiro goto give_up; 305940266059SGregory Neil Shapiro } 306040266059SGregory Neil Shapiro } 306140266059SGregory Neil Shapiro 306240266059SGregory Neil Shapiro #if STARTTLS 306340266059SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */ 306440266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 306540266059SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags)) 306640266059SGregory Neil Shapiro { 306740266059SGregory Neil Shapiro int olderrors; 306840266059SGregory Neil Shapiro bool usetls; 306940266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 307040266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 307140266059SGregory Neil Shapiro char *host = NULL; 307240266059SGregory Neil Shapiro 307340266059SGregory Neil Shapiro rcode = EX_OK; 307440266059SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags); 307540266059SGregory Neil Shapiro if (usetls) 307640266059SGregory Neil Shapiro usetls = !iscltflgset(e, D_NOTLS); 3077*5b0945b5SGregory Neil Shapiro if (usetls) 3078*5b0945b5SGregory Neil Shapiro usetls = tlsstate == 0; 307940266059SGregory Neil Shapiro 3080d0cef73dSGregory Neil Shapiro host = macvalue(macid("{server_name}"), e); 308140266059SGregory Neil Shapiro if (usetls) 308240266059SGregory Neil Shapiro { 308340266059SGregory Neil Shapiro olderrors = Errors; 308440266059SGregory Neil Shapiro QuickAbort = false; 308540266059SGregory Neil Shapiro SuprErrs = true; 3086959366dcSGregory Neil Shapiro if (rscheck("try_tls", host, NULL, e, 3087da7d7b9cSGregory Neil Shapiro RSF_RMCOMM, 7, host, NOQID, NULL, 3088da7d7b9cSGregory Neil Shapiro NULL) != EX_OK 308940266059SGregory Neil Shapiro || Errors > olderrors) 3090d0cef73dSGregory Neil Shapiro { 309140266059SGregory Neil Shapiro usetls = false; 3092d0cef73dSGregory Neil Shapiro } 309340266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 309440266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 309540266059SGregory Neil Shapiro } 309640266059SGregory Neil Shapiro 309706f25ae9SGregory Neil Shapiro if (usetls) 309806f25ae9SGregory Neil Shapiro { 3099*5b0945b5SGregory Neil Shapiro if ((rcode = starttls(m, mci, e 3100*5b0945b5SGregory Neil Shapiro # if DANE 3101*5b0945b5SGregory Neil Shapiro , &dane_vrfy_ctx 3102*5b0945b5SGregory Neil Shapiro # endif 3103*5b0945b5SGregory Neil Shapiro )) == EX_OK) 310406f25ae9SGregory Neil Shapiro { 310506f25ae9SGregory Neil Shapiro /* start again without STARTTLS */ 310606f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT; 310706f25ae9SGregory Neil Shapiro } 310806f25ae9SGregory Neil Shapiro else 310906f25ae9SGregory Neil Shapiro { 311006f25ae9SGregory Neil Shapiro char *s; 311106f25ae9SGregory Neil Shapiro 311206f25ae9SGregory Neil Shapiro /* 31139bd497b8SGregory Neil Shapiro ** TLS negotiation failed, what to do? 311406f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection 311506f25ae9SGregory Neil Shapiro ** or abort? How to decide? 311606f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset. 311706f25ae9SGregory Neil Shapiro */ 311840266059SGregory Neil Shapiro 311906f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS; 312006f25ae9SGregory Neil Shapiro switch (rcode) 312106f25ae9SGregory Neil Shapiro { 312206f25ae9SGregory Neil Shapiro case EX_TEMPFAIL: 312306f25ae9SGregory Neil Shapiro s = "TEMP"; 312406f25ae9SGregory Neil Shapiro break; 312506f25ae9SGregory Neil Shapiro case EX_USAGE: 312606f25ae9SGregory Neil Shapiro s = "USAGE"; 312706f25ae9SGregory Neil Shapiro break; 312806f25ae9SGregory Neil Shapiro case EX_PROTOCOL: 312906f25ae9SGregory Neil Shapiro s = "PROTOCOL"; 313006f25ae9SGregory Neil Shapiro break; 313106f25ae9SGregory Neil Shapiro case EX_SOFTWARE: 313206f25ae9SGregory Neil Shapiro s = "SOFTWARE"; 313306f25ae9SGregory Neil Shapiro break; 31344e4196cbSGregory Neil Shapiro case EX_UNAVAILABLE: 31354e4196cbSGregory Neil Shapiro s = "NONE"; 31364e4196cbSGregory Neil Shapiro break; 313706f25ae9SGregory Neil Shapiro 313806f25ae9SGregory Neil Shapiro /* everything else is a failure */ 313906f25ae9SGregory Neil Shapiro default: 314006f25ae9SGregory Neil Shapiro s = "FAILURE"; 314106f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL; 314206f25ae9SGregory Neil Shapiro } 314340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 314440266059SGregory Neil Shapiro macid("{verify}"), s); 314506f25ae9SGregory Neil Shapiro } 314606f25ae9SGregory Neil Shapiro } 314706f25ae9SGregory Neil Shapiro else 3148*5b0945b5SGregory Neil Shapiro { 3149*5b0945b5SGregory Neil Shapiro p = tlsstate == 0 ? "NONE": "CLEAR"; 3150*5b0945b5SGregory Neil Shapiro # if DANE 3151*5b0945b5SGregory Neil Shapiro /* 3152*5b0945b5SGregory Neil Shapiro ** TLSA found but STARTTLS not offered? 3153*5b0945b5SGregory Neil Shapiro ** What is the best way to "fail"? 3154*5b0945b5SGregory Neil Shapiro ** XXX: check expiration! 3155*5b0945b5SGregory Neil Shapiro */ 3156*5b0945b5SGregory Neil Shapiro 3157*5b0945b5SGregory Neil Shapiro if (!bitset(MCIF_TLS, mci->mci_flags) && 3158*5b0945b5SGregory Neil Shapiro ste != NULL && 3159*5b0945b5SGregory Neil Shapiro ste->s_tlsa != NULL && 3160*5b0945b5SGregory Neil Shapiro ste->s_tlsa->dane_tlsa_n > 0) 3161*5b0945b5SGregory Neil Shapiro { 3162*5b0945b5SGregory Neil Shapiro if (LogLevel > 8) 3163*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID, 3164*5b0945b5SGregory Neil Shapiro "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but no STARTTLS available", 3165*5b0945b5SGregory Neil Shapiro host); 3166*5b0945b5SGregory Neil Shapiro /* XXX include TLSA RR from DNS? */ 3167*5b0945b5SGregory Neil Shapiro 3168*5b0945b5SGregory Neil Shapiro p = "DANE_FAIL"; 3169*5b0945b5SGregory Neil Shapiro } 3170*5b0945b5SGregory Neil Shapiro # endif /* DANE */ 317140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 3172*5b0945b5SGregory Neil Shapiro macid("{verify}"), p); 3173*5b0945b5SGregory Neil Shapiro } 317406f25ae9SGregory Neil Shapiro olderrors = Errors; 317540266059SGregory Neil Shapiro QuickAbort = false; 317640266059SGregory Neil Shapiro SuprErrs = true; 317706f25ae9SGregory Neil Shapiro 317806f25ae9SGregory Neil Shapiro /* 317906f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special: 31809bd497b8SGregory Neil Shapiro ** the TLS negotiation failed 318106f25ae9SGregory Neil Shapiro ** we have to drop the connection no matter what 318206f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance 318306f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate 318406f25ae9SGregory Neil Shapiro ** error code. 318506f25ae9SGregory Neil Shapiro */ 318640266059SGregory Neil Shapiro 318706f25ae9SGregory Neil Shapiro if (rscheck("tls_server", 318840266059SGregory Neil Shapiro macvalue(macid("{verify}"), e), 3189959366dcSGregory Neil Shapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 5, 3190da7d7b9cSGregory Neil Shapiro host, NOQID, NULL, NULL) != EX_OK || 319106f25ae9SGregory Neil Shapiro Errors > olderrors || 319206f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE) 319306f25ae9SGregory Neil Shapiro { 319406f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN]; 319506f25ae9SGregory Neil Shapiro extern char MsgBuf[]; 319606f25ae9SGregory Neil Shapiro 319706f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) && 319806f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 319906f25ae9SGregory Neil Shapiro { 320040266059SGregory Neil Shapiro p = sm_rpool_strdup_x(e->e_rpool, 320140266059SGregory Neil Shapiro MsgBuf); 320206f25ae9SGregory Neil Shapiro } 320306f25ae9SGregory Neil Shapiro else 320406f25ae9SGregory Neil Shapiro { 320506f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated."; 320640266059SGregory Neil Shapiro (void) sm_strlcpy(enhsc, "4.7.0", 3207d0cef73dSGregory Neil Shapiro sizeof(enhsc)); 320806f25ae9SGregory Neil Shapiro } 320906f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 321006f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 321106f25ae9SGregory Neil Shapiro 321206f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE) 321306f25ae9SGregory Neil Shapiro { 321406f25ae9SGregory Neil Shapiro /* drop the connection */ 321506f25ae9SGregory Neil Shapiro mci->mci_state = MCIS_QUITING; 321606f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 321706f25ae9SGregory Neil Shapiro { 321840266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, 321940266059SGregory Neil Shapiro SM_TIME_DEFAULT); 322006f25ae9SGregory Neil Shapiro mci->mci_in = NULL; 322106f25ae9SGregory Neil Shapiro } 322206f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 322306f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv); 3224*5b0945b5SGregory Neil Shapiro 3225*5b0945b5SGregory Neil Shapiro if ((TLSFallbacktoClear || 3226*5b0945b5SGregory Neil Shapiro SM_TLSI_IS(&(mci->mci_tlsi), 3227*5b0945b5SGregory Neil Shapiro TLSI_FL_FB2CLR)) && 3228*5b0945b5SGregory Neil Shapiro !SM_TLSI_IS(&(mci->mci_tlsi), 3229*5b0945b5SGregory Neil Shapiro TLSI_FL_NOFB2CLR) 3230*5b0945b5SGregory Neil Shapiro # if DANE 3231*5b0945b5SGregory Neil Shapiro && dane_vrfy_ctx.dane_vrfy_chk != 3232*5b0945b5SGregory Neil Shapiro DANE_SECURE 3233*5b0945b5SGregory Neil Shapiro # endif 3234*5b0945b5SGregory Neil Shapiro ) 3235*5b0945b5SGregory Neil Shapiro { 3236*5b0945b5SGregory Neil Shapiro ++tlsstate; 3237*5b0945b5SGregory Neil Shapiro } 323806f25ae9SGregory Neil Shapiro } 323906f25ae9SGregory Neil Shapiro else 324006f25ae9SGregory Neil Shapiro { 324106f25ae9SGregory Neil Shapiro /* abort transfer */ 324206f25ae9SGregory Neil Shapiro smtpquit(m, mci, e); 324306f25ae9SGregory Neil Shapiro } 324406f25ae9SGregory Neil Shapiro 3245193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 3246193538b7SGregory Neil Shapiro mci->mci_errno = 0; 3247193538b7SGregory Neil Shapiro 324806f25ae9SGregory Neil Shapiro /* temp or permanent failure? */ 324906f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL 325006f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE; 325140266059SGregory Neil Shapiro mci_setstat(mci, rcode, enhsc, p); 325206f25ae9SGregory Neil Shapiro 325306f25ae9SGregory Neil Shapiro /* 325406f25ae9SGregory Neil Shapiro ** hack to get the error message into 325506f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse()) 325606f25ae9SGregory Neil Shapiro */ 325740266059SGregory Neil Shapiro 325840266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, p, 3259d0cef73dSGregory Neil Shapiro sizeof(SmtpError)); 326006f25ae9SGregory Neil Shapiro } 3261d0cef73dSGregory Neil Shapiro else if (mci->mci_state == MCIS_CLOSED) 3262d0cef73dSGregory Neil Shapiro { 3263d0cef73dSGregory Neil Shapiro /* connection close caused by 421 */ 3264d0cef73dSGregory Neil Shapiro mci->mci_errno = 0; 3265d0cef73dSGregory Neil Shapiro rcode = EX_TEMPFAIL; 3266d0cef73dSGregory Neil Shapiro mci_setstat(mci, rcode, NULL, "421"); 3267d0cef73dSGregory Neil Shapiro } 3268d0cef73dSGregory Neil Shapiro else 3269d0cef73dSGregory Neil Shapiro rcode = 0; 3270d0cef73dSGregory Neil Shapiro 327106f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 327206f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 3273193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) && 3274193538b7SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED) 327506f25ae9SGregory Neil Shapiro { 3276193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 32776f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 327806f25ae9SGregory Neil Shapiro goto reconnect; 327906f25ae9SGregory Neil Shapiro } 3280*5b0945b5SGregory Neil Shapiro if (tlsstate == 1) 3281*5b0945b5SGregory Neil Shapiro { 3282*5b0945b5SGregory Neil Shapiro if (tTd(11, 1)) 3283*5b0945b5SGregory Neil Shapiro { 3284*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_DEBUG, NOQID, 3285*5b0945b5SGregory Neil Shapiro "STARTTLS=client, relay=%.100s, tlsstate=%d, status=trying_again", 3286*5b0945b5SGregory Neil Shapiro mci->mci_host, tlsstate); 3287*5b0945b5SGregory Neil Shapiro mci_dump(NULL, mci, true); 3288*5b0945b5SGregory Neil Shapiro } 3289*5b0945b5SGregory Neil Shapiro ++tlsstate; 3290*5b0945b5SGregory Neil Shapiro 3291*5b0945b5SGregory Neil Shapiro /* 3292*5b0945b5SGregory Neil Shapiro ** Fake the status so a new connection is 3293*5b0945b5SGregory Neil Shapiro ** tried, otherwise the TLS error will 3294*5b0945b5SGregory Neil Shapiro ** "persist" during this delivery attempt. 3295*5b0945b5SGregory Neil Shapiro */ 3296*5b0945b5SGregory Neil Shapiro 3297*5b0945b5SGregory Neil Shapiro mci->mci_errno = 0; 3298*5b0945b5SGregory Neil Shapiro rcode = EX_OK; 3299*5b0945b5SGregory Neil Shapiro mci_setstat(mci, rcode, NULL, NULL); 3300*5b0945b5SGregory Neil Shapiro goto one_last_try; 3301*5b0945b5SGregory Neil Shapiro } 330206f25ae9SGregory Neil Shapiro } 330306f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 330406f25ae9SGregory Neil Shapiro #if SASL 330506f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */ 330606f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 330706f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL && 330840266059SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH)) 330906f25ae9SGregory Neil Shapiro { 331040266059SGregory Neil Shapiro /* Should we require some minimum authentication? */ 331140266059SGregory Neil Shapiro if ((ret = smtpauth(m, mci, e)) == EX_OK) 331206f25ae9SGregory Neil Shapiro { 331306f25ae9SGregory Neil Shapiro int result; 331440266059SGregory Neil Shapiro sasl_ssf_t *ssf = NULL; 331506f25ae9SGregory Neil Shapiro 331640266059SGregory Neil Shapiro /* Get security strength (features) */ 331706f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF, 331894c01205SGregory Neil Shapiro # if SASL >= 20000 331994c01205SGregory Neil Shapiro (const void **) &ssf); 3320*5b0945b5SGregory Neil Shapiro # else 332106f25ae9SGregory Neil Shapiro (void **) &ssf); 3322*5b0945b5SGregory Neil Shapiro # endif 332340266059SGregory Neil Shapiro 332440266059SGregory Neil Shapiro /* XXX authid? */ 332506f25ae9SGregory Neil Shapiro if (LogLevel > 9) 332606f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 332740266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, mech=%.16s, bits=%d", 332806f25ae9SGregory Neil Shapiro mci->mci_host, 332940266059SGregory Neil Shapiro macvalue(macid("{auth_type}"), e), 333040266059SGregory Neil Shapiro result == SASL_OK ? *ssf : 0); 33318774250cSGregory Neil Shapiro 333206f25ae9SGregory Neil Shapiro /* 333340266059SGregory Neil Shapiro ** Only switch to encrypted connection 333406f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated 333506f25ae9SGregory Neil Shapiro */ 333640266059SGregory Neil Shapiro 333706f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0) 333806f25ae9SGregory Neil Shapiro { 3339af9557fdSGregory Neil Shapiro int tmo; 3340af9557fdSGregory Neil Shapiro 334106f25ae9SGregory Neil Shapiro /* 334240266059SGregory Neil Shapiro ** Convert I/O layer to use SASL. 334340266059SGregory Neil Shapiro ** If the call fails, the connection 334440266059SGregory Neil Shapiro ** is aborted. 334506f25ae9SGregory Neil Shapiro */ 334640266059SGregory Neil Shapiro 3347af9557fdSGregory Neil Shapiro tmo = DATA_PROGRESS_TIMEOUT * 1000; 334840266059SGregory Neil Shapiro if (sfdcsasl(&mci->mci_in, 334940266059SGregory Neil Shapiro &mci->mci_out, 3350af9557fdSGregory Neil Shapiro mci->mci_conn, tmo) == 0) 335106f25ae9SGregory Neil Shapiro { 33526f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 335340266059SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT| 335440266059SGregory Neil Shapiro MCIF_ONLY_EHLO; 335506f25ae9SGregory Neil Shapiro goto reconnect; 335606f25ae9SGregory Neil Shapiro } 335740266059SGregory Neil Shapiro syserr("AUTH TLS switch failed in client"); 335806f25ae9SGregory Neil Shapiro } 335906f25ae9SGregory Neil Shapiro /* else? XXX */ 336006f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 336106f25ae9SGregory Neil Shapiro 336206f25ae9SGregory Neil Shapiro } 336340266059SGregory Neil Shapiro else if (ret == EX_TEMPFAIL) 336440266059SGregory Neil Shapiro { 336540266059SGregory Neil Shapiro if (LogLevel > 8) 336640266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 336740266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, temporary failure, connection abort", 336840266059SGregory Neil Shapiro mci->mci_host); 336940266059SGregory Neil Shapiro smtpquit(m, mci, e); 337040266059SGregory Neil Shapiro 337140266059SGregory Neil Shapiro /* avoid bogus error msg */ 337240266059SGregory Neil Shapiro mci->mci_errno = 0; 337340266059SGregory Neil Shapiro rcode = EX_TEMPFAIL; 3374e92d3f3fSGregory Neil Shapiro mci_setstat(mci, rcode, "4.3.0", p); 337540266059SGregory Neil Shapiro 337640266059SGregory Neil Shapiro /* 337740266059SGregory Neil Shapiro ** hack to get the error message into 337840266059SGregory Neil Shapiro ** the envelope (done in giveresponse()) 337940266059SGregory Neil Shapiro */ 338040266059SGregory Neil Shapiro 338140266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, 338240266059SGregory Neil Shapiro "Temporary AUTH failure", 3383d0cef73dSGregory Neil Shapiro sizeof(SmtpError)); 338440266059SGregory Neil Shapiro } 338506f25ae9SGregory Neil Shapiro } 338606f25ae9SGregory Neil Shapiro #endif /* SASL */ 338706f25ae9SGregory Neil Shapiro } 338806f25ae9SGregory Neil Shapiro 3389c2aa98e2SPeter Wemm do_transfer: 3390c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 3391c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 3392c2aa98e2SPeter Wemm 3393c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 3394c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 3395c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags)) 3396c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7; 3397c2aa98e2SPeter Wemm 3398c2aa98e2SPeter Wemm #if MIME7TO8 3399c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) && 3400c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) && 3401c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 340240266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 340340266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 3404c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 3405c2aa98e2SPeter Wemm { 3406c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 3407c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 340840266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 3409c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 3410c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8; 3411c2aa98e2SPeter Wemm } 341206f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 3413c2aa98e2SPeter Wemm 3414c2aa98e2SPeter Wemm if (tTd(11, 1)) 3415c2aa98e2SPeter Wemm { 341640266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 3417e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 3418c2aa98e2SPeter Wemm } 3419c2aa98e2SPeter Wemm 342040266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE 342140266059SGregory Neil Shapiro /* 342240266059SGregory Neil Shapiro ** See if we know the maximum size and 342340266059SGregory Neil Shapiro ** abort if the message is too big. 342440266059SGregory Neil Shapiro ** 342540266059SGregory Neil Shapiro ** NOTE: _FFR_CLIENT_SIZE is untested. 342640266059SGregory Neil Shapiro */ 342740266059SGregory Neil Shapiro 342840266059SGregory Neil Shapiro if (bitset(MCIF_SIZE, mci->mci_flags) && 342940266059SGregory Neil Shapiro mci->mci_maxsize > 0 && 343040266059SGregory Neil Shapiro e->e_msgsize > mci->mci_maxsize) 343140266059SGregory Neil Shapiro { 343240266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 343340266059SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags)) 343440266059SGregory Neil Shapiro e->e_status = "5.2.3"; 343540266059SGregory Neil Shapiro else 343640266059SGregory Neil Shapiro e->e_status = "5.3.4"; 343740266059SGregory Neil Shapiro 343840266059SGregory Neil Shapiro usrerrenh(e->e_status, 343940266059SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 344040266059SGregory Neil Shapiro mci->mci_maxsize); 344140266059SGregory Neil Shapiro rcode = EX_DATAERR; 344240266059SGregory Neil Shapiro 344340266059SGregory Neil Shapiro /* Need an e_message for error */ 3444d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError), 344540266059SGregory Neil Shapiro "Message is too large; %ld bytes max", 344640266059SGregory Neil Shapiro mci->mci_maxsize); 344740266059SGregory Neil Shapiro goto give_up; 344840266059SGregory Neil Shapiro } 344940266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */ 345040266059SGregory Neil Shapiro 3451c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 3452c2aa98e2SPeter Wemm { 3453c2aa98e2SPeter Wemm /* couldn't open the mailer */ 3454c2aa98e2SPeter Wemm rcode = mci->mci_exitstat; 3455c2aa98e2SPeter Wemm errno = mci->mci_errno; 3456602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno); 3457c2aa98e2SPeter Wemm if (rcode == EX_OK) 3458c2aa98e2SPeter Wemm { 3459c2aa98e2SPeter Wemm /* shouldn't happen */ 346006f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 346140266059SGregory Neil Shapiro (unsigned long) mci, rcode, errno, 346240266059SGregory Neil Shapiro mci->mci_state, firstsig); 3463e92d3f3fSGregory Neil Shapiro mci_dump_all(smioout, true); 3464c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 3465c2aa98e2SPeter Wemm } 346606f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum) 3467c2aa98e2SPeter Wemm { 3468c2aa98e2SPeter Wemm /* try next MX site */ 3469c2aa98e2SPeter Wemm goto tryhost; 3470c2aa98e2SPeter Wemm } 3471c2aa98e2SPeter Wemm } 3472c2aa98e2SPeter Wemm else if (!clever) 3473c2aa98e2SPeter Wemm { 34744e4196cbSGregory Neil Shapiro bool ok; 34754e4196cbSGregory Neil Shapiro 3476c2aa98e2SPeter Wemm /* 3477c2aa98e2SPeter Wemm ** Format and send message. 3478c2aa98e2SPeter Wemm */ 3479c2aa98e2SPeter Wemm 34804e4196cbSGregory Neil Shapiro rcode = EX_OK; 34814e4196cbSGregory Neil Shapiro errno = 0; 34824e4196cbSGregory Neil Shapiro ok = putfromline(mci, e); 34834e4196cbSGregory Neil Shapiro if (ok) 34844e4196cbSGregory Neil Shapiro ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 34854e4196cbSGregory Neil Shapiro if (ok) 34864e4196cbSGregory Neil Shapiro ok = (*e->e_putbody)(mci, e, NULL); 3487ffb83623SGregory Neil Shapiro if (ok && bitset(MCIF_INLONGLINE, mci->mci_flags)) 3488ffb83623SGregory Neil Shapiro ok = putline("", mci); 3489c2aa98e2SPeter Wemm 34904e4196cbSGregory Neil Shapiro /* 34914e4196cbSGregory Neil Shapiro ** Ignore an I/O error that was caused by EPIPE. 34924e4196cbSGregory Neil Shapiro ** Some broken mailers don't read the entire body 34934e4196cbSGregory Neil Shapiro ** but just exit() thus causing an I/O error. 34944e4196cbSGregory Neil Shapiro */ 34954e4196cbSGregory Neil Shapiro 34964e4196cbSGregory Neil Shapiro if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE)) 34974e4196cbSGregory Neil Shapiro ok = true; 34984e4196cbSGregory Neil Shapiro 34994e4196cbSGregory Neil Shapiro /* (always) get the exit status */ 3500c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv); 35014e4196cbSGregory Neil Shapiro if (!ok) 35024e4196cbSGregory Neil Shapiro rcode = EX_TEMPFAIL; 350340266059SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 3504602a2b1bSGregory Neil Shapiro { 3505602a2b1bSGregory Neil Shapiro /* 3506602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display. 3507602a2b1bSGregory Neil Shapiro ** We set SmtpError as 3508602a2b1bSGregory Neil Shapiro */ 3509602a2b1bSGregory Neil Shapiro 3510d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError), 3511602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL", 3512602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer); 3513602a2b1bSGregory Neil Shapiro } 3514c2aa98e2SPeter Wemm } 3515c2aa98e2SPeter Wemm else 3516c2aa98e2SPeter Wemm { 3517c2aa98e2SPeter Wemm /* 3518c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol 3519c2aa98e2SPeter Wemm */ 3520c2aa98e2SPeter Wemm 352140266059SGregory Neil Shapiro /* XXX this isn't pipelined... */ 3522c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e); 3523c2aa98e2SPeter Wemm if (rcode == EX_OK) 3524c2aa98e2SPeter Wemm { 3525c2aa98e2SPeter Wemm register int i; 352640266059SGregory Neil Shapiro #if PIPELINING 352740266059SGregory Neil Shapiro ADDRESS *volatile pchain; 3528*5b0945b5SGregory Neil Shapiro #endif 3529c2aa98e2SPeter Wemm 3530c2aa98e2SPeter Wemm /* send the recipient list */ 3531c2aa98e2SPeter Wemm tobuf[0] = '\0'; 353240266059SGregory Neil Shapiro mci->mci_retryrcpt = false; 353340266059SGregory Neil Shapiro mci->mci_tolist = tobuf; 353440266059SGregory Neil Shapiro #if PIPELINING 353540266059SGregory Neil Shapiro pchain = NULL; 353640266059SGregory Neil Shapiro mci->mci_nextaddr = NULL; 3537*5b0945b5SGregory Neil Shapiro #endif 353806f25ae9SGregory Neil Shapiro 3539c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3540c2aa98e2SPeter Wemm { 354140266059SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state)) 3542c2aa98e2SPeter Wemm continue; 354306f25ae9SGregory Neil Shapiro 354440266059SGregory Neil Shapiro /* mark recipient state as "ok so far" */ 354540266059SGregory Neil Shapiro to->q_state = QS_OK; 354640266059SGregory Neil Shapiro e->e_to = to->q_paddr; 354706f25ae9SGregory Neil Shapiro #if STARTTLS 354806f25ae9SGregory Neil Shapiro i = rscheck("tls_rcpt", to->q_user, NULL, e, 3549959366dcSGregory Neil Shapiro RSF_RMCOMM|RSF_COUNT, 3, 3550da7d7b9cSGregory Neil Shapiro mci->mci_host, e->e_id, NULL, NULL); 355106f25ae9SGregory Neil Shapiro if (i != EX_OK) 3552c2aa98e2SPeter Wemm { 355340266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 355440266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 355540266059SGregory Neil Shapiro ctladdr, xstart, e, to); 355640266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 355740266059SGregory Neil Shapiro { 355840266059SGregory Neil Shapiro mci->mci_retryrcpt = true; 355940266059SGregory Neil Shapiro to->q_state = QS_RETRY; 356040266059SGregory Neil Shapiro } 356106f25ae9SGregory Neil Shapiro continue; 356206f25ae9SGregory Neil Shapiro } 356306f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 356406f25ae9SGregory Neil Shapiro 356540266059SGregory Neil Shapiro i = smtprcpt(to, m, mci, e, ctladdr, xstart); 356640266059SGregory Neil Shapiro #if PIPELINING 356740266059SGregory Neil Shapiro if (i == EX_OK && 356840266059SGregory Neil Shapiro bitset(MCIF_PIPELINED, mci->mci_flags)) 356906f25ae9SGregory Neil Shapiro { 357040266059SGregory Neil Shapiro /* 357140266059SGregory Neil Shapiro ** Add new element to list of 357240266059SGregory Neil Shapiro ** recipients for pipelining. 357340266059SGregory Neil Shapiro */ 357440266059SGregory Neil Shapiro 357540266059SGregory Neil Shapiro to->q_pchain = NULL; 357640266059SGregory Neil Shapiro if (mci->mci_nextaddr == NULL) 357740266059SGregory Neil Shapiro mci->mci_nextaddr = to; 357840266059SGregory Neil Shapiro if (pchain == NULL) 357940266059SGregory Neil Shapiro pchain = to; 3580c2aa98e2SPeter Wemm else 3581c2aa98e2SPeter Wemm { 358240266059SGregory Neil Shapiro pchain->q_pchain = to; 358340266059SGregory Neil Shapiro pchain = pchain->q_pchain; 358440266059SGregory Neil Shapiro } 358540266059SGregory Neil Shapiro } 358640266059SGregory Neil Shapiro #endif /* PIPELINING */ 358740266059SGregory Neil Shapiro if (i != EX_OK) 358840266059SGregory Neil Shapiro { 358940266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 359040266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 359140266059SGregory Neil Shapiro ctladdr, xstart, e, to); 359240266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 359340266059SGregory Neil Shapiro to->q_state = QS_RETRY; 3594c2aa98e2SPeter Wemm } 3595c2aa98e2SPeter Wemm } 3596c2aa98e2SPeter Wemm 359740266059SGregory Neil Shapiro /* No recipients in list and no missing responses? */ 359840266059SGregory Neil Shapiro if (tobuf[0] == '\0' 359940266059SGregory Neil Shapiro #if PIPELINING 3600ffb83623SGregory Neil Shapiro && bitset(MCIF_PIPELINED, mci->mci_flags) 360140266059SGregory Neil Shapiro && mci->mci_nextaddr == NULL 3602*5b0945b5SGregory Neil Shapiro #endif 360340266059SGregory Neil Shapiro ) 3604c2aa98e2SPeter Wemm { 3605c2aa98e2SPeter Wemm rcode = EX_OK; 3606c2aa98e2SPeter Wemm e->e_to = NULL; 3607c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 3608c2aa98e2SPeter Wemm smtprset(m, mci, e); 3609c2aa98e2SPeter Wemm } 3610c2aa98e2SPeter Wemm else 3611c2aa98e2SPeter Wemm { 3612c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 361340266059SGregory Neil Shapiro rcode = smtpdata(m, mci, e, ctladdr, xstart); 3614c2aa98e2SPeter Wemm } 3615c2aa98e2SPeter Wemm } 361606f25ae9SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 3617c2aa98e2SPeter Wemm { 3618c2aa98e2SPeter Wemm /* try next MX site */ 3619c2aa98e2SPeter Wemm goto tryhost; 3620c2aa98e2SPeter Wemm } 3621c2aa98e2SPeter Wemm } 3622c2aa98e2SPeter Wemm #if NAMED_BIND 3623c2aa98e2SPeter Wemm if (ConfigLevel < 2) 3624c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 3625*5b0945b5SGregory Neil Shapiro #endif 3626c2aa98e2SPeter Wemm 3627c2aa98e2SPeter Wemm if (tTd(62, 1)) 3628c2aa98e2SPeter Wemm checkfds("after delivery"); 3629c2aa98e2SPeter Wemm 3630c2aa98e2SPeter Wemm /* 3631c2aa98e2SPeter Wemm ** Do final status disposal. 3632c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case. 3633c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the 3634c2aa98e2SPeter Wemm ** addressees. 3635c2aa98e2SPeter Wemm */ 3636c2aa98e2SPeter Wemm 3637c2aa98e2SPeter Wemm give_up: 3638c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3639c2aa98e2SPeter Wemm { 3640c2aa98e2SPeter Wemm lmtp_rcode = rcode; 3641c2aa98e2SPeter Wemm tobuf[0] = '\0'; 364240266059SGregory Neil Shapiro anyok = false; 364340266059SGregory Neil Shapiro strsize = 0; 3644c2aa98e2SPeter Wemm } 3645c2aa98e2SPeter Wemm else 3646c2aa98e2SPeter Wemm anyok = rcode == EX_OK; 3647c2aa98e2SPeter Wemm 3648c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3649c2aa98e2SPeter Wemm { 3650c2aa98e2SPeter Wemm /* see if address already marked */ 365106f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 3652c2aa98e2SPeter Wemm continue; 3653c2aa98e2SPeter Wemm 3654c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */ 3655c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3656c2aa98e2SPeter Wemm { 3657c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK) 3658c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e); 3659c2aa98e2SPeter Wemm if (rcode == EX_OK) 3660c2aa98e2SPeter Wemm { 366140266059SGregory Neil Shapiro strsize += sm_strlcat2(tobuf + strsize, ",", 366240266059SGregory Neil Shapiro to->q_paddr, 366340266059SGregory Neil Shapiro tobufsize - strsize); 366440266059SGregory Neil Shapiro SM_ASSERT(strsize < tobufsize); 366540266059SGregory Neil Shapiro anyok = true; 3666c2aa98e2SPeter Wemm } 3667c2aa98e2SPeter Wemm else 3668c2aa98e2SPeter Wemm { 3669c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 367040266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 367106f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci, 367240266059SGregory Neil Shapiro ctladdr, xstart, e, to); 3673c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 3674c2aa98e2SPeter Wemm continue; 3675c2aa98e2SPeter Wemm } 3676c2aa98e2SPeter Wemm } 3677c2aa98e2SPeter Wemm else 3678c2aa98e2SPeter Wemm { 3679c2aa98e2SPeter Wemm /* mark bad addresses */ 3680c2aa98e2SPeter Wemm if (rcode != EX_OK) 3681c2aa98e2SPeter Wemm { 3682c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST) 3683c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL; 368440266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 3685c2aa98e2SPeter Wemm continue; 3686c2aa98e2SPeter Wemm } 3687c2aa98e2SPeter Wemm } 3688c2aa98e2SPeter Wemm 3689c2aa98e2SPeter Wemm /* successful delivery */ 369006f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 3691c2aa98e2SPeter Wemm to->q_statdate = curtime(); 3692c2aa98e2SPeter Wemm e->e_nsent++; 369306f25ae9SGregory Neil Shapiro 369406f25ae9SGregory Neil Shapiro /* 369506f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses 369606f25ae9SGregory Neil Shapiro */ 369706f25ae9SGregory Neil Shapiro 369842e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 369906f25ae9SGregory Neil Shapiro { 370040266059SGregory Neil Shapiro queueup(e, false, false); 370106f25ae9SGregory Neil Shapiro e->e_nsent = 0; 370206f25ae9SGregory Neil Shapiro } 370306f25ae9SGregory Neil Shapiro 3704c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 3705c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 3706c2aa98e2SPeter Wemm { 3707c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 3708c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 370940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 371040266059SGregory Neil Shapiro "%s... Successfully delivered\n", 3711c2aa98e2SPeter Wemm to->q_paddr); 3712c2aa98e2SPeter Wemm } 3713c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) && 3714c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) && 3715c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags)) 3716c2aa98e2SPeter Wemm { 3717c2aa98e2SPeter Wemm to->q_flags |= QRELAYED; 371840266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 371940266059SGregory Neil Shapiro "%s... relayed; expect no further notifications\n", 372040266059SGregory Neil Shapiro to->q_paddr); 372140266059SGregory Neil Shapiro } 372240266059SGregory Neil Shapiro else if (IS_DLVR_NOTIFY(e) && 372340266059SGregory Neil Shapiro !bitset(MCIF_DLVR_BY, mci->mci_flags) && 372440266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags) && 372540266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 372640266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 372740266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 372840266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags))) 372940266059SGregory Neil Shapiro { 373040266059SGregory Neil Shapiro /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 373140266059SGregory Neil Shapiro to->q_flags |= QBYNRELAY; 373240266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 373340266059SGregory Neil Shapiro "%s... Deliver-by notify: relayed\n", 373440266059SGregory Neil Shapiro to->q_paddr); 373540266059SGregory Neil Shapiro } 373640266059SGregory Neil Shapiro else if (IS_DLVR_TRACE(e) && 373740266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 373840266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 373940266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 374040266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)) && 374140266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags)) 374240266059SGregory Neil Shapiro { 374340266059SGregory Neil Shapiro /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 374440266059SGregory Neil Shapiro to->q_flags |= QBYTRACE; 374540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 374640266059SGregory Neil Shapiro "%s... Deliver-By trace: relayed\n", 3747c2aa98e2SPeter Wemm to->q_paddr); 3748c2aa98e2SPeter Wemm } 3749c2aa98e2SPeter Wemm } 3750c2aa98e2SPeter Wemm 3751c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3752c2aa98e2SPeter Wemm { 3753c2aa98e2SPeter Wemm /* 3754c2aa98e2SPeter Wemm ** Global information applies to the last recipient only; 3755c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors. 3756c2aa98e2SPeter Wemm */ 3757c2aa98e2SPeter Wemm 3758c2aa98e2SPeter Wemm rcode = EX_OK; 3759c2aa98e2SPeter Wemm e->e_statmsg = NULL; 3760c2aa98e2SPeter Wemm 3761c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */ 376240266059SGregory Neil Shapiro if (mci != NULL && 376340266059SGregory Neil Shapiro (mci->mci_state == MCIS_MAIL || 376440266059SGregory Neil Shapiro mci->mci_state == MCIS_RCPT || 376540266059SGregory Neil Shapiro mci->mci_state == MCIS_DATA)) 3766323f6dcbSGregory Neil Shapiro { 3767c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 3768323f6dcbSGregory Neil Shapiro SmtpPhase = mci->mci_phase = "idle"; 3769323f6dcbSGregory Neil Shapiro sm_setproctitle(true, e, "%s: %s", CurHostName, 3770323f6dcbSGregory Neil Shapiro mci->mci_phase); 3771323f6dcbSGregory Neil Shapiro } 3772c2aa98e2SPeter Wemm } 3773c2aa98e2SPeter Wemm 3774c2aa98e2SPeter Wemm if (tobuf[0] != '\0') 377540266059SGregory Neil Shapiro { 3776da7d7b9cSGregory Neil Shapiro giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, NULL); 377740266059SGregory Neil Shapiro #if 0 377840266059SGregory Neil Shapiro /* 377940266059SGregory Neil Shapiro ** This code is disabled for now because I am not 378040266059SGregory Neil Shapiro ** sure that copying status from the first recipient 378140266059SGregory Neil Shapiro ** to all non-status'ed recipients is a good idea. 378240266059SGregory Neil Shapiro */ 378340266059SGregory Neil Shapiro 378440266059SGregory Neil Shapiro if (tochain->q_message != NULL && 378540266059SGregory Neil Shapiro !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 378640266059SGregory Neil Shapiro { 378740266059SGregory Neil Shapiro for (to = tochain->q_tchain; to != NULL; 378840266059SGregory Neil Shapiro to = to->q_tchain) 378940266059SGregory Neil Shapiro { 379040266059SGregory Neil Shapiro /* see if address already marked */ 379140266059SGregory Neil Shapiro if (QS_IS_QUEUEUP(to->q_state) && 379240266059SGregory Neil Shapiro to->q_message == NULL) 379340266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 379440266059SGregory Neil Shapiro tochain->q_message); 379540266059SGregory Neil Shapiro } 379640266059SGregory Neil Shapiro } 379740266059SGregory Neil Shapiro #endif /* 0 */ 379840266059SGregory Neil Shapiro } 3799c2aa98e2SPeter Wemm if (anyok) 380040266059SGregory Neil Shapiro markstats(e, tochain, STATS_NORMAL); 3801c2aa98e2SPeter Wemm mci_store_persistent(mci); 3802c2aa98e2SPeter Wemm 3803*5b0945b5SGregory Neil Shapiro #if _FFR_OCC 3804*5b0945b5SGregory Neil Shapiro /* 3805*5b0945b5SGregory Neil Shapiro ** HACK: this is NOT the right place to "close" a connection! 3806*5b0945b5SGregory Neil Shapiro ** use smtpquit? 3807*5b0945b5SGregory Neil Shapiro ** add a flag to mci to indicate that rate/conc. was increased? 3808*5b0945b5SGregory Neil Shapiro */ 3809*5b0945b5SGregory Neil Shapiro 3810*5b0945b5SGregory Neil Shapiro if (clever) 3811*5b0945b5SGregory Neil Shapiro { 3812*5b0945b5SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 3813*5b0945b5SGregory Neil Shapiro 3814*5b0945b5SGregory Neil Shapiro /* check family... {} */ 3815*5b0945b5SGregory Neil Shapiro /* r = anynet_pton(AF_INET, p, dst); */ 3816*5b0945b5SGregory Neil Shapiro occ_close(e, mci, host, &CurHostAddr); 3817*5b0945b5SGregory Neil Shapiro } 3818*5b0945b5SGregory Neil Shapiro #endif /* _FFR_OCC */ 3819*5b0945b5SGregory Neil Shapiro 382040266059SGregory Neil Shapiro /* Some recipients were tempfailed, try them on the next host */ 382140266059SGregory Neil Shapiro if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 382240266059SGregory Neil Shapiro { 382340266059SGregory Neil Shapiro /* try next MX site */ 382440266059SGregory Neil Shapiro goto tryhost; 382540266059SGregory Neil Shapiro } 382640266059SGregory Neil Shapiro 3827c2aa98e2SPeter Wemm /* now close the connection */ 3828c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 3829c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags)) 3830c2aa98e2SPeter Wemm smtpquit(m, mci, e); 3831c2aa98e2SPeter Wemm 383240266059SGregory Neil Shapiro cleanup: ; 383340266059SGregory Neil Shapiro } 383440266059SGregory Neil Shapiro SM_FINALLY 383540266059SGregory Neil Shapiro { 3836c2aa98e2SPeter Wemm /* 3837c2aa98e2SPeter Wemm ** Restore state and return. 3838c2aa98e2SPeter Wemm */ 3839c2aa98e2SPeter Wemm #if XDEBUG 3840c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 3841c2aa98e2SPeter Wemm 3842c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 3843d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), 384440266059SGregory Neil Shapiro "%s... end of deliver(%s)", 3845c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST" 384640266059SGregory Neil Shapiro : shortenstring(e->e_to, 384740266059SGregory Neil Shapiro MAXSHORTSTR), 3848c2aa98e2SPeter Wemm m->m_name); 3849c2aa98e2SPeter Wemm checkfd012(wbuf); 385006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 3851c2aa98e2SPeter Wemm 3852c2aa98e2SPeter Wemm errno = 0; 385340266059SGregory Neil Shapiro 385440266059SGregory Neil Shapiro /* 385540266059SGregory Neil Shapiro ** It was originally necessary to set macro 'g' to NULL 385640266059SGregory Neil Shapiro ** because it previously pointed to an auto buffer. 385740266059SGregory Neil Shapiro ** We don't do this any more, so this may be unnecessary. 385840266059SGregory Neil Shapiro */ 385940266059SGregory Neil Shapiro 386040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 386106f25ae9SGregory Neil Shapiro e->e_to = NULL; 386240266059SGregory Neil Shapiro } 386340266059SGregory Neil Shapiro SM_END_TRY 386406f25ae9SGregory Neil Shapiro return rcode; 3865c2aa98e2SPeter Wemm } 386606f25ae9SGregory Neil Shapiro 386740266059SGregory Neil Shapiro /* 3868c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address. 3869c2aa98e2SPeter Wemm ** 3870c2aa98e2SPeter Wemm ** Parameters: 3871c2aa98e2SPeter Wemm ** e -- the envelope we are sending. 3872c2aa98e2SPeter Wemm ** q -- the address to mark. 3873c2aa98e2SPeter Wemm ** mci -- mailer connection information. 3874c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure. 387506f25ae9SGregory Neil Shapiro ** ovr -- override an existing code? 3876c2aa98e2SPeter Wemm ** 3877c2aa98e2SPeter Wemm ** Returns: 3878c2aa98e2SPeter Wemm ** none. 3879c2aa98e2SPeter Wemm ** 3880c2aa98e2SPeter Wemm ** Side Effects: 3881c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the 3882c2aa98e2SPeter Wemm ** failure so that an error will be returned or 3883c2aa98e2SPeter Wemm ** the message will be queued, as appropriate. 3884c2aa98e2SPeter Wemm */ 3885c2aa98e2SPeter Wemm 388640266059SGregory Neil Shapiro void 388706f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr) 3888c2aa98e2SPeter Wemm register ENVELOPE *e; 3889c2aa98e2SPeter Wemm register ADDRESS *q; 3890c2aa98e2SPeter Wemm register MCI *mci; 3891c2aa98e2SPeter Wemm int rcode; 389206f25ae9SGregory Neil Shapiro bool ovr; 3893c2aa98e2SPeter Wemm { 389440266059SGregory Neil Shapiro int save_errno = errno; 389506f25ae9SGregory Neil Shapiro char *status = NULL; 389606f25ae9SGregory Neil Shapiro char *rstatus = NULL; 3897c2aa98e2SPeter Wemm 3898c2aa98e2SPeter Wemm switch (rcode) 3899c2aa98e2SPeter Wemm { 3900c2aa98e2SPeter Wemm case EX_OK: 3901c2aa98e2SPeter Wemm break; 3902c2aa98e2SPeter Wemm 3903c2aa98e2SPeter Wemm case EX_TEMPFAIL: 3904c2aa98e2SPeter Wemm case EX_IOERR: 3905c2aa98e2SPeter Wemm case EX_OSERR: 390606f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 3907c2aa98e2SPeter Wemm break; 3908c2aa98e2SPeter Wemm 3909c2aa98e2SPeter Wemm default: 391006f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 3911c2aa98e2SPeter Wemm break; 3912c2aa98e2SPeter Wemm } 3913c2aa98e2SPeter Wemm 3914c2aa98e2SPeter Wemm /* find most specific error code possible */ 3915c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL) 3916c2aa98e2SPeter Wemm { 391740266059SGregory Neil Shapiro status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 3918c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 391940266059SGregory Neil Shapiro rstatus = sm_rpool_strdup_x(e->e_rpool, 392040266059SGregory Neil Shapiro mci->mci_rstatus); 3921c2aa98e2SPeter Wemm } 3922c2aa98e2SPeter Wemm else if (e->e_status != NULL) 3923c2aa98e2SPeter Wemm { 392406f25ae9SGregory Neil Shapiro status = e->e_status; 3925c2aa98e2SPeter Wemm } 3926c2aa98e2SPeter Wemm else 3927c2aa98e2SPeter Wemm { 3928c2aa98e2SPeter Wemm switch (rcode) 3929c2aa98e2SPeter Wemm { 3930c2aa98e2SPeter Wemm case EX_USAGE: 393106f25ae9SGregory Neil Shapiro status = "5.5.4"; 3932c2aa98e2SPeter Wemm break; 3933c2aa98e2SPeter Wemm 3934c2aa98e2SPeter Wemm case EX_DATAERR: 393506f25ae9SGregory Neil Shapiro status = "5.5.2"; 3936c2aa98e2SPeter Wemm break; 3937c2aa98e2SPeter Wemm 3938c2aa98e2SPeter Wemm case EX_NOUSER: 393906f25ae9SGregory Neil Shapiro status = "5.1.1"; 3940c2aa98e2SPeter Wemm break; 3941c2aa98e2SPeter Wemm 3942c2aa98e2SPeter Wemm case EX_NOHOST: 394306f25ae9SGregory Neil Shapiro status = "5.1.2"; 3944c2aa98e2SPeter Wemm break; 3945c2aa98e2SPeter Wemm 3946c2aa98e2SPeter Wemm case EX_NOINPUT: 3947c2aa98e2SPeter Wemm case EX_CANTCREAT: 3948c2aa98e2SPeter Wemm case EX_NOPERM: 394906f25ae9SGregory Neil Shapiro status = "5.3.0"; 3950c2aa98e2SPeter Wemm break; 3951c2aa98e2SPeter Wemm 3952c2aa98e2SPeter Wemm case EX_UNAVAILABLE: 3953c2aa98e2SPeter Wemm case EX_SOFTWARE: 3954c2aa98e2SPeter Wemm case EX_OSFILE: 3955c2aa98e2SPeter Wemm case EX_PROTOCOL: 3956c2aa98e2SPeter Wemm case EX_CONFIG: 395706f25ae9SGregory Neil Shapiro status = "5.5.0"; 3958c2aa98e2SPeter Wemm break; 3959c2aa98e2SPeter Wemm 3960c2aa98e2SPeter Wemm case EX_OSERR: 3961c2aa98e2SPeter Wemm case EX_IOERR: 396206f25ae9SGregory Neil Shapiro status = "4.5.0"; 3963c2aa98e2SPeter Wemm break; 3964c2aa98e2SPeter Wemm 3965c2aa98e2SPeter Wemm case EX_TEMPFAIL: 396606f25ae9SGregory Neil Shapiro status = "4.2.0"; 3967c2aa98e2SPeter Wemm break; 3968c2aa98e2SPeter Wemm } 3969c2aa98e2SPeter Wemm } 3970c2aa98e2SPeter Wemm 397106f25ae9SGregory Neil Shapiro /* new status? */ 397206f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 397306f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status)) 397406f25ae9SGregory Neil Shapiro { 397506f25ae9SGregory Neil Shapiro q->q_status = status; 397606f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus; 397706f25ae9SGregory Neil Shapiro } 3978c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL && 3979c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 398040266059SGregory Neil Shapiro sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 3981c2aa98e2SPeter Wemm { 398206f25ae9SGregory Neil Shapiro char buf[16]; 3983c2aa98e2SPeter Wemm 3984d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", rcode); 398540266059SGregory Neil Shapiro q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 3986c2aa98e2SPeter Wemm } 398706f25ae9SGregory Neil Shapiro 398806f25ae9SGregory Neil Shapiro q->q_statdate = curtime(); 398906f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' && 399006f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 399140266059SGregory Neil Shapiro q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 399240266059SGregory Neil Shapiro 399340266059SGregory Neil Shapiro /* restore errno */ 399440266059SGregory Neil Shapiro errno = save_errno; 3995c2aa98e2SPeter Wemm } 399640266059SGregory Neil Shapiro /* 3997c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate. 3998c2aa98e2SPeter Wemm ** 3999c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation 4000c2aa98e2SPeter Wemm ** violation), so we report those specially. For other 4001c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg), 4002c2aa98e2SPeter Wemm ** and if it represents an error, we print it. 4003c2aa98e2SPeter Wemm ** 4004c2aa98e2SPeter Wemm ** Parameters: 400513058a91SGregory Neil Shapiro ** mci -- the mailer connection info. 4006c2aa98e2SPeter Wemm ** e -- the current envelope. 4007c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer 4008c2aa98e2SPeter Wemm ** (for error messages). 4009c2aa98e2SPeter Wemm ** 4010c2aa98e2SPeter Wemm ** Returns: 4011c2aa98e2SPeter Wemm ** exit code of mailer. 4012c2aa98e2SPeter Wemm ** 4013c2aa98e2SPeter Wemm ** Side Effects: 4014c2aa98e2SPeter Wemm ** none. 4015c2aa98e2SPeter Wemm */ 4016c2aa98e2SPeter Wemm 401706f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout; 401806f25ae9SGregory Neil Shapiro 401906f25ae9SGregory Neil Shapiro static void 4020b6bacd31SGregory Neil Shapiro endwaittimeout(ignore) 4021b6bacd31SGregory Neil Shapiro int ignore; 402206f25ae9SGregory Neil Shapiro { 40238774250cSGregory Neil Shapiro /* 40248774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 40258774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 40268774250cSGregory Neil Shapiro ** DOING. 40278774250cSGregory Neil Shapiro */ 40288774250cSGregory Neil Shapiro 402906f25ae9SGregory Neil Shapiro errno = ETIMEDOUT; 403006f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1); 403106f25ae9SGregory Neil Shapiro } 403206f25ae9SGregory Neil Shapiro 4033c2aa98e2SPeter Wemm int 4034c2aa98e2SPeter Wemm endmailer(mci, e, pv) 4035c2aa98e2SPeter Wemm register MCI *mci; 4036c2aa98e2SPeter Wemm register ENVELOPE *e; 4037c2aa98e2SPeter Wemm char **pv; 4038c2aa98e2SPeter Wemm { 4039c2aa98e2SPeter Wemm int st; 404006f25ae9SGregory Neil Shapiro int save_errno = errno; 404106f25ae9SGregory Neil Shapiro char buf[MAXLINE]; 404240266059SGregory Neil Shapiro SM_EVENT *ev = NULL; 404306f25ae9SGregory Neil Shapiro 4044c2aa98e2SPeter Wemm 4045c2aa98e2SPeter Wemm mci_unlock_host(mci); 4046c2aa98e2SPeter Wemm 40478774250cSGregory Neil Shapiro /* close output to mailer */ 40488774250cSGregory Neil Shapiro if (mci->mci_out != NULL) 4049b6bacd31SGregory Neil Shapiro { 405040266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 4051b6bacd31SGregory Neil Shapiro mci->mci_out = NULL; 4052b6bacd31SGregory Neil Shapiro } 40538774250cSGregory Neil Shapiro 40548774250cSGregory Neil Shapiro /* copy any remaining input to transcript */ 40558774250cSGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 40568774250cSGregory Neil Shapiro e->e_xfp != NULL) 40578774250cSGregory Neil Shapiro { 4058d0cef73dSGregory Neil Shapiro while (sfgets(buf, sizeof(buf), mci->mci_in, 40598774250cSGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL) 406040266059SGregory Neil Shapiro (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 40618774250cSGregory Neil Shapiro } 40628774250cSGregory Neil Shapiro 406306f25ae9SGregory Neil Shapiro #if SASL 406440266059SGregory Neil Shapiro /* close SASL connection */ 406506f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 406606f25ae9SGregory Neil Shapiro { 406706f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 406806f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT; 406906f25ae9SGregory Neil Shapiro } 407006f25ae9SGregory Neil Shapiro #endif /* SASL */ 407106f25ae9SGregory Neil Shapiro 407206f25ae9SGregory Neil Shapiro #if STARTTLS 407306f25ae9SGregory Neil Shapiro /* shutdown TLS */ 407406f25ae9SGregory Neil Shapiro (void) endtlsclt(mci); 4075*5b0945b5SGregory Neil Shapiro #endif 407606f25ae9SGregory Neil Shapiro 407706f25ae9SGregory Neil Shapiro /* now close the input */ 407806f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 4079b6bacd31SGregory Neil Shapiro { 408040266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 4081b6bacd31SGregory Neil Shapiro mci->mci_in = NULL; 4082b6bacd31SGregory Neil Shapiro } 4083c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 4084c2aa98e2SPeter Wemm 408506f25ae9SGregory Neil Shapiro errno = save_errno; 408606f25ae9SGregory Neil Shapiro 4087c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */ 4088c2aa98e2SPeter Wemm if (mci->mci_pid == 0) 408906f25ae9SGregory Neil Shapiro return EX_OK; 4090c2aa98e2SPeter Wemm 409106f25ae9SGregory Neil Shapiro /* put a timeout around the wait */ 409206f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0) 409306f25ae9SGregory Neil Shapiro { 409406f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0) 409540266059SGregory Neil Shapiro ev = sm_setevent(mci->mci_mailer->m_wait, 409606f25ae9SGregory Neil Shapiro endwaittimeout, 0); 409706f25ae9SGregory Neil Shapiro else 409806f25ae9SGregory Neil Shapiro { 409942e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)", 410006f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, 410142e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait); 410206f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 410306f25ae9SGregory Neil Shapiro } 410406f25ae9SGregory Neil Shapiro } 4105c2aa98e2SPeter Wemm 410606f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */ 4107c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid); 410806f25ae9SGregory Neil Shapiro save_errno = errno; 410906f25ae9SGregory Neil Shapiro if (ev != NULL) 411040266059SGregory Neil Shapiro sm_clrevent(ev); 411106f25ae9SGregory Neil Shapiro errno = save_errno; 411206f25ae9SGregory Neil Shapiro 4113c2aa98e2SPeter Wemm if (st == -1) 4114c2aa98e2SPeter Wemm { 4115c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name); 411606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 4117c2aa98e2SPeter Wemm } 4118c2aa98e2SPeter Wemm 4119c2aa98e2SPeter Wemm if (WIFEXITED(st)) 4120c2aa98e2SPeter Wemm { 4121c2aa98e2SPeter Wemm /* normal death -- return status */ 4122c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 4123c2aa98e2SPeter Wemm } 4124c2aa98e2SPeter Wemm 4125c2aa98e2SPeter Wemm /* it died a horrid death */ 412606f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s", 412706f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st), 412806f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" : 412906f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : "")); 4130c2aa98e2SPeter Wemm 4131c2aa98e2SPeter Wemm /* log the arguments */ 4132c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL) 4133c2aa98e2SPeter Wemm { 4134c2aa98e2SPeter Wemm register char **av; 4135c2aa98e2SPeter Wemm 413640266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 4137c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 413840266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 413940266059SGregory Neil Shapiro *av); 414040266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 4141c2aa98e2SPeter Wemm } 4142c2aa98e2SPeter Wemm 4143c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL; 414406f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 4145c2aa98e2SPeter Wemm } 414640266059SGregory Neil Shapiro /* 4147c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer 4148c2aa98e2SPeter Wemm ** 4149c2aa98e2SPeter Wemm ** Parameters: 415006f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte 4151c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of 4152c2aa98e2SPeter Wemm ** already). 415306f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any. 4154c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer. 4155c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 4156c2aa98e2SPeter Wemm ** response is given before the connection is made. 4157c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient 4158c2aa98e2SPeter Wemm ** address(es). 4159c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing 4160c2aa98e2SPeter Wemm ** transaction delays. 4161c2aa98e2SPeter Wemm ** e -- the current envelope. 416240266059SGregory Neil Shapiro ** to -- the current recipient (NULL if none). 4163c2aa98e2SPeter Wemm ** 4164c2aa98e2SPeter Wemm ** Returns: 4165c2aa98e2SPeter Wemm ** none. 4166c2aa98e2SPeter Wemm ** 4167c2aa98e2SPeter Wemm ** Side Effects: 4168c2aa98e2SPeter Wemm ** Errors may be incremented. 4169c2aa98e2SPeter Wemm ** ExitStat may be set. 4170c2aa98e2SPeter Wemm */ 4171c2aa98e2SPeter Wemm 4172c2aa98e2SPeter Wemm void 417340266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 417406f25ae9SGregory Neil Shapiro int status; 417506f25ae9SGregory Neil Shapiro char *dsn; 4176c2aa98e2SPeter Wemm register MAILER *m; 4177c2aa98e2SPeter Wemm register MCI *mci; 4178c2aa98e2SPeter Wemm ADDRESS *ctladdr; 4179c2aa98e2SPeter Wemm time_t xstart; 4180c2aa98e2SPeter Wemm ENVELOPE *e; 418140266059SGregory Neil Shapiro ADDRESS *to; 4182c2aa98e2SPeter Wemm { 4183c2aa98e2SPeter Wemm register const char *statmsg; 418406f25ae9SGregory Neil Shapiro int errnum = errno; 418506f25ae9SGregory Neil Shapiro int off = 4; 418640266059SGregory Neil Shapiro bool usestat = false; 418706f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN]; 4188c2aa98e2SPeter Wemm char buf[MAXLINE]; 418940266059SGregory Neil Shapiro char *exmsg; 4190c2aa98e2SPeter Wemm 4191c2aa98e2SPeter Wemm if (e == NULL) 4192af9557fdSGregory Neil Shapiro { 4193c2aa98e2SPeter Wemm syserr("giveresponse: null envelope"); 4194af9557fdSGregory Neil Shapiro /* NOTREACHED */ 4195af9557fdSGregory Neil Shapiro SM_ASSERT(0); 4196af9557fdSGregory Neil Shapiro } 4197c2aa98e2SPeter Wemm 4198c2aa98e2SPeter Wemm /* 4199c2aa98e2SPeter Wemm ** Compute status message from code. 4200c2aa98e2SPeter Wemm */ 4201c2aa98e2SPeter Wemm 420240266059SGregory Neil Shapiro exmsg = sm_sysexmsg(status); 420306f25ae9SGregory Neil Shapiro if (status == 0) 4204c2aa98e2SPeter Wemm { 420506f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent"; 4206c2aa98e2SPeter Wemm if (e->e_statmsg != NULL) 4207c2aa98e2SPeter Wemm { 4208d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", 420906f25ae9SGregory Neil Shapiro statmsg, 421006f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 4211c2aa98e2SPeter Wemm statmsg = buf; 4212c2aa98e2SPeter Wemm } 4213c2aa98e2SPeter Wemm } 421440266059SGregory Neil Shapiro else if (exmsg == NULL) 4215c2aa98e2SPeter Wemm { 4216d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 421706f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d", 421806f25ae9SGregory Neil Shapiro status); 421906f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE; 4220c2aa98e2SPeter Wemm statmsg = buf; 422140266059SGregory Neil Shapiro usestat = true; 4222c2aa98e2SPeter Wemm } 422306f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL) 4224c2aa98e2SPeter Wemm { 4225c2aa98e2SPeter Wemm char *bp = buf; 4226c2aa98e2SPeter Wemm 422740266059SGregory Neil Shapiro (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 4228c2aa98e2SPeter Wemm bp += strlen(bp); 4229c2aa98e2SPeter Wemm #if NAMED_BIND 4230c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN) 423140266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 4232c2aa98e2SPeter Wemm else 423306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 4234c2aa98e2SPeter Wemm { 423506f25ae9SGregory Neil Shapiro if (errnum != 0) 423640266059SGregory Neil Shapiro statmsg = sm_errstring(errnum); 4237c2aa98e2SPeter Wemm else 4238c2aa98e2SPeter Wemm statmsg = SmtpError; 4239c2aa98e2SPeter Wemm } 4240c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0') 424106f25ae9SGregory Neil Shapiro { 424206f25ae9SGregory Neil Shapiro switch (errnum) 424306f25ae9SGregory Neil Shapiro { 424406f25ae9SGregory Neil Shapiro #ifdef ENETDOWN 424506f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */ 4246*5b0945b5SGregory Neil Shapiro #endif 424706f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH 424806f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */ 4249*5b0945b5SGregory Neil Shapiro #endif 425006f25ae9SGregory Neil Shapiro #ifdef ENETRESET 425106f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */ 4252*5b0945b5SGregory Neil Shapiro #endif 425306f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED 425406f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */ 4255*5b0945b5SGregory Neil Shapiro #endif 425606f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN 425706f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */ 4258*5b0945b5SGregory Neil Shapiro #endif 425906f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH 426006f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */ 4261*5b0945b5SGregory Neil Shapiro #endif 4262b6bacd31SGregory Neil Shapiro if (mci != NULL && mci->mci_host != NULL) 426306f25ae9SGregory Neil Shapiro { 426440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, 426540266059SGregory Neil Shapiro SPACELEFT(buf, bp), 426640266059SGregory Neil Shapiro 2, ": ", 426740266059SGregory Neil Shapiro mci->mci_host); 426806f25ae9SGregory Neil Shapiro bp += strlen(bp); 426906f25ae9SGregory Neil Shapiro } 427006f25ae9SGregory Neil Shapiro break; 427106f25ae9SGregory Neil Shapiro } 427240266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 427340266059SGregory Neil Shapiro statmsg); 4274*5b0945b5SGregory Neil Shapiro #if DANE 4275*5b0945b5SGregory Neil Shapiro if (errnum == 0 && SmtpError[0] != '\0' && 4276*5b0945b5SGregory Neil Shapiro h_errno == TRY_AGAIN && 4277*5b0945b5SGregory Neil Shapiro mci->mci_exitstat == EX_TEMPFAIL) 4278*5b0945b5SGregory Neil Shapiro { 4279*5b0945b5SGregory Neil Shapiro (void) sm_strlcat(bp, SmtpError, 4280*5b0945b5SGregory Neil Shapiro SPACELEFT(buf, bp)); 4281*5b0945b5SGregory Neil Shapiro bp += strlen(bp); 4282*5b0945b5SGregory Neil Shapiro } 4283*5b0945b5SGregory Neil Shapiro #endif /* DANE */ 428440266059SGregory Neil Shapiro usestat = true; 428506f25ae9SGregory Neil Shapiro } 4286c2aa98e2SPeter Wemm statmsg = buf; 4287c2aa98e2SPeter Wemm } 4288c2aa98e2SPeter Wemm #if NAMED_BIND 428906f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0) 4290c2aa98e2SPeter Wemm { 429140266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 4292d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", exmsg + 1, 429340266059SGregory Neil Shapiro statmsg); 4294c2aa98e2SPeter Wemm statmsg = buf; 429540266059SGregory Neil Shapiro usestat = true; 4296c2aa98e2SPeter Wemm } 429706f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 4298c2aa98e2SPeter Wemm else 4299c2aa98e2SPeter Wemm { 430040266059SGregory Neil Shapiro statmsg = exmsg; 430106f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0) 4302c2aa98e2SPeter Wemm { 4303d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s: %s", statmsg, 430440266059SGregory Neil Shapiro sm_errstring(errnum)); 4305c2aa98e2SPeter Wemm statmsg = buf; 430640266059SGregory Neil Shapiro usestat = true; 4307c2aa98e2SPeter Wemm } 4308605302a5SGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL) 4309605302a5SGregory Neil Shapiro { 4310d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", statmsg, 4311605302a5SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 4312605302a5SGregory Neil Shapiro statmsg = buf; 4313605302a5SGregory Neil Shapiro usestat = true; 4314605302a5SGregory Neil Shapiro } 4315c2aa98e2SPeter Wemm } 4316c2aa98e2SPeter Wemm 4317c2aa98e2SPeter Wemm /* 4318c2aa98e2SPeter Wemm ** Print the message as appropriate 4319c2aa98e2SPeter Wemm */ 4320c2aa98e2SPeter Wemm 432106f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL) 4322c2aa98e2SPeter Wemm { 4323c2aa98e2SPeter Wemm extern char MsgBuf[]; 4324c2aa98e2SPeter Wemm 432506f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0) 432606f25ae9SGregory Neil Shapiro { 432706f25ae9SGregory Neil Shapiro if (dsn == NULL) 432806f25ae9SGregory Neil Shapiro { 4329d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf), 433006f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 433106f25ae9SGregory Neil Shapiro dsn = dsnbuf; 433206f25ae9SGregory Neil Shapiro } 433306f25ae9SGregory Neil Shapiro off += 5; 433406f25ae9SGregory Neil Shapiro } 433506f25ae9SGregory Neil Shapiro else 433606f25ae9SGregory Neil Shapiro { 433706f25ae9SGregory Neil Shapiro off = 4; 433806f25ae9SGregory Neil Shapiro } 433906f25ae9SGregory Neil Shapiro message("%s", statmsg + off); 434006f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL) 434140266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 434240266059SGregory Neil Shapiro &MsgBuf[4]); 4343c2aa98e2SPeter Wemm } 4344c2aa98e2SPeter Wemm else 4345c2aa98e2SPeter Wemm { 434606f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4]; 4347c2aa98e2SPeter Wemm 4348c2aa98e2SPeter Wemm Errors++; 434906f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 4350d0cef73dSGregory Neil Shapiro off < sizeof(mbuf) - 4) 435106f25ae9SGregory Neil Shapiro { 435206f25ae9SGregory Neil Shapiro if (dsn == NULL) 435306f25ae9SGregory Neil Shapiro { 4354d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf), 435506f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 435606f25ae9SGregory Neil Shapiro dsn = dsnbuf; 435706f25ae9SGregory Neil Shapiro } 435806f25ae9SGregory Neil Shapiro off += 5; 435940266059SGregory Neil Shapiro 436040266059SGregory Neil Shapiro /* copy only part of statmsg to mbuf */ 436140266059SGregory Neil Shapiro (void) sm_strlcpy(mbuf, statmsg, off); 4362d0cef73dSGregory Neil Shapiro (void) sm_strlcat(mbuf, " %s", sizeof(mbuf)); 436306f25ae9SGregory Neil Shapiro } 436406f25ae9SGregory Neil Shapiro else 436506f25ae9SGregory Neil Shapiro { 436606f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0'; 4367d0cef73dSGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof(mbuf), "%.3s %%s", 436840266059SGregory Neil Shapiro statmsg); 436906f25ae9SGregory Neil Shapiro off = 4; 437006f25ae9SGregory Neil Shapiro } 437106f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]); 4372c2aa98e2SPeter Wemm } 4373c2aa98e2SPeter Wemm 4374c2aa98e2SPeter Wemm /* 4375c2aa98e2SPeter Wemm ** Final cleanup. 4376da7d7b9cSGregory Neil Shapiro ** Log a record of the transaction. Compute the new ExitStat 4377da7d7b9cSGregory Neil Shapiro ** -- if we already had an error, stick with that. 4378c2aa98e2SPeter Wemm */ 4379c2aa98e2SPeter Wemm 4380c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 438106f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 4382da7d7b9cSGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e, to, status); 4383c2aa98e2SPeter Wemm 4384c2aa98e2SPeter Wemm if (tTd(11, 2)) 438540266059SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 438606f25ae9SGregory Neil Shapiro status, 438706f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn, 438840266059SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message, 438940266059SGregory Neil Shapiro errnum); 4390c2aa98e2SPeter Wemm 439106f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL) 439206f25ae9SGregory Neil Shapiro setstat(status); 439306f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 439440266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 439540266059SGregory Neil Shapiro if (status != EX_OK && to != NULL && to->q_message == NULL) 4396c2aa98e2SPeter Wemm { 439740266059SGregory Neil Shapiro if (!usestat && e->e_message != NULL) 439840266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 439940266059SGregory Neil Shapiro e->e_message); 440040266059SGregory Neil Shapiro else 440140266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 440240266059SGregory Neil Shapiro statmsg + off); 4403c2aa98e2SPeter Wemm } 4404c2aa98e2SPeter Wemm errno = 0; 4405602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 4406c2aa98e2SPeter Wemm } 440740266059SGregory Neil Shapiro /* 4408c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log 4409c2aa98e2SPeter Wemm ** 4410c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because 4411c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core 4412c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical. 4413c2aa98e2SPeter Wemm ** 4414c2aa98e2SPeter Wemm ** Parameters: 4415c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue. 4416c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 441706f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active. 441806f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status. 441906f25ae9SGregory Neil Shapiro ** status -- the message to print for the status. 4420c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list. 4421c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for 4422c2aa98e2SPeter Wemm ** computing transaction delay. 4423c2aa98e2SPeter Wemm ** e -- the current envelope. 4424da7d7b9cSGregory Neil Shapiro ** to -- the current recipient (NULL if none). 4425da7d7b9cSGregory Neil Shapiro ** rcode -- status code 4426c2aa98e2SPeter Wemm ** 4427c2aa98e2SPeter Wemm ** Returns: 4428c2aa98e2SPeter Wemm ** none 4429c2aa98e2SPeter Wemm ** 4430c2aa98e2SPeter Wemm ** Side Effects: 4431c2aa98e2SPeter Wemm ** none 4432c2aa98e2SPeter Wemm */ 4433c2aa98e2SPeter Wemm 4434c2aa98e2SPeter Wemm void 4435da7d7b9cSGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode) 4436c2aa98e2SPeter Wemm MAILER *m; 4437c2aa98e2SPeter Wemm register MCI *mci; 443806f25ae9SGregory Neil Shapiro char *dsn; 443906f25ae9SGregory Neil Shapiro const char *status; 4440c2aa98e2SPeter Wemm ADDRESS *ctladdr; 4441c2aa98e2SPeter Wemm time_t xstart; 4442c2aa98e2SPeter Wemm register ENVELOPE *e; 4443da7d7b9cSGregory Neil Shapiro ADDRESS *to; 4444da7d7b9cSGregory Neil Shapiro int rcode; 4445c2aa98e2SPeter Wemm { 4446c2aa98e2SPeter Wemm register char *bp; 4447c2aa98e2SPeter Wemm register char *p; 4448c2aa98e2SPeter Wemm int l; 444940266059SGregory Neil Shapiro time_t now = curtime(); 4450c2aa98e2SPeter Wemm char buf[1024]; 4451c2aa98e2SPeter Wemm 4452c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 4453c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */ 4454c2aa98e2SPeter Wemm bp = buf; 4455c2aa98e2SPeter Wemm if (ctladdr != NULL) 4456c2aa98e2SPeter Wemm { 445740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 4458c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4459c2aa98e2SPeter Wemm bp += strlen(bp); 4460c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4461c2aa98e2SPeter Wemm { 446240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 446306f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid, 446406f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid); 4465c2aa98e2SPeter Wemm bp += strlen(bp); 4466c2aa98e2SPeter Wemm } 4467c2aa98e2SPeter Wemm } 4468c2aa98e2SPeter Wemm 4469c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */ 447040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 447140266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4472c2aa98e2SPeter Wemm bp += strlen(bp); 4473c2aa98e2SPeter Wemm 4474c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4475c2aa98e2SPeter Wemm { 447640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 447740266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4478c2aa98e2SPeter Wemm bp += strlen(bp); 4479c2aa98e2SPeter Wemm } 4480c2aa98e2SPeter Wemm 4481c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 4482c2aa98e2SPeter Wemm if (m != NULL) 4483c2aa98e2SPeter Wemm { 448440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 448540266059SGregory Neil Shapiro m->m_name); 4486c2aa98e2SPeter Wemm bp += strlen(bp); 4487c2aa98e2SPeter Wemm } 4488c2aa98e2SPeter Wemm 4489da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE2 4490*5b0945b5SGregory Neil Shapiro LOG_MORE(buf, bp); 4491*5b0945b5SGregory Neil Shapiro # endif 4492da7d7b9cSGregory Neil Shapiro 449306f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */ 449440266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 4495ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgpriority)); 449606f25ae9SGregory Neil Shapiro bp += strlen(bp); 449706f25ae9SGregory Neil Shapiro 4498c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */ 4499c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4500c2aa98e2SPeter Wemm { 4501c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4502c2aa98e2SPeter Wemm 450340266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 4504c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40)); 4505c2aa98e2SPeter Wemm bp += strlen(bp); 4506c2aa98e2SPeter Wemm 4507c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 4508c2aa98e2SPeter Wemm { 450940266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 4510c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4511c2aa98e2SPeter Wemm } 4512c2aa98e2SPeter Wemm } 451340266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 451440266059SGregory Neil Shapiro { 451540266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 451640266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 451740266059SGregory Neil Shapiro ", quarantine=%s", 451840266059SGregory Neil Shapiro shortenstring(e->e_quarmsg, 40)); 451940266059SGregory Neil Shapiro } 452006f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4521c2aa98e2SPeter Wemm { 4522c2aa98e2SPeter Wemm p = macvalue('h', e); 4523c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4524c2aa98e2SPeter Wemm { 452540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 452640266059SGregory Neil Shapiro ", relay=%s", shortenstring(p, 40)); 4527c2aa98e2SPeter Wemm } 4528c2aa98e2SPeter Wemm } 4529c2aa98e2SPeter Wemm bp += strlen(bp); 4530c2aa98e2SPeter Wemm 453106f25ae9SGregory Neil Shapiro /* dsn */ 453206f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0') 453306f25ae9SGregory Neil Shapiro { 453440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 453506f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN)); 453606f25ae9SGregory Neil Shapiro bp += strlen(bp); 453706f25ae9SGregory Neil Shapiro } 453806f25ae9SGregory Neil Shapiro 453913d88268SGregory Neil Shapiro # if _FFR_LOG_NTRIES 454013d88268SGregory Neil Shapiro /* ntries */ 454113d88268SGregory Neil Shapiro if (e->e_ntries >= 0) 454213d88268SGregory Neil Shapiro { 454313d88268SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 454413d88268SGregory Neil Shapiro ", ntries=%d", e->e_ntries + 1); 454513d88268SGregory Neil Shapiro bp += strlen(bp); 454613d88268SGregory Neil Shapiro } 454713d88268SGregory Neil Shapiro # endif /* _FFR_LOG_NTRIES */ 454813d88268SGregory Neil Shapiro 4549c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 4550c2aa98e2SPeter Wemm # if (STATLEN) < 63 4551c2aa98e2SPeter Wemm # undef STATLEN 4552c2aa98e2SPeter Wemm # define STATLEN 63 455306f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */ 4554c2aa98e2SPeter Wemm # if (STATLEN) > 203 4555c2aa98e2SPeter Wemm # undef STATLEN 4556c2aa98e2SPeter Wemm # define STATLEN 203 455706f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */ 4558c2aa98e2SPeter Wemm 4559da7d7b9cSGregory Neil Shapiro /* 4560da7d7b9cSGregory Neil Shapiro ** Notes: 4561da7d7b9cSGregory Neil Shapiro ** per-rcpt status: to->q_rstatus 4562da7d7b9cSGregory Neil Shapiro ** global status: e->e_text 4563da7d7b9cSGregory Neil Shapiro ** 4564da7d7b9cSGregory Neil Shapiro ** We (re)use STATLEN here, is that a good choice? 4565da7d7b9cSGregory Neil Shapiro ** 4566da7d7b9cSGregory Neil Shapiro ** stat=Deferred: ... 4567da7d7b9cSGregory Neil Shapiro ** has sometimes the same text? 4568da7d7b9cSGregory Neil Shapiro ** 4569da7d7b9cSGregory Neil Shapiro ** Note: this doesn't show the stage at which the error happened. 4570da7d7b9cSGregory Neil Shapiro ** can/should we log that? 4571da7d7b9cSGregory Neil Shapiro ** XS_* in reply() basically encodes the state. 4572*5b0945b5SGregory Neil Shapiro ** 4573*5b0945b5SGregory Neil Shapiro ** Note: in some case the normal logging might show the same server 4574*5b0945b5SGregory Neil Shapiro ** reply - how to avoid that? 4575da7d7b9cSGregory Neil Shapiro */ 4576da7d7b9cSGregory Neil Shapiro 4577da7d7b9cSGregory Neil Shapiro /* only show errors */ 4578da7d7b9cSGregory Neil Shapiro if (rcode != EX_OK && to != NULL && to->q_rstatus != NULL && 4579da7d7b9cSGregory Neil Shapiro *to->q_rstatus != '\0') 4580da7d7b9cSGregory Neil Shapiro { 4581da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 4582da7d7b9cSGregory Neil Shapiro ", reply=%s", 4583da7d7b9cSGregory Neil Shapiro shortenstring(to->q_rstatus, STATLEN)); 4584da7d7b9cSGregory Neil Shapiro bp += strlen(bp); 4585da7d7b9cSGregory Neil Shapiro } 4586da7d7b9cSGregory Neil Shapiro else if (rcode != EX_OK && e->e_text != NULL) 4587da7d7b9cSGregory Neil Shapiro { 4588da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 4589da7d7b9cSGregory Neil Shapiro ", reply=%d %s%s%s", 4590da7d7b9cSGregory Neil Shapiro e->e_rcode, 4591da7d7b9cSGregory Neil Shapiro e->e_renhsc, 4592da7d7b9cSGregory Neil Shapiro (e->e_renhsc[0] != '\0') ? " " : "", 4593da7d7b9cSGregory Neil Shapiro shortenstring(e->e_text, STATLEN)); 4594da7d7b9cSGregory Neil Shapiro bp += strlen(bp); 4595da7d7b9cSGregory Neil Shapiro } 4596da7d7b9cSGregory Neil Shapiro 4597c2aa98e2SPeter Wemm /* stat: max 210 bytes */ 4598d0cef73dSGregory Neil Shapiro if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20))) 4599c2aa98e2SPeter Wemm { 4600c2aa98e2SPeter Wemm /* desperation move -- truncate data */ 4601d0cef73dSGregory Neil Shapiro bp = buf + sizeof(buf) - ((STATLEN) + 17); 460240266059SGregory Neil Shapiro (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 4603c2aa98e2SPeter Wemm bp += 3; 4604c2aa98e2SPeter Wemm } 4605c2aa98e2SPeter Wemm 460640266059SGregory Neil Shapiro (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 4607c2aa98e2SPeter Wemm bp += strlen(bp); 4608c2aa98e2SPeter Wemm 460940266059SGregory Neil Shapiro (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 461040266059SGregory Neil Shapiro SPACELEFT(buf, bp)); 4611c2aa98e2SPeter Wemm 4612c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */ 4613c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf); 461440266059SGregory Neil Shapiro if (l < 0) 461540266059SGregory Neil Shapiro l = 0; 461606f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 461740266059SGregory Neil Shapiro while (strlen(p) >= l) 4618c2aa98e2SPeter Wemm { 461906f25ae9SGregory Neil Shapiro register char *q; 4620c2aa98e2SPeter Wemm 462106f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 462206f25ae9SGregory Neil Shapiro { 4623da7d7b9cSGregory Neil Shapiro /* XXX a comma in an address will break this! */ 462406f25ae9SGregory Neil Shapiro if (*q == ',') 462506f25ae9SGregory Neil Shapiro break; 462606f25ae9SGregory Neil Shapiro } 462706f25ae9SGregory Neil Shapiro if (p == q) 462806f25ae9SGregory Neil Shapiro break; 462940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 463042e5d165SGregory Neil Shapiro (int) (++q - p), p, buf); 4631c2aa98e2SPeter Wemm p = q; 4632c2aa98e2SPeter Wemm } 463306f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 4634c2aa98e2SPeter Wemm 463506f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 4636c2aa98e2SPeter Wemm 4637c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85; 463840266059SGregory Neil Shapiro if (l < 0) 463940266059SGregory Neil Shapiro l = 0; 464006f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 464140266059SGregory Neil Shapiro while (strlen(p) >= l) 4642c2aa98e2SPeter Wemm { 464306f25ae9SGregory Neil Shapiro register char *q; 4644c2aa98e2SPeter Wemm 464506f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 464606f25ae9SGregory Neil Shapiro { 464706f25ae9SGregory Neil Shapiro if (*q == ',') 464806f25ae9SGregory Neil Shapiro break; 464906f25ae9SGregory Neil Shapiro } 465006f25ae9SGregory Neil Shapiro if (p == q) 465106f25ae9SGregory Neil Shapiro break; 465206f25ae9SGregory Neil Shapiro 465340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 465442e5d165SGregory Neil Shapiro (int) (++q - p), p); 4655c2aa98e2SPeter Wemm p = q; 4656c2aa98e2SPeter Wemm } 465706f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 4658c2aa98e2SPeter Wemm 4659c2aa98e2SPeter Wemm if (ctladdr != NULL) 4660c2aa98e2SPeter Wemm { 4661c2aa98e2SPeter Wemm bp = buf; 466240266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 4663c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4664c2aa98e2SPeter Wemm bp += strlen(bp); 4665c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4666c2aa98e2SPeter Wemm { 466740266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 4668c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid); 4669c2aa98e2SPeter Wemm bp += strlen(bp); 4670c2aa98e2SPeter Wemm } 4671c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf); 4672c2aa98e2SPeter Wemm } 4673c2aa98e2SPeter Wemm bp = buf; 467440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 467540266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4676c2aa98e2SPeter Wemm bp += strlen(bp); 4677c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4678c2aa98e2SPeter Wemm { 467940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 468040266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4681c2aa98e2SPeter Wemm bp += strlen(bp); 4682c2aa98e2SPeter Wemm } 4683c2aa98e2SPeter Wemm 4684c2aa98e2SPeter Wemm if (m != NULL) 4685c2aa98e2SPeter Wemm { 468640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 468740266059SGregory Neil Shapiro m->m_name); 4688c2aa98e2SPeter Wemm bp += strlen(bp); 4689c2aa98e2SPeter Wemm } 4690c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4691c2aa98e2SPeter Wemm 4692c2aa98e2SPeter Wemm buf[0] = '\0'; 4693c2aa98e2SPeter Wemm bp = buf; 4694c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4695c2aa98e2SPeter Wemm { 4696c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4697c2aa98e2SPeter Wemm 469840266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 469940266059SGregory Neil Shapiro mci->mci_host); 4700c2aa98e2SPeter Wemm bp += strlen(bp); 4701c2aa98e2SPeter Wemm 4702c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 470340266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 470440266059SGregory Neil Shapiro " [%.100s]", 4705c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4706c2aa98e2SPeter Wemm } 470740266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 470840266059SGregory Neil Shapiro { 470940266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 471040266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 471140266059SGregory Neil Shapiro ", quarantine=%.100s", 471240266059SGregory Neil Shapiro e->e_quarmsg); 471340266059SGregory Neil Shapiro } 471406f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4715c2aa98e2SPeter Wemm { 4716c2aa98e2SPeter Wemm p = macvalue('h', e); 4717c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4718d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "relay=%.100s", p); 4719c2aa98e2SPeter Wemm } 4720c2aa98e2SPeter Wemm if (buf[0] != '\0') 4721c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4722c2aa98e2SPeter Wemm 472306f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 472406f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 4725c2aa98e2SPeter Wemm } 472640266059SGregory Neil Shapiro /* 4727c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 4728c2aa98e2SPeter Wemm ** 4729c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l 4730c2aa98e2SPeter Wemm ** 4731c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein: 4732c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why 4733c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with 4734c2aa98e2SPeter Wemm ** this kind of antique garbage???? 4735c2aa98e2SPeter Wemm ** 4736c2aa98e2SPeter Wemm ** Parameters: 4737c2aa98e2SPeter Wemm ** mci -- the connection information. 4738c2aa98e2SPeter Wemm ** e -- the envelope. 4739c2aa98e2SPeter Wemm ** 4740c2aa98e2SPeter Wemm ** Returns: 47414e4196cbSGregory Neil Shapiro ** true iff line was written successfully 4742c2aa98e2SPeter Wemm ** 4743c2aa98e2SPeter Wemm ** Side Effects: 4744c2aa98e2SPeter Wemm ** outputs some text to fp. 4745c2aa98e2SPeter Wemm */ 4746c2aa98e2SPeter Wemm 47474e4196cbSGregory Neil Shapiro bool 4748c2aa98e2SPeter Wemm putfromline(mci, e) 4749c2aa98e2SPeter Wemm register MCI *mci; 4750c2aa98e2SPeter Wemm ENVELOPE *e; 4751c2aa98e2SPeter Wemm { 4752c2aa98e2SPeter Wemm char *template = UnixFromLine; 4753c2aa98e2SPeter Wemm char buf[MAXLINE]; 4754c2aa98e2SPeter Wemm char xbuf[MAXLINE]; 4755c2aa98e2SPeter Wemm 4756c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 47574e4196cbSGregory Neil Shapiro return true; 4758c2aa98e2SPeter Wemm 4759c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4760c2aa98e2SPeter Wemm 4761c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 4762c2aa98e2SPeter Wemm { 4763c2aa98e2SPeter Wemm char *bang; 4764c2aa98e2SPeter Wemm 4765d0cef73dSGregory Neil Shapiro expand("\201g", buf, sizeof(buf), e); 4766c2aa98e2SPeter Wemm bang = strchr(buf, '!'); 4767c2aa98e2SPeter Wemm if (bang == NULL) 4768c2aa98e2SPeter Wemm { 4769c2aa98e2SPeter Wemm char *at; 4770c2aa98e2SPeter Wemm char hname[MAXNAME]; 4771c2aa98e2SPeter Wemm 4772c2aa98e2SPeter Wemm /* 4773c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so 4774c2aa98e2SPeter Wemm */ 4775c2aa98e2SPeter Wemm 4776c2aa98e2SPeter Wemm at = strrchr(buf, '@'); 4777c2aa98e2SPeter Wemm if (at == NULL) 4778c2aa98e2SPeter Wemm { 4779d0cef73dSGregory Neil Shapiro expand("\201k", hname, sizeof(hname), e); 4780c2aa98e2SPeter Wemm at = hname; 4781c2aa98e2SPeter Wemm } 4782c2aa98e2SPeter Wemm else 4783c2aa98e2SPeter Wemm *at++ = '\0'; 4784d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf), 4785c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4786c2aa98e2SPeter Wemm buf, at); 4787c2aa98e2SPeter Wemm } 4788c2aa98e2SPeter Wemm else 4789c2aa98e2SPeter Wemm { 4790c2aa98e2SPeter Wemm *bang++ = '\0'; 4791d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf), 4792c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4793c2aa98e2SPeter Wemm bang, buf); 4794c2aa98e2SPeter Wemm template = xbuf; 4795c2aa98e2SPeter Wemm } 4796c2aa98e2SPeter Wemm } 4797d0cef73dSGregory Neil Shapiro expand(template, buf, sizeof(buf), e); 47984e4196cbSGregory Neil Shapiro return putxline(buf, strlen(buf), mci, PXLF_HEADER); 4799c2aa98e2SPeter Wemm } 48004e4196cbSGregory Neil Shapiro 480140266059SGregory Neil Shapiro /* 4802c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message. 4803c2aa98e2SPeter Wemm ** 4804c2aa98e2SPeter Wemm ** Parameters: 4805c2aa98e2SPeter Wemm ** mci -- the connection information. 4806c2aa98e2SPeter Wemm ** e -- the envelope to put out. 4807c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must 4808c2aa98e2SPeter Wemm ** not be permitted in the resulting message. 4809c2aa98e2SPeter Wemm ** 4810c2aa98e2SPeter Wemm ** Returns: 48114e4196cbSGregory Neil Shapiro ** true iff message was written successfully 4812c2aa98e2SPeter Wemm ** 4813c2aa98e2SPeter Wemm ** Side Effects: 4814c2aa98e2SPeter Wemm ** The message is written onto fp. 4815c2aa98e2SPeter Wemm */ 4816c2aa98e2SPeter Wemm 4817c2aa98e2SPeter Wemm /* values for output state variable */ 48184e4196cbSGregory Neil Shapiro #define OSTATE_HEAD 0 /* at beginning of line */ 48194e4196cbSGregory Neil Shapiro #define OSTATE_CR 1 /* read a carriage return */ 48204e4196cbSGregory Neil Shapiro #define OSTATE_INLINE 2 /* putting rest of line */ 4821c2aa98e2SPeter Wemm 48224e4196cbSGregory Neil Shapiro bool 4823c2aa98e2SPeter Wemm putbody(mci, e, separator) 4824c2aa98e2SPeter Wemm register MCI *mci; 4825c2aa98e2SPeter Wemm register ENVELOPE *e; 4826c2aa98e2SPeter Wemm char *separator; 4827c2aa98e2SPeter Wemm { 482840266059SGregory Neil Shapiro bool dead = false; 48294e4196cbSGregory Neil Shapiro bool ioerr = false; 48304e4196cbSGregory Neil Shapiro int save_errno; 4831c2aa98e2SPeter Wemm char buf[MAXLINE]; 483240266059SGregory Neil Shapiro #if MIME8TO7 4833065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1]; 4834*5b0945b5SGregory Neil Shapiro #endif 4835c2aa98e2SPeter Wemm 4836c2aa98e2SPeter Wemm /* 4837c2aa98e2SPeter Wemm ** Output the body of the message 4838c2aa98e2SPeter Wemm */ 4839c2aa98e2SPeter Wemm 4840c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 4841c2aa98e2SPeter Wemm { 484240266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 4843c2aa98e2SPeter Wemm 484440266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 4845a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL); 4846c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 484706f25ae9SGregory Neil Shapiro { 484806f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s"; 484906f25ae9SGregory Neil Shapiro 485006f25ae9SGregory Neil Shapiro if (errno == ENOENT) 485106f25ae9SGregory Neil Shapiro msg++; 485206f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr); 485306f25ae9SGregory Neil Shapiro } 485440266059SGregory Neil Shapiro 4855c2aa98e2SPeter Wemm } 4856c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 4857c2aa98e2SPeter Wemm { 4858c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4859c2aa98e2SPeter Wemm { 48604e4196cbSGregory Neil Shapiro if (!putline("", mci)) 48614e4196cbSGregory Neil Shapiro goto writeerr; 4862c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4863c2aa98e2SPeter Wemm } 48644e4196cbSGregory Neil Shapiro if (!putline("<<< No Message Collected >>>", mci)) 48654e4196cbSGregory Neil Shapiro goto writeerr; 4866c2aa98e2SPeter Wemm goto endofmessage; 4867c2aa98e2SPeter Wemm } 486806f25ae9SGregory Neil Shapiro 4869c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0) 4870c2aa98e2SPeter Wemm { 4871c2aa98e2SPeter Wemm struct stat stbuf; 4872c2aa98e2SPeter Wemm 487340266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 487440266059SGregory Neil Shapiro < 0) 4875c2aa98e2SPeter Wemm e->e_dfino = -1; 4876c2aa98e2SPeter Wemm else 4877c2aa98e2SPeter Wemm { 4878c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 4879c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 4880c2aa98e2SPeter Wemm } 4881c2aa98e2SPeter Wemm } 488206f25ae9SGregory Neil Shapiro 488340266059SGregory Neil Shapiro /* paranoia: the data file should always be in a rewound state */ 488406f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 4885c2aa98e2SPeter Wemm 48864e4196cbSGregory Neil Shapiro /* simulate an I/O timeout when used as source */ 48874e4196cbSGregory Neil Shapiro if (tTd(84, 101)) 48884e4196cbSGregory Neil Shapiro sleep(319); 48894e4196cbSGregory Neil Shapiro 4890c2aa98e2SPeter Wemm #if MIME8TO7 4891c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 4892c2aa98e2SPeter Wemm { 4893c2aa98e2SPeter Wemm /* 4894c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion. 4895c2aa98e2SPeter Wemm */ 4896c2aa98e2SPeter Wemm 4897c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */ 48984e4196cbSGregory Neil Shapiro if (hvalue("MIME-Version", e->e_header) == NULL && 48994e4196cbSGregory Neil Shapiro !putline("MIME-Version: 1.0", mci)) 49004e4196cbSGregory Neil Shapiro goto writeerr; 4901c2aa98e2SPeter Wemm 4902c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 4903c2aa98e2SPeter Wemm { 4904d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 4905c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 4906c2aa98e2SPeter Wemm defcharset(e)); 49074e4196cbSGregory Neil Shapiro if (!putline(buf, mci)) 49084e4196cbSGregory Neil Shapiro goto writeerr; 4909c2aa98e2SPeter Wemm } 4910c2aa98e2SPeter Wemm 4911c2aa98e2SPeter Wemm /* now do the hard work */ 4912c2aa98e2SPeter Wemm boundaries[0] = NULL; 4913c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4914af9557fdSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER, 0) == 49154e4196cbSGregory Neil Shapiro SM_IO_EOF) 49164e4196cbSGregory Neil Shapiro goto writeerr; 4917c2aa98e2SPeter Wemm } 4918c2aa98e2SPeter Wemm # if MIME7TO8 4919c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 4920c2aa98e2SPeter Wemm { 49214e4196cbSGregory Neil Shapiro if (!mime7to8(mci, e->e_header, e)) 49224e4196cbSGregory Neil Shapiro goto writeerr; 4923c2aa98e2SPeter Wemm } 492406f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */ 4925065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 4926065a643dSPeter Wemm { 492706f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs; 492806f25ae9SGregory Neil Shapiro 4929065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */ 4930065a643dSPeter Wemm boundaries[0] = NULL; 4931065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER; 493206f25ae9SGregory Neil Shapiro 493306f25ae9SGregory Neil Shapiro /* 493406f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message 493506f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose 493606f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call 493706f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security 493806f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors. 493906f25ae9SGregory Neil Shapiro */ 494006f25ae9SGregory Neil Shapiro 494106f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags)) 494240266059SGregory Neil Shapiro SuprErrs = true; 494306f25ae9SGregory Neil Shapiro 49444e4196cbSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries, 4945af9557fdSGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7, 0) == SM_IO_EOF) 49464e4196cbSGregory Neil Shapiro goto writeerr; 494706f25ae9SGregory Neil Shapiro 494806f25ae9SGregory Neil Shapiro /* restore SuprErrs */ 494906f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs; 4950065a643dSPeter Wemm } 4951c2aa98e2SPeter Wemm else 495206f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */ 4953c2aa98e2SPeter Wemm { 4954c2aa98e2SPeter Wemm int ostate; 4955c2aa98e2SPeter Wemm register char *bp; 4956c2aa98e2SPeter Wemm register char *pbp; 4957c2aa98e2SPeter Wemm register int c; 4958c2aa98e2SPeter Wemm register char *xp; 4959c2aa98e2SPeter Wemm int padc; 4960c2aa98e2SPeter Wemm char *buflim; 4961c2aa98e2SPeter Wemm int pos = 0; 496206f25ae9SGregory Neil Shapiro char peekbuf[12]; 4963c2aa98e2SPeter Wemm 4964c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4965c2aa98e2SPeter Wemm { 49664e4196cbSGregory Neil Shapiro if (!putline("", mci)) 49674e4196cbSGregory Neil Shapiro goto writeerr; 4968c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4969c2aa98e2SPeter Wemm } 4970c2aa98e2SPeter Wemm 4971c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */ 4972d0cef73dSGregory Neil Shapiro buflim = &buf[sizeof(buf) - 1]; 4973c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 4974d0cef73dSGregory Neil Shapiro mci->mci_mailer->m_linelimit < sizeof(buf) - 1) 4975c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 4976c2aa98e2SPeter Wemm 4977c2aa98e2SPeter Wemm /* copy temp file to output with mapping */ 49784e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 4979c2aa98e2SPeter Wemm bp = buf; 4980c2aa98e2SPeter Wemm pbp = peekbuf; 498140266059SGregory Neil Shapiro while (!sm_io_error(mci->mci_out) && !dead) 4982c2aa98e2SPeter Wemm { 4983c2aa98e2SPeter Wemm if (pbp > peekbuf) 4984c2aa98e2SPeter Wemm c = *--pbp; 498540266059SGregory Neil Shapiro else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 498640266059SGregory Neil Shapiro == SM_IO_EOF) 4987c2aa98e2SPeter Wemm break; 4988c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags)) 4989c2aa98e2SPeter Wemm c &= 0x7f; 4990c2aa98e2SPeter Wemm switch (ostate) 4991c2aa98e2SPeter Wemm { 49924e4196cbSGregory Neil Shapiro case OSTATE_HEAD: 4993c2aa98e2SPeter Wemm if (c == '\0' && 499440266059SGregory Neil Shapiro bitnset(M_NONULLS, 499540266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4996c2aa98e2SPeter Wemm break; 4997c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim) 4998c2aa98e2SPeter Wemm { 4999c2aa98e2SPeter Wemm *bp++ = c; 5000c2aa98e2SPeter Wemm break; 5001c2aa98e2SPeter Wemm } 5002c2aa98e2SPeter Wemm 5003c2aa98e2SPeter Wemm /* check beginning of line for special cases */ 5004c2aa98e2SPeter Wemm *bp = '\0'; 5005c2aa98e2SPeter Wemm pos = 0; 500640266059SGregory Neil Shapiro padc = SM_IO_EOF; 5007c2aa98e2SPeter Wemm if (buf[0] == 'F' && 500840266059SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 500940266059SGregory Neil Shapiro && strncmp(buf, "From ", 5) == 0) 5010c2aa98e2SPeter Wemm { 5011c2aa98e2SPeter Wemm padc = '>'; 5012c2aa98e2SPeter Wemm } 5013c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' && 5014c2aa98e2SPeter Wemm separator != NULL) 5015c2aa98e2SPeter Wemm { 5016c2aa98e2SPeter Wemm /* possible separator */ 5017c2aa98e2SPeter Wemm int sl = strlen(separator); 5018c2aa98e2SPeter Wemm 501940266059SGregory Neil Shapiro if (strncmp(&buf[2], separator, sl) 502040266059SGregory Neil Shapiro == 0) 5021c2aa98e2SPeter Wemm padc = ' '; 5022c2aa98e2SPeter Wemm } 5023c2aa98e2SPeter Wemm if (buf[0] == '.' && 5024c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 5025c2aa98e2SPeter Wemm { 5026c2aa98e2SPeter Wemm padc = '.'; 5027c2aa98e2SPeter Wemm } 5028c2aa98e2SPeter Wemm 5029c2aa98e2SPeter Wemm /* now copy out saved line */ 5030c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 5031c2aa98e2SPeter Wemm { 503240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 503340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 503440266059SGregory Neil Shapiro "%05d >>> ", 503540266059SGregory Neil Shapiro (int) CurrentPid); 503640266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 503740266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 503840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 503940266059SGregory Neil Shapiro padc); 5040c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 504140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 504240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 504340266059SGregory Neil Shapiro (unsigned char) *xp); 5044c2aa98e2SPeter Wemm if (c == '\n') 504540266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 504640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 504740266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 5048c2aa98e2SPeter Wemm } 504940266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 5050c2aa98e2SPeter Wemm { 505140266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 505240266059SGregory Neil Shapiro SM_TIME_DEFAULT, padc) 505340266059SGregory Neil Shapiro == SM_IO_EOF) 505406f25ae9SGregory Neil Shapiro { 505540266059SGregory Neil Shapiro dead = true; 505606f25ae9SGregory Neil Shapiro continue; 505706f25ae9SGregory Neil Shapiro } 5058c2aa98e2SPeter Wemm pos++; 5059c2aa98e2SPeter Wemm } 5060c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 5061c2aa98e2SPeter Wemm { 506240266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 506340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 506440266059SGregory Neil Shapiro (unsigned char) *xp) 506540266059SGregory Neil Shapiro == SM_IO_EOF) 506606f25ae9SGregory Neil Shapiro { 506740266059SGregory Neil Shapiro dead = true; 506806f25ae9SGregory Neil Shapiro break; 5069c2aa98e2SPeter Wemm } 5070193538b7SGregory Neil Shapiro } 507106f25ae9SGregory Neil Shapiro if (dead) 507206f25ae9SGregory Neil Shapiro continue; 5073c2aa98e2SPeter Wemm if (c == '\n') 5074c2aa98e2SPeter Wemm { 507540266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 507640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 507740266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 507840266059SGregory Neil Shapiro == SM_IO_EOF) 507906f25ae9SGregory Neil Shapiro break; 5080c2aa98e2SPeter Wemm pos = 0; 5081c2aa98e2SPeter Wemm } 5082c2aa98e2SPeter Wemm else 5083c2aa98e2SPeter Wemm { 5084c2aa98e2SPeter Wemm pos += bp - buf; 5085c2aa98e2SPeter Wemm if (c != '\r') 50865ef517c0SGregory Neil Shapiro { 50875ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 50885ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 5089c2aa98e2SPeter Wemm *pbp++ = c; 5090c2aa98e2SPeter Wemm } 50915ef517c0SGregory Neil Shapiro } 509206f25ae9SGregory Neil Shapiro 5093c2aa98e2SPeter Wemm bp = buf; 5094c2aa98e2SPeter Wemm 5095c2aa98e2SPeter Wemm /* determine next state */ 5096c2aa98e2SPeter Wemm if (c == '\n') 50974e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 5098c2aa98e2SPeter Wemm else if (c == '\r') 50994e4196cbSGregory Neil Shapiro ostate = OSTATE_CR; 5100c2aa98e2SPeter Wemm else 51014e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 5102c2aa98e2SPeter Wemm continue; 5103c2aa98e2SPeter Wemm 51044e4196cbSGregory Neil Shapiro case OSTATE_CR: 5105c2aa98e2SPeter Wemm if (c == '\n') 5106c2aa98e2SPeter Wemm { 5107c2aa98e2SPeter Wemm /* got CRLF */ 510840266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 510940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 511040266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 511140266059SGregory Neil Shapiro == SM_IO_EOF) 511206f25ae9SGregory Neil Shapiro continue; 511306f25ae9SGregory Neil Shapiro 5114c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 5115c2aa98e2SPeter Wemm { 511640266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 511740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 511840266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 5119c2aa98e2SPeter Wemm } 5120d0cef73dSGregory Neil Shapiro pos = 0; 51214e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 5122c2aa98e2SPeter Wemm continue; 5123c2aa98e2SPeter Wemm } 5124c2aa98e2SPeter Wemm 5125c2aa98e2SPeter Wemm /* had a naked carriage return */ 51265ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 5127c2aa98e2SPeter Wemm *pbp++ = c; 5128c2aa98e2SPeter Wemm c = '\r'; 51294e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 5130c2aa98e2SPeter Wemm goto putch; 5131c2aa98e2SPeter Wemm 51324e4196cbSGregory Neil Shapiro case OSTATE_INLINE: 5133c2aa98e2SPeter Wemm if (c == '\r') 5134c2aa98e2SPeter Wemm { 51354e4196cbSGregory Neil Shapiro ostate = OSTATE_CR; 5136c2aa98e2SPeter Wemm continue; 5137c2aa98e2SPeter Wemm } 5138c2aa98e2SPeter Wemm if (c == '\0' && 513940266059SGregory Neil Shapiro bitnset(M_NONULLS, 514040266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 5141c2aa98e2SPeter Wemm break; 5142c2aa98e2SPeter Wemm putch: 5143c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 514406f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 && 5145c2aa98e2SPeter Wemm c != '\n') 5146c2aa98e2SPeter Wemm { 514706f25ae9SGregory Neil Shapiro int d; 514806f25ae9SGregory Neil Shapiro 514906f25ae9SGregory Neil Shapiro /* check next character for EOL */ 515006f25ae9SGregory Neil Shapiro if (pbp > peekbuf) 515106f25ae9SGregory Neil Shapiro d = *(pbp - 1); 515240266059SGregory Neil Shapiro else if ((d = sm_io_getc(e->e_dfp, 515340266059SGregory Neil Shapiro SM_TIME_DEFAULT)) 515440266059SGregory Neil Shapiro != SM_IO_EOF) 51555ef517c0SGregory Neil Shapiro { 51565ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 51575ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 515806f25ae9SGregory Neil Shapiro *pbp++ = d; 51595ef517c0SGregory Neil Shapiro } 516006f25ae9SGregory Neil Shapiro 516140266059SGregory Neil Shapiro if (d == '\n' || d == SM_IO_EOF) 516206f25ae9SGregory Neil Shapiro { 516306f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL) 516440266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 516540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 516640266059SGregory Neil Shapiro (unsigned char) c); 516740266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 516840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 516940266059SGregory Neil Shapiro (unsigned char) c) 517040266059SGregory Neil Shapiro == SM_IO_EOF) 517106f25ae9SGregory Neil Shapiro { 517240266059SGregory Neil Shapiro dead = true; 517306f25ae9SGregory Neil Shapiro continue; 517406f25ae9SGregory Neil Shapiro } 517506f25ae9SGregory Neil Shapiro pos++; 517606f25ae9SGregory Neil Shapiro continue; 517706f25ae9SGregory Neil Shapiro } 517806f25ae9SGregory Neil Shapiro 517940266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 518040266059SGregory Neil Shapiro SM_TIME_DEFAULT, '!') 518140266059SGregory Neil Shapiro == SM_IO_EOF || 518240266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out, 518340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 518440266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 518540266059SGregory Neil Shapiro == SM_IO_EOF) 518606f25ae9SGregory Neil Shapiro { 518740266059SGregory Neil Shapiro dead = true; 518806f25ae9SGregory Neil Shapiro continue; 518906f25ae9SGregory Neil Shapiro } 519006f25ae9SGregory Neil Shapiro 5191c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 5192c2aa98e2SPeter Wemm { 519340266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 519440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 519540266059SGregory Neil Shapiro "!%s", 5196c2aa98e2SPeter Wemm mci->mci_mailer->m_eol); 5197c2aa98e2SPeter Wemm } 51984e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 51995ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 52005ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 5201c2aa98e2SPeter Wemm *pbp++ = c; 5202c2aa98e2SPeter Wemm continue; 5203c2aa98e2SPeter Wemm } 5204c2aa98e2SPeter Wemm if (c == '\n') 5205c2aa98e2SPeter Wemm { 5206c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 520740266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 520840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 520940266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 521040266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 521140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 521240266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 521340266059SGregory Neil Shapiro == SM_IO_EOF) 521406f25ae9SGregory Neil Shapiro continue; 5215c2aa98e2SPeter Wemm pos = 0; 52164e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 5217c2aa98e2SPeter Wemm } 5218c2aa98e2SPeter Wemm else 5219c2aa98e2SPeter Wemm { 5220c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 522140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 522240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 522340266059SGregory Neil Shapiro (unsigned char) c); 522440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 522540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 522640266059SGregory Neil Shapiro (unsigned char) c) 522740266059SGregory Neil Shapiro == SM_IO_EOF) 522806f25ae9SGregory Neil Shapiro { 522940266059SGregory Neil Shapiro dead = true; 523006f25ae9SGregory Neil Shapiro continue; 523106f25ae9SGregory Neil Shapiro } 5232c2aa98e2SPeter Wemm pos++; 52334e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 5234c2aa98e2SPeter Wemm } 5235c2aa98e2SPeter Wemm break; 5236c2aa98e2SPeter Wemm } 5237c2aa98e2SPeter Wemm } 5238c2aa98e2SPeter Wemm 5239c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */ 5240c2aa98e2SPeter Wemm if (bp > buf) 5241c2aa98e2SPeter Wemm { 5242c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 5243c2aa98e2SPeter Wemm { 5244c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 524540266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 524640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 524740266059SGregory Neil Shapiro (unsigned char) *xp); 5248c2aa98e2SPeter Wemm } 5249c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 5250c2aa98e2SPeter Wemm { 525140266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 525240266059SGregory Neil Shapiro (unsigned char) *xp) 525340266059SGregory Neil Shapiro == SM_IO_EOF) 525406f25ae9SGregory Neil Shapiro { 525540266059SGregory Neil Shapiro dead = true; 525606f25ae9SGregory Neil Shapiro break; 525706f25ae9SGregory Neil Shapiro } 5258193538b7SGregory Neil Shapiro } 5259c2aa98e2SPeter Wemm pos += bp - buf; 5260c2aa98e2SPeter Wemm } 526106f25ae9SGregory Neil Shapiro if (!dead && pos > 0) 5262c2aa98e2SPeter Wemm { 5263c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 526440266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 526540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 526640266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 52674e4196cbSGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 52684e4196cbSGregory Neil Shapiro mci->mci_mailer->m_eol) == SM_IO_EOF) 52694e4196cbSGregory Neil Shapiro goto writeerr; 5270c2aa98e2SPeter Wemm } 5271c2aa98e2SPeter Wemm } 5272c2aa98e2SPeter Wemm 527340266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp)) 5274c2aa98e2SPeter Wemm { 527540266059SGregory Neil Shapiro syserr("putbody: %s/%cf%s: read error", 527640266059SGregory Neil Shapiro qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 527740266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 5278c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 52794e4196cbSGregory Neil Shapiro ioerr = true; 5280c2aa98e2SPeter Wemm } 5281c2aa98e2SPeter Wemm 5282c2aa98e2SPeter Wemm endofmessage: 528306f25ae9SGregory Neil Shapiro /* 528406f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process, 528506f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the 528606f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel 528706f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared 528806f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital 528906f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the 529006f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell) 529106f25ae9SGregory Neil Shapiro ** offset to match. 529206f25ae9SGregory Neil Shapiro */ 529306f25ae9SGregory Neil Shapiro 52944e4196cbSGregory Neil Shapiro save_errno = errno; 529506f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) 529606f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 529706f25ae9SGregory Neil Shapiro 5298c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */ 529906f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 5300c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n') 5301c2aa98e2SPeter Wemm { 53024e4196cbSGregory Neil Shapiro if (!putline("", mci)) 53034e4196cbSGregory Neil Shapiro goto writeerr; 53044e4196cbSGregory Neil Shapiro } 53054e4196cbSGregory Neil Shapiro 53064e4196cbSGregory Neil Shapiro if (!dead && 53074e4196cbSGregory Neil Shapiro (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF || 53084e4196cbSGregory Neil Shapiro (sm_io_error(mci->mci_out) && errno != EPIPE))) 53094e4196cbSGregory Neil Shapiro { 53104e4196cbSGregory Neil Shapiro save_errno = errno; 5311c2aa98e2SPeter Wemm syserr("putbody: write error"); 5312c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 53134e4196cbSGregory Neil Shapiro ioerr = true; 5314c2aa98e2SPeter Wemm } 531506f25ae9SGregory Neil Shapiro 53164e4196cbSGregory Neil Shapiro errno = save_errno; 53174e4196cbSGregory Neil Shapiro return !dead && !ioerr; 53184e4196cbSGregory Neil Shapiro 53194e4196cbSGregory Neil Shapiro writeerr: 53204e4196cbSGregory Neil Shapiro return false; 5321c2aa98e2SPeter Wemm } 53224e4196cbSGregory Neil Shapiro 532340266059SGregory Neil Shapiro /* 5324c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file. 5325c2aa98e2SPeter Wemm ** 532640266059SGregory Neil Shapiro ** If the file has the set-user-ID/set-group-ID bits set, but NO 532740266059SGregory Neil Shapiro ** execute bits, sendmail will try to become the owner of that file 5328c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if 5329c2aa98e2SPeter Wemm ** sendmail runs as root. 5330c2aa98e2SPeter Wemm ** 5331c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it 5332c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We 5333c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it 5334c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have 5335c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message. 5336c2aa98e2SPeter Wemm ** 5337c2aa98e2SPeter Wemm ** Parameters: 5338c2aa98e2SPeter Wemm ** filename -- the name of the file to send to. 5339c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL, 5340c2aa98e2SPeter Wemm ** use FileMailer. 5341c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes 5342c2aa98e2SPeter Wemm ** the userid/groupid to be when sending. 5343c2aa98e2SPeter Wemm ** sfflags -- flags for opening. 5344c2aa98e2SPeter Wemm ** e -- the current envelope. 5345c2aa98e2SPeter Wemm ** 5346c2aa98e2SPeter Wemm ** Returns: 5347c2aa98e2SPeter Wemm ** The exit code associated with the operation. 5348c2aa98e2SPeter Wemm ** 5349c2aa98e2SPeter Wemm ** Side Effects: 5350c2aa98e2SPeter Wemm ** none. 5351c2aa98e2SPeter Wemm */ 5352c2aa98e2SPeter Wemm 535340266059SGregory Neil Shapiro # define RETURN(st) exit(st); 535440266059SGregory Neil Shapiro 5355c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout; 5356c2aa98e2SPeter Wemm 5357c2aa98e2SPeter Wemm int 5358c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e) 5359c2aa98e2SPeter Wemm char *volatile filename; 5360c2aa98e2SPeter Wemm MAILER *volatile mailer; 5361c2aa98e2SPeter Wemm ADDRESS *ctladdr; 536206f25ae9SGregory Neil Shapiro volatile long sfflags; 5363c2aa98e2SPeter Wemm register ENVELOPE *e; 5364c2aa98e2SPeter Wemm { 536540266059SGregory Neil Shapiro register SM_FILE_T *f; 5366c2aa98e2SPeter Wemm register pid_t pid = -1; 536706f25ae9SGregory Neil Shapiro volatile int mode; 536806f25ae9SGregory Neil Shapiro int len; 536906f25ae9SGregory Neil Shapiro off_t curoff; 5370c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0; 5371c2aa98e2SPeter Wemm char *p; 537206f25ae9SGregory Neil Shapiro char *volatile realfile; 537340266059SGregory Neil Shapiro SM_EVENT *ev; 537494c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 537594c01205SGregory Neil Shapiro char targetfile[MAXPATHLEN]; 5376c2aa98e2SPeter Wemm 5377c2aa98e2SPeter Wemm if (tTd(11, 1)) 5378c2aa98e2SPeter Wemm { 537940266059SGregory Neil Shapiro sm_dprintf("mailfile %s\n ctladdr=", filename); 5380e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false); 5381c2aa98e2SPeter Wemm } 5382c2aa98e2SPeter Wemm 5383c2aa98e2SPeter Wemm if (mailer == NULL) 5384c2aa98e2SPeter Wemm mailer = FileMailer; 5385c2aa98e2SPeter Wemm 5386c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 538740266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 5388c2aa98e2SPeter Wemm 5389c2aa98e2SPeter Wemm /* 5390c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file 5391c2aa98e2SPeter Wemm ** delivery to regular files only. 5392c2aa98e2SPeter Wemm */ 5393c2aa98e2SPeter Wemm 539440266059SGregory Neil Shapiro if (sm_path_isdevnull(filename)) 5395c2aa98e2SPeter Wemm return EX_OK; 5396c2aa98e2SPeter Wemm 5397c2aa98e2SPeter Wemm /* check for 8-bit available */ 5398c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5399c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) && 5400c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 5401c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 5402c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 5403c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 5404c2aa98e2SPeter Wemm { 5405c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 540606f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 540706f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 540840266059SGregory Neil Shapiro errno = 0; 540906f25ae9SGregory Neil Shapiro return EX_DATAERR; 541006f25ae9SGregory Neil Shapiro } 541106f25ae9SGregory Neil Shapiro 541206f25ae9SGregory Neil Shapiro /* Find the actual file */ 541306f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 541406f25ae9SGregory Neil Shapiro { 541506f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv); 541606f25ae9SGregory Neil Shapiro 541706f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0) 541806f25ae9SGregory Neil Shapiro filename += len; 541906f25ae9SGregory Neil Shapiro 5420d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile)) 542106f25ae9SGregory Neil Shapiro { 542206f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 542306f25ae9SGregory Neil Shapiro SafeFileEnv, filename); 542406f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 542506f25ae9SGregory Neil Shapiro } 5426d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof(targetfile)); 542706f25ae9SGregory Neil Shapiro realfile = targetfile + len; 542806f25ae9SGregory Neil Shapiro if (*filename == '/') 542906f25ae9SGregory Neil Shapiro filename++; 5430605302a5SGregory Neil Shapiro if (*filename != '\0') 5431605302a5SGregory Neil Shapiro { 5432605302a5SGregory Neil Shapiro /* paranoia: trailing / should be removed in readcf */ 5433605302a5SGregory Neil Shapiro if (targetfile[len - 1] != '/') 5434605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, 5435d0cef73dSGregory Neil Shapiro "/", sizeof(targetfile)); 5436605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 5437d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 5438605302a5SGregory Neil Shapiro } 543906f25ae9SGregory Neil Shapiro } 544006f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL) 544106f25ae9SGregory Neil Shapiro { 5442d0cef73dSGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof(targetfile), e); 544306f25ae9SGregory Neil Shapiro len = strlen(targetfile); 544406f25ae9SGregory Neil Shapiro 544506f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0) 544606f25ae9SGregory Neil Shapiro filename += len; 544706f25ae9SGregory Neil Shapiro 5448d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile)) 544906f25ae9SGregory Neil Shapiro { 545006f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 545106f25ae9SGregory Neil Shapiro targetfile, filename); 545206f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 545306f25ae9SGregory Neil Shapiro } 545406f25ae9SGregory Neil Shapiro realfile = targetfile + len; 545506f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 5456d0cef73dSGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof(targetfile)); 545706f25ae9SGregory Neil Shapiro if (*filename == '/') 545840266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename + 1, 5459d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 546006f25ae9SGregory Neil Shapiro else 546140266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 5462d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 546306f25ae9SGregory Neil Shapiro } 546406f25ae9SGregory Neil Shapiro else 546506f25ae9SGregory Neil Shapiro { 5466d0cef73dSGregory Neil Shapiro if (sm_strlcpy(targetfile, filename, sizeof(targetfile)) >= 5467d0cef73dSGregory Neil Shapiro sizeof(targetfile)) 546806f25ae9SGregory Neil Shapiro { 546906f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename); 547006f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 547106f25ae9SGregory Neil Shapiro } 547206f25ae9SGregory Neil Shapiro realfile = targetfile; 5473c2aa98e2SPeter Wemm } 5474c2aa98e2SPeter Wemm 5475c2aa98e2SPeter Wemm /* 5476c2aa98e2SPeter Wemm ** Fork so we can change permissions here. 5477c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of 5478c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc. 5479c2aa98e2SPeter Wemm */ 5480c2aa98e2SPeter Wemm 5481605302a5SGregory Neil Shapiro 5482605302a5SGregory Neil Shapiro /* 5483605302a5SGregory Neil Shapiro ** Dispose of SIGCHLD signal catchers that may be laying 5484605302a5SGregory Neil Shapiro ** around so that the waitfor() below will get it. 5485605302a5SGregory Neil Shapiro */ 5486605302a5SGregory Neil Shapiro 5487605302a5SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 5488605302a5SGregory Neil Shapiro 5489c2aa98e2SPeter Wemm DOFORK(fork); 5490c2aa98e2SPeter Wemm 5491c2aa98e2SPeter Wemm if (pid < 0) 549206f25ae9SGregory Neil Shapiro return EX_OSERR; 5493c2aa98e2SPeter Wemm else if (pid == 0) 5494c2aa98e2SPeter Wemm { 5495c2aa98e2SPeter Wemm /* child -- actually write to file */ 5496c2aa98e2SPeter Wemm struct stat stb; 5497c2aa98e2SPeter Wemm MCI mcibuf; 5498065a643dSPeter Wemm int err; 5499c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND; 5500c2aa98e2SPeter Wemm 55018774250cSGregory Neil Shapiro /* Reset global flags */ 55028774250cSGregory Neil Shapiro RestartRequest = NULL; 550340266059SGregory Neil Shapiro RestartWorkGroup = false; 55048774250cSGregory Neil Shapiro ShutdownRequest = NULL; 55058774250cSGregory Neil Shapiro PendingSignal = 0; 550640266059SGregory Neil Shapiro CurrentPid = getpid(); 55078774250cSGregory Neil Shapiro 5508c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 5509af9557fdSGregory Neil Shapiro { 5510af9557fdSGregory Neil Shapiro int fd; 5511af9557fdSGregory Neil Shapiro 5512af9557fdSGregory Neil Shapiro fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL); 5513af9557fdSGregory Neil Shapiro /* SM_ASSERT(fd >= 0); */ 5514af9557fdSGregory Neil Shapiro if (fd >= 0) 5515af9557fdSGregory Neil Shapiro (void) close(fd); 5516af9557fdSGregory Neil Shapiro } 5517c2aa98e2SPeter Wemm 551840266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_DFL); 551940266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_DFL); 552040266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 5521c2aa98e2SPeter Wemm (void) umask(OldUmask); 5522c2aa98e2SPeter Wemm e->e_to = filename; 5523c2aa98e2SPeter Wemm ExitStat = EX_OK; 5524c2aa98e2SPeter Wemm 5525c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0) 5526c2aa98e2SPeter Wemm { 552740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 5528c2aa98e2SPeter Wemm } 5529c2aa98e2SPeter Wemm 5530c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0) 553140266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 553240266059SGregory Neil Shapiro 0); 5533c2aa98e2SPeter Wemm else 5534c2aa98e2SPeter Wemm ev = NULL; 5535c2aa98e2SPeter Wemm 553640266059SGregory Neil Shapiro /* check file mode to see if set-user-ID */ 553706f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0) 5538c2aa98e2SPeter Wemm mode = FileMode; 553906f25ae9SGregory Neil Shapiro else 5540c2aa98e2SPeter Wemm mode = stb.st_mode; 5541c2aa98e2SPeter Wemm 5542c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */ 5543c2aa98e2SPeter Wemm errno = 0; 5544c2aa98e2SPeter Wemm ExitStat = EX_OK; 5545c2aa98e2SPeter Wemm 554606f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */ 554706f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 554806f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags)) 5549c2aa98e2SPeter Wemm { 555040266059SGregory Neil Shapiro /* ignore set-user-ID and set-group-ID bits */ 5551c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID); 555206f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 555340266059SGregory Neil Shapiro sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 5554c2aa98e2SPeter Wemm } 5555c2aa98e2SPeter Wemm 555640266059SGregory Neil Shapiro /* we have to open the data file BEFORE setuid() */ 5557c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 5558c2aa98e2SPeter Wemm { 555940266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 5560c2aa98e2SPeter Wemm 556140266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 5562a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL); 5563c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 5564c2aa98e2SPeter Wemm { 5565c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s", 5566c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr); 5567c2aa98e2SPeter Wemm } 5568c2aa98e2SPeter Wemm } 5569c2aa98e2SPeter Wemm 5570c2aa98e2SPeter Wemm /* select a new user to run as */ 5571c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags)) 5572c2aa98e2SPeter Wemm { 5573c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 5574c2aa98e2SPeter Wemm { 5575c2aa98e2SPeter Wemm RealUserName = NULL; 5576e92d3f3fSGregory Neil Shapiro if (mailer->m_uid == NO_UID) 5577e92d3f3fSGregory Neil Shapiro RealUid = RunAsUid; 5578e92d3f3fSGregory Neil Shapiro else 5579c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 558006f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid) 558106f25ae9SGregory Neil Shapiro { 558206f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 5583da7d7b9cSGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid, RunAsUid=%ld, RealUid=%ld", 5584da7d7b9cSGregory Neil Shapiro (long) RunAsUid, (long) RealUid); 558540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 558606f25ae9SGregory Neil Shapiro } 5587c2aa98e2SPeter Wemm } 5588c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode)) 5589c2aa98e2SPeter Wemm { 5590c2aa98e2SPeter Wemm RealUserName = NULL; 5591c2aa98e2SPeter Wemm RealUid = stb.st_uid; 5592c2aa98e2SPeter Wemm } 5593c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 5594c2aa98e2SPeter Wemm { 5595c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL) 5596c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser; 5597c2aa98e2SPeter Wemm else 5598c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user; 5599c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid; 5600c2aa98e2SPeter Wemm } 5601e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_uid != NO_UID) 5602c2aa98e2SPeter Wemm { 5603c2aa98e2SPeter Wemm RealUserName = DefUser; 5604c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 5605c2aa98e2SPeter Wemm } 5606c2aa98e2SPeter Wemm else 5607c2aa98e2SPeter Wemm { 5608c2aa98e2SPeter Wemm RealUserName = DefUser; 5609c2aa98e2SPeter Wemm RealUid = DefUid; 5610c2aa98e2SPeter Wemm } 5611c2aa98e2SPeter Wemm 5612c2aa98e2SPeter Wemm /* select a new group to run as */ 5613c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 561406f25ae9SGregory Neil Shapiro { 5615e92d3f3fSGregory Neil Shapiro if (mailer->m_gid == NO_GID) 5616e92d3f3fSGregory Neil Shapiro RealGid = RunAsGid; 5617e92d3f3fSGregory Neil Shapiro else 5618c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 561906f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 562006f25ae9SGregory Neil Shapiro (RealGid != getgid() || 562106f25ae9SGregory Neil Shapiro RealGid != getegid())) 562206f25ae9SGregory Neil Shapiro { 562306f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 5624da7d7b9cSGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid, RealGid=%ld, RunAsUid=%ld, gid=%ld, egid=%ld", 5625da7d7b9cSGregory Neil Shapiro (long) RealGid, (long) RunAsUid, 5626da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid()); 562740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 562806f25ae9SGregory Neil Shapiro } 562906f25ae9SGregory Neil Shapiro } 5630c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode)) 5631c2aa98e2SPeter Wemm RealGid = stb.st_gid; 563206f25ae9SGregory Neil Shapiro else if (ctladdr != NULL && 563306f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid && 563406f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0) 5635193538b7SGregory Neil Shapiro { 5636193538b7SGregory Neil Shapiro /* 5637193538b7SGregory Neil Shapiro ** Special case: This means it is an 5638193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser. 5639193538b7SGregory Neil Shapiro ** See alias()'s comments. 5640193538b7SGregory Neil Shapiro */ 5641193538b7SGregory Neil Shapiro 564206f25ae9SGregory Neil Shapiro RealGid = DefGid; 5643193538b7SGregory Neil Shapiro RealUserName = DefUser; 5644193538b7SGregory Neil Shapiro } 5645193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0) 5646193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid; 5647e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_gid != NO_GID) 5648c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 5649c2aa98e2SPeter Wemm else 5650c2aa98e2SPeter Wemm RealGid = DefGid; 5651c2aa98e2SPeter Wemm } 5652c2aa98e2SPeter Wemm 5653c2aa98e2SPeter Wemm /* last ditch */ 5654c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags)) 5655c2aa98e2SPeter Wemm { 5656c2aa98e2SPeter Wemm if (RealUid == 0) 5657c2aa98e2SPeter Wemm RealUid = DefUid; 5658c2aa98e2SPeter Wemm if (RealGid == 0) 5659c2aa98e2SPeter Wemm RealGid = DefGid; 5660c2aa98e2SPeter Wemm } 5661c2aa98e2SPeter Wemm 5662c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */ 5663c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups) 5664c2aa98e2SPeter Wemm { 5665c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 566606f25ae9SGregory Neil Shapiro { 5667da7d7b9cSGregory Neil Shapiro syserr("mailfile: initgroups(%s, %ld) failed", 5668da7d7b9cSGregory Neil Shapiro RealUserName, (long) RealGid); 566940266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 567006f25ae9SGregory Neil Shapiro } 5671c2aa98e2SPeter Wemm } 5672c2aa98e2SPeter Wemm else 5673c2aa98e2SPeter Wemm { 5674c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 5675c2aa98e2SPeter Wemm 5676c2aa98e2SPeter Wemm gidset[0] = RealGid; 5677c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 567806f25ae9SGregory Neil Shapiro { 5679c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed"); 568040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 568106f25ae9SGregory Neil Shapiro } 5682c2aa98e2SPeter Wemm } 5683c2aa98e2SPeter Wemm 568406f25ae9SGregory Neil Shapiro /* 568506f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it. 568606f25ae9SGregory Neil Shapiro */ 5687c2aa98e2SPeter Wemm 568806f25ae9SGregory Neil Shapiro if (realfile != targetfile) 568906f25ae9SGregory Neil Shapiro { 5690605302a5SGregory Neil Shapiro char save; 5691605302a5SGregory Neil Shapiro 5692605302a5SGregory Neil Shapiro save = *realfile; 569306f25ae9SGregory Neil Shapiro *realfile = '\0'; 569406f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 569540266059SGregory Neil Shapiro sm_dprintf("mailfile: chroot %s\n", targetfile); 569606f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0) 5697c2aa98e2SPeter Wemm { 5698c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)", 569906f25ae9SGregory Neil Shapiro targetfile); 570040266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5701c2aa98e2SPeter Wemm } 5702605302a5SGregory Neil Shapiro *realfile = save; 5703c2aa98e2SPeter Wemm } 570406f25ae9SGregory Neil Shapiro 570506f25ae9SGregory Neil Shapiro if (tTd(11, 40)) 570640266059SGregory Neil Shapiro sm_dprintf("mailfile: deliver to %s\n", realfile); 570706f25ae9SGregory Neil Shapiro 5708c2aa98e2SPeter Wemm if (chdir("/") < 0) 570906f25ae9SGregory Neil Shapiro { 5710c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)"); 571140266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 571206f25ae9SGregory Neil Shapiro } 5713c2aa98e2SPeter Wemm 5714c2aa98e2SPeter Wemm /* now reset the group and user ids */ 5715c2aa98e2SPeter Wemm endpwent(); 571640266059SGregory Neil Shapiro sm_mbdb_terminate(); 5717c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn) 571806f25ae9SGregory Neil Shapiro { 5719c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid); 572040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 572106f25ae9SGregory Neil Shapiro } 5722c2aa98e2SPeter Wemm vendor_set_uid(RealUid); 5723c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn) 572406f25ae9SGregory Neil Shapiro { 5725c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid); 572640266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 572706f25ae9SGregory Neil Shapiro } 572806f25ae9SGregory Neil Shapiro 572906f25ae9SGregory Neil Shapiro if (tTd(11, 2)) 5730da7d7b9cSGregory Neil Shapiro sm_dprintf("mailfile: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n", 5731da7d7b9cSGregory Neil Shapiro (long) getuid(), (long) geteuid(), 5732da7d7b9cSGregory Neil Shapiro (long) getgid(), (long) getegid()); 573306f25ae9SGregory Neil Shapiro 5734c2aa98e2SPeter Wemm 5735c2aa98e2SPeter Wemm /* move into some "safe" directory */ 5736c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL) 5737c2aa98e2SPeter Wemm { 5738c2aa98e2SPeter Wemm char *q; 5739c2aa98e2SPeter Wemm 5740c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q) 5741c2aa98e2SPeter Wemm { 5742c2aa98e2SPeter Wemm q = strchr(p, ':'); 5743c2aa98e2SPeter Wemm if (q != NULL) 5744c2aa98e2SPeter Wemm *q = '\0'; 5745d0cef73dSGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 5746c2aa98e2SPeter Wemm if (q != NULL) 5747c2aa98e2SPeter Wemm *q++ = ':'; 5748c2aa98e2SPeter Wemm if (tTd(11, 20)) 574940266059SGregory Neil Shapiro sm_dprintf("mailfile: trydir %s\n", 575040266059SGregory Neil Shapiro buf); 5751c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 5752c2aa98e2SPeter Wemm break; 5753c2aa98e2SPeter Wemm } 5754c2aa98e2SPeter Wemm } 5755c2aa98e2SPeter Wemm 575606f25ae9SGregory Neil Shapiro /* 575706f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the 575806f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as 575906f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running 576006f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats 576106f25ae9SGregory Neil Shapiro ** root as nobody. 576206f25ae9SGregory Neil Shapiro */ 576306f25ae9SGregory Neil Shapiro 576406f25ae9SGregory Neil Shapiro #if HASLSTAT 576506f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 576606f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 576706f25ae9SGregory Neil Shapiro else 576806f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb); 576906f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 577006f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 577106f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 577206f25ae9SGregory Neil Shapiro 577306f25ae9SGregory Neil Shapiro if (err < 0) 577406f25ae9SGregory Neil Shapiro { 577506f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE; 577606f25ae9SGregory Neil Shapiro mode = FileMode; 577706f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL; 577806f25ae9SGregory Neil Shapiro } 577906f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 578006f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 578106f25ae9SGregory Neil Shapiro DontBlameSendmail) && 578206f25ae9SGregory Neil Shapiro stb.st_nlink != 1) || 578306f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode))) 578406f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 578506f25ae9SGregory Neil Shapiro else 578606f25ae9SGregory Neil Shapiro mode = stb.st_mode; 578706f25ae9SGregory Neil Shapiro 578806f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 5789c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK; 579006f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 5791c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK; 5792c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT; 579306f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags); 5794c2aa98e2SPeter Wemm if (f == NULL) 5795c2aa98e2SPeter Wemm { 579606f25ae9SGregory Neil Shapiro if (transienterror(errno)) 579706f25ae9SGregory Neil Shapiro { 579806f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s", 579906f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 580040266059SGregory Neil Shapiro sm_errstring(errno)); 580140266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 580206f25ae9SGregory Neil Shapiro } 580306f25ae9SGregory Neil Shapiro else 580406f25ae9SGregory Neil Shapiro { 580506f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s", 580606f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 580740266059SGregory Neil Shapiro sm_errstring(errno)); 580840266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5809c2aa98e2SPeter Wemm } 581006f25ae9SGregory Neil Shapiro } 581140266059SGregory Neil Shapiro if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 581240266059SGregory Neil Shapiro &stb)) 5813c2aa98e2SPeter Wemm { 581406f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open"); 581540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5816c2aa98e2SPeter Wemm } 581740266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 5818c2aa98e2SPeter Wemm { 581940266059SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s", 582040266059SGregory Neil Shapiro sm_errstring(errno)); 582140266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5822c2aa98e2SPeter Wemm } 5823c2aa98e2SPeter Wemm 582406f25ae9SGregory Neil Shapiro curoff = stb.st_size; 582506f25ae9SGregory Neil Shapiro 5826c2aa98e2SPeter Wemm if (ev != NULL) 582740266059SGregory Neil Shapiro sm_clrevent(ev); 5828c2aa98e2SPeter Wemm 5829d0cef73dSGregory Neil Shapiro memset(&mcibuf, '\0', sizeof(mcibuf)); 5830c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer; 5831c2aa98e2SPeter Wemm mcibuf.mci_out = f; 5832c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags)) 5833c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT; 5834c2aa98e2SPeter Wemm 5835c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 5836c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 5837c2aa98e2SPeter Wemm 5838c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5839c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 5840c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags)) 5841c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7; 5842c2aa98e2SPeter Wemm 5843c2aa98e2SPeter Wemm #if MIME7TO8 5844c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) && 5845c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) && 5846c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 584740266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 584840266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 5849c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 5850c2aa98e2SPeter Wemm { 5851c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 5852c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 585340266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 5854c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 5855c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8; 5856c2aa98e2SPeter Wemm } 585706f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 5858c2aa98e2SPeter Wemm 58594e4196cbSGregory Neil Shapiro if (!putfromline(&mcibuf, e) || 58604e4196cbSGregory Neil Shapiro !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) || 58614e4196cbSGregory Neil Shapiro !(*e->e_putbody)(&mcibuf, e, NULL) || 58624e4196cbSGregory Neil Shapiro !putline("\n", &mcibuf) || 58634e4196cbSGregory Neil Shapiro (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 586440266059SGregory Neil Shapiro (SuperSafe != SAFE_NO && 586540266059SGregory Neil Shapiro fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 58664e4196cbSGregory Neil Shapiro sm_io_error(f))) 5867c2aa98e2SPeter Wemm { 5868c2aa98e2SPeter Wemm setstat(EX_IOERR); 586906f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE 587040266059SGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 587140266059SGregory Neil Shapiro curoff); 5872*5b0945b5SGregory Neil Shapiro #endif 5873c2aa98e2SPeter Wemm } 5874c2aa98e2SPeter Wemm 5875c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */ 5876c2aa98e2SPeter Wemm #if HASFCHMOD 587740266059SGregory Neil Shapiro (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 587840266059SGregory Neil Shapiro (MODE_T) mode); 587906f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */ 588006f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode); 588106f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */ 588240266059SGregory Neil Shapiro if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 588306f25ae9SGregory Neil Shapiro setstat(EX_IOERR); 588440266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 588506f25ae9SGregory Neil Shapiro (void) setuid(RealUid); 5886c2aa98e2SPeter Wemm exit(ExitStat); 5887c2aa98e2SPeter Wemm /* NOTREACHED */ 5888c2aa98e2SPeter Wemm } 5889c2aa98e2SPeter Wemm else 5890c2aa98e2SPeter Wemm { 5891c2aa98e2SPeter Wemm /* parent -- wait for exit status */ 5892c2aa98e2SPeter Wemm int st; 5893c2aa98e2SPeter Wemm 5894c2aa98e2SPeter Wemm st = waitfor(pid); 5895c2aa98e2SPeter Wemm if (st == -1) 5896c2aa98e2SPeter Wemm { 5897c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name); 589806f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 5899c2aa98e2SPeter Wemm } 5900c2aa98e2SPeter Wemm if (WIFEXITED(st)) 590140266059SGregory Neil Shapiro { 590240266059SGregory Neil Shapiro errno = 0; 5903c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 590440266059SGregory Neil Shapiro } 5905c2aa98e2SPeter Wemm else 5906c2aa98e2SPeter Wemm { 5907c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d", 5908c2aa98e2SPeter Wemm mailer->m_name, st); 590906f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE; 5910c2aa98e2SPeter Wemm } 5911c2aa98e2SPeter Wemm /* NOTREACHED */ 5912c2aa98e2SPeter Wemm } 5913c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 5914c2aa98e2SPeter Wemm } 5915c2aa98e2SPeter Wemm 5916c2aa98e2SPeter Wemm static void 5917b6bacd31SGregory Neil Shapiro mailfiletimeout(ignore) 5918b6bacd31SGregory Neil Shapiro int ignore; 5919c2aa98e2SPeter Wemm { 59208774250cSGregory Neil Shapiro /* 59218774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 59228774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 59238774250cSGregory Neil Shapiro ** DOING. 59248774250cSGregory Neil Shapiro */ 59258774250cSGregory Neil Shapiro 59268774250cSGregory Neil Shapiro errno = ETIMEDOUT; 5927c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1); 5928c2aa98e2SPeter Wemm } 5929*5b0945b5SGregory Neil Shapiro 5930*5b0945b5SGregory Neil Shapiro #if DANE 5931*5b0945b5SGregory Neil Shapiro 5932*5b0945b5SGregory Neil Shapiro /* 5933*5b0945b5SGregory Neil Shapiro ** GETMPORT -- return the port of a mailer 5934*5b0945b5SGregory Neil Shapiro ** 5935*5b0945b5SGregory Neil Shapiro ** Parameters: 5936*5b0945b5SGregory Neil Shapiro ** m -- the mailer describing this host. 5937*5b0945b5SGregory Neil Shapiro ** 5938*5b0945b5SGregory Neil Shapiro ** Returns: 5939*5b0945b5SGregory Neil Shapiro ** the port of the mailer if defined. 5940*5b0945b5SGregory Neil Shapiro ** 0 otherwise 5941*5b0945b5SGregory Neil Shapiro ** <0 error 5942*5b0945b5SGregory Neil Shapiro */ 5943*5b0945b5SGregory Neil Shapiro 5944*5b0945b5SGregory Neil Shapiro static int getmport __P((MAILER *)); 5945*5b0945b5SGregory Neil Shapiro 5946*5b0945b5SGregory Neil Shapiro static int 5947*5b0945b5SGregory Neil Shapiro getmport(m) 5948*5b0945b5SGregory Neil Shapiro MAILER *m; 5949*5b0945b5SGregory Neil Shapiro { 5950*5b0945b5SGregory Neil Shapiro unsigned long ulval; 5951*5b0945b5SGregory Neil Shapiro char *buf, *ep; 5952*5b0945b5SGregory Neil Shapiro 5953*5b0945b5SGregory Neil Shapiro if (m->m_port > 0) 5954*5b0945b5SGregory Neil Shapiro return m->m_port; 5955*5b0945b5SGregory Neil Shapiro 5956*5b0945b5SGregory Neil Shapiro if (NULL == m->m_argv[0] ||NULL == m->m_argv[1]) 5957*5b0945b5SGregory Neil Shapiro return -1; 5958*5b0945b5SGregory Neil Shapiro buf = m->m_argv[2]; 5959*5b0945b5SGregory Neil Shapiro if (NULL == buf) 5960*5b0945b5SGregory Neil Shapiro return 0; 5961*5b0945b5SGregory Neil Shapiro 5962*5b0945b5SGregory Neil Shapiro errno = 0; 5963*5b0945b5SGregory Neil Shapiro ulval = strtoul(buf, &ep, 0); 5964*5b0945b5SGregory Neil Shapiro if (buf[0] == '\0' || *ep != '\0') 5965*5b0945b5SGregory Neil Shapiro return -1; 5966*5b0945b5SGregory Neil Shapiro if (errno == ERANGE && ulval == ULONG_MAX) 5967*5b0945b5SGregory Neil Shapiro return -1; 5968*5b0945b5SGregory Neil Shapiro if (ulval > USHRT_MAX) 5969*5b0945b5SGregory Neil Shapiro return -1; 5970*5b0945b5SGregory Neil Shapiro m->m_port = (unsigned short) ulval; 5971*5b0945b5SGregory Neil Shapiro if (tTd(17, 30)) 5972*5b0945b5SGregory Neil Shapiro sm_dprintf("getmport: mailer=%s, port=%d\n", m->m_name, 5973*5b0945b5SGregory Neil Shapiro m->m_port); 5974*5b0945b5SGregory Neil Shapiro return m->m_port; 5975*5b0945b5SGregory Neil Shapiro } 5976*5b0945b5SGregory Neil Shapiro # define GETMPORT(m) getmport(m) 5977*5b0945b5SGregory Neil Shapiro #else /* DANE */ 5978*5b0945b5SGregory Neil Shapiro # define GETMPORT(m) 25 5979*5b0945b5SGregory Neil Shapiro #endif /* DANE */ 5980*5b0945b5SGregory Neil Shapiro 598140266059SGregory Neil Shapiro /* 5982c2aa98e2SPeter Wemm ** HOSTSIGNATURE -- return the "signature" for a host. 5983c2aa98e2SPeter Wemm ** 5984c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it 5985c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be 5986c2aa98e2SPeter Wemm ** an ordered list of MX hosts. 5987c2aa98e2SPeter Wemm ** 5988c2aa98e2SPeter Wemm ** Parameters: 5989c2aa98e2SPeter Wemm ** m -- the mailer describing this host. 5990c2aa98e2SPeter Wemm ** host -- the host name. 5991*5b0945b5SGregory Neil Shapiro ** ad -- DNSSEC: ad 5992c2aa98e2SPeter Wemm ** 5993c2aa98e2SPeter Wemm ** Returns: 5994c2aa98e2SPeter Wemm ** The signature for this host. 5995c2aa98e2SPeter Wemm ** 5996c2aa98e2SPeter Wemm ** Side Effects: 5997c2aa98e2SPeter Wemm ** Can tweak the symbol table. 5998c2aa98e2SPeter Wemm */ 599940266059SGregory Neil Shapiro 600006f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 6001c2aa98e2SPeter Wemm 600240266059SGregory Neil Shapiro char * 6003*5b0945b5SGregory Neil Shapiro hostsignature(m, host, ad) 6004c2aa98e2SPeter Wemm register MAILER *m; 6005c2aa98e2SPeter Wemm char *host; 6006*5b0945b5SGregory Neil Shapiro bool ad; 6007c2aa98e2SPeter Wemm { 6008c2aa98e2SPeter Wemm register char *p; 6009c2aa98e2SPeter Wemm register STAB *s; 601040266059SGregory Neil Shapiro time_t now; 601106f25ae9SGregory Neil Shapiro #if NAMED_BIND 601206f25ae9SGregory Neil Shapiro char sep = ':'; 601306f25ae9SGregory Neil Shapiro char prevsep = ':'; 6014c2aa98e2SPeter Wemm int i; 6015c2aa98e2SPeter Wemm int len; 6016c2aa98e2SPeter Wemm int nmx; 601706f25ae9SGregory Neil Shapiro int hl; 6018c2aa98e2SPeter Wemm char *hp; 6019c2aa98e2SPeter Wemm char *endp; 6020c2aa98e2SPeter Wemm int oldoptions = _res.options; 6021c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 602240266059SGregory Neil Shapiro unsigned short mxprefs[MAXMXHOSTS + 1]; 602306f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 602406f25ae9SGregory Neil Shapiro 602506f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 6026*5b0945b5SGregory Neil Shapiro sm_dprintf("hostsignature(%s), ad=%d\n", host, ad); 602706f25ae9SGregory Neil Shapiro 602806f25ae9SGregory Neil Shapiro /* 60298774250cSGregory Neil Shapiro ** If local delivery (and not remote), just return a constant. 603006f25ae9SGregory Neil Shapiro */ 603106f25ae9SGregory Neil Shapiro 60328774250cSGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags) && 603340266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") != 0 && 603440266059SGregory Neil Shapiro !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 603506f25ae9SGregory Neil Shapiro return "localhost"; 6036c2aa98e2SPeter Wemm 603713d88268SGregory Neil Shapiro /* an empty host does not have MX records */ 603813d88268SGregory Neil Shapiro if (*host == '\0') 603913d88268SGregory Neil Shapiro return "_empty_"; 604013d88268SGregory Neil Shapiro 6041c2aa98e2SPeter Wemm /* 6042c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records. 6043c2aa98e2SPeter Wemm */ 6044c2aa98e2SPeter Wemm 604540266059SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") != 0 || 604640266059SGregory Neil Shapiro CurEnv->e_sendmode == SM_DEFER) 6047c2aa98e2SPeter Wemm { 604840266059SGregory Neil Shapiro /* just an ordinary mailer or deferred mode */ 6049c2aa98e2SPeter Wemm return host; 6050c2aa98e2SPeter Wemm } 605106f25ae9SGregory Neil Shapiro #if NETUNIX 605206f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL && 605306f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0) 605406f25ae9SGregory Neil Shapiro { 605506f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */ 605606f25ae9SGregory Neil Shapiro return host; 605706f25ae9SGregory Neil Shapiro } 605806f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 6059c2aa98e2SPeter Wemm 6060c2aa98e2SPeter Wemm /* 6061c2aa98e2SPeter Wemm ** Look it up in the symbol table. 6062c2aa98e2SPeter Wemm */ 6063c2aa98e2SPeter Wemm 606440266059SGregory Neil Shapiro now = curtime(); 6065c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER); 606640266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 606740266059SGregory Neil Shapiro { 606840266059SGregory Neil Shapiro if (s->s_hostsig.hs_exp >= now) 606906f25ae9SGregory Neil Shapiro { 607006f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 607140266059SGregory Neil Shapiro sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 607240266059SGregory Neil Shapiro s->s_hostsig.hs_sig); 607340266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 607406f25ae9SGregory Neil Shapiro } 6075c2aa98e2SPeter Wemm 607640266059SGregory Neil Shapiro /* signature is expired: clear it */ 607740266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); 607840266059SGregory Neil Shapiro s->s_hostsig.hs_sig = NULL; 607940266059SGregory Neil Shapiro } 608040266059SGregory Neil Shapiro 608140266059SGregory Neil Shapiro /* set default TTL */ 608240266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 608340266059SGregory Neil Shapiro 6084c2aa98e2SPeter Wemm /* 608540266059SGregory Neil Shapiro ** Not already there or expired -- create a signature. 6086c2aa98e2SPeter Wemm */ 6087c2aa98e2SPeter Wemm 6088c2aa98e2SPeter Wemm #if NAMED_BIND 6089c2aa98e2SPeter Wemm if (ConfigLevel < 2) 6090c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 6091c2aa98e2SPeter Wemm 6092c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp) 6093c2aa98e2SPeter Wemm { 609406f25ae9SGregory Neil Shapiro # if NETINET6 609506f25ae9SGregory Neil Shapiro if (*hp == '[') 609606f25ae9SGregory Neil Shapiro { 609706f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 6098c2aa98e2SPeter Wemm if (endp != NULL) 609906f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 610006f25ae9SGregory Neil Shapiro } 610106f25ae9SGregory Neil Shapiro else 610206f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 610306f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 610406f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 610506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 610606f25ae9SGregory Neil Shapiro if (endp != NULL) 610706f25ae9SGregory Neil Shapiro { 610806f25ae9SGregory Neil Shapiro sep = *endp; 6109c2aa98e2SPeter Wemm *endp = '\0'; 611006f25ae9SGregory Neil Shapiro } 6111c2aa98e2SPeter Wemm 6112c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags)) 6113c2aa98e2SPeter Wemm { 6114c2aa98e2SPeter Wemm /* skip MX lookups */ 6115c2aa98e2SPeter Wemm nmx = 1; 6116c2aa98e2SPeter Wemm mxhosts[0] = hp; 6117c2aa98e2SPeter Wemm } 6118c2aa98e2SPeter Wemm else 6119c2aa98e2SPeter Wemm { 6120c2aa98e2SPeter Wemm auto int rcode; 612140266059SGregory Neil Shapiro int ttl; 6122c2aa98e2SPeter Wemm 6123*5b0945b5SGregory Neil Shapiro GETMPORT(m); 6124*5b0945b5SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs, 6125*5b0945b5SGregory Neil Shapiro DROPLOCALHOST|TRYFALLBACK|(ad ? ISAD :0), 6126*5b0945b5SGregory Neil Shapiro &rcode, &ttl, M_PORT(m)); 6127c2aa98e2SPeter Wemm if (nmx <= 0) 6128c2aa98e2SPeter Wemm { 612913058a91SGregory Neil Shapiro int save_errno; 6130c2aa98e2SPeter Wemm register MCI *mci; 6131c2aa98e2SPeter Wemm 6132c2aa98e2SPeter Wemm /* update the connection info for this host */ 613313058a91SGregory Neil Shapiro save_errno = errno; 6134c2aa98e2SPeter Wemm mci = mci_get(hp, m); 613513058a91SGregory Neil Shapiro mci->mci_errno = save_errno; 6136c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 6137193538b7SGregory Neil Shapiro mci->mci_lastuse = now; 6138*5b0945b5SGregory Neil Shapiro if (nmx == NULLMX) 6139*5b0945b5SGregory Neil Shapiro mci_setstat(mci, rcode, "5.7.27", 6140*5b0945b5SGregory Neil Shapiro "550 Host does not accept mail"); 6141*5b0945b5SGregory Neil Shapiro else if (rcode == EX_NOHOST) 614206f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2", 614306f25ae9SGregory Neil Shapiro "550 Host unknown"); 614406f25ae9SGregory Neil Shapiro else 6145c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL); 6146c2aa98e2SPeter Wemm 6147c2aa98e2SPeter Wemm /* use the original host name as signature */ 6148c2aa98e2SPeter Wemm nmx = 1; 6149c2aa98e2SPeter Wemm mxhosts[0] = hp; 6150c2aa98e2SPeter Wemm } 615106f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 615240266059SGregory Neil Shapiro sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 615306f25ae9SGregory Neil Shapiro nmx, mxhosts[0]); 615440266059SGregory Neil Shapiro 615540266059SGregory Neil Shapiro /* 615640266059SGregory Neil Shapiro ** Set new TTL: we use only one! 615740266059SGregory Neil Shapiro ** We could try to use the minimum instead. 615840266059SGregory Neil Shapiro */ 615940266059SGregory Neil Shapiro 616040266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 6161c2aa98e2SPeter Wemm } 6162c2aa98e2SPeter Wemm 6163c2aa98e2SPeter Wemm len = 0; 6164c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 6165c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1; 616640266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 616740266059SGregory Neil Shapiro len += strlen(s->s_hostsig.hs_sig) + 1; 616840266059SGregory Neil Shapiro if (len < 0 || len >= MAXHOSTSIGNATURE) 616906f25ae9SGregory Neil Shapiro { 617006f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 617106f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len); 617206f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE; 617306f25ae9SGregory Neil Shapiro } 617440266059SGregory Neil Shapiro p = sm_pmalloc_x(len); 617540266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 6176c2aa98e2SPeter Wemm { 617740266059SGregory Neil Shapiro (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 617840266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); /* XXX */ 617940266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 618006f25ae9SGregory Neil Shapiro hl = strlen(p); 618106f25ae9SGregory Neil Shapiro p += hl; 618206f25ae9SGregory Neil Shapiro *p++ = prevsep; 618306f25ae9SGregory Neil Shapiro len -= hl + 1; 6184c2aa98e2SPeter Wemm } 6185c2aa98e2SPeter Wemm else 618640266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 6187c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 6188c2aa98e2SPeter Wemm { 618906f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]); 619006f25ae9SGregory Neil Shapiro if (len - 1 < hl || len <= 1) 619106f25ae9SGregory Neil Shapiro { 619206f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */ 619306f25ae9SGregory Neil Shapiro len = -1; 619406f25ae9SGregory Neil Shapiro break; 6195c2aa98e2SPeter Wemm } 619606f25ae9SGregory Neil Shapiro if (i != 0) 619706f25ae9SGregory Neil Shapiro { 619806f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1]) 619906f25ae9SGregory Neil Shapiro *p++ = ','; 620006f25ae9SGregory Neil Shapiro else 620106f25ae9SGregory Neil Shapiro *p++ = ':'; 620206f25ae9SGregory Neil Shapiro len--; 620306f25ae9SGregory Neil Shapiro } 620440266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], len); 620506f25ae9SGregory Neil Shapiro p += hl; 620606f25ae9SGregory Neil Shapiro len -= hl; 620706f25ae9SGregory Neil Shapiro } 620806f25ae9SGregory Neil Shapiro 620906f25ae9SGregory Neil Shapiro /* 621006f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE 621106f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts 621206f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file). 621306f25ae9SGregory Neil Shapiro */ 621406f25ae9SGregory Neil Shapiro 621506f25ae9SGregory Neil Shapiro if (len < 0) 621606f25ae9SGregory Neil Shapiro break; 6217c2aa98e2SPeter Wemm if (endp != NULL) 621806f25ae9SGregory Neil Shapiro *endp++ = sep; 621906f25ae9SGregory Neil Shapiro prevsep = sep; 6220c2aa98e2SPeter Wemm } 622140266059SGregory Neil Shapiro makelower(s->s_hostsig.hs_sig); 6222c2aa98e2SPeter Wemm if (ConfigLevel < 2) 6223c2aa98e2SPeter Wemm _res.options = oldoptions; 622406f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 6225c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */ 622640266059SGregory Neil Shapiro /* 622740266059SGregory Neil Shapiro ** 'host' points to storage that will be freed after we are 622840266059SGregory Neil Shapiro ** done processing the current envelope, so we copy it. 622940266059SGregory Neil Shapiro */ 623040266059SGregory Neil Shapiro s->s_hostsig.hs_sig = sm_pstrdup_x(host); 623106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 6232c2aa98e2SPeter Wemm if (tTd(17, 1)) 623340266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 623440266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 6235c2aa98e2SPeter Wemm } 623640266059SGregory Neil Shapiro /* 623706f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 623806f25ae9SGregory Neil Shapiro ** 623906f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it 624006f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be 624106f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal 624206f25ae9SGregory Neil Shapiro ** MX preference values. 624306f25ae9SGregory Neil Shapiro ** 624406f25ae9SGregory Neil Shapiro ** Parameters: 624506f25ae9SGregory Neil Shapiro ** sig -- the host signature. 624606f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate. 624740266059SGregory Neil Shapiro ** mailer -- mailer. 624806f25ae9SGregory Neil Shapiro ** 624906f25ae9SGregory Neil Shapiro ** Returns: 625006f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array. 625106f25ae9SGregory Neil Shapiro ** 625206f25ae9SGregory Neil Shapiro ** Side Effects: 625306f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts. 625406f25ae9SGregory Neil Shapiro */ 625506f25ae9SGregory Neil Shapiro 625606f25ae9SGregory Neil Shapiro static int 625706f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer) 625806f25ae9SGregory Neil Shapiro char *sig; 625906f25ae9SGregory Neil Shapiro char **mxhosts; 626006f25ae9SGregory Neil Shapiro MAILER *mailer; 626106f25ae9SGregory Neil Shapiro { 626240266059SGregory Neil Shapiro unsigned short curpref = 0; 626340266059SGregory Neil Shapiro int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 626406f25ae9SGregory Neil Shapiro char *hp, *endp; 626540266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 626606f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS]; 626706f25ae9SGregory Neil Shapiro 626806f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp) 626906f25ae9SGregory Neil Shapiro { 627006f25ae9SGregory Neil Shapiro char sep = ':'; 627106f25ae9SGregory Neil Shapiro 627206f25ae9SGregory Neil Shapiro #if NETINET6 627306f25ae9SGregory Neil Shapiro if (*hp == '[') 627406f25ae9SGregory Neil Shapiro { 627506f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 627606f25ae9SGregory Neil Shapiro if (endp != NULL) 627706f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 627806f25ae9SGregory Neil Shapiro } 627906f25ae9SGregory Neil Shapiro else 628006f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 628106f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 628206f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 628306f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 628406f25ae9SGregory Neil Shapiro if (endp != NULL) 628506f25ae9SGregory Neil Shapiro { 628606f25ae9SGregory Neil Shapiro sep = *endp; 628706f25ae9SGregory Neil Shapiro *endp = '\0'; 628806f25ae9SGregory Neil Shapiro } 628906f25ae9SGregory Neil Shapiro 629006f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp; 629106f25ae9SGregory Neil Shapiro prefer[nmx] = curpref; 629206f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer)) 629306f25ae9SGregory Neil Shapiro rndm[nmx] = 0; 629406f25ae9SGregory Neil Shapiro else 629506f25ae9SGregory Neil Shapiro rndm[nmx] = get_random(); 629606f25ae9SGregory Neil Shapiro 629706f25ae9SGregory Neil Shapiro if (endp != NULL) 629806f25ae9SGregory Neil Shapiro { 629906f25ae9SGregory Neil Shapiro /* 630006f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs, 630106f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that 630206f25ae9SGregory Neil Shapiro ** means the preference for the next host will be 630306f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref. 630406f25ae9SGregory Neil Shapiro */ 630506f25ae9SGregory Neil Shapiro 630606f25ae9SGregory Neil Shapiro if (sep == ':') 630706f25ae9SGregory Neil Shapiro curpref++; 630806f25ae9SGregory Neil Shapiro 630906f25ae9SGregory Neil Shapiro *endp++ = sep; 631006f25ae9SGregory Neil Shapiro } 631106f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS) 631206f25ae9SGregory Neil Shapiro break; 631306f25ae9SGregory Neil Shapiro } 631406f25ae9SGregory Neil Shapiro 631506f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */ 631606f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++) 631706f25ae9SGregory Neil Shapiro { 631806f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++) 631906f25ae9SGregory Neil Shapiro { 632006f25ae9SGregory Neil Shapiro /* 632106f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only 632206f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records 632306f25ae9SGregory Neil Shapiro */ 632406f25ae9SGregory Neil Shapiro 632506f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j]) 632606f25ae9SGregory Neil Shapiro break; 632706f25ae9SGregory Neil Shapiro 632806f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] || 632906f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 633006f25ae9SGregory Neil Shapiro { 633140266059SGregory Neil Shapiro register unsigned short tempp; 633206f25ae9SGregory Neil Shapiro register long tempr; 633306f25ae9SGregory Neil Shapiro register char *temp1; 633406f25ae9SGregory Neil Shapiro 633506f25ae9SGregory Neil Shapiro tempp = prefer[i]; 633606f25ae9SGregory Neil Shapiro prefer[i] = prefer[j]; 633706f25ae9SGregory Neil Shapiro prefer[j] = tempp; 633806f25ae9SGregory Neil Shapiro temp1 = mxhosts[i]; 633906f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j]; 634006f25ae9SGregory Neil Shapiro mxhosts[j] = temp1; 634106f25ae9SGregory Neil Shapiro tempr = rndm[i]; 634206f25ae9SGregory Neil Shapiro rndm[i] = rndm[j]; 634306f25ae9SGregory Neil Shapiro rndm[j] = tempr; 634406f25ae9SGregory Neil Shapiro } 634506f25ae9SGregory Neil Shapiro } 634606f25ae9SGregory Neil Shapiro } 634706f25ae9SGregory Neil Shapiro return nmx; 634806f25ae9SGregory Neil Shapiro } 634906f25ae9SGregory Neil Shapiro 635006f25ae9SGregory Neil Shapiro #if STARTTLS 635106f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL; 635240266059SGregory Neil Shapiro static bool tls_ok_clt = true; 635306f25ae9SGregory Neil Shapiro 635440266059SGregory Neil Shapiro /* 635540266059SGregory Neil Shapiro ** SETCLTTLS -- client side TLS: allow/disallow. 635640266059SGregory Neil Shapiro ** 635740266059SGregory Neil Shapiro ** Parameters: 635840266059SGregory Neil Shapiro ** tls_ok -- should tls be done? 635940266059SGregory Neil Shapiro ** 636040266059SGregory Neil Shapiro ** Returns: 636140266059SGregory Neil Shapiro ** none. 636240266059SGregory Neil Shapiro ** 636340266059SGregory Neil Shapiro ** Side Effects: 636440266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 636540266059SGregory Neil Shapiro */ 636640266059SGregory Neil Shapiro 636740266059SGregory Neil Shapiro void 636840266059SGregory Neil Shapiro setclttls(tls_ok) 636940266059SGregory Neil Shapiro bool tls_ok; 637040266059SGregory Neil Shapiro { 637140266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 637240266059SGregory Neil Shapiro return; 637340266059SGregory Neil Shapiro } 637440266059SGregory Neil Shapiro /* 637506f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS 637606f25ae9SGregory Neil Shapiro ** 637706f25ae9SGregory Neil Shapiro ** Parameters: 637840266059SGregory Neil Shapiro ** tls_ok -- should tls initialization be done? 637906f25ae9SGregory Neil Shapiro ** 638006f25ae9SGregory Neil Shapiro ** Returns: 638106f25ae9SGregory Neil Shapiro ** succeeded? 638240266059SGregory Neil Shapiro ** 638340266059SGregory Neil Shapiro ** Side Effects: 638440266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 638506f25ae9SGregory Neil Shapiro */ 638606f25ae9SGregory Neil Shapiro 638706f25ae9SGregory Neil Shapiro bool 638840266059SGregory Neil Shapiro initclttls(tls_ok) 638940266059SGregory Neil Shapiro bool tls_ok; 639006f25ae9SGregory Neil Shapiro { 639140266059SGregory Neil Shapiro if (!tls_ok_clt) 639240266059SGregory Neil Shapiro return false; 639340266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 639440266059SGregory Neil Shapiro if (!tls_ok_clt) 639540266059SGregory Neil Shapiro return false; 639606f25ae9SGregory Neil Shapiro if (clt_ctx != NULL) 639740266059SGregory Neil Shapiro return true; /* already done */ 63989bd497b8SGregory Neil Shapiro tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, Clt_SSL_Options, false, 63999bd497b8SGregory Neil Shapiro CltCertFile, CltKeyFile, 6400*5b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA 6401*5b0945b5SGregory Neil Shapiro (CltCACertPath != NULL) ? CltCACertPath : 6402*5b0945b5SGregory Neil Shapiro # endif 6403*5b0945b5SGregory Neil Shapiro CACertPath, 6404*5b0945b5SGregory Neil Shapiro # if _FFR_CLIENTCA 6405*5b0945b5SGregory Neil Shapiro (CltCACertFile != NULL) ? CltCACertFile : 6406*5b0945b5SGregory Neil Shapiro # endif 6407*5b0945b5SGregory Neil Shapiro CACertFile, 6408*5b0945b5SGregory Neil Shapiro DHParams); 640940266059SGregory Neil Shapiro return tls_ok_clt; 641006f25ae9SGregory Neil Shapiro } 641106f25ae9SGregory Neil Shapiro 641240266059SGregory Neil Shapiro /* 641306f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side) 641406f25ae9SGregory Neil Shapiro ** 641506f25ae9SGregory Neil Shapiro ** Parameters: 641606f25ae9SGregory Neil Shapiro ** m -- the mailer. 641706f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 641806f25ae9SGregory Neil Shapiro ** e -- the envelope. 641906f25ae9SGregory Neil Shapiro ** 642006f25ae9SGregory Neil Shapiro ** Returns: 642106f25ae9SGregory Neil Shapiro ** success? 642206f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_ 642306f25ae9SGregory Neil Shapiro ** that denotes which stage failed.) 642406f25ae9SGregory Neil Shapiro */ 642506f25ae9SGregory Neil Shapiro 642606f25ae9SGregory Neil Shapiro static int 6427*5b0945b5SGregory Neil Shapiro starttls(m, mci, e 6428*5b0945b5SGregory Neil Shapiro # if DANE 6429*5b0945b5SGregory Neil Shapiro , dane_vrfy_ctx 6430*5b0945b5SGregory Neil Shapiro # endif 6431*5b0945b5SGregory Neil Shapiro ) 643206f25ae9SGregory Neil Shapiro MAILER *m; 643306f25ae9SGregory Neil Shapiro MCI *mci; 643406f25ae9SGregory Neil Shapiro ENVELOPE *e; 6435*5b0945b5SGregory Neil Shapiro # if DANE 6436*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx_P dane_vrfy_ctx; 6437*5b0945b5SGregory Neil Shapiro # endif 643806f25ae9SGregory Neil Shapiro { 643906f25ae9SGregory Neil Shapiro int smtpresult; 644042e5d165SGregory Neil Shapiro int result = 0; 644142e5d165SGregory Neil Shapiro int rfd, wfd; 644206f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL; 644340266059SGregory Neil Shapiro time_t tlsstart; 6444*5b0945b5SGregory Neil Shapiro extern int TLSsslidx; 644506f25ae9SGregory Neil Shapiro 644640266059SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls(true)) 644742e5d165SGregory Neil Shapiro return EX_TEMPFAIL; 64489bd497b8SGregory Neil Shapiro 6449*5b0945b5SGregory Neil Shapiro if (!TLS_set_engine(SSLEngine, false)) 64509bd497b8SGregory Neil Shapiro { 64519bd497b8SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 6452*5b0945b5SGregory Neil Shapiro "STARTTLS=client, engine=%s, TLS_set_engine=failed", 6453*5b0945b5SGregory Neil Shapiro SSLEngine); 64549bd497b8SGregory Neil Shapiro return EX_TEMPFAIL; 64559bd497b8SGregory Neil Shapiro } 64569bd497b8SGregory Neil Shapiro 645706f25ae9SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci); 645806f25ae9SGregory Neil Shapiro 645906f25ae9SGregory Neil Shapiro /* get the reply */ 6460e92d3f3fSGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL, 6461e92d3f3fSGregory Neil Shapiro XS_STARTTLS); 646206f25ae9SGregory Neil Shapiro 646306f25ae9SGregory Neil Shapiro /* check return code from server */ 64644e4196cbSGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 4) 646506f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 646606f25ae9SGregory Neil Shapiro if (smtpresult == 501) 646706f25ae9SGregory Neil Shapiro return EX_USAGE; 646806f25ae9SGregory Neil Shapiro if (smtpresult == -1) 646906f25ae9SGregory Neil Shapiro return smtpresult; 64704e4196cbSGregory Neil Shapiro 64714e4196cbSGregory Neil Shapiro /* not an expected reply but we have to deal with it */ 64724e4196cbSGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 5) 64734e4196cbSGregory Neil Shapiro return EX_UNAVAILABLE; 647406f25ae9SGregory Neil Shapiro if (smtpresult != 220) 647506f25ae9SGregory Neil Shapiro return EX_PROTOCOL; 647606f25ae9SGregory Neil Shapiro 647706f25ae9SGregory Neil Shapiro if (LogLevel > 13) 647840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 647906f25ae9SGregory Neil Shapiro 648006f25ae9SGregory Neil Shapiro /* start connection */ 648106f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 648206f25ae9SGregory Neil Shapiro { 648306f25ae9SGregory Neil Shapiro if (LogLevel > 5) 648406f25ae9SGregory Neil Shapiro { 648540266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 648640266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_new failed"); 6487*5b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client"); 648806f25ae9SGregory Neil Shapiro } 648906f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 649006f25ae9SGregory Neil Shapiro } 6491da7d7b9cSGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */ 6492da7d7b9cSGregory Neil Shapiro 6493*5b0945b5SGregory Neil Shapiro if (get_tls_se_options(e, clt_ssl, &mci->mci_tlsi, false) != 0) 6494da7d7b9cSGregory Neil Shapiro { 6495da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 6496da7d7b9cSGregory Neil Shapiro "STARTTLS=client, get_tls_se_options=fail"); 6497da7d7b9cSGregory Neil Shapiro return EX_SOFTWARE; 6498da7d7b9cSGregory Neil Shapiro } 6499*5b0945b5SGregory Neil Shapiro result = SSL_set_ex_data(clt_ssl, TLSsslidx, &mci->mci_tlsi); 6500*5b0945b5SGregory Neil Shapiro if (0 == result) 6501*5b0945b5SGregory Neil Shapiro { 6502*5b0945b5SGregory Neil Shapiro if (LogLevel > 5) 6503*5b0945b5SGregory Neil Shapiro { 6504*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 6505*5b0945b5SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_ex_data failed=%d, idx=%d", 6506*5b0945b5SGregory Neil Shapiro result, TLSsslidx); 6507*5b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client"); 6508*5b0945b5SGregory Neil Shapiro } 6509*5b0945b5SGregory Neil Shapiro return EX_SOFTWARE; 6510*5b0945b5SGregory Neil Shapiro } 6511*5b0945b5SGregory Neil Shapiro # if DANE 6512*5b0945b5SGregory Neil Shapiro if (SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE)) 6513*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_chk = DANE_NEVER; 6514*5b0945b5SGregory Neil Shapiro else 6515*5b0945b5SGregory Neil Shapiro { 6516*5b0945b5SGregory Neil Shapiro int r; 6517*5b0945b5SGregory Neil Shapiro 6518*5b0945b5SGregory Neil Shapiro # define SM_IS_EMPTY(s) (NULL == (s) || '\0' == *(s)) 6519*5b0945b5SGregory Neil Shapiro 6520*5b0945b5SGregory Neil Shapiro /* set SNI only if there is a TLSA RR */ 6521*5b0945b5SGregory Neil Shapiro if (dane_get_tlsa(dane_vrfy_ctx) != NULL && 6522*5b0945b5SGregory Neil Shapiro !(SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_host) && 6523*5b0945b5SGregory Neil Shapiro SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)) && 6524*5b0945b5SGregory Neil Shapiro (r = SSL_set_tlsext_host_name(clt_ssl, 6525*5b0945b5SGregory Neil Shapiro (!SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni) 6526*5b0945b5SGregory Neil Shapiro ? dane_vrfy_ctx->dane_vrfy_sni 6527*5b0945b5SGregory Neil Shapiro : dane_vrfy_ctx->dane_vrfy_host))) <= 0) 6528*5b0945b5SGregory Neil Shapiro { 6529*5b0945b5SGregory Neil Shapiro if (LogLevel > 5) 6530*5b0945b5SGregory Neil Shapiro { 6531*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 6532*5b0945b5SGregory Neil Shapiro "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d", 6533*5b0945b5SGregory Neil Shapiro dane_vrfy_ctx->dane_vrfy_host, r); 6534*5b0945b5SGregory Neil Shapiro } 6535*5b0945b5SGregory Neil Shapiro tlslogerr(LOG_ERR, 5, "client"); 6536*5b0945b5SGregory Neil Shapiro /* return EX_SOFTWARE; */ 6537*5b0945b5SGregory Neil Shapiro } 6538*5b0945b5SGregory Neil Shapiro } 6539*5b0945b5SGregory Neil Shapiro memcpy(&mci->mci_tlsi.tlsi_dvc, dane_vrfy_ctx, sizeof(*dane_vrfy_ctx)); 6540*5b0945b5SGregory Neil Shapiro # endif /* DANE */ 654106f25ae9SGregory Neil Shapiro 654240266059SGregory Neil Shapiro rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 654340266059SGregory Neil Shapiro wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 654442e5d165SGregory Neil Shapiro 654542e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 || 654640266059SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 654740266059SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 654806f25ae9SGregory Neil Shapiro { 654906f25ae9SGregory Neil Shapiro if (LogLevel > 5) 655006f25ae9SGregory Neil Shapiro { 655140266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 655240266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_xfd failed=%d", 655340266059SGregory Neil Shapiro result); 6554*5b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client"); 655506f25ae9SGregory Neil Shapiro } 655606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 655706f25ae9SGregory Neil Shapiro } 655806f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl); 655940266059SGregory Neil Shapiro tlsstart = curtime(); 656040266059SGregory Neil Shapiro 656140266059SGregory Neil Shapiro ssl_retry: 656206f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0) 656306f25ae9SGregory Neil Shapiro { 65644e4196cbSGregory Neil Shapiro int i, ssl_err; 6565da7d7b9cSGregory Neil Shapiro int save_errno = errno; 656606f25ae9SGregory Neil Shapiro 65674e4196cbSGregory Neil Shapiro ssl_err = SSL_get_error(clt_ssl, result); 65684e4196cbSGregory Neil Shapiro i = tls_retry(clt_ssl, rfd, wfd, tlsstart, 65694e4196cbSGregory Neil Shapiro TimeOuts.to_starttls, ssl_err, "client"); 65704e4196cbSGregory Neil Shapiro if (i > 0) 65714e4196cbSGregory Neil Shapiro goto ssl_retry; 657240266059SGregory Neil Shapiro 657313bd1963SGregory Neil Shapiro if (LogLevel > 5) 657413bd1963SGregory Neil Shapiro { 6575ba00ec3dSGregory Neil Shapiro unsigned long l; 6576ba00ec3dSGregory Neil Shapiro const char *sr; 6577ba00ec3dSGregory Neil Shapiro 6578ba00ec3dSGregory Neil Shapiro l = ERR_peek_error(); 6579ba00ec3dSGregory Neil Shapiro sr = ERR_reason_error_string(l); 65804e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 6581ba00ec3dSGregory Neil Shapiro "STARTTLS=client, error: connect failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d", 6582ba00ec3dSGregory Neil Shapiro result, sr == NULL ? "unknown" : sr, ssl_err, 6583da7d7b9cSGregory Neil Shapiro save_errno, i); 6584*5b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "client"); 658513bd1963SGregory Neil Shapiro } 658640266059SGregory Neil Shapiro 6587*5b0945b5SGregory Neil Shapiro SM_SSL_FREE(clt_ssl); 658806f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 658906f25ae9SGregory Neil Shapiro } 659006f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl; 659140266059SGregory Neil Shapiro result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 659240266059SGregory Neil Shapiro &mci->mci_macro, true); 659306f25ae9SGregory Neil Shapiro 659440266059SGregory Neil Shapiro /* switch to use TLS... */ 659506f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 659606f25ae9SGregory Neil Shapiro return EX_OK; 659706f25ae9SGregory Neil Shapiro 659806f25ae9SGregory Neil Shapiro /* failure */ 6599*5b0945b5SGregory Neil Shapiro SM_SSL_FREE(clt_ssl); 660006f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 660106f25ae9SGregory Neil Shapiro } 660240266059SGregory Neil Shapiro /* 660306f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side) 660406f25ae9SGregory Neil Shapiro ** 660506f25ae9SGregory Neil Shapiro ** Parameters: 660606f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 660706f25ae9SGregory Neil Shapiro ** 660806f25ae9SGregory Neil Shapiro ** Returns: 660906f25ae9SGregory Neil Shapiro ** success? 661006f25ae9SGregory Neil Shapiro */ 661140266059SGregory Neil Shapiro 661240266059SGregory Neil Shapiro static int 661306f25ae9SGregory Neil Shapiro endtlsclt(mci) 661406f25ae9SGregory Neil Shapiro MCI *mci; 661506f25ae9SGregory Neil Shapiro { 661606f25ae9SGregory Neil Shapiro int r; 661706f25ae9SGregory Neil Shapiro 661806f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags)) 661906f25ae9SGregory Neil Shapiro return EX_OK; 6620*5b0945b5SGregory Neil Shapiro r = endtls(&mci->mci_ssl, "client"); 662106f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 662206f25ae9SGregory Neil Shapiro return r; 662306f25ae9SGregory Neil Shapiro } 662440266059SGregory Neil Shapiro #endif /* STARTTLS */ 662540266059SGregory Neil Shapiro #if STARTTLS || SASL 662640266059SGregory Neil Shapiro /* 662740266059SGregory Neil Shapiro ** ISCLTFLGSET -- check whether client flag is set. 662806f25ae9SGregory Neil Shapiro ** 662906f25ae9SGregory Neil Shapiro ** Parameters: 663040266059SGregory Neil Shapiro ** e -- envelope. 663140266059SGregory Neil Shapiro ** flag -- flag to check in {client_flags} 663206f25ae9SGregory Neil Shapiro ** 663306f25ae9SGregory Neil Shapiro ** Returns: 663440266059SGregory Neil Shapiro ** true iff flag is set. 663506f25ae9SGregory Neil Shapiro */ 663606f25ae9SGregory Neil Shapiro 663740266059SGregory Neil Shapiro static bool 663840266059SGregory Neil Shapiro iscltflgset(e, flag) 663940266059SGregory Neil Shapiro ENVELOPE *e; 664040266059SGregory Neil Shapiro int flag; 664106f25ae9SGregory Neil Shapiro { 664240266059SGregory Neil Shapiro char *p; 6643602a2b1bSGregory Neil Shapiro 664440266059SGregory Neil Shapiro p = macvalue(macid("{client_flags}"), e); 664540266059SGregory Neil Shapiro if (p == NULL) 664640266059SGregory Neil Shapiro return false; 664740266059SGregory Neil Shapiro for (; *p != '\0'; p++) 664806f25ae9SGregory Neil Shapiro { 664940266059SGregory Neil Shapiro /* look for just this one flag */ 665040266059SGregory Neil Shapiro if (*p == (char) flag) 665140266059SGregory Neil Shapiro return true; 665206f25ae9SGregory Neil Shapiro } 665340266059SGregory Neil Shapiro return false; 665406f25ae9SGregory Neil Shapiro } 665540266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */ 6656