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 17*4313cc83SGregory 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> 2106f25ae9SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 2206f25ae9SGregory Neil Shapiro 23605302a5SGregory Neil Shapiro #if NETINET || NETINET6 24605302a5SGregory Neil Shapiro # include <arpa/inet.h> 25605302a5SGregory Neil Shapiro #endif /* NETINET || NETINET6 */ 26605302a5SGregory Neil Shapiro 2740266059SGregory Neil Shapiro #if STARTTLS || SASL 2806f25ae9SGregory Neil Shapiro # include "sfsasl.h" 2940266059SGregory Neil Shapiro #endif /* STARTTLS || SASL */ 3006f25ae9SGregory Neil Shapiro 3106f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *)); 3206f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 33b6bacd31SGregory Neil Shapiro static void mailfiletimeout __P((int)); 34b6bacd31SGregory Neil Shapiro static void endwaittimeout __P((int)); 3506f25ae9SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *)); 3606f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int)); 3740266059SGregory Neil Shapiro static int coloncmp __P((const char *, const char *)); 38c2aa98e2SPeter Wemm 3906f25ae9SGregory Neil Shapiro #if STARTTLS 40ba00ec3dSGregory Neil Shapiro # include <openssl/err.h> 4106f25ae9SGregory Neil Shapiro static int starttls __P((MAILER *, MCI *, ENVELOPE *)); 4240266059SGregory Neil Shapiro static int endtlsclt __P((MCI *)); 4306f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 4440266059SGregory Neil Shapiro # if STARTTLS || SASL 4540266059SGregory Neil Shapiro static bool iscltflgset __P((ENVELOPE *, int)); 4640266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 47c2aa98e2SPeter Wemm 48c2aa98e2SPeter Wemm /* 49c2aa98e2SPeter Wemm ** SENDALL -- actually send all the messages. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** Parameters: 52c2aa98e2SPeter Wemm ** e -- the envelope to send. 53c2aa98e2SPeter Wemm ** mode -- the delivery mode to use. If SM_DEFAULT, use 54c2aa98e2SPeter Wemm ** the current e->e_sendmode. 55c2aa98e2SPeter Wemm ** 56c2aa98e2SPeter Wemm ** Returns: 57c2aa98e2SPeter Wemm ** none. 58c2aa98e2SPeter Wemm ** 59c2aa98e2SPeter Wemm ** Side Effects: 60c2aa98e2SPeter Wemm ** Scans the send lists and sends everything it finds. 61c2aa98e2SPeter Wemm ** Delivers any appropriate error messages. 62c2aa98e2SPeter Wemm ** If we are running in a non-interactive mode, takes the 63c2aa98e2SPeter Wemm ** appropriate action. 64c2aa98e2SPeter Wemm */ 65c2aa98e2SPeter Wemm 66c2aa98e2SPeter Wemm void 67c2aa98e2SPeter Wemm sendall(e, mode) 68c2aa98e2SPeter Wemm ENVELOPE *e; 69c2aa98e2SPeter Wemm int mode; 70c2aa98e2SPeter Wemm { 71c2aa98e2SPeter Wemm register ADDRESS *q; 72c2aa98e2SPeter Wemm char *owner; 73c2aa98e2SPeter Wemm int otherowners; 7406f25ae9SGregory Neil Shapiro int save_errno; 75c2aa98e2SPeter Wemm register ENVELOPE *ee; 76c2aa98e2SPeter Wemm ENVELOPE *splitenv = NULL; 77c2aa98e2SPeter Wemm int oldverbose = Verbose; 7840266059SGregory Neil Shapiro bool somedeliveries = false, expensive = false; 79c2aa98e2SPeter Wemm pid_t pid; 80c2aa98e2SPeter Wemm 81c2aa98e2SPeter Wemm /* 82c2aa98e2SPeter Wemm ** If this message is to be discarded, don't bother sending 83c2aa98e2SPeter Wemm ** the message at all. 84c2aa98e2SPeter Wemm */ 85c2aa98e2SPeter Wemm 86c2aa98e2SPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 87c2aa98e2SPeter Wemm { 88c2aa98e2SPeter Wemm if (tTd(13, 1)) 8940266059SGregory Neil Shapiro sm_dprintf("sendall: discarding id %s\n", e->e_id); 90c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 9140266059SGregory Neil Shapiro if (LogLevel > 9) 9240266059SGregory Neil Shapiro logundelrcpts(e, "discarded", 9, true); 9340266059SGregory Neil Shapiro else if (LogLevel > 4) 94c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "discarded"); 9540266059SGregory Neil Shapiro markstats(e, NULL, STATS_REJECT); 96c2aa98e2SPeter Wemm return; 97c2aa98e2SPeter Wemm } 98c2aa98e2SPeter Wemm 99c2aa98e2SPeter Wemm /* 100c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 101c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 102c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 103c2aa98e2SPeter Wemm ** addresses to be sent. 104c2aa98e2SPeter Wemm */ 105c2aa98e2SPeter Wemm 106c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 107c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 108c2aa98e2SPeter Wemm { 109c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 110c2aa98e2SPeter Wemm return; 111c2aa98e2SPeter Wemm } 112c2aa98e2SPeter Wemm 113c2aa98e2SPeter Wemm /* determine actual delivery mode */ 114c2aa98e2SPeter Wemm if (mode == SM_DEFAULT) 115c2aa98e2SPeter Wemm { 116c2aa98e2SPeter Wemm mode = e->e_sendmode; 117c2aa98e2SPeter Wemm if (mode != SM_VERIFY && mode != SM_DEFER && 118c2aa98e2SPeter Wemm shouldqueue(e->e_msgpriority, e->e_ctime)) 119c2aa98e2SPeter Wemm mode = SM_QUEUE; 120c2aa98e2SPeter Wemm } 121c2aa98e2SPeter Wemm 122c2aa98e2SPeter Wemm if (tTd(13, 1)) 123c2aa98e2SPeter Wemm { 12440266059SGregory Neil Shapiro sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ", 125c2aa98e2SPeter Wemm mode, e->e_id); 126e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 12740266059SGregory Neil Shapiro sm_dprintf("\te_flags = "); 128c2aa98e2SPeter Wemm printenvflags(e); 12940266059SGregory Neil Shapiro sm_dprintf("sendqueue:\n"); 130e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 131c2aa98e2SPeter Wemm } 132c2aa98e2SPeter Wemm 133c2aa98e2SPeter Wemm /* 134c2aa98e2SPeter Wemm ** Do any preprocessing necessary for the mode we are running. 135c2aa98e2SPeter Wemm ** Check to make sure the hop count is reasonable. 136c2aa98e2SPeter Wemm ** Delete sends to the sender in mailing lists. 137c2aa98e2SPeter Wemm */ 138c2aa98e2SPeter Wemm 139c2aa98e2SPeter Wemm CurEnv = e; 140c2aa98e2SPeter Wemm if (tTd(62, 1)) 141c2aa98e2SPeter Wemm checkfds(NULL); 142c2aa98e2SPeter Wemm 143c2aa98e2SPeter Wemm if (e->e_hopcount > MaxHopCount) 144c2aa98e2SPeter Wemm { 1458774250cSGregory Neil Shapiro char *recip; 1468774250cSGregory Neil Shapiro 1478774250cSGregory Neil Shapiro if (e->e_sendqueue != NULL && 1488774250cSGregory Neil Shapiro e->e_sendqueue->q_paddr != NULL) 1498774250cSGregory Neil Shapiro recip = e->e_sendqueue->q_paddr; 1508774250cSGregory Neil Shapiro else 1518774250cSGregory Neil Shapiro recip = "(nobody)"; 1528774250cSGregory Neil Shapiro 153c2aa98e2SPeter Wemm errno = 0; 15440266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), false); 155c2aa98e2SPeter Wemm e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 15606f25ae9SGregory Neil Shapiro ExitStat = EX_UNAVAILABLE; 1578774250cSGregory Neil Shapiro syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s", 158c2aa98e2SPeter Wemm e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 159c2aa98e2SPeter Wemm RealHostName == NULL ? "localhost" : RealHostName, 1608774250cSGregory Neil Shapiro recip); 16106f25ae9SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16206f25ae9SGregory Neil Shapiro { 16306f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 16406f25ae9SGregory Neil Shapiro continue; 16506f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 16606f25ae9SGregory Neil Shapiro q->q_status = "5.4.6"; 1678774250cSGregory Neil Shapiro q->q_rstatus = "554 5.4.6 Too many hops"; 16806f25ae9SGregory Neil Shapiro } 169c2aa98e2SPeter Wemm return; 170c2aa98e2SPeter Wemm } 171c2aa98e2SPeter Wemm 172c2aa98e2SPeter Wemm /* 173c2aa98e2SPeter Wemm ** Do sender deletion. 174c2aa98e2SPeter Wemm ** 17506f25ae9SGregory Neil Shapiro ** If the sender should be queued up, skip this. 176c2aa98e2SPeter Wemm ** This can happen if the name server is hosed when you 177c2aa98e2SPeter Wemm ** are trying to send mail. The result is that the sender 178c2aa98e2SPeter Wemm ** is instantiated in the queue as a recipient. 179c2aa98e2SPeter Wemm */ 180c2aa98e2SPeter Wemm 181c2aa98e2SPeter Wemm if (!bitset(EF_METOO, e->e_flags) && 18206f25ae9SGregory Neil Shapiro !QS_IS_QUEUEUP(e->e_from.q_state)) 183c2aa98e2SPeter Wemm { 184c2aa98e2SPeter Wemm if (tTd(13, 5)) 185c2aa98e2SPeter Wemm { 18640266059SGregory Neil Shapiro sm_dprintf("sendall: QS_SENDER "); 187e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 188c2aa98e2SPeter Wemm } 18906f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 190c2aa98e2SPeter Wemm (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 191c2aa98e2SPeter Wemm } 192c2aa98e2SPeter Wemm 193c2aa98e2SPeter Wemm /* 194c2aa98e2SPeter Wemm ** Handle alias owners. 195c2aa98e2SPeter Wemm ** 196c2aa98e2SPeter Wemm ** We scan up the q_alias chain looking for owners. 197c2aa98e2SPeter Wemm ** We discard owners that are the same as the return path. 198c2aa98e2SPeter Wemm */ 199c2aa98e2SPeter Wemm 200c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 201c2aa98e2SPeter Wemm { 202c2aa98e2SPeter Wemm register struct address *a; 203c2aa98e2SPeter Wemm 204c2aa98e2SPeter Wemm for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 205c2aa98e2SPeter Wemm continue; 206c2aa98e2SPeter Wemm if (a != NULL) 207c2aa98e2SPeter Wemm q->q_owner = a->q_owner; 208c2aa98e2SPeter Wemm 209c2aa98e2SPeter Wemm if (q->q_owner != NULL && 21006f25ae9SGregory Neil Shapiro !QS_IS_DEAD(q->q_state) && 211c2aa98e2SPeter Wemm strcmp(q->q_owner, e->e_from.q_paddr) == 0) 212c2aa98e2SPeter Wemm q->q_owner = NULL; 213c2aa98e2SPeter Wemm } 214c2aa98e2SPeter Wemm 215c2aa98e2SPeter Wemm if (tTd(13, 25)) 216c2aa98e2SPeter Wemm { 21740266059SGregory Neil Shapiro sm_dprintf("\nAfter first owner pass, sendq =\n"); 218e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 219c2aa98e2SPeter Wemm } 220c2aa98e2SPeter Wemm 221c2aa98e2SPeter Wemm owner = ""; 222c2aa98e2SPeter Wemm otherowners = 1; 223c2aa98e2SPeter Wemm while (owner != NULL && otherowners > 0) 224c2aa98e2SPeter Wemm { 225c2aa98e2SPeter Wemm if (tTd(13, 28)) 22640266059SGregory Neil Shapiro sm_dprintf("owner = \"%s\", otherowners = %d\n", 227c2aa98e2SPeter Wemm owner, otherowners); 228c2aa98e2SPeter Wemm owner = NULL; 229c2aa98e2SPeter Wemm otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; 230c2aa98e2SPeter Wemm 231c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 232c2aa98e2SPeter Wemm { 233c2aa98e2SPeter Wemm if (tTd(13, 30)) 234c2aa98e2SPeter Wemm { 23540266059SGregory Neil Shapiro sm_dprintf("Checking "); 236e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false); 237c2aa98e2SPeter Wemm } 23806f25ae9SGregory Neil Shapiro if (QS_IS_DEAD(q->q_state)) 239c2aa98e2SPeter Wemm { 240c2aa98e2SPeter Wemm if (tTd(13, 30)) 24140266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_DEAD\n"); 242c2aa98e2SPeter Wemm continue; 243c2aa98e2SPeter Wemm } 244c2aa98e2SPeter Wemm if (tTd(13, 29) && !tTd(13, 30)) 245c2aa98e2SPeter Wemm { 24640266059SGregory Neil Shapiro sm_dprintf("Checking "); 247e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), q, false); 248c2aa98e2SPeter Wemm } 249c2aa98e2SPeter Wemm 250c2aa98e2SPeter Wemm if (q->q_owner != NULL) 251c2aa98e2SPeter Wemm { 252c2aa98e2SPeter Wemm if (owner == NULL) 253c2aa98e2SPeter Wemm { 254c2aa98e2SPeter Wemm if (tTd(13, 40)) 25540266059SGregory Neil Shapiro sm_dprintf(" ... First owner = \"%s\"\n", 256c2aa98e2SPeter Wemm q->q_owner); 257c2aa98e2SPeter Wemm owner = q->q_owner; 258c2aa98e2SPeter Wemm } 259c2aa98e2SPeter Wemm else if (owner != q->q_owner) 260c2aa98e2SPeter Wemm { 261c2aa98e2SPeter Wemm if (strcmp(owner, q->q_owner) == 0) 262c2aa98e2SPeter Wemm { 263c2aa98e2SPeter Wemm if (tTd(13, 40)) 26440266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 265c2aa98e2SPeter Wemm owner); 266c2aa98e2SPeter Wemm 267c2aa98e2SPeter Wemm /* make future comparisons cheap */ 268c2aa98e2SPeter Wemm q->q_owner = owner; 269c2aa98e2SPeter Wemm } 270c2aa98e2SPeter Wemm else 271c2aa98e2SPeter Wemm { 272c2aa98e2SPeter Wemm if (tTd(13, 40)) 27340266059SGregory Neil Shapiro sm_dprintf(" ... Another owner \"%s\"\n", 274c2aa98e2SPeter Wemm q->q_owner); 275c2aa98e2SPeter Wemm otherowners++; 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm owner = q->q_owner; 278c2aa98e2SPeter Wemm } 279c2aa98e2SPeter Wemm else if (tTd(13, 40)) 28040266059SGregory Neil Shapiro sm_dprintf(" ... Same owner = \"%s\"\n", 281c2aa98e2SPeter Wemm owner); 282c2aa98e2SPeter Wemm } 283c2aa98e2SPeter Wemm else 284c2aa98e2SPeter Wemm { 285c2aa98e2SPeter Wemm if (tTd(13, 40)) 28640266059SGregory Neil Shapiro sm_dprintf(" ... Null owner\n"); 287c2aa98e2SPeter Wemm otherowners++; 288c2aa98e2SPeter Wemm } 289c2aa98e2SPeter Wemm 29006f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(q->q_state)) 29106f25ae9SGregory Neil Shapiro { 29206f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 29340266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_BADADDR\n"); 29406f25ae9SGregory Neil Shapiro continue; 29506f25ae9SGregory Neil Shapiro } 29606f25ae9SGregory Neil Shapiro 29706f25ae9SGregory Neil Shapiro if (QS_IS_QUEUEUP(q->q_state)) 29806f25ae9SGregory Neil Shapiro { 29906f25ae9SGregory Neil Shapiro MAILER *m = q->q_mailer; 30006f25ae9SGregory Neil Shapiro 30106f25ae9SGregory Neil Shapiro /* 30206f25ae9SGregory Neil Shapiro ** If we have temporary address failures 30306f25ae9SGregory Neil Shapiro ** (e.g., dns failure) and a fallback MX is 30406f25ae9SGregory Neil Shapiro ** set, send directly to the fallback MX host. 30506f25ae9SGregory Neil Shapiro */ 30606f25ae9SGregory Neil Shapiro 307e92d3f3fSGregory Neil Shapiro if (FallbackMX != NULL && 308e92d3f3fSGregory Neil Shapiro !wordinclass(FallbackMX, 'w') && 30906f25ae9SGregory Neil Shapiro mode != SM_VERIFY && 31040266059SGregory Neil Shapiro !bitnset(M_NOMX, m->m_flags) && 31140266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") == 0 && 31206f25ae9SGregory Neil Shapiro m->m_argv[0] != NULL && 31340266059SGregory Neil Shapiro strcmp(m->m_argv[0], "TCP") == 0) 31406f25ae9SGregory Neil Shapiro { 31506f25ae9SGregory Neil Shapiro int len; 31606f25ae9SGregory Neil Shapiro char *p; 31706f25ae9SGregory Neil Shapiro 31806f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 319e92d3f3fSGregory Neil Shapiro sm_dprintf(" ... FallbackMX\n"); 32006f25ae9SGregory Neil Shapiro 321e92d3f3fSGregory Neil Shapiro len = strlen(FallbackMX) + 1; 32240266059SGregory Neil Shapiro p = sm_rpool_malloc_x(e->e_rpool, len); 323e92d3f3fSGregory Neil Shapiro (void) sm_strlcpy(p, FallbackMX, len); 32406f25ae9SGregory Neil Shapiro q->q_state = QS_OK; 32506f25ae9SGregory Neil Shapiro q->q_host = p; 32606f25ae9SGregory Neil Shapiro } 32706f25ae9SGregory Neil Shapiro else 32806f25ae9SGregory Neil Shapiro { 32906f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 33040266059SGregory Neil Shapiro sm_dprintf(" ... QS_IS_QUEUEUP\n"); 33106f25ae9SGregory Neil Shapiro continue; 33206f25ae9SGregory Neil Shapiro } 33306f25ae9SGregory Neil Shapiro } 33406f25ae9SGregory Neil Shapiro 335c2aa98e2SPeter Wemm /* 336c2aa98e2SPeter Wemm ** If this mailer is expensive, and if we don't 337c2aa98e2SPeter Wemm ** want to make connections now, just mark these 338c2aa98e2SPeter Wemm ** addresses and return. This is useful if we 339c2aa98e2SPeter Wemm ** want to batch connections to reduce load. This 340c2aa98e2SPeter Wemm ** will cause the messages to be queued up, and a 341c2aa98e2SPeter Wemm ** daemon will come along to send the messages later. 342c2aa98e2SPeter Wemm */ 343c2aa98e2SPeter Wemm 344c2aa98e2SPeter Wemm if (NoConnect && !Verbose && 345c2aa98e2SPeter Wemm bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 346c2aa98e2SPeter Wemm { 347c2aa98e2SPeter Wemm if (tTd(13, 30)) 34840266059SGregory Neil Shapiro sm_dprintf(" ... expensive\n"); 34906f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 35040266059SGregory Neil Shapiro expensive = true; 35106f25ae9SGregory Neil Shapiro } 35206f25ae9SGregory Neil Shapiro else if (bitnset(M_HOLD, q->q_mailer->m_flags) && 35306f25ae9SGregory Neil Shapiro QueueLimitId == NULL && 35406f25ae9SGregory Neil Shapiro QueueLimitSender == NULL && 35506f25ae9SGregory Neil Shapiro QueueLimitRecipient == NULL) 35606f25ae9SGregory Neil Shapiro { 35706f25ae9SGregory Neil Shapiro if (tTd(13, 30)) 35840266059SGregory Neil Shapiro sm_dprintf(" ... hold\n"); 35906f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 36040266059SGregory Neil Shapiro expensive = true; 361c2aa98e2SPeter Wemm } 36240266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE && 36340266059SGregory Neil Shapiro e->e_quarmsg != NULL) 36440266059SGregory Neil Shapiro { 36540266059SGregory Neil Shapiro if (tTd(13, 30)) 36640266059SGregory Neil Shapiro sm_dprintf(" ... quarantine: %s\n", 36740266059SGregory Neil Shapiro e->e_quarmsg); 36840266059SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 36940266059SGregory Neil Shapiro expensive = true; 37040266059SGregory Neil Shapiro } 371c2aa98e2SPeter Wemm else 372c2aa98e2SPeter Wemm { 373c2aa98e2SPeter Wemm if (tTd(13, 30)) 37440266059SGregory Neil Shapiro sm_dprintf(" ... deliverable\n"); 37540266059SGregory Neil Shapiro somedeliveries = true; 376c2aa98e2SPeter Wemm } 377c2aa98e2SPeter Wemm } 378c2aa98e2SPeter Wemm 379c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0) 380c2aa98e2SPeter Wemm { 381c2aa98e2SPeter Wemm /* 382c2aa98e2SPeter Wemm ** Split this envelope into two. 383c2aa98e2SPeter Wemm */ 384c2aa98e2SPeter Wemm 38540266059SGregory Neil Shapiro ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, 386d0cef73dSGregory Neil Shapiro sizeof(*ee)); 38740266059SGregory Neil Shapiro STRUCTCOPY(*e, *ee); 38806f25ae9SGregory Neil Shapiro ee->e_message = NULL; 389c2aa98e2SPeter Wemm ee->e_id = NULL; 39006f25ae9SGregory Neil Shapiro assign_queueid(ee); 391c2aa98e2SPeter Wemm 392c2aa98e2SPeter Wemm if (tTd(13, 1)) 39340266059SGregory Neil Shapiro sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 39440266059SGregory Neil Shapiro e->e_id, ee->e_id, owner, 39540266059SGregory Neil Shapiro otherowners); 396c2aa98e2SPeter Wemm 39740266059SGregory Neil Shapiro ee->e_header = copyheader(e->e_header, ee->e_rpool); 39840266059SGregory Neil Shapiro ee->e_sendqueue = copyqueue(e->e_sendqueue, 39940266059SGregory Neil Shapiro ee->e_rpool); 40040266059SGregory Neil Shapiro ee->e_errorqueue = copyqueue(e->e_errorqueue, 40140266059SGregory Neil Shapiro ee->e_rpool); 402c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 403c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT; 40440266059SGregory Neil Shapiro setsender(owner, ee, NULL, '\0', true); 405c2aa98e2SPeter Wemm if (tTd(13, 5)) 406c2aa98e2SPeter Wemm { 40740266059SGregory Neil Shapiro sm_dprintf("sendall(split): QS_SENDER "); 408e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &ee->e_from, false); 409c2aa98e2SPeter Wemm } 41006f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER; 411c2aa98e2SPeter Wemm ee->e_dfp = NULL; 41206f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL; 413c2aa98e2SPeter Wemm ee->e_xfp = NULL; 41440266059SGregory Neil Shapiro ee->e_qgrp = e->e_qgrp; 41540266059SGregory Neil Shapiro ee->e_qdir = e->e_qdir; 416c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL; 417c2aa98e2SPeter Wemm ee->e_sibling = splitenv; 41806f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL; 41940266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 42040266059SGregory Neil Shapiro ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 42140266059SGregory Neil Shapiro e->e_quarmsg); 422c2aa98e2SPeter Wemm splitenv = ee; 423c2aa98e2SPeter Wemm 424c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 425c2aa98e2SPeter Wemm { 426c2aa98e2SPeter Wemm if (q->q_owner == owner) 427c2aa98e2SPeter Wemm { 42806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 429c2aa98e2SPeter Wemm if (tTd(13, 6)) 43040266059SGregory Neil Shapiro sm_dprintf("\t... stripping %s from original envelope\n", 431c2aa98e2SPeter Wemm q->q_paddr); 432c2aa98e2SPeter Wemm } 433c2aa98e2SPeter Wemm } 434c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 435c2aa98e2SPeter Wemm { 436c2aa98e2SPeter Wemm if (q->q_owner != owner) 437c2aa98e2SPeter Wemm { 43806f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 439c2aa98e2SPeter Wemm if (tTd(13, 6)) 44040266059SGregory Neil Shapiro sm_dprintf("\t... dropping %s from cloned envelope\n", 441c2aa98e2SPeter Wemm q->q_paddr); 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm else 444c2aa98e2SPeter Wemm { 445c2aa98e2SPeter Wemm /* clear DSN parameters */ 446c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 447c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 448c2aa98e2SPeter Wemm if (tTd(13, 6)) 44940266059SGregory Neil Shapiro sm_dprintf("\t... moving %s to cloned envelope\n", 450c2aa98e2SPeter Wemm q->q_paddr); 451c2aa98e2SPeter Wemm } 452c2aa98e2SPeter Wemm } 453c2aa98e2SPeter Wemm 454c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 45540266059SGregory Neil Shapiro dup_queue_file(e, ee, DATAFL_LETTER); 45606f25ae9SGregory Neil Shapiro 45706f25ae9SGregory Neil Shapiro /* 45806f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent 45906f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while 46006f25ae9SGregory Neil Shapiro ** processing the recipients (done before the 46106f25ae9SGregory Neil Shapiro ** envelope splitting). 46206f25ae9SGregory Neil Shapiro */ 46306f25ae9SGregory Neil Shapiro 46406f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL) 46540266059SGregory Neil Shapiro ee->e_xfp = sm_io_dup(e->e_xfp); 46606f25ae9SGregory Neil Shapiro 46706f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */ 46806f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL) 469c2aa98e2SPeter Wemm openxscript(ee); 47006f25ae9SGregory Neil Shapiro 471065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4) 47240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 47340266059SGregory Neil Shapiro "%s: clone: owner=%s", 47440266059SGregory Neil Shapiro ee->e_id, owner); 475c2aa98e2SPeter Wemm } 476c2aa98e2SPeter Wemm } 477c2aa98e2SPeter Wemm 478c2aa98e2SPeter Wemm if (owner != NULL) 479c2aa98e2SPeter Wemm { 48040266059SGregory Neil Shapiro setsender(owner, e, NULL, '\0', true); 481c2aa98e2SPeter Wemm if (tTd(13, 5)) 482c2aa98e2SPeter Wemm { 48340266059SGregory Neil Shapiro sm_dprintf("sendall(owner): QS_SENDER "); 484e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), &e->e_from, false); 485c2aa98e2SPeter Wemm } 48606f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 487c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL; 488c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT; 489c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 490c2aa98e2SPeter Wemm } 491c2aa98e2SPeter Wemm 492c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */ 49340266059SGregory Neil Shapiro if (!somedeliveries && !WILL_BE_QUEUED(mode) && 494c2aa98e2SPeter Wemm mode != SM_VERIFY) 495c2aa98e2SPeter Wemm { 49640266059SGregory Neil Shapiro time_t now; 497193538b7SGregory Neil Shapiro 498c2aa98e2SPeter Wemm if (tTd(13, 29)) 499ffb83623SGregory Neil Shapiro sm_dprintf("No deliveries: auto-queueing\n"); 500c2aa98e2SPeter Wemm mode = SM_QUEUE; 50140266059SGregory Neil Shapiro now = curtime(); 502c2aa98e2SPeter Wemm 503c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */ 504193538b7SGregory Neil Shapiro e->e_dtime = now; 505c2aa98e2SPeter Wemm if (!expensive) 506c2aa98e2SPeter Wemm e->e_ntries++; 507c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 508c2aa98e2SPeter Wemm { 509193538b7SGregory Neil Shapiro ee->e_dtime = now; 510c2aa98e2SPeter Wemm if (!expensive) 511c2aa98e2SPeter Wemm ee->e_ntries++; 512c2aa98e2SPeter Wemm } 513c2aa98e2SPeter Wemm } 514c2aa98e2SPeter Wemm 51540266059SGregory Neil Shapiro if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || 516e92d3f3fSGregory Neil Shapiro (mode != SM_VERIFY && 517e92d3f3fSGregory Neil Shapiro (SuperSafe == SAFE_REALLY || 518e92d3f3fSGregory Neil Shapiro SuperSafe == SAFE_REALLY_POSTMILTER))) && 519c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 520c2aa98e2SPeter Wemm { 52140266059SGregory Neil Shapiro bool msync; 52240266059SGregory Neil Shapiro 52342e5d165SGregory Neil Shapiro /* 52442e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue. 52542e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes. 52642e5d165SGregory Neil Shapiro ** If the original were done first, we may lose 52742e5d165SGregory Neil Shapiro ** recipients. 52842e5d165SGregory Neil Shapiro */ 52942e5d165SGregory Neil Shapiro 53040266059SGregory Neil Shapiro #if !HASFLOCK 53140266059SGregory Neil Shapiro msync = false; 53240266059SGregory Neil Shapiro #else /* !HASFLOCK */ 53340266059SGregory Neil Shapiro msync = mode == SM_FORK; 53440266059SGregory Neil Shapiro #endif /* !HASFLOCK */ 53540266059SGregory Neil Shapiro 536c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 53740266059SGregory Neil Shapiro queueup(ee, WILL_BE_QUEUED(mode), msync); 53840266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), msync); 539c2aa98e2SPeter Wemm } 540c2aa98e2SPeter Wemm 541c2aa98e2SPeter Wemm if (tTd(62, 10)) 542c2aa98e2SPeter Wemm checkfds("after envelope splitting"); 543c2aa98e2SPeter Wemm 544c2aa98e2SPeter Wemm /* 545c2aa98e2SPeter Wemm ** If we belong in background, fork now. 546c2aa98e2SPeter Wemm */ 547c2aa98e2SPeter Wemm 548c2aa98e2SPeter Wemm if (tTd(13, 20)) 549c2aa98e2SPeter Wemm { 55040266059SGregory Neil Shapiro sm_dprintf("sendall: final mode = %c\n", mode); 551c2aa98e2SPeter Wemm if (tTd(13, 21)) 552c2aa98e2SPeter Wemm { 55340266059SGregory Neil Shapiro sm_dprintf("\n================ Final Send Queue(s) =====================\n"); 55440266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 555c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr); 556e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), e->e_sendqueue, true); 557c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 558c2aa98e2SPeter Wemm { 55940266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 560c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr); 561e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ee->e_sendqueue, true); 562c2aa98e2SPeter Wemm } 56340266059SGregory Neil Shapiro sm_dprintf("==========================================================\n\n"); 564c2aa98e2SPeter Wemm } 565c2aa98e2SPeter Wemm } 566c2aa98e2SPeter Wemm switch (mode) 567c2aa98e2SPeter Wemm { 568c2aa98e2SPeter Wemm case SM_VERIFY: 569c2aa98e2SPeter Wemm Verbose = 2; 570c2aa98e2SPeter Wemm break; 571c2aa98e2SPeter Wemm 572c2aa98e2SPeter Wemm case SM_QUEUE: 573c2aa98e2SPeter Wemm case SM_DEFER: 574c2aa98e2SPeter Wemm #if HASFLOCK 575c2aa98e2SPeter Wemm queueonly: 57606f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 577c2aa98e2SPeter Wemm if (e->e_nrcpts > 0) 578c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 5799bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, true); 580c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 581c2aa98e2SPeter Wemm { 582c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0) 583c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 5849bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, true); 585c2aa98e2SPeter Wemm } 586c2aa98e2SPeter Wemm return; 587c2aa98e2SPeter Wemm 588c2aa98e2SPeter Wemm case SM_FORK: 589c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 59040266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 591c2aa98e2SPeter Wemm 592c2aa98e2SPeter Wemm #if !HASFLOCK 593c2aa98e2SPeter Wemm /* 594c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that 595c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file 596c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and 597c2aa98e2SPeter Wemm ** then restart from scratch in the child. 598c2aa98e2SPeter Wemm */ 599c2aa98e2SPeter Wemm 600c2aa98e2SPeter Wemm { 601c2aa98e2SPeter Wemm /* save id for future use */ 602c2aa98e2SPeter Wemm char *qid = e->e_id; 603c2aa98e2SPeter Wemm 604c2aa98e2SPeter Wemm /* now drop the envelope in the parent */ 605c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 6069bd497b8SGregory Neil Shapiro (void) dropenvelope(e, splitenv != NULL, false); 607c2aa98e2SPeter Wemm 608c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */ 609c2aa98e2SPeter Wemm e->e_id = qid; 610c2aa98e2SPeter Wemm } 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 613c2aa98e2SPeter Wemm { 614c2aa98e2SPeter Wemm /* save id for future use */ 615c2aa98e2SPeter Wemm char *qid = ee->e_id; 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm /* drop envelope in parent */ 618c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 6199bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, false, false); 620c2aa98e2SPeter Wemm 621c2aa98e2SPeter Wemm /* and save qid for reacquisition */ 622c2aa98e2SPeter Wemm ee->e_id = qid; 623c2aa98e2SPeter Wemm } 624e92d3f3fSGregory Neil Shapiro 625c2aa98e2SPeter Wemm #endif /* !HASFLOCK */ 626c2aa98e2SPeter Wemm 62706f25ae9SGregory Neil Shapiro /* 62806f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent 62906f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby 63006f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore, 63106f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open 63206f25ae9SGregory Neil Shapiro ** them if necessary. 63306f25ae9SGregory Neil Shapiro */ 63406f25ae9SGregory Neil Shapiro 63540266059SGregory Neil Shapiro closemaps(false); 63606f25ae9SGregory Neil Shapiro 637c2aa98e2SPeter Wemm pid = fork(); 638c2aa98e2SPeter Wemm if (pid < 0) 639c2aa98e2SPeter Wemm { 64006f25ae9SGregory Neil Shapiro syserr("deliver: fork 1"); 641c2aa98e2SPeter Wemm #if HASFLOCK 642c2aa98e2SPeter Wemm goto queueonly; 64306f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 644c2aa98e2SPeter Wemm e->e_id = NULL; 645c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 646c2aa98e2SPeter Wemm ee->e_id = NULL; 647c2aa98e2SPeter Wemm return; 648c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 649c2aa98e2SPeter Wemm } 650c2aa98e2SPeter Wemm else if (pid > 0) 651c2aa98e2SPeter Wemm { 652c2aa98e2SPeter Wemm #if HASFLOCK 653c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */ 654c2aa98e2SPeter Wemm /* close any random open files in the envelope */ 655c2aa98e2SPeter Wemm closexscript(e); 656c2aa98e2SPeter Wemm if (e->e_dfp != NULL) 65740266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 658c2aa98e2SPeter Wemm e->e_dfp = NULL; 659c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF; 660c2aa98e2SPeter Wemm 661c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */ 662c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 66340266059SGregory Neil Shapiro (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 66406f25ae9SGregory Neil Shapiro else 66506f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id); 666c2aa98e2SPeter Wemm e->e_lockfp = NULL; 66706f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 668c2aa98e2SPeter Wemm 669c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */ 670c2aa98e2SPeter Wemm e->e_id = NULL; 671c2aa98e2SPeter Wemm 67240266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 673c2aa98e2SPeter Wemm /* catch intermediate zombie */ 674c2aa98e2SPeter Wemm (void) waitfor(pid); 67540266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 676c2aa98e2SPeter Wemm return; 677c2aa98e2SPeter Wemm } 678c2aa98e2SPeter Wemm 6798774250cSGregory Neil Shapiro /* Reset global flags */ 6808774250cSGregory Neil Shapiro RestartRequest = NULL; 68140266059SGregory Neil Shapiro RestartWorkGroup = false; 6828774250cSGregory Neil Shapiro ShutdownRequest = NULL; 6838774250cSGregory Neil Shapiro PendingSignal = 0; 6848774250cSGregory Neil Shapiro 68542e5d165SGregory Neil Shapiro /* 68640266059SGregory Neil Shapiro ** Initialize exception stack and default exception 68740266059SGregory Neil Shapiro ** handler for child process. 68840266059SGregory Neil Shapiro */ 68940266059SGregory Neil Shapiro 69040266059SGregory Neil Shapiro sm_exc_newthread(fatal_error); 69140266059SGregory Neil Shapiro 69240266059SGregory Neil Shapiro /* 69342e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message, 69442e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler) 69542e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line 69642e5d165SGregory Neil Shapiro ** message submission. 69742e5d165SGregory Neil Shapiro */ 69842e5d165SGregory Neil Shapiro 69940266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 70042e5d165SGregory Neil Shapiro 70140266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 702c2aa98e2SPeter Wemm /* double fork to avoid zombies */ 703c2aa98e2SPeter Wemm pid = fork(); 704c2aa98e2SPeter Wemm if (pid > 0) 705c2aa98e2SPeter Wemm exit(EX_OK); 70606f25ae9SGregory Neil Shapiro save_errno = errno; 70740266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 70840266059SGregory Neil Shapiro 70940266059SGregory Neil Shapiro CurrentPid = getpid(); 710c2aa98e2SPeter Wemm 711c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */ 712c2aa98e2SPeter Wemm disconnect(2, e); 71306f25ae9SGregory Neil Shapiro clearstats(); 714c2aa98e2SPeter Wemm 715c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */ 716c2aa98e2SPeter Wemm if (pid < 0) 717c2aa98e2SPeter Wemm { 71806f25ae9SGregory Neil Shapiro errno = save_errno; 71906f25ae9SGregory Neil Shapiro syserr("deliver: fork 2"); 720c2aa98e2SPeter Wemm #if HASFLOCK 721c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 72206f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 723c2aa98e2SPeter Wemm e->e_id = NULL; 724c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 72540266059SGregory Neil Shapiro finis(true, true, ExitStat); 726c2aa98e2SPeter Wemm } 727c2aa98e2SPeter Wemm 728c2aa98e2SPeter Wemm /* be sure to give error messages in child */ 72940266059SGregory Neil Shapiro QuickAbort = false; 730c2aa98e2SPeter Wemm 731c2aa98e2SPeter Wemm /* 732c2aa98e2SPeter Wemm ** Close any cached connections. 733c2aa98e2SPeter Wemm ** 734c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent 735c2aa98e2SPeter Wemm ** still knows about the connection. 736c2aa98e2SPeter Wemm ** 737c2aa98e2SPeter Wemm ** This should only happen when delivering an error 738c2aa98e2SPeter Wemm ** message. 739c2aa98e2SPeter Wemm */ 740c2aa98e2SPeter Wemm 74140266059SGregory Neil Shapiro mci_flush(false, NULL); 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm #if HASFLOCK 744c2aa98e2SPeter Wemm break; 74506f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 746c2aa98e2SPeter Wemm 747c2aa98e2SPeter Wemm /* 748c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files. 749c2aa98e2SPeter Wemm */ 750c2aa98e2SPeter Wemm 751c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 752c2aa98e2SPeter Wemm { 753c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling; 754c2aa98e2SPeter Wemm 75540266059SGregory Neil Shapiro (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id, 75640266059SGregory Neil Shapiro false, false, ee); 757c2aa98e2SPeter Wemm ee->e_sibling = sibling; 758c2aa98e2SPeter Wemm } 75940266059SGregory Neil Shapiro (void) dowork(e->e_qgrp, e->e_qdir, e->e_id, 76040266059SGregory Neil Shapiro false, false, e); 76140266059SGregory Neil Shapiro finis(true, true, ExitStat); 76206f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 763c2aa98e2SPeter Wemm } 764c2aa98e2SPeter Wemm 765c2aa98e2SPeter Wemm sendenvelope(e, mode); 7669bd497b8SGregory Neil Shapiro (void) dropenvelope(e, true, true); 767c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 768c2aa98e2SPeter Wemm { 769c2aa98e2SPeter Wemm CurEnv = ee; 770c2aa98e2SPeter Wemm if (mode != SM_VERIFY) 771c2aa98e2SPeter Wemm openxscript(ee); 772c2aa98e2SPeter Wemm sendenvelope(ee, mode); 7739bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, true, true); 774c2aa98e2SPeter Wemm } 775c2aa98e2SPeter Wemm CurEnv = e; 776c2aa98e2SPeter Wemm 777c2aa98e2SPeter Wemm Verbose = oldverbose; 778c2aa98e2SPeter Wemm if (mode == SM_FORK) 77940266059SGregory Neil Shapiro finis(true, true, ExitStat); 780c2aa98e2SPeter Wemm } 781c2aa98e2SPeter Wemm 78206f25ae9SGregory Neil Shapiro static void 783c2aa98e2SPeter Wemm sendenvelope(e, mode) 784c2aa98e2SPeter Wemm register ENVELOPE *e; 785c2aa98e2SPeter Wemm int mode; 786c2aa98e2SPeter Wemm { 787c2aa98e2SPeter Wemm register ADDRESS *q; 788c2aa98e2SPeter Wemm bool didany; 789c2aa98e2SPeter Wemm 790c2aa98e2SPeter Wemm if (tTd(13, 10)) 79140266059SGregory Neil Shapiro sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n", 792c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 793c2aa98e2SPeter Wemm e->e_flags); 794c2aa98e2SPeter Wemm if (LogLevel > 80) 795c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id, 79606f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx", 797c2aa98e2SPeter Wemm e->e_flags); 798c2aa98e2SPeter Wemm 799c2aa98e2SPeter Wemm /* 800c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 801c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 802c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 803c2aa98e2SPeter Wemm ** addresses to be sent. 804c2aa98e2SPeter Wemm */ 805c2aa98e2SPeter Wemm 806c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 807c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 808c2aa98e2SPeter Wemm { 809c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 810c2aa98e2SPeter Wemm return; 811c2aa98e2SPeter Wemm } 812c2aa98e2SPeter Wemm 81340266059SGregory Neil Shapiro /* 81440266059SGregory Neil Shapiro ** Don't attempt deliveries if we want to bounce now 81540266059SGregory Neil Shapiro ** or if deliver-by time is exceeded. 81640266059SGregory Neil Shapiro */ 81740266059SGregory Neil Shapiro 81806f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) && 81940266059SGregory Neil Shapiro (TimeOuts.to_q_return[e->e_timeoutclass] == NOW || 82040266059SGregory Neil Shapiro (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 && 82140266059SGregory Neil Shapiro curtime() > e->e_ctime + e->e_deliver_by))) 82206f25ae9SGregory Neil Shapiro return; 82306f25ae9SGregory Neil Shapiro 824c2aa98e2SPeter Wemm /* 825c2aa98e2SPeter Wemm ** Run through the list and send everything. 826c2aa98e2SPeter Wemm ** 827c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery 828c2aa98e2SPeter Wemm ** result in returned mail. 829c2aa98e2SPeter Wemm */ 830c2aa98e2SPeter Wemm 831c2aa98e2SPeter Wemm e->e_nsent = 0; 832c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS; 83306f25ae9SGregory Neil Shapiro 83440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid); 83540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype); 83640266059SGregory Neil Shapiro didany = false; 83740266059SGregory Neil Shapiro 83840266059SGregory Neil Shapiro if (!bitset(EF_SPLIT, e->e_flags)) 83940266059SGregory Neil Shapiro { 84040266059SGregory Neil Shapiro ENVELOPE *oldsib; 84140266059SGregory Neil Shapiro ENVELOPE *ee; 84240266059SGregory Neil Shapiro 84340266059SGregory Neil Shapiro /* 84440266059SGregory Neil Shapiro ** Save old sibling and set it to NULL to avoid 84540266059SGregory Neil Shapiro ** queueing up the same envelopes again. 84640266059SGregory Neil Shapiro ** This requires that envelopes in that list have 84740266059SGregory Neil Shapiro ** been take care of before (or at some other place). 84840266059SGregory Neil Shapiro */ 84940266059SGregory Neil Shapiro 85040266059SGregory Neil Shapiro oldsib = e->e_sibling; 85140266059SGregory Neil Shapiro e->e_sibling = NULL; 85240266059SGregory Neil Shapiro if (!split_by_recipient(e) && 85340266059SGregory Neil Shapiro bitset(EF_FATALERRS, e->e_flags)) 85440266059SGregory Neil Shapiro { 85540266059SGregory Neil Shapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 85640266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE; 85740266059SGregory Neil Shapiro return; 85840266059SGregory Neil Shapiro } 85940266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86040266059SGregory Neil Shapiro queueup(ee, false, true); 86140266059SGregory Neil Shapiro 86240266059SGregory Neil Shapiro /* clean up */ 86340266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86440266059SGregory Neil Shapiro { 86540266059SGregory Neil Shapiro /* now unlock the job */ 86640266059SGregory Neil Shapiro closexscript(ee); 86740266059SGregory Neil Shapiro unlockqueue(ee); 86840266059SGregory Neil Shapiro 86940266059SGregory Neil Shapiro /* this envelope is marked unused */ 87040266059SGregory Neil Shapiro if (ee->e_dfp != NULL) 87140266059SGregory Neil Shapiro { 87240266059SGregory Neil Shapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 87340266059SGregory Neil Shapiro ee->e_dfp = NULL; 87440266059SGregory Neil Shapiro } 87540266059SGregory Neil Shapiro ee->e_id = NULL; 87640266059SGregory Neil Shapiro ee->e_flags &= ~EF_HAS_DF; 87740266059SGregory Neil Shapiro } 87840266059SGregory Neil Shapiro e->e_sibling = oldsib; 87940266059SGregory Neil Shapiro } 880c2aa98e2SPeter Wemm 881c2aa98e2SPeter Wemm /* now run through the queue */ 882c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 883c2aa98e2SPeter Wemm { 884c2aa98e2SPeter Wemm #if XDEBUG 885c2aa98e2SPeter Wemm char wbuf[MAXNAME + 20]; 886c2aa98e2SPeter Wemm 887d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "sendall(%.*s)", 888c2aa98e2SPeter Wemm MAXNAME, q->q_paddr); 889c2aa98e2SPeter Wemm checkfd012(wbuf); 89006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 891c2aa98e2SPeter Wemm if (mode == SM_VERIFY) 892c2aa98e2SPeter Wemm { 893c2aa98e2SPeter Wemm e->e_to = q->q_paddr; 89406f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state)) 895c2aa98e2SPeter Wemm { 896c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0') 897c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s", 898c2aa98e2SPeter Wemm q->q_mailer->m_name, 899c2aa98e2SPeter Wemm q->q_host, 900c2aa98e2SPeter Wemm q->q_user); 901c2aa98e2SPeter Wemm else 902c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s", 903c2aa98e2SPeter Wemm q->q_mailer->m_name, 904c2aa98e2SPeter Wemm q->q_user); 905c2aa98e2SPeter Wemm } 906c2aa98e2SPeter Wemm } 90706f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state)) 908c2aa98e2SPeter Wemm { 909c2aa98e2SPeter Wemm /* 910c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses 911c2aa98e2SPeter Wemm */ 912c2aa98e2SPeter Wemm 91342e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && 91442e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval) 915c2aa98e2SPeter Wemm { 91640266059SGregory Neil Shapiro queueup(e, false, false); 917c2aa98e2SPeter Wemm e->e_nsent = 0; 918c2aa98e2SPeter Wemm } 919c2aa98e2SPeter Wemm (void) deliver(e, q); 92040266059SGregory Neil Shapiro didany = true; 921c2aa98e2SPeter Wemm } 922c2aa98e2SPeter Wemm } 923c2aa98e2SPeter Wemm if (didany) 924c2aa98e2SPeter Wemm { 925c2aa98e2SPeter Wemm e->e_dtime = curtime(); 926c2aa98e2SPeter Wemm e->e_ntries++; 927c2aa98e2SPeter Wemm } 928c2aa98e2SPeter Wemm 929c2aa98e2SPeter Wemm #if XDEBUG 930c2aa98e2SPeter Wemm checkfd012("end of sendenvelope"); 93106f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 932c2aa98e2SPeter Wemm } 93340266059SGregory Neil Shapiro 93440266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC 93540266059SGregory Neil Shapiro /* 93640266059SGregory Neil Shapiro ** SYNC_DIR -- fsync a directory based on a filename 93740266059SGregory Neil Shapiro ** 93840266059SGregory Neil Shapiro ** Parameters: 93940266059SGregory Neil Shapiro ** filename -- path of file 94040266059SGregory Neil Shapiro ** panic -- panic? 94140266059SGregory Neil Shapiro ** 94240266059SGregory Neil Shapiro ** Returns: 94340266059SGregory Neil Shapiro ** none 94440266059SGregory Neil Shapiro */ 94540266059SGregory Neil Shapiro 94640266059SGregory Neil Shapiro void 94740266059SGregory Neil Shapiro sync_dir(filename, panic) 94840266059SGregory Neil Shapiro char *filename; 94940266059SGregory Neil Shapiro bool panic; 95040266059SGregory Neil Shapiro { 95140266059SGregory Neil Shapiro int dirfd; 95240266059SGregory Neil Shapiro char *dirp; 95340266059SGregory Neil Shapiro char dir[MAXPATHLEN]; 95440266059SGregory Neil Shapiro 95513bd1963SGregory Neil Shapiro if (!RequiresDirfsync) 95613bd1963SGregory Neil Shapiro return; 95713bd1963SGregory Neil Shapiro 95840266059SGregory Neil Shapiro /* filesystems which require the directory be synced */ 95940266059SGregory Neil Shapiro dirp = strrchr(filename, '/'); 96040266059SGregory Neil Shapiro if (dirp != NULL) 96140266059SGregory Neil Shapiro { 962d0cef73dSGregory Neil Shapiro if (sm_strlcpy(dir, filename, sizeof(dir)) >= sizeof(dir)) 96340266059SGregory Neil Shapiro return; 96440266059SGregory Neil Shapiro dir[dirp - filename] = '\0'; 96540266059SGregory Neil Shapiro dirp = dir; 96640266059SGregory Neil Shapiro } 96740266059SGregory Neil Shapiro else 96840266059SGregory Neil Shapiro dirp = "."; 96940266059SGregory Neil Shapiro dirfd = open(dirp, O_RDONLY, 0700); 97040266059SGregory Neil Shapiro if (tTd(40,32)) 97140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)", 97240266059SGregory Neil Shapiro dirp, dirfd); 97340266059SGregory Neil Shapiro if (dirfd >= 0) 97440266059SGregory Neil Shapiro { 97540266059SGregory Neil Shapiro if (fsync(dirfd) < 0) 97640266059SGregory Neil Shapiro { 97740266059SGregory Neil Shapiro if (panic) 97840266059SGregory Neil Shapiro syserr("!sync_dir: cannot fsync directory %s", 97940266059SGregory Neil Shapiro dirp); 98040266059SGregory Neil Shapiro else if (LogLevel > 1) 98140266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 98240266059SGregory Neil Shapiro "sync_dir: cannot fsync directory %s: %s", 98340266059SGregory Neil Shapiro dirp, sm_errstring(errno)); 98440266059SGregory Neil Shapiro } 98540266059SGregory Neil Shapiro (void) close(dirfd); 98640266059SGregory Neil Shapiro } 98740266059SGregory Neil Shapiro } 98840266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */ 98940266059SGregory Neil Shapiro /* 990c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 991c2aa98e2SPeter Wemm ** 992c2aa98e2SPeter Wemm ** Parameters: 993c2aa98e2SPeter Wemm ** e -- the existing envelope 994c2aa98e2SPeter Wemm ** ee -- the new envelope 99540266059SGregory Neil Shapiro ** type -- the queue file type (e.g., DATAFL_LETTER) 996c2aa98e2SPeter Wemm ** 997c2aa98e2SPeter Wemm ** Returns: 998c2aa98e2SPeter Wemm ** none 999c2aa98e2SPeter Wemm */ 1000c2aa98e2SPeter Wemm 100106f25ae9SGregory Neil Shapiro static void 1002c2aa98e2SPeter Wemm dup_queue_file(e, ee, type) 100340266059SGregory Neil Shapiro ENVELOPE *e, *ee; 1004c2aa98e2SPeter Wemm int type; 1005c2aa98e2SPeter Wemm { 100606f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 1007c2aa98e2SPeter Wemm 1008c2aa98e2SPeter Wemm ee->e_dfp = NULL; 1009c2aa98e2SPeter Wemm ee->e_xfp = NULL; 101006f25ae9SGregory Neil Shapiro 101106f25ae9SGregory Neil Shapiro /* 101206f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory. 101306f25ae9SGregory Neil Shapiro */ 101406f25ae9SGregory Neil Shapiro 1015d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f1buf, queuename(e, type), sizeof(f1buf)); 1016d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof(f2buf)); 1017959366dcSGregory Neil Shapiro 1018959366dcSGregory Neil Shapiro /* Force the df to disk if it's not there yet */ 1019959366dcSGregory Neil Shapiro if (type == DATAFL_LETTER && e->e_dfp != NULL && 1020959366dcSGregory Neil Shapiro sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 1021959366dcSGregory Neil Shapiro errno != EINVAL) 1022959366dcSGregory Neil Shapiro { 1023959366dcSGregory Neil Shapiro syserr("!dup_queue_file: can't commit %s", f1buf); 1024959366dcSGregory Neil Shapiro /* NOTREACHED */ 1025959366dcSGregory Neil Shapiro } 1026959366dcSGregory Neil Shapiro 1027c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1028c2aa98e2SPeter Wemm { 102906f25ae9SGregory Neil Shapiro int save_errno = errno; 1030c2aa98e2SPeter Wemm 1031c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf); 103206f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 1033c2aa98e2SPeter Wemm { 1034c2aa98e2SPeter Wemm if (unlink(f2buf) < 0) 1035c2aa98e2SPeter Wemm { 1036c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent", 1037c2aa98e2SPeter Wemm f2buf); 1038c2aa98e2SPeter Wemm /* NOTREACHED */ 1039c2aa98e2SPeter Wemm } 1040c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1041c2aa98e2SPeter Wemm { 1042c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent", 1043c2aa98e2SPeter Wemm f1buf, f2buf); 1044c2aa98e2SPeter Wemm /* NOTREACHED */ 1045c2aa98e2SPeter Wemm } 1046c2aa98e2SPeter Wemm } 1047c2aa98e2SPeter Wemm } 104840266059SGregory Neil Shapiro SYNC_DIR(f2buf, true); 1049c2aa98e2SPeter Wemm } 105040266059SGregory Neil Shapiro /* 1051c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure. 1052c2aa98e2SPeter Wemm ** 1053c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running 1054c2aa98e2SPeter Wemm ** two processes on the same stack!!! 1055c2aa98e2SPeter Wemm ** 1056c2aa98e2SPeter Wemm ** Parameters: 1057c2aa98e2SPeter Wemm ** none. 1058c2aa98e2SPeter Wemm ** 1059c2aa98e2SPeter Wemm ** Returns: 1060c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding! 1061c2aa98e2SPeter Wemm ** 1062c2aa98e2SPeter Wemm ** Side Effects: 1063c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving: 1064c2aa98e2SPeter Wemm ** pid of child in parent, zero in child. 1065c2aa98e2SPeter Wemm ** -1 on unrecoverable error. 1066c2aa98e2SPeter Wemm ** 1067c2aa98e2SPeter Wemm ** Notes: 1068c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's 1069c2aa98e2SPeter Wemm ** vfork for you..... 1070c2aa98e2SPeter Wemm */ 1071c2aa98e2SPeter Wemm 1072c2aa98e2SPeter Wemm #define NFORKTRIES 5 1073c2aa98e2SPeter Wemm 1074c2aa98e2SPeter Wemm #ifndef FORK 1075c2aa98e2SPeter Wemm # define FORK fork 107606f25ae9SGregory Neil Shapiro #endif /* ! FORK */ 1077c2aa98e2SPeter Wemm 1078c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \ 1079c2aa98e2SPeter Wemm {\ 1080c2aa98e2SPeter Wemm register int i;\ 1081c2aa98e2SPeter Wemm \ 1082c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\ 1083c2aa98e2SPeter Wemm {\ 1084c2aa98e2SPeter Wemm pid = fORKfN();\ 1085c2aa98e2SPeter Wemm if (pid >= 0)\ 1086c2aa98e2SPeter Wemm break;\ 1087c2aa98e2SPeter Wemm if (i > 0)\ 108806f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\ 1089c2aa98e2SPeter Wemm }\ 1090c2aa98e2SPeter Wemm } 109140266059SGregory Neil Shapiro /* 1092c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK. 1093c2aa98e2SPeter Wemm ** 1094c2aa98e2SPeter Wemm ** Parameters: 1095c2aa98e2SPeter Wemm ** none. 1096c2aa98e2SPeter Wemm ** 1097c2aa98e2SPeter Wemm ** Returns: 1098c2aa98e2SPeter Wemm ** pid of child in parent. 1099c2aa98e2SPeter Wemm ** zero in child. 1100c2aa98e2SPeter Wemm ** -1 on error. 1101c2aa98e2SPeter Wemm ** 1102c2aa98e2SPeter Wemm ** Side Effects: 1103c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child. 1104c2aa98e2SPeter Wemm */ 1105c2aa98e2SPeter Wemm 11068774250cSGregory Neil Shapiro pid_t 1107c2aa98e2SPeter Wemm dofork() 1108c2aa98e2SPeter Wemm { 1109c2aa98e2SPeter Wemm register pid_t pid = -1; 1110c2aa98e2SPeter Wemm 1111c2aa98e2SPeter Wemm DOFORK(fork); 111206f25ae9SGregory Neil Shapiro return pid; 1113c2aa98e2SPeter Wemm } 111440266059SGregory Neil Shapiro 111540266059SGregory Neil Shapiro /* 111640266059SGregory Neil Shapiro ** COLONCMP -- compare host-signatures up to first ':' or EOS 111740266059SGregory Neil Shapiro ** 111840266059SGregory Neil Shapiro ** This takes two strings which happen to be host-signatures and 111940266059SGregory Neil Shapiro ** compares them. If the lowest preference portions of the MX-RR's 112040266059SGregory Neil Shapiro ** match (up to ':' or EOS, whichever is first), then we have 112140266059SGregory Neil Shapiro ** match. This is used for coattail-piggybacking messages during 112240266059SGregory Neil Shapiro ** message delivery. 112340266059SGregory Neil Shapiro ** If the signatures are the same up to the first ':' the remainder of 112440266059SGregory Neil Shapiro ** the signatures are then compared with a normal strcmp(). This saves 112540266059SGregory Neil Shapiro ** re-examining the first part of the signatures. 112640266059SGregory Neil Shapiro ** 112740266059SGregory Neil Shapiro ** Parameters: 112840266059SGregory Neil Shapiro ** a - first host-signature 112940266059SGregory Neil Shapiro ** b - second host-signature 113040266059SGregory Neil Shapiro ** 113140266059SGregory Neil Shapiro ** Returns: 113240266059SGregory Neil Shapiro ** HS_MATCH_NO -- no "match". 113340266059SGregory Neil Shapiro ** HS_MATCH_FIRST -- "match" for the first MX preference 113440266059SGregory Neil Shapiro ** (up to the first colon (':')). 113540266059SGregory Neil Shapiro ** HS_MATCH_FULL -- match for the entire MX record. 113640266059SGregory Neil Shapiro ** 113740266059SGregory Neil Shapiro ** Side Effects: 113840266059SGregory Neil Shapiro ** none. 113940266059SGregory Neil Shapiro */ 114040266059SGregory Neil Shapiro 114140266059SGregory Neil Shapiro #define HS_MATCH_NO 0 114240266059SGregory Neil Shapiro #define HS_MATCH_FIRST 1 114340266059SGregory Neil Shapiro #define HS_MATCH_FULL 2 114440266059SGregory Neil Shapiro 114540266059SGregory Neil Shapiro static int 114640266059SGregory Neil Shapiro coloncmp(a, b) 114740266059SGregory Neil Shapiro register const char *a; 114840266059SGregory Neil Shapiro register const char *b; 114940266059SGregory Neil Shapiro { 115040266059SGregory Neil Shapiro int ret = HS_MATCH_NO; 115140266059SGregory Neil Shapiro int braclev = 0; 115240266059SGregory Neil Shapiro 115340266059SGregory Neil Shapiro while (*a == *b++) 115440266059SGregory Neil Shapiro { 115540266059SGregory Neil Shapiro /* Need to account for IPv6 bracketed addresses */ 115640266059SGregory Neil Shapiro if (*a == '[') 115740266059SGregory Neil Shapiro braclev++; 11585ef517c0SGregory Neil Shapiro else if (*a == ']' && braclev > 0) 115940266059SGregory Neil Shapiro braclev--; 116040266059SGregory Neil Shapiro else if (*a == ':' && braclev <= 0) 116140266059SGregory Neil Shapiro { 116240266059SGregory Neil Shapiro ret = HS_MATCH_FIRST; 116340266059SGregory Neil Shapiro a++; 116440266059SGregory Neil Shapiro break; 116540266059SGregory Neil Shapiro } 116640266059SGregory Neil Shapiro else if (*a == '\0') 116740266059SGregory Neil Shapiro return HS_MATCH_FULL; /* a full match */ 116840266059SGregory Neil Shapiro a++; 116940266059SGregory Neil Shapiro } 117040266059SGregory Neil Shapiro if (ret == HS_MATCH_NO && 117140266059SGregory Neil Shapiro braclev <= 0 && 117240266059SGregory Neil Shapiro ((*a == '\0' && *(b - 1) == ':') || 117340266059SGregory Neil Shapiro (*a == ':' && *(b - 1) == '\0'))) 117440266059SGregory Neil Shapiro return HS_MATCH_FIRST; 117540266059SGregory Neil Shapiro if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0) 117640266059SGregory Neil Shapiro return HS_MATCH_FULL; 117740266059SGregory Neil Shapiro 117840266059SGregory Neil Shapiro return ret; 117940266059SGregory Neil Shapiro } 1180e92d3f3fSGregory Neil Shapiro 1181e92d3f3fSGregory Neil Shapiro /* 1182e92d3f3fSGregory Neil Shapiro ** SHOULD_TRY_FBSH -- Should try FallbackSmartHost? 1183e92d3f3fSGregory Neil Shapiro ** 1184e92d3f3fSGregory Neil Shapiro ** Parameters: 1185e92d3f3fSGregory Neil Shapiro ** e -- envelope 1186e92d3f3fSGregory Neil Shapiro ** tried_fallbacksmarthost -- has been tried already? (in/out) 1187e92d3f3fSGregory Neil Shapiro ** hostbuf -- buffer for hostname (expand FallbackSmartHost) (out) 1188e92d3f3fSGregory Neil Shapiro ** hbsz -- size of hostbuf 1189e92d3f3fSGregory Neil Shapiro ** status -- current delivery status 1190e92d3f3fSGregory Neil Shapiro ** 1191e92d3f3fSGregory Neil Shapiro ** Returns: 1192e92d3f3fSGregory Neil Shapiro ** true iff FallbackSmartHost should be tried. 1193e92d3f3fSGregory Neil Shapiro */ 1194e92d3f3fSGregory Neil Shapiro 1195d0cef73dSGregory Neil Shapiro static bool should_try_fbsh __P((ENVELOPE *, bool *, char *, size_t, int)); 1196d0cef73dSGregory Neil Shapiro 1197e92d3f3fSGregory Neil Shapiro static bool 1198e92d3f3fSGregory Neil Shapiro should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status) 1199e92d3f3fSGregory Neil Shapiro ENVELOPE *e; 1200e92d3f3fSGregory Neil Shapiro bool *tried_fallbacksmarthost; 1201e92d3f3fSGregory Neil Shapiro char *hostbuf; 1202e92d3f3fSGregory Neil Shapiro size_t hbsz; 1203e92d3f3fSGregory Neil Shapiro int status; 1204e92d3f3fSGregory Neil Shapiro { 1205e92d3f3fSGregory Neil Shapiro /* 12064e4196cbSGregory Neil Shapiro ** If the host was not found or a temporary failure occurred 12074e4196cbSGregory Neil Shapiro ** and a FallbackSmartHost is defined (and we have not yet 12084e4196cbSGregory Neil Shapiro ** tried it), then make one last try with it as the host. 1209e92d3f3fSGregory Neil Shapiro */ 1210e92d3f3fSGregory Neil Shapiro 12114e4196cbSGregory Neil Shapiro if ((status == EX_NOHOST || status == EX_TEMPFAIL) && 12124e4196cbSGregory Neil Shapiro FallbackSmartHost != NULL && !*tried_fallbacksmarthost) 1213e92d3f3fSGregory Neil Shapiro { 1214e92d3f3fSGregory Neil Shapiro *tried_fallbacksmarthost = true; 1215e92d3f3fSGregory Neil Shapiro expand(FallbackSmartHost, hostbuf, hbsz, e); 1216e92d3f3fSGregory Neil Shapiro if (!wordinclass(hostbuf, 'w')) 1217e92d3f3fSGregory Neil Shapiro { 1218e92d3f3fSGregory Neil Shapiro if (tTd(11, 1)) 1219e92d3f3fSGregory Neil Shapiro sm_dprintf("one last try with FallbackSmartHost %s\n", 1220e92d3f3fSGregory Neil Shapiro hostbuf); 1221e92d3f3fSGregory Neil Shapiro return true; 1222e92d3f3fSGregory Neil Shapiro } 1223e92d3f3fSGregory Neil Shapiro } 1224e92d3f3fSGregory Neil Shapiro return false; 1225e92d3f3fSGregory Neil Shapiro } 122640266059SGregory Neil Shapiro /* 1227c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses. 1228c2aa98e2SPeter Wemm ** 1229c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the 1230c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers 1231c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed 1232c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so 1233c2aa98e2SPeter Wemm ** deliver should be called once for each address on the 1234c2aa98e2SPeter Wemm ** list. 123540266059SGregory Neil Shapiro ** Deliver tries to be as opportunistic as possible about piggybacking 123640266059SGregory Neil Shapiro ** messages. Some definitions to make understanding easier follow below. 123740266059SGregory Neil Shapiro ** Piggybacking occurs when an existing connection to a mail host can 123840266059SGregory Neil Shapiro ** be used to send the same message to more than one recipient at the 123940266059SGregory Neil Shapiro ** same time. So "no piggybacking" means one message for one recipient 124040266059SGregory Neil Shapiro ** per connection. "Intentional piggybacking" happens when the 124140266059SGregory Neil Shapiro ** recipients' host address (not the mail host address) is used to 124240266059SGregory Neil Shapiro ** attempt piggybacking. Recipients with the same host address 124340266059SGregory Neil Shapiro ** have the same mail host. "Coincidental piggybacking" relies on 124440266059SGregory Neil Shapiro ** piggybacking based on all the mail host addresses in the MX-RR. This 124540266059SGregory Neil Shapiro ** is "coincidental" in the fact it could not be predicted until the 124640266059SGregory Neil Shapiro ** MX Resource Records for the hosts were obtained and examined. For 124740266059SGregory Neil Shapiro ** example (preference order and equivalence is important, not values): 124840266059SGregory Neil Shapiro ** domain1 IN MX 10 mxhost-A 124940266059SGregory Neil Shapiro ** IN MX 20 mxhost-B 125040266059SGregory Neil Shapiro ** domain2 IN MX 4 mxhost-A 125140266059SGregory Neil Shapiro ** IN MX 8 mxhost-B 125240266059SGregory Neil Shapiro ** Domain1 and domain2 can piggyback the same message to mxhost-A or 125340266059SGregory Neil Shapiro ** mxhost-B (if mxhost-A cannot be reached). 125440266059SGregory Neil Shapiro ** "Coattail piggybacking" relaxes the strictness of "coincidental 125540266059SGregory Neil Shapiro ** piggybacking" in the hope that most significant (lowest value) 125640266059SGregory Neil Shapiro ** MX preference host(s) can create more piggybacking. For example 125740266059SGregory Neil Shapiro ** (again, preference order and equivalence is important, not values): 125840266059SGregory Neil Shapiro ** domain3 IN MX 100 mxhost-C 125940266059SGregory Neil Shapiro ** IN MX 100 mxhost-D 126040266059SGregory Neil Shapiro ** IN MX 200 mxhost-E 126140266059SGregory Neil Shapiro ** domain4 IN MX 50 mxhost-C 126240266059SGregory Neil Shapiro ** IN MX 50 mxhost-D 126340266059SGregory Neil Shapiro ** IN MX 80 mxhost-F 126440266059SGregory Neil Shapiro ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C 126540266059SGregory Neil Shapiro ** is available. Same with mxhost-D because in both RR's the preference 126640266059SGregory Neil Shapiro ** value is the same as mxhost-C, respectively. 126740266059SGregory Neil Shapiro ** So deliver attempts coattail piggybacking when possible. If the 126840266059SGregory Neil Shapiro ** first MX preference level hosts cannot be used then the piggybacking 126940266059SGregory Neil Shapiro ** reverts to coincidental piggybacking. Using the above example you 127040266059SGregory Neil Shapiro ** cannot deliver to mxhost-F for domain3 regardless of preference value. 127140266059SGregory Neil Shapiro ** ("Coattail" from "riding on the coattails of your predecessor" meaning 127240266059SGregory Neil Shapiro ** gaining benefit from a predecessor effort with no or little addition 127340266059SGregory Neil Shapiro ** effort. The predecessor here being the preceding MX RR). 1274c2aa98e2SPeter Wemm ** 1275c2aa98e2SPeter Wemm ** Parameters: 1276c2aa98e2SPeter Wemm ** e -- the envelope to deliver. 1277c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to. 1278c2aa98e2SPeter Wemm ** 1279c2aa98e2SPeter Wemm ** Returns: 1280c2aa98e2SPeter Wemm ** zero -- successfully delivered. 1281c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info. 1282c2aa98e2SPeter Wemm ** 1283c2aa98e2SPeter Wemm ** Side Effects: 1284c2aa98e2SPeter Wemm ** The standard input is passed off to someone. 1285c2aa98e2SPeter Wemm */ 1286c2aa98e2SPeter Wemm 128706f25ae9SGregory Neil Shapiro static int 1288c2aa98e2SPeter Wemm deliver(e, firstto) 1289c2aa98e2SPeter Wemm register ENVELOPE *e; 1290c2aa98e2SPeter Wemm ADDRESS *firstto; 1291c2aa98e2SPeter Wemm { 1292c2aa98e2SPeter Wemm char *host; /* host being sent to */ 1293c2aa98e2SPeter Wemm char *user; /* user being sent to */ 1294c2aa98e2SPeter Wemm char **pvp; 1295c2aa98e2SPeter Wemm register char **mvp; 1296c2aa98e2SPeter Wemm register char *p; 1297c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */ 1298c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr; 129940266059SGregory Neil Shapiro #if HASSETUSERCONTEXT 1300c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL; 130140266059SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 1302c2aa98e2SPeter Wemm register MCI *volatile mci; 130340266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE to = firstto; 130440266059SGregory Neil Shapiro volatile bool clever = false; /* running user smtp to this mailer */ 1305c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 1306c2aa98e2SPeter Wemm int rcode; /* response code */ 130740266059SGregory Neil Shapiro SM_NONVOLATILE int lmtp_rcode = EX_OK; 130840266059SGregory Neil Shapiro SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */ 130940266059SGregory Neil Shapiro SM_NONVOLATILE int hostnum = 0; /* current MX host index */ 1310c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */ 131140266059SGregory Neil Shapiro volatile pid_t pid = -1; 1312c2aa98e2SPeter Wemm char *volatile curhost; 131340266059SGregory Neil Shapiro SM_NONVOLATILE unsigned short port = 0; 131440266059SGregory Neil Shapiro SM_NONVOLATILE time_t enough = 0; 131506f25ae9SGregory Neil Shapiro #if NETUNIX 131640266059SGregory Neil Shapiro char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */ 131706f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 1318c2aa98e2SPeter Wemm time_t xstart; 1319c2aa98e2SPeter Wemm bool suidwarn; 1320c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */ 132140266059SGregory Neil Shapiro SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ 132206f25ae9SGregory Neil Shapiro bool ovr; 132340266059SGregory Neil Shapiro bool quarantine; 132406f25ae9SGregory Neil Shapiro int strsize; 132506f25ae9SGregory Neil Shapiro int rcptcount; 132640266059SGregory Neil Shapiro int ret; 132706f25ae9SGregory Neil Shapiro static int tobufsize = 0; 132806f25ae9SGregory Neil Shapiro static char *tobuf = NULL; 132940266059SGregory Neil Shapiro char *rpath; /* translated return path */ 1330c2aa98e2SPeter Wemm int mpvect[2]; 1331c2aa98e2SPeter Wemm int rpvect[2]; 133206f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1]; 1333c2aa98e2SPeter Wemm char *pv[MAXPV + 1]; 1334c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 133594c01205SGregory Neil Shapiro char cbuf[MAXPATHLEN]; 1336c2aa98e2SPeter Wemm 1337c2aa98e2SPeter Wemm errno = 0; 1338d0cef73dSGregory Neil Shapiro SM_REQUIRE(firstto != NULL); /* same as to */ 133906f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 134006f25ae9SGregory Neil Shapiro return 0; 1341c2aa98e2SPeter Wemm 1342c2aa98e2SPeter Wemm suidwarn = geteuid() == 0; 1343c2aa98e2SPeter Wemm 1344d0cef73dSGregory Neil Shapiro SM_REQUIRE(e != NULL); 1345c2aa98e2SPeter Wemm m = to->q_mailer; 1346c2aa98e2SPeter Wemm host = to->q_host; 1347c2aa98e2SPeter Wemm CurEnv = e; /* just in case */ 1348c2aa98e2SPeter Wemm e->e_statmsg = NULL; 1349c2aa98e2SPeter Wemm SmtpError[0] = '\0'; 1350c2aa98e2SPeter Wemm xstart = curtime(); 1351c2aa98e2SPeter Wemm 1352c2aa98e2SPeter Wemm if (tTd(10, 1)) 135340266059SGregory Neil Shapiro sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 1354c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user); 1355c2aa98e2SPeter Wemm if (tTd(10, 100)) 135640266059SGregory Neil Shapiro printopenfds(false); 1357c2aa98e2SPeter Wemm 1358c2aa98e2SPeter Wemm /* 135940266059SGregory Neil Shapiro ** Clear {client_*} macros if this is a bounce message to 1360c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset. 1361c2aa98e2SPeter Wemm */ 1362c2aa98e2SPeter Wemm 1363c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1364c2aa98e2SPeter Wemm { 136540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); 1366e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), ""); 136740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); 136840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); 136940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); 1370c2aa98e2SPeter Wemm } 1371c2aa98e2SPeter Wemm 137240266059SGregory Neil Shapiro SM_TRY 137340266059SGregory Neil Shapiro { 137440266059SGregory Neil Shapiro ADDRESS *skip_back = NULL; 137540266059SGregory Neil Shapiro 1376c2aa98e2SPeter Wemm /* 1377c2aa98e2SPeter Wemm ** Do initial argv setup. 1378c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is 1379c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has 1380c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This 1381c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a 1382c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV. 1383c2aa98e2SPeter Wemm ** The from address rewrite is expected to make 1384c2aa98e2SPeter Wemm ** the address relative to the other end. 1385c2aa98e2SPeter Wemm */ 1386c2aa98e2SPeter Wemm 1387c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */ 1388c2aa98e2SPeter Wemm rcode = EX_OK; 1389d0cef73dSGregory Neil Shapiro SM_ASSERT(e->e_from.q_mailer != NULL); 1390c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 1391c2aa98e2SPeter Wemm p = e->e_sender; 1392c2aa98e2SPeter Wemm else 1393c2aa98e2SPeter Wemm p = e->e_from.q_paddr; 139440266059SGregory Neil Shapiro rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 13959bd497b8SGregory Neil Shapiro if (strlen(rpath) > MAXNAME) 1396c2aa98e2SPeter Wemm { 139740266059SGregory Neil Shapiro rpath = shortenstring(rpath, MAXSHORTSTR); 139840266059SGregory Neil Shapiro 139940266059SGregory Neil Shapiro /* avoid bogus errno */ 140040266059SGregory Neil Shapiro errno = 0; 140140266059SGregory Neil Shapiro syserr("remotename: huge return path %s", rpath); 1402c2aa98e2SPeter Wemm } 140340266059SGregory Neil Shapiro rpath = sm_rpool_strdup_x(e->e_rpool, rpath); 140440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', rpath); 140540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', host); 1406c2aa98e2SPeter Wemm Errors = 0; 1407c2aa98e2SPeter Wemm pvp = pv; 1408c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0]; 1409c2aa98e2SPeter Wemm 1410e92d3f3fSGregory Neil Shapiro /* ignore long term host status information if mailer flag W is set */ 1411e92d3f3fSGregory Neil Shapiro if (bitnset(M_NOHOSTSTAT, m->m_flags)) 1412e92d3f3fSGregory Neil Shapiro IgnoreHostStatus = true; 1413e92d3f3fSGregory Neil Shapiro 1414c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */ 141506f25ae9SGregory Neil Shapiro if (FromFlag && 141606f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) || 141706f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags))) 1418c2aa98e2SPeter Wemm { 1419c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags)) 1420c2aa98e2SPeter Wemm *pvp++ = "-f"; 1421c2aa98e2SPeter Wemm else 1422c2aa98e2SPeter Wemm *pvp++ = "-r"; 142340266059SGregory Neil Shapiro *pvp++ = rpath; 1424c2aa98e2SPeter Wemm } 1425c2aa98e2SPeter Wemm 1426c2aa98e2SPeter Wemm /* 1427c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run 1428c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only 1429c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots 1430c2aa98e2SPeter Wemm ** in the pv after it. 1431c2aa98e2SPeter Wemm */ 1432c2aa98e2SPeter Wemm 1433c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1434c2aa98e2SPeter Wemm { 1435c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */ 1436c2aa98e2SPeter Wemm while (*p != '\0') 1437c2aa98e2SPeter Wemm { 1438c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND) 1439c2aa98e2SPeter Wemm { 1440c2aa98e2SPeter Wemm if (*p == 'u') 1441c2aa98e2SPeter Wemm break; 1442c2aa98e2SPeter Wemm } 1443c2aa98e2SPeter Wemm } 1444c2aa98e2SPeter Wemm 1445c2aa98e2SPeter Wemm if (*p != '\0') 1446c2aa98e2SPeter Wemm break; 1447c2aa98e2SPeter Wemm 1448c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */ 1449d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 145040266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1451c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3]) 1452c2aa98e2SPeter Wemm { 145306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u", 145406f25ae9SGregory Neil Shapiro pv[0]); 145540266059SGregory Neil Shapiro rcode = -1; 145640266059SGregory Neil Shapiro goto cleanup; 1457c2aa98e2SPeter Wemm } 1458c2aa98e2SPeter Wemm } 1459c2aa98e2SPeter Wemm 1460c2aa98e2SPeter Wemm /* 1461c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument 1462c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and 1463c2aa98e2SPeter Wemm ** SMTP is the answer!! 1464c2aa98e2SPeter Wemm */ 1465c2aa98e2SPeter Wemm 1466c2aa98e2SPeter Wemm if (*mvp == NULL) 1467c2aa98e2SPeter Wemm { 1468602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */ 146940266059SGregory Neil Shapiro clever = true; 1470c2aa98e2SPeter Wemm *pvp = NULL; 1471c2aa98e2SPeter Wemm } 1472602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags)) 1473602a2b1bSGregory Neil Shapiro { 1474602a2b1bSGregory Neil Shapiro /* not running LMTP */ 1475602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL, 1476602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off", 1477602a2b1bSGregory Neil Shapiro m->m_name); 1478602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags); 1479602a2b1bSGregory Neil Shapiro } 1480c2aa98e2SPeter Wemm 1481c2aa98e2SPeter Wemm /* 1482c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We 1483c2aa98e2SPeter Wemm ** run through our address list and append all the addresses 1484c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can 1485c2aa98e2SPeter Wemm ** always send another copy later. 1486c2aa98e2SPeter Wemm */ 1487c2aa98e2SPeter Wemm 148806f25ae9SGregory Neil Shapiro e->e_to = NULL; 148906f25ae9SGregory Neil Shapiro strsize = 2; 149006f25ae9SGregory Neil Shapiro rcptcount = 0; 1491c2aa98e2SPeter Wemm ctladdr = NULL; 149240266059SGregory Neil Shapiro if (firstto->q_signature == NULL) 149340266059SGregory Neil Shapiro firstto->q_signature = hostsignature(firstto->q_mailer, 149440266059SGregory Neil Shapiro firstto->q_host); 149540266059SGregory Neil Shapiro firstsig = firstto->q_signature; 149640266059SGregory Neil Shapiro 1497c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next) 1498c2aa98e2SPeter Wemm { 1499c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */ 150006f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 150106f25ae9SGregory Neil Shapiro break; 1502c2aa98e2SPeter Wemm 1503c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */ 150440266059SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) /* already sent; look at next */ 1505c2aa98e2SPeter Wemm continue; 1506c2aa98e2SPeter Wemm 150740266059SGregory Neil Shapiro /* 150840266059SGregory Neil Shapiro ** Must be same mailer to keep grouping rcpts. 150940266059SGregory Neil Shapiro ** If mailers don't match: continue; sendqueue is not 151040266059SGregory Neil Shapiro ** sorted by mailers, so don't break; 151140266059SGregory Neil Shapiro */ 151240266059SGregory Neil Shapiro 151340266059SGregory Neil Shapiro if (to->q_mailer != firstto->q_mailer) 151440266059SGregory Neil Shapiro continue; 151540266059SGregory Neil Shapiro 151640266059SGregory Neil Shapiro if (to->q_signature == NULL) /* for safety */ 151740266059SGregory Neil Shapiro to->q_signature = hostsignature(to->q_mailer, 151840266059SGregory Neil Shapiro to->q_host); 151940266059SGregory Neil Shapiro 152040266059SGregory Neil Shapiro /* 152140266059SGregory Neil Shapiro ** This is for coincidental and tailcoat piggybacking messages 152240266059SGregory Neil Shapiro ** to the same mail host. While the signatures are identical 152340266059SGregory Neil Shapiro ** (that's the MX-RR's are identical) we can do coincidental 152440266059SGregory Neil Shapiro ** piggybacking. We try hard for coattail piggybacking 152540266059SGregory Neil Shapiro ** with the same mail host when the next recipient has the 152640266059SGregory Neil Shapiro ** same host at lowest preference. It may be that this 152740266059SGregory Neil Shapiro ** won't work out, so 'skip_back' is maintained if a backup 152840266059SGregory Neil Shapiro ** to coincidental piggybacking or full signature must happen. 152940266059SGregory Neil Shapiro */ 153040266059SGregory Neil Shapiro 153140266059SGregory Neil Shapiro ret = firstto == to ? HS_MATCH_FULL : 153240266059SGregory Neil Shapiro coloncmp(to->q_signature, firstsig); 153340266059SGregory Neil Shapiro if (ret == HS_MATCH_FULL) 153440266059SGregory Neil Shapiro skip_back = to; 153540266059SGregory Neil Shapiro else if (ret == HS_MATCH_NO) 153606f25ae9SGregory Neil Shapiro break; 153706f25ae9SGregory Neil Shapiro 153840266059SGregory Neil Shapiro if (!clever) 153940266059SGregory Neil Shapiro { 154040266059SGregory Neil Shapiro /* avoid overflowing tobuf */ 154140266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 154240266059SGregory Neil Shapiro if (strsize > TOBUFSIZE) 154340266059SGregory Neil Shapiro break; 154440266059SGregory Neil Shapiro } 154540266059SGregory Neil Shapiro 154606f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt) 154706f25ae9SGregory Neil Shapiro break; 1548c2aa98e2SPeter Wemm 1549c2aa98e2SPeter Wemm if (tTd(10, 1)) 1550c2aa98e2SPeter Wemm { 155140266059SGregory Neil Shapiro sm_dprintf("\nsend to "); 1552e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false); 1553c2aa98e2SPeter Wemm } 1554c2aa98e2SPeter Wemm 1555c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */ 1556c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 155740266059SGregory Neil Shapiro # if HASSETUSERCONTEXT 1558c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to); 155940266059SGregory Neil Shapiro # else /* HASSETUSERCONTEXT */ 156040266059SGregory Neil Shapiro ctladdr = getctladdr(to); 156140266059SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 1562c2aa98e2SPeter Wemm 1563c2aa98e2SPeter Wemm if (tTd(10, 2)) 1564c2aa98e2SPeter Wemm { 156540266059SGregory Neil Shapiro sm_dprintf("ctladdr="); 1566e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false); 1567c2aa98e2SPeter Wemm } 1568c2aa98e2SPeter Wemm 1569c2aa98e2SPeter Wemm user = to->q_user; 1570c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 1571c2aa98e2SPeter Wemm 1572c2aa98e2SPeter Wemm /* 1573c2aa98e2SPeter Wemm ** Check to see that these people are allowed to 1574c2aa98e2SPeter Wemm ** talk to each other. 157542e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize. 1576c2aa98e2SPeter Wemm */ 1577c2aa98e2SPeter Wemm 157842e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 && 157942e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 1580c2aa98e2SPeter Wemm { 1581c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 1582c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 1583c2aa98e2SPeter Wemm to->q_status = "5.2.3"; 1584c2aa98e2SPeter Wemm else 1585c2aa98e2SPeter Wemm to->q_status = "5.3.4"; 158640266059SGregory Neil Shapiro 158706f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */ 158806f25ae9SGregory Neil Shapiro usrerrenh(to->q_status, 158906f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 159006f25ae9SGregory Neil Shapiro m->m_maxsize); 159140266059SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, false); 159206f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m, 159340266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1594c2aa98e2SPeter Wemm continue; 1595c2aa98e2SPeter Wemm } 1596602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 159740266059SGregory Neil Shapiro ovr = true; 1598c2aa98e2SPeter Wemm 1599c2aa98e2SPeter Wemm /* do config file checking of compatibility */ 160040266059SGregory Neil Shapiro quarantine = (e->e_quarmsg != NULL); 160106f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 1602959366dcSGregory Neil Shapiro e, RSF_RMCOMM|RSF_COUNT, 3, NULL, 1603d0cef73dSGregory Neil Shapiro e->e_id, NULL); 1604c2aa98e2SPeter Wemm if (rcode == EX_OK) 1605c2aa98e2SPeter Wemm { 1606065a643dSPeter Wemm /* do in-code checking if not discarding */ 1607065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags)) 160806f25ae9SGregory Neil Shapiro { 1609c2aa98e2SPeter Wemm rcode = checkcompat(to, e); 161040266059SGregory Neil Shapiro ovr = false; 161106f25ae9SGregory Neil Shapiro } 1612c2aa98e2SPeter Wemm } 1613c2aa98e2SPeter Wemm if (rcode != EX_OK) 1614c2aa98e2SPeter Wemm { 161506f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr); 161606f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, 161740266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1618c2aa98e2SPeter Wemm continue; 1619c2aa98e2SPeter Wemm } 162040266059SGregory Neil Shapiro if (!quarantine && e->e_quarmsg != NULL) 162140266059SGregory Neil Shapiro { 162240266059SGregory Neil Shapiro /* 162340266059SGregory Neil Shapiro ** check_compat or checkcompat() has tried 162440266059SGregory Neil Shapiro ** to quarantine but that isn't supported. 162540266059SGregory Neil Shapiro ** Revert the attempt. 162640266059SGregory Neil Shapiro */ 162740266059SGregory Neil Shapiro 162840266059SGregory Neil Shapiro e->e_quarmsg = NULL; 162940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 163040266059SGregory Neil Shapiro macid("{quarantine}"), ""); 163140266059SGregory Neil Shapiro } 1632065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 1633065a643dSPeter Wemm { 1634065a643dSPeter Wemm if (tTd(10, 5)) 1635065a643dSPeter Wemm { 163640266059SGregory Neil Shapiro sm_dprintf("deliver: discarding recipient "); 1637e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), to, false); 1638065a643dSPeter Wemm } 1639065a643dSPeter Wemm 164006f25ae9SGregory Neil Shapiro /* pretend the message was sent */ 164106f25ae9SGregory Neil Shapiro /* XXX should we log something here? */ 164206f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED; 164306f25ae9SGregory Neil Shapiro 1644065a643dSPeter Wemm /* 1645065a643dSPeter Wemm ** Remove discard bit to prevent discard of 164606f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the 164706f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before 164806f25ae9SGregory Neil Shapiro ** we get here. 1649065a643dSPeter Wemm */ 1650065a643dSPeter Wemm 165106f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD; 1652065a643dSPeter Wemm continue; 1653065a643dSPeter Wemm } 1654c2aa98e2SPeter Wemm 1655c2aa98e2SPeter Wemm /* 1656c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb 1657c2aa98e2SPeter Wemm ** about them. 1658c2aa98e2SPeter Wemm */ 1659c2aa98e2SPeter Wemm 1660c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags)) 1661c2aa98e2SPeter Wemm { 1662c2aa98e2SPeter Wemm stripquotes(user); 1663c2aa98e2SPeter Wemm stripquotes(host); 1664c2aa98e2SPeter Wemm } 1665e92d3f3fSGregory Neil Shapiro 166613bd1963SGregory Neil Shapiro /* 1667b6bacd31SGregory Neil Shapiro ** Strip all leading backslashes if requested and the 166813bd1963SGregory Neil Shapiro ** next character is alphanumerical (the latter can 166913bd1963SGregory Neil Shapiro ** probably relaxed a bit, see RFC2821). 167013bd1963SGregory Neil Shapiro */ 167113bd1963SGregory Neil Shapiro 167213bd1963SGregory Neil Shapiro if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\') 167313bd1963SGregory Neil Shapiro stripbackslash(user); 1674c2aa98e2SPeter Wemm 1675c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */ 1676c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|') 1677c2aa98e2SPeter Wemm user++; 1678c2aa98e2SPeter Wemm 1679c2aa98e2SPeter Wemm /* 1680c2aa98e2SPeter Wemm ** If an error message has already been given, don't 1681c2aa98e2SPeter Wemm ** bother to send to this address. 1682c2aa98e2SPeter Wemm ** 1683c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer 1684c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that 1685c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail. 1686c2aa98e2SPeter Wemm */ 1687c2aa98e2SPeter Wemm 168806f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 1689c2aa98e2SPeter Wemm continue; 1690c2aa98e2SPeter Wemm 1691c2aa98e2SPeter Wemm /* 1692c2aa98e2SPeter Wemm ** See if this user name is "special". 1693c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this 1694c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note 1695c2aa98e2SPeter Wemm ** that this type of addresses is not processed along 1696c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person. 1697c2aa98e2SPeter Wemm */ 1698c2aa98e2SPeter Wemm 1699c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0) 1700c2aa98e2SPeter Wemm { 170140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); 1702c2aa98e2SPeter Wemm p = to->q_home; 1703c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1704c2aa98e2SPeter Wemm p = ctladdr->q_home; 170540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); 1706d0cef73dSGregory Neil Shapiro expand(m->m_argv[1], buf, sizeof(buf), e); 1707c2aa98e2SPeter Wemm if (strlen(buf) > 0) 1708c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 1709c2aa98e2SPeter Wemm else 1710c2aa98e2SPeter Wemm { 1711c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s", 1712c2aa98e2SPeter Wemm m->m_name); 1713c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1714c2aa98e2SPeter Wemm } 171506f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL, 171640266059SGregory Neil Shapiro ctladdr, xstart, e, to); 171740266059SGregory Neil Shapiro markfailure(e, to, NULL, rcode, true); 1718c2aa98e2SPeter Wemm e->e_nsent++; 1719c2aa98e2SPeter Wemm if (rcode == EX_OK) 1720c2aa98e2SPeter Wemm { 172106f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 1722c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 1723c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 1724c2aa98e2SPeter Wemm { 1725c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 1726c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 172740266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, 172840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 172940266059SGregory Neil Shapiro "%s... Successfully delivered\n", 1730c2aa98e2SPeter Wemm to->q_paddr); 1731c2aa98e2SPeter Wemm } 1732c2aa98e2SPeter Wemm } 1733c2aa98e2SPeter Wemm to->q_statdate = curtime(); 173440266059SGregory Neil Shapiro markstats(e, to, STATS_NORMAL); 1735c2aa98e2SPeter Wemm continue; 1736c2aa98e2SPeter Wemm } 1737c2aa98e2SPeter Wemm 1738c2aa98e2SPeter Wemm /* 1739c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer 1740c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients. 1741c2aa98e2SPeter Wemm */ 1742c2aa98e2SPeter Wemm 1743c2aa98e2SPeter Wemm /* link together the chain of recipients */ 1744c2aa98e2SPeter Wemm to->q_tchain = tochain; 1745c2aa98e2SPeter Wemm tochain = to; 174606f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]"; 174706f25ae9SGregory Neil Shapiro 174840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */ 1749c2aa98e2SPeter Wemm p = to->q_home; 1750c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1751c2aa98e2SPeter Wemm p = ctladdr->q_home; 175240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */ 1753c2aa98e2SPeter Wemm 175406f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */ 175506f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags)) 175606f25ae9SGregory Neil Shapiro { 175706f25ae9SGregory Neil Shapiro char notify[MAXLINE]; 175806f25ae9SGregory Neil Shapiro 175906f25ae9SGregory Neil Shapiro notify[0] = '\0'; 176006f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags)) 176140266059SGregory Neil Shapiro (void) sm_strlcat(notify, "SUCCESS,", 1762d0cef73dSGregory Neil Shapiro sizeof(notify)); 176306f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags)) 176440266059SGregory Neil Shapiro (void) sm_strlcat(notify, "FAILURE,", 1765d0cef73dSGregory Neil Shapiro sizeof(notify)); 176606f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags)) 176740266059SGregory Neil Shapiro (void) sm_strlcat(notify, "DELAY,", 1768d0cef73dSGregory Neil Shapiro sizeof(notify)); 176906f25ae9SGregory Neil Shapiro 177006f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */ 177106f25ae9SGregory Neil Shapiro if (notify[0] == '\0') 177240266059SGregory Neil Shapiro (void) sm_strlcat(notify, "NEVER", 1773d0cef73dSGregory Neil Shapiro sizeof(notify)); 177406f25ae9SGregory Neil Shapiro else 177506f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0'; 177606f25ae9SGregory Neil Shapiro 177740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 177840266059SGregory Neil Shapiro macid("{dsn_notify}"), notify); 177906f25ae9SGregory Neil Shapiro } 178006f25ae9SGregory Neil Shapiro else 178140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 178240266059SGregory Neil Shapiro macid("{dsn_notify}"), NULL); 178306f25ae9SGregory Neil Shapiro 1784c2aa98e2SPeter Wemm /* 1785c2aa98e2SPeter Wemm ** Expand out this user into argument list. 1786c2aa98e2SPeter Wemm */ 1787c2aa98e2SPeter Wemm 1788c2aa98e2SPeter Wemm if (!clever) 1789c2aa98e2SPeter Wemm { 1790d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 179140266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1792c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2]) 1793c2aa98e2SPeter Wemm { 1794c2aa98e2SPeter Wemm /* allow some space for trailing parms */ 1795c2aa98e2SPeter Wemm break; 1796c2aa98e2SPeter Wemm } 1797c2aa98e2SPeter Wemm } 1798c2aa98e2SPeter Wemm } 1799c2aa98e2SPeter Wemm 1800c2aa98e2SPeter Wemm /* see if any addresses still exist */ 180106f25ae9SGregory Neil Shapiro if (tochain == NULL) 1802c2aa98e2SPeter Wemm { 180340266059SGregory Neil Shapiro rcode = 0; 180440266059SGregory Neil Shapiro goto cleanup; 1805c2aa98e2SPeter Wemm } 1806c2aa98e2SPeter Wemm 1807c2aa98e2SPeter Wemm /* print out messages as full list */ 180840266059SGregory Neil Shapiro strsize = 1; 180906f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 181040266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 181140266059SGregory Neil Shapiro if (strsize < TOBUFSIZE) 181240266059SGregory Neil Shapiro strsize = TOBUFSIZE; 181340266059SGregory Neil Shapiro if (strsize > tobufsize) 181406f25ae9SGregory Neil Shapiro { 181540266059SGregory Neil Shapiro SM_FREE_CLR(tobuf); 181640266059SGregory Neil Shapiro tobuf = sm_pmalloc_x(strsize); 181740266059SGregory Neil Shapiro tobufsize = strsize; 181806f25ae9SGregory Neil Shapiro } 181940266059SGregory Neil Shapiro p = tobuf; 182040266059SGregory Neil Shapiro *p = '\0'; 182106f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 182206f25ae9SGregory Neil Shapiro { 182340266059SGregory Neil Shapiro (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2, 182440266059SGregory Neil Shapiro ",", to->q_paddr); 182540266059SGregory Neil Shapiro p += strlen(p); 182606f25ae9SGregory Neil Shapiro } 1827c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 1828c2aa98e2SPeter Wemm 1829c2aa98e2SPeter Wemm /* 1830c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter. 1831c2aa98e2SPeter Wemm */ 1832c2aa98e2SPeter Wemm 183340266059SGregory Neil Shapiro if (!clever) 183440266059SGregory Neil Shapiro { 183540266059SGregory Neil Shapiro while (*++mvp != NULL) 1836c2aa98e2SPeter Wemm { 1837d0cef73dSGregory Neil Shapiro expand(*mvp, buf, sizeof(buf), e); 183840266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1839c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV]) 184006f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s", 184106f25ae9SGregory Neil Shapiro pv[0]); 1842c2aa98e2SPeter Wemm } 184340266059SGregory Neil Shapiro } 1844c2aa98e2SPeter Wemm *pvp++ = NULL; 1845c2aa98e2SPeter Wemm 1846c2aa98e2SPeter Wemm /* 1847c2aa98e2SPeter Wemm ** Call the mailer. 1848c2aa98e2SPeter Wemm ** The argument vector gets built, pipes 1849c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as 1850c2aa98e2SPeter Wemm ** appropriate. 1851c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up. 1852c2aa98e2SPeter Wemm */ 1853c2aa98e2SPeter Wemm 18546f9c8e5bSGregory Neil Shapiro /* XXX this seems a bit weird */ 1855c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 1856c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags)) 1857c2aa98e2SPeter Wemm ctladdr = &e->e_from; 1858c2aa98e2SPeter Wemm 1859c2aa98e2SPeter Wemm #if NAMED_BIND 1860c2aa98e2SPeter Wemm if (ConfigLevel < 2) 1861c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 186206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1863c2aa98e2SPeter Wemm 1864c2aa98e2SPeter Wemm if (tTd(11, 1)) 1865c2aa98e2SPeter Wemm { 186640266059SGregory Neil Shapiro sm_dprintf("openmailer:"); 1867e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pv); 1868c2aa98e2SPeter Wemm } 1869c2aa98e2SPeter Wemm errno = 0; 1870602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 1871c2aa98e2SPeter Wemm CurHostName = NULL; 1872c2aa98e2SPeter Wemm 1873c2aa98e2SPeter Wemm /* 1874c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC 1875c2aa98e2SPeter Wemm ** connection. 1876c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be 1877c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a 1878c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC. 1879c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out. 1880c2aa98e2SPeter Wemm */ 1881c2aa98e2SPeter Wemm 1882c2aa98e2SPeter Wemm curhost = NULL; 1883c2aa98e2SPeter Wemm SmtpPhase = NULL; 1884c2aa98e2SPeter Wemm mci = NULL; 1885c2aa98e2SPeter Wemm 1886c2aa98e2SPeter Wemm #if XDEBUG 1887c2aa98e2SPeter Wemm { 1888c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 1889c2aa98e2SPeter Wemm 1890c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 1891d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), "%s... openmailer(%s)", 189240266059SGregory Neil Shapiro shortenstring(e->e_to, MAXSHORTSTR), 189340266059SGregory Neil Shapiro m->m_name); 1894c2aa98e2SPeter Wemm checkfd012(wbuf); 1895c2aa98e2SPeter Wemm } 189606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1897c2aa98e2SPeter Wemm 1898c2aa98e2SPeter Wemm /* check for 8-bit available */ 1899c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 1900c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) && 1901c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 1902c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 1903c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 1904c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 1905c2aa98e2SPeter Wemm { 1906c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 190706f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 190806f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 190906f25ae9SGregory Neil Shapiro rcode = EX_DATAERR; 1910c2aa98e2SPeter Wemm goto give_up; 1911c2aa98e2SPeter Wemm } 1912c2aa98e2SPeter Wemm 1913c2aa98e2SPeter Wemm if (tTd(62, 8)) 1914c2aa98e2SPeter Wemm checkfds("before delivery"); 1915c2aa98e2SPeter Wemm 1916c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */ 1917c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0) 1918c2aa98e2SPeter Wemm { 191940266059SGregory Neil Shapiro if (clever) 192040266059SGregory Neil Shapiro { 192140266059SGregory Neil Shapiro /* flush any expired connections */ 192240266059SGregory Neil Shapiro (void) mci_scan(NULL); 192340266059SGregory Neil Shapiro 192440266059SGregory Neil Shapiro /* try to get a cached connection or just a slot */ 192540266059SGregory Neil Shapiro mci = mci_get(m->m_name, m); 192640266059SGregory Neil Shapiro if (mci->mci_host == NULL) 192740266059SGregory Neil Shapiro mci->mci_host = m->m_name; 192840266059SGregory Neil Shapiro CurHostName = mci->mci_host; 192940266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED) 193040266059SGregory Neil Shapiro { 193140266059SGregory Neil Shapiro message("Using cached SMTP/LPC connection for %s...", 193240266059SGregory Neil Shapiro m->m_name); 193340266059SGregory Neil Shapiro mci->mci_deliveries++; 193440266059SGregory Neil Shapiro goto do_transfer; 193540266059SGregory Neil Shapiro } 193640266059SGregory Neil Shapiro } 193740266059SGregory Neil Shapiro else 193840266059SGregory Neil Shapiro { 193940266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 194040266059SGregory Neil Shapiro } 194140266059SGregory Neil Shapiro mci->mci_in = smioin; 194240266059SGregory Neil Shapiro mci->mci_out = smioout; 194340266059SGregory Neil Shapiro mci->mci_mailer = m; 194440266059SGregory Neil Shapiro mci->mci_host = m->m_name; 194540266059SGregory Neil Shapiro if (clever) 194640266059SGregory Neil Shapiro { 194740266059SGregory Neil Shapiro mci->mci_state = MCIS_OPENING; 194840266059SGregory Neil Shapiro mci_cache(mci); 194940266059SGregory Neil Shapiro } 195040266059SGregory Neil Shapiro else 195140266059SGregory Neil Shapiro mci->mci_state = MCIS_OPEN; 1952c2aa98e2SPeter Wemm } 195340266059SGregory Neil Shapiro else if (strcmp(m->m_mailer, "[IPC]") == 0) 1954c2aa98e2SPeter Wemm { 1955c2aa98e2SPeter Wemm register int i; 1956c2aa98e2SPeter Wemm 1957c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1958c2aa98e2SPeter Wemm { 195906f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer); 1960c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1961c2aa98e2SPeter Wemm goto give_up; 1962c2aa98e2SPeter Wemm } 1963c2aa98e2SPeter Wemm 196406f25ae9SGregory Neil Shapiro # if NETUNIX 196506f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0) 196606f25ae9SGregory Neil Shapiro { 196706f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost"; 196806f25ae9SGregory Neil Shapiro mux_path = pv[1]; 196906f25ae9SGregory Neil Shapiro } 197006f25ae9SGregory Neil Shapiro else 197106f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 197206f25ae9SGregory Neil Shapiro { 1973c2aa98e2SPeter Wemm CurHostName = pv[1]; 197406f25ae9SGregory Neil Shapiro curhost = hostsignature(m, pv[1]); 197506f25ae9SGregory Neil Shapiro } 1976c2aa98e2SPeter Wemm 1977c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0') 1978c2aa98e2SPeter Wemm { 1979c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]); 1980c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1981c2aa98e2SPeter Wemm goto give_up; 1982c2aa98e2SPeter Wemm } 1983c2aa98e2SPeter Wemm 1984c2aa98e2SPeter Wemm if (!clever) 1985c2aa98e2SPeter Wemm { 198606f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC"); 1987c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1988c2aa98e2SPeter Wemm goto give_up; 1989c2aa98e2SPeter Wemm } 199006f25ae9SGregory Neil Shapiro if (pv[2] != NULL 199106f25ae9SGregory Neil Shapiro # if NETUNIX 199206f25ae9SGregory Neil Shapiro && mux_path == NULL 199306f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 199406f25ae9SGregory Neil Shapiro ) 1995c2aa98e2SPeter Wemm { 199640266059SGregory Neil Shapiro port = htons((unsigned short) atoi(pv[2])); 1997c2aa98e2SPeter Wemm if (port == 0) 1998c2aa98e2SPeter Wemm { 199906f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME 200006f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]); 200106f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */ 2002c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp"); 2003c2aa98e2SPeter Wemm 2004c2aa98e2SPeter Wemm if (sp == NULL) 2005c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]); 2006c2aa98e2SPeter Wemm else 2007c2aa98e2SPeter Wemm port = sp->s_port; 200806f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */ 2009c2aa98e2SPeter Wemm } 2010c2aa98e2SPeter Wemm } 2011c2aa98e2SPeter Wemm 201206f25ae9SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m); 201340266059SGregory Neil Shapiro if (TimeOuts.to_aconnect > 0) 201440266059SGregory Neil Shapiro enough = curtime() + TimeOuts.to_aconnect; 201506f25ae9SGregory Neil Shapiro tryhost: 201606f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts) 201706f25ae9SGregory Neil Shapiro { 201806f25ae9SGregory Neil Shapiro char sep = ':'; 201906f25ae9SGregory Neil Shapiro char *endp; 202006f25ae9SGregory Neil Shapiro static char hostbuf[MAXNAME + 1]; 2021e92d3f3fSGregory Neil Shapiro bool tried_fallbacksmarthost = false; 202206f25ae9SGregory Neil Shapiro 202306f25ae9SGregory Neil Shapiro # if NETINET6 202406f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '[') 202506f25ae9SGregory Neil Shapiro { 202606f25ae9SGregory Neil Shapiro endp = strchr(mxhosts[hostnum] + 1, ']'); 202706f25ae9SGregory Neil Shapiro if (endp != NULL) 202806f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 202906f25ae9SGregory Neil Shapiro } 203006f25ae9SGregory Neil Shapiro else 203106f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 203206f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 203306f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 203406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 203506f25ae9SGregory Neil Shapiro if (endp != NULL) 203606f25ae9SGregory Neil Shapiro { 203706f25ae9SGregory Neil Shapiro sep = *endp; 203806f25ae9SGregory Neil Shapiro *endp = '\0'; 203906f25ae9SGregory Neil Shapiro } 204006f25ae9SGregory Neil Shapiro 204140266059SGregory Neil Shapiro if (hostnum == 1 && skip_back != NULL) 204240266059SGregory Neil Shapiro { 204340266059SGregory Neil Shapiro /* 204440266059SGregory Neil Shapiro ** Coattail piggybacking is no longer an 204540266059SGregory Neil Shapiro ** option with the mail host next to be tried 204640266059SGregory Neil Shapiro ** no longer the lowest MX preference 204740266059SGregory Neil Shapiro ** (hostnum == 1 meaning we're on the second 204840266059SGregory Neil Shapiro ** preference). We do not try to coattail 204940266059SGregory Neil Shapiro ** piggyback more than the first MX preference. 205040266059SGregory Neil Shapiro ** Revert 'tochain' to last location for 205140266059SGregory Neil Shapiro ** coincidental piggybacking. This works this 205240266059SGregory Neil Shapiro ** easily because the q_tchain kept getting 205340266059SGregory Neil Shapiro ** added to the top of the linked list. 205440266059SGregory Neil Shapiro */ 205540266059SGregory Neil Shapiro 205640266059SGregory Neil Shapiro tochain = skip_back; 205740266059SGregory Neil Shapiro } 205840266059SGregory Neil Shapiro 205906f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0') 2060c2aa98e2SPeter Wemm { 2061c2aa98e2SPeter Wemm syserr("deliver: null host name in signature"); 206206f25ae9SGregory Neil Shapiro hostnum++; 206306f25ae9SGregory Neil Shapiro if (endp != NULL) 206406f25ae9SGregory Neil Shapiro *endp = sep; 2065c2aa98e2SPeter Wemm continue; 2066c2aa98e2SPeter Wemm } 206740266059SGregory Neil Shapiro (void) sm_strlcpy(hostbuf, mxhosts[hostnum], 2068d0cef73dSGregory Neil Shapiro sizeof(hostbuf)); 206906f25ae9SGregory Neil Shapiro hostnum++; 207006f25ae9SGregory Neil Shapiro if (endp != NULL) 207106f25ae9SGregory Neil Shapiro *endp = sep; 2072c2aa98e2SPeter Wemm 2073e92d3f3fSGregory Neil Shapiro one_last_try: 2074c2aa98e2SPeter Wemm /* see if we already know that this host is fried */ 2075c2aa98e2SPeter Wemm CurHostName = hostbuf; 2076c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m); 2077c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2078c2aa98e2SPeter Wemm { 207940266059SGregory Neil Shapiro char *type; 208040266059SGregory Neil Shapiro 2081c2aa98e2SPeter Wemm if (tTd(11, 1)) 2082c2aa98e2SPeter Wemm { 208340266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 2084e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 2085c2aa98e2SPeter Wemm } 2086c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 208740266059SGregory Neil Shapiro if (bitnset(M_LMTP, m->m_flags)) 208840266059SGregory Neil Shapiro type = "L"; 208940266059SGregory Neil Shapiro else if (bitset(MCIF_ESMTP, mci->mci_flags)) 209040266059SGregory Neil Shapiro type = "ES"; 209140266059SGregory Neil Shapiro else 209240266059SGregory Neil Shapiro type = "S"; 209340266059SGregory Neil Shapiro message("Using cached %sMTP connection to %s via %s...", 209440266059SGregory Neil Shapiro type, hostbuf, m->m_name); 209506f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2096c2aa98e2SPeter Wemm break; 2097c2aa98e2SPeter Wemm } 2098c2aa98e2SPeter Wemm mci->mci_mailer = m; 2099c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK) 2100c2aa98e2SPeter Wemm { 2101c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL) 210240266059SGregory Neil Shapiro goodmxfound = true; 2103e92d3f3fSGregory Neil Shapiro 2104e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */ 2105e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost, 2106d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf), 2107e92d3f3fSGregory Neil Shapiro mci->mci_exitstat)) 2108e92d3f3fSGregory Neil Shapiro goto one_last_try; 2109e92d3f3fSGregory Neil Shapiro 2110c2aa98e2SPeter Wemm continue; 2111c2aa98e2SPeter Wemm } 2112c2aa98e2SPeter Wemm 2113c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK) 2114c2aa98e2SPeter Wemm { 2115c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 211640266059SGregory Neil Shapiro goodmxfound = true; 2117c2aa98e2SPeter Wemm continue; 2118c2aa98e2SPeter Wemm } 2119c2aa98e2SPeter Wemm 2120c2aa98e2SPeter Wemm /* try the connection */ 212140266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %s", 212206f25ae9SGregory Neil Shapiro qid_printname(e), 212306f25ae9SGregory Neil Shapiro hostbuf, "user open"); 212406f25ae9SGregory Neil Shapiro # if NETUNIX 212506f25ae9SGregory Neil Shapiro if (mux_path != NULL) 212606f25ae9SGregory Neil Shapiro { 212706f25ae9SGregory Neil Shapiro message("Connecting to %s via %s...", 212806f25ae9SGregory Neil Shapiro mux_path, m->m_name); 212940266059SGregory Neil Shapiro i = makeconnection_ds((char *) mux_path, mci); 213006f25ae9SGregory Neil Shapiro } 213106f25ae9SGregory Neil Shapiro else 213206f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 213306f25ae9SGregory Neil Shapiro { 2134c2aa98e2SPeter Wemm if (port == 0) 2135c2aa98e2SPeter Wemm message("Connecting to %s via %s...", 2136c2aa98e2SPeter Wemm hostbuf, m->m_name); 2137c2aa98e2SPeter Wemm else 2138c2aa98e2SPeter Wemm message("Connecting to %s port %d via %s...", 213906f25ae9SGregory Neil Shapiro hostbuf, ntohs(port), 214006f25ae9SGregory Neil Shapiro m->m_name); 214140266059SGregory Neil Shapiro i = makeconnection(hostbuf, port, mci, e, 214240266059SGregory Neil Shapiro enough); 214306f25ae9SGregory Neil Shapiro } 21448774250cSGregory Neil Shapiro mci->mci_errno = errno; 2145c2aa98e2SPeter Wemm mci->mci_lastuse = curtime(); 214606f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0; 2147c2aa98e2SPeter Wemm mci->mci_exitstat = i; 21486f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 2149c2aa98e2SPeter Wemm # if NAMED_BIND 2150c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 215106f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */ 215240266059SGregory Neil Shapiro 215340266059SGregory Neil Shapiro /* 215440266059SGregory Neil Shapiro ** Have we tried long enough to get a connection? 215540266059SGregory Neil Shapiro ** If yes, skip to the fallback MX hosts 215640266059SGregory Neil Shapiro ** (if existent). 215740266059SGregory Neil Shapiro */ 215840266059SGregory Neil Shapiro 215940266059SGregory Neil Shapiro if (enough > 0 && mci->mci_lastuse >= enough) 216040266059SGregory Neil Shapiro { 216140266059SGregory Neil Shapiro int h; 216240266059SGregory Neil Shapiro # if NAMED_BIND 2163e92d3f3fSGregory Neil Shapiro extern int NumFallbackMXHosts; 216440266059SGregory Neil Shapiro # else /* NAMED_BIND */ 2165e92d3f3fSGregory Neil Shapiro const int NumFallbackMXHosts = 0; 216640266059SGregory Neil Shapiro # endif /* NAMED_BIND */ 216740266059SGregory Neil Shapiro 216840266059SGregory Neil Shapiro if (hostnum < nummxhosts && LogLevel > 9) 216940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 217040266059SGregory Neil Shapiro "Timeout.to_aconnect occurred before exhausting all addresses"); 217140266059SGregory Neil Shapiro 217240266059SGregory Neil Shapiro /* turn off timeout if fallback available */ 2173e92d3f3fSGregory Neil Shapiro if (NumFallbackMXHosts > 0) 217440266059SGregory Neil Shapiro enough = 0; 217540266059SGregory Neil Shapiro 217640266059SGregory Neil Shapiro /* skip to a fallback MX host */ 2177e92d3f3fSGregory Neil Shapiro h = nummxhosts - NumFallbackMXHosts; 217840266059SGregory Neil Shapiro if (hostnum < h) 217940266059SGregory Neil Shapiro hostnum = h; 218040266059SGregory Neil Shapiro } 2181c2aa98e2SPeter Wemm if (i == EX_OK) 2182c2aa98e2SPeter Wemm { 218340266059SGregory Neil Shapiro goodmxfound = true; 2184605302a5SGregory Neil Shapiro markstats(e, firstto, STATS_CONNECT); 2185c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2186c2aa98e2SPeter Wemm mci_cache(mci); 2187c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 218840266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 218940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 219040266059SGregory Neil Shapiro "%05d === CONNECT %s\n", 219140266059SGregory Neil Shapiro (int) CurrentPid, 219240266059SGregory Neil Shapiro hostbuf); 2193c2aa98e2SPeter Wemm break; 2194c2aa98e2SPeter Wemm } 2195c2aa98e2SPeter Wemm else 2196c2aa98e2SPeter Wemm { 2197e92d3f3fSGregory Neil Shapiro /* Try FallbackSmartHost? */ 2198e92d3f3fSGregory Neil Shapiro if (should_try_fbsh(e, &tried_fallbacksmarthost, 2199d0cef73dSGregory Neil Shapiro hostbuf, sizeof(hostbuf), i)) 2200e92d3f3fSGregory Neil Shapiro goto one_last_try; 2201e92d3f3fSGregory Neil Shapiro 2202c2aa98e2SPeter Wemm if (tTd(11, 1)) 220340266059SGregory Neil Shapiro sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 2204c2aa98e2SPeter Wemm i, errno); 2205c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL) 220640266059SGregory Neil Shapiro goodmxfound = true; 2207c2aa98e2SPeter Wemm mci_unlock_host(mci); 2208c2aa98e2SPeter Wemm } 2209c2aa98e2SPeter Wemm 2210c2aa98e2SPeter Wemm /* enter status of this host */ 2211c2aa98e2SPeter Wemm setstat(i); 2212c2aa98e2SPeter Wemm 2213c2aa98e2SPeter Wemm /* should print some message here for -v mode */ 2214c2aa98e2SPeter Wemm } 2215c2aa98e2SPeter Wemm if (mci == NULL) 2216c2aa98e2SPeter Wemm { 2217c2aa98e2SPeter Wemm syserr("deliver: no host name"); 2218c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 2219c2aa98e2SPeter Wemm goto give_up; 2220c2aa98e2SPeter Wemm } 2221c2aa98e2SPeter Wemm mci->mci_pid = 0; 2222c2aa98e2SPeter Wemm } 2223c2aa98e2SPeter Wemm else 2224c2aa98e2SPeter Wemm { 2225c2aa98e2SPeter Wemm /* flush any expired connections */ 2226c2aa98e2SPeter Wemm (void) mci_scan(NULL); 2227c2aa98e2SPeter Wemm mci = NULL; 2228c2aa98e2SPeter Wemm 2229c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2230c2aa98e2SPeter Wemm { 2231c2aa98e2SPeter Wemm /* try to get a cached connection */ 2232c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m); 2233c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 2234c2aa98e2SPeter Wemm mci->mci_host = m->m_name; 2235c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 2236c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2237c2aa98e2SPeter Wemm { 2238c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...", 2239c2aa98e2SPeter Wemm m->m_name); 224006f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2241c2aa98e2SPeter Wemm goto do_transfer; 2242c2aa98e2SPeter Wemm } 2243c2aa98e2SPeter Wemm } 2244c2aa98e2SPeter Wemm 2245c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */ 2246c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0') 2247c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name); 2248c2aa98e2SPeter Wemm else 2249c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name); 2250c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 2251c2aa98e2SPeter Wemm { 2252c2aa98e2SPeter Wemm char **av; 2253c2aa98e2SPeter Wemm 225440266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 225540266059SGregory Neil Shapiro "%05d === EXEC", (int) CurrentPid); 2256c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 225740266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 225840266059SGregory Neil Shapiro SM_TIME_DEFAULT, " %s", 225940266059SGregory Neil Shapiro *av); 226040266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 226140266059SGregory Neil Shapiro "\n"); 2262c2aa98e2SPeter Wemm } 2263c2aa98e2SPeter Wemm 2264c2aa98e2SPeter Wemm #if XDEBUG 2265c2aa98e2SPeter Wemm checkfd012("before creating mail pipe"); 226606f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2267c2aa98e2SPeter Wemm 2268c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */ 2269c2aa98e2SPeter Wemm if (pipe(mpvect) < 0) 2270c2aa98e2SPeter Wemm { 2271c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)", 2272c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2273c2aa98e2SPeter Wemm if (tTd(11, 1)) 227440266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2275c2aa98e2SPeter Wemm rcode = EX_OSERR; 2276c2aa98e2SPeter Wemm goto give_up; 2277c2aa98e2SPeter Wemm } 2278c2aa98e2SPeter Wemm 2279c2aa98e2SPeter Wemm #if XDEBUG 2280c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */ 2281c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3) 2282c2aa98e2SPeter Wemm { 2283c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d", 2284c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 2285c2aa98e2SPeter Wemm mpvect[0], mpvect[1]); 228640266059SGregory Neil Shapiro printopenfds(true); 2287c2aa98e2SPeter Wemm if (tTd(11, 1)) 228840266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2289c2aa98e2SPeter Wemm rcode = EX_OSERR; 2290c2aa98e2SPeter Wemm goto give_up; 2291c2aa98e2SPeter Wemm } 2292c2aa98e2SPeter Wemm 2293c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */ 2294c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]"); 2295c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]"); 2296c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] || 2297c2aa98e2SPeter Wemm (e->e_lockfp != NULL && 229840266059SGregory Neil Shapiro (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 229940266059SGregory Neil Shapiro NULL) || 230040266059SGregory Neil Shapiro mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 230140266059SGregory Neil Shapiro NULL)))) 2302c2aa98e2SPeter Wemm { 2303c2aa98e2SPeter Wemm if (e->e_lockfp == NULL) 2304c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d", 2305c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2306c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]); 2307c2aa98e2SPeter Wemm else 2308c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 2309c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2310c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1], 231140266059SGregory Neil Shapiro sm_io_getinfo(e->e_lockfp, 231240266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL)); 2313c2aa98e2SPeter Wemm } 231406f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2315c2aa98e2SPeter Wemm 231606f25ae9SGregory Neil Shapiro /* create a return pipe */ 2317c2aa98e2SPeter Wemm if (pipe(rpvect) < 0) 2318c2aa98e2SPeter Wemm { 2319c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)", 2320c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2321c2aa98e2SPeter Wemm m->m_name); 2322c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2323c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2324c2aa98e2SPeter Wemm if (tTd(11, 1)) 232540266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2326c2aa98e2SPeter Wemm rcode = EX_OSERR; 2327c2aa98e2SPeter Wemm goto give_up; 2328c2aa98e2SPeter Wemm } 2329c2aa98e2SPeter Wemm #if XDEBUG 2330c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]"); 2331c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]"); 233206f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2333c2aa98e2SPeter Wemm 2334c2aa98e2SPeter Wemm /* 2335c2aa98e2SPeter Wemm ** Actually fork the mailer process. 2336c2aa98e2SPeter Wemm ** DOFORK is clever about retrying. 2337c2aa98e2SPeter Wemm ** 2338c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying 233906f25ae9SGregory Neil Shapiro ** around so that endmailer will get it. 2340c2aa98e2SPeter Wemm */ 2341c2aa98e2SPeter Wemm 234240266059SGregory Neil Shapiro if (e->e_xfp != NULL) /* for debugging */ 234340266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 234440266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 234540266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 234606f25ae9SGregory Neil Shapiro 234706f25ae9SGregory Neil Shapiro 2348c2aa98e2SPeter Wemm DOFORK(FORK); 2349c2aa98e2SPeter Wemm /* pid is set by DOFORK */ 235006f25ae9SGregory Neil Shapiro 2351c2aa98e2SPeter Wemm if (pid < 0) 2352c2aa98e2SPeter Wemm { 2353c2aa98e2SPeter Wemm /* failure */ 2354c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork", 2355c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2356c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2357c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2358c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2359c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2360c2aa98e2SPeter Wemm if (tTd(11, 1)) 236140266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2362c2aa98e2SPeter Wemm rcode = EX_OSERR; 2363c2aa98e2SPeter Wemm goto give_up; 2364c2aa98e2SPeter Wemm } 2365c2aa98e2SPeter Wemm else if (pid == 0) 2366c2aa98e2SPeter Wemm { 236706f25ae9SGregory Neil Shapiro int save_errno; 236840266059SGregory Neil Shapiro int sff; 2369c2aa98e2SPeter Wemm int new_euid = NO_UID; 2370c2aa98e2SPeter Wemm int new_ruid = NO_UID; 2371c2aa98e2SPeter Wemm int new_gid = NO_GID; 237240266059SGregory Neil Shapiro char *user = NULL; 2373c2aa98e2SPeter Wemm struct stat stb; 2374c2aa98e2SPeter Wemm extern int DtableSize; 2375c2aa98e2SPeter Wemm 237640266059SGregory Neil Shapiro CurrentPid = getpid(); 237740266059SGregory Neil Shapiro 237813058a91SGregory Neil Shapiro /* clear the events to turn off SIGALRMs */ 237940266059SGregory Neil Shapiro sm_clear_events(); 238013058a91SGregory Neil Shapiro 23818774250cSGregory Neil Shapiro /* Reset global flags */ 23828774250cSGregory Neil Shapiro RestartRequest = NULL; 238340266059SGregory Neil Shapiro RestartWorkGroup = false; 23848774250cSGregory Neil Shapiro ShutdownRequest = NULL; 23858774250cSGregory Neil Shapiro PendingSignal = 0; 23868774250cSGregory Neil Shapiro 2387c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 238840266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, 238940266059SGregory Neil Shapiro SM_IO_WHAT_FD, 239040266059SGregory Neil Shapiro NULL)); 2391c2aa98e2SPeter Wemm 2392c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */ 239340266059SGregory Neil Shapiro (void) sm_signal(SIGALRM, sm_signal_noop); 239440266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 239540266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_IGN); 239640266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_IGN); 239740266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 239813058a91SGregory Neil Shapiro # ifdef SIGUSR1 239940266059SGregory Neil Shapiro (void) sm_signal(SIGUSR1, sm_signal_noop); 240013058a91SGregory Neil Shapiro # endif /* SIGUSR1 */ 2401c2aa98e2SPeter Wemm 2402c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 2403c2aa98e2SPeter Wemm stb.st_mode = 0; 2404c2aa98e2SPeter Wemm 2405c2aa98e2SPeter Wemm # if HASSETUSERCONTEXT 2406c2aa98e2SPeter Wemm /* 2407c2aa98e2SPeter Wemm ** Set user resources. 2408c2aa98e2SPeter Wemm */ 2409c2aa98e2SPeter Wemm 2410c2aa98e2SPeter Wemm if (contextaddr != NULL) 2411c2aa98e2SPeter Wemm { 241213bd1963SGregory Neil Shapiro int sucflags; 2413c2aa98e2SPeter Wemm struct passwd *pwd; 2414c2aa98e2SPeter Wemm 2415c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL) 2416c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser); 2417c2aa98e2SPeter Wemm else 2418c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user); 241913bd1963SGregory Neil Shapiro sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; 2420906a940eSEdward Tomasz Napierala #ifdef LOGIN_SETCPUMASK 2421906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETCPUMASK; 2422906a940eSEdward Tomasz Napierala #endif /* LOGIN_SETCPUMASK */ 2423906a940eSEdward Tomasz Napierala #ifdef LOGIN_SETLOGINCLASS 2424906a940eSEdward Tomasz Napierala sucflags |= LOGIN_SETLOGINCLASS; 2425906a940eSEdward Tomasz Napierala #endif /* LOGIN_SETLOGINCLASS */ 242613bd1963SGregory Neil Shapiro #ifdef LOGIN_SETMAC 242713bd1963SGregory Neil Shapiro sucflags |= LOGIN_SETMAC; 242813bd1963SGregory Neil Shapiro #endif /* LOGIN_SETMAC */ 2429959366dcSGregory Neil Shapiro if (pwd != NULL && 2430959366dcSGregory Neil Shapiro setusercontext(NULL, pwd, pwd->pw_uid, 243113bd1963SGregory Neil Shapiro sucflags) == -1 && 2432959366dcSGregory Neil Shapiro suidwarn) 2433959366dcSGregory Neil Shapiro { 2434959366dcSGregory Neil Shapiro syserr("openmailer: setusercontext() failed"); 2435959366dcSGregory Neil Shapiro exit(EX_TEMPFAIL); 2436959366dcSGregory Neil Shapiro } 2437c2aa98e2SPeter Wemm } 243806f25ae9SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 2439c2aa98e2SPeter Wemm 244040266059SGregory Neil Shapiro #if HASNICE 2441c2aa98e2SPeter Wemm /* tweak niceness */ 2442c2aa98e2SPeter Wemm if (m->m_nice != 0) 244306f25ae9SGregory Neil Shapiro (void) nice(m->m_nice); 244440266059SGregory Neil Shapiro #endif /* HASNICE */ 2445c2aa98e2SPeter Wemm 2446c2aa98e2SPeter Wemm /* reset group id */ 2447c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 2448e92d3f3fSGregory Neil Shapiro { 2449e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID) 2450e92d3f3fSGregory Neil Shapiro new_gid = RunAsGid; 2451e92d3f3fSGregory Neil Shapiro else 2452c2aa98e2SPeter Wemm new_gid = m->m_gid; 2453e92d3f3fSGregory Neil Shapiro } 2454c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode)) 2455c2aa98e2SPeter Wemm new_gid = stb.st_gid; 2456c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0) 2457c2aa98e2SPeter Wemm { 2458c2aa98e2SPeter Wemm if (!DontInitGroups) 2459c2aa98e2SPeter Wemm { 246040266059SGregory Neil Shapiro user = ctladdr->q_ruser; 246140266059SGregory Neil Shapiro if (user == NULL) 246240266059SGregory Neil Shapiro user = ctladdr->q_user; 2463c2aa98e2SPeter Wemm 246440266059SGregory Neil Shapiro if (initgroups(user, 246540266059SGregory Neil Shapiro ctladdr->q_gid) == -1 246640266059SGregory Neil Shapiro && suidwarn) 246706f25ae9SGregory Neil Shapiro { 2468c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 246940266059SGregory Neil Shapiro user, ctladdr->q_gid); 247006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 247106f25ae9SGregory Neil Shapiro } 2472c2aa98e2SPeter Wemm } 2473c2aa98e2SPeter Wemm else 2474c2aa98e2SPeter Wemm { 2475c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2476c2aa98e2SPeter Wemm 2477c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid; 247840266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 247940266059SGregory Neil Shapiro && suidwarn) 248006f25ae9SGregory Neil Shapiro { 2481c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 248206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 248306f25ae9SGregory Neil Shapiro } 2484c2aa98e2SPeter Wemm } 2485c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid; 2486c2aa98e2SPeter Wemm } 2487c2aa98e2SPeter Wemm else 2488c2aa98e2SPeter Wemm { 2489c2aa98e2SPeter Wemm if (!DontInitGroups) 2490c2aa98e2SPeter Wemm { 249140266059SGregory Neil Shapiro user = DefUser; 249240266059SGregory Neil Shapiro if (initgroups(DefUser, DefGid) == -1 && 249340266059SGregory Neil Shapiro suidwarn) 249406f25ae9SGregory Neil Shapiro { 2495c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 2496c2aa98e2SPeter Wemm DefUser, DefGid); 249706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 249806f25ae9SGregory Neil Shapiro } 2499c2aa98e2SPeter Wemm } 2500c2aa98e2SPeter Wemm else 2501c2aa98e2SPeter Wemm { 2502c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2503c2aa98e2SPeter Wemm 2504c2aa98e2SPeter Wemm gidset[0] = DefGid; 250540266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 250640266059SGregory Neil Shapiro && suidwarn) 250706f25ae9SGregory Neil Shapiro { 2508c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 250906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 251006f25ae9SGregory Neil Shapiro } 2511c2aa98e2SPeter Wemm } 2512e92d3f3fSGregory Neil Shapiro if (m->m_gid == NO_GID) 2513c2aa98e2SPeter Wemm new_gid = DefGid; 2514c2aa98e2SPeter Wemm else 2515c2aa98e2SPeter Wemm new_gid = m->m_gid; 2516c2aa98e2SPeter Wemm } 251706f25ae9SGregory Neil Shapiro if (new_gid != NO_GID) 251806f25ae9SGregory Neil Shapiro { 251906f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 252006f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) && 252106f25ae9SGregory Neil Shapiro new_gid != getgid() && 252206f25ae9SGregory Neil Shapiro new_gid != getegid()) 252306f25ae9SGregory Neil Shapiro { 252406f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 252540266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d", 252640266059SGregory Neil Shapiro (int) RunAsUid, (int) new_gid, 252740266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 252806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 252906f25ae9SGregory Neil Shapiro } 253006f25ae9SGregory Neil Shapiro 253106f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn) 253206f25ae9SGregory Neil Shapiro { 2533c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed", 2534c2aa98e2SPeter Wemm (long) new_gid); 253506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 253606f25ae9SGregory Neil Shapiro } 253706f25ae9SGregory Neil Shapiro } 253806f25ae9SGregory Neil Shapiro 253906f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */ 254006f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL) 254106f25ae9SGregory Neil Shapiro { 2542d0cef73dSGregory Neil Shapiro expand(m->m_rootdir, cbuf, sizeof(cbuf), e); 254306f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 254440266059SGregory Neil Shapiro sm_dprintf("openmailer: chroot %s\n", 254594c01205SGregory Neil Shapiro cbuf); 254694c01205SGregory Neil Shapiro if (chroot(cbuf) < 0) 254706f25ae9SGregory Neil Shapiro { 254806f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)", 254994c01205SGregory Neil Shapiro cbuf); 255006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 255106f25ae9SGregory Neil Shapiro } 255206f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 255306f25ae9SGregory Neil Shapiro { 255406f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)"); 255506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 255606f25ae9SGregory Neil Shapiro } 255706f25ae9SGregory Neil Shapiro } 2558c2aa98e2SPeter Wemm 2559c2aa98e2SPeter Wemm /* reset user id */ 2560c2aa98e2SPeter Wemm endpwent(); 256140266059SGregory Neil Shapiro sm_mbdb_terminate(); 2562c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 256313058a91SGregory Neil Shapiro { 2564e92d3f3fSGregory Neil Shapiro if (m->m_uid == NO_UID) 2565e92d3f3fSGregory Neil Shapiro new_euid = RunAsUid; 2566e92d3f3fSGregory Neil Shapiro else 2567c2aa98e2SPeter Wemm new_euid = m->m_uid; 256813058a91SGregory Neil Shapiro 256913058a91SGregory Neil Shapiro /* 257013058a91SGregory Neil Shapiro ** Undo the effects of the uid change in main 257113058a91SGregory Neil Shapiro ** for signal handling. The real uid may 257213058a91SGregory Neil Shapiro ** be used by mailer in adding a "From " 257313058a91SGregory Neil Shapiro ** line. 257413058a91SGregory Neil Shapiro */ 257513058a91SGregory Neil Shapiro 257613058a91SGregory Neil Shapiro if (RealUid != 0 && RealUid != getuid()) 257740266059SGregory Neil Shapiro { 257840266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 257940266059SGregory Neil Shapiro # if HASSETREUID 258040266059SGregory Neil Shapiro if (setreuid(RealUid, geteuid()) < 0) 258140266059SGregory Neil Shapiro { 258240266059SGregory Neil Shapiro syserr("openmailer: setreuid(%d, %d) failed", 258340266059SGregory Neil Shapiro (int) RealUid, (int) geteuid()); 258440266059SGregory Neil Shapiro exit(EX_OSERR); 258540266059SGregory Neil Shapiro } 258640266059SGregory Neil Shapiro # endif /* HASSETREUID */ 258740266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 258840266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 258913058a91SGregory Neil Shapiro new_ruid = RealUid; 259040266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 259140266059SGregory Neil Shapiro } 259213058a91SGregory Neil Shapiro } 2593c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode)) 2594c2aa98e2SPeter Wemm new_ruid = stb.st_uid; 2595c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 2596c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid; 2597e92d3f3fSGregory Neil Shapiro else if (m->m_uid != NO_UID) 2598c2aa98e2SPeter Wemm new_ruid = m->m_uid; 2599c2aa98e2SPeter Wemm else 2600c2aa98e2SPeter Wemm new_ruid = DefUid; 2601605302a5SGregory Neil Shapiro 2602605302a5SGregory Neil Shapiro # if _FFR_USE_SETLOGIN 2603605302a5SGregory Neil Shapiro /* run disconnected from terminal and set login name */ 2604605302a5SGregory Neil Shapiro if (setsid() >= 0 && 2605605302a5SGregory Neil Shapiro ctladdr != NULL && ctladdr->q_uid != 0 && 2606605302a5SGregory Neil Shapiro new_euid == ctladdr->q_uid) 2607605302a5SGregory Neil Shapiro { 2608605302a5SGregory Neil Shapiro struct passwd *pwd; 2609605302a5SGregory Neil Shapiro 2610605302a5SGregory Neil Shapiro pwd = sm_getpwuid(ctladdr->q_uid); 2611605302a5SGregory Neil Shapiro if (pwd != NULL && suidwarn) 2612605302a5SGregory Neil Shapiro (void) setlogin(pwd->pw_name); 2613605302a5SGregory Neil Shapiro endpwent(); 2614605302a5SGregory Neil Shapiro } 2615605302a5SGregory Neil Shapiro # endif /* _FFR_USE_SETLOGIN */ 2616605302a5SGregory Neil Shapiro 2617c2aa98e2SPeter Wemm if (new_euid != NO_UID) 2618c2aa98e2SPeter Wemm { 261906f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid) 262006f25ae9SGregory Neil Shapiro { 262106f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 262240266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d", 262340266059SGregory Neil Shapiro (int) new_euid, (int) RunAsUid); 262406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 262506f25ae9SGregory Neil Shapiro } 262606f25ae9SGregory Neil Shapiro 2627c2aa98e2SPeter Wemm vendor_set_uid(new_euid); 262806f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 2629c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn) 263006f25ae9SGregory Neil Shapiro { 2631c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed", 2632c2aa98e2SPeter Wemm (long) new_euid); 263306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 263406f25ae9SGregory Neil Shapiro } 263506f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 263606f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 2637c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 263806f25ae9SGregory Neil Shapiro { 2639c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed", 2640c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid); 264106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 264206f25ae9SGregory Neil Shapiro } 264306f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 264406f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETUID 2645c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 264606f25ae9SGregory Neil Shapiro { 2647c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2648c2aa98e2SPeter Wemm (long) new_euid); 264906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 265006f25ae9SGregory Neil Shapiro } 265106f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETUID */ 2652c2aa98e2SPeter Wemm } 2653c2aa98e2SPeter Wemm else if (new_ruid != NO_UID) 2654c2aa98e2SPeter Wemm { 2655c2aa98e2SPeter Wemm vendor_set_uid(new_ruid); 2656c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn) 265706f25ae9SGregory Neil Shapiro { 2658c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2659c2aa98e2SPeter Wemm (long) new_ruid); 266006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 266106f25ae9SGregory Neil Shapiro } 2662c2aa98e2SPeter Wemm } 2663c2aa98e2SPeter Wemm 2664c2aa98e2SPeter Wemm if (tTd(11, 2)) 266540266059SGregory Neil Shapiro sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", 266606f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 266706f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 2668c2aa98e2SPeter Wemm 2669c2aa98e2SPeter Wemm /* move into some "safe" directory */ 2670c2aa98e2SPeter Wemm if (m->m_execdir != NULL) 2671c2aa98e2SPeter Wemm { 2672c2aa98e2SPeter Wemm char *q; 2673c2aa98e2SPeter Wemm 2674c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q) 2675c2aa98e2SPeter Wemm { 2676c2aa98e2SPeter Wemm q = strchr(p, ':'); 2677c2aa98e2SPeter Wemm if (q != NULL) 2678c2aa98e2SPeter Wemm *q = '\0'; 2679d0cef73dSGregory Neil Shapiro expand(p, cbuf, sizeof(cbuf), e); 2680c2aa98e2SPeter Wemm if (q != NULL) 2681c2aa98e2SPeter Wemm *q++ = ':'; 2682c2aa98e2SPeter Wemm if (tTd(11, 20)) 268340266059SGregory Neil Shapiro sm_dprintf("openmailer: trydir %s\n", 268494c01205SGregory Neil Shapiro cbuf); 268594c01205SGregory Neil Shapiro if (cbuf[0] != '\0' && 268694c01205SGregory Neil Shapiro chdir(cbuf) >= 0) 2687c2aa98e2SPeter Wemm break; 2688c2aa98e2SPeter Wemm } 2689c2aa98e2SPeter Wemm } 2690c2aa98e2SPeter Wemm 269140266059SGregory Neil Shapiro /* Check safety of program to be run */ 269240266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK; 269340266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, 269440266059SGregory Neil Shapiro DontBlameSendmail)) 269540266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 269640266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, 269740266059SGregory Neil Shapiro DontBlameSendmail)) 269840266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK; 269940266059SGregory Neil Shapiro else 270040266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH; 270140266059SGregory Neil Shapiro ret = safefile(m->m_mailer, getuid(), getgid(), 270240266059SGregory Neil Shapiro user, sff, 0, NULL); 270340266059SGregory Neil Shapiro if (ret != 0) 270440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 270540266059SGregory Neil Shapiro "Warning: program %s unsafe: %s", 270640266059SGregory Neil Shapiro m->m_mailer, sm_errstring(ret)); 270740266059SGregory Neil Shapiro 2708c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */ 2709c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2710c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0) 2711c2aa98e2SPeter Wemm { 2712c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 2713c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2714c2aa98e2SPeter Wemm m->m_name, rpvect[1]); 2715c2aa98e2SPeter Wemm _exit(EX_OSERR); 2716c2aa98e2SPeter Wemm } 2717c2aa98e2SPeter Wemm (void) close(rpvect[1]); 271806f25ae9SGregory Neil Shapiro 2719c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 2720c2aa98e2SPeter Wemm { 2721c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr", 2722c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2723c2aa98e2SPeter Wemm m->m_name); 2724c2aa98e2SPeter Wemm _exit(EX_OSERR); 2725c2aa98e2SPeter Wemm } 2726c2aa98e2SPeter Wemm 2727c2aa98e2SPeter Wemm /* arrange to get standard input */ 2728c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2729c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0) 2730c2aa98e2SPeter Wemm { 2731c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 2732c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2733c2aa98e2SPeter Wemm m->m_name, mpvect[0]); 2734c2aa98e2SPeter Wemm _exit(EX_OSERR); 2735c2aa98e2SPeter Wemm } 2736c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2737c2aa98e2SPeter Wemm 2738c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2739e92d3f3fSGregory Neil Shapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 2740c2aa98e2SPeter Wemm 2741605302a5SGregory Neil Shapiro # if !_FFR_USE_SETLOGIN 2742c2aa98e2SPeter Wemm /* run disconnected from terminal */ 2743c2aa98e2SPeter Wemm (void) setsid(); 2744605302a5SGregory Neil Shapiro # endif /* !_FFR_USE_SETLOGIN */ 2745c2aa98e2SPeter Wemm 2746c2aa98e2SPeter Wemm /* try to execute the mailer */ 274706f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv, 274806f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron); 274906f25ae9SGregory Neil Shapiro save_errno = errno; 2750c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer); 2751c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) || 275206f25ae9SGregory Neil Shapiro transienterror(save_errno)) 2753c2aa98e2SPeter Wemm _exit(EX_OSERR); 2754c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE); 2755c2aa98e2SPeter Wemm } 2756c2aa98e2SPeter Wemm 2757c2aa98e2SPeter Wemm /* 2758c2aa98e2SPeter Wemm ** Set up return value. 2759c2aa98e2SPeter Wemm */ 2760c2aa98e2SPeter Wemm 2761c2aa98e2SPeter Wemm if (mci == NULL) 2762c2aa98e2SPeter Wemm { 276340266059SGregory Neil Shapiro if (clever) 276440266059SGregory Neil Shapiro { 276540266059SGregory Neil Shapiro /* 276640266059SGregory Neil Shapiro ** Allocate from general heap, not 276740266059SGregory Neil Shapiro ** envelope rpool, because this mci 276840266059SGregory Neil Shapiro ** is going to be cached. 276940266059SGregory Neil Shapiro */ 277040266059SGregory Neil Shapiro 277140266059SGregory Neil Shapiro mci = mci_new(NULL); 277240266059SGregory Neil Shapiro } 277340266059SGregory Neil Shapiro else 277440266059SGregory Neil Shapiro { 277540266059SGregory Neil Shapiro /* 277640266059SGregory Neil Shapiro ** Prevent a storage leak by allocating 277740266059SGregory Neil Shapiro ** this from the envelope rpool. 277840266059SGregory Neil Shapiro */ 277940266059SGregory Neil Shapiro 278040266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 278140266059SGregory Neil Shapiro } 2782c2aa98e2SPeter Wemm } 2783c2aa98e2SPeter Wemm mci->mci_mailer = m; 2784c2aa98e2SPeter Wemm if (clever) 2785c2aa98e2SPeter Wemm { 2786c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2787c2aa98e2SPeter Wemm mci_cache(mci); 2788c2aa98e2SPeter Wemm } 2789c2aa98e2SPeter Wemm else 2790c2aa98e2SPeter Wemm { 2791c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2792c2aa98e2SPeter Wemm } 2793c2aa98e2SPeter Wemm mci->mci_pid = pid; 2794c2aa98e2SPeter Wemm (void) close(mpvect[0]); 279540266059SGregory Neil Shapiro mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2796e92d3f3fSGregory Neil Shapiro (void *) &(mpvect[1]), SM_IO_WRONLY_B, 279740266059SGregory Neil Shapiro NULL); 2798c2aa98e2SPeter Wemm if (mci->mci_out == NULL) 2799c2aa98e2SPeter Wemm { 2800c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d", 2801c2aa98e2SPeter Wemm mpvect[1]); 2802c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2803c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2804c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2805c2aa98e2SPeter Wemm rcode = EX_OSERR; 2806c2aa98e2SPeter Wemm goto give_up; 2807c2aa98e2SPeter Wemm } 280806f25ae9SGregory Neil Shapiro 2809c2aa98e2SPeter Wemm (void) close(rpvect[1]); 281040266059SGregory Neil Shapiro mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2811e92d3f3fSGregory Neil Shapiro (void *) &(rpvect[0]), SM_IO_RDONLY_B, 281240266059SGregory Neil Shapiro NULL); 2813c2aa98e2SPeter Wemm if (mci->mci_in == NULL) 2814c2aa98e2SPeter Wemm { 2815c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d", 2816c2aa98e2SPeter Wemm mpvect[1]); 2817c2aa98e2SPeter Wemm (void) close(rpvect[0]); 281840266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 2819c2aa98e2SPeter Wemm mci->mci_out = NULL; 2820c2aa98e2SPeter Wemm rcode = EX_OSERR; 2821c2aa98e2SPeter Wemm goto give_up; 2822c2aa98e2SPeter Wemm } 2823c2aa98e2SPeter Wemm } 2824c2aa98e2SPeter Wemm 2825c2aa98e2SPeter Wemm /* 2826c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol. 2827c2aa98e2SPeter Wemm */ 2828c2aa98e2SPeter Wemm 2829c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) && 2830c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING)) 2831c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT; 2832c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED) 2833c2aa98e2SPeter Wemm { 283440266059SGregory Neil Shapiro # if STARTTLS || SASL 283540266059SGregory Neil Shapiro int dotpos; 283640266059SGregory Neil Shapiro char *srvname; 283740266059SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 283840266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 283940266059SGregory Neil Shapiro 284040266059SGregory Neil Shapiro # if SASL 2841193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 284240266059SGregory Neil Shapiro # endif /* SASL */ 284306f25ae9SGregory Neil Shapiro # if STARTTLS 2844193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 284506f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 2846193538b7SGregory Neil Shapiro # define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 2847193538b7SGregory Neil Shapiro # define SET_HELO(f) f |= MCIF_ONLY_EHLO 2848193538b7SGregory Neil Shapiro # define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 2849c2aa98e2SPeter Wemm 285040266059SGregory Neil Shapiro # if STARTTLS || SASL 285140266059SGregory Neil Shapiro /* don't use CurHostName, it is changed in many places */ 2852602a2b1bSGregory Neil Shapiro if (mci->mci_host != NULL) 2853602a2b1bSGregory Neil Shapiro { 2854602a2b1bSGregory Neil Shapiro srvname = mci->mci_host; 2855602a2b1bSGregory Neil Shapiro dotpos = strlen(srvname) - 1; 2856602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2857602a2b1bSGregory Neil Shapiro { 2858602a2b1bSGregory Neil Shapiro if (srvname[dotpos] == '.') 2859602a2b1bSGregory Neil Shapiro srvname[dotpos] = '\0'; 2860602a2b1bSGregory Neil Shapiro else 2861602a2b1bSGregory Neil Shapiro dotpos = -1; 2862602a2b1bSGregory Neil Shapiro } 2863602a2b1bSGregory Neil Shapiro } 286440266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 2865602a2b1bSGregory Neil Shapiro { 286640266059SGregory Neil Shapiro srvname = mci->mci_mailer->m_name; 2867602a2b1bSGregory Neil Shapiro dotpos = -1; 2868602a2b1bSGregory Neil Shapiro } 286906f25ae9SGregory Neil Shapiro else 287006f25ae9SGregory Neil Shapiro { 287140266059SGregory Neil Shapiro srvname = "local"; 287240266059SGregory Neil Shapiro dotpos = -1; 2873193538b7SGregory Neil Shapiro } 287406f25ae9SGregory Neil Shapiro 287540266059SGregory Neil Shapiro /* don't set {server_name} to NULL or "": see getauth() */ 287640266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"), 287740266059SGregory Neil Shapiro srvname); 287840266059SGregory Neil Shapiro 287940266059SGregory Neil Shapiro /* CurHostAddr is set by makeconnection() and mci_get() */ 288040266059SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0) 288140266059SGregory Neil Shapiro { 288240266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, 288340266059SGregory Neil Shapiro macid("{server_addr}"), 288440266059SGregory Neil Shapiro anynet_ntoa(&CurHostAddr)); 288540266059SGregory Neil Shapiro } 288640266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 288740266059SGregory Neil Shapiro { 288840266059SGregory Neil Shapiro /* mailer name is unique, use it as address */ 288940266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 289040266059SGregory Neil Shapiro macid("{server_addr}"), 289140266059SGregory Neil Shapiro mci->mci_mailer->m_name); 289240266059SGregory Neil Shapiro } 289340266059SGregory Neil Shapiro else 289440266059SGregory Neil Shapiro { 289540266059SGregory Neil Shapiro /* don't set it to NULL or "": see getauth() */ 289640266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 289740266059SGregory Neil Shapiro macid("{server_addr}"), "0"); 289840266059SGregory Neil Shapiro } 289940266059SGregory Neil Shapiro 290040266059SGregory Neil Shapiro /* undo change of srvname (mci->mci_host) */ 2901602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2902602a2b1bSGregory Neil Shapiro srvname[dotpos] = '.'; 290340266059SGregory Neil Shapiro 290440266059SGregory Neil Shapiro reconnect: /* after switching to an encrypted connection */ 290540266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 290640266059SGregory Neil Shapiro 290740266059SGregory Neil Shapiro /* set the current connection information */ 290840266059SGregory Neil Shapiro e->e_mci = mci; 290940266059SGregory Neil Shapiro # if SASL 291040266059SGregory Neil Shapiro mci->mci_saslcap = NULL; 291140266059SGregory Neil Shapiro # endif /* SASL */ 291240266059SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 291340266059SGregory Neil Shapiro CLR_HELO(mci->mci_flags); 291440266059SGregory Neil Shapiro 291540266059SGregory Neil Shapiro if (IS_DLVR_RETURN(e)) 291640266059SGregory Neil Shapiro { 291740266059SGregory Neil Shapiro /* 291840266059SGregory Neil Shapiro ** Check whether other side can deliver e-mail 291940266059SGregory Neil Shapiro ** fast enough 292040266059SGregory Neil Shapiro */ 292140266059SGregory Neil Shapiro 292240266059SGregory Neil Shapiro if (!bitset(MCIF_DLVR_BY, mci->mci_flags)) 292340266059SGregory Neil Shapiro { 292440266059SGregory Neil Shapiro e->e_status = "5.4.7"; 292540266059SGregory Neil Shapiro usrerrenh(e->e_status, 292640266059SGregory Neil Shapiro "554 Server does not support Deliver By"); 292740266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 292840266059SGregory Neil Shapiro goto give_up; 292940266059SGregory Neil Shapiro } 293040266059SGregory Neil Shapiro if (e->e_deliver_by > 0 && 293140266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime) < 293240266059SGregory Neil Shapiro mci->mci_min_by) 293340266059SGregory Neil Shapiro { 293440266059SGregory Neil Shapiro e->e_status = "5.4.7"; 293540266059SGregory Neil Shapiro usrerrenh(e->e_status, 293640266059SGregory Neil Shapiro "554 Message can't be delivered in time; %ld < %ld", 293740266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime), 293840266059SGregory Neil Shapiro mci->mci_min_by); 293940266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 294040266059SGregory Neil Shapiro goto give_up; 294140266059SGregory Neil Shapiro } 294240266059SGregory Neil Shapiro } 294340266059SGregory Neil Shapiro 294440266059SGregory Neil Shapiro # if STARTTLS 294540266059SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */ 294640266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 294740266059SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags)) 294840266059SGregory Neil Shapiro { 294940266059SGregory Neil Shapiro int olderrors; 295040266059SGregory Neil Shapiro bool usetls; 295140266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 295240266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 295340266059SGregory Neil Shapiro char *host = NULL; 295440266059SGregory Neil Shapiro 295540266059SGregory Neil Shapiro rcode = EX_OK; 295640266059SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags); 295740266059SGregory Neil Shapiro if (usetls) 295840266059SGregory Neil Shapiro usetls = !iscltflgset(e, D_NOTLS); 295940266059SGregory Neil Shapiro 2960d0cef73dSGregory Neil Shapiro host = macvalue(macid("{server_name}"), e); 296140266059SGregory Neil Shapiro if (usetls) 296240266059SGregory Neil Shapiro { 296340266059SGregory Neil Shapiro olderrors = Errors; 296440266059SGregory Neil Shapiro QuickAbort = false; 296540266059SGregory Neil Shapiro SuprErrs = true; 2966959366dcSGregory Neil Shapiro if (rscheck("try_tls", host, NULL, e, 2967d0cef73dSGregory Neil Shapiro RSF_RMCOMM, 7, host, NOQID, NULL) 2968d0cef73dSGregory Neil Shapiro != EX_OK 296940266059SGregory Neil Shapiro || Errors > olderrors) 2970d0cef73dSGregory Neil Shapiro { 297140266059SGregory Neil Shapiro usetls = false; 2972d0cef73dSGregory Neil Shapiro } 297340266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 297440266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 297540266059SGregory Neil Shapiro } 297640266059SGregory Neil Shapiro 297706f25ae9SGregory Neil Shapiro if (usetls) 297806f25ae9SGregory Neil Shapiro { 297906f25ae9SGregory Neil Shapiro if ((rcode = starttls(m, mci, e)) == EX_OK) 298006f25ae9SGregory Neil Shapiro { 298106f25ae9SGregory Neil Shapiro /* start again without STARTTLS */ 298206f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT; 298306f25ae9SGregory Neil Shapiro } 298406f25ae9SGregory Neil Shapiro else 298506f25ae9SGregory Neil Shapiro { 298606f25ae9SGregory Neil Shapiro char *s; 298706f25ae9SGregory Neil Shapiro 298806f25ae9SGregory Neil Shapiro /* 29899bd497b8SGregory Neil Shapiro ** TLS negotiation failed, what to do? 299006f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection 299106f25ae9SGregory Neil Shapiro ** or abort? How to decide? 299206f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset. 299306f25ae9SGregory Neil Shapiro */ 299440266059SGregory Neil Shapiro 299506f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS; 299606f25ae9SGregory Neil Shapiro switch (rcode) 299706f25ae9SGregory Neil Shapiro { 299806f25ae9SGregory Neil Shapiro case EX_TEMPFAIL: 299906f25ae9SGregory Neil Shapiro s = "TEMP"; 300006f25ae9SGregory Neil Shapiro break; 300106f25ae9SGregory Neil Shapiro case EX_USAGE: 300206f25ae9SGregory Neil Shapiro s = "USAGE"; 300306f25ae9SGregory Neil Shapiro break; 300406f25ae9SGregory Neil Shapiro case EX_PROTOCOL: 300506f25ae9SGregory Neil Shapiro s = "PROTOCOL"; 300606f25ae9SGregory Neil Shapiro break; 300706f25ae9SGregory Neil Shapiro case EX_SOFTWARE: 300806f25ae9SGregory Neil Shapiro s = "SOFTWARE"; 300906f25ae9SGregory Neil Shapiro break; 30104e4196cbSGregory Neil Shapiro case EX_UNAVAILABLE: 30114e4196cbSGregory Neil Shapiro s = "NONE"; 30124e4196cbSGregory Neil Shapiro break; 301306f25ae9SGregory Neil Shapiro 301406f25ae9SGregory Neil Shapiro /* everything else is a failure */ 301506f25ae9SGregory Neil Shapiro default: 301606f25ae9SGregory Neil Shapiro s = "FAILURE"; 301706f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL; 301806f25ae9SGregory Neil Shapiro } 301940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 302040266059SGregory Neil Shapiro macid("{verify}"), s); 302106f25ae9SGregory Neil Shapiro } 302206f25ae9SGregory Neil Shapiro } 302306f25ae9SGregory Neil Shapiro else 302440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 302540266059SGregory Neil Shapiro macid("{verify}"), "NONE"); 302606f25ae9SGregory Neil Shapiro olderrors = Errors; 302740266059SGregory Neil Shapiro QuickAbort = false; 302840266059SGregory Neil Shapiro SuprErrs = true; 302906f25ae9SGregory Neil Shapiro 303006f25ae9SGregory Neil Shapiro /* 303106f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special: 30329bd497b8SGregory Neil Shapiro ** the TLS negotiation failed 303306f25ae9SGregory Neil Shapiro ** we have to drop the connection no matter what 303406f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance 303506f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate 303606f25ae9SGregory Neil Shapiro ** error code. 303706f25ae9SGregory Neil Shapiro */ 303840266059SGregory Neil Shapiro 303906f25ae9SGregory Neil Shapiro if (rscheck("tls_server", 304040266059SGregory Neil Shapiro macvalue(macid("{verify}"), e), 3041959366dcSGregory Neil Shapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 5, 3042d0cef73dSGregory Neil Shapiro host, NOQID, NULL) != EX_OK || 304306f25ae9SGregory Neil Shapiro Errors > olderrors || 304406f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE) 304506f25ae9SGregory Neil Shapiro { 304606f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN]; 304706f25ae9SGregory Neil Shapiro extern char MsgBuf[]; 304806f25ae9SGregory Neil Shapiro 304906f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) && 305006f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 305106f25ae9SGregory Neil Shapiro { 305240266059SGregory Neil Shapiro p = sm_rpool_strdup_x(e->e_rpool, 305340266059SGregory Neil Shapiro MsgBuf); 305406f25ae9SGregory Neil Shapiro } 305506f25ae9SGregory Neil Shapiro else 305606f25ae9SGregory Neil Shapiro { 305706f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated."; 305840266059SGregory Neil Shapiro (void) sm_strlcpy(enhsc, "4.7.0", 3059d0cef73dSGregory Neil Shapiro sizeof(enhsc)); 306006f25ae9SGregory Neil Shapiro } 306106f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 306206f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 306306f25ae9SGregory Neil Shapiro 306406f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE) 306506f25ae9SGregory Neil Shapiro { 306606f25ae9SGregory Neil Shapiro /* drop the connection */ 306706f25ae9SGregory Neil Shapiro mci->mci_state = MCIS_QUITING; 306806f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 306906f25ae9SGregory Neil Shapiro { 307040266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, 307140266059SGregory Neil Shapiro SM_TIME_DEFAULT); 307206f25ae9SGregory Neil Shapiro mci->mci_in = NULL; 307306f25ae9SGregory Neil Shapiro } 307406f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 307506f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv); 307606f25ae9SGregory Neil Shapiro } 307706f25ae9SGregory Neil Shapiro else 307806f25ae9SGregory Neil Shapiro { 307906f25ae9SGregory Neil Shapiro /* abort transfer */ 308006f25ae9SGregory Neil Shapiro smtpquit(m, mci, e); 308106f25ae9SGregory Neil Shapiro } 308206f25ae9SGregory Neil Shapiro 3083193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 3084193538b7SGregory Neil Shapiro mci->mci_errno = 0; 3085193538b7SGregory Neil Shapiro 308606f25ae9SGregory Neil Shapiro /* temp or permanent failure? */ 308706f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL 308806f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE; 308940266059SGregory Neil Shapiro mci_setstat(mci, rcode, enhsc, p); 309006f25ae9SGregory Neil Shapiro 309106f25ae9SGregory Neil Shapiro /* 309206f25ae9SGregory Neil Shapiro ** hack to get the error message into 309306f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse()) 309406f25ae9SGregory Neil Shapiro */ 309540266059SGregory Neil Shapiro 309640266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, p, 3097d0cef73dSGregory Neil Shapiro sizeof(SmtpError)); 309806f25ae9SGregory Neil Shapiro } 3099d0cef73dSGregory Neil Shapiro else if (mci->mci_state == MCIS_CLOSED) 3100d0cef73dSGregory Neil Shapiro { 3101d0cef73dSGregory Neil Shapiro /* connection close caused by 421 */ 3102d0cef73dSGregory Neil Shapiro mci->mci_errno = 0; 3103d0cef73dSGregory Neil Shapiro rcode = EX_TEMPFAIL; 3104d0cef73dSGregory Neil Shapiro mci_setstat(mci, rcode, NULL, "421"); 3105d0cef73dSGregory Neil Shapiro } 3106d0cef73dSGregory Neil Shapiro else 3107d0cef73dSGregory Neil Shapiro rcode = 0; 3108d0cef73dSGregory Neil Shapiro 310906f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 311006f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 3111193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) && 3112193538b7SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED) 311306f25ae9SGregory Neil Shapiro { 3114193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 31156f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 311606f25ae9SGregory Neil Shapiro goto reconnect; 311706f25ae9SGregory Neil Shapiro } 311806f25ae9SGregory Neil Shapiro } 311906f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 312006f25ae9SGregory Neil Shapiro # if SASL 312106f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */ 312206f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 312306f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL && 312440266059SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH)) 312506f25ae9SGregory Neil Shapiro { 312640266059SGregory Neil Shapiro /* Should we require some minimum authentication? */ 312740266059SGregory Neil Shapiro if ((ret = smtpauth(m, mci, e)) == EX_OK) 312806f25ae9SGregory Neil Shapiro { 312906f25ae9SGregory Neil Shapiro int result; 313040266059SGregory Neil Shapiro sasl_ssf_t *ssf = NULL; 313106f25ae9SGregory Neil Shapiro 313240266059SGregory Neil Shapiro /* Get security strength (features) */ 313306f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF, 313494c01205SGregory Neil Shapiro # if SASL >= 20000 313594c01205SGregory Neil Shapiro (const void **) &ssf); 313694c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 313706f25ae9SGregory Neil Shapiro (void **) &ssf); 313894c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 313940266059SGregory Neil Shapiro 314040266059SGregory Neil Shapiro /* XXX authid? */ 314106f25ae9SGregory Neil Shapiro if (LogLevel > 9) 314206f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 314340266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, mech=%.16s, bits=%d", 314406f25ae9SGregory Neil Shapiro mci->mci_host, 314540266059SGregory Neil Shapiro macvalue(macid("{auth_type}"), e), 314640266059SGregory Neil Shapiro result == SASL_OK ? *ssf : 0); 31478774250cSGregory Neil Shapiro 314806f25ae9SGregory Neil Shapiro /* 314940266059SGregory Neil Shapiro ** Only switch to encrypted connection 315006f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated 315106f25ae9SGregory Neil Shapiro */ 315240266059SGregory Neil Shapiro 315306f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0) 315406f25ae9SGregory Neil Shapiro { 3155af9557fdSGregory Neil Shapiro int tmo; 3156af9557fdSGregory Neil Shapiro 315706f25ae9SGregory Neil Shapiro /* 315840266059SGregory Neil Shapiro ** Convert I/O layer to use SASL. 315940266059SGregory Neil Shapiro ** If the call fails, the connection 316040266059SGregory Neil Shapiro ** is aborted. 316106f25ae9SGregory Neil Shapiro */ 316240266059SGregory Neil Shapiro 3163af9557fdSGregory Neil Shapiro tmo = DATA_PROGRESS_TIMEOUT * 1000; 316440266059SGregory Neil Shapiro if (sfdcsasl(&mci->mci_in, 316540266059SGregory Neil Shapiro &mci->mci_out, 3166af9557fdSGregory Neil Shapiro mci->mci_conn, tmo) == 0) 316706f25ae9SGregory Neil Shapiro { 31686f9c8e5bSGregory Neil Shapiro mci_clr_extensions(mci); 316940266059SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT| 317040266059SGregory Neil Shapiro MCIF_ONLY_EHLO; 317106f25ae9SGregory Neil Shapiro goto reconnect; 317206f25ae9SGregory Neil Shapiro } 317340266059SGregory Neil Shapiro syserr("AUTH TLS switch failed in client"); 317406f25ae9SGregory Neil Shapiro } 317506f25ae9SGregory Neil Shapiro /* else? XXX */ 317606f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 317706f25ae9SGregory Neil Shapiro 317806f25ae9SGregory Neil Shapiro } 317940266059SGregory Neil Shapiro else if (ret == EX_TEMPFAIL) 318040266059SGregory Neil Shapiro { 318140266059SGregory Neil Shapiro if (LogLevel > 8) 318240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 318340266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, temporary failure, connection abort", 318440266059SGregory Neil Shapiro mci->mci_host); 318540266059SGregory Neil Shapiro smtpquit(m, mci, e); 318640266059SGregory Neil Shapiro 318740266059SGregory Neil Shapiro /* avoid bogus error msg */ 318840266059SGregory Neil Shapiro mci->mci_errno = 0; 318940266059SGregory Neil Shapiro rcode = EX_TEMPFAIL; 3190e92d3f3fSGregory Neil Shapiro mci_setstat(mci, rcode, "4.3.0", p); 319140266059SGregory Neil Shapiro 319240266059SGregory Neil Shapiro /* 319340266059SGregory Neil Shapiro ** hack to get the error message into 319440266059SGregory Neil Shapiro ** the envelope (done in giveresponse()) 319540266059SGregory Neil Shapiro */ 319640266059SGregory Neil Shapiro 319740266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, 319840266059SGregory Neil Shapiro "Temporary AUTH failure", 3199d0cef73dSGregory Neil Shapiro sizeof(SmtpError)); 320040266059SGregory Neil Shapiro } 320106f25ae9SGregory Neil Shapiro } 320206f25ae9SGregory Neil Shapiro # endif /* SASL */ 320306f25ae9SGregory Neil Shapiro } 320406f25ae9SGregory Neil Shapiro 3205c2aa98e2SPeter Wemm 3206c2aa98e2SPeter Wemm do_transfer: 3207c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 3208c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 3209c2aa98e2SPeter Wemm 3210c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 3211c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 3212c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags)) 3213c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7; 3214c2aa98e2SPeter Wemm 3215c2aa98e2SPeter Wemm #if MIME7TO8 3216c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) && 3217c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) && 3218c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 321940266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 322040266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 3221c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 3222c2aa98e2SPeter Wemm { 3223c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 3224c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 322540266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 3226c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 3227c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8; 3228c2aa98e2SPeter Wemm } 322906f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 3230c2aa98e2SPeter Wemm 3231c2aa98e2SPeter Wemm if (tTd(11, 1)) 3232c2aa98e2SPeter Wemm { 323340266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 3234e92d3f3fSGregory Neil Shapiro mci_dump(sm_debug_file(), mci, false); 3235c2aa98e2SPeter Wemm } 3236c2aa98e2SPeter Wemm 323740266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE 323840266059SGregory Neil Shapiro /* 323940266059SGregory Neil Shapiro ** See if we know the maximum size and 324040266059SGregory Neil Shapiro ** abort if the message is too big. 324140266059SGregory Neil Shapiro ** 324240266059SGregory Neil Shapiro ** NOTE: _FFR_CLIENT_SIZE is untested. 324340266059SGregory Neil Shapiro */ 324440266059SGregory Neil Shapiro 324540266059SGregory Neil Shapiro if (bitset(MCIF_SIZE, mci->mci_flags) && 324640266059SGregory Neil Shapiro mci->mci_maxsize > 0 && 324740266059SGregory Neil Shapiro e->e_msgsize > mci->mci_maxsize) 324840266059SGregory Neil Shapiro { 324940266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 325040266059SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags)) 325140266059SGregory Neil Shapiro e->e_status = "5.2.3"; 325240266059SGregory Neil Shapiro else 325340266059SGregory Neil Shapiro e->e_status = "5.3.4"; 325440266059SGregory Neil Shapiro 325540266059SGregory Neil Shapiro usrerrenh(e->e_status, 325640266059SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 325740266059SGregory Neil Shapiro mci->mci_maxsize); 325840266059SGregory Neil Shapiro rcode = EX_DATAERR; 325940266059SGregory Neil Shapiro 326040266059SGregory Neil Shapiro /* Need an e_message for error */ 3261d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError), 326240266059SGregory Neil Shapiro "Message is too large; %ld bytes max", 326340266059SGregory Neil Shapiro mci->mci_maxsize); 326440266059SGregory Neil Shapiro goto give_up; 326540266059SGregory Neil Shapiro } 326640266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */ 326740266059SGregory Neil Shapiro 3268c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 3269c2aa98e2SPeter Wemm { 3270c2aa98e2SPeter Wemm /* couldn't open the mailer */ 3271c2aa98e2SPeter Wemm rcode = mci->mci_exitstat; 3272c2aa98e2SPeter Wemm errno = mci->mci_errno; 3273602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno); 3274c2aa98e2SPeter Wemm if (rcode == EX_OK) 3275c2aa98e2SPeter Wemm { 3276c2aa98e2SPeter Wemm /* shouldn't happen */ 327706f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 327840266059SGregory Neil Shapiro (unsigned long) mci, rcode, errno, 327940266059SGregory Neil Shapiro mci->mci_state, firstsig); 3280e92d3f3fSGregory Neil Shapiro mci_dump_all(smioout, true); 3281c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 3282c2aa98e2SPeter Wemm } 328306f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum) 3284c2aa98e2SPeter Wemm { 3285c2aa98e2SPeter Wemm /* try next MX site */ 3286c2aa98e2SPeter Wemm goto tryhost; 3287c2aa98e2SPeter Wemm } 3288c2aa98e2SPeter Wemm } 3289c2aa98e2SPeter Wemm else if (!clever) 3290c2aa98e2SPeter Wemm { 32914e4196cbSGregory Neil Shapiro bool ok; 32924e4196cbSGregory Neil Shapiro 3293c2aa98e2SPeter Wemm /* 3294c2aa98e2SPeter Wemm ** Format and send message. 3295c2aa98e2SPeter Wemm */ 3296c2aa98e2SPeter Wemm 32974e4196cbSGregory Neil Shapiro rcode = EX_OK; 32984e4196cbSGregory Neil Shapiro errno = 0; 32994e4196cbSGregory Neil Shapiro ok = putfromline(mci, e); 33004e4196cbSGregory Neil Shapiro if (ok) 33014e4196cbSGregory Neil Shapiro ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 33024e4196cbSGregory Neil Shapiro if (ok) 33034e4196cbSGregory Neil Shapiro ok = (*e->e_putbody)(mci, e, NULL); 3304ffb83623SGregory Neil Shapiro if (ok && bitset(MCIF_INLONGLINE, mci->mci_flags)) 3305ffb83623SGregory Neil Shapiro ok = putline("", mci); 3306c2aa98e2SPeter Wemm 33074e4196cbSGregory Neil Shapiro /* 33084e4196cbSGregory Neil Shapiro ** Ignore an I/O error that was caused by EPIPE. 33094e4196cbSGregory Neil Shapiro ** Some broken mailers don't read the entire body 33104e4196cbSGregory Neil Shapiro ** but just exit() thus causing an I/O error. 33114e4196cbSGregory Neil Shapiro */ 33124e4196cbSGregory Neil Shapiro 33134e4196cbSGregory Neil Shapiro if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE)) 33144e4196cbSGregory Neil Shapiro ok = true; 33154e4196cbSGregory Neil Shapiro 33164e4196cbSGregory Neil Shapiro /* (always) get the exit status */ 3317c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv); 33184e4196cbSGregory Neil Shapiro if (!ok) 33194e4196cbSGregory Neil Shapiro rcode = EX_TEMPFAIL; 332040266059SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 3321602a2b1bSGregory Neil Shapiro { 3322602a2b1bSGregory Neil Shapiro /* 3323602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display. 3324602a2b1bSGregory Neil Shapiro ** We set SmtpError as 3325602a2b1bSGregory Neil Shapiro */ 3326602a2b1bSGregory Neil Shapiro 3327d0cef73dSGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof(SmtpError), 3328602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL", 3329602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer); 3330602a2b1bSGregory Neil Shapiro } 3331c2aa98e2SPeter Wemm } 3332c2aa98e2SPeter Wemm else 3333c2aa98e2SPeter Wemm { 3334c2aa98e2SPeter Wemm /* 3335c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol 3336c2aa98e2SPeter Wemm */ 3337c2aa98e2SPeter Wemm 333840266059SGregory Neil Shapiro /* XXX this isn't pipelined... */ 3339c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e); 3340c2aa98e2SPeter Wemm if (rcode == EX_OK) 3341c2aa98e2SPeter Wemm { 3342c2aa98e2SPeter Wemm register int i; 334340266059SGregory Neil Shapiro # if PIPELINING 334440266059SGregory Neil Shapiro ADDRESS *volatile pchain; 334540266059SGregory Neil Shapiro # endif /* PIPELINING */ 3346c2aa98e2SPeter Wemm 3347c2aa98e2SPeter Wemm /* send the recipient list */ 3348c2aa98e2SPeter Wemm tobuf[0] = '\0'; 334940266059SGregory Neil Shapiro mci->mci_retryrcpt = false; 335040266059SGregory Neil Shapiro mci->mci_tolist = tobuf; 335140266059SGregory Neil Shapiro # if PIPELINING 335240266059SGregory Neil Shapiro pchain = NULL; 335340266059SGregory Neil Shapiro mci->mci_nextaddr = NULL; 335440266059SGregory Neil Shapiro # endif /* PIPELINING */ 335506f25ae9SGregory Neil Shapiro 3356c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3357c2aa98e2SPeter Wemm { 335840266059SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state)) 3359c2aa98e2SPeter Wemm continue; 336006f25ae9SGregory Neil Shapiro 336140266059SGregory Neil Shapiro /* mark recipient state as "ok so far" */ 336240266059SGregory Neil Shapiro to->q_state = QS_OK; 336340266059SGregory Neil Shapiro e->e_to = to->q_paddr; 336406f25ae9SGregory Neil Shapiro # if STARTTLS 336506f25ae9SGregory Neil Shapiro i = rscheck("tls_rcpt", to->q_user, NULL, e, 3366959366dcSGregory Neil Shapiro RSF_RMCOMM|RSF_COUNT, 3, 3367d0cef73dSGregory Neil Shapiro mci->mci_host, e->e_id, NULL); 336806f25ae9SGregory Neil Shapiro if (i != EX_OK) 3369c2aa98e2SPeter Wemm { 337040266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 337140266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 337240266059SGregory Neil Shapiro ctladdr, xstart, e, to); 337340266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 337440266059SGregory Neil Shapiro { 337540266059SGregory Neil Shapiro mci->mci_retryrcpt = true; 337640266059SGregory Neil Shapiro to->q_state = QS_RETRY; 337740266059SGregory Neil Shapiro } 337806f25ae9SGregory Neil Shapiro continue; 337906f25ae9SGregory Neil Shapiro } 338006f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 338106f25ae9SGregory Neil Shapiro 338240266059SGregory Neil Shapiro i = smtprcpt(to, m, mci, e, ctladdr, xstart); 338340266059SGregory Neil Shapiro # if PIPELINING 338440266059SGregory Neil Shapiro if (i == EX_OK && 338540266059SGregory Neil Shapiro bitset(MCIF_PIPELINED, mci->mci_flags)) 338606f25ae9SGregory Neil Shapiro { 338740266059SGregory Neil Shapiro /* 338840266059SGregory Neil Shapiro ** Add new element to list of 338940266059SGregory Neil Shapiro ** recipients for pipelining. 339040266059SGregory Neil Shapiro */ 339140266059SGregory Neil Shapiro 339240266059SGregory Neil Shapiro to->q_pchain = NULL; 339340266059SGregory Neil Shapiro if (mci->mci_nextaddr == NULL) 339440266059SGregory Neil Shapiro mci->mci_nextaddr = to; 339540266059SGregory Neil Shapiro if (pchain == NULL) 339640266059SGregory Neil Shapiro pchain = to; 3397c2aa98e2SPeter Wemm else 3398c2aa98e2SPeter Wemm { 339940266059SGregory Neil Shapiro pchain->q_pchain = to; 340040266059SGregory Neil Shapiro pchain = pchain->q_pchain; 340140266059SGregory Neil Shapiro } 340240266059SGregory Neil Shapiro } 340340266059SGregory Neil Shapiro # endif /* PIPELINING */ 340440266059SGregory Neil Shapiro if (i != EX_OK) 340540266059SGregory Neil Shapiro { 340640266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 340740266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 340840266059SGregory Neil Shapiro ctladdr, xstart, e, to); 340940266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 341040266059SGregory Neil Shapiro to->q_state = QS_RETRY; 3411c2aa98e2SPeter Wemm } 3412c2aa98e2SPeter Wemm } 3413c2aa98e2SPeter Wemm 341440266059SGregory Neil Shapiro /* No recipients in list and no missing responses? */ 341540266059SGregory Neil Shapiro if (tobuf[0] == '\0' 341640266059SGregory Neil Shapiro # if PIPELINING 3417ffb83623SGregory Neil Shapiro && bitset(MCIF_PIPELINED, mci->mci_flags) 341840266059SGregory Neil Shapiro && mci->mci_nextaddr == NULL 341940266059SGregory Neil Shapiro # endif /* PIPELINING */ 342040266059SGregory Neil Shapiro ) 3421c2aa98e2SPeter Wemm { 3422c2aa98e2SPeter Wemm rcode = EX_OK; 3423c2aa98e2SPeter Wemm e->e_to = NULL; 3424c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 3425c2aa98e2SPeter Wemm smtprset(m, mci, e); 3426c2aa98e2SPeter Wemm } 3427c2aa98e2SPeter Wemm else 3428c2aa98e2SPeter Wemm { 3429c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 343040266059SGregory Neil Shapiro rcode = smtpdata(m, mci, e, ctladdr, xstart); 3431c2aa98e2SPeter Wemm } 3432c2aa98e2SPeter Wemm } 343306f25ae9SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 3434c2aa98e2SPeter Wemm { 3435c2aa98e2SPeter Wemm /* try next MX site */ 3436c2aa98e2SPeter Wemm goto tryhost; 3437c2aa98e2SPeter Wemm } 3438c2aa98e2SPeter Wemm } 3439c2aa98e2SPeter Wemm #if NAMED_BIND 3440c2aa98e2SPeter Wemm if (ConfigLevel < 2) 3441c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 344206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3443c2aa98e2SPeter Wemm 3444c2aa98e2SPeter Wemm if (tTd(62, 1)) 3445c2aa98e2SPeter Wemm checkfds("after delivery"); 3446c2aa98e2SPeter Wemm 3447c2aa98e2SPeter Wemm /* 3448c2aa98e2SPeter Wemm ** Do final status disposal. 3449c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case. 3450c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the 3451c2aa98e2SPeter Wemm ** addressees. 3452c2aa98e2SPeter Wemm */ 3453c2aa98e2SPeter Wemm 3454c2aa98e2SPeter Wemm give_up: 3455c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3456c2aa98e2SPeter Wemm { 3457c2aa98e2SPeter Wemm lmtp_rcode = rcode; 3458c2aa98e2SPeter Wemm tobuf[0] = '\0'; 345940266059SGregory Neil Shapiro anyok = false; 346040266059SGregory Neil Shapiro strsize = 0; 3461c2aa98e2SPeter Wemm } 3462c2aa98e2SPeter Wemm else 3463c2aa98e2SPeter Wemm anyok = rcode == EX_OK; 3464c2aa98e2SPeter Wemm 3465c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3466c2aa98e2SPeter Wemm { 3467c2aa98e2SPeter Wemm /* see if address already marked */ 346806f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 3469c2aa98e2SPeter Wemm continue; 3470c2aa98e2SPeter Wemm 3471c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */ 3472c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3473c2aa98e2SPeter Wemm { 3474c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK) 3475c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e); 3476c2aa98e2SPeter Wemm if (rcode == EX_OK) 3477c2aa98e2SPeter Wemm { 347840266059SGregory Neil Shapiro strsize += sm_strlcat2(tobuf + strsize, ",", 347940266059SGregory Neil Shapiro to->q_paddr, 348040266059SGregory Neil Shapiro tobufsize - strsize); 348140266059SGregory Neil Shapiro SM_ASSERT(strsize < tobufsize); 348240266059SGregory Neil Shapiro anyok = true; 3483c2aa98e2SPeter Wemm } 3484c2aa98e2SPeter Wemm else 3485c2aa98e2SPeter Wemm { 3486c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 348740266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 348806f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci, 348940266059SGregory Neil Shapiro ctladdr, xstart, e, to); 3490c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 3491c2aa98e2SPeter Wemm continue; 3492c2aa98e2SPeter Wemm } 3493c2aa98e2SPeter Wemm } 3494c2aa98e2SPeter Wemm else 3495c2aa98e2SPeter Wemm { 3496c2aa98e2SPeter Wemm /* mark bad addresses */ 3497c2aa98e2SPeter Wemm if (rcode != EX_OK) 3498c2aa98e2SPeter Wemm { 3499c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST) 3500c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL; 350140266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 3502c2aa98e2SPeter Wemm continue; 3503c2aa98e2SPeter Wemm } 3504c2aa98e2SPeter Wemm } 3505c2aa98e2SPeter Wemm 3506c2aa98e2SPeter Wemm /* successful delivery */ 350706f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 3508c2aa98e2SPeter Wemm to->q_statdate = curtime(); 3509c2aa98e2SPeter Wemm e->e_nsent++; 351006f25ae9SGregory Neil Shapiro 351106f25ae9SGregory Neil Shapiro /* 351206f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses 351306f25ae9SGregory Neil Shapiro */ 351406f25ae9SGregory Neil Shapiro 351542e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 351606f25ae9SGregory Neil Shapiro { 351740266059SGregory Neil Shapiro queueup(e, false, false); 351806f25ae9SGregory Neil Shapiro e->e_nsent = 0; 351906f25ae9SGregory Neil Shapiro } 352006f25ae9SGregory Neil Shapiro 3521c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 3522c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 3523c2aa98e2SPeter Wemm { 3524c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 3525c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 352640266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 352740266059SGregory Neil Shapiro "%s... Successfully delivered\n", 3528c2aa98e2SPeter Wemm to->q_paddr); 3529c2aa98e2SPeter Wemm } 3530c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) && 3531c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) && 3532c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags)) 3533c2aa98e2SPeter Wemm { 3534c2aa98e2SPeter Wemm to->q_flags |= QRELAYED; 353540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 353640266059SGregory Neil Shapiro "%s... relayed; expect no further notifications\n", 353740266059SGregory Neil Shapiro to->q_paddr); 353840266059SGregory Neil Shapiro } 353940266059SGregory Neil Shapiro else if (IS_DLVR_NOTIFY(e) && 354040266059SGregory Neil Shapiro !bitset(MCIF_DLVR_BY, mci->mci_flags) && 354140266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags) && 354240266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 354340266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 354440266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 354540266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags))) 354640266059SGregory Neil Shapiro { 354740266059SGregory Neil Shapiro /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 354840266059SGregory Neil Shapiro to->q_flags |= QBYNRELAY; 354940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 355040266059SGregory Neil Shapiro "%s... Deliver-by notify: relayed\n", 355140266059SGregory Neil Shapiro to->q_paddr); 355240266059SGregory Neil Shapiro } 355340266059SGregory Neil Shapiro else if (IS_DLVR_TRACE(e) && 355440266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 355540266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 355640266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 355740266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)) && 355840266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags)) 355940266059SGregory Neil Shapiro { 356040266059SGregory Neil Shapiro /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 356140266059SGregory Neil Shapiro to->q_flags |= QBYTRACE; 356240266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 356340266059SGregory Neil Shapiro "%s... Deliver-By trace: relayed\n", 3564c2aa98e2SPeter Wemm to->q_paddr); 3565c2aa98e2SPeter Wemm } 3566c2aa98e2SPeter Wemm } 3567c2aa98e2SPeter Wemm 3568c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3569c2aa98e2SPeter Wemm { 3570c2aa98e2SPeter Wemm /* 3571c2aa98e2SPeter Wemm ** Global information applies to the last recipient only; 3572c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors. 3573c2aa98e2SPeter Wemm */ 3574c2aa98e2SPeter Wemm 3575c2aa98e2SPeter Wemm rcode = EX_OK; 3576c2aa98e2SPeter Wemm e->e_statmsg = NULL; 3577c2aa98e2SPeter Wemm 3578c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */ 357940266059SGregory Neil Shapiro if (mci != NULL && 358040266059SGregory Neil Shapiro (mci->mci_state == MCIS_MAIL || 358140266059SGregory Neil Shapiro mci->mci_state == MCIS_RCPT || 358240266059SGregory Neil Shapiro mci->mci_state == MCIS_DATA)) 3583323f6dcbSGregory Neil Shapiro { 3584c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 3585323f6dcbSGregory Neil Shapiro SmtpPhase = mci->mci_phase = "idle"; 3586323f6dcbSGregory Neil Shapiro sm_setproctitle(true, e, "%s: %s", CurHostName, 3587323f6dcbSGregory Neil Shapiro mci->mci_phase); 3588323f6dcbSGregory Neil Shapiro } 3589c2aa98e2SPeter Wemm } 3590c2aa98e2SPeter Wemm 3591c2aa98e2SPeter Wemm if (tobuf[0] != '\0') 359240266059SGregory Neil Shapiro { 359340266059SGregory Neil Shapiro giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); 359440266059SGregory Neil Shapiro #if 0 359540266059SGregory Neil Shapiro /* 359640266059SGregory Neil Shapiro ** This code is disabled for now because I am not 359740266059SGregory Neil Shapiro ** sure that copying status from the first recipient 359840266059SGregory Neil Shapiro ** to all non-status'ed recipients is a good idea. 359940266059SGregory Neil Shapiro */ 360040266059SGregory Neil Shapiro 360140266059SGregory Neil Shapiro if (tochain->q_message != NULL && 360240266059SGregory Neil Shapiro !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 360340266059SGregory Neil Shapiro { 360440266059SGregory Neil Shapiro for (to = tochain->q_tchain; to != NULL; 360540266059SGregory Neil Shapiro to = to->q_tchain) 360640266059SGregory Neil Shapiro { 360740266059SGregory Neil Shapiro /* see if address already marked */ 360840266059SGregory Neil Shapiro if (QS_IS_QUEUEUP(to->q_state) && 360940266059SGregory Neil Shapiro to->q_message == NULL) 361040266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 361140266059SGregory Neil Shapiro tochain->q_message); 361240266059SGregory Neil Shapiro } 361340266059SGregory Neil Shapiro } 361440266059SGregory Neil Shapiro #endif /* 0 */ 361540266059SGregory Neil Shapiro } 3616c2aa98e2SPeter Wemm if (anyok) 361740266059SGregory Neil Shapiro markstats(e, tochain, STATS_NORMAL); 3618c2aa98e2SPeter Wemm mci_store_persistent(mci); 3619c2aa98e2SPeter Wemm 362040266059SGregory Neil Shapiro /* Some recipients were tempfailed, try them on the next host */ 362140266059SGregory Neil Shapiro if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 362240266059SGregory Neil Shapiro { 362340266059SGregory Neil Shapiro /* try next MX site */ 362440266059SGregory Neil Shapiro goto tryhost; 362540266059SGregory Neil Shapiro } 362640266059SGregory Neil Shapiro 3627c2aa98e2SPeter Wemm /* now close the connection */ 3628c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 3629c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags)) 3630c2aa98e2SPeter Wemm smtpquit(m, mci, e); 3631c2aa98e2SPeter Wemm 363240266059SGregory Neil Shapiro cleanup: ; 363340266059SGregory Neil Shapiro } 363440266059SGregory Neil Shapiro SM_FINALLY 363540266059SGregory Neil Shapiro { 3636c2aa98e2SPeter Wemm /* 3637c2aa98e2SPeter Wemm ** Restore state and return. 3638c2aa98e2SPeter Wemm */ 3639c2aa98e2SPeter Wemm #if XDEBUG 3640c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 3641c2aa98e2SPeter Wemm 3642c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 3643d0cef73dSGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof(wbuf), 364440266059SGregory Neil Shapiro "%s... end of deliver(%s)", 3645c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST" 364640266059SGregory Neil Shapiro : shortenstring(e->e_to, 364740266059SGregory Neil Shapiro MAXSHORTSTR), 3648c2aa98e2SPeter Wemm m->m_name); 3649c2aa98e2SPeter Wemm checkfd012(wbuf); 365006f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 3651c2aa98e2SPeter Wemm 3652c2aa98e2SPeter Wemm errno = 0; 365340266059SGregory Neil Shapiro 365440266059SGregory Neil Shapiro /* 365540266059SGregory Neil Shapiro ** It was originally necessary to set macro 'g' to NULL 365640266059SGregory Neil Shapiro ** because it previously pointed to an auto buffer. 365740266059SGregory Neil Shapiro ** We don't do this any more, so this may be unnecessary. 365840266059SGregory Neil Shapiro */ 365940266059SGregory Neil Shapiro 366040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 366106f25ae9SGregory Neil Shapiro e->e_to = NULL; 366240266059SGregory Neil Shapiro } 366340266059SGregory Neil Shapiro SM_END_TRY 366406f25ae9SGregory Neil Shapiro return rcode; 3665c2aa98e2SPeter Wemm } 366606f25ae9SGregory Neil Shapiro 366740266059SGregory Neil Shapiro /* 3668c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address. 3669c2aa98e2SPeter Wemm ** 3670c2aa98e2SPeter Wemm ** Parameters: 3671c2aa98e2SPeter Wemm ** e -- the envelope we are sending. 3672c2aa98e2SPeter Wemm ** q -- the address to mark. 3673c2aa98e2SPeter Wemm ** mci -- mailer connection information. 3674c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure. 367506f25ae9SGregory Neil Shapiro ** ovr -- override an existing code? 3676c2aa98e2SPeter Wemm ** 3677c2aa98e2SPeter Wemm ** Returns: 3678c2aa98e2SPeter Wemm ** none. 3679c2aa98e2SPeter Wemm ** 3680c2aa98e2SPeter Wemm ** Side Effects: 3681c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the 3682c2aa98e2SPeter Wemm ** failure so that an error will be returned or 3683c2aa98e2SPeter Wemm ** the message will be queued, as appropriate. 3684c2aa98e2SPeter Wemm */ 3685c2aa98e2SPeter Wemm 368640266059SGregory Neil Shapiro void 368706f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr) 3688c2aa98e2SPeter Wemm register ENVELOPE *e; 3689c2aa98e2SPeter Wemm register ADDRESS *q; 3690c2aa98e2SPeter Wemm register MCI *mci; 3691c2aa98e2SPeter Wemm int rcode; 369206f25ae9SGregory Neil Shapiro bool ovr; 3693c2aa98e2SPeter Wemm { 369440266059SGregory Neil Shapiro int save_errno = errno; 369506f25ae9SGregory Neil Shapiro char *status = NULL; 369606f25ae9SGregory Neil Shapiro char *rstatus = NULL; 3697c2aa98e2SPeter Wemm 3698c2aa98e2SPeter Wemm switch (rcode) 3699c2aa98e2SPeter Wemm { 3700c2aa98e2SPeter Wemm case EX_OK: 3701c2aa98e2SPeter Wemm break; 3702c2aa98e2SPeter Wemm 3703c2aa98e2SPeter Wemm case EX_TEMPFAIL: 3704c2aa98e2SPeter Wemm case EX_IOERR: 3705c2aa98e2SPeter Wemm case EX_OSERR: 370606f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 3707c2aa98e2SPeter Wemm break; 3708c2aa98e2SPeter Wemm 3709c2aa98e2SPeter Wemm default: 371006f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 3711c2aa98e2SPeter Wemm break; 3712c2aa98e2SPeter Wemm } 3713c2aa98e2SPeter Wemm 3714c2aa98e2SPeter Wemm /* find most specific error code possible */ 3715c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL) 3716c2aa98e2SPeter Wemm { 371740266059SGregory Neil Shapiro status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 3718c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 371940266059SGregory Neil Shapiro rstatus = sm_rpool_strdup_x(e->e_rpool, 372040266059SGregory Neil Shapiro mci->mci_rstatus); 3721c2aa98e2SPeter Wemm else 372206f25ae9SGregory Neil Shapiro rstatus = NULL; 3723c2aa98e2SPeter Wemm } 3724c2aa98e2SPeter Wemm else if (e->e_status != NULL) 3725c2aa98e2SPeter Wemm { 372606f25ae9SGregory Neil Shapiro status = e->e_status; 372706f25ae9SGregory Neil Shapiro rstatus = NULL; 3728c2aa98e2SPeter Wemm } 3729c2aa98e2SPeter Wemm else 3730c2aa98e2SPeter Wemm { 3731c2aa98e2SPeter Wemm switch (rcode) 3732c2aa98e2SPeter Wemm { 3733c2aa98e2SPeter Wemm case EX_USAGE: 373406f25ae9SGregory Neil Shapiro status = "5.5.4"; 3735c2aa98e2SPeter Wemm break; 3736c2aa98e2SPeter Wemm 3737c2aa98e2SPeter Wemm case EX_DATAERR: 373806f25ae9SGregory Neil Shapiro status = "5.5.2"; 3739c2aa98e2SPeter Wemm break; 3740c2aa98e2SPeter Wemm 3741c2aa98e2SPeter Wemm case EX_NOUSER: 374206f25ae9SGregory Neil Shapiro status = "5.1.1"; 3743c2aa98e2SPeter Wemm break; 3744c2aa98e2SPeter Wemm 3745c2aa98e2SPeter Wemm case EX_NOHOST: 374606f25ae9SGregory Neil Shapiro status = "5.1.2"; 3747c2aa98e2SPeter Wemm break; 3748c2aa98e2SPeter Wemm 3749c2aa98e2SPeter Wemm case EX_NOINPUT: 3750c2aa98e2SPeter Wemm case EX_CANTCREAT: 3751c2aa98e2SPeter Wemm case EX_NOPERM: 375206f25ae9SGregory Neil Shapiro status = "5.3.0"; 3753c2aa98e2SPeter Wemm break; 3754c2aa98e2SPeter Wemm 3755c2aa98e2SPeter Wemm case EX_UNAVAILABLE: 3756c2aa98e2SPeter Wemm case EX_SOFTWARE: 3757c2aa98e2SPeter Wemm case EX_OSFILE: 3758c2aa98e2SPeter Wemm case EX_PROTOCOL: 3759c2aa98e2SPeter Wemm case EX_CONFIG: 376006f25ae9SGregory Neil Shapiro status = "5.5.0"; 3761c2aa98e2SPeter Wemm break; 3762c2aa98e2SPeter Wemm 3763c2aa98e2SPeter Wemm case EX_OSERR: 3764c2aa98e2SPeter Wemm case EX_IOERR: 376506f25ae9SGregory Neil Shapiro status = "4.5.0"; 3766c2aa98e2SPeter Wemm break; 3767c2aa98e2SPeter Wemm 3768c2aa98e2SPeter Wemm case EX_TEMPFAIL: 376906f25ae9SGregory Neil Shapiro status = "4.2.0"; 3770c2aa98e2SPeter Wemm break; 3771c2aa98e2SPeter Wemm } 3772c2aa98e2SPeter Wemm } 3773c2aa98e2SPeter Wemm 377406f25ae9SGregory Neil Shapiro /* new status? */ 377506f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 377606f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status)) 377706f25ae9SGregory Neil Shapiro { 377806f25ae9SGregory Neil Shapiro q->q_status = status; 377906f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus; 378006f25ae9SGregory Neil Shapiro } 3781c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL && 3782c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 378340266059SGregory Neil Shapiro sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 3784c2aa98e2SPeter Wemm { 378506f25ae9SGregory Neil Shapiro char buf[16]; 3786c2aa98e2SPeter Wemm 3787d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", rcode); 378840266059SGregory Neil Shapiro q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 3789c2aa98e2SPeter Wemm } 379006f25ae9SGregory Neil Shapiro 379106f25ae9SGregory Neil Shapiro q->q_statdate = curtime(); 379206f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' && 379306f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 379440266059SGregory Neil Shapiro q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 379540266059SGregory Neil Shapiro 379640266059SGregory Neil Shapiro /* restore errno */ 379740266059SGregory Neil Shapiro errno = save_errno; 3798c2aa98e2SPeter Wemm } 379940266059SGregory Neil Shapiro /* 3800c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate. 3801c2aa98e2SPeter Wemm ** 3802c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation 3803c2aa98e2SPeter Wemm ** violation), so we report those specially. For other 3804c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg), 3805c2aa98e2SPeter Wemm ** and if it represents an error, we print it. 3806c2aa98e2SPeter Wemm ** 3807c2aa98e2SPeter Wemm ** Parameters: 380813058a91SGregory Neil Shapiro ** mci -- the mailer connection info. 3809c2aa98e2SPeter Wemm ** e -- the current envelope. 3810c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer 3811c2aa98e2SPeter Wemm ** (for error messages). 3812c2aa98e2SPeter Wemm ** 3813c2aa98e2SPeter Wemm ** Returns: 3814c2aa98e2SPeter Wemm ** exit code of mailer. 3815c2aa98e2SPeter Wemm ** 3816c2aa98e2SPeter Wemm ** Side Effects: 3817c2aa98e2SPeter Wemm ** none. 3818c2aa98e2SPeter Wemm */ 3819c2aa98e2SPeter Wemm 382006f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout; 382106f25ae9SGregory Neil Shapiro 382206f25ae9SGregory Neil Shapiro static void 3823b6bacd31SGregory Neil Shapiro endwaittimeout(ignore) 3824b6bacd31SGregory Neil Shapiro int ignore; 382506f25ae9SGregory Neil Shapiro { 38268774250cSGregory Neil Shapiro /* 38278774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 38288774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 38298774250cSGregory Neil Shapiro ** DOING. 38308774250cSGregory Neil Shapiro */ 38318774250cSGregory Neil Shapiro 383206f25ae9SGregory Neil Shapiro errno = ETIMEDOUT; 383306f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1); 383406f25ae9SGregory Neil Shapiro } 383506f25ae9SGregory Neil Shapiro 3836c2aa98e2SPeter Wemm int 3837c2aa98e2SPeter Wemm endmailer(mci, e, pv) 3838c2aa98e2SPeter Wemm register MCI *mci; 3839c2aa98e2SPeter Wemm register ENVELOPE *e; 3840c2aa98e2SPeter Wemm char **pv; 3841c2aa98e2SPeter Wemm { 3842c2aa98e2SPeter Wemm int st; 384306f25ae9SGregory Neil Shapiro int save_errno = errno; 384406f25ae9SGregory Neil Shapiro char buf[MAXLINE]; 384540266059SGregory Neil Shapiro SM_EVENT *ev = NULL; 384606f25ae9SGregory Neil Shapiro 3847c2aa98e2SPeter Wemm 3848c2aa98e2SPeter Wemm mci_unlock_host(mci); 3849c2aa98e2SPeter Wemm 38508774250cSGregory Neil Shapiro /* close output to mailer */ 38518774250cSGregory Neil Shapiro if (mci->mci_out != NULL) 3852b6bacd31SGregory Neil Shapiro { 385340266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 3854b6bacd31SGregory Neil Shapiro mci->mci_out = NULL; 3855b6bacd31SGregory Neil Shapiro } 38568774250cSGregory Neil Shapiro 38578774250cSGregory Neil Shapiro /* copy any remaining input to transcript */ 38588774250cSGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 38598774250cSGregory Neil Shapiro e->e_xfp != NULL) 38608774250cSGregory Neil Shapiro { 3861d0cef73dSGregory Neil Shapiro while (sfgets(buf, sizeof(buf), mci->mci_in, 38628774250cSGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL) 386340266059SGregory Neil Shapiro (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 38648774250cSGregory Neil Shapiro } 38658774250cSGregory Neil Shapiro 386606f25ae9SGregory Neil Shapiro #if SASL 386740266059SGregory Neil Shapiro /* close SASL connection */ 386806f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 386906f25ae9SGregory Neil Shapiro { 387006f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 387106f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT; 387206f25ae9SGregory Neil Shapiro } 387306f25ae9SGregory Neil Shapiro #endif /* SASL */ 387406f25ae9SGregory Neil Shapiro 387506f25ae9SGregory Neil Shapiro #if STARTTLS 387606f25ae9SGregory Neil Shapiro /* shutdown TLS */ 387706f25ae9SGregory Neil Shapiro (void) endtlsclt(mci); 387806f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 387906f25ae9SGregory Neil Shapiro 388006f25ae9SGregory Neil Shapiro /* now close the input */ 388106f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 3882b6bacd31SGregory Neil Shapiro { 388340266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 3884b6bacd31SGregory Neil Shapiro mci->mci_in = NULL; 3885b6bacd31SGregory Neil Shapiro } 3886c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 3887c2aa98e2SPeter Wemm 388806f25ae9SGregory Neil Shapiro errno = save_errno; 388906f25ae9SGregory Neil Shapiro 3890c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */ 3891c2aa98e2SPeter Wemm if (mci->mci_pid == 0) 389206f25ae9SGregory Neil Shapiro return EX_OK; 3893c2aa98e2SPeter Wemm 389406f25ae9SGregory Neil Shapiro /* put a timeout around the wait */ 389506f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0) 389606f25ae9SGregory Neil Shapiro { 389706f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0) 389840266059SGregory Neil Shapiro ev = sm_setevent(mci->mci_mailer->m_wait, 389906f25ae9SGregory Neil Shapiro endwaittimeout, 0); 390006f25ae9SGregory Neil Shapiro else 390106f25ae9SGregory Neil Shapiro { 390242e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)", 390306f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, 390442e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait); 390506f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 390606f25ae9SGregory Neil Shapiro } 390706f25ae9SGregory Neil Shapiro } 3908c2aa98e2SPeter Wemm 390906f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */ 3910c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid); 391106f25ae9SGregory Neil Shapiro save_errno = errno; 391206f25ae9SGregory Neil Shapiro if (ev != NULL) 391340266059SGregory Neil Shapiro sm_clrevent(ev); 391406f25ae9SGregory Neil Shapiro errno = save_errno; 391506f25ae9SGregory Neil Shapiro 3916c2aa98e2SPeter Wemm if (st == -1) 3917c2aa98e2SPeter Wemm { 3918c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name); 391906f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 3920c2aa98e2SPeter Wemm } 3921c2aa98e2SPeter Wemm 3922c2aa98e2SPeter Wemm if (WIFEXITED(st)) 3923c2aa98e2SPeter Wemm { 3924c2aa98e2SPeter Wemm /* normal death -- return status */ 3925c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 3926c2aa98e2SPeter Wemm } 3927c2aa98e2SPeter Wemm 3928c2aa98e2SPeter Wemm /* it died a horrid death */ 392906f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s", 393006f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st), 393106f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" : 393206f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : "")); 3933c2aa98e2SPeter Wemm 3934c2aa98e2SPeter Wemm /* log the arguments */ 3935c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL) 3936c2aa98e2SPeter Wemm { 3937c2aa98e2SPeter Wemm register char **av; 3938c2aa98e2SPeter Wemm 393940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 3940c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 394140266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 394240266059SGregory Neil Shapiro *av); 394340266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 3944c2aa98e2SPeter Wemm } 3945c2aa98e2SPeter Wemm 3946c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL; 394706f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 3948c2aa98e2SPeter Wemm } 394940266059SGregory Neil Shapiro /* 3950c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer 3951c2aa98e2SPeter Wemm ** 3952c2aa98e2SPeter Wemm ** Parameters: 395306f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte 3954c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of 3955c2aa98e2SPeter Wemm ** already). 395606f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any. 3957c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer. 3958c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 3959c2aa98e2SPeter Wemm ** response is given before the connection is made. 3960c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient 3961c2aa98e2SPeter Wemm ** address(es). 3962c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing 3963c2aa98e2SPeter Wemm ** transaction delays. 3964c2aa98e2SPeter Wemm ** e -- the current envelope. 396540266059SGregory Neil Shapiro ** to -- the current recipient (NULL if none). 3966c2aa98e2SPeter Wemm ** 3967c2aa98e2SPeter Wemm ** Returns: 3968c2aa98e2SPeter Wemm ** none. 3969c2aa98e2SPeter Wemm ** 3970c2aa98e2SPeter Wemm ** Side Effects: 3971c2aa98e2SPeter Wemm ** Errors may be incremented. 3972c2aa98e2SPeter Wemm ** ExitStat may be set. 3973c2aa98e2SPeter Wemm */ 3974c2aa98e2SPeter Wemm 3975c2aa98e2SPeter Wemm void 397640266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 397706f25ae9SGregory Neil Shapiro int status; 397806f25ae9SGregory Neil Shapiro char *dsn; 3979c2aa98e2SPeter Wemm register MAILER *m; 3980c2aa98e2SPeter Wemm register MCI *mci; 3981c2aa98e2SPeter Wemm ADDRESS *ctladdr; 3982c2aa98e2SPeter Wemm time_t xstart; 3983c2aa98e2SPeter Wemm ENVELOPE *e; 398440266059SGregory Neil Shapiro ADDRESS *to; 3985c2aa98e2SPeter Wemm { 3986c2aa98e2SPeter Wemm register const char *statmsg; 398706f25ae9SGregory Neil Shapiro int errnum = errno; 398806f25ae9SGregory Neil Shapiro int off = 4; 398940266059SGregory Neil Shapiro bool usestat = false; 399006f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN]; 3991c2aa98e2SPeter Wemm char buf[MAXLINE]; 399240266059SGregory Neil Shapiro char *exmsg; 3993c2aa98e2SPeter Wemm 3994c2aa98e2SPeter Wemm if (e == NULL) 3995af9557fdSGregory Neil Shapiro { 3996c2aa98e2SPeter Wemm syserr("giveresponse: null envelope"); 3997af9557fdSGregory Neil Shapiro /* NOTREACHED */ 3998af9557fdSGregory Neil Shapiro SM_ASSERT(0); 3999af9557fdSGregory Neil Shapiro } 4000c2aa98e2SPeter Wemm 4001c2aa98e2SPeter Wemm /* 4002c2aa98e2SPeter Wemm ** Compute status message from code. 4003c2aa98e2SPeter Wemm */ 4004c2aa98e2SPeter Wemm 400540266059SGregory Neil Shapiro exmsg = sm_sysexmsg(status); 400606f25ae9SGregory Neil Shapiro if (status == 0) 4007c2aa98e2SPeter Wemm { 400806f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent"; 4009c2aa98e2SPeter Wemm if (e->e_statmsg != NULL) 4010c2aa98e2SPeter Wemm { 4011d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", 401206f25ae9SGregory Neil Shapiro statmsg, 401306f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 4014c2aa98e2SPeter Wemm statmsg = buf; 4015c2aa98e2SPeter Wemm } 4016c2aa98e2SPeter Wemm } 401740266059SGregory Neil Shapiro else if (exmsg == NULL) 4018c2aa98e2SPeter Wemm { 4019d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 402006f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d", 402106f25ae9SGregory Neil Shapiro status); 402206f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE; 4023c2aa98e2SPeter Wemm statmsg = buf; 402440266059SGregory Neil Shapiro usestat = true; 4025c2aa98e2SPeter Wemm } 402606f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL) 4027c2aa98e2SPeter Wemm { 4028c2aa98e2SPeter Wemm char *bp = buf; 4029c2aa98e2SPeter Wemm 403040266059SGregory Neil Shapiro (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 4031c2aa98e2SPeter Wemm bp += strlen(bp); 4032c2aa98e2SPeter Wemm #if NAMED_BIND 4033c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN) 403440266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 4035c2aa98e2SPeter Wemm else 403606f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 4037c2aa98e2SPeter Wemm { 403806f25ae9SGregory Neil Shapiro if (errnum != 0) 403940266059SGregory Neil Shapiro statmsg = sm_errstring(errnum); 4040c2aa98e2SPeter Wemm else 4041c2aa98e2SPeter Wemm statmsg = SmtpError; 4042c2aa98e2SPeter Wemm } 4043c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0') 404406f25ae9SGregory Neil Shapiro { 404506f25ae9SGregory Neil Shapiro switch (errnum) 404606f25ae9SGregory Neil Shapiro { 404706f25ae9SGregory Neil Shapiro #ifdef ENETDOWN 404806f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */ 404906f25ae9SGregory Neil Shapiro #endif /* ENETDOWN */ 405006f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH 405106f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */ 405206f25ae9SGregory Neil Shapiro #endif /* ENETUNREACH */ 405306f25ae9SGregory Neil Shapiro #ifdef ENETRESET 405406f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */ 405506f25ae9SGregory Neil Shapiro #endif /* ENETRESET */ 405606f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED 405706f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */ 405806f25ae9SGregory Neil Shapiro #endif /* ECONNABORTED */ 405906f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN 406006f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */ 406106f25ae9SGregory Neil Shapiro #endif /* EHOSTDOWN */ 406206f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH 406306f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */ 406406f25ae9SGregory Neil Shapiro #endif /* EHOSTUNREACH */ 4065b6bacd31SGregory Neil Shapiro if (mci != NULL && mci->mci_host != NULL) 406606f25ae9SGregory Neil Shapiro { 406740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, 406840266059SGregory Neil Shapiro SPACELEFT(buf, bp), 406940266059SGregory Neil Shapiro 2, ": ", 407040266059SGregory Neil Shapiro mci->mci_host); 407106f25ae9SGregory Neil Shapiro bp += strlen(bp); 407206f25ae9SGregory Neil Shapiro } 407306f25ae9SGregory Neil Shapiro break; 407406f25ae9SGregory Neil Shapiro } 407540266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 407640266059SGregory Neil Shapiro statmsg); 407740266059SGregory Neil Shapiro usestat = true; 407806f25ae9SGregory Neil Shapiro } 4079c2aa98e2SPeter Wemm statmsg = buf; 4080c2aa98e2SPeter Wemm } 4081c2aa98e2SPeter Wemm #if NAMED_BIND 408206f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0) 4083c2aa98e2SPeter Wemm { 408440266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 4085d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", exmsg + 1, 408640266059SGregory Neil Shapiro statmsg); 4087c2aa98e2SPeter Wemm statmsg = buf; 408840266059SGregory Neil Shapiro usestat = true; 4089c2aa98e2SPeter Wemm } 409006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 4091c2aa98e2SPeter Wemm else 4092c2aa98e2SPeter Wemm { 409340266059SGregory Neil Shapiro statmsg = exmsg; 409406f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0) 4095c2aa98e2SPeter Wemm { 4096d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s: %s", statmsg, 409740266059SGregory Neil Shapiro sm_errstring(errnum)); 4098c2aa98e2SPeter Wemm statmsg = buf; 409940266059SGregory Neil Shapiro usestat = true; 4100c2aa98e2SPeter Wemm } 4101605302a5SGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL) 4102605302a5SGregory Neil Shapiro { 4103d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%s (%s)", statmsg, 4104605302a5SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 4105605302a5SGregory Neil Shapiro statmsg = buf; 4106605302a5SGregory Neil Shapiro usestat = true; 4107605302a5SGregory Neil Shapiro } 4108c2aa98e2SPeter Wemm } 4109c2aa98e2SPeter Wemm 4110c2aa98e2SPeter Wemm /* 4111c2aa98e2SPeter Wemm ** Print the message as appropriate 4112c2aa98e2SPeter Wemm */ 4113c2aa98e2SPeter Wemm 411406f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL) 4115c2aa98e2SPeter Wemm { 4116c2aa98e2SPeter Wemm extern char MsgBuf[]; 4117c2aa98e2SPeter Wemm 411806f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0) 411906f25ae9SGregory Neil Shapiro { 412006f25ae9SGregory Neil Shapiro if (dsn == NULL) 412106f25ae9SGregory Neil Shapiro { 4122d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf), 412306f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 412406f25ae9SGregory Neil Shapiro dsn = dsnbuf; 412506f25ae9SGregory Neil Shapiro } 412606f25ae9SGregory Neil Shapiro off += 5; 412706f25ae9SGregory Neil Shapiro } 412806f25ae9SGregory Neil Shapiro else 412906f25ae9SGregory Neil Shapiro { 413006f25ae9SGregory Neil Shapiro off = 4; 413106f25ae9SGregory Neil Shapiro } 413206f25ae9SGregory Neil Shapiro message("%s", statmsg + off); 413306f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL) 413440266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 413540266059SGregory Neil Shapiro &MsgBuf[4]); 4136c2aa98e2SPeter Wemm } 4137c2aa98e2SPeter Wemm else 4138c2aa98e2SPeter Wemm { 413906f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4]; 4140c2aa98e2SPeter Wemm 4141c2aa98e2SPeter Wemm Errors++; 414206f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 4143d0cef73dSGregory Neil Shapiro off < sizeof(mbuf) - 4) 414406f25ae9SGregory Neil Shapiro { 414506f25ae9SGregory Neil Shapiro if (dsn == NULL) 414606f25ae9SGregory Neil Shapiro { 4147d0cef73dSGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof(dsnbuf), 414806f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 414906f25ae9SGregory Neil Shapiro dsn = dsnbuf; 415006f25ae9SGregory Neil Shapiro } 415106f25ae9SGregory Neil Shapiro off += 5; 415240266059SGregory Neil Shapiro 415340266059SGregory Neil Shapiro /* copy only part of statmsg to mbuf */ 415440266059SGregory Neil Shapiro (void) sm_strlcpy(mbuf, statmsg, off); 4155d0cef73dSGregory Neil Shapiro (void) sm_strlcat(mbuf, " %s", sizeof(mbuf)); 415606f25ae9SGregory Neil Shapiro } 415706f25ae9SGregory Neil Shapiro else 415806f25ae9SGregory Neil Shapiro { 415906f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0'; 4160d0cef73dSGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof(mbuf), "%.3s %%s", 416140266059SGregory Neil Shapiro statmsg); 416206f25ae9SGregory Neil Shapiro off = 4; 416306f25ae9SGregory Neil Shapiro } 416406f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]); 4165c2aa98e2SPeter Wemm } 4166c2aa98e2SPeter Wemm 4167c2aa98e2SPeter Wemm /* 4168c2aa98e2SPeter Wemm ** Final cleanup. 4169c2aa98e2SPeter Wemm ** Log a record of the transaction. Compute the new 4170c2aa98e2SPeter Wemm ** ExitStat -- if we already had an error, stick with 4171c2aa98e2SPeter Wemm ** that. 4172c2aa98e2SPeter Wemm */ 4173c2aa98e2SPeter Wemm 4174c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 417506f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 417606f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 4177c2aa98e2SPeter Wemm 4178c2aa98e2SPeter Wemm if (tTd(11, 2)) 417940266059SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 418006f25ae9SGregory Neil Shapiro status, 418106f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn, 418240266059SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message, 418340266059SGregory Neil Shapiro errnum); 4184c2aa98e2SPeter Wemm 418506f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL) 418606f25ae9SGregory Neil Shapiro setstat(status); 418706f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 418840266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 418940266059SGregory Neil Shapiro if (status != EX_OK && to != NULL && to->q_message == NULL) 4190c2aa98e2SPeter Wemm { 419140266059SGregory Neil Shapiro if (!usestat && e->e_message != NULL) 419240266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 419340266059SGregory Neil Shapiro e->e_message); 419440266059SGregory Neil Shapiro else 419540266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 419640266059SGregory Neil Shapiro statmsg + off); 4197c2aa98e2SPeter Wemm } 4198c2aa98e2SPeter Wemm errno = 0; 4199602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 4200c2aa98e2SPeter Wemm } 420140266059SGregory Neil Shapiro /* 4202c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log 4203c2aa98e2SPeter Wemm ** 4204c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because 4205c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core 4206c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical. 4207c2aa98e2SPeter Wemm ** 4208c2aa98e2SPeter Wemm ** Parameters: 4209c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue. 4210c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 421106f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active. 421206f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status. 421306f25ae9SGregory Neil Shapiro ** status -- the message to print for the status. 4214c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list. 4215c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for 4216c2aa98e2SPeter Wemm ** computing transaction delay. 4217c2aa98e2SPeter Wemm ** e -- the current envelope. 4218c2aa98e2SPeter Wemm ** 4219c2aa98e2SPeter Wemm ** Returns: 4220c2aa98e2SPeter Wemm ** none 4221c2aa98e2SPeter Wemm ** 4222c2aa98e2SPeter Wemm ** Side Effects: 4223c2aa98e2SPeter Wemm ** none 4224c2aa98e2SPeter Wemm */ 4225c2aa98e2SPeter Wemm 4226c2aa98e2SPeter Wemm void 422706f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 4228c2aa98e2SPeter Wemm MAILER *m; 4229c2aa98e2SPeter Wemm register MCI *mci; 423006f25ae9SGregory Neil Shapiro char *dsn; 423106f25ae9SGregory Neil Shapiro const char *status; 4232c2aa98e2SPeter Wemm ADDRESS *ctladdr; 4233c2aa98e2SPeter Wemm time_t xstart; 4234c2aa98e2SPeter Wemm register ENVELOPE *e; 4235c2aa98e2SPeter Wemm { 4236c2aa98e2SPeter Wemm register char *bp; 4237c2aa98e2SPeter Wemm register char *p; 4238c2aa98e2SPeter Wemm int l; 423940266059SGregory Neil Shapiro time_t now = curtime(); 4240c2aa98e2SPeter Wemm char buf[1024]; 4241c2aa98e2SPeter Wemm 4242c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 4243c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */ 4244c2aa98e2SPeter Wemm bp = buf; 4245c2aa98e2SPeter Wemm if (ctladdr != NULL) 4246c2aa98e2SPeter Wemm { 424740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 4248c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4249c2aa98e2SPeter Wemm bp += strlen(bp); 4250c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4251c2aa98e2SPeter Wemm { 425240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 425306f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid, 425406f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid); 4255c2aa98e2SPeter Wemm bp += strlen(bp); 4256c2aa98e2SPeter Wemm } 4257c2aa98e2SPeter Wemm } 4258c2aa98e2SPeter Wemm 4259c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */ 426040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 426140266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4262c2aa98e2SPeter Wemm bp += strlen(bp); 4263c2aa98e2SPeter Wemm 4264c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4265c2aa98e2SPeter Wemm { 426640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 426740266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4268c2aa98e2SPeter Wemm bp += strlen(bp); 4269c2aa98e2SPeter Wemm } 4270c2aa98e2SPeter Wemm 4271c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 4272c2aa98e2SPeter Wemm if (m != NULL) 4273c2aa98e2SPeter Wemm { 427440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 427540266059SGregory Neil Shapiro m->m_name); 4276c2aa98e2SPeter Wemm bp += strlen(bp); 4277c2aa98e2SPeter Wemm } 4278c2aa98e2SPeter Wemm 427906f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */ 428040266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 4281ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgpriority)); 428206f25ae9SGregory Neil Shapiro bp += strlen(bp); 428306f25ae9SGregory Neil Shapiro 4284c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */ 4285c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4286c2aa98e2SPeter Wemm { 4287c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4288c2aa98e2SPeter Wemm 428940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 4290c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40)); 4291c2aa98e2SPeter Wemm bp += strlen(bp); 4292c2aa98e2SPeter Wemm 4293c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 4294c2aa98e2SPeter Wemm { 429540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 4296c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4297c2aa98e2SPeter Wemm } 4298c2aa98e2SPeter Wemm } 429940266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 430040266059SGregory Neil Shapiro { 430140266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 430240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 430340266059SGregory Neil Shapiro ", quarantine=%s", 430440266059SGregory Neil Shapiro shortenstring(e->e_quarmsg, 40)); 430540266059SGregory Neil Shapiro } 430606f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4307c2aa98e2SPeter Wemm { 4308c2aa98e2SPeter Wemm p = macvalue('h', e); 4309c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4310c2aa98e2SPeter Wemm { 431140266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 431240266059SGregory Neil Shapiro ", relay=%s", shortenstring(p, 40)); 4313c2aa98e2SPeter Wemm } 4314c2aa98e2SPeter Wemm } 4315c2aa98e2SPeter Wemm bp += strlen(bp); 4316c2aa98e2SPeter Wemm 431706f25ae9SGregory Neil Shapiro /* dsn */ 431806f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0') 431906f25ae9SGregory Neil Shapiro { 432040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 432106f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN)); 432206f25ae9SGregory Neil Shapiro bp += strlen(bp); 432306f25ae9SGregory Neil Shapiro } 432406f25ae9SGregory Neil Shapiro 432513d88268SGregory Neil Shapiro #if _FFR_LOG_NTRIES 432613d88268SGregory Neil Shapiro /* ntries */ 432713d88268SGregory Neil Shapiro if (e->e_ntries >= 0) 432813d88268SGregory Neil Shapiro { 432913d88268SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 433013d88268SGregory Neil Shapiro ", ntries=%d", e->e_ntries + 1); 433113d88268SGregory Neil Shapiro bp += strlen(bp); 433213d88268SGregory Neil Shapiro } 433313d88268SGregory Neil Shapiro #endif /* _FFR_LOG_NTRIES */ 433413d88268SGregory Neil Shapiro 4335c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 4336c2aa98e2SPeter Wemm # if (STATLEN) < 63 4337c2aa98e2SPeter Wemm # undef STATLEN 4338c2aa98e2SPeter Wemm # define STATLEN 63 433906f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */ 4340c2aa98e2SPeter Wemm # if (STATLEN) > 203 4341c2aa98e2SPeter Wemm # undef STATLEN 4342c2aa98e2SPeter Wemm # define STATLEN 203 434306f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */ 4344c2aa98e2SPeter Wemm 4345c2aa98e2SPeter Wemm /* stat: max 210 bytes */ 4346d0cef73dSGregory Neil Shapiro if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20))) 4347c2aa98e2SPeter Wemm { 4348c2aa98e2SPeter Wemm /* desperation move -- truncate data */ 4349d0cef73dSGregory Neil Shapiro bp = buf + sizeof(buf) - ((STATLEN) + 17); 435040266059SGregory Neil Shapiro (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 4351c2aa98e2SPeter Wemm bp += 3; 4352c2aa98e2SPeter Wemm } 4353c2aa98e2SPeter Wemm 435440266059SGregory Neil Shapiro (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 4355c2aa98e2SPeter Wemm bp += strlen(bp); 4356c2aa98e2SPeter Wemm 435740266059SGregory Neil Shapiro (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 435840266059SGregory Neil Shapiro SPACELEFT(buf, bp)); 4359c2aa98e2SPeter Wemm 4360c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */ 4361c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf); 436240266059SGregory Neil Shapiro if (l < 0) 436340266059SGregory Neil Shapiro l = 0; 436406f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 436540266059SGregory Neil Shapiro while (strlen(p) >= l) 4366c2aa98e2SPeter Wemm { 436706f25ae9SGregory Neil Shapiro register char *q; 4368c2aa98e2SPeter Wemm 436906f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 437006f25ae9SGregory Neil Shapiro { 437106f25ae9SGregory Neil Shapiro if (*q == ',') 437206f25ae9SGregory Neil Shapiro break; 437306f25ae9SGregory Neil Shapiro } 437406f25ae9SGregory Neil Shapiro if (p == q) 437506f25ae9SGregory Neil Shapiro break; 437640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 437742e5d165SGregory Neil Shapiro (int) (++q - p), p, buf); 4378c2aa98e2SPeter Wemm p = q; 4379c2aa98e2SPeter Wemm } 438006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 4381c2aa98e2SPeter Wemm 438206f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 4383c2aa98e2SPeter Wemm 4384c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85; 438540266059SGregory Neil Shapiro if (l < 0) 438640266059SGregory Neil Shapiro l = 0; 438706f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 438840266059SGregory Neil Shapiro while (strlen(p) >= l) 4389c2aa98e2SPeter Wemm { 439006f25ae9SGregory Neil Shapiro register char *q; 4391c2aa98e2SPeter Wemm 439206f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 439306f25ae9SGregory Neil Shapiro { 439406f25ae9SGregory Neil Shapiro if (*q == ',') 439506f25ae9SGregory Neil Shapiro break; 439606f25ae9SGregory Neil Shapiro } 439706f25ae9SGregory Neil Shapiro if (p == q) 439806f25ae9SGregory Neil Shapiro break; 439906f25ae9SGregory Neil Shapiro 440040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 440142e5d165SGregory Neil Shapiro (int) (++q - p), p); 4402c2aa98e2SPeter Wemm p = q; 4403c2aa98e2SPeter Wemm } 440406f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 4405c2aa98e2SPeter Wemm 4406c2aa98e2SPeter Wemm if (ctladdr != NULL) 4407c2aa98e2SPeter Wemm { 4408c2aa98e2SPeter Wemm bp = buf; 440940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 4410c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4411c2aa98e2SPeter Wemm bp += strlen(bp); 4412c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4413c2aa98e2SPeter Wemm { 441440266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 4415c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid); 4416c2aa98e2SPeter Wemm bp += strlen(bp); 4417c2aa98e2SPeter Wemm } 4418c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf); 4419c2aa98e2SPeter Wemm } 4420c2aa98e2SPeter Wemm bp = buf; 442140266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 442240266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4423c2aa98e2SPeter Wemm bp += strlen(bp); 4424c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4425c2aa98e2SPeter Wemm { 442640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 442740266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4428c2aa98e2SPeter Wemm bp += strlen(bp); 4429c2aa98e2SPeter Wemm } 4430c2aa98e2SPeter Wemm 4431c2aa98e2SPeter Wemm if (m != NULL) 4432c2aa98e2SPeter Wemm { 443340266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 443440266059SGregory Neil Shapiro m->m_name); 4435c2aa98e2SPeter Wemm bp += strlen(bp); 4436c2aa98e2SPeter Wemm } 4437c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4438c2aa98e2SPeter Wemm 4439c2aa98e2SPeter Wemm buf[0] = '\0'; 4440c2aa98e2SPeter Wemm bp = buf; 4441c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4442c2aa98e2SPeter Wemm { 4443c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4444c2aa98e2SPeter Wemm 444540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 444640266059SGregory Neil Shapiro mci->mci_host); 4447c2aa98e2SPeter Wemm bp += strlen(bp); 4448c2aa98e2SPeter Wemm 4449c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 445040266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 445140266059SGregory Neil Shapiro " [%.100s]", 4452c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4453c2aa98e2SPeter Wemm } 445440266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 445540266059SGregory Neil Shapiro { 445640266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 445740266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 445840266059SGregory Neil Shapiro ", quarantine=%.100s", 445940266059SGregory Neil Shapiro e->e_quarmsg); 446040266059SGregory Neil Shapiro } 446106f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4462c2aa98e2SPeter Wemm { 4463c2aa98e2SPeter Wemm p = macvalue('h', e); 4464c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4465d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "relay=%.100s", p); 4466c2aa98e2SPeter Wemm } 4467c2aa98e2SPeter Wemm if (buf[0] != '\0') 4468c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4469c2aa98e2SPeter Wemm 447006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 447106f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 4472c2aa98e2SPeter Wemm } 447340266059SGregory Neil Shapiro /* 4474c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 4475c2aa98e2SPeter Wemm ** 4476c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l 4477c2aa98e2SPeter Wemm ** 4478c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein: 4479c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why 4480c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with 4481c2aa98e2SPeter Wemm ** this kind of antique garbage???? 4482c2aa98e2SPeter Wemm ** 4483c2aa98e2SPeter Wemm ** Parameters: 4484c2aa98e2SPeter Wemm ** mci -- the connection information. 4485c2aa98e2SPeter Wemm ** e -- the envelope. 4486c2aa98e2SPeter Wemm ** 4487c2aa98e2SPeter Wemm ** Returns: 44884e4196cbSGregory Neil Shapiro ** true iff line was written successfully 4489c2aa98e2SPeter Wemm ** 4490c2aa98e2SPeter Wemm ** Side Effects: 4491c2aa98e2SPeter Wemm ** outputs some text to fp. 4492c2aa98e2SPeter Wemm */ 4493c2aa98e2SPeter Wemm 44944e4196cbSGregory Neil Shapiro bool 4495c2aa98e2SPeter Wemm putfromline(mci, e) 4496c2aa98e2SPeter Wemm register MCI *mci; 4497c2aa98e2SPeter Wemm ENVELOPE *e; 4498c2aa98e2SPeter Wemm { 4499c2aa98e2SPeter Wemm char *template = UnixFromLine; 4500c2aa98e2SPeter Wemm char buf[MAXLINE]; 4501c2aa98e2SPeter Wemm char xbuf[MAXLINE]; 4502c2aa98e2SPeter Wemm 4503c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 45044e4196cbSGregory Neil Shapiro return true; 4505c2aa98e2SPeter Wemm 4506c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4507c2aa98e2SPeter Wemm 4508c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 4509c2aa98e2SPeter Wemm { 4510c2aa98e2SPeter Wemm char *bang; 4511c2aa98e2SPeter Wemm 4512d0cef73dSGregory Neil Shapiro expand("\201g", buf, sizeof(buf), e); 4513c2aa98e2SPeter Wemm bang = strchr(buf, '!'); 4514c2aa98e2SPeter Wemm if (bang == NULL) 4515c2aa98e2SPeter Wemm { 4516c2aa98e2SPeter Wemm char *at; 4517c2aa98e2SPeter Wemm char hname[MAXNAME]; 4518c2aa98e2SPeter Wemm 4519c2aa98e2SPeter Wemm /* 4520c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so 4521c2aa98e2SPeter Wemm */ 4522c2aa98e2SPeter Wemm 4523c2aa98e2SPeter Wemm at = strrchr(buf, '@'); 4524c2aa98e2SPeter Wemm if (at == NULL) 4525c2aa98e2SPeter Wemm { 4526d0cef73dSGregory Neil Shapiro expand("\201k", hname, sizeof(hname), e); 4527c2aa98e2SPeter Wemm at = hname; 4528c2aa98e2SPeter Wemm } 4529c2aa98e2SPeter Wemm else 4530c2aa98e2SPeter Wemm *at++ = '\0'; 4531d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf), 4532c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4533c2aa98e2SPeter Wemm buf, at); 4534c2aa98e2SPeter Wemm } 4535c2aa98e2SPeter Wemm else 4536c2aa98e2SPeter Wemm { 4537c2aa98e2SPeter Wemm *bang++ = '\0'; 4538d0cef73dSGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof(xbuf), 4539c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4540c2aa98e2SPeter Wemm bang, buf); 4541c2aa98e2SPeter Wemm template = xbuf; 4542c2aa98e2SPeter Wemm } 4543c2aa98e2SPeter Wemm } 4544d0cef73dSGregory Neil Shapiro expand(template, buf, sizeof(buf), e); 45454e4196cbSGregory Neil Shapiro return putxline(buf, strlen(buf), mci, PXLF_HEADER); 4546c2aa98e2SPeter Wemm } 45474e4196cbSGregory Neil Shapiro 454840266059SGregory Neil Shapiro /* 4549c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message. 4550c2aa98e2SPeter Wemm ** 4551c2aa98e2SPeter Wemm ** Parameters: 4552c2aa98e2SPeter Wemm ** mci -- the connection information. 4553c2aa98e2SPeter Wemm ** e -- the envelope to put out. 4554c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must 4555c2aa98e2SPeter Wemm ** not be permitted in the resulting message. 4556c2aa98e2SPeter Wemm ** 4557c2aa98e2SPeter Wemm ** Returns: 45584e4196cbSGregory Neil Shapiro ** true iff message was written successfully 4559c2aa98e2SPeter Wemm ** 4560c2aa98e2SPeter Wemm ** Side Effects: 4561c2aa98e2SPeter Wemm ** The message is written onto fp. 4562c2aa98e2SPeter Wemm */ 4563c2aa98e2SPeter Wemm 4564c2aa98e2SPeter Wemm /* values for output state variable */ 45654e4196cbSGregory Neil Shapiro #define OSTATE_HEAD 0 /* at beginning of line */ 45664e4196cbSGregory Neil Shapiro #define OSTATE_CR 1 /* read a carriage return */ 45674e4196cbSGregory Neil Shapiro #define OSTATE_INLINE 2 /* putting rest of line */ 4568c2aa98e2SPeter Wemm 45694e4196cbSGregory Neil Shapiro bool 4570c2aa98e2SPeter Wemm putbody(mci, e, separator) 4571c2aa98e2SPeter Wemm register MCI *mci; 4572c2aa98e2SPeter Wemm register ENVELOPE *e; 4573c2aa98e2SPeter Wemm char *separator; 4574c2aa98e2SPeter Wemm { 457540266059SGregory Neil Shapiro bool dead = false; 45764e4196cbSGregory Neil Shapiro bool ioerr = false; 45774e4196cbSGregory Neil Shapiro int save_errno; 4578c2aa98e2SPeter Wemm char buf[MAXLINE]; 457940266059SGregory Neil Shapiro #if MIME8TO7 4580065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1]; 458140266059SGregory Neil Shapiro #endif /* MIME8TO7 */ 4582c2aa98e2SPeter Wemm 4583c2aa98e2SPeter Wemm /* 4584c2aa98e2SPeter Wemm ** Output the body of the message 4585c2aa98e2SPeter Wemm */ 4586c2aa98e2SPeter Wemm 4587c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 4588c2aa98e2SPeter Wemm { 458940266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 4590c2aa98e2SPeter Wemm 459140266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 4592a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL); 4593c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 459406f25ae9SGregory Neil Shapiro { 459506f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s"; 459606f25ae9SGregory Neil Shapiro 459706f25ae9SGregory Neil Shapiro if (errno == ENOENT) 459806f25ae9SGregory Neil Shapiro msg++; 459906f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr); 460006f25ae9SGregory Neil Shapiro } 460140266059SGregory Neil Shapiro 4602c2aa98e2SPeter Wemm } 4603c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 4604c2aa98e2SPeter Wemm { 4605c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4606c2aa98e2SPeter Wemm { 46074e4196cbSGregory Neil Shapiro if (!putline("", mci)) 46084e4196cbSGregory Neil Shapiro goto writeerr; 4609c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4610c2aa98e2SPeter Wemm } 46114e4196cbSGregory Neil Shapiro if (!putline("<<< No Message Collected >>>", mci)) 46124e4196cbSGregory Neil Shapiro goto writeerr; 4613c2aa98e2SPeter Wemm goto endofmessage; 4614c2aa98e2SPeter Wemm } 461506f25ae9SGregory Neil Shapiro 4616c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0) 4617c2aa98e2SPeter Wemm { 4618c2aa98e2SPeter Wemm struct stat stbuf; 4619c2aa98e2SPeter Wemm 462040266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 462140266059SGregory Neil Shapiro < 0) 4622c2aa98e2SPeter Wemm e->e_dfino = -1; 4623c2aa98e2SPeter Wemm else 4624c2aa98e2SPeter Wemm { 4625c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 4626c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 4627c2aa98e2SPeter Wemm } 4628c2aa98e2SPeter Wemm } 462906f25ae9SGregory Neil Shapiro 463040266059SGregory Neil Shapiro /* paranoia: the data file should always be in a rewound state */ 463106f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 4632c2aa98e2SPeter Wemm 46334e4196cbSGregory Neil Shapiro /* simulate an I/O timeout when used as source */ 46344e4196cbSGregory Neil Shapiro if (tTd(84, 101)) 46354e4196cbSGregory Neil Shapiro sleep(319); 46364e4196cbSGregory Neil Shapiro 4637c2aa98e2SPeter Wemm #if MIME8TO7 4638c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 4639c2aa98e2SPeter Wemm { 4640c2aa98e2SPeter Wemm /* 4641c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion. 4642c2aa98e2SPeter Wemm */ 4643c2aa98e2SPeter Wemm 4644c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */ 46454e4196cbSGregory Neil Shapiro if (hvalue("MIME-Version", e->e_header) == NULL && 46464e4196cbSGregory Neil Shapiro !putline("MIME-Version: 1.0", mci)) 46474e4196cbSGregory Neil Shapiro goto writeerr; 4648c2aa98e2SPeter Wemm 4649c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 4650c2aa98e2SPeter Wemm { 4651d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), 4652c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 4653c2aa98e2SPeter Wemm defcharset(e)); 46544e4196cbSGregory Neil Shapiro if (!putline(buf, mci)) 46554e4196cbSGregory Neil Shapiro goto writeerr; 4656c2aa98e2SPeter Wemm } 4657c2aa98e2SPeter Wemm 4658c2aa98e2SPeter Wemm /* now do the hard work */ 4659c2aa98e2SPeter Wemm boundaries[0] = NULL; 4660c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4661af9557fdSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER, 0) == 46624e4196cbSGregory Neil Shapiro SM_IO_EOF) 46634e4196cbSGregory Neil Shapiro goto writeerr; 4664c2aa98e2SPeter Wemm } 4665c2aa98e2SPeter Wemm # if MIME7TO8 4666c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 4667c2aa98e2SPeter Wemm { 46684e4196cbSGregory Neil Shapiro if (!mime7to8(mci, e->e_header, e)) 46694e4196cbSGregory Neil Shapiro goto writeerr; 4670c2aa98e2SPeter Wemm } 467106f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */ 4672065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 4673065a643dSPeter Wemm { 467406f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs; 467506f25ae9SGregory Neil Shapiro 4676065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */ 4677065a643dSPeter Wemm boundaries[0] = NULL; 4678065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER; 467906f25ae9SGregory Neil Shapiro 468006f25ae9SGregory Neil Shapiro /* 468106f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message 468206f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose 468306f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call 468406f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security 468506f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors. 468606f25ae9SGregory Neil Shapiro */ 468706f25ae9SGregory Neil Shapiro 468806f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags)) 468940266059SGregory Neil Shapiro SuprErrs = true; 469006f25ae9SGregory Neil Shapiro 46914e4196cbSGregory Neil Shapiro if (mime8to7(mci, e->e_header, e, boundaries, 4692af9557fdSGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7, 0) == SM_IO_EOF) 46934e4196cbSGregory Neil Shapiro goto writeerr; 469406f25ae9SGregory Neil Shapiro 469506f25ae9SGregory Neil Shapiro /* restore SuprErrs */ 469606f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs; 4697065a643dSPeter Wemm } 4698c2aa98e2SPeter Wemm else 469906f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */ 4700c2aa98e2SPeter Wemm { 4701c2aa98e2SPeter Wemm int ostate; 4702c2aa98e2SPeter Wemm register char *bp; 4703c2aa98e2SPeter Wemm register char *pbp; 4704c2aa98e2SPeter Wemm register int c; 4705c2aa98e2SPeter Wemm register char *xp; 4706c2aa98e2SPeter Wemm int padc; 4707c2aa98e2SPeter Wemm char *buflim; 4708c2aa98e2SPeter Wemm int pos = 0; 470906f25ae9SGregory Neil Shapiro char peekbuf[12]; 4710c2aa98e2SPeter Wemm 4711c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4712c2aa98e2SPeter Wemm { 47134e4196cbSGregory Neil Shapiro if (!putline("", mci)) 47144e4196cbSGregory Neil Shapiro goto writeerr; 4715c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4716c2aa98e2SPeter Wemm } 4717c2aa98e2SPeter Wemm 4718c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */ 4719d0cef73dSGregory Neil Shapiro buflim = &buf[sizeof(buf) - 1]; 4720c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 4721d0cef73dSGregory Neil Shapiro mci->mci_mailer->m_linelimit < sizeof(buf) - 1) 4722c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 4723c2aa98e2SPeter Wemm 4724c2aa98e2SPeter Wemm /* copy temp file to output with mapping */ 47254e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 4726c2aa98e2SPeter Wemm bp = buf; 4727c2aa98e2SPeter Wemm pbp = peekbuf; 472840266059SGregory Neil Shapiro while (!sm_io_error(mci->mci_out) && !dead) 4729c2aa98e2SPeter Wemm { 4730c2aa98e2SPeter Wemm if (pbp > peekbuf) 4731c2aa98e2SPeter Wemm c = *--pbp; 473240266059SGregory Neil Shapiro else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 473340266059SGregory Neil Shapiro == SM_IO_EOF) 4734c2aa98e2SPeter Wemm break; 4735c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags)) 4736c2aa98e2SPeter Wemm c &= 0x7f; 4737c2aa98e2SPeter Wemm switch (ostate) 4738c2aa98e2SPeter Wemm { 47394e4196cbSGregory Neil Shapiro case OSTATE_HEAD: 4740c2aa98e2SPeter Wemm if (c == '\0' && 474140266059SGregory Neil Shapiro bitnset(M_NONULLS, 474240266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4743c2aa98e2SPeter Wemm break; 4744c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim) 4745c2aa98e2SPeter Wemm { 4746c2aa98e2SPeter Wemm *bp++ = c; 4747c2aa98e2SPeter Wemm break; 4748c2aa98e2SPeter Wemm } 4749c2aa98e2SPeter Wemm 4750c2aa98e2SPeter Wemm /* check beginning of line for special cases */ 4751c2aa98e2SPeter Wemm *bp = '\0'; 4752c2aa98e2SPeter Wemm pos = 0; 475340266059SGregory Neil Shapiro padc = SM_IO_EOF; 4754c2aa98e2SPeter Wemm if (buf[0] == 'F' && 475540266059SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 475640266059SGregory Neil Shapiro && strncmp(buf, "From ", 5) == 0) 4757c2aa98e2SPeter Wemm { 4758c2aa98e2SPeter Wemm padc = '>'; 4759c2aa98e2SPeter Wemm } 4760c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' && 4761c2aa98e2SPeter Wemm separator != NULL) 4762c2aa98e2SPeter Wemm { 4763c2aa98e2SPeter Wemm /* possible separator */ 4764c2aa98e2SPeter Wemm int sl = strlen(separator); 4765c2aa98e2SPeter Wemm 476640266059SGregory Neil Shapiro if (strncmp(&buf[2], separator, sl) 476740266059SGregory Neil Shapiro == 0) 4768c2aa98e2SPeter Wemm padc = ' '; 4769c2aa98e2SPeter Wemm } 4770c2aa98e2SPeter Wemm if (buf[0] == '.' && 4771c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 4772c2aa98e2SPeter Wemm { 4773c2aa98e2SPeter Wemm padc = '.'; 4774c2aa98e2SPeter Wemm } 4775c2aa98e2SPeter Wemm 4776c2aa98e2SPeter Wemm /* now copy out saved line */ 4777c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4778c2aa98e2SPeter Wemm { 477940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 478040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 478140266059SGregory Neil Shapiro "%05d >>> ", 478240266059SGregory Neil Shapiro (int) CurrentPid); 478340266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 478440266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 478540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 478640266059SGregory Neil Shapiro padc); 4787c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 478840266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 478940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 479040266059SGregory Neil Shapiro (unsigned char) *xp); 4791c2aa98e2SPeter Wemm if (c == '\n') 479240266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 479340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 479440266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4795c2aa98e2SPeter Wemm } 479640266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 4797c2aa98e2SPeter Wemm { 479840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 479940266059SGregory Neil Shapiro SM_TIME_DEFAULT, padc) 480040266059SGregory Neil Shapiro == SM_IO_EOF) 480106f25ae9SGregory Neil Shapiro { 480240266059SGregory Neil Shapiro dead = true; 480306f25ae9SGregory Neil Shapiro continue; 480406f25ae9SGregory Neil Shapiro } 4805c2aa98e2SPeter Wemm pos++; 4806c2aa98e2SPeter Wemm } 4807c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4808c2aa98e2SPeter Wemm { 480940266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 481040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 481140266059SGregory Neil Shapiro (unsigned char) *xp) 481240266059SGregory Neil Shapiro == SM_IO_EOF) 481306f25ae9SGregory Neil Shapiro { 481440266059SGregory Neil Shapiro dead = true; 481506f25ae9SGregory Neil Shapiro break; 4816c2aa98e2SPeter Wemm } 4817193538b7SGregory Neil Shapiro } 481806f25ae9SGregory Neil Shapiro if (dead) 481906f25ae9SGregory Neil Shapiro continue; 4820c2aa98e2SPeter Wemm if (c == '\n') 4821c2aa98e2SPeter Wemm { 482240266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 482340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 482440266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 482540266059SGregory Neil Shapiro == SM_IO_EOF) 482606f25ae9SGregory Neil Shapiro break; 4827c2aa98e2SPeter Wemm pos = 0; 4828c2aa98e2SPeter Wemm } 4829c2aa98e2SPeter Wemm else 4830c2aa98e2SPeter Wemm { 4831c2aa98e2SPeter Wemm pos += bp - buf; 4832c2aa98e2SPeter Wemm if (c != '\r') 48335ef517c0SGregory Neil Shapiro { 48345ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 48355ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 4836c2aa98e2SPeter Wemm *pbp++ = c; 4837c2aa98e2SPeter Wemm } 48385ef517c0SGregory Neil Shapiro } 483906f25ae9SGregory Neil Shapiro 4840c2aa98e2SPeter Wemm bp = buf; 4841c2aa98e2SPeter Wemm 4842c2aa98e2SPeter Wemm /* determine next state */ 4843c2aa98e2SPeter Wemm if (c == '\n') 48444e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 4845c2aa98e2SPeter Wemm else if (c == '\r') 48464e4196cbSGregory Neil Shapiro ostate = OSTATE_CR; 4847c2aa98e2SPeter Wemm else 48484e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 4849c2aa98e2SPeter Wemm continue; 4850c2aa98e2SPeter Wemm 48514e4196cbSGregory Neil Shapiro case OSTATE_CR: 4852c2aa98e2SPeter Wemm if (c == '\n') 4853c2aa98e2SPeter Wemm { 4854c2aa98e2SPeter Wemm /* got CRLF */ 485540266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 485640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 485740266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 485840266059SGregory Neil Shapiro == SM_IO_EOF) 485906f25ae9SGregory Neil Shapiro continue; 486006f25ae9SGregory Neil Shapiro 4861c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4862c2aa98e2SPeter Wemm { 486340266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 486440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 486540266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4866c2aa98e2SPeter Wemm } 4867d0cef73dSGregory Neil Shapiro pos = 0; 48684e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 4869c2aa98e2SPeter Wemm continue; 4870c2aa98e2SPeter Wemm } 4871c2aa98e2SPeter Wemm 4872c2aa98e2SPeter Wemm /* had a naked carriage return */ 48735ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 4874c2aa98e2SPeter Wemm *pbp++ = c; 4875c2aa98e2SPeter Wemm c = '\r'; 48764e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 4877c2aa98e2SPeter Wemm goto putch; 4878c2aa98e2SPeter Wemm 48794e4196cbSGregory Neil Shapiro case OSTATE_INLINE: 4880c2aa98e2SPeter Wemm if (c == '\r') 4881c2aa98e2SPeter Wemm { 48824e4196cbSGregory Neil Shapiro ostate = OSTATE_CR; 4883c2aa98e2SPeter Wemm continue; 4884c2aa98e2SPeter Wemm } 4885c2aa98e2SPeter Wemm if (c == '\0' && 488640266059SGregory Neil Shapiro bitnset(M_NONULLS, 488740266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4888c2aa98e2SPeter Wemm break; 4889c2aa98e2SPeter Wemm putch: 4890c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 489106f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 && 4892c2aa98e2SPeter Wemm c != '\n') 4893c2aa98e2SPeter Wemm { 489406f25ae9SGregory Neil Shapiro int d; 489506f25ae9SGregory Neil Shapiro 489606f25ae9SGregory Neil Shapiro /* check next character for EOL */ 489706f25ae9SGregory Neil Shapiro if (pbp > peekbuf) 489806f25ae9SGregory Neil Shapiro d = *(pbp - 1); 489940266059SGregory Neil Shapiro else if ((d = sm_io_getc(e->e_dfp, 490040266059SGregory Neil Shapiro SM_TIME_DEFAULT)) 490140266059SGregory Neil Shapiro != SM_IO_EOF) 49025ef517c0SGregory Neil Shapiro { 49035ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 49045ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 490506f25ae9SGregory Neil Shapiro *pbp++ = d; 49065ef517c0SGregory Neil Shapiro } 490706f25ae9SGregory Neil Shapiro 490840266059SGregory Neil Shapiro if (d == '\n' || d == SM_IO_EOF) 490906f25ae9SGregory Neil Shapiro { 491006f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL) 491140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 491240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 491340266059SGregory Neil Shapiro (unsigned char) c); 491440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 491540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 491640266059SGregory Neil Shapiro (unsigned char) c) 491740266059SGregory Neil Shapiro == SM_IO_EOF) 491806f25ae9SGregory Neil Shapiro { 491940266059SGregory Neil Shapiro dead = true; 492006f25ae9SGregory Neil Shapiro continue; 492106f25ae9SGregory Neil Shapiro } 492206f25ae9SGregory Neil Shapiro pos++; 492306f25ae9SGregory Neil Shapiro continue; 492406f25ae9SGregory Neil Shapiro } 492506f25ae9SGregory Neil Shapiro 492640266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 492740266059SGregory Neil Shapiro SM_TIME_DEFAULT, '!') 492840266059SGregory Neil Shapiro == SM_IO_EOF || 492940266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out, 493040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 493140266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 493240266059SGregory Neil Shapiro == SM_IO_EOF) 493306f25ae9SGregory Neil Shapiro { 493440266059SGregory Neil Shapiro dead = true; 493506f25ae9SGregory Neil Shapiro continue; 493606f25ae9SGregory Neil Shapiro } 493706f25ae9SGregory Neil Shapiro 4938c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4939c2aa98e2SPeter Wemm { 494040266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 494140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 494240266059SGregory Neil Shapiro "!%s", 4943c2aa98e2SPeter Wemm mci->mci_mailer->m_eol); 4944c2aa98e2SPeter Wemm } 49454e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 49465ef517c0SGregory Neil Shapiro SM_ASSERT(pbp < peekbuf + 49475ef517c0SGregory Neil Shapiro sizeof(peekbuf)); 4948c2aa98e2SPeter Wemm *pbp++ = c; 4949c2aa98e2SPeter Wemm continue; 4950c2aa98e2SPeter Wemm } 4951c2aa98e2SPeter Wemm if (c == '\n') 4952c2aa98e2SPeter Wemm { 4953c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 495440266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 495540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 495640266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 495740266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 495840266059SGregory Neil Shapiro SM_TIME_DEFAULT, 495940266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 496040266059SGregory Neil Shapiro == SM_IO_EOF) 496106f25ae9SGregory Neil Shapiro continue; 4962c2aa98e2SPeter Wemm pos = 0; 49634e4196cbSGregory Neil Shapiro ostate = OSTATE_HEAD; 4964c2aa98e2SPeter Wemm } 4965c2aa98e2SPeter Wemm else 4966c2aa98e2SPeter Wemm { 4967c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 496840266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 496940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 497040266059SGregory Neil Shapiro (unsigned char) c); 497140266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 497240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 497340266059SGregory Neil Shapiro (unsigned char) c) 497440266059SGregory Neil Shapiro == SM_IO_EOF) 497506f25ae9SGregory Neil Shapiro { 497640266059SGregory Neil Shapiro dead = true; 497706f25ae9SGregory Neil Shapiro continue; 497806f25ae9SGregory Neil Shapiro } 4979c2aa98e2SPeter Wemm pos++; 49804e4196cbSGregory Neil Shapiro ostate = OSTATE_INLINE; 4981c2aa98e2SPeter Wemm } 4982c2aa98e2SPeter Wemm break; 4983c2aa98e2SPeter Wemm } 4984c2aa98e2SPeter Wemm } 4985c2aa98e2SPeter Wemm 4986c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */ 4987c2aa98e2SPeter Wemm if (bp > buf) 4988c2aa98e2SPeter Wemm { 4989c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4990c2aa98e2SPeter Wemm { 4991c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 499240266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 499340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 499440266059SGregory Neil Shapiro (unsigned char) *xp); 4995c2aa98e2SPeter Wemm } 4996c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4997c2aa98e2SPeter Wemm { 499840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 499940266059SGregory Neil Shapiro (unsigned char) *xp) 500040266059SGregory Neil Shapiro == SM_IO_EOF) 500106f25ae9SGregory Neil Shapiro { 500240266059SGregory Neil Shapiro dead = true; 500306f25ae9SGregory Neil Shapiro break; 500406f25ae9SGregory Neil Shapiro } 5005193538b7SGregory Neil Shapiro } 5006c2aa98e2SPeter Wemm pos += bp - buf; 5007c2aa98e2SPeter Wemm } 500806f25ae9SGregory Neil Shapiro if (!dead && pos > 0) 5009c2aa98e2SPeter Wemm { 5010c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 501140266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 501240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 501340266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 50144e4196cbSGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 50154e4196cbSGregory Neil Shapiro mci->mci_mailer->m_eol) == SM_IO_EOF) 50164e4196cbSGregory Neil Shapiro goto writeerr; 5017c2aa98e2SPeter Wemm } 5018c2aa98e2SPeter Wemm } 5019c2aa98e2SPeter Wemm 502040266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp)) 5021c2aa98e2SPeter Wemm { 502240266059SGregory Neil Shapiro syserr("putbody: %s/%cf%s: read error", 502340266059SGregory Neil Shapiro qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 502440266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 5025c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 50264e4196cbSGregory Neil Shapiro ioerr = true; 5027c2aa98e2SPeter Wemm } 5028c2aa98e2SPeter Wemm 5029c2aa98e2SPeter Wemm endofmessage: 503006f25ae9SGregory Neil Shapiro /* 503106f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process, 503206f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the 503306f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel 503406f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared 503506f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital 503606f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the 503706f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell) 503806f25ae9SGregory Neil Shapiro ** offset to match. 503906f25ae9SGregory Neil Shapiro */ 504006f25ae9SGregory Neil Shapiro 50414e4196cbSGregory Neil Shapiro save_errno = errno; 504206f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) 504306f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 504406f25ae9SGregory Neil Shapiro 5045c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */ 504606f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 5047c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n') 5048c2aa98e2SPeter Wemm { 50494e4196cbSGregory Neil Shapiro if (!putline("", mci)) 50504e4196cbSGregory Neil Shapiro goto writeerr; 50514e4196cbSGregory Neil Shapiro } 50524e4196cbSGregory Neil Shapiro 50534e4196cbSGregory Neil Shapiro if (!dead && 50544e4196cbSGregory Neil Shapiro (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF || 50554e4196cbSGregory Neil Shapiro (sm_io_error(mci->mci_out) && errno != EPIPE))) 50564e4196cbSGregory Neil Shapiro { 50574e4196cbSGregory Neil Shapiro save_errno = errno; 5058c2aa98e2SPeter Wemm syserr("putbody: write error"); 5059c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 50604e4196cbSGregory Neil Shapiro ioerr = true; 5061c2aa98e2SPeter Wemm } 506206f25ae9SGregory Neil Shapiro 50634e4196cbSGregory Neil Shapiro errno = save_errno; 50644e4196cbSGregory Neil Shapiro return !dead && !ioerr; 50654e4196cbSGregory Neil Shapiro 50664e4196cbSGregory Neil Shapiro writeerr: 50674e4196cbSGregory Neil Shapiro return false; 5068c2aa98e2SPeter Wemm } 50694e4196cbSGregory Neil Shapiro 507040266059SGregory Neil Shapiro /* 5071c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file. 5072c2aa98e2SPeter Wemm ** 507340266059SGregory Neil Shapiro ** If the file has the set-user-ID/set-group-ID bits set, but NO 507440266059SGregory Neil Shapiro ** execute bits, sendmail will try to become the owner of that file 5075c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if 5076c2aa98e2SPeter Wemm ** sendmail runs as root. 5077c2aa98e2SPeter Wemm ** 5078c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it 5079c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We 5080c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it 5081c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have 5082c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message. 5083c2aa98e2SPeter Wemm ** 5084c2aa98e2SPeter Wemm ** Parameters: 5085c2aa98e2SPeter Wemm ** filename -- the name of the file to send to. 5086c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL, 5087c2aa98e2SPeter Wemm ** use FileMailer. 5088c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes 5089c2aa98e2SPeter Wemm ** the userid/groupid to be when sending. 5090c2aa98e2SPeter Wemm ** sfflags -- flags for opening. 5091c2aa98e2SPeter Wemm ** e -- the current envelope. 5092c2aa98e2SPeter Wemm ** 5093c2aa98e2SPeter Wemm ** Returns: 5094c2aa98e2SPeter Wemm ** The exit code associated with the operation. 5095c2aa98e2SPeter Wemm ** 5096c2aa98e2SPeter Wemm ** Side Effects: 5097c2aa98e2SPeter Wemm ** none. 5098c2aa98e2SPeter Wemm */ 5099c2aa98e2SPeter Wemm 510040266059SGregory Neil Shapiro # define RETURN(st) exit(st); 510140266059SGregory Neil Shapiro 5102c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout; 5103c2aa98e2SPeter Wemm 5104c2aa98e2SPeter Wemm int 5105c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e) 5106c2aa98e2SPeter Wemm char *volatile filename; 5107c2aa98e2SPeter Wemm MAILER *volatile mailer; 5108c2aa98e2SPeter Wemm ADDRESS *ctladdr; 510906f25ae9SGregory Neil Shapiro volatile long sfflags; 5110c2aa98e2SPeter Wemm register ENVELOPE *e; 5111c2aa98e2SPeter Wemm { 511240266059SGregory Neil Shapiro register SM_FILE_T *f; 5113c2aa98e2SPeter Wemm register pid_t pid = -1; 511406f25ae9SGregory Neil Shapiro volatile int mode; 511506f25ae9SGregory Neil Shapiro int len; 511606f25ae9SGregory Neil Shapiro off_t curoff; 5117c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0; 5118c2aa98e2SPeter Wemm char *p; 511906f25ae9SGregory Neil Shapiro char *volatile realfile; 512040266059SGregory Neil Shapiro SM_EVENT *ev; 512194c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 512294c01205SGregory Neil Shapiro char targetfile[MAXPATHLEN]; 5123c2aa98e2SPeter Wemm 5124c2aa98e2SPeter Wemm if (tTd(11, 1)) 5125c2aa98e2SPeter Wemm { 512640266059SGregory Neil Shapiro sm_dprintf("mailfile %s\n ctladdr=", filename); 5127e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), ctladdr, false); 5128c2aa98e2SPeter Wemm } 5129c2aa98e2SPeter Wemm 5130c2aa98e2SPeter Wemm if (mailer == NULL) 5131c2aa98e2SPeter Wemm mailer = FileMailer; 5132c2aa98e2SPeter Wemm 5133c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 513440266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 5135c2aa98e2SPeter Wemm 5136c2aa98e2SPeter Wemm /* 5137c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file 5138c2aa98e2SPeter Wemm ** delivery to regular files only. 5139c2aa98e2SPeter Wemm */ 5140c2aa98e2SPeter Wemm 514140266059SGregory Neil Shapiro if (sm_path_isdevnull(filename)) 5142c2aa98e2SPeter Wemm return EX_OK; 5143c2aa98e2SPeter Wemm 5144c2aa98e2SPeter Wemm /* check for 8-bit available */ 5145c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5146c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) && 5147c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 5148c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 5149c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 5150c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 5151c2aa98e2SPeter Wemm { 5152c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 515306f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 515406f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 515540266059SGregory Neil Shapiro errno = 0; 515606f25ae9SGregory Neil Shapiro return EX_DATAERR; 515706f25ae9SGregory Neil Shapiro } 515806f25ae9SGregory Neil Shapiro 515906f25ae9SGregory Neil Shapiro /* Find the actual file */ 516006f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 516106f25ae9SGregory Neil Shapiro { 516206f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv); 516306f25ae9SGregory Neil Shapiro 516406f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0) 516506f25ae9SGregory Neil Shapiro filename += len; 516606f25ae9SGregory Neil Shapiro 5167d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile)) 516806f25ae9SGregory Neil Shapiro { 516906f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 517006f25ae9SGregory Neil Shapiro SafeFileEnv, filename); 517106f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 517206f25ae9SGregory Neil Shapiro } 5173d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof(targetfile)); 517406f25ae9SGregory Neil Shapiro realfile = targetfile + len; 517506f25ae9SGregory Neil Shapiro if (*filename == '/') 517606f25ae9SGregory Neil Shapiro filename++; 5177605302a5SGregory Neil Shapiro if (*filename != '\0') 5178605302a5SGregory Neil Shapiro { 5179605302a5SGregory Neil Shapiro /* paranoia: trailing / should be removed in readcf */ 5180605302a5SGregory Neil Shapiro if (targetfile[len - 1] != '/') 5181605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, 5182d0cef73dSGregory Neil Shapiro "/", sizeof(targetfile)); 5183605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 5184d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 5185605302a5SGregory Neil Shapiro } 518606f25ae9SGregory Neil Shapiro } 518706f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL) 518806f25ae9SGregory Neil Shapiro { 5189d0cef73dSGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof(targetfile), e); 519006f25ae9SGregory Neil Shapiro len = strlen(targetfile); 519106f25ae9SGregory Neil Shapiro 519206f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0) 519306f25ae9SGregory Neil Shapiro filename += len; 519406f25ae9SGregory Neil Shapiro 5195d0cef73dSGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof(targetfile)) 519606f25ae9SGregory Neil Shapiro { 519706f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 519806f25ae9SGregory Neil Shapiro targetfile, filename); 519906f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 520006f25ae9SGregory Neil Shapiro } 520106f25ae9SGregory Neil Shapiro realfile = targetfile + len; 520206f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 5203d0cef73dSGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof(targetfile)); 520406f25ae9SGregory Neil Shapiro if (*filename == '/') 520540266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename + 1, 5206d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 520706f25ae9SGregory Neil Shapiro else 520840266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 5209d0cef73dSGregory Neil Shapiro sizeof(targetfile)); 521006f25ae9SGregory Neil Shapiro } 521106f25ae9SGregory Neil Shapiro else 521206f25ae9SGregory Neil Shapiro { 5213d0cef73dSGregory Neil Shapiro if (sm_strlcpy(targetfile, filename, sizeof(targetfile)) >= 5214d0cef73dSGregory Neil Shapiro sizeof(targetfile)) 521506f25ae9SGregory Neil Shapiro { 521606f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename); 521706f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 521806f25ae9SGregory Neil Shapiro } 521906f25ae9SGregory Neil Shapiro realfile = targetfile; 5220c2aa98e2SPeter Wemm } 5221c2aa98e2SPeter Wemm 5222c2aa98e2SPeter Wemm /* 5223c2aa98e2SPeter Wemm ** Fork so we can change permissions here. 5224c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of 5225c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc. 5226c2aa98e2SPeter Wemm */ 5227c2aa98e2SPeter Wemm 5228605302a5SGregory Neil Shapiro 5229605302a5SGregory Neil Shapiro /* 5230605302a5SGregory Neil Shapiro ** Dispose of SIGCHLD signal catchers that may be laying 5231605302a5SGregory Neil Shapiro ** around so that the waitfor() below will get it. 5232605302a5SGregory Neil Shapiro */ 5233605302a5SGregory Neil Shapiro 5234605302a5SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 5235605302a5SGregory Neil Shapiro 5236c2aa98e2SPeter Wemm DOFORK(fork); 5237c2aa98e2SPeter Wemm 5238c2aa98e2SPeter Wemm if (pid < 0) 523906f25ae9SGregory Neil Shapiro return EX_OSERR; 5240c2aa98e2SPeter Wemm else if (pid == 0) 5241c2aa98e2SPeter Wemm { 5242c2aa98e2SPeter Wemm /* child -- actually write to file */ 5243c2aa98e2SPeter Wemm struct stat stb; 5244c2aa98e2SPeter Wemm MCI mcibuf; 5245065a643dSPeter Wemm int err; 5246c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND; 5247c2aa98e2SPeter Wemm 52488774250cSGregory Neil Shapiro /* Reset global flags */ 52498774250cSGregory Neil Shapiro RestartRequest = NULL; 525040266059SGregory Neil Shapiro RestartWorkGroup = false; 52518774250cSGregory Neil Shapiro ShutdownRequest = NULL; 52528774250cSGregory Neil Shapiro PendingSignal = 0; 525340266059SGregory Neil Shapiro CurrentPid = getpid(); 52548774250cSGregory Neil Shapiro 5255c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 5256af9557fdSGregory Neil Shapiro { 5257af9557fdSGregory Neil Shapiro int fd; 5258af9557fdSGregory Neil Shapiro 5259af9557fdSGregory Neil Shapiro fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL); 5260af9557fdSGregory Neil Shapiro /* SM_ASSERT(fd >= 0); */ 5261af9557fdSGregory Neil Shapiro if (fd >= 0) 5262af9557fdSGregory Neil Shapiro (void) close(fd); 5263af9557fdSGregory Neil Shapiro } 5264c2aa98e2SPeter Wemm 526540266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_DFL); 526640266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_DFL); 526740266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 5268c2aa98e2SPeter Wemm (void) umask(OldUmask); 5269c2aa98e2SPeter Wemm e->e_to = filename; 5270c2aa98e2SPeter Wemm ExitStat = EX_OK; 5271c2aa98e2SPeter Wemm 5272c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0) 5273c2aa98e2SPeter Wemm { 527440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 5275c2aa98e2SPeter Wemm } 5276c2aa98e2SPeter Wemm 5277c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0) 527840266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 527940266059SGregory Neil Shapiro 0); 5280c2aa98e2SPeter Wemm else 5281c2aa98e2SPeter Wemm ev = NULL; 5282c2aa98e2SPeter Wemm 528340266059SGregory Neil Shapiro /* check file mode to see if set-user-ID */ 528406f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0) 5285c2aa98e2SPeter Wemm mode = FileMode; 528606f25ae9SGregory Neil Shapiro else 5287c2aa98e2SPeter Wemm mode = stb.st_mode; 5288c2aa98e2SPeter Wemm 5289c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */ 5290c2aa98e2SPeter Wemm errno = 0; 5291c2aa98e2SPeter Wemm ExitStat = EX_OK; 5292c2aa98e2SPeter Wemm 529306f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */ 529406f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 529506f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags)) 5296c2aa98e2SPeter Wemm { 529740266059SGregory Neil Shapiro /* ignore set-user-ID and set-group-ID bits */ 5298c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID); 529906f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 530040266059SGregory Neil Shapiro sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 5301c2aa98e2SPeter Wemm } 5302c2aa98e2SPeter Wemm 530340266059SGregory Neil Shapiro /* we have to open the data file BEFORE setuid() */ 5304c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 5305c2aa98e2SPeter Wemm { 530640266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 5307c2aa98e2SPeter Wemm 530840266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 5309a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL); 5310c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 5311c2aa98e2SPeter Wemm { 5312c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s", 5313c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr); 5314c2aa98e2SPeter Wemm } 5315c2aa98e2SPeter Wemm } 5316c2aa98e2SPeter Wemm 5317c2aa98e2SPeter Wemm /* select a new user to run as */ 5318c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags)) 5319c2aa98e2SPeter Wemm { 5320c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 5321c2aa98e2SPeter Wemm { 5322c2aa98e2SPeter Wemm RealUserName = NULL; 5323e92d3f3fSGregory Neil Shapiro if (mailer->m_uid == NO_UID) 5324e92d3f3fSGregory Neil Shapiro RealUid = RunAsUid; 5325e92d3f3fSGregory Neil Shapiro else 5326c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 532706f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid) 532806f25ae9SGregory Neil Shapiro { 532906f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 533040266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", 533140266059SGregory Neil Shapiro (int) RunAsUid, (int) RealUid); 533240266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 533306f25ae9SGregory Neil Shapiro } 5334c2aa98e2SPeter Wemm } 5335c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode)) 5336c2aa98e2SPeter Wemm { 5337c2aa98e2SPeter Wemm RealUserName = NULL; 5338c2aa98e2SPeter Wemm RealUid = stb.st_uid; 5339c2aa98e2SPeter Wemm } 5340c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 5341c2aa98e2SPeter Wemm { 5342c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL) 5343c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser; 5344c2aa98e2SPeter Wemm else 5345c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user; 5346c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid; 5347c2aa98e2SPeter Wemm } 5348e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_uid != NO_UID) 5349c2aa98e2SPeter Wemm { 5350c2aa98e2SPeter Wemm RealUserName = DefUser; 5351c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 5352c2aa98e2SPeter Wemm } 5353c2aa98e2SPeter Wemm else 5354c2aa98e2SPeter Wemm { 5355c2aa98e2SPeter Wemm RealUserName = DefUser; 5356c2aa98e2SPeter Wemm RealUid = DefUid; 5357c2aa98e2SPeter Wemm } 5358c2aa98e2SPeter Wemm 5359c2aa98e2SPeter Wemm /* select a new group to run as */ 5360c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 536106f25ae9SGregory Neil Shapiro { 5362e92d3f3fSGregory Neil Shapiro if (mailer->m_gid == NO_GID) 5363e92d3f3fSGregory Neil Shapiro RealGid = RunAsGid; 5364e92d3f3fSGregory Neil Shapiro else 5365c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 536606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 536706f25ae9SGregory Neil Shapiro (RealGid != getgid() || 536806f25ae9SGregory Neil Shapiro RealGid != getegid())) 536906f25ae9SGregory Neil Shapiro { 537006f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 537140266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", 537240266059SGregory Neil Shapiro (int) RealGid, (int) RunAsUid, 537340266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 537440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 537506f25ae9SGregory Neil Shapiro } 537606f25ae9SGregory Neil Shapiro } 5377c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode)) 5378c2aa98e2SPeter Wemm RealGid = stb.st_gid; 537906f25ae9SGregory Neil Shapiro else if (ctladdr != NULL && 538006f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid && 538106f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0) 5382193538b7SGregory Neil Shapiro { 5383193538b7SGregory Neil Shapiro /* 5384193538b7SGregory Neil Shapiro ** Special case: This means it is an 5385193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser. 5386193538b7SGregory Neil Shapiro ** See alias()'s comments. 5387193538b7SGregory Neil Shapiro */ 5388193538b7SGregory Neil Shapiro 538906f25ae9SGregory Neil Shapiro RealGid = DefGid; 5390193538b7SGregory Neil Shapiro RealUserName = DefUser; 5391193538b7SGregory Neil Shapiro } 5392193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0) 5393193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid; 5394e92d3f3fSGregory Neil Shapiro else if (mailer != NULL && mailer->m_gid != NO_GID) 5395c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 5396c2aa98e2SPeter Wemm else 5397c2aa98e2SPeter Wemm RealGid = DefGid; 5398c2aa98e2SPeter Wemm } 5399c2aa98e2SPeter Wemm 5400c2aa98e2SPeter Wemm /* last ditch */ 5401c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags)) 5402c2aa98e2SPeter Wemm { 5403c2aa98e2SPeter Wemm if (RealUid == 0) 5404c2aa98e2SPeter Wemm RealUid = DefUid; 5405c2aa98e2SPeter Wemm if (RealGid == 0) 5406c2aa98e2SPeter Wemm RealGid = DefGid; 5407c2aa98e2SPeter Wemm } 5408c2aa98e2SPeter Wemm 5409c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */ 5410c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups) 5411c2aa98e2SPeter Wemm { 5412c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 541306f25ae9SGregory Neil Shapiro { 5414c2aa98e2SPeter Wemm syserr("mailfile: initgroups(%s, %d) failed", 5415c2aa98e2SPeter Wemm RealUserName, RealGid); 541640266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 541706f25ae9SGregory Neil Shapiro } 5418c2aa98e2SPeter Wemm } 5419c2aa98e2SPeter Wemm else 5420c2aa98e2SPeter Wemm { 5421c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 5422c2aa98e2SPeter Wemm 5423c2aa98e2SPeter Wemm gidset[0] = RealGid; 5424c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 542506f25ae9SGregory Neil Shapiro { 5426c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed"); 542740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 542806f25ae9SGregory Neil Shapiro } 5429c2aa98e2SPeter Wemm } 5430c2aa98e2SPeter Wemm 543106f25ae9SGregory Neil Shapiro /* 543206f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it. 543306f25ae9SGregory Neil Shapiro */ 5434c2aa98e2SPeter Wemm 543506f25ae9SGregory Neil Shapiro if (realfile != targetfile) 543606f25ae9SGregory Neil Shapiro { 5437605302a5SGregory Neil Shapiro char save; 5438605302a5SGregory Neil Shapiro 5439605302a5SGregory Neil Shapiro save = *realfile; 544006f25ae9SGregory Neil Shapiro *realfile = '\0'; 544106f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 544240266059SGregory Neil Shapiro sm_dprintf("mailfile: chroot %s\n", targetfile); 544306f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0) 5444c2aa98e2SPeter Wemm { 5445c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)", 544606f25ae9SGregory Neil Shapiro targetfile); 544740266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5448c2aa98e2SPeter Wemm } 5449605302a5SGregory Neil Shapiro *realfile = save; 5450c2aa98e2SPeter Wemm } 545106f25ae9SGregory Neil Shapiro 545206f25ae9SGregory Neil Shapiro if (tTd(11, 40)) 545340266059SGregory Neil Shapiro sm_dprintf("mailfile: deliver to %s\n", realfile); 545406f25ae9SGregory Neil Shapiro 5455c2aa98e2SPeter Wemm if (chdir("/") < 0) 545606f25ae9SGregory Neil Shapiro { 5457c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)"); 545840266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 545906f25ae9SGregory Neil Shapiro } 5460c2aa98e2SPeter Wemm 5461c2aa98e2SPeter Wemm /* now reset the group and user ids */ 5462c2aa98e2SPeter Wemm endpwent(); 546340266059SGregory Neil Shapiro sm_mbdb_terminate(); 5464c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn) 546506f25ae9SGregory Neil Shapiro { 5466c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid); 546740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 546806f25ae9SGregory Neil Shapiro } 5469c2aa98e2SPeter Wemm vendor_set_uid(RealUid); 5470c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn) 547106f25ae9SGregory Neil Shapiro { 5472c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid); 547340266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 547406f25ae9SGregory Neil Shapiro } 547506f25ae9SGregory Neil Shapiro 547606f25ae9SGregory Neil Shapiro if (tTd(11, 2)) 547740266059SGregory Neil Shapiro sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 547806f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 547906f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 548006f25ae9SGregory Neil Shapiro 5481c2aa98e2SPeter Wemm 5482c2aa98e2SPeter Wemm /* move into some "safe" directory */ 5483c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL) 5484c2aa98e2SPeter Wemm { 5485c2aa98e2SPeter Wemm char *q; 5486c2aa98e2SPeter Wemm 5487c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q) 5488c2aa98e2SPeter Wemm { 5489c2aa98e2SPeter Wemm q = strchr(p, ':'); 5490c2aa98e2SPeter Wemm if (q != NULL) 5491c2aa98e2SPeter Wemm *q = '\0'; 5492d0cef73dSGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 5493c2aa98e2SPeter Wemm if (q != NULL) 5494c2aa98e2SPeter Wemm *q++ = ':'; 5495c2aa98e2SPeter Wemm if (tTd(11, 20)) 549640266059SGregory Neil Shapiro sm_dprintf("mailfile: trydir %s\n", 549740266059SGregory Neil Shapiro buf); 5498c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 5499c2aa98e2SPeter Wemm break; 5500c2aa98e2SPeter Wemm } 5501c2aa98e2SPeter Wemm } 5502c2aa98e2SPeter Wemm 550306f25ae9SGregory Neil Shapiro /* 550406f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the 550506f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as 550606f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running 550706f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats 550806f25ae9SGregory Neil Shapiro ** root as nobody. 550906f25ae9SGregory Neil Shapiro */ 551006f25ae9SGregory Neil Shapiro 551106f25ae9SGregory Neil Shapiro #if HASLSTAT 551206f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 551306f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 551406f25ae9SGregory Neil Shapiro else 551506f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb); 551606f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 551706f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 551806f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 551906f25ae9SGregory Neil Shapiro 552006f25ae9SGregory Neil Shapiro if (err < 0) 552106f25ae9SGregory Neil Shapiro { 552206f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE; 552306f25ae9SGregory Neil Shapiro mode = FileMode; 552406f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL; 552506f25ae9SGregory Neil Shapiro } 552606f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 552706f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 552806f25ae9SGregory Neil Shapiro DontBlameSendmail) && 552906f25ae9SGregory Neil Shapiro stb.st_nlink != 1) || 553006f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode))) 553106f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 553206f25ae9SGregory Neil Shapiro else 553306f25ae9SGregory Neil Shapiro mode = stb.st_mode; 553406f25ae9SGregory Neil Shapiro 553506f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 5536c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK; 553706f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 5538c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK; 5539c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT; 554006f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags); 5541c2aa98e2SPeter Wemm if (f == NULL) 5542c2aa98e2SPeter Wemm { 554306f25ae9SGregory Neil Shapiro if (transienterror(errno)) 554406f25ae9SGregory Neil Shapiro { 554506f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s", 554606f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 554740266059SGregory Neil Shapiro sm_errstring(errno)); 554840266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 554906f25ae9SGregory Neil Shapiro } 555006f25ae9SGregory Neil Shapiro else 555106f25ae9SGregory Neil Shapiro { 555206f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s", 555306f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 555440266059SGregory Neil Shapiro sm_errstring(errno)); 555540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5556c2aa98e2SPeter Wemm } 555706f25ae9SGregory Neil Shapiro } 555840266059SGregory Neil Shapiro if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 555940266059SGregory Neil Shapiro &stb)) 5560c2aa98e2SPeter Wemm { 556106f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open"); 556240266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5563c2aa98e2SPeter Wemm } 556440266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 5565c2aa98e2SPeter Wemm { 556640266059SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s", 556740266059SGregory Neil Shapiro sm_errstring(errno)); 556840266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5569c2aa98e2SPeter Wemm } 5570c2aa98e2SPeter Wemm 557106f25ae9SGregory Neil Shapiro curoff = stb.st_size; 557206f25ae9SGregory Neil Shapiro 5573c2aa98e2SPeter Wemm if (ev != NULL) 557440266059SGregory Neil Shapiro sm_clrevent(ev); 5575c2aa98e2SPeter Wemm 5576d0cef73dSGregory Neil Shapiro memset(&mcibuf, '\0', sizeof(mcibuf)); 5577c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer; 5578c2aa98e2SPeter Wemm mcibuf.mci_out = f; 5579c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags)) 5580c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT; 5581c2aa98e2SPeter Wemm 5582c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 5583c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 5584c2aa98e2SPeter Wemm 5585c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5586c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 5587c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags)) 5588c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7; 5589c2aa98e2SPeter Wemm 5590c2aa98e2SPeter Wemm #if MIME7TO8 5591c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) && 5592c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) && 5593c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 559440266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 559540266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 5596c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 5597c2aa98e2SPeter Wemm { 5598c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 5599c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 560040266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 5601c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 5602c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8; 5603c2aa98e2SPeter Wemm } 560406f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 5605c2aa98e2SPeter Wemm 56064e4196cbSGregory Neil Shapiro if (!putfromline(&mcibuf, e) || 56074e4196cbSGregory Neil Shapiro !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) || 56084e4196cbSGregory Neil Shapiro !(*e->e_putbody)(&mcibuf, e, NULL) || 56094e4196cbSGregory Neil Shapiro !putline("\n", &mcibuf) || 56104e4196cbSGregory Neil Shapiro (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 561140266059SGregory Neil Shapiro (SuperSafe != SAFE_NO && 561240266059SGregory Neil Shapiro fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 56134e4196cbSGregory Neil Shapiro sm_io_error(f))) 5614c2aa98e2SPeter Wemm { 5615c2aa98e2SPeter Wemm setstat(EX_IOERR); 561606f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE 561740266059SGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 561840266059SGregory Neil Shapiro curoff); 561906f25ae9SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 5620c2aa98e2SPeter Wemm } 5621c2aa98e2SPeter Wemm 5622c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */ 5623c2aa98e2SPeter Wemm #if HASFCHMOD 562440266059SGregory Neil Shapiro (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 562540266059SGregory Neil Shapiro (MODE_T) mode); 562606f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */ 562706f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode); 562806f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */ 562940266059SGregory Neil Shapiro if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 563006f25ae9SGregory Neil Shapiro setstat(EX_IOERR); 563140266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 563206f25ae9SGregory Neil Shapiro (void) setuid(RealUid); 5633c2aa98e2SPeter Wemm exit(ExitStat); 5634c2aa98e2SPeter Wemm /* NOTREACHED */ 5635c2aa98e2SPeter Wemm } 5636c2aa98e2SPeter Wemm else 5637c2aa98e2SPeter Wemm { 5638c2aa98e2SPeter Wemm /* parent -- wait for exit status */ 5639c2aa98e2SPeter Wemm int st; 5640c2aa98e2SPeter Wemm 5641c2aa98e2SPeter Wemm st = waitfor(pid); 5642c2aa98e2SPeter Wemm if (st == -1) 5643c2aa98e2SPeter Wemm { 5644c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name); 564506f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 5646c2aa98e2SPeter Wemm } 5647c2aa98e2SPeter Wemm if (WIFEXITED(st)) 564840266059SGregory Neil Shapiro { 564940266059SGregory Neil Shapiro errno = 0; 5650c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 565140266059SGregory Neil Shapiro } 5652c2aa98e2SPeter Wemm else 5653c2aa98e2SPeter Wemm { 5654c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d", 5655c2aa98e2SPeter Wemm mailer->m_name, st); 565606f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE; 5657c2aa98e2SPeter Wemm } 5658c2aa98e2SPeter Wemm /* NOTREACHED */ 5659c2aa98e2SPeter Wemm } 5660c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 5661c2aa98e2SPeter Wemm } 5662c2aa98e2SPeter Wemm 5663c2aa98e2SPeter Wemm static void 5664b6bacd31SGregory Neil Shapiro mailfiletimeout(ignore) 5665b6bacd31SGregory Neil Shapiro int ignore; 5666c2aa98e2SPeter Wemm { 56678774250cSGregory Neil Shapiro /* 56688774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 56698774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 56708774250cSGregory Neil Shapiro ** DOING. 56718774250cSGregory Neil Shapiro */ 56728774250cSGregory Neil Shapiro 56738774250cSGregory Neil Shapiro errno = ETIMEDOUT; 5674c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1); 5675c2aa98e2SPeter Wemm } 567640266059SGregory Neil Shapiro /* 5677c2aa98e2SPeter Wemm ** HOSTSIGNATURE -- return the "signature" for a host. 5678c2aa98e2SPeter Wemm ** 5679c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it 5680c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be 5681c2aa98e2SPeter Wemm ** an ordered list of MX hosts. 5682c2aa98e2SPeter Wemm ** 5683c2aa98e2SPeter Wemm ** Parameters: 5684c2aa98e2SPeter Wemm ** m -- the mailer describing this host. 5685c2aa98e2SPeter Wemm ** host -- the host name. 5686c2aa98e2SPeter Wemm ** 5687c2aa98e2SPeter Wemm ** Returns: 5688c2aa98e2SPeter Wemm ** The signature for this host. 5689c2aa98e2SPeter Wemm ** 5690c2aa98e2SPeter Wemm ** Side Effects: 5691c2aa98e2SPeter Wemm ** Can tweak the symbol table. 5692c2aa98e2SPeter Wemm */ 569340266059SGregory Neil Shapiro 569406f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 5695c2aa98e2SPeter Wemm 569640266059SGregory Neil Shapiro char * 569706f25ae9SGregory Neil Shapiro hostsignature(m, host) 5698c2aa98e2SPeter Wemm register MAILER *m; 5699c2aa98e2SPeter Wemm char *host; 5700c2aa98e2SPeter Wemm { 5701c2aa98e2SPeter Wemm register char *p; 5702c2aa98e2SPeter Wemm register STAB *s; 570340266059SGregory Neil Shapiro time_t now; 570406f25ae9SGregory Neil Shapiro #if NAMED_BIND 570506f25ae9SGregory Neil Shapiro char sep = ':'; 570606f25ae9SGregory Neil Shapiro char prevsep = ':'; 5707c2aa98e2SPeter Wemm int i; 5708c2aa98e2SPeter Wemm int len; 5709c2aa98e2SPeter Wemm int nmx; 571006f25ae9SGregory Neil Shapiro int hl; 5711c2aa98e2SPeter Wemm char *hp; 5712c2aa98e2SPeter Wemm char *endp; 5713c2aa98e2SPeter Wemm int oldoptions = _res.options; 5714c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 571540266059SGregory Neil Shapiro unsigned short mxprefs[MAXMXHOSTS + 1]; 571606f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 571706f25ae9SGregory Neil Shapiro 571806f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 571940266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s)\n", host); 572006f25ae9SGregory Neil Shapiro 572106f25ae9SGregory Neil Shapiro /* 57228774250cSGregory Neil Shapiro ** If local delivery (and not remote), just return a constant. 572306f25ae9SGregory Neil Shapiro */ 572406f25ae9SGregory Neil Shapiro 57258774250cSGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags) && 572640266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") != 0 && 572740266059SGregory Neil Shapiro !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 572806f25ae9SGregory Neil Shapiro return "localhost"; 5729c2aa98e2SPeter Wemm 573013d88268SGregory Neil Shapiro /* an empty host does not have MX records */ 573113d88268SGregory Neil Shapiro if (*host == '\0') 573213d88268SGregory Neil Shapiro return "_empty_"; 573313d88268SGregory Neil Shapiro 5734c2aa98e2SPeter Wemm /* 5735c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records. 5736c2aa98e2SPeter Wemm */ 5737c2aa98e2SPeter Wemm 573840266059SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") != 0 || 573940266059SGregory Neil Shapiro CurEnv->e_sendmode == SM_DEFER) 5740c2aa98e2SPeter Wemm { 574140266059SGregory Neil Shapiro /* just an ordinary mailer or deferred mode */ 5742c2aa98e2SPeter Wemm return host; 5743c2aa98e2SPeter Wemm } 574406f25ae9SGregory Neil Shapiro #if NETUNIX 574506f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL && 574606f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0) 574706f25ae9SGregory Neil Shapiro { 574806f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */ 574906f25ae9SGregory Neil Shapiro return host; 575006f25ae9SGregory Neil Shapiro } 575106f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 5752c2aa98e2SPeter Wemm 5753c2aa98e2SPeter Wemm /* 5754c2aa98e2SPeter Wemm ** Look it up in the symbol table. 5755c2aa98e2SPeter Wemm */ 5756c2aa98e2SPeter Wemm 575740266059SGregory Neil Shapiro now = curtime(); 5758c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER); 575940266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 576040266059SGregory Neil Shapiro { 576140266059SGregory Neil Shapiro if (s->s_hostsig.hs_exp >= now) 576206f25ae9SGregory Neil Shapiro { 576306f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 576440266059SGregory Neil Shapiro sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 576540266059SGregory Neil Shapiro s->s_hostsig.hs_sig); 576640266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 576706f25ae9SGregory Neil Shapiro } 5768c2aa98e2SPeter Wemm 576940266059SGregory Neil Shapiro /* signature is expired: clear it */ 577040266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); 577140266059SGregory Neil Shapiro s->s_hostsig.hs_sig = NULL; 577240266059SGregory Neil Shapiro } 577340266059SGregory Neil Shapiro 577440266059SGregory Neil Shapiro /* set default TTL */ 577540266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 577640266059SGregory Neil Shapiro 5777c2aa98e2SPeter Wemm /* 577840266059SGregory Neil Shapiro ** Not already there or expired -- create a signature. 5779c2aa98e2SPeter Wemm */ 5780c2aa98e2SPeter Wemm 5781c2aa98e2SPeter Wemm #if NAMED_BIND 5782c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5783c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 5784c2aa98e2SPeter Wemm 5785c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp) 5786c2aa98e2SPeter Wemm { 578706f25ae9SGregory Neil Shapiro #if NETINET6 578806f25ae9SGregory Neil Shapiro if (*hp == '[') 578906f25ae9SGregory Neil Shapiro { 579006f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 5791c2aa98e2SPeter Wemm if (endp != NULL) 579206f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 579306f25ae9SGregory Neil Shapiro } 579406f25ae9SGregory Neil Shapiro else 579506f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 579606f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 579706f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 579806f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 579906f25ae9SGregory Neil Shapiro if (endp != NULL) 580006f25ae9SGregory Neil Shapiro { 580106f25ae9SGregory Neil Shapiro sep = *endp; 5802c2aa98e2SPeter Wemm *endp = '\0'; 580306f25ae9SGregory Neil Shapiro } 5804c2aa98e2SPeter Wemm 5805c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags)) 5806c2aa98e2SPeter Wemm { 5807c2aa98e2SPeter Wemm /* skip MX lookups */ 5808c2aa98e2SPeter Wemm nmx = 1; 5809c2aa98e2SPeter Wemm mxhosts[0] = hp; 5810c2aa98e2SPeter Wemm } 5811c2aa98e2SPeter Wemm else 5812c2aa98e2SPeter Wemm { 5813c2aa98e2SPeter Wemm auto int rcode; 581440266059SGregory Neil Shapiro int ttl; 5815c2aa98e2SPeter Wemm 581640266059SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true, 581740266059SGregory Neil Shapiro &ttl); 5818c2aa98e2SPeter Wemm if (nmx <= 0) 5819c2aa98e2SPeter Wemm { 582013058a91SGregory Neil Shapiro int save_errno; 5821c2aa98e2SPeter Wemm register MCI *mci; 5822c2aa98e2SPeter Wemm 5823c2aa98e2SPeter Wemm /* update the connection info for this host */ 582413058a91SGregory Neil Shapiro save_errno = errno; 5825c2aa98e2SPeter Wemm mci = mci_get(hp, m); 582613058a91SGregory Neil Shapiro mci->mci_errno = save_errno; 5827c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 5828193538b7SGregory Neil Shapiro mci->mci_lastuse = now; 582906f25ae9SGregory Neil Shapiro if (rcode == EX_NOHOST) 583006f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2", 583106f25ae9SGregory Neil Shapiro "550 Host unknown"); 583206f25ae9SGregory Neil Shapiro else 5833c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL); 5834c2aa98e2SPeter Wemm 5835c2aa98e2SPeter Wemm /* use the original host name as signature */ 5836c2aa98e2SPeter Wemm nmx = 1; 5837c2aa98e2SPeter Wemm mxhosts[0] = hp; 5838c2aa98e2SPeter Wemm } 583906f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 584040266059SGregory Neil Shapiro sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 584106f25ae9SGregory Neil Shapiro nmx, mxhosts[0]); 584240266059SGregory Neil Shapiro 584340266059SGregory Neil Shapiro /* 584440266059SGregory Neil Shapiro ** Set new TTL: we use only one! 584540266059SGregory Neil Shapiro ** We could try to use the minimum instead. 584640266059SGregory Neil Shapiro */ 584740266059SGregory Neil Shapiro 584840266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 5849c2aa98e2SPeter Wemm } 5850c2aa98e2SPeter Wemm 5851c2aa98e2SPeter Wemm len = 0; 5852c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5853c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1; 585440266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 585540266059SGregory Neil Shapiro len += strlen(s->s_hostsig.hs_sig) + 1; 585640266059SGregory Neil Shapiro if (len < 0 || len >= MAXHOSTSIGNATURE) 585706f25ae9SGregory Neil Shapiro { 585806f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 585906f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len); 586006f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE; 586106f25ae9SGregory Neil Shapiro } 586240266059SGregory Neil Shapiro p = sm_pmalloc_x(len); 586340266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 5864c2aa98e2SPeter Wemm { 586540266059SGregory Neil Shapiro (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 586640266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); /* XXX */ 586740266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 586806f25ae9SGregory Neil Shapiro hl = strlen(p); 586906f25ae9SGregory Neil Shapiro p += hl; 587006f25ae9SGregory Neil Shapiro *p++ = prevsep; 587106f25ae9SGregory Neil Shapiro len -= hl + 1; 5872c2aa98e2SPeter Wemm } 5873c2aa98e2SPeter Wemm else 587440266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 5875c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5876c2aa98e2SPeter Wemm { 587706f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]); 587806f25ae9SGregory Neil Shapiro if (len - 1 < hl || len <= 1) 587906f25ae9SGregory Neil Shapiro { 588006f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */ 588106f25ae9SGregory Neil Shapiro len = -1; 588206f25ae9SGregory Neil Shapiro break; 5883c2aa98e2SPeter Wemm } 588406f25ae9SGregory Neil Shapiro if (i != 0) 588506f25ae9SGregory Neil Shapiro { 588606f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1]) 588706f25ae9SGregory Neil Shapiro *p++ = ','; 588806f25ae9SGregory Neil Shapiro else 588906f25ae9SGregory Neil Shapiro *p++ = ':'; 589006f25ae9SGregory Neil Shapiro len--; 589106f25ae9SGregory Neil Shapiro } 589240266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], len); 589306f25ae9SGregory Neil Shapiro p += hl; 589406f25ae9SGregory Neil Shapiro len -= hl; 589506f25ae9SGregory Neil Shapiro } 589606f25ae9SGregory Neil Shapiro 589706f25ae9SGregory Neil Shapiro /* 589806f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE 589906f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts 590006f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file). 590106f25ae9SGregory Neil Shapiro */ 590206f25ae9SGregory Neil Shapiro 590306f25ae9SGregory Neil Shapiro if (len < 0) 590406f25ae9SGregory Neil Shapiro break; 5905c2aa98e2SPeter Wemm if (endp != NULL) 590606f25ae9SGregory Neil Shapiro *endp++ = sep; 590706f25ae9SGregory Neil Shapiro prevsep = sep; 5908c2aa98e2SPeter Wemm } 590940266059SGregory Neil Shapiro makelower(s->s_hostsig.hs_sig); 5910c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5911c2aa98e2SPeter Wemm _res.options = oldoptions; 591206f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 5913c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */ 591440266059SGregory Neil Shapiro /* 591540266059SGregory Neil Shapiro ** 'host' points to storage that will be freed after we are 591640266059SGregory Neil Shapiro ** done processing the current envelope, so we copy it. 591740266059SGregory Neil Shapiro */ 591840266059SGregory Neil Shapiro s->s_hostsig.hs_sig = sm_pstrdup_x(host); 591906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 5920c2aa98e2SPeter Wemm if (tTd(17, 1)) 592140266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 592240266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 5923c2aa98e2SPeter Wemm } 592440266059SGregory Neil Shapiro /* 592506f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 592606f25ae9SGregory Neil Shapiro ** 592706f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it 592806f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be 592906f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal 593006f25ae9SGregory Neil Shapiro ** MX preference values. 593106f25ae9SGregory Neil Shapiro ** 593206f25ae9SGregory Neil Shapiro ** Parameters: 593306f25ae9SGregory Neil Shapiro ** sig -- the host signature. 593406f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate. 593540266059SGregory Neil Shapiro ** mailer -- mailer. 593606f25ae9SGregory Neil Shapiro ** 593706f25ae9SGregory Neil Shapiro ** Returns: 593806f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array. 593906f25ae9SGregory Neil Shapiro ** 594006f25ae9SGregory Neil Shapiro ** Side Effects: 594106f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts. 594206f25ae9SGregory Neil Shapiro */ 594306f25ae9SGregory Neil Shapiro 594406f25ae9SGregory Neil Shapiro static int 594506f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer) 594606f25ae9SGregory Neil Shapiro char *sig; 594706f25ae9SGregory Neil Shapiro char **mxhosts; 594806f25ae9SGregory Neil Shapiro MAILER *mailer; 594906f25ae9SGregory Neil Shapiro { 595040266059SGregory Neil Shapiro unsigned short curpref = 0; 595140266059SGregory Neil Shapiro int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 595206f25ae9SGregory Neil Shapiro char *hp, *endp; 595340266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 595406f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS]; 595506f25ae9SGregory Neil Shapiro 595606f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp) 595706f25ae9SGregory Neil Shapiro { 595806f25ae9SGregory Neil Shapiro char sep = ':'; 595906f25ae9SGregory Neil Shapiro 596006f25ae9SGregory Neil Shapiro #if NETINET6 596106f25ae9SGregory Neil Shapiro if (*hp == '[') 596206f25ae9SGregory Neil Shapiro { 596306f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 596406f25ae9SGregory Neil Shapiro if (endp != NULL) 596506f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 596606f25ae9SGregory Neil Shapiro } 596706f25ae9SGregory Neil Shapiro else 596806f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 596906f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 597006f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 597106f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 597206f25ae9SGregory Neil Shapiro if (endp != NULL) 597306f25ae9SGregory Neil Shapiro { 597406f25ae9SGregory Neil Shapiro sep = *endp; 597506f25ae9SGregory Neil Shapiro *endp = '\0'; 597606f25ae9SGregory Neil Shapiro } 597706f25ae9SGregory Neil Shapiro 597806f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp; 597906f25ae9SGregory Neil Shapiro prefer[nmx] = curpref; 598006f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer)) 598106f25ae9SGregory Neil Shapiro rndm[nmx] = 0; 598206f25ae9SGregory Neil Shapiro else 598306f25ae9SGregory Neil Shapiro rndm[nmx] = get_random(); 598406f25ae9SGregory Neil Shapiro 598506f25ae9SGregory Neil Shapiro if (endp != NULL) 598606f25ae9SGregory Neil Shapiro { 598706f25ae9SGregory Neil Shapiro /* 598806f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs, 598906f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that 599006f25ae9SGregory Neil Shapiro ** means the preference for the next host will be 599106f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref. 599206f25ae9SGregory Neil Shapiro */ 599306f25ae9SGregory Neil Shapiro 599406f25ae9SGregory Neil Shapiro if (sep == ':') 599506f25ae9SGregory Neil Shapiro curpref++; 599606f25ae9SGregory Neil Shapiro 599706f25ae9SGregory Neil Shapiro *endp++ = sep; 599806f25ae9SGregory Neil Shapiro } 599906f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS) 600006f25ae9SGregory Neil Shapiro break; 600106f25ae9SGregory Neil Shapiro } 600206f25ae9SGregory Neil Shapiro 600306f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */ 600406f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++) 600506f25ae9SGregory Neil Shapiro { 600606f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++) 600706f25ae9SGregory Neil Shapiro { 600806f25ae9SGregory Neil Shapiro /* 600906f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only 601006f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records 601106f25ae9SGregory Neil Shapiro */ 601206f25ae9SGregory Neil Shapiro 601306f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j]) 601406f25ae9SGregory Neil Shapiro break; 601506f25ae9SGregory Neil Shapiro 601606f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] || 601706f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 601806f25ae9SGregory Neil Shapiro { 601940266059SGregory Neil Shapiro register unsigned short tempp; 602006f25ae9SGregory Neil Shapiro register long tempr; 602106f25ae9SGregory Neil Shapiro register char *temp1; 602206f25ae9SGregory Neil Shapiro 602306f25ae9SGregory Neil Shapiro tempp = prefer[i]; 602406f25ae9SGregory Neil Shapiro prefer[i] = prefer[j]; 602506f25ae9SGregory Neil Shapiro prefer[j] = tempp; 602606f25ae9SGregory Neil Shapiro temp1 = mxhosts[i]; 602706f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j]; 602806f25ae9SGregory Neil Shapiro mxhosts[j] = temp1; 602906f25ae9SGregory Neil Shapiro tempr = rndm[i]; 603006f25ae9SGregory Neil Shapiro rndm[i] = rndm[j]; 603106f25ae9SGregory Neil Shapiro rndm[j] = tempr; 603206f25ae9SGregory Neil Shapiro } 603306f25ae9SGregory Neil Shapiro } 603406f25ae9SGregory Neil Shapiro } 603506f25ae9SGregory Neil Shapiro return nmx; 603606f25ae9SGregory Neil Shapiro } 603706f25ae9SGregory Neil Shapiro 603806f25ae9SGregory Neil Shapiro # if STARTTLS 603906f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL; 604040266059SGregory Neil Shapiro static bool tls_ok_clt = true; 604106f25ae9SGregory Neil Shapiro 604240266059SGregory Neil Shapiro /* 604340266059SGregory Neil Shapiro ** SETCLTTLS -- client side TLS: allow/disallow. 604440266059SGregory Neil Shapiro ** 604540266059SGregory Neil Shapiro ** Parameters: 604640266059SGregory Neil Shapiro ** tls_ok -- should tls be done? 604740266059SGregory Neil Shapiro ** 604840266059SGregory Neil Shapiro ** Returns: 604940266059SGregory Neil Shapiro ** none. 605040266059SGregory Neil Shapiro ** 605140266059SGregory Neil Shapiro ** Side Effects: 605240266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 605340266059SGregory Neil Shapiro */ 605440266059SGregory Neil Shapiro 605540266059SGregory Neil Shapiro void 605640266059SGregory Neil Shapiro setclttls(tls_ok) 605740266059SGregory Neil Shapiro bool tls_ok; 605840266059SGregory Neil Shapiro { 605940266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 606040266059SGregory Neil Shapiro return; 606140266059SGregory Neil Shapiro } 606240266059SGregory Neil Shapiro /* 606306f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS 606406f25ae9SGregory Neil Shapiro ** 606506f25ae9SGregory Neil Shapiro ** Parameters: 606640266059SGregory Neil Shapiro ** tls_ok -- should tls initialization be done? 606706f25ae9SGregory Neil Shapiro ** 606806f25ae9SGregory Neil Shapiro ** Returns: 606906f25ae9SGregory Neil Shapiro ** succeeded? 607040266059SGregory Neil Shapiro ** 607140266059SGregory Neil Shapiro ** Side Effects: 607240266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 607306f25ae9SGregory Neil Shapiro */ 607406f25ae9SGregory Neil Shapiro 607506f25ae9SGregory Neil Shapiro bool 607640266059SGregory Neil Shapiro initclttls(tls_ok) 607740266059SGregory Neil Shapiro bool tls_ok; 607806f25ae9SGregory Neil Shapiro { 607940266059SGregory Neil Shapiro if (!tls_ok_clt) 608040266059SGregory Neil Shapiro return false; 608140266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 608240266059SGregory Neil Shapiro if (!tls_ok_clt) 608340266059SGregory Neil Shapiro return false; 608406f25ae9SGregory Neil Shapiro if (clt_ctx != NULL) 608540266059SGregory Neil Shapiro return true; /* already done */ 60869bd497b8SGregory Neil Shapiro tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, Clt_SSL_Options, false, 60879bd497b8SGregory Neil Shapiro CltCertFile, CltKeyFile, 60889bd497b8SGregory Neil Shapiro CACertPath, CACertFile, DHParams); 608940266059SGregory Neil Shapiro return tls_ok_clt; 609006f25ae9SGregory Neil Shapiro } 609106f25ae9SGregory Neil Shapiro 609240266059SGregory Neil Shapiro /* 609306f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side) 609406f25ae9SGregory Neil Shapiro ** 609506f25ae9SGregory Neil Shapiro ** Parameters: 609606f25ae9SGregory Neil Shapiro ** m -- the mailer. 609706f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 609806f25ae9SGregory Neil Shapiro ** e -- the envelope. 609906f25ae9SGregory Neil Shapiro ** 610006f25ae9SGregory Neil Shapiro ** Returns: 610106f25ae9SGregory Neil Shapiro ** success? 610206f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_ 610306f25ae9SGregory Neil Shapiro ** that denotes which stage failed.) 610406f25ae9SGregory Neil Shapiro */ 610506f25ae9SGregory Neil Shapiro 610606f25ae9SGregory Neil Shapiro static int 610706f25ae9SGregory Neil Shapiro starttls(m, mci, e) 610806f25ae9SGregory Neil Shapiro MAILER *m; 610906f25ae9SGregory Neil Shapiro MCI *mci; 611006f25ae9SGregory Neil Shapiro ENVELOPE *e; 611106f25ae9SGregory Neil Shapiro { 611206f25ae9SGregory Neil Shapiro int smtpresult; 611342e5d165SGregory Neil Shapiro int result = 0; 611442e5d165SGregory Neil Shapiro int rfd, wfd; 611506f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL; 611640266059SGregory Neil Shapiro time_t tlsstart; 611706f25ae9SGregory Neil Shapiro 611840266059SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls(true)) 611942e5d165SGregory Neil Shapiro return EX_TEMPFAIL; 61209bd497b8SGregory Neil Shapiro 61219bd497b8SGregory Neil Shapiro # if USE_OPENSSL_ENGINE 61226f9c8e5bSGregory Neil Shapiro if (!SSLEngineInitialized && !SSL_set_engine(NULL)) 61239bd497b8SGregory Neil Shapiro { 61249bd497b8SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 61259bd497b8SGregory Neil Shapiro "STARTTLS=client, SSL_set_engine=failed"); 61269bd497b8SGregory Neil Shapiro return EX_TEMPFAIL; 61279bd497b8SGregory Neil Shapiro } 61286f9c8e5bSGregory Neil Shapiro SSLEngineInitialized = true; 61299bd497b8SGregory Neil Shapiro # endif /* USE_OPENSSL_ENGINE */ 61309bd497b8SGregory Neil Shapiro 613106f25ae9SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci); 613206f25ae9SGregory Neil Shapiro 613306f25ae9SGregory Neil Shapiro /* get the reply */ 6134e92d3f3fSGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL, 6135e92d3f3fSGregory Neil Shapiro XS_STARTTLS); 613606f25ae9SGregory Neil Shapiro 613706f25ae9SGregory Neil Shapiro /* check return code from server */ 61384e4196cbSGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 4) 613906f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 614006f25ae9SGregory Neil Shapiro if (smtpresult == 501) 614106f25ae9SGregory Neil Shapiro return EX_USAGE; 614206f25ae9SGregory Neil Shapiro if (smtpresult == -1) 614306f25ae9SGregory Neil Shapiro return smtpresult; 61444e4196cbSGregory Neil Shapiro 61454e4196cbSGregory Neil Shapiro /* not an expected reply but we have to deal with it */ 61464e4196cbSGregory Neil Shapiro if (REPLYTYPE(smtpresult) == 5) 61474e4196cbSGregory Neil Shapiro return EX_UNAVAILABLE; 614806f25ae9SGregory Neil Shapiro if (smtpresult != 220) 614906f25ae9SGregory Neil Shapiro return EX_PROTOCOL; 615006f25ae9SGregory Neil Shapiro 615106f25ae9SGregory Neil Shapiro if (LogLevel > 13) 615240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 615306f25ae9SGregory Neil Shapiro 615406f25ae9SGregory Neil Shapiro /* start connection */ 615506f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 615606f25ae9SGregory Neil Shapiro { 615706f25ae9SGregory Neil Shapiro if (LogLevel > 5) 615806f25ae9SGregory Neil Shapiro { 615940266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 616040266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_new failed"); 616106f25ae9SGregory Neil Shapiro if (LogLevel > 9) 6162552d4955SGregory Neil Shapiro tlslogerr(LOG_WARNING, "client"); 616306f25ae9SGregory Neil Shapiro } 616406f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 616506f25ae9SGregory Neil Shapiro } 616606f25ae9SGregory Neil Shapiro 616740266059SGregory Neil Shapiro rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 616840266059SGregory Neil Shapiro wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 616942e5d165SGregory Neil Shapiro 617006f25ae9SGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */ 617142e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 || 617240266059SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 617340266059SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 617406f25ae9SGregory Neil Shapiro { 617506f25ae9SGregory Neil Shapiro if (LogLevel > 5) 617606f25ae9SGregory Neil Shapiro { 617740266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 617840266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_xfd failed=%d", 617940266059SGregory Neil Shapiro result); 618006f25ae9SGregory Neil Shapiro if (LogLevel > 9) 6181552d4955SGregory Neil Shapiro tlslogerr(LOG_WARNING, "client"); 618206f25ae9SGregory Neil Shapiro } 618306f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 618406f25ae9SGregory Neil Shapiro } 618506f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl); 618640266059SGregory Neil Shapiro tlsstart = curtime(); 618740266059SGregory Neil Shapiro 618840266059SGregory Neil Shapiro ssl_retry: 618906f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0) 619006f25ae9SGregory Neil Shapiro { 61914e4196cbSGregory Neil Shapiro int i, ssl_err; 619206f25ae9SGregory Neil Shapiro 61934e4196cbSGregory Neil Shapiro ssl_err = SSL_get_error(clt_ssl, result); 61944e4196cbSGregory Neil Shapiro i = tls_retry(clt_ssl, rfd, wfd, tlsstart, 61954e4196cbSGregory Neil Shapiro TimeOuts.to_starttls, ssl_err, "client"); 61964e4196cbSGregory Neil Shapiro if (i > 0) 61974e4196cbSGregory Neil Shapiro goto ssl_retry; 619840266059SGregory Neil Shapiro 619913bd1963SGregory Neil Shapiro if (LogLevel > 5) 620013bd1963SGregory Neil Shapiro { 6201ba00ec3dSGregory Neil Shapiro unsigned long l; 6202ba00ec3dSGregory Neil Shapiro const char *sr; 6203ba00ec3dSGregory Neil Shapiro 6204ba00ec3dSGregory Neil Shapiro l = ERR_peek_error(); 6205ba00ec3dSGregory Neil Shapiro sr = ERR_reason_error_string(l); 62064e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 6207ba00ec3dSGregory Neil Shapiro "STARTTLS=client, error: connect failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d", 6208ba00ec3dSGregory Neil Shapiro result, sr == NULL ? "unknown" : sr, ssl_err, 6209ba00ec3dSGregory Neil Shapiro errno, i); 6210ba00ec3dSGregory Neil Shapiro if (LogLevel > 9) 6211552d4955SGregory Neil Shapiro tlslogerr(LOG_WARNING, "client"); 621213bd1963SGregory Neil Shapiro } 621340266059SGregory Neil Shapiro 621406f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 621506f25ae9SGregory Neil Shapiro clt_ssl = NULL; 621606f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 621706f25ae9SGregory Neil Shapiro } 621806f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl; 621940266059SGregory Neil Shapiro result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 622040266059SGregory Neil Shapiro &mci->mci_macro, true); 622106f25ae9SGregory Neil Shapiro 622240266059SGregory Neil Shapiro /* switch to use TLS... */ 622306f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 622406f25ae9SGregory Neil Shapiro return EX_OK; 622506f25ae9SGregory Neil Shapiro 622606f25ae9SGregory Neil Shapiro /* failure */ 622706f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 622806f25ae9SGregory Neil Shapiro clt_ssl = NULL; 622906f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 623006f25ae9SGregory Neil Shapiro } 623140266059SGregory Neil Shapiro /* 623206f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side) 623306f25ae9SGregory Neil Shapiro ** 623406f25ae9SGregory Neil Shapiro ** Parameters: 623506f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 623606f25ae9SGregory Neil Shapiro ** 623706f25ae9SGregory Neil Shapiro ** Returns: 623806f25ae9SGregory Neil Shapiro ** success? 623906f25ae9SGregory Neil Shapiro */ 624040266059SGregory Neil Shapiro 624140266059SGregory Neil Shapiro static int 624206f25ae9SGregory Neil Shapiro endtlsclt(mci) 624306f25ae9SGregory Neil Shapiro MCI *mci; 624406f25ae9SGregory Neil Shapiro { 624506f25ae9SGregory Neil Shapiro int r; 624606f25ae9SGregory Neil Shapiro 624706f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags)) 624806f25ae9SGregory Neil Shapiro return EX_OK; 624906f25ae9SGregory Neil Shapiro r = endtls(mci->mci_ssl, "client"); 625006f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 625106f25ae9SGregory Neil Shapiro return r; 625206f25ae9SGregory Neil Shapiro } 625340266059SGregory Neil Shapiro # endif /* STARTTLS */ 625440266059SGregory Neil Shapiro # if STARTTLS || SASL 625540266059SGregory Neil Shapiro /* 625640266059SGregory Neil Shapiro ** ISCLTFLGSET -- check whether client flag is set. 625706f25ae9SGregory Neil Shapiro ** 625806f25ae9SGregory Neil Shapiro ** Parameters: 625940266059SGregory Neil Shapiro ** e -- envelope. 626040266059SGregory Neil Shapiro ** flag -- flag to check in {client_flags} 626106f25ae9SGregory Neil Shapiro ** 626206f25ae9SGregory Neil Shapiro ** Returns: 626340266059SGregory Neil Shapiro ** true iff flag is set. 626406f25ae9SGregory Neil Shapiro */ 626506f25ae9SGregory Neil Shapiro 626640266059SGregory Neil Shapiro static bool 626740266059SGregory Neil Shapiro iscltflgset(e, flag) 626840266059SGregory Neil Shapiro ENVELOPE *e; 626940266059SGregory Neil Shapiro int flag; 627006f25ae9SGregory Neil Shapiro { 627140266059SGregory Neil Shapiro char *p; 6272602a2b1bSGregory Neil Shapiro 627340266059SGregory Neil Shapiro p = macvalue(macid("{client_flags}"), e); 627440266059SGregory Neil Shapiro if (p == NULL) 627540266059SGregory Neil Shapiro return false; 627640266059SGregory Neil Shapiro for (; *p != '\0'; p++) 627706f25ae9SGregory Neil Shapiro { 627840266059SGregory Neil Shapiro /* look for just this one flag */ 627940266059SGregory Neil Shapiro if (*p == (char) flag) 628040266059SGregory Neil Shapiro return true; 628106f25ae9SGregory Neil Shapiro } 628240266059SGregory Neil Shapiro return false; 628306f25ae9SGregory Neil Shapiro } 628440266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 6285