1c2aa98e2SPeter Wemm /* 240266059SGregory Neil Shapiro * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 1540266059SGregory Neil Shapiro #include <sys/time.h> 1606f25ae9SGregory Neil Shapiro 1794c01205SGregory Neil Shapiro SM_RCSID("@(#)$Id: deliver.c,v 8.939 2002/05/25 00:46:00 gshapiro 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 3140266059SGregory Neil Shapiro void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool)); 3206f25ae9SGregory Neil Shapiro static int deliver __P((ENVELOPE *, ADDRESS *)); 3306f25ae9SGregory Neil Shapiro static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 3406f25ae9SGregory Neil Shapiro static void mailfiletimeout __P((void)); 3506f25ae9SGregory Neil Shapiro static int parse_hostsignature __P((char *, char **, MAILER *)); 3606f25ae9SGregory Neil Shapiro static void sendenvelope __P((ENVELOPE *, int)); 3740266059SGregory Neil Shapiro extern MCI *mci_new __P((SM_RPOOL_T *)); 3840266059SGregory Neil Shapiro static int coloncmp __P((const char *, const char *)); 39c2aa98e2SPeter Wemm 4006f25ae9SGregory Neil Shapiro #if STARTTLS 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); 12640266059SGregory Neil Shapiro printaddr(&e->e_from, false); 12740266059SGregory Neil Shapiro sm_dprintf("\te_flags = "); 128c2aa98e2SPeter Wemm printenvflags(e); 12940266059SGregory Neil Shapiro sm_dprintf("sendqueue:\n"); 13040266059SGregory Neil Shapiro printaddr(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 "); 18740266059SGregory Neil Shapiro printaddr(&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"); 21840266059SGregory Neil Shapiro printaddr(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 "); 23640266059SGregory Neil Shapiro printaddr(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 "); 24740266059SGregory Neil Shapiro printaddr(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 30706f25ae9SGregory Neil Shapiro if (FallBackMX != NULL && 30806f25ae9SGregory 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)) 31940266059SGregory Neil Shapiro sm_dprintf(" ... FallBackMX\n"); 32006f25ae9SGregory Neil Shapiro 32140266059SGregory Neil Shapiro len = strlen(FallBackMX) + 1; 32240266059SGregory Neil Shapiro p = sm_rpool_malloc_x(e->e_rpool, len); 32340266059SGregory 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 #if _FFR_QUARANTINE 36340266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE && 36440266059SGregory Neil Shapiro e->e_quarmsg != NULL) 36540266059SGregory Neil Shapiro { 36640266059SGregory Neil Shapiro if (tTd(13, 30)) 36740266059SGregory Neil Shapiro sm_dprintf(" ... quarantine: %s\n", 36840266059SGregory Neil Shapiro e->e_quarmsg); 36940266059SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 37040266059SGregory Neil Shapiro expensive = true; 37140266059SGregory Neil Shapiro } 37240266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 373c2aa98e2SPeter Wemm else 374c2aa98e2SPeter Wemm { 375c2aa98e2SPeter Wemm if (tTd(13, 30)) 37640266059SGregory Neil Shapiro sm_dprintf(" ... deliverable\n"); 37740266059SGregory Neil Shapiro somedeliveries = true; 378c2aa98e2SPeter Wemm } 379c2aa98e2SPeter Wemm } 380c2aa98e2SPeter Wemm 381c2aa98e2SPeter Wemm if (owner != NULL && otherowners > 0) 382c2aa98e2SPeter Wemm { 383c2aa98e2SPeter Wemm /* 384c2aa98e2SPeter Wemm ** Split this envelope into two. 385c2aa98e2SPeter Wemm */ 386c2aa98e2SPeter Wemm 38740266059SGregory Neil Shapiro ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, 38840266059SGregory Neil Shapiro sizeof *ee); 38940266059SGregory Neil Shapiro STRUCTCOPY(*e, *ee); 39006f25ae9SGregory Neil Shapiro ee->e_message = NULL; 391c2aa98e2SPeter Wemm ee->e_id = NULL; 39206f25ae9SGregory Neil Shapiro assign_queueid(ee); 393c2aa98e2SPeter Wemm 394c2aa98e2SPeter Wemm if (tTd(13, 1)) 39540266059SGregory Neil Shapiro sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 39640266059SGregory Neil Shapiro e->e_id, ee->e_id, owner, 39740266059SGregory Neil Shapiro otherowners); 398c2aa98e2SPeter Wemm 39940266059SGregory Neil Shapiro ee->e_header = copyheader(e->e_header, ee->e_rpool); 40040266059SGregory Neil Shapiro ee->e_sendqueue = copyqueue(e->e_sendqueue, 40140266059SGregory Neil Shapiro ee->e_rpool); 40240266059SGregory Neil Shapiro ee->e_errorqueue = copyqueue(e->e_errorqueue, 40340266059SGregory Neil Shapiro ee->e_rpool); 404c2aa98e2SPeter Wemm ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 405c2aa98e2SPeter Wemm ee->e_flags |= EF_NORECEIPT; 40640266059SGregory Neil Shapiro setsender(owner, ee, NULL, '\0', true); 407c2aa98e2SPeter Wemm if (tTd(13, 5)) 408c2aa98e2SPeter Wemm { 40940266059SGregory Neil Shapiro sm_dprintf("sendall(split): QS_SENDER "); 41040266059SGregory Neil Shapiro printaddr(&ee->e_from, false); 411c2aa98e2SPeter Wemm } 41206f25ae9SGregory Neil Shapiro ee->e_from.q_state = QS_SENDER; 413c2aa98e2SPeter Wemm ee->e_dfp = NULL; 41406f25ae9SGregory Neil Shapiro ee->e_lockfp = NULL; 415c2aa98e2SPeter Wemm ee->e_xfp = NULL; 41640266059SGregory Neil Shapiro ee->e_qgrp = e->e_qgrp; 41740266059SGregory Neil Shapiro ee->e_qdir = e->e_qdir; 418c2aa98e2SPeter Wemm ee->e_errormode = EM_MAIL; 419c2aa98e2SPeter Wemm ee->e_sibling = splitenv; 42006f25ae9SGregory Neil Shapiro ee->e_statmsg = NULL; 42140266059SGregory Neil Shapiro #if _FFR_QUARANTINE 42240266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 42340266059SGregory Neil Shapiro ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 42440266059SGregory Neil Shapiro e->e_quarmsg); 42540266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 426c2aa98e2SPeter Wemm splitenv = ee; 427c2aa98e2SPeter Wemm 428c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 429c2aa98e2SPeter Wemm { 430c2aa98e2SPeter Wemm if (q->q_owner == owner) 431c2aa98e2SPeter Wemm { 43206f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 433c2aa98e2SPeter Wemm if (tTd(13, 6)) 43440266059SGregory Neil Shapiro sm_dprintf("\t... stripping %s from original envelope\n", 435c2aa98e2SPeter Wemm q->q_paddr); 436c2aa98e2SPeter Wemm } 437c2aa98e2SPeter Wemm } 438c2aa98e2SPeter Wemm for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 439c2aa98e2SPeter Wemm { 440c2aa98e2SPeter Wemm if (q->q_owner != owner) 441c2aa98e2SPeter Wemm { 44206f25ae9SGregory Neil Shapiro q->q_state = QS_CLONED; 443c2aa98e2SPeter Wemm if (tTd(13, 6)) 44440266059SGregory Neil Shapiro sm_dprintf("\t... dropping %s from cloned envelope\n", 445c2aa98e2SPeter Wemm q->q_paddr); 446c2aa98e2SPeter Wemm } 447c2aa98e2SPeter Wemm else 448c2aa98e2SPeter Wemm { 449c2aa98e2SPeter Wemm /* clear DSN parameters */ 450c2aa98e2SPeter Wemm q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 451c2aa98e2SPeter Wemm q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 452c2aa98e2SPeter Wemm if (tTd(13, 6)) 45340266059SGregory Neil Shapiro sm_dprintf("\t... moving %s to cloned envelope\n", 454c2aa98e2SPeter Wemm q->q_paddr); 455c2aa98e2SPeter Wemm } 456c2aa98e2SPeter Wemm } 457c2aa98e2SPeter Wemm 458c2aa98e2SPeter Wemm if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 45940266059SGregory Neil Shapiro dup_queue_file(e, ee, DATAFL_LETTER); 46006f25ae9SGregory Neil Shapiro 46106f25ae9SGregory Neil Shapiro /* 46206f25ae9SGregory Neil Shapiro ** Give the split envelope access to the parent 46306f25ae9SGregory Neil Shapiro ** transcript file for errors obtained while 46406f25ae9SGregory Neil Shapiro ** processing the recipients (done before the 46506f25ae9SGregory Neil Shapiro ** envelope splitting). 46606f25ae9SGregory Neil Shapiro */ 46706f25ae9SGregory Neil Shapiro 46806f25ae9SGregory Neil Shapiro if (e->e_xfp != NULL) 46940266059SGregory Neil Shapiro ee->e_xfp = sm_io_dup(e->e_xfp); 47006f25ae9SGregory Neil Shapiro 47106f25ae9SGregory Neil Shapiro /* failed to dup e->e_xfp, start a new transcript */ 47206f25ae9SGregory Neil Shapiro if (ee->e_xfp == NULL) 473c2aa98e2SPeter Wemm openxscript(ee); 47406f25ae9SGregory Neil Shapiro 475065a643dSPeter Wemm if (mode != SM_VERIFY && LogLevel > 4) 47640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 47740266059SGregory Neil Shapiro "%s: clone: owner=%s", 47840266059SGregory Neil Shapiro ee->e_id, owner); 479c2aa98e2SPeter Wemm } 480c2aa98e2SPeter Wemm } 481c2aa98e2SPeter Wemm 482c2aa98e2SPeter Wemm if (owner != NULL) 483c2aa98e2SPeter Wemm { 48440266059SGregory Neil Shapiro setsender(owner, e, NULL, '\0', true); 485c2aa98e2SPeter Wemm if (tTd(13, 5)) 486c2aa98e2SPeter Wemm { 48740266059SGregory Neil Shapiro sm_dprintf("sendall(owner): QS_SENDER "); 48840266059SGregory Neil Shapiro printaddr(&e->e_from, false); 489c2aa98e2SPeter Wemm } 49006f25ae9SGregory Neil Shapiro e->e_from.q_state = QS_SENDER; 491c2aa98e2SPeter Wemm e->e_errormode = EM_MAIL; 492c2aa98e2SPeter Wemm e->e_flags |= EF_NORECEIPT; 493c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 494c2aa98e2SPeter Wemm } 495c2aa98e2SPeter Wemm 496c2aa98e2SPeter Wemm /* if nothing to be delivered, just queue up everything */ 49740266059SGregory Neil Shapiro if (!somedeliveries && !WILL_BE_QUEUED(mode) && 498c2aa98e2SPeter Wemm mode != SM_VERIFY) 499c2aa98e2SPeter Wemm { 50040266059SGregory Neil Shapiro time_t now; 501193538b7SGregory Neil Shapiro 502c2aa98e2SPeter Wemm if (tTd(13, 29)) 50340266059SGregory Neil Shapiro sm_dprintf("No deliveries: auto-queuing\n"); 504c2aa98e2SPeter Wemm mode = SM_QUEUE; 50540266059SGregory Neil Shapiro now = curtime(); 506c2aa98e2SPeter Wemm 507c2aa98e2SPeter Wemm /* treat this as a delivery in terms of counting tries */ 508193538b7SGregory Neil Shapiro e->e_dtime = now; 509c2aa98e2SPeter Wemm if (!expensive) 510c2aa98e2SPeter Wemm e->e_ntries++; 511c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 512c2aa98e2SPeter Wemm { 513193538b7SGregory Neil Shapiro ee->e_dtime = now; 514c2aa98e2SPeter Wemm if (!expensive) 515c2aa98e2SPeter Wemm ee->e_ntries++; 516c2aa98e2SPeter Wemm } 517c2aa98e2SPeter Wemm } 518c2aa98e2SPeter Wemm 51940266059SGregory Neil Shapiro if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || 52040266059SGregory Neil Shapiro (mode != SM_VERIFY && SuperSafe == SAFE_REALLY)) && 521c2aa98e2SPeter Wemm (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 522c2aa98e2SPeter Wemm { 52340266059SGregory Neil Shapiro bool msync; 52440266059SGregory Neil Shapiro 52542e5d165SGregory Neil Shapiro /* 52642e5d165SGregory Neil Shapiro ** Be sure everything is instantiated in the queue. 52742e5d165SGregory Neil Shapiro ** Split envelopes first in case the machine crashes. 52842e5d165SGregory Neil Shapiro ** If the original were done first, we may lose 52942e5d165SGregory Neil Shapiro ** recipients. 53042e5d165SGregory Neil Shapiro */ 53142e5d165SGregory Neil Shapiro 53240266059SGregory Neil Shapiro #if !HASFLOCK 53340266059SGregory Neil Shapiro msync = false; 53440266059SGregory Neil Shapiro #else /* !HASFLOCK */ 53540266059SGregory Neil Shapiro msync = mode == SM_FORK; 53640266059SGregory Neil Shapiro #endif /* !HASFLOCK */ 53740266059SGregory Neil Shapiro 538c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 53940266059SGregory Neil Shapiro queueup(ee, WILL_BE_QUEUED(mode), msync); 54040266059SGregory Neil Shapiro queueup(e, WILL_BE_QUEUED(mode), msync); 541c2aa98e2SPeter Wemm } 542c2aa98e2SPeter Wemm 543c2aa98e2SPeter Wemm if (tTd(62, 10)) 544c2aa98e2SPeter Wemm checkfds("after envelope splitting"); 545c2aa98e2SPeter Wemm 546c2aa98e2SPeter Wemm /* 547c2aa98e2SPeter Wemm ** If we belong in background, fork now. 548c2aa98e2SPeter Wemm */ 549c2aa98e2SPeter Wemm 550c2aa98e2SPeter Wemm if (tTd(13, 20)) 551c2aa98e2SPeter Wemm { 55240266059SGregory Neil Shapiro sm_dprintf("sendall: final mode = %c\n", mode); 553c2aa98e2SPeter Wemm if (tTd(13, 21)) 554c2aa98e2SPeter Wemm { 55540266059SGregory Neil Shapiro sm_dprintf("\n================ Final Send Queue(s) =====================\n"); 55640266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 557c2aa98e2SPeter Wemm e->e_id, e->e_from.q_paddr); 55840266059SGregory Neil Shapiro printaddr(e->e_sendqueue, true); 559c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 560c2aa98e2SPeter Wemm { 56140266059SGregory Neil Shapiro sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 562c2aa98e2SPeter Wemm ee->e_id, ee->e_from.q_paddr); 56340266059SGregory Neil Shapiro printaddr(ee->e_sendqueue, true); 564c2aa98e2SPeter Wemm } 56540266059SGregory Neil Shapiro sm_dprintf("==========================================================\n\n"); 566c2aa98e2SPeter Wemm } 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm switch (mode) 569c2aa98e2SPeter Wemm { 570c2aa98e2SPeter Wemm case SM_VERIFY: 571c2aa98e2SPeter Wemm Verbose = 2; 572c2aa98e2SPeter Wemm break; 573c2aa98e2SPeter Wemm 574c2aa98e2SPeter Wemm case SM_QUEUE: 575c2aa98e2SPeter Wemm case SM_DEFER: 576c2aa98e2SPeter Wemm #if HASFLOCK 577c2aa98e2SPeter Wemm queueonly: 57806f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 579c2aa98e2SPeter Wemm if (e->e_nrcpts > 0) 580c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 58140266059SGregory Neil Shapiro dropenvelope(e, splitenv != NULL, true); 582c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 583c2aa98e2SPeter Wemm { 584c2aa98e2SPeter Wemm if (ee->e_nrcpts > 0) 585c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 58640266059SGregory Neil Shapiro dropenvelope(ee, false, true); 587c2aa98e2SPeter Wemm } 588c2aa98e2SPeter Wemm return; 589c2aa98e2SPeter Wemm 590c2aa98e2SPeter Wemm case SM_FORK: 591c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 59240266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 593c2aa98e2SPeter Wemm 594c2aa98e2SPeter Wemm #if !HASFLOCK 595c2aa98e2SPeter Wemm /* 596c2aa98e2SPeter Wemm ** Since fcntl locking has the interesting semantic that 597c2aa98e2SPeter Wemm ** the lock is owned by a process, not by an open file 598c2aa98e2SPeter Wemm ** descriptor, we have to flush this to the queue, and 599c2aa98e2SPeter Wemm ** then restart from scratch in the child. 600c2aa98e2SPeter Wemm */ 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm { 603c2aa98e2SPeter Wemm /* save id for future use */ 604c2aa98e2SPeter Wemm char *qid = e->e_id; 605c2aa98e2SPeter Wemm 606c2aa98e2SPeter Wemm /* now drop the envelope in the parent */ 607c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 60840266059SGregory Neil Shapiro dropenvelope(e, splitenv != NULL, false); 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm /* arrange to reacquire lock after fork */ 611c2aa98e2SPeter Wemm e->e_id = qid; 612c2aa98e2SPeter Wemm } 613c2aa98e2SPeter Wemm 614c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 615c2aa98e2SPeter Wemm { 616c2aa98e2SPeter Wemm /* save id for future use */ 617c2aa98e2SPeter Wemm char *qid = ee->e_id; 618c2aa98e2SPeter Wemm 619c2aa98e2SPeter Wemm /* drop envelope in parent */ 620c2aa98e2SPeter Wemm ee->e_flags |= EF_INQUEUE; 62140266059SGregory Neil Shapiro dropenvelope(ee, false, false); 622c2aa98e2SPeter Wemm 623c2aa98e2SPeter Wemm /* and save qid for reacquisition */ 624c2aa98e2SPeter Wemm ee->e_id = qid; 625c2aa98e2SPeter Wemm } 626c2aa98e2SPeter Wemm 627c2aa98e2SPeter Wemm #endif /* !HASFLOCK */ 628c2aa98e2SPeter Wemm 62906f25ae9SGregory Neil Shapiro /* 63006f25ae9SGregory Neil Shapiro ** Since the delivery may happen in a child and the parent 63106f25ae9SGregory Neil Shapiro ** does not wait, the parent may close the maps thereby 63206f25ae9SGregory Neil Shapiro ** removing any shared memory used by the map. Therefore, 63306f25ae9SGregory Neil Shapiro ** close the maps now so the child will dynamically open 63406f25ae9SGregory Neil Shapiro ** them if necessary. 63506f25ae9SGregory Neil Shapiro */ 63606f25ae9SGregory Neil Shapiro 63740266059SGregory Neil Shapiro closemaps(false); 63806f25ae9SGregory Neil Shapiro 639c2aa98e2SPeter Wemm pid = fork(); 640c2aa98e2SPeter Wemm if (pid < 0) 641c2aa98e2SPeter Wemm { 64206f25ae9SGregory Neil Shapiro syserr("deliver: fork 1"); 643c2aa98e2SPeter Wemm #if HASFLOCK 644c2aa98e2SPeter Wemm goto queueonly; 64506f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 646c2aa98e2SPeter Wemm e->e_id = NULL; 647c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 648c2aa98e2SPeter Wemm ee->e_id = NULL; 649c2aa98e2SPeter Wemm return; 650c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 651c2aa98e2SPeter Wemm } 652c2aa98e2SPeter Wemm else if (pid > 0) 653c2aa98e2SPeter Wemm { 654c2aa98e2SPeter Wemm #if HASFLOCK 655c2aa98e2SPeter Wemm /* be sure we leave the temp files to our child */ 656c2aa98e2SPeter Wemm /* close any random open files in the envelope */ 657c2aa98e2SPeter Wemm closexscript(e); 658c2aa98e2SPeter Wemm if (e->e_dfp != NULL) 65940266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 660c2aa98e2SPeter Wemm e->e_dfp = NULL; 661c2aa98e2SPeter Wemm e->e_flags &= ~EF_HAS_DF; 662c2aa98e2SPeter Wemm 663c2aa98e2SPeter Wemm /* can't call unlockqueue to avoid unlink of xfp */ 664c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 66540266059SGregory Neil Shapiro (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 66606f25ae9SGregory Neil Shapiro else 66706f25ae9SGregory Neil Shapiro syserr("%s: sendall: null lockfp", e->e_id); 668c2aa98e2SPeter Wemm e->e_lockfp = NULL; 66906f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 670c2aa98e2SPeter Wemm 671c2aa98e2SPeter Wemm /* make sure the parent doesn't own the envelope */ 672c2aa98e2SPeter Wemm e->e_id = NULL; 673c2aa98e2SPeter Wemm 67440266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 675c2aa98e2SPeter Wemm /* catch intermediate zombie */ 676c2aa98e2SPeter Wemm (void) waitfor(pid); 67740266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 678c2aa98e2SPeter Wemm return; 679c2aa98e2SPeter Wemm } 680c2aa98e2SPeter Wemm 6818774250cSGregory Neil Shapiro /* Reset global flags */ 6828774250cSGregory Neil Shapiro RestartRequest = NULL; 68340266059SGregory Neil Shapiro RestartWorkGroup = false; 6848774250cSGregory Neil Shapiro ShutdownRequest = NULL; 6858774250cSGregory Neil Shapiro PendingSignal = 0; 6868774250cSGregory Neil Shapiro 68742e5d165SGregory Neil Shapiro /* 68840266059SGregory Neil Shapiro ** Initialize exception stack and default exception 68940266059SGregory Neil Shapiro ** handler for child process. 69040266059SGregory Neil Shapiro */ 69140266059SGregory Neil Shapiro 69240266059SGregory Neil Shapiro sm_exc_newthread(fatal_error); 69340266059SGregory Neil Shapiro 69440266059SGregory Neil Shapiro /* 69542e5d165SGregory Neil Shapiro ** Since we have accepted responsbility for the message, 69642e5d165SGregory Neil Shapiro ** change the SIGTERM handler. intsig() (the old handler) 69742e5d165SGregory Neil Shapiro ** would remove the envelope if this was a command line 69842e5d165SGregory Neil Shapiro ** message submission. 69942e5d165SGregory Neil Shapiro */ 70042e5d165SGregory Neil Shapiro 70140266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 70242e5d165SGregory Neil Shapiro 70340266059SGregory Neil Shapiro #if USE_DOUBLE_FORK 704c2aa98e2SPeter Wemm /* double fork to avoid zombies */ 705c2aa98e2SPeter Wemm pid = fork(); 706c2aa98e2SPeter Wemm if (pid > 0) 707c2aa98e2SPeter Wemm exit(EX_OK); 70806f25ae9SGregory Neil Shapiro save_errno = errno; 70940266059SGregory Neil Shapiro #endif /* USE_DOUBLE_FORK */ 71040266059SGregory Neil Shapiro 71140266059SGregory Neil Shapiro CurrentPid = getpid(); 712c2aa98e2SPeter Wemm 713c2aa98e2SPeter Wemm /* be sure we are immune from the terminal */ 714c2aa98e2SPeter Wemm disconnect(2, e); 71506f25ae9SGregory Neil Shapiro clearstats(); 716c2aa98e2SPeter Wemm 717c2aa98e2SPeter Wemm /* prevent parent from waiting if there was an error */ 718c2aa98e2SPeter Wemm if (pid < 0) 719c2aa98e2SPeter Wemm { 72006f25ae9SGregory Neil Shapiro errno = save_errno; 72106f25ae9SGregory Neil Shapiro syserr("deliver: fork 2"); 722c2aa98e2SPeter Wemm #if HASFLOCK 723c2aa98e2SPeter Wemm e->e_flags |= EF_INQUEUE; 72406f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 725c2aa98e2SPeter Wemm e->e_id = NULL; 726c2aa98e2SPeter Wemm #endif /* HASFLOCK */ 72740266059SGregory Neil Shapiro finis(true, true, ExitStat); 728c2aa98e2SPeter Wemm } 729c2aa98e2SPeter Wemm 730c2aa98e2SPeter Wemm /* be sure to give error messages in child */ 73140266059SGregory Neil Shapiro QuickAbort = false; 732c2aa98e2SPeter Wemm 733c2aa98e2SPeter Wemm /* 734c2aa98e2SPeter Wemm ** Close any cached connections. 735c2aa98e2SPeter Wemm ** 736c2aa98e2SPeter Wemm ** We don't send the QUIT protocol because the parent 737c2aa98e2SPeter Wemm ** still knows about the connection. 738c2aa98e2SPeter Wemm ** 739c2aa98e2SPeter Wemm ** This should only happen when delivering an error 740c2aa98e2SPeter Wemm ** message. 741c2aa98e2SPeter Wemm */ 742c2aa98e2SPeter Wemm 74340266059SGregory Neil Shapiro mci_flush(false, NULL); 744c2aa98e2SPeter Wemm 745c2aa98e2SPeter Wemm #if HASFLOCK 746c2aa98e2SPeter Wemm break; 74706f25ae9SGregory Neil Shapiro #else /* HASFLOCK */ 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm /* 750c2aa98e2SPeter Wemm ** Now reacquire and run the various queue files. 751c2aa98e2SPeter Wemm */ 752c2aa98e2SPeter Wemm 753c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 754c2aa98e2SPeter Wemm { 755c2aa98e2SPeter Wemm ENVELOPE *sibling = ee->e_sibling; 756c2aa98e2SPeter Wemm 75740266059SGregory Neil Shapiro (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id, 75840266059SGregory Neil Shapiro false, false, ee); 759c2aa98e2SPeter Wemm ee->e_sibling = sibling; 760c2aa98e2SPeter Wemm } 76140266059SGregory Neil Shapiro (void) dowork(e->e_qgrp, e->e_qdir, e->e_id, 76240266059SGregory Neil Shapiro false, false, e); 76340266059SGregory Neil Shapiro finis(true, true, ExitStat); 76406f25ae9SGregory Neil Shapiro #endif /* HASFLOCK */ 765c2aa98e2SPeter Wemm } 766c2aa98e2SPeter Wemm 767c2aa98e2SPeter Wemm sendenvelope(e, mode); 76840266059SGregory Neil Shapiro dropenvelope(e, true, true); 769c2aa98e2SPeter Wemm for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 770c2aa98e2SPeter Wemm { 771c2aa98e2SPeter Wemm CurEnv = ee; 772c2aa98e2SPeter Wemm if (mode != SM_VERIFY) 773c2aa98e2SPeter Wemm openxscript(ee); 774c2aa98e2SPeter Wemm sendenvelope(ee, mode); 77540266059SGregory Neil Shapiro dropenvelope(ee, true, true); 776c2aa98e2SPeter Wemm } 777c2aa98e2SPeter Wemm CurEnv = e; 778c2aa98e2SPeter Wemm 779c2aa98e2SPeter Wemm Verbose = oldverbose; 780c2aa98e2SPeter Wemm if (mode == SM_FORK) 78140266059SGregory Neil Shapiro finis(true, true, ExitStat); 782c2aa98e2SPeter Wemm } 783c2aa98e2SPeter Wemm 78406f25ae9SGregory Neil Shapiro static void 785c2aa98e2SPeter Wemm sendenvelope(e, mode) 786c2aa98e2SPeter Wemm register ENVELOPE *e; 787c2aa98e2SPeter Wemm int mode; 788c2aa98e2SPeter Wemm { 789c2aa98e2SPeter Wemm register ADDRESS *q; 790c2aa98e2SPeter Wemm bool didany; 791c2aa98e2SPeter Wemm 792c2aa98e2SPeter Wemm if (tTd(13, 10)) 79340266059SGregory Neil Shapiro sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n", 794c2aa98e2SPeter Wemm e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 795c2aa98e2SPeter Wemm e->e_flags); 796c2aa98e2SPeter Wemm if (LogLevel > 80) 797c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, e->e_id, 79806f25ae9SGregory Neil Shapiro "sendenvelope, flags=0x%lx", 799c2aa98e2SPeter Wemm e->e_flags); 800c2aa98e2SPeter Wemm 801c2aa98e2SPeter Wemm /* 802c2aa98e2SPeter Wemm ** If we have had global, fatal errors, don't bother sending 803c2aa98e2SPeter Wemm ** the message at all if we are in SMTP mode. Local errors 804c2aa98e2SPeter Wemm ** (e.g., a single address failing) will still cause the other 805c2aa98e2SPeter Wemm ** addresses to be sent. 806c2aa98e2SPeter Wemm */ 807c2aa98e2SPeter Wemm 808c2aa98e2SPeter Wemm if (bitset(EF_FATALERRS, e->e_flags) && 809c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 810c2aa98e2SPeter Wemm { 811c2aa98e2SPeter Wemm e->e_flags |= EF_CLRQUEUE; 812c2aa98e2SPeter Wemm return; 813c2aa98e2SPeter Wemm } 814c2aa98e2SPeter Wemm 81540266059SGregory Neil Shapiro /* 81640266059SGregory Neil Shapiro ** Don't attempt deliveries if we want to bounce now 81740266059SGregory Neil Shapiro ** or if deliver-by time is exceeded. 81840266059SGregory Neil Shapiro */ 81940266059SGregory Neil Shapiro 82006f25ae9SGregory Neil Shapiro if (!bitset(EF_RESPONSE, e->e_flags) && 82140266059SGregory Neil Shapiro (TimeOuts.to_q_return[e->e_timeoutclass] == NOW || 82240266059SGregory Neil Shapiro (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 && 82340266059SGregory Neil Shapiro curtime() > e->e_ctime + e->e_deliver_by))) 82406f25ae9SGregory Neil Shapiro return; 82506f25ae9SGregory Neil Shapiro 826c2aa98e2SPeter Wemm /* 827c2aa98e2SPeter Wemm ** Run through the list and send everything. 828c2aa98e2SPeter Wemm ** 829c2aa98e2SPeter Wemm ** Set EF_GLOBALERRS so that error messages during delivery 830c2aa98e2SPeter Wemm ** result in returned mail. 831c2aa98e2SPeter Wemm */ 832c2aa98e2SPeter Wemm 833c2aa98e2SPeter Wemm e->e_nsent = 0; 834c2aa98e2SPeter Wemm e->e_flags |= EF_GLOBALERRS; 83506f25ae9SGregory Neil Shapiro 83640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid); 83740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype); 83840266059SGregory Neil Shapiro didany = false; 83940266059SGregory Neil Shapiro 84040266059SGregory Neil Shapiro if (!bitset(EF_SPLIT, e->e_flags)) 84140266059SGregory Neil Shapiro { 84240266059SGregory Neil Shapiro ENVELOPE *oldsib; 84340266059SGregory Neil Shapiro ENVELOPE *ee; 84440266059SGregory Neil Shapiro 84540266059SGregory Neil Shapiro /* 84640266059SGregory Neil Shapiro ** Save old sibling and set it to NULL to avoid 84740266059SGregory Neil Shapiro ** queueing up the same envelopes again. 84840266059SGregory Neil Shapiro ** This requires that envelopes in that list have 84940266059SGregory Neil Shapiro ** been take care of before (or at some other place). 85040266059SGregory Neil Shapiro */ 85140266059SGregory Neil Shapiro 85240266059SGregory Neil Shapiro oldsib = e->e_sibling; 85340266059SGregory Neil Shapiro e->e_sibling = NULL; 85440266059SGregory Neil Shapiro if (!split_by_recipient(e) && 85540266059SGregory Neil Shapiro bitset(EF_FATALERRS, e->e_flags)) 85640266059SGregory Neil Shapiro { 85740266059SGregory Neil Shapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 85840266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE; 85940266059SGregory Neil Shapiro return; 86040266059SGregory Neil Shapiro } 86140266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86240266059SGregory Neil Shapiro queueup(ee, false, true); 86340266059SGregory Neil Shapiro 86440266059SGregory Neil Shapiro /* clean up */ 86540266059SGregory Neil Shapiro for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 86640266059SGregory Neil Shapiro { 86740266059SGregory Neil Shapiro /* now unlock the job */ 86840266059SGregory Neil Shapiro closexscript(ee); 86940266059SGregory Neil Shapiro unlockqueue(ee); 87040266059SGregory Neil Shapiro 87140266059SGregory Neil Shapiro /* this envelope is marked unused */ 87240266059SGregory Neil Shapiro if (ee->e_dfp != NULL) 87340266059SGregory Neil Shapiro { 87440266059SGregory Neil Shapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 87540266059SGregory Neil Shapiro ee->e_dfp = NULL; 87640266059SGregory Neil Shapiro } 87740266059SGregory Neil Shapiro ee->e_id = NULL; 87840266059SGregory Neil Shapiro ee->e_flags &= ~EF_HAS_DF; 87940266059SGregory Neil Shapiro } 88040266059SGregory Neil Shapiro e->e_sibling = oldsib; 88140266059SGregory Neil Shapiro } 882c2aa98e2SPeter Wemm 883c2aa98e2SPeter Wemm /* now run through the queue */ 884c2aa98e2SPeter Wemm for (q = e->e_sendqueue; q != NULL; q = q->q_next) 885c2aa98e2SPeter Wemm { 886c2aa98e2SPeter Wemm #if XDEBUG 887c2aa98e2SPeter Wemm char wbuf[MAXNAME + 20]; 888c2aa98e2SPeter Wemm 88940266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, "sendall(%.*s)", 890c2aa98e2SPeter Wemm MAXNAME, q->q_paddr); 891c2aa98e2SPeter Wemm checkfd012(wbuf); 89206f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 893c2aa98e2SPeter Wemm if (mode == SM_VERIFY) 894c2aa98e2SPeter Wemm { 895c2aa98e2SPeter Wemm e->e_to = q->q_paddr; 89606f25ae9SGregory Neil Shapiro if (QS_IS_SENDABLE(q->q_state)) 897c2aa98e2SPeter Wemm { 898c2aa98e2SPeter Wemm if (q->q_host != NULL && q->q_host[0] != '\0') 899c2aa98e2SPeter Wemm message("deliverable: mailer %s, host %s, user %s", 900c2aa98e2SPeter Wemm q->q_mailer->m_name, 901c2aa98e2SPeter Wemm q->q_host, 902c2aa98e2SPeter Wemm q->q_user); 903c2aa98e2SPeter Wemm else 904c2aa98e2SPeter Wemm message("deliverable: mailer %s, user %s", 905c2aa98e2SPeter Wemm q->q_mailer->m_name, 906c2aa98e2SPeter Wemm q->q_user); 907c2aa98e2SPeter Wemm } 908c2aa98e2SPeter Wemm } 90906f25ae9SGregory Neil Shapiro else if (QS_IS_OK(q->q_state)) 910c2aa98e2SPeter Wemm { 911c2aa98e2SPeter Wemm /* 912c2aa98e2SPeter Wemm ** Checkpoint the send list every few addresses 913c2aa98e2SPeter Wemm */ 914c2aa98e2SPeter Wemm 91542e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && 91642e5d165SGregory Neil Shapiro e->e_nsent >= CheckpointInterval) 917c2aa98e2SPeter Wemm { 91840266059SGregory Neil Shapiro queueup(e, false, false); 919c2aa98e2SPeter Wemm e->e_nsent = 0; 920c2aa98e2SPeter Wemm } 921c2aa98e2SPeter Wemm (void) deliver(e, q); 92240266059SGregory Neil Shapiro didany = true; 923c2aa98e2SPeter Wemm } 924c2aa98e2SPeter Wemm } 925c2aa98e2SPeter Wemm if (didany) 926c2aa98e2SPeter Wemm { 927c2aa98e2SPeter Wemm e->e_dtime = curtime(); 928c2aa98e2SPeter Wemm e->e_ntries++; 929c2aa98e2SPeter Wemm } 930c2aa98e2SPeter Wemm 931c2aa98e2SPeter Wemm #if XDEBUG 932c2aa98e2SPeter Wemm checkfd012("end of sendenvelope"); 93306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 934c2aa98e2SPeter Wemm } 93540266059SGregory Neil Shapiro 93640266059SGregory Neil Shapiro #if REQUIRES_DIR_FSYNC 93740266059SGregory Neil Shapiro /* 93840266059SGregory Neil Shapiro ** SYNC_DIR -- fsync a directory based on a filename 93940266059SGregory Neil Shapiro ** 94040266059SGregory Neil Shapiro ** Parameters: 94140266059SGregory Neil Shapiro ** filename -- path of file 94240266059SGregory Neil Shapiro ** panic -- panic? 94340266059SGregory Neil Shapiro ** 94440266059SGregory Neil Shapiro ** Returns: 94540266059SGregory Neil Shapiro ** none 94640266059SGregory Neil Shapiro */ 94740266059SGregory Neil Shapiro 94840266059SGregory Neil Shapiro void 94940266059SGregory Neil Shapiro sync_dir(filename, panic) 95040266059SGregory Neil Shapiro char *filename; 95140266059SGregory Neil Shapiro bool panic; 95240266059SGregory Neil Shapiro { 95340266059SGregory Neil Shapiro int dirfd; 95440266059SGregory Neil Shapiro char *dirp; 95540266059SGregory Neil Shapiro char dir[MAXPATHLEN]; 95640266059SGregory Neil Shapiro 95740266059SGregory Neil Shapiro /* filesystems which require the directory be synced */ 95840266059SGregory Neil Shapiro dirp = strrchr(filename, '/'); 95940266059SGregory Neil Shapiro if (dirp != NULL) 96040266059SGregory Neil Shapiro { 96140266059SGregory Neil Shapiro if (sm_strlcpy(dir, filename, sizeof dir) >= sizeof dir) 96240266059SGregory Neil Shapiro return; 96340266059SGregory Neil Shapiro dir[dirp - filename] = '\0'; 96440266059SGregory Neil Shapiro dirp = dir; 96540266059SGregory Neil Shapiro } 96640266059SGregory Neil Shapiro else 96740266059SGregory Neil Shapiro dirp = "."; 96840266059SGregory Neil Shapiro dirfd = open(dirp, O_RDONLY, 0700); 96940266059SGregory Neil Shapiro if (tTd(40,32)) 97040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)", 97140266059SGregory Neil Shapiro dirp, dirfd); 97240266059SGregory Neil Shapiro if (dirfd >= 0) 97340266059SGregory Neil Shapiro { 97440266059SGregory Neil Shapiro if (fsync(dirfd) < 0) 97540266059SGregory Neil Shapiro { 97640266059SGregory Neil Shapiro if (panic) 97740266059SGregory Neil Shapiro syserr("!sync_dir: cannot fsync directory %s", 97840266059SGregory Neil Shapiro dirp); 97940266059SGregory Neil Shapiro else if (LogLevel > 1) 98040266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 98140266059SGregory Neil Shapiro "sync_dir: cannot fsync directory %s: %s", 98240266059SGregory Neil Shapiro dirp, sm_errstring(errno)); 98340266059SGregory Neil Shapiro } 98440266059SGregory Neil Shapiro (void) close(dirfd); 98540266059SGregory Neil Shapiro } 98640266059SGregory Neil Shapiro } 98740266059SGregory Neil Shapiro #endif /* REQUIRES_DIR_FSYNC */ 98840266059SGregory Neil Shapiro /* 989c2aa98e2SPeter Wemm ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 990c2aa98e2SPeter Wemm ** 991c2aa98e2SPeter Wemm ** Parameters: 992c2aa98e2SPeter Wemm ** e -- the existing envelope 993c2aa98e2SPeter Wemm ** ee -- the new envelope 99440266059SGregory Neil Shapiro ** type -- the queue file type (e.g., DATAFL_LETTER) 995c2aa98e2SPeter Wemm ** 996c2aa98e2SPeter Wemm ** Returns: 997c2aa98e2SPeter Wemm ** none 998c2aa98e2SPeter Wemm */ 999c2aa98e2SPeter Wemm 100006f25ae9SGregory Neil Shapiro static void 1001c2aa98e2SPeter Wemm dup_queue_file(e, ee, type) 100240266059SGregory Neil Shapiro ENVELOPE *e, *ee; 1003c2aa98e2SPeter Wemm int type; 1004c2aa98e2SPeter Wemm { 100506f25ae9SGregory Neil Shapiro char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 1006c2aa98e2SPeter Wemm 1007c2aa98e2SPeter Wemm ee->e_dfp = NULL; 1008c2aa98e2SPeter Wemm ee->e_xfp = NULL; 100906f25ae9SGregory Neil Shapiro 101006f25ae9SGregory Neil Shapiro /* 101106f25ae9SGregory Neil Shapiro ** Make sure both are in the same directory. 101206f25ae9SGregory Neil Shapiro */ 101306f25ae9SGregory Neil Shapiro 101440266059SGregory Neil Shapiro (void) sm_strlcpy(f1buf, queuename(e, type), sizeof f1buf); 101540266059SGregory Neil Shapiro (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof f2buf); 1016c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1017c2aa98e2SPeter Wemm { 101806f25ae9SGregory Neil Shapiro int save_errno = errno; 1019c2aa98e2SPeter Wemm 1020c2aa98e2SPeter Wemm syserr("sendall: link(%s, %s)", f1buf, f2buf); 102106f25ae9SGregory Neil Shapiro if (save_errno == EEXIST) 1022c2aa98e2SPeter Wemm { 1023c2aa98e2SPeter Wemm if (unlink(f2buf) < 0) 1024c2aa98e2SPeter Wemm { 1025c2aa98e2SPeter Wemm syserr("!sendall: unlink(%s): permanent", 1026c2aa98e2SPeter Wemm f2buf); 1027c2aa98e2SPeter Wemm /* NOTREACHED */ 1028c2aa98e2SPeter Wemm } 1029c2aa98e2SPeter Wemm if (link(f1buf, f2buf) < 0) 1030c2aa98e2SPeter Wemm { 1031c2aa98e2SPeter Wemm syserr("!sendall: link(%s, %s): permanent", 1032c2aa98e2SPeter Wemm f1buf, f2buf); 1033c2aa98e2SPeter Wemm /* NOTREACHED */ 1034c2aa98e2SPeter Wemm } 1035c2aa98e2SPeter Wemm } 1036c2aa98e2SPeter Wemm } 103740266059SGregory Neil Shapiro SYNC_DIR(f2buf, true); 1038c2aa98e2SPeter Wemm } 103940266059SGregory Neil Shapiro /* 1040c2aa98e2SPeter Wemm ** DOFORK -- do a fork, retrying a couple of times on failure. 1041c2aa98e2SPeter Wemm ** 1042c2aa98e2SPeter Wemm ** This MUST be a macro, since after a vfork we are running 1043c2aa98e2SPeter Wemm ** two processes on the same stack!!! 1044c2aa98e2SPeter Wemm ** 1045c2aa98e2SPeter Wemm ** Parameters: 1046c2aa98e2SPeter Wemm ** none. 1047c2aa98e2SPeter Wemm ** 1048c2aa98e2SPeter Wemm ** Returns: 1049c2aa98e2SPeter Wemm ** From a macro??? You've got to be kidding! 1050c2aa98e2SPeter Wemm ** 1051c2aa98e2SPeter Wemm ** Side Effects: 1052c2aa98e2SPeter Wemm ** Modifies the ==> LOCAL <== variable 'pid', leaving: 1053c2aa98e2SPeter Wemm ** pid of child in parent, zero in child. 1054c2aa98e2SPeter Wemm ** -1 on unrecoverable error. 1055c2aa98e2SPeter Wemm ** 1056c2aa98e2SPeter Wemm ** Notes: 1057c2aa98e2SPeter Wemm ** I'm awfully sorry this looks so awful. That's 1058c2aa98e2SPeter Wemm ** vfork for you..... 1059c2aa98e2SPeter Wemm */ 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm #define NFORKTRIES 5 1062c2aa98e2SPeter Wemm 1063c2aa98e2SPeter Wemm #ifndef FORK 1064c2aa98e2SPeter Wemm # define FORK fork 106506f25ae9SGregory Neil Shapiro #endif /* ! FORK */ 1066c2aa98e2SPeter Wemm 1067c2aa98e2SPeter Wemm #define DOFORK(fORKfN) \ 1068c2aa98e2SPeter Wemm {\ 1069c2aa98e2SPeter Wemm register int i;\ 1070c2aa98e2SPeter Wemm \ 1071c2aa98e2SPeter Wemm for (i = NFORKTRIES; --i >= 0; )\ 1072c2aa98e2SPeter Wemm {\ 1073c2aa98e2SPeter Wemm pid = fORKfN();\ 1074c2aa98e2SPeter Wemm if (pid >= 0)\ 1075c2aa98e2SPeter Wemm break;\ 1076c2aa98e2SPeter Wemm if (i > 0)\ 107706f25ae9SGregory Neil Shapiro (void) sleep((unsigned) NFORKTRIES - i);\ 1078c2aa98e2SPeter Wemm }\ 1079c2aa98e2SPeter Wemm } 108040266059SGregory Neil Shapiro /* 1081c2aa98e2SPeter Wemm ** DOFORK -- simple fork interface to DOFORK. 1082c2aa98e2SPeter Wemm ** 1083c2aa98e2SPeter Wemm ** Parameters: 1084c2aa98e2SPeter Wemm ** none. 1085c2aa98e2SPeter Wemm ** 1086c2aa98e2SPeter Wemm ** Returns: 1087c2aa98e2SPeter Wemm ** pid of child in parent. 1088c2aa98e2SPeter Wemm ** zero in child. 1089c2aa98e2SPeter Wemm ** -1 on error. 1090c2aa98e2SPeter Wemm ** 1091c2aa98e2SPeter Wemm ** Side Effects: 1092c2aa98e2SPeter Wemm ** returns twice, once in parent and once in child. 1093c2aa98e2SPeter Wemm */ 1094c2aa98e2SPeter Wemm 10958774250cSGregory Neil Shapiro pid_t 1096c2aa98e2SPeter Wemm dofork() 1097c2aa98e2SPeter Wemm { 1098c2aa98e2SPeter Wemm register pid_t pid = -1; 1099c2aa98e2SPeter Wemm 1100c2aa98e2SPeter Wemm DOFORK(fork); 110106f25ae9SGregory Neil Shapiro return pid; 1102c2aa98e2SPeter Wemm } 110340266059SGregory Neil Shapiro 110440266059SGregory Neil Shapiro /* 110540266059SGregory Neil Shapiro ** COLONCMP -- compare host-signatures up to first ':' or EOS 110640266059SGregory Neil Shapiro ** 110740266059SGregory Neil Shapiro ** This takes two strings which happen to be host-signatures and 110840266059SGregory Neil Shapiro ** compares them. If the lowest preference portions of the MX-RR's 110940266059SGregory Neil Shapiro ** match (up to ':' or EOS, whichever is first), then we have 111040266059SGregory Neil Shapiro ** match. This is used for coattail-piggybacking messages during 111140266059SGregory Neil Shapiro ** message delivery. 111240266059SGregory Neil Shapiro ** If the signatures are the same up to the first ':' the remainder of 111340266059SGregory Neil Shapiro ** the signatures are then compared with a normal strcmp(). This saves 111440266059SGregory Neil Shapiro ** re-examining the first part of the signatures. 111540266059SGregory Neil Shapiro ** 111640266059SGregory Neil Shapiro ** Parameters: 111740266059SGregory Neil Shapiro ** a - first host-signature 111840266059SGregory Neil Shapiro ** b - second host-signature 111940266059SGregory Neil Shapiro ** 112040266059SGregory Neil Shapiro ** Returns: 112140266059SGregory Neil Shapiro ** HS_MATCH_NO -- no "match". 112240266059SGregory Neil Shapiro ** HS_MATCH_FIRST -- "match" for the first MX preference 112340266059SGregory Neil Shapiro ** (up to the first colon (':')). 112440266059SGregory Neil Shapiro ** HS_MATCH_FULL -- match for the entire MX record. 112540266059SGregory Neil Shapiro ** 112640266059SGregory Neil Shapiro ** Side Effects: 112740266059SGregory Neil Shapiro ** none. 112840266059SGregory Neil Shapiro */ 112940266059SGregory Neil Shapiro 113040266059SGregory Neil Shapiro #define HS_MATCH_NO 0 113140266059SGregory Neil Shapiro #define HS_MATCH_FIRST 1 113240266059SGregory Neil Shapiro #define HS_MATCH_FULL 2 113340266059SGregory Neil Shapiro 113440266059SGregory Neil Shapiro static int 113540266059SGregory Neil Shapiro coloncmp(a, b) 113640266059SGregory Neil Shapiro register const char *a; 113740266059SGregory Neil Shapiro register const char *b; 113840266059SGregory Neil Shapiro { 113940266059SGregory Neil Shapiro int ret = HS_MATCH_NO; 114040266059SGregory Neil Shapiro int braclev = 0; 114140266059SGregory Neil Shapiro 114240266059SGregory Neil Shapiro while (*a == *b++) 114340266059SGregory Neil Shapiro { 114440266059SGregory Neil Shapiro /* Need to account for IPv6 bracketed addresses */ 114540266059SGregory Neil Shapiro if (*a == '[') 114640266059SGregory Neil Shapiro braclev++; 114740266059SGregory Neil Shapiro else if (*a == '[' && braclev > 0) 114840266059SGregory Neil Shapiro braclev--; 114940266059SGregory Neil Shapiro else if (*a == ':' && braclev <= 0) 115040266059SGregory Neil Shapiro { 115140266059SGregory Neil Shapiro ret = HS_MATCH_FIRST; 115240266059SGregory Neil Shapiro a++; 115340266059SGregory Neil Shapiro break; 115440266059SGregory Neil Shapiro } 115540266059SGregory Neil Shapiro else if (*a == '\0') 115640266059SGregory Neil Shapiro return HS_MATCH_FULL; /* a full match */ 115740266059SGregory Neil Shapiro a++; 115840266059SGregory Neil Shapiro } 115940266059SGregory Neil Shapiro if (ret == HS_MATCH_NO && 116040266059SGregory Neil Shapiro braclev <= 0 && 116140266059SGregory Neil Shapiro ((*a == '\0' && *(b - 1) == ':') || 116240266059SGregory Neil Shapiro (*a == ':' && *(b - 1) == '\0'))) 116340266059SGregory Neil Shapiro return HS_MATCH_FIRST; 116440266059SGregory Neil Shapiro if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0) 116540266059SGregory Neil Shapiro return HS_MATCH_FULL; 116640266059SGregory Neil Shapiro 116740266059SGregory Neil Shapiro return ret; 116840266059SGregory Neil Shapiro } 116940266059SGregory Neil Shapiro /* 1170c2aa98e2SPeter Wemm ** DELIVER -- Deliver a message to a list of addresses. 1171c2aa98e2SPeter Wemm ** 1172c2aa98e2SPeter Wemm ** This routine delivers to everyone on the same host as the 1173c2aa98e2SPeter Wemm ** user on the head of the list. It is clever about mailers 1174c2aa98e2SPeter Wemm ** that don't handle multiple users. It is NOT guaranteed 1175c2aa98e2SPeter Wemm ** that it will deliver to all these addresses however -- so 1176c2aa98e2SPeter Wemm ** deliver should be called once for each address on the 1177c2aa98e2SPeter Wemm ** list. 117840266059SGregory Neil Shapiro ** Deliver tries to be as opportunistic as possible about piggybacking 117940266059SGregory Neil Shapiro ** messages. Some definitions to make understanding easier follow below. 118040266059SGregory Neil Shapiro ** Piggybacking occurs when an existing connection to a mail host can 118140266059SGregory Neil Shapiro ** be used to send the same message to more than one recipient at the 118240266059SGregory Neil Shapiro ** same time. So "no piggybacking" means one message for one recipient 118340266059SGregory Neil Shapiro ** per connection. "Intentional piggybacking" happens when the 118440266059SGregory Neil Shapiro ** recipients' host address (not the mail host address) is used to 118540266059SGregory Neil Shapiro ** attempt piggybacking. Recipients with the same host address 118640266059SGregory Neil Shapiro ** have the same mail host. "Coincidental piggybacking" relies on 118740266059SGregory Neil Shapiro ** piggybacking based on all the mail host addresses in the MX-RR. This 118840266059SGregory Neil Shapiro ** is "coincidental" in the fact it could not be predicted until the 118940266059SGregory Neil Shapiro ** MX Resource Records for the hosts were obtained and examined. For 119040266059SGregory Neil Shapiro ** example (preference order and equivalence is important, not values): 119140266059SGregory Neil Shapiro ** domain1 IN MX 10 mxhost-A 119240266059SGregory Neil Shapiro ** IN MX 20 mxhost-B 119340266059SGregory Neil Shapiro ** domain2 IN MX 4 mxhost-A 119440266059SGregory Neil Shapiro ** IN MX 8 mxhost-B 119540266059SGregory Neil Shapiro ** Domain1 and domain2 can piggyback the same message to mxhost-A or 119640266059SGregory Neil Shapiro ** mxhost-B (if mxhost-A cannot be reached). 119740266059SGregory Neil Shapiro ** "Coattail piggybacking" relaxes the strictness of "coincidental 119840266059SGregory Neil Shapiro ** piggybacking" in the hope that most significant (lowest value) 119940266059SGregory Neil Shapiro ** MX preference host(s) can create more piggybacking. For example 120040266059SGregory Neil Shapiro ** (again, preference order and equivalence is important, not values): 120140266059SGregory Neil Shapiro ** domain3 IN MX 100 mxhost-C 120240266059SGregory Neil Shapiro ** IN MX 100 mxhost-D 120340266059SGregory Neil Shapiro ** IN MX 200 mxhost-E 120440266059SGregory Neil Shapiro ** domain4 IN MX 50 mxhost-C 120540266059SGregory Neil Shapiro ** IN MX 50 mxhost-D 120640266059SGregory Neil Shapiro ** IN MX 80 mxhost-F 120740266059SGregory Neil Shapiro ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C 120840266059SGregory Neil Shapiro ** is available. Same with mxhost-D because in both RR's the preference 120940266059SGregory Neil Shapiro ** value is the same as mxhost-C, respectively. 121040266059SGregory Neil Shapiro ** So deliver attempts coattail piggybacking when possible. If the 121140266059SGregory Neil Shapiro ** first MX preference level hosts cannot be used then the piggybacking 121240266059SGregory Neil Shapiro ** reverts to coincidental piggybacking. Using the above example you 121340266059SGregory Neil Shapiro ** cannot deliver to mxhost-F for domain3 regardless of preference value. 121440266059SGregory Neil Shapiro ** ("Coattail" from "riding on the coattails of your predecessor" meaning 121540266059SGregory Neil Shapiro ** gaining benefit from a predecessor effort with no or little addition 121640266059SGregory Neil Shapiro ** effort. The predecessor here being the preceding MX RR). 1217c2aa98e2SPeter Wemm ** 1218c2aa98e2SPeter Wemm ** Parameters: 1219c2aa98e2SPeter Wemm ** e -- the envelope to deliver. 1220c2aa98e2SPeter Wemm ** firstto -- head of the address list to deliver to. 1221c2aa98e2SPeter Wemm ** 1222c2aa98e2SPeter Wemm ** Returns: 1223c2aa98e2SPeter Wemm ** zero -- successfully delivered. 1224c2aa98e2SPeter Wemm ** else -- some failure, see ExitStat for more info. 1225c2aa98e2SPeter Wemm ** 1226c2aa98e2SPeter Wemm ** Side Effects: 1227c2aa98e2SPeter Wemm ** The standard input is passed off to someone. 1228c2aa98e2SPeter Wemm */ 1229c2aa98e2SPeter Wemm 1230c2aa98e2SPeter Wemm #ifndef NO_UID 1231c2aa98e2SPeter Wemm # define NO_UID -1 123206f25ae9SGregory Neil Shapiro #endif /* ! NO_UID */ 1233c2aa98e2SPeter Wemm #ifndef NO_GID 1234c2aa98e2SPeter Wemm # define NO_GID -1 123506f25ae9SGregory Neil Shapiro #endif /* ! NO_GID */ 1236c2aa98e2SPeter Wemm 123706f25ae9SGregory Neil Shapiro static int 1238c2aa98e2SPeter Wemm deliver(e, firstto) 1239c2aa98e2SPeter Wemm register ENVELOPE *e; 1240c2aa98e2SPeter Wemm ADDRESS *firstto; 1241c2aa98e2SPeter Wemm { 1242c2aa98e2SPeter Wemm char *host; /* host being sent to */ 1243c2aa98e2SPeter Wemm char *user; /* user being sent to */ 1244c2aa98e2SPeter Wemm char **pvp; 1245c2aa98e2SPeter Wemm register char **mvp; 1246c2aa98e2SPeter Wemm register char *p; 1247c2aa98e2SPeter Wemm register MAILER *m; /* mailer for this recipient */ 1248c2aa98e2SPeter Wemm ADDRESS *volatile ctladdr; 124940266059SGregory Neil Shapiro #if HASSETUSERCONTEXT 1250c2aa98e2SPeter Wemm ADDRESS *volatile contextaddr = NULL; 125140266059SGregory Neil Shapiro #endif /* HASSETUSERCONTEXT */ 1252c2aa98e2SPeter Wemm register MCI *volatile mci; 125340266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE to = firstto; 125440266059SGregory Neil Shapiro volatile bool clever = false; /* running user smtp to this mailer */ 1255c2aa98e2SPeter Wemm ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 1256c2aa98e2SPeter Wemm int rcode; /* response code */ 125740266059SGregory Neil Shapiro SM_NONVOLATILE int lmtp_rcode = EX_OK; 125840266059SGregory Neil Shapiro SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */ 125940266059SGregory Neil Shapiro SM_NONVOLATILE int hostnum = 0; /* current MX host index */ 1260c2aa98e2SPeter Wemm char *firstsig; /* signature of firstto */ 126140266059SGregory Neil Shapiro volatile pid_t pid = -1; 1262c2aa98e2SPeter Wemm char *volatile curhost; 126340266059SGregory Neil Shapiro SM_NONVOLATILE unsigned short port = 0; 126440266059SGregory Neil Shapiro SM_NONVOLATILE time_t enough = 0; 126506f25ae9SGregory Neil Shapiro #if NETUNIX 126640266059SGregory Neil Shapiro char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */ 126706f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 1268c2aa98e2SPeter Wemm time_t xstart; 1269c2aa98e2SPeter Wemm bool suidwarn; 1270c2aa98e2SPeter Wemm bool anyok; /* at least one address was OK */ 127140266059SGregory Neil Shapiro SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ 127206f25ae9SGregory Neil Shapiro bool ovr; 127340266059SGregory Neil Shapiro #if _FFR_QUARANTINE 127440266059SGregory Neil Shapiro bool quarantine; 127540266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 127606f25ae9SGregory Neil Shapiro int strsize; 127706f25ae9SGregory Neil Shapiro int rcptcount; 127840266059SGregory Neil Shapiro int ret; 127906f25ae9SGregory Neil Shapiro static int tobufsize = 0; 128006f25ae9SGregory Neil Shapiro static char *tobuf = NULL; 128140266059SGregory Neil Shapiro char *rpath; /* translated return path */ 1282c2aa98e2SPeter Wemm int mpvect[2]; 1283c2aa98e2SPeter Wemm int rpvect[2]; 128406f25ae9SGregory Neil Shapiro char *mxhosts[MAXMXHOSTS + 1]; 1285c2aa98e2SPeter Wemm char *pv[MAXPV + 1]; 1286c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 128794c01205SGregory Neil Shapiro char cbuf[MAXPATHLEN]; 1288c2aa98e2SPeter Wemm 1289c2aa98e2SPeter Wemm errno = 0; 129006f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 129106f25ae9SGregory Neil Shapiro return 0; 1292c2aa98e2SPeter Wemm 1293c2aa98e2SPeter Wemm suidwarn = geteuid() == 0; 1294c2aa98e2SPeter Wemm 1295c2aa98e2SPeter Wemm m = to->q_mailer; 1296c2aa98e2SPeter Wemm host = to->q_host; 1297c2aa98e2SPeter Wemm CurEnv = e; /* just in case */ 1298c2aa98e2SPeter Wemm e->e_statmsg = NULL; 1299c2aa98e2SPeter Wemm SmtpError[0] = '\0'; 1300c2aa98e2SPeter Wemm xstart = curtime(); 1301c2aa98e2SPeter Wemm 1302c2aa98e2SPeter Wemm if (tTd(10, 1)) 130340266059SGregory Neil Shapiro sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 1304c2aa98e2SPeter Wemm e->e_id, m->m_name, host, to->q_user); 1305c2aa98e2SPeter Wemm if (tTd(10, 100)) 130640266059SGregory Neil Shapiro printopenfds(false); 1307c2aa98e2SPeter Wemm 1308c2aa98e2SPeter Wemm /* 130940266059SGregory Neil Shapiro ** Clear {client_*} macros if this is a bounce message to 1310c2aa98e2SPeter Wemm ** prevent rejection by check_compat ruleset. 1311c2aa98e2SPeter Wemm */ 1312c2aa98e2SPeter Wemm 1313c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 1314c2aa98e2SPeter Wemm { 131540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); 131640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); 131740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); 131840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); 1319c2aa98e2SPeter Wemm } 1320c2aa98e2SPeter Wemm 132140266059SGregory Neil Shapiro SM_TRY 132240266059SGregory Neil Shapiro { 132340266059SGregory Neil Shapiro ADDRESS *skip_back = NULL; 132440266059SGregory Neil Shapiro 1325c2aa98e2SPeter Wemm /* 1326c2aa98e2SPeter Wemm ** Do initial argv setup. 1327c2aa98e2SPeter Wemm ** Insert the mailer name. Notice that $x expansion is 1328c2aa98e2SPeter Wemm ** NOT done on the mailer name. Then, if the mailer has 1329c2aa98e2SPeter Wemm ** a picky -f flag, we insert it as appropriate. This 1330c2aa98e2SPeter Wemm ** code does not check for 'pv' overflow; this places a 1331c2aa98e2SPeter Wemm ** manifest lower limit of 4 for MAXPV. 1332c2aa98e2SPeter Wemm ** The from address rewrite is expected to make 1333c2aa98e2SPeter Wemm ** the address relative to the other end. 1334c2aa98e2SPeter Wemm */ 1335c2aa98e2SPeter Wemm 1336c2aa98e2SPeter Wemm /* rewrite from address, using rewriting rules */ 1337c2aa98e2SPeter Wemm rcode = EX_OK; 1338c2aa98e2SPeter Wemm if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 1339c2aa98e2SPeter Wemm p = e->e_sender; 1340c2aa98e2SPeter Wemm else 1341c2aa98e2SPeter Wemm p = e->e_from.q_paddr; 134240266059SGregory Neil Shapiro rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 134340266059SGregory Neil Shapiro if (strlen(rpath) > MAXSHORTSTR) 1344c2aa98e2SPeter Wemm { 134540266059SGregory Neil Shapiro rpath = shortenstring(rpath, MAXSHORTSTR); 134640266059SGregory Neil Shapiro 134740266059SGregory Neil Shapiro /* avoid bogus errno */ 134840266059SGregory Neil Shapiro errno = 0; 134940266059SGregory Neil Shapiro syserr("remotename: huge return path %s", rpath); 1350c2aa98e2SPeter Wemm } 135140266059SGregory Neil Shapiro rpath = sm_rpool_strdup_x(e->e_rpool, rpath); 135240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', rpath); 135340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', host); 1354c2aa98e2SPeter Wemm Errors = 0; 1355c2aa98e2SPeter Wemm pvp = pv; 1356c2aa98e2SPeter Wemm *pvp++ = m->m_argv[0]; 1357c2aa98e2SPeter Wemm 1358c2aa98e2SPeter Wemm /* insert -f or -r flag as appropriate */ 135906f25ae9SGregory Neil Shapiro if (FromFlag && 136006f25ae9SGregory Neil Shapiro (bitnset(M_FOPT, m->m_flags) || 136106f25ae9SGregory Neil Shapiro bitnset(M_ROPT, m->m_flags))) 1362c2aa98e2SPeter Wemm { 1363c2aa98e2SPeter Wemm if (bitnset(M_FOPT, m->m_flags)) 1364c2aa98e2SPeter Wemm *pvp++ = "-f"; 1365c2aa98e2SPeter Wemm else 1366c2aa98e2SPeter Wemm *pvp++ = "-r"; 136740266059SGregory Neil Shapiro *pvp++ = rpath; 1368c2aa98e2SPeter Wemm } 1369c2aa98e2SPeter Wemm 1370c2aa98e2SPeter Wemm /* 1371c2aa98e2SPeter Wemm ** Append the other fixed parts of the argv. These run 1372c2aa98e2SPeter Wemm ** up to the first entry containing "$u". There can only 1373c2aa98e2SPeter Wemm ** be one of these, and there are only a few more slots 1374c2aa98e2SPeter Wemm ** in the pv after it. 1375c2aa98e2SPeter Wemm */ 1376c2aa98e2SPeter Wemm 1377c2aa98e2SPeter Wemm for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1378c2aa98e2SPeter Wemm { 1379c2aa98e2SPeter Wemm /* can't use strchr here because of sign extension problems */ 1380c2aa98e2SPeter Wemm while (*p != '\0') 1381c2aa98e2SPeter Wemm { 1382c2aa98e2SPeter Wemm if ((*p++ & 0377) == MACROEXPAND) 1383c2aa98e2SPeter Wemm { 1384c2aa98e2SPeter Wemm if (*p == 'u') 1385c2aa98e2SPeter Wemm break; 1386c2aa98e2SPeter Wemm } 1387c2aa98e2SPeter Wemm } 1388c2aa98e2SPeter Wemm 1389c2aa98e2SPeter Wemm if (*p != '\0') 1390c2aa98e2SPeter Wemm break; 1391c2aa98e2SPeter Wemm 1392c2aa98e2SPeter Wemm /* this entry is safe -- go ahead and process it */ 1393c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 139440266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1395c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 3]) 1396c2aa98e2SPeter Wemm { 139706f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Too many parameters to %s before $u", 139806f25ae9SGregory Neil Shapiro pv[0]); 139940266059SGregory Neil Shapiro rcode = -1; 140040266059SGregory Neil Shapiro goto cleanup; 1401c2aa98e2SPeter Wemm } 1402c2aa98e2SPeter Wemm } 1403c2aa98e2SPeter Wemm 1404c2aa98e2SPeter Wemm /* 1405c2aa98e2SPeter Wemm ** If we have no substitution for the user name in the argument 1406c2aa98e2SPeter Wemm ** list, we know that we must supply the names otherwise -- and 1407c2aa98e2SPeter Wemm ** SMTP is the answer!! 1408c2aa98e2SPeter Wemm */ 1409c2aa98e2SPeter Wemm 1410c2aa98e2SPeter Wemm if (*mvp == NULL) 1411c2aa98e2SPeter Wemm { 1412602a2b1bSGregory Neil Shapiro /* running LMTP or SMTP */ 141340266059SGregory Neil Shapiro clever = true; 1414c2aa98e2SPeter Wemm *pvp = NULL; 1415c2aa98e2SPeter Wemm } 1416602a2b1bSGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags)) 1417602a2b1bSGregory Neil Shapiro { 1418602a2b1bSGregory Neil Shapiro /* not running LMTP */ 1419602a2b1bSGregory Neil Shapiro sm_syslog(LOG_ERR, NULL, 1420602a2b1bSGregory Neil Shapiro "Warning: mailer %s: LMTP flag (F=z) turned off", 1421602a2b1bSGregory Neil Shapiro m->m_name); 1422602a2b1bSGregory Neil Shapiro clrbitn(M_LMTP, m->m_flags); 1423602a2b1bSGregory Neil Shapiro } 1424c2aa98e2SPeter Wemm 1425c2aa98e2SPeter Wemm /* 1426c2aa98e2SPeter Wemm ** At this point *mvp points to the argument with $u. We 1427c2aa98e2SPeter Wemm ** run through our address list and append all the addresses 1428c2aa98e2SPeter Wemm ** we can. If we run out of space, do not fret! We can 1429c2aa98e2SPeter Wemm ** always send another copy later. 1430c2aa98e2SPeter Wemm */ 1431c2aa98e2SPeter Wemm 143206f25ae9SGregory Neil Shapiro e->e_to = NULL; 143306f25ae9SGregory Neil Shapiro strsize = 2; 143406f25ae9SGregory Neil Shapiro rcptcount = 0; 1435c2aa98e2SPeter Wemm ctladdr = NULL; 143640266059SGregory Neil Shapiro if (firstto->q_signature == NULL) 143740266059SGregory Neil Shapiro firstto->q_signature = hostsignature(firstto->q_mailer, 143840266059SGregory Neil Shapiro firstto->q_host); 143940266059SGregory Neil Shapiro firstsig = firstto->q_signature; 144040266059SGregory Neil Shapiro 1441c2aa98e2SPeter Wemm for (; to != NULL; to = to->q_next) 1442c2aa98e2SPeter Wemm { 1443c2aa98e2SPeter Wemm /* avoid sending multiple recipients to dumb mailers */ 144406f25ae9SGregory Neil Shapiro if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 144506f25ae9SGregory Neil Shapiro break; 1446c2aa98e2SPeter Wemm 1447c2aa98e2SPeter Wemm /* if already sent or not for this host, don't send */ 144840266059SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) /* already sent; look at next */ 1449c2aa98e2SPeter Wemm continue; 1450c2aa98e2SPeter Wemm 145140266059SGregory Neil Shapiro /* 145240266059SGregory Neil Shapiro ** Must be same mailer to keep grouping rcpts. 145340266059SGregory Neil Shapiro ** If mailers don't match: continue; sendqueue is not 145440266059SGregory Neil Shapiro ** sorted by mailers, so don't break; 145540266059SGregory Neil Shapiro */ 145640266059SGregory Neil Shapiro 145740266059SGregory Neil Shapiro if (to->q_mailer != firstto->q_mailer) 145840266059SGregory Neil Shapiro continue; 145940266059SGregory Neil Shapiro 146040266059SGregory Neil Shapiro if (to->q_signature == NULL) /* for safety */ 146140266059SGregory Neil Shapiro to->q_signature = hostsignature(to->q_mailer, 146240266059SGregory Neil Shapiro to->q_host); 146340266059SGregory Neil Shapiro 146440266059SGregory Neil Shapiro /* 146540266059SGregory Neil Shapiro ** This is for coincidental and tailcoat piggybacking messages 146640266059SGregory Neil Shapiro ** to the same mail host. While the signatures are identical 146740266059SGregory Neil Shapiro ** (that's the MX-RR's are identical) we can do coincidental 146840266059SGregory Neil Shapiro ** piggybacking. We try hard for coattail piggybacking 146940266059SGregory Neil Shapiro ** with the same mail host when the next recipient has the 147040266059SGregory Neil Shapiro ** same host at lowest preference. It may be that this 147140266059SGregory Neil Shapiro ** won't work out, so 'skip_back' is maintained if a backup 147240266059SGregory Neil Shapiro ** to coincidental piggybacking or full signature must happen. 147340266059SGregory Neil Shapiro */ 147440266059SGregory Neil Shapiro 147540266059SGregory Neil Shapiro ret = firstto == to ? HS_MATCH_FULL : 147640266059SGregory Neil Shapiro coloncmp(to->q_signature, firstsig); 147740266059SGregory Neil Shapiro if (ret == HS_MATCH_FULL) 147840266059SGregory Neil Shapiro skip_back = to; 147940266059SGregory Neil Shapiro else if (ret == HS_MATCH_NO) 148006f25ae9SGregory Neil Shapiro break; 148106f25ae9SGregory Neil Shapiro 148240266059SGregory Neil Shapiro if (!clever) 148340266059SGregory Neil Shapiro { 148440266059SGregory Neil Shapiro /* avoid overflowing tobuf */ 148540266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 148640266059SGregory Neil Shapiro if (strsize > TOBUFSIZE) 148740266059SGregory Neil Shapiro break; 148840266059SGregory Neil Shapiro } 148940266059SGregory Neil Shapiro 149006f25ae9SGregory Neil Shapiro if (++rcptcount > to->q_mailer->m_maxrcpt) 149106f25ae9SGregory Neil Shapiro break; 1492c2aa98e2SPeter Wemm 1493c2aa98e2SPeter Wemm if (tTd(10, 1)) 1494c2aa98e2SPeter Wemm { 149540266059SGregory Neil Shapiro sm_dprintf("\nsend to "); 149640266059SGregory Neil Shapiro printaddr(to, false); 1497c2aa98e2SPeter Wemm } 1498c2aa98e2SPeter Wemm 1499c2aa98e2SPeter Wemm /* compute effective uid/gid when sending */ 1500c2aa98e2SPeter Wemm if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 150140266059SGregory Neil Shapiro # if HASSETUSERCONTEXT 1502c2aa98e2SPeter Wemm contextaddr = ctladdr = getctladdr(to); 150340266059SGregory Neil Shapiro # else /* HASSETUSERCONTEXT */ 150440266059SGregory Neil Shapiro ctladdr = getctladdr(to); 150540266059SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 1506c2aa98e2SPeter Wemm 1507c2aa98e2SPeter Wemm if (tTd(10, 2)) 1508c2aa98e2SPeter Wemm { 150940266059SGregory Neil Shapiro sm_dprintf("ctladdr="); 151040266059SGregory Neil Shapiro printaddr(ctladdr, false); 1511c2aa98e2SPeter Wemm } 1512c2aa98e2SPeter Wemm 1513c2aa98e2SPeter Wemm user = to->q_user; 1514c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 1515c2aa98e2SPeter Wemm 1516c2aa98e2SPeter Wemm /* 1517c2aa98e2SPeter Wemm ** Check to see that these people are allowed to 1518c2aa98e2SPeter Wemm ** talk to each other. 151942e5d165SGregory Neil Shapiro ** Check also for overflow of e_msgsize. 1520c2aa98e2SPeter Wemm */ 1521c2aa98e2SPeter Wemm 152242e5d165SGregory Neil Shapiro if (m->m_maxsize != 0 && 152342e5d165SGregory Neil Shapiro (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 1524c2aa98e2SPeter Wemm { 1525c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN; 1526c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 1527c2aa98e2SPeter Wemm to->q_status = "5.2.3"; 1528c2aa98e2SPeter Wemm else 1529c2aa98e2SPeter Wemm to->q_status = "5.3.4"; 153040266059SGregory Neil Shapiro 153106f25ae9SGregory Neil Shapiro /* set to->q_rstatus = NULL; or to the following? */ 153206f25ae9SGregory Neil Shapiro usrerrenh(to->q_status, 153306f25ae9SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 153406f25ae9SGregory Neil Shapiro m->m_maxsize); 153540266059SGregory Neil Shapiro markfailure(e, to, NULL, EX_UNAVAILABLE, false); 153606f25ae9SGregory Neil Shapiro giveresponse(EX_UNAVAILABLE, to->q_status, m, 153740266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1538c2aa98e2SPeter Wemm continue; 1539c2aa98e2SPeter Wemm } 1540602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 154140266059SGregory Neil Shapiro ovr = true; 1542c2aa98e2SPeter Wemm 1543c2aa98e2SPeter Wemm /* do config file checking of compatibility */ 154440266059SGregory Neil Shapiro #if _FFR_QUARANTINE 154540266059SGregory Neil Shapiro quarantine = (e->e_quarmsg != NULL); 154640266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 154706f25ae9SGregory Neil Shapiro rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 154840266059SGregory Neil Shapiro e, true, true, 3, NULL, e->e_id); 1549c2aa98e2SPeter Wemm if (rcode == EX_OK) 1550c2aa98e2SPeter Wemm { 1551065a643dSPeter Wemm /* do in-code checking if not discarding */ 1552065a643dSPeter Wemm if (!bitset(EF_DISCARD, e->e_flags)) 155306f25ae9SGregory Neil Shapiro { 1554c2aa98e2SPeter Wemm rcode = checkcompat(to, e); 155540266059SGregory Neil Shapiro ovr = false; 155606f25ae9SGregory Neil Shapiro } 1557c2aa98e2SPeter Wemm } 1558c2aa98e2SPeter Wemm if (rcode != EX_OK) 1559c2aa98e2SPeter Wemm { 156006f25ae9SGregory Neil Shapiro markfailure(e, to, NULL, rcode, ovr); 156106f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, 156240266059SGregory Neil Shapiro NULL, ctladdr, xstart, e, to); 1563c2aa98e2SPeter Wemm continue; 1564c2aa98e2SPeter Wemm } 156540266059SGregory Neil Shapiro #if _FFR_QUARANTINE 156640266059SGregory Neil Shapiro if (!quarantine && e->e_quarmsg != NULL) 156740266059SGregory Neil Shapiro { 156840266059SGregory Neil Shapiro /* 156940266059SGregory Neil Shapiro ** check_compat or checkcompat() has tried 157040266059SGregory Neil Shapiro ** to quarantine but that isn't supported. 157140266059SGregory Neil Shapiro ** Revert the attempt. 157240266059SGregory Neil Shapiro */ 157340266059SGregory Neil Shapiro 157440266059SGregory Neil Shapiro e->e_quarmsg = NULL; 157540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 157640266059SGregory Neil Shapiro macid("{quarantine}"), ""); 157740266059SGregory Neil Shapiro } 157840266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 1579065a643dSPeter Wemm if (bitset(EF_DISCARD, e->e_flags)) 1580065a643dSPeter Wemm { 1581065a643dSPeter Wemm if (tTd(10, 5)) 1582065a643dSPeter Wemm { 158340266059SGregory Neil Shapiro sm_dprintf("deliver: discarding recipient "); 158440266059SGregory Neil Shapiro printaddr(to, false); 1585065a643dSPeter Wemm } 1586065a643dSPeter Wemm 158706f25ae9SGregory Neil Shapiro /* pretend the message was sent */ 158806f25ae9SGregory Neil Shapiro /* XXX should we log something here? */ 158906f25ae9SGregory Neil Shapiro to->q_state = QS_DISCARDED; 159006f25ae9SGregory Neil Shapiro 1591065a643dSPeter Wemm /* 1592065a643dSPeter Wemm ** Remove discard bit to prevent discard of 159306f25ae9SGregory Neil Shapiro ** future recipients. This is safe because the 159406f25ae9SGregory Neil Shapiro ** true "global discard" has been handled before 159506f25ae9SGregory Neil Shapiro ** we get here. 1596065a643dSPeter Wemm */ 1597065a643dSPeter Wemm 159806f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_DISCARD; 1599065a643dSPeter Wemm continue; 1600065a643dSPeter Wemm } 1601c2aa98e2SPeter Wemm 1602c2aa98e2SPeter Wemm /* 1603c2aa98e2SPeter Wemm ** Strip quote bits from names if the mailer is dumb 1604c2aa98e2SPeter Wemm ** about them. 1605c2aa98e2SPeter Wemm */ 1606c2aa98e2SPeter Wemm 1607c2aa98e2SPeter Wemm if (bitnset(M_STRIPQ, m->m_flags)) 1608c2aa98e2SPeter Wemm { 1609c2aa98e2SPeter Wemm stripquotes(user); 1610c2aa98e2SPeter Wemm stripquotes(host); 1611c2aa98e2SPeter Wemm } 1612c2aa98e2SPeter Wemm 1613c2aa98e2SPeter Wemm /* hack attack -- delivermail compatibility */ 1614c2aa98e2SPeter Wemm if (m == ProgMailer && *user == '|') 1615c2aa98e2SPeter Wemm user++; 1616c2aa98e2SPeter Wemm 1617c2aa98e2SPeter Wemm /* 1618c2aa98e2SPeter Wemm ** If an error message has already been given, don't 1619c2aa98e2SPeter Wemm ** bother to send to this address. 1620c2aa98e2SPeter Wemm ** 1621c2aa98e2SPeter Wemm ** >>>>>>>>>> This clause assumes that the local mailer 1622c2aa98e2SPeter Wemm ** >> NOTE >> cannot do any further aliasing; that 1623c2aa98e2SPeter Wemm ** >>>>>>>>>> function is subsumed by sendmail. 1624c2aa98e2SPeter Wemm */ 1625c2aa98e2SPeter Wemm 162606f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 1627c2aa98e2SPeter Wemm continue; 1628c2aa98e2SPeter Wemm 1629c2aa98e2SPeter Wemm /* 1630c2aa98e2SPeter Wemm ** See if this user name is "special". 1631c2aa98e2SPeter Wemm ** If the user name has a slash in it, assume that this 1632c2aa98e2SPeter Wemm ** is a file -- send it off without further ado. Note 1633c2aa98e2SPeter Wemm ** that this type of addresses is not processed along 1634c2aa98e2SPeter Wemm ** with the others, so we fudge on the To person. 1635c2aa98e2SPeter Wemm */ 1636c2aa98e2SPeter Wemm 1637c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[FILE]") == 0) 1638c2aa98e2SPeter Wemm { 163940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); 1640c2aa98e2SPeter Wemm p = to->q_home; 1641c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1642c2aa98e2SPeter Wemm p = ctladdr->q_home; 164340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); 1644c2aa98e2SPeter Wemm expand(m->m_argv[1], buf, sizeof buf, e); 1645c2aa98e2SPeter Wemm if (strlen(buf) > 0) 1646c2aa98e2SPeter Wemm rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 1647c2aa98e2SPeter Wemm else 1648c2aa98e2SPeter Wemm { 1649c2aa98e2SPeter Wemm syserr("empty filename specification for mailer %s", 1650c2aa98e2SPeter Wemm m->m_name); 1651c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1652c2aa98e2SPeter Wemm } 165306f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, NULL, 165440266059SGregory Neil Shapiro ctladdr, xstart, e, to); 165540266059SGregory Neil Shapiro markfailure(e, to, NULL, rcode, true); 1656c2aa98e2SPeter Wemm e->e_nsent++; 1657c2aa98e2SPeter Wemm if (rcode == EX_OK) 1658c2aa98e2SPeter Wemm { 165906f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 1660c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 1661c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 1662c2aa98e2SPeter Wemm { 1663c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 1664c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 166540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, 166640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 166740266059SGregory Neil Shapiro "%s... Successfully delivered\n", 1668c2aa98e2SPeter Wemm to->q_paddr); 1669c2aa98e2SPeter Wemm } 1670c2aa98e2SPeter Wemm } 1671c2aa98e2SPeter Wemm to->q_statdate = curtime(); 167240266059SGregory Neil Shapiro markstats(e, to, STATS_NORMAL); 1673c2aa98e2SPeter Wemm continue; 1674c2aa98e2SPeter Wemm } 1675c2aa98e2SPeter Wemm 1676c2aa98e2SPeter Wemm /* 1677c2aa98e2SPeter Wemm ** Address is verified -- add this user to mailer 1678c2aa98e2SPeter Wemm ** argv, and add it to the print list of recipients. 1679c2aa98e2SPeter Wemm */ 1680c2aa98e2SPeter Wemm 1681c2aa98e2SPeter Wemm /* link together the chain of recipients */ 1682c2aa98e2SPeter Wemm to->q_tchain = tochain; 1683c2aa98e2SPeter Wemm tochain = to; 168406f25ae9SGregory Neil Shapiro e->e_to = "[CHAIN]"; 168506f25ae9SGregory Neil Shapiro 168640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */ 1687c2aa98e2SPeter Wemm p = to->q_home; 1688c2aa98e2SPeter Wemm if (p == NULL && ctladdr != NULL) 1689c2aa98e2SPeter Wemm p = ctladdr->q_home; 169040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */ 1691c2aa98e2SPeter Wemm 169206f25ae9SGregory Neil Shapiro /* set the ${dsn_notify} macro if applicable */ 169306f25ae9SGregory Neil Shapiro if (bitset(QHASNOTIFY, to->q_flags)) 169406f25ae9SGregory Neil Shapiro { 169506f25ae9SGregory Neil Shapiro char notify[MAXLINE]; 169606f25ae9SGregory Neil Shapiro 169706f25ae9SGregory Neil Shapiro notify[0] = '\0'; 169806f25ae9SGregory Neil Shapiro if (bitset(QPINGONSUCCESS, to->q_flags)) 169940266059SGregory Neil Shapiro (void) sm_strlcat(notify, "SUCCESS,", 170006f25ae9SGregory Neil Shapiro sizeof notify); 170106f25ae9SGregory Neil Shapiro if (bitset(QPINGONFAILURE, to->q_flags)) 170240266059SGregory Neil Shapiro (void) sm_strlcat(notify, "FAILURE,", 170306f25ae9SGregory Neil Shapiro sizeof notify); 170406f25ae9SGregory Neil Shapiro if (bitset(QPINGONDELAY, to->q_flags)) 170540266059SGregory Neil Shapiro (void) sm_strlcat(notify, "DELAY,", 170640266059SGregory Neil Shapiro sizeof notify); 170706f25ae9SGregory Neil Shapiro 170806f25ae9SGregory Neil Shapiro /* Set to NEVER or drop trailing comma */ 170906f25ae9SGregory Neil Shapiro if (notify[0] == '\0') 171040266059SGregory Neil Shapiro (void) sm_strlcat(notify, "NEVER", 171140266059SGregory Neil Shapiro sizeof notify); 171206f25ae9SGregory Neil Shapiro else 171306f25ae9SGregory Neil Shapiro notify[strlen(notify) - 1] = '\0'; 171406f25ae9SGregory Neil Shapiro 171540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 171640266059SGregory Neil Shapiro macid("{dsn_notify}"), notify); 171706f25ae9SGregory Neil Shapiro } 171806f25ae9SGregory Neil Shapiro else 171940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 172040266059SGregory Neil Shapiro macid("{dsn_notify}"), NULL); 172106f25ae9SGregory Neil Shapiro 1722c2aa98e2SPeter Wemm /* 1723c2aa98e2SPeter Wemm ** Expand out this user into argument list. 1724c2aa98e2SPeter Wemm */ 1725c2aa98e2SPeter Wemm 1726c2aa98e2SPeter Wemm if (!clever) 1727c2aa98e2SPeter Wemm { 1728c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 172940266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1730c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV - 2]) 1731c2aa98e2SPeter Wemm { 1732c2aa98e2SPeter Wemm /* allow some space for trailing parms */ 1733c2aa98e2SPeter Wemm break; 1734c2aa98e2SPeter Wemm } 1735c2aa98e2SPeter Wemm } 1736c2aa98e2SPeter Wemm } 1737c2aa98e2SPeter Wemm 1738c2aa98e2SPeter Wemm /* see if any addresses still exist */ 173906f25ae9SGregory Neil Shapiro if (tochain == NULL) 1740c2aa98e2SPeter Wemm { 174140266059SGregory Neil Shapiro rcode = 0; 174240266059SGregory Neil Shapiro goto cleanup; 1743c2aa98e2SPeter Wemm } 1744c2aa98e2SPeter Wemm 1745c2aa98e2SPeter Wemm /* print out messages as full list */ 174640266059SGregory Neil Shapiro strsize = 1; 174706f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 174840266059SGregory Neil Shapiro strsize += strlen(to->q_paddr) + 1; 174940266059SGregory Neil Shapiro if (strsize < TOBUFSIZE) 175040266059SGregory Neil Shapiro strsize = TOBUFSIZE; 175140266059SGregory Neil Shapiro if (strsize > tobufsize) 175206f25ae9SGregory Neil Shapiro { 175340266059SGregory Neil Shapiro SM_FREE_CLR(tobuf); 175440266059SGregory Neil Shapiro tobuf = sm_pmalloc_x(strsize); 175540266059SGregory Neil Shapiro tobufsize = strsize; 175606f25ae9SGregory Neil Shapiro } 175740266059SGregory Neil Shapiro p = tobuf; 175840266059SGregory Neil Shapiro *p = '\0'; 175906f25ae9SGregory Neil Shapiro for (to = tochain; to != NULL; to = to->q_tchain) 176006f25ae9SGregory Neil Shapiro { 176140266059SGregory Neil Shapiro (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2, 176240266059SGregory Neil Shapiro ",", to->q_paddr); 176340266059SGregory Neil Shapiro p += strlen(p); 176406f25ae9SGregory Neil Shapiro } 1765c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 1766c2aa98e2SPeter Wemm 1767c2aa98e2SPeter Wemm /* 1768c2aa98e2SPeter Wemm ** Fill out any parameters after the $u parameter. 1769c2aa98e2SPeter Wemm */ 1770c2aa98e2SPeter Wemm 177140266059SGregory Neil Shapiro if (!clever) 177240266059SGregory Neil Shapiro { 177340266059SGregory Neil Shapiro while (*++mvp != NULL) 1774c2aa98e2SPeter Wemm { 1775c2aa98e2SPeter Wemm expand(*mvp, buf, sizeof buf, e); 177640266059SGregory Neil Shapiro *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 1777c2aa98e2SPeter Wemm if (pvp >= &pv[MAXPV]) 177806f25ae9SGregory Neil Shapiro syserr("554 5.3.0 deliver: pv overflow after $u for %s", 177906f25ae9SGregory Neil Shapiro pv[0]); 1780c2aa98e2SPeter Wemm } 178140266059SGregory Neil Shapiro } 1782c2aa98e2SPeter Wemm *pvp++ = NULL; 1783c2aa98e2SPeter Wemm 1784c2aa98e2SPeter Wemm /* 1785c2aa98e2SPeter Wemm ** Call the mailer. 1786c2aa98e2SPeter Wemm ** The argument vector gets built, pipes 1787c2aa98e2SPeter Wemm ** are created as necessary, and we fork & exec as 1788c2aa98e2SPeter Wemm ** appropriate. 1789c2aa98e2SPeter Wemm ** If we are running SMTP, we just need to clean up. 1790c2aa98e2SPeter Wemm */ 1791c2aa98e2SPeter Wemm 1792c2aa98e2SPeter Wemm /* XXX this seems a bit wierd */ 1793c2aa98e2SPeter Wemm if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 1794c2aa98e2SPeter Wemm bitset(QGOODUID, e->e_from.q_flags)) 1795c2aa98e2SPeter Wemm ctladdr = &e->e_from; 1796c2aa98e2SPeter Wemm 1797c2aa98e2SPeter Wemm #if NAMED_BIND 1798c2aa98e2SPeter Wemm if (ConfigLevel < 2) 1799c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 180006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 1801c2aa98e2SPeter Wemm 1802c2aa98e2SPeter Wemm if (tTd(11, 1)) 1803c2aa98e2SPeter Wemm { 180440266059SGregory Neil Shapiro sm_dprintf("openmailer:"); 1805c2aa98e2SPeter Wemm printav(pv); 1806c2aa98e2SPeter Wemm } 1807c2aa98e2SPeter Wemm errno = 0; 1808602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 1809c2aa98e2SPeter Wemm CurHostName = NULL; 1810c2aa98e2SPeter Wemm 1811c2aa98e2SPeter Wemm /* 1812c2aa98e2SPeter Wemm ** Deal with the special case of mail handled through an IPC 1813c2aa98e2SPeter Wemm ** connection. 1814c2aa98e2SPeter Wemm ** In this case we don't actually fork. We must be 1815c2aa98e2SPeter Wemm ** running SMTP for this to work. We will return a 1816c2aa98e2SPeter Wemm ** zero pid to indicate that we are running IPC. 1817c2aa98e2SPeter Wemm ** We also handle a debug version that just talks to stdin/out. 1818c2aa98e2SPeter Wemm */ 1819c2aa98e2SPeter Wemm 1820c2aa98e2SPeter Wemm curhost = NULL; 1821c2aa98e2SPeter Wemm SmtpPhase = NULL; 1822c2aa98e2SPeter Wemm mci = NULL; 1823c2aa98e2SPeter Wemm 1824c2aa98e2SPeter Wemm #if XDEBUG 1825c2aa98e2SPeter Wemm { 1826c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 1827c2aa98e2SPeter Wemm 1828c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 182940266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)", 183040266059SGregory Neil Shapiro shortenstring(e->e_to, MAXSHORTSTR), 183140266059SGregory Neil Shapiro m->m_name); 1832c2aa98e2SPeter Wemm checkfd012(wbuf); 1833c2aa98e2SPeter Wemm } 183406f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1835c2aa98e2SPeter Wemm 1836c2aa98e2SPeter Wemm /* check for 8-bit available */ 1837c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 1838c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags) && 1839c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 1840c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 1841c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 1842c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 1843c2aa98e2SPeter Wemm { 1844c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 184506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 184606f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 184706f25ae9SGregory Neil Shapiro rcode = EX_DATAERR; 1848c2aa98e2SPeter Wemm goto give_up; 1849c2aa98e2SPeter Wemm } 1850c2aa98e2SPeter Wemm 1851c2aa98e2SPeter Wemm if (tTd(62, 8)) 1852c2aa98e2SPeter Wemm checkfds("before delivery"); 1853c2aa98e2SPeter Wemm 1854c2aa98e2SPeter Wemm /* check for Local Person Communication -- not for mortals!!! */ 1855c2aa98e2SPeter Wemm if (strcmp(m->m_mailer, "[LPC]") == 0) 1856c2aa98e2SPeter Wemm { 185740266059SGregory Neil Shapiro #if _FFR_CACHE_LPC 185840266059SGregory Neil Shapiro if (clever) 185940266059SGregory Neil Shapiro { 186040266059SGregory Neil Shapiro /* flush any expired connections */ 186140266059SGregory Neil Shapiro (void) mci_scan(NULL); 186240266059SGregory Neil Shapiro 186340266059SGregory Neil Shapiro /* try to get a cached connection or just a slot */ 186440266059SGregory Neil Shapiro mci = mci_get(m->m_name, m); 186540266059SGregory Neil Shapiro if (mci->mci_host == NULL) 186640266059SGregory Neil Shapiro mci->mci_host = m->m_name; 186740266059SGregory Neil Shapiro CurHostName = mci->mci_host; 186840266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED) 186940266059SGregory Neil Shapiro { 187040266059SGregory Neil Shapiro message("Using cached SMTP/LPC connection for %s...", 187140266059SGregory Neil Shapiro m->m_name); 187240266059SGregory Neil Shapiro mci->mci_deliveries++; 187340266059SGregory Neil Shapiro goto do_transfer; 187440266059SGregory Neil Shapiro } 187540266059SGregory Neil Shapiro } 187640266059SGregory Neil Shapiro else 187740266059SGregory Neil Shapiro { 187840266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 187940266059SGregory Neil Shapiro } 188040266059SGregory Neil Shapiro mci->mci_in = smioin; 188140266059SGregory Neil Shapiro mci->mci_out = smioout; 188240266059SGregory Neil Shapiro mci->mci_mailer = m; 188340266059SGregory Neil Shapiro mci->mci_host = m->m_name; 188440266059SGregory Neil Shapiro if (clever) 188540266059SGregory Neil Shapiro { 188640266059SGregory Neil Shapiro mci->mci_state = MCIS_OPENING; 188740266059SGregory Neil Shapiro mci_cache(mci); 188840266059SGregory Neil Shapiro } 188940266059SGregory Neil Shapiro else 189040266059SGregory Neil Shapiro mci->mci_state = MCIS_OPEN; 189140266059SGregory Neil Shapiro #else /* _FFR_CACHE_LPC */ 189240266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 189340266059SGregory Neil Shapiro mci->mci_in = smioin; 189440266059SGregory Neil Shapiro mci->mci_out = smioout; 1895c2aa98e2SPeter Wemm mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 1896c2aa98e2SPeter Wemm mci->mci_mailer = m; 189740266059SGregory Neil Shapiro #endif /* _FFR_CACHE_LPC */ 1898c2aa98e2SPeter Wemm } 189940266059SGregory Neil Shapiro else if (strcmp(m->m_mailer, "[IPC]") == 0) 1900c2aa98e2SPeter Wemm { 1901c2aa98e2SPeter Wemm register int i; 1902c2aa98e2SPeter Wemm 1903c2aa98e2SPeter Wemm if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1904c2aa98e2SPeter Wemm { 190506f25ae9SGregory Neil Shapiro syserr("null destination for %s mailer", m->m_mailer); 1906c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1907c2aa98e2SPeter Wemm goto give_up; 1908c2aa98e2SPeter Wemm } 1909c2aa98e2SPeter Wemm 191006f25ae9SGregory Neil Shapiro # if NETUNIX 191106f25ae9SGregory Neil Shapiro if (strcmp(pv[0], "FILE") == 0) 191206f25ae9SGregory Neil Shapiro { 191306f25ae9SGregory Neil Shapiro curhost = CurHostName = "localhost"; 191406f25ae9SGregory Neil Shapiro mux_path = pv[1]; 191506f25ae9SGregory Neil Shapiro } 191606f25ae9SGregory Neil Shapiro else 191706f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 191806f25ae9SGregory Neil Shapiro { 1919c2aa98e2SPeter Wemm CurHostName = pv[1]; 192006f25ae9SGregory Neil Shapiro curhost = hostsignature(m, pv[1]); 192106f25ae9SGregory Neil Shapiro } 1922c2aa98e2SPeter Wemm 1923c2aa98e2SPeter Wemm if (curhost == NULL || curhost[0] == '\0') 1924c2aa98e2SPeter Wemm { 1925c2aa98e2SPeter Wemm syserr("null host signature for %s", pv[1]); 1926c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1927c2aa98e2SPeter Wemm goto give_up; 1928c2aa98e2SPeter Wemm } 1929c2aa98e2SPeter Wemm 1930c2aa98e2SPeter Wemm if (!clever) 1931c2aa98e2SPeter Wemm { 193206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 non-clever IPC"); 1933c2aa98e2SPeter Wemm rcode = EX_CONFIG; 1934c2aa98e2SPeter Wemm goto give_up; 1935c2aa98e2SPeter Wemm } 193606f25ae9SGregory Neil Shapiro if (pv[2] != NULL 193706f25ae9SGregory Neil Shapiro # if NETUNIX 193806f25ae9SGregory Neil Shapiro && mux_path == NULL 193906f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 194006f25ae9SGregory Neil Shapiro ) 1941c2aa98e2SPeter Wemm { 194240266059SGregory Neil Shapiro port = htons((unsigned short) atoi(pv[2])); 1943c2aa98e2SPeter Wemm if (port == 0) 1944c2aa98e2SPeter Wemm { 194506f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME 194606f25ae9SGregory Neil Shapiro syserr("Invalid port number: %s", pv[2]); 194706f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */ 1948c2aa98e2SPeter Wemm struct servent *sp = getservbyname(pv[2], "tcp"); 1949c2aa98e2SPeter Wemm 1950c2aa98e2SPeter Wemm if (sp == NULL) 1951c2aa98e2SPeter Wemm syserr("Service %s unknown", pv[2]); 1952c2aa98e2SPeter Wemm else 1953c2aa98e2SPeter Wemm port = sp->s_port; 195406f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */ 1955c2aa98e2SPeter Wemm } 1956c2aa98e2SPeter Wemm } 1957c2aa98e2SPeter Wemm 195806f25ae9SGregory Neil Shapiro nummxhosts = parse_hostsignature(curhost, mxhosts, m); 195940266059SGregory Neil Shapiro if (TimeOuts.to_aconnect > 0) 196040266059SGregory Neil Shapiro enough = curtime() + TimeOuts.to_aconnect; 196106f25ae9SGregory Neil Shapiro tryhost: 196206f25ae9SGregory Neil Shapiro while (hostnum < nummxhosts) 196306f25ae9SGregory Neil Shapiro { 196406f25ae9SGregory Neil Shapiro char sep = ':'; 196506f25ae9SGregory Neil Shapiro char *endp; 196606f25ae9SGregory Neil Shapiro static char hostbuf[MAXNAME + 1]; 196706f25ae9SGregory Neil Shapiro 196806f25ae9SGregory Neil Shapiro # if NETINET6 196906f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '[') 197006f25ae9SGregory Neil Shapiro { 197106f25ae9SGregory Neil Shapiro endp = strchr(mxhosts[hostnum] + 1, ']'); 197206f25ae9SGregory Neil Shapiro if (endp != NULL) 197306f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 197406f25ae9SGregory Neil Shapiro } 197506f25ae9SGregory Neil Shapiro else 197606f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 197706f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 197806f25ae9SGregory Neil Shapiro endp = strpbrk(mxhosts[hostnum], ":,"); 197906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 198006f25ae9SGregory Neil Shapiro if (endp != NULL) 198106f25ae9SGregory Neil Shapiro { 198206f25ae9SGregory Neil Shapiro sep = *endp; 198306f25ae9SGregory Neil Shapiro *endp = '\0'; 198406f25ae9SGregory Neil Shapiro } 198506f25ae9SGregory Neil Shapiro 198640266059SGregory Neil Shapiro if (hostnum == 1 && skip_back != NULL) 198740266059SGregory Neil Shapiro { 198840266059SGregory Neil Shapiro /* 198940266059SGregory Neil Shapiro ** Coattail piggybacking is no longer an 199040266059SGregory Neil Shapiro ** option with the mail host next to be tried 199140266059SGregory Neil Shapiro ** no longer the lowest MX preference 199240266059SGregory Neil Shapiro ** (hostnum == 1 meaning we're on the second 199340266059SGregory Neil Shapiro ** preference). We do not try to coattail 199440266059SGregory Neil Shapiro ** piggyback more than the first MX preference. 199540266059SGregory Neil Shapiro ** Revert 'tochain' to last location for 199640266059SGregory Neil Shapiro ** coincidental piggybacking. This works this 199740266059SGregory Neil Shapiro ** easily because the q_tchain kept getting 199840266059SGregory Neil Shapiro ** added to the top of the linked list. 199940266059SGregory Neil Shapiro */ 200040266059SGregory Neil Shapiro 200140266059SGregory Neil Shapiro tochain = skip_back; 200240266059SGregory Neil Shapiro } 200340266059SGregory Neil Shapiro 200406f25ae9SGregory Neil Shapiro if (*mxhosts[hostnum] == '\0') 2005c2aa98e2SPeter Wemm { 2006c2aa98e2SPeter Wemm syserr("deliver: null host name in signature"); 200706f25ae9SGregory Neil Shapiro hostnum++; 200806f25ae9SGregory Neil Shapiro if (endp != NULL) 200906f25ae9SGregory Neil Shapiro *endp = sep; 2010c2aa98e2SPeter Wemm continue; 2011c2aa98e2SPeter Wemm } 201240266059SGregory Neil Shapiro (void) sm_strlcpy(hostbuf, mxhosts[hostnum], 201306f25ae9SGregory Neil Shapiro sizeof hostbuf); 201406f25ae9SGregory Neil Shapiro hostnum++; 201506f25ae9SGregory Neil Shapiro if (endp != NULL) 201606f25ae9SGregory Neil Shapiro *endp = sep; 2017c2aa98e2SPeter Wemm 2018c2aa98e2SPeter Wemm /* see if we already know that this host is fried */ 2019c2aa98e2SPeter Wemm CurHostName = hostbuf; 2020c2aa98e2SPeter Wemm mci = mci_get(hostbuf, m); 2021c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2022c2aa98e2SPeter Wemm { 202340266059SGregory Neil Shapiro char *type; 202440266059SGregory Neil Shapiro 2025c2aa98e2SPeter Wemm if (tTd(11, 1)) 2026c2aa98e2SPeter Wemm { 202740266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 202840266059SGregory Neil Shapiro mci_dump(mci, false); 2029c2aa98e2SPeter Wemm } 2030c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 203140266059SGregory Neil Shapiro if (bitnset(M_LMTP, m->m_flags)) 203240266059SGregory Neil Shapiro type = "L"; 203340266059SGregory Neil Shapiro else if (bitset(MCIF_ESMTP, mci->mci_flags)) 203440266059SGregory Neil Shapiro type = "ES"; 203540266059SGregory Neil Shapiro else 203640266059SGregory Neil Shapiro type = "S"; 203740266059SGregory Neil Shapiro message("Using cached %sMTP connection to %s via %s...", 203840266059SGregory Neil Shapiro type, hostbuf, m->m_name); 203906f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2040c2aa98e2SPeter Wemm break; 2041c2aa98e2SPeter Wemm } 2042c2aa98e2SPeter Wemm mci->mci_mailer = m; 2043c2aa98e2SPeter Wemm if (mci->mci_exitstat != EX_OK) 2044c2aa98e2SPeter Wemm { 2045c2aa98e2SPeter Wemm if (mci->mci_exitstat == EX_TEMPFAIL) 204640266059SGregory Neil Shapiro goodmxfound = true; 2047c2aa98e2SPeter Wemm continue; 2048c2aa98e2SPeter Wemm } 2049c2aa98e2SPeter Wemm 2050c2aa98e2SPeter Wemm if (mci_lock_host(mci) != EX_OK) 2051c2aa98e2SPeter Wemm { 2052c2aa98e2SPeter Wemm mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 205340266059SGregory Neil Shapiro goodmxfound = true; 2054c2aa98e2SPeter Wemm continue; 2055c2aa98e2SPeter Wemm } 2056c2aa98e2SPeter Wemm 2057c2aa98e2SPeter Wemm /* try the connection */ 205840266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %s", 205906f25ae9SGregory Neil Shapiro qid_printname(e), 206006f25ae9SGregory Neil Shapiro hostbuf, "user open"); 206106f25ae9SGregory Neil Shapiro # if NETUNIX 206206f25ae9SGregory Neil Shapiro if (mux_path != NULL) 206306f25ae9SGregory Neil Shapiro { 206406f25ae9SGregory Neil Shapiro message("Connecting to %s via %s...", 206506f25ae9SGregory Neil Shapiro mux_path, m->m_name); 206640266059SGregory Neil Shapiro i = makeconnection_ds((char *) mux_path, mci); 206706f25ae9SGregory Neil Shapiro } 206806f25ae9SGregory Neil Shapiro else 206906f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 207006f25ae9SGregory Neil Shapiro { 2071c2aa98e2SPeter Wemm if (port == 0) 2072c2aa98e2SPeter Wemm message("Connecting to %s via %s...", 2073c2aa98e2SPeter Wemm hostbuf, m->m_name); 2074c2aa98e2SPeter Wemm else 2075c2aa98e2SPeter Wemm message("Connecting to %s port %d via %s...", 207606f25ae9SGregory Neil Shapiro hostbuf, ntohs(port), 207706f25ae9SGregory Neil Shapiro m->m_name); 207840266059SGregory Neil Shapiro i = makeconnection(hostbuf, port, mci, e, 207940266059SGregory Neil Shapiro enough); 208006f25ae9SGregory Neil Shapiro } 20818774250cSGregory Neil Shapiro mci->mci_errno = errno; 2082c2aa98e2SPeter Wemm mci->mci_lastuse = curtime(); 208306f25ae9SGregory Neil Shapiro mci->mci_deliveries = 0; 2084c2aa98e2SPeter Wemm mci->mci_exitstat = i; 2085c2aa98e2SPeter Wemm # if NAMED_BIND 2086c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 208706f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */ 208840266059SGregory Neil Shapiro 208940266059SGregory Neil Shapiro /* 209040266059SGregory Neil Shapiro ** Have we tried long enough to get a connection? 209140266059SGregory Neil Shapiro ** If yes, skip to the fallback MX hosts 209240266059SGregory Neil Shapiro ** (if existent). 209340266059SGregory Neil Shapiro */ 209440266059SGregory Neil Shapiro 209540266059SGregory Neil Shapiro if (enough > 0 && mci->mci_lastuse >= enough) 209640266059SGregory Neil Shapiro { 209740266059SGregory Neil Shapiro int h; 209840266059SGregory Neil Shapiro # if NAMED_BIND 209940266059SGregory Neil Shapiro extern int NumFallBackMXHosts; 210040266059SGregory Neil Shapiro # else /* NAMED_BIND */ 210140266059SGregory Neil Shapiro const int NumFallBackMXHosts = 0; 210240266059SGregory Neil Shapiro # endif /* NAMED_BIND */ 210340266059SGregory Neil Shapiro 210440266059SGregory Neil Shapiro if (hostnum < nummxhosts && LogLevel > 9) 210540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 210640266059SGregory Neil Shapiro "Timeout.to_aconnect occurred before exhausting all addresses"); 210740266059SGregory Neil Shapiro 210840266059SGregory Neil Shapiro /* turn off timeout if fallback available */ 210940266059SGregory Neil Shapiro if (NumFallBackMXHosts > 0) 211040266059SGregory Neil Shapiro enough = 0; 211140266059SGregory Neil Shapiro 211240266059SGregory Neil Shapiro /* skip to a fallback MX host */ 211340266059SGregory Neil Shapiro h = nummxhosts - NumFallBackMXHosts; 211440266059SGregory Neil Shapiro if (hostnum < h) 211540266059SGregory Neil Shapiro hostnum = h; 211640266059SGregory Neil Shapiro } 2117c2aa98e2SPeter Wemm if (i == EX_OK) 2118c2aa98e2SPeter Wemm { 211940266059SGregory Neil Shapiro goodmxfound = true; 2120605302a5SGregory Neil Shapiro markstats(e, firstto, STATS_CONNECT); 2121c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2122c2aa98e2SPeter Wemm mci_cache(mci); 2123c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 212440266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 212540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 212640266059SGregory Neil Shapiro "%05d === CONNECT %s\n", 212740266059SGregory Neil Shapiro (int) CurrentPid, 212840266059SGregory Neil Shapiro hostbuf); 2129c2aa98e2SPeter Wemm break; 2130c2aa98e2SPeter Wemm } 2131c2aa98e2SPeter Wemm else 2132c2aa98e2SPeter Wemm { 2133c2aa98e2SPeter Wemm if (tTd(11, 1)) 213440266059SGregory Neil Shapiro sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 2135c2aa98e2SPeter Wemm i, errno); 2136c2aa98e2SPeter Wemm if (i == EX_TEMPFAIL) 213740266059SGregory Neil Shapiro goodmxfound = true; 2138c2aa98e2SPeter Wemm mci_unlock_host(mci); 2139c2aa98e2SPeter Wemm } 2140c2aa98e2SPeter Wemm 2141c2aa98e2SPeter Wemm /* enter status of this host */ 2142c2aa98e2SPeter Wemm setstat(i); 2143c2aa98e2SPeter Wemm 2144c2aa98e2SPeter Wemm /* should print some message here for -v mode */ 2145c2aa98e2SPeter Wemm } 2146c2aa98e2SPeter Wemm if (mci == NULL) 2147c2aa98e2SPeter Wemm { 2148c2aa98e2SPeter Wemm syserr("deliver: no host name"); 2149c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 2150c2aa98e2SPeter Wemm goto give_up; 2151c2aa98e2SPeter Wemm } 2152c2aa98e2SPeter Wemm mci->mci_pid = 0; 2153c2aa98e2SPeter Wemm } 2154c2aa98e2SPeter Wemm else 2155c2aa98e2SPeter Wemm { 2156c2aa98e2SPeter Wemm /* flush any expired connections */ 2157c2aa98e2SPeter Wemm (void) mci_scan(NULL); 2158c2aa98e2SPeter Wemm mci = NULL; 2159c2aa98e2SPeter Wemm 2160c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 2161c2aa98e2SPeter Wemm { 2162c2aa98e2SPeter Wemm /* try to get a cached connection */ 2163c2aa98e2SPeter Wemm mci = mci_get(m->m_name, m); 2164c2aa98e2SPeter Wemm if (mci->mci_host == NULL) 2165c2aa98e2SPeter Wemm mci->mci_host = m->m_name; 2166c2aa98e2SPeter Wemm CurHostName = mci->mci_host; 2167c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_CLOSED) 2168c2aa98e2SPeter Wemm { 2169c2aa98e2SPeter Wemm message("Using cached LMTP connection for %s...", 2170c2aa98e2SPeter Wemm m->m_name); 217106f25ae9SGregory Neil Shapiro mci->mci_deliveries++; 2172c2aa98e2SPeter Wemm goto do_transfer; 2173c2aa98e2SPeter Wemm } 2174c2aa98e2SPeter Wemm } 2175c2aa98e2SPeter Wemm 2176c2aa98e2SPeter Wemm /* announce the connection to verbose listeners */ 2177c2aa98e2SPeter Wemm if (host == NULL || host[0] == '\0') 2178c2aa98e2SPeter Wemm message("Connecting to %s...", m->m_name); 2179c2aa98e2SPeter Wemm else 2180c2aa98e2SPeter Wemm message("Connecting to %s via %s...", host, m->m_name); 2181c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 2182c2aa98e2SPeter Wemm { 2183c2aa98e2SPeter Wemm char **av; 2184c2aa98e2SPeter Wemm 218540266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 218640266059SGregory Neil Shapiro "%05d === EXEC", (int) CurrentPid); 2187c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 218840266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 218940266059SGregory Neil Shapiro SM_TIME_DEFAULT, " %s", 219040266059SGregory Neil Shapiro *av); 219140266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 219240266059SGregory Neil Shapiro "\n"); 2193c2aa98e2SPeter Wemm } 2194c2aa98e2SPeter Wemm 2195c2aa98e2SPeter Wemm #if XDEBUG 2196c2aa98e2SPeter Wemm checkfd012("before creating mail pipe"); 219706f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2198c2aa98e2SPeter Wemm 2199c2aa98e2SPeter Wemm /* create a pipe to shove the mail through */ 2200c2aa98e2SPeter Wemm if (pipe(mpvect) < 0) 2201c2aa98e2SPeter Wemm { 2202c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (to mailer)", 2203c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2204c2aa98e2SPeter Wemm if (tTd(11, 1)) 220540266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2206c2aa98e2SPeter Wemm rcode = EX_OSERR; 2207c2aa98e2SPeter Wemm goto give_up; 2208c2aa98e2SPeter Wemm } 2209c2aa98e2SPeter Wemm 2210c2aa98e2SPeter Wemm #if XDEBUG 2211c2aa98e2SPeter Wemm /* make sure we didn't get one of the standard I/O files */ 2212c2aa98e2SPeter Wemm if (mpvect[0] < 3 || mpvect[1] < 3) 2213c2aa98e2SPeter Wemm { 2214c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): bogus mpvect %d %d", 2215c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 2216c2aa98e2SPeter Wemm mpvect[0], mpvect[1]); 221740266059SGregory Neil Shapiro printopenfds(true); 2218c2aa98e2SPeter Wemm if (tTd(11, 1)) 221940266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2220c2aa98e2SPeter Wemm rcode = EX_OSERR; 2221c2aa98e2SPeter Wemm goto give_up; 2222c2aa98e2SPeter Wemm } 2223c2aa98e2SPeter Wemm 2224c2aa98e2SPeter Wemm /* make sure system call isn't dead meat */ 2225c2aa98e2SPeter Wemm checkfdopen(mpvect[0], "mpvect[0]"); 2226c2aa98e2SPeter Wemm checkfdopen(mpvect[1], "mpvect[1]"); 2227c2aa98e2SPeter Wemm if (mpvect[0] == mpvect[1] || 2228c2aa98e2SPeter Wemm (e->e_lockfp != NULL && 222940266059SGregory Neil Shapiro (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 223040266059SGregory Neil Shapiro NULL) || 223140266059SGregory Neil Shapiro mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 223240266059SGregory Neil Shapiro NULL)))) 2233c2aa98e2SPeter Wemm { 2234c2aa98e2SPeter Wemm if (e->e_lockfp == NULL) 2235c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d", 2236c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2237c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1]); 2238c2aa98e2SPeter Wemm else 2239c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 2240c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2241c2aa98e2SPeter Wemm m->m_name, mpvect[0], mpvect[1], 224240266059SGregory Neil Shapiro sm_io_getinfo(e->e_lockfp, 224340266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL)); 2244c2aa98e2SPeter Wemm } 224506f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2246c2aa98e2SPeter Wemm 224706f25ae9SGregory Neil Shapiro /* create a return pipe */ 2248c2aa98e2SPeter Wemm if (pipe(rpvect) < 0) 2249c2aa98e2SPeter Wemm { 2250c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): pipe (from mailer)", 2251c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2252c2aa98e2SPeter Wemm m->m_name); 2253c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2254c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2255c2aa98e2SPeter Wemm if (tTd(11, 1)) 225640266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2257c2aa98e2SPeter Wemm rcode = EX_OSERR; 2258c2aa98e2SPeter Wemm goto give_up; 2259c2aa98e2SPeter Wemm } 2260c2aa98e2SPeter Wemm #if XDEBUG 2261c2aa98e2SPeter Wemm checkfdopen(rpvect[0], "rpvect[0]"); 2262c2aa98e2SPeter Wemm checkfdopen(rpvect[1], "rpvect[1]"); 226306f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 2264c2aa98e2SPeter Wemm 2265c2aa98e2SPeter Wemm /* 2266c2aa98e2SPeter Wemm ** Actually fork the mailer process. 2267c2aa98e2SPeter Wemm ** DOFORK is clever about retrying. 2268c2aa98e2SPeter Wemm ** 2269c2aa98e2SPeter Wemm ** Dispose of SIGCHLD signal catchers that may be laying 227006f25ae9SGregory Neil Shapiro ** around so that endmailer will get it. 2271c2aa98e2SPeter Wemm */ 2272c2aa98e2SPeter Wemm 227340266059SGregory Neil Shapiro if (e->e_xfp != NULL) /* for debugging */ 227440266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 227540266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 227640266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 227706f25ae9SGregory Neil Shapiro 227806f25ae9SGregory Neil Shapiro 2279c2aa98e2SPeter Wemm DOFORK(FORK); 2280c2aa98e2SPeter Wemm /* pid is set by DOFORK */ 228106f25ae9SGregory Neil Shapiro 2282c2aa98e2SPeter Wemm if (pid < 0) 2283c2aa98e2SPeter Wemm { 2284c2aa98e2SPeter Wemm /* failure */ 2285c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot fork", 2286c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 2287c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2288c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2289c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2290c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2291c2aa98e2SPeter Wemm if (tTd(11, 1)) 229240266059SGregory Neil Shapiro sm_dprintf("openmailer: NULL\n"); 2293c2aa98e2SPeter Wemm rcode = EX_OSERR; 2294c2aa98e2SPeter Wemm goto give_up; 2295c2aa98e2SPeter Wemm } 2296c2aa98e2SPeter Wemm else if (pid == 0) 2297c2aa98e2SPeter Wemm { 2298c2aa98e2SPeter Wemm int i; 229906f25ae9SGregory Neil Shapiro int save_errno; 230040266059SGregory Neil Shapiro int sff; 2301c2aa98e2SPeter Wemm int new_euid = NO_UID; 2302c2aa98e2SPeter Wemm int new_ruid = NO_UID; 2303c2aa98e2SPeter Wemm int new_gid = NO_GID; 230440266059SGregory Neil Shapiro char *user = NULL; 2305c2aa98e2SPeter Wemm struct stat stb; 2306c2aa98e2SPeter Wemm extern int DtableSize; 2307c2aa98e2SPeter Wemm 230840266059SGregory Neil Shapiro CurrentPid = getpid(); 230940266059SGregory Neil Shapiro 231013058a91SGregory Neil Shapiro /* clear the events to turn off SIGALRMs */ 231140266059SGregory Neil Shapiro sm_clear_events(); 231213058a91SGregory Neil Shapiro 23138774250cSGregory Neil Shapiro /* Reset global flags */ 23148774250cSGregory Neil Shapiro RestartRequest = NULL; 231540266059SGregory Neil Shapiro RestartWorkGroup = false; 23168774250cSGregory Neil Shapiro ShutdownRequest = NULL; 23178774250cSGregory Neil Shapiro PendingSignal = 0; 23188774250cSGregory Neil Shapiro 2319c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 232040266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, 232140266059SGregory Neil Shapiro SM_IO_WHAT_FD, 232240266059SGregory Neil Shapiro NULL)); 2323c2aa98e2SPeter Wemm 2324c2aa98e2SPeter Wemm /* child -- set up input & exec mailer */ 232540266059SGregory Neil Shapiro (void) sm_signal(SIGALRM, sm_signal_noop); 232640266059SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 232740266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_IGN); 232840266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_IGN); 232940266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 233013058a91SGregory Neil Shapiro # ifdef SIGUSR1 233140266059SGregory Neil Shapiro (void) sm_signal(SIGUSR1, sm_signal_noop); 233213058a91SGregory Neil Shapiro # endif /* SIGUSR1 */ 2333c2aa98e2SPeter Wemm 2334c2aa98e2SPeter Wemm if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 2335c2aa98e2SPeter Wemm stb.st_mode = 0; 2336c2aa98e2SPeter Wemm 2337c2aa98e2SPeter Wemm # if HASSETUSERCONTEXT 2338c2aa98e2SPeter Wemm /* 2339c2aa98e2SPeter Wemm ** Set user resources. 2340c2aa98e2SPeter Wemm */ 2341c2aa98e2SPeter Wemm 2342c2aa98e2SPeter Wemm if (contextaddr != NULL) 2343c2aa98e2SPeter Wemm { 2344c2aa98e2SPeter Wemm struct passwd *pwd; 2345c2aa98e2SPeter Wemm 2346c2aa98e2SPeter Wemm if (contextaddr->q_ruser != NULL) 2347c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_ruser); 2348c2aa98e2SPeter Wemm else 2349c2aa98e2SPeter Wemm pwd = sm_getpwnam(contextaddr->q_user); 2350c2aa98e2SPeter Wemm if (pwd != NULL) 2351c2aa98e2SPeter Wemm (void) setusercontext(NULL, 2352c2aa98e2SPeter Wemm pwd, pwd->pw_uid, 2353c2aa98e2SPeter Wemm LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); 2354c2aa98e2SPeter Wemm } 235506f25ae9SGregory Neil Shapiro # endif /* HASSETUSERCONTEXT */ 2356c2aa98e2SPeter Wemm 235740266059SGregory Neil Shapiro #if HASNICE 2358c2aa98e2SPeter Wemm /* tweak niceness */ 2359c2aa98e2SPeter Wemm if (m->m_nice != 0) 236006f25ae9SGregory Neil Shapiro (void) nice(m->m_nice); 236140266059SGregory Neil Shapiro #endif /* HASNICE */ 2362c2aa98e2SPeter Wemm 2363c2aa98e2SPeter Wemm /* reset group id */ 2364c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 2365c2aa98e2SPeter Wemm new_gid = m->m_gid; 2366c2aa98e2SPeter Wemm else if (bitset(S_ISGID, stb.st_mode)) 2367c2aa98e2SPeter Wemm new_gid = stb.st_gid; 2368c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_gid != 0) 2369c2aa98e2SPeter Wemm { 2370c2aa98e2SPeter Wemm if (!DontInitGroups) 2371c2aa98e2SPeter Wemm { 237240266059SGregory Neil Shapiro user = ctladdr->q_ruser; 237340266059SGregory Neil Shapiro if (user == NULL) 237440266059SGregory Neil Shapiro user = ctladdr->q_user; 2375c2aa98e2SPeter Wemm 237640266059SGregory Neil Shapiro if (initgroups(user, 237740266059SGregory Neil Shapiro ctladdr->q_gid) == -1 237840266059SGregory Neil Shapiro && suidwarn) 237906f25ae9SGregory Neil Shapiro { 2380c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 238140266059SGregory Neil Shapiro user, ctladdr->q_gid); 238206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 238306f25ae9SGregory Neil Shapiro } 2384c2aa98e2SPeter Wemm } 2385c2aa98e2SPeter Wemm else 2386c2aa98e2SPeter Wemm { 2387c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2388c2aa98e2SPeter Wemm 2389c2aa98e2SPeter Wemm gidset[0] = ctladdr->q_gid; 239040266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 239140266059SGregory Neil Shapiro && suidwarn) 239206f25ae9SGregory Neil Shapiro { 2393c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 239406f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 239506f25ae9SGregory Neil Shapiro } 2396c2aa98e2SPeter Wemm } 2397c2aa98e2SPeter Wemm new_gid = ctladdr->q_gid; 2398c2aa98e2SPeter Wemm } 2399c2aa98e2SPeter Wemm else 2400c2aa98e2SPeter Wemm { 2401c2aa98e2SPeter Wemm if (!DontInitGroups) 2402c2aa98e2SPeter Wemm { 240340266059SGregory Neil Shapiro user = DefUser; 240440266059SGregory Neil Shapiro if (initgroups(DefUser, DefGid) == -1 && 240540266059SGregory Neil Shapiro suidwarn) 240606f25ae9SGregory Neil Shapiro { 2407c2aa98e2SPeter Wemm syserr("openmailer: initgroups(%s, %d) failed", 2408c2aa98e2SPeter Wemm DefUser, DefGid); 240906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 241006f25ae9SGregory Neil Shapiro } 2411c2aa98e2SPeter Wemm } 2412c2aa98e2SPeter Wemm else 2413c2aa98e2SPeter Wemm { 2414c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 2415c2aa98e2SPeter Wemm 2416c2aa98e2SPeter Wemm gidset[0] = DefGid; 241740266059SGregory Neil Shapiro if (setgroups(1, gidset) == -1 241840266059SGregory Neil Shapiro && suidwarn) 241906f25ae9SGregory Neil Shapiro { 2420c2aa98e2SPeter Wemm syserr("openmailer: setgroups() failed"); 242106f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 242206f25ae9SGregory Neil Shapiro } 2423c2aa98e2SPeter Wemm } 2424c2aa98e2SPeter Wemm if (m->m_gid == 0) 2425c2aa98e2SPeter Wemm new_gid = DefGid; 2426c2aa98e2SPeter Wemm else 2427c2aa98e2SPeter Wemm new_gid = m->m_gid; 2428c2aa98e2SPeter Wemm } 242906f25ae9SGregory Neil Shapiro if (new_gid != NO_GID) 243006f25ae9SGregory Neil Shapiro { 243106f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 243206f25ae9SGregory Neil Shapiro bitnset(M_SPECIFIC_UID, m->m_flags) && 243306f25ae9SGregory Neil Shapiro new_gid != getgid() && 243406f25ae9SGregory Neil Shapiro new_gid != getegid()) 243506f25ae9SGregory Neil Shapiro { 243606f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 243740266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d", 243840266059SGregory Neil Shapiro (int) RunAsUid, (int) new_gid, 243940266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 244006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 244106f25ae9SGregory Neil Shapiro } 244206f25ae9SGregory Neil Shapiro 244306f25ae9SGregory Neil Shapiro if (setgid(new_gid) < 0 && suidwarn) 244406f25ae9SGregory Neil Shapiro { 2445c2aa98e2SPeter Wemm syserr("openmailer: setgid(%ld) failed", 2446c2aa98e2SPeter Wemm (long) new_gid); 244706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 244806f25ae9SGregory Neil Shapiro } 244906f25ae9SGregory Neil Shapiro } 245006f25ae9SGregory Neil Shapiro 245106f25ae9SGregory Neil Shapiro /* change root to some "safe" directory */ 245206f25ae9SGregory Neil Shapiro if (m->m_rootdir != NULL) 245306f25ae9SGregory Neil Shapiro { 245494c01205SGregory Neil Shapiro expand(m->m_rootdir, cbuf, sizeof cbuf, e); 245506f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 245640266059SGregory Neil Shapiro sm_dprintf("openmailer: chroot %s\n", 245794c01205SGregory Neil Shapiro cbuf); 245894c01205SGregory Neil Shapiro if (chroot(cbuf) < 0) 245906f25ae9SGregory Neil Shapiro { 246006f25ae9SGregory Neil Shapiro syserr("openmailer: Cannot chroot(%s)", 246194c01205SGregory Neil Shapiro cbuf); 246206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 246306f25ae9SGregory Neil Shapiro } 246406f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 246506f25ae9SGregory Neil Shapiro { 246606f25ae9SGregory Neil Shapiro syserr("openmailer: cannot chdir(/)"); 246706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 246806f25ae9SGregory Neil Shapiro } 246906f25ae9SGregory Neil Shapiro } 2470c2aa98e2SPeter Wemm 2471c2aa98e2SPeter Wemm /* reset user id */ 2472c2aa98e2SPeter Wemm endpwent(); 247340266059SGregory Neil Shapiro sm_mbdb_terminate(); 2474c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, m->m_flags)) 247513058a91SGregory Neil Shapiro { 2476c2aa98e2SPeter Wemm new_euid = m->m_uid; 247713058a91SGregory Neil Shapiro 247813058a91SGregory Neil Shapiro /* 247913058a91SGregory Neil Shapiro ** Undo the effects of the uid change in main 248013058a91SGregory Neil Shapiro ** for signal handling. The real uid may 248113058a91SGregory Neil Shapiro ** be used by mailer in adding a "From " 248213058a91SGregory Neil Shapiro ** line. 248313058a91SGregory Neil Shapiro */ 248413058a91SGregory Neil Shapiro 248513058a91SGregory Neil Shapiro if (RealUid != 0 && RealUid != getuid()) 248640266059SGregory Neil Shapiro { 248740266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 248840266059SGregory Neil Shapiro # if HASSETREUID 248940266059SGregory Neil Shapiro if (setreuid(RealUid, geteuid()) < 0) 249040266059SGregory Neil Shapiro { 249140266059SGregory Neil Shapiro syserr("openmailer: setreuid(%d, %d) failed", 249240266059SGregory Neil Shapiro (int) RealUid, (int) geteuid()); 249340266059SGregory Neil Shapiro exit(EX_OSERR); 249440266059SGregory Neil Shapiro } 249540266059SGregory Neil Shapiro # endif /* HASSETREUID */ 249640266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 249740266059SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 249813058a91SGregory Neil Shapiro new_ruid = RealUid; 249940266059SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 250040266059SGregory Neil Shapiro } 250113058a91SGregory Neil Shapiro } 2502c2aa98e2SPeter Wemm else if (bitset(S_ISUID, stb.st_mode)) 2503c2aa98e2SPeter Wemm new_ruid = stb.st_uid; 2504c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 2505c2aa98e2SPeter Wemm new_ruid = ctladdr->q_uid; 2506c2aa98e2SPeter Wemm else if (m->m_uid != 0) 2507c2aa98e2SPeter Wemm new_ruid = m->m_uid; 2508c2aa98e2SPeter Wemm else 2509c2aa98e2SPeter Wemm new_ruid = DefUid; 2510605302a5SGregory Neil Shapiro 2511605302a5SGregory Neil Shapiro # if _FFR_USE_SETLOGIN 2512605302a5SGregory Neil Shapiro /* run disconnected from terminal and set login name */ 2513605302a5SGregory Neil Shapiro if (setsid() >= 0 && 2514605302a5SGregory Neil Shapiro ctladdr != NULL && ctladdr->q_uid != 0 && 2515605302a5SGregory Neil Shapiro new_euid == ctladdr->q_uid) 2516605302a5SGregory Neil Shapiro { 2517605302a5SGregory Neil Shapiro struct passwd *pwd; 2518605302a5SGregory Neil Shapiro 2519605302a5SGregory Neil Shapiro pwd = sm_getpwuid(ctladdr->q_uid); 2520605302a5SGregory Neil Shapiro if (pwd != NULL && suidwarn) 2521605302a5SGregory Neil Shapiro (void) setlogin(pwd->pw_name); 2522605302a5SGregory Neil Shapiro endpwent(); 2523605302a5SGregory Neil Shapiro } 2524605302a5SGregory Neil Shapiro # endif /* _FFR_USE_SETLOGIN */ 2525605302a5SGregory Neil Shapiro 2526c2aa98e2SPeter Wemm if (new_euid != NO_UID) 2527c2aa98e2SPeter Wemm { 252806f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && new_euid != RunAsUid) 252906f25ae9SGregory Neil Shapiro { 253006f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 253140266059SGregory Neil Shapiro syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d", 253240266059SGregory Neil Shapiro (int) new_euid, (int) RunAsUid); 253306f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 253406f25ae9SGregory Neil Shapiro } 253506f25ae9SGregory Neil Shapiro 2536c2aa98e2SPeter Wemm vendor_set_uid(new_euid); 253706f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETEUID 2538c2aa98e2SPeter Wemm if (seteuid(new_euid) < 0 && suidwarn) 253906f25ae9SGregory Neil Shapiro { 2540c2aa98e2SPeter Wemm syserr("openmailer: seteuid(%ld) failed", 2541c2aa98e2SPeter Wemm (long) new_euid); 254206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 254306f25ae9SGregory Neil Shapiro } 254406f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 254506f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETREUID 2546c2aa98e2SPeter Wemm if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 254706f25ae9SGregory Neil Shapiro { 2548c2aa98e2SPeter Wemm syserr("openmailer: setreuid(%ld, %ld) failed", 2549c2aa98e2SPeter Wemm (long) new_ruid, (long) new_euid); 255006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 255106f25ae9SGregory Neil Shapiro } 255206f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 255306f25ae9SGregory Neil Shapiro # if MAILER_SETUID_METHOD == USE_SETUID 2554c2aa98e2SPeter Wemm if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 255506f25ae9SGregory Neil Shapiro { 2556c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2557c2aa98e2SPeter Wemm (long) new_euid); 255806f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 255906f25ae9SGregory Neil Shapiro } 256006f25ae9SGregory Neil Shapiro # endif /* MAILER_SETUID_METHOD == USE_SETUID */ 2561c2aa98e2SPeter Wemm } 2562c2aa98e2SPeter Wemm else if (new_ruid != NO_UID) 2563c2aa98e2SPeter Wemm { 2564c2aa98e2SPeter Wemm vendor_set_uid(new_ruid); 2565c2aa98e2SPeter Wemm if (setuid(new_ruid) < 0 && suidwarn) 256606f25ae9SGregory Neil Shapiro { 2567c2aa98e2SPeter Wemm syserr("openmailer: setuid(%ld) failed", 2568c2aa98e2SPeter Wemm (long) new_ruid); 256906f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 257006f25ae9SGregory Neil Shapiro } 2571c2aa98e2SPeter Wemm } 2572c2aa98e2SPeter Wemm 2573c2aa98e2SPeter Wemm if (tTd(11, 2)) 257440266059SGregory Neil Shapiro sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", 257506f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 257606f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 2577c2aa98e2SPeter Wemm 2578c2aa98e2SPeter Wemm /* move into some "safe" directory */ 2579c2aa98e2SPeter Wemm if (m->m_execdir != NULL) 2580c2aa98e2SPeter Wemm { 2581c2aa98e2SPeter Wemm char *q; 2582c2aa98e2SPeter Wemm 2583c2aa98e2SPeter Wemm for (p = m->m_execdir; p != NULL; p = q) 2584c2aa98e2SPeter Wemm { 2585c2aa98e2SPeter Wemm q = strchr(p, ':'); 2586c2aa98e2SPeter Wemm if (q != NULL) 2587c2aa98e2SPeter Wemm *q = '\0'; 258894c01205SGregory Neil Shapiro expand(p, cbuf, sizeof cbuf, e); 2589c2aa98e2SPeter Wemm if (q != NULL) 2590c2aa98e2SPeter Wemm *q++ = ':'; 2591c2aa98e2SPeter Wemm if (tTd(11, 20)) 259240266059SGregory Neil Shapiro sm_dprintf("openmailer: trydir %s\n", 259394c01205SGregory Neil Shapiro cbuf); 259494c01205SGregory Neil Shapiro if (cbuf[0] != '\0' && 259594c01205SGregory Neil Shapiro chdir(cbuf) >= 0) 2596c2aa98e2SPeter Wemm break; 2597c2aa98e2SPeter Wemm } 2598c2aa98e2SPeter Wemm } 2599c2aa98e2SPeter Wemm 260040266059SGregory Neil Shapiro /* Check safety of program to be run */ 260140266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK; 260240266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, 260340266059SGregory Neil Shapiro DontBlameSendmail)) 260440266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 260540266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, 260640266059SGregory Neil Shapiro DontBlameSendmail)) 260740266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK; 260840266059SGregory Neil Shapiro else 260940266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH; 261040266059SGregory Neil Shapiro ret = safefile(m->m_mailer, getuid(), getgid(), 261140266059SGregory Neil Shapiro user, sff, 0, NULL); 261240266059SGregory Neil Shapiro if (ret != 0) 261340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 261440266059SGregory Neil Shapiro "Warning: program %s unsafe: %s", 261540266059SGregory Neil Shapiro m->m_mailer, sm_errstring(ret)); 261640266059SGregory Neil Shapiro 2617c2aa98e2SPeter Wemm /* arrange to filter std & diag output of command */ 2618c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2619c2aa98e2SPeter Wemm if (dup2(rpvect[1], STDOUT_FILENO) < 0) 2620c2aa98e2SPeter Wemm { 2621c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 2622c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2623c2aa98e2SPeter Wemm m->m_name, rpvect[1]); 2624c2aa98e2SPeter Wemm _exit(EX_OSERR); 2625c2aa98e2SPeter Wemm } 2626c2aa98e2SPeter Wemm (void) close(rpvect[1]); 262706f25ae9SGregory Neil Shapiro 2628c2aa98e2SPeter Wemm if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 2629c2aa98e2SPeter Wemm { 2630c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup stdout for stderr", 2631c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2632c2aa98e2SPeter Wemm m->m_name); 2633c2aa98e2SPeter Wemm _exit(EX_OSERR); 2634c2aa98e2SPeter Wemm } 2635c2aa98e2SPeter Wemm 2636c2aa98e2SPeter Wemm /* arrange to get standard input */ 2637c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2638c2aa98e2SPeter Wemm if (dup2(mpvect[0], STDIN_FILENO) < 0) 2639c2aa98e2SPeter Wemm { 2640c2aa98e2SPeter Wemm syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 2641c2aa98e2SPeter Wemm shortenstring(e->e_to, MAXSHORTSTR), 2642c2aa98e2SPeter Wemm m->m_name, mpvect[0]); 2643c2aa98e2SPeter Wemm _exit(EX_OSERR); 2644c2aa98e2SPeter Wemm } 2645c2aa98e2SPeter Wemm (void) close(mpvect[0]); 2646c2aa98e2SPeter Wemm 2647c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2648c2aa98e2SPeter Wemm for (i = 3; i < DtableSize; i++) 2649c2aa98e2SPeter Wemm { 2650c2aa98e2SPeter Wemm register int j; 2651c2aa98e2SPeter Wemm 2652c2aa98e2SPeter Wemm if ((j = fcntl(i, F_GETFD, 0)) != -1) 265306f25ae9SGregory Neil Shapiro (void) fcntl(i, F_SETFD, 265406f25ae9SGregory Neil Shapiro j | FD_CLOEXEC); 2655c2aa98e2SPeter Wemm } 2656c2aa98e2SPeter Wemm 2657605302a5SGregory Neil Shapiro # if !_FFR_USE_SETLOGIN 2658c2aa98e2SPeter Wemm /* run disconnected from terminal */ 2659c2aa98e2SPeter Wemm (void) setsid(); 2660605302a5SGregory Neil Shapiro # endif /* !_FFR_USE_SETLOGIN */ 2661c2aa98e2SPeter Wemm 2662c2aa98e2SPeter Wemm /* try to execute the mailer */ 266306f25ae9SGregory Neil Shapiro (void) execve(m->m_mailer, (ARGV_T) pv, 266406f25ae9SGregory Neil Shapiro (ARGV_T) UserEnviron); 266506f25ae9SGregory Neil Shapiro save_errno = errno; 2666c2aa98e2SPeter Wemm syserr("Cannot exec %s", m->m_mailer); 2667c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) || 266806f25ae9SGregory Neil Shapiro transienterror(save_errno)) 2669c2aa98e2SPeter Wemm _exit(EX_OSERR); 2670c2aa98e2SPeter Wemm _exit(EX_UNAVAILABLE); 2671c2aa98e2SPeter Wemm } 2672c2aa98e2SPeter Wemm 2673c2aa98e2SPeter Wemm /* 2674c2aa98e2SPeter Wemm ** Set up return value. 2675c2aa98e2SPeter Wemm */ 2676c2aa98e2SPeter Wemm 2677c2aa98e2SPeter Wemm if (mci == NULL) 2678c2aa98e2SPeter Wemm { 267940266059SGregory Neil Shapiro if (clever) 268040266059SGregory Neil Shapiro { 268140266059SGregory Neil Shapiro /* 268240266059SGregory Neil Shapiro ** Allocate from general heap, not 268340266059SGregory Neil Shapiro ** envelope rpool, because this mci 268440266059SGregory Neil Shapiro ** is going to be cached. 268540266059SGregory Neil Shapiro */ 268640266059SGregory Neil Shapiro 268740266059SGregory Neil Shapiro mci = mci_new(NULL); 268840266059SGregory Neil Shapiro } 268940266059SGregory Neil Shapiro else 269040266059SGregory Neil Shapiro { 269140266059SGregory Neil Shapiro /* 269240266059SGregory Neil Shapiro ** Prevent a storage leak by allocating 269340266059SGregory Neil Shapiro ** this from the envelope rpool. 269440266059SGregory Neil Shapiro */ 269540266059SGregory Neil Shapiro 269640266059SGregory Neil Shapiro mci = mci_new(e->e_rpool); 269740266059SGregory Neil Shapiro } 2698c2aa98e2SPeter Wemm } 2699c2aa98e2SPeter Wemm mci->mci_mailer = m; 2700c2aa98e2SPeter Wemm if (clever) 2701c2aa98e2SPeter Wemm { 2702c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPENING; 2703c2aa98e2SPeter Wemm mci_cache(mci); 2704c2aa98e2SPeter Wemm } 2705c2aa98e2SPeter Wemm else 2706c2aa98e2SPeter Wemm { 2707c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 2708c2aa98e2SPeter Wemm } 2709c2aa98e2SPeter Wemm mci->mci_pid = pid; 2710c2aa98e2SPeter Wemm (void) close(mpvect[0]); 271140266059SGregory Neil Shapiro mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 271240266059SGregory Neil Shapiro (void *) &(mpvect[1]), SM_IO_WRONLY, 271340266059SGregory Neil Shapiro NULL); 2714c2aa98e2SPeter Wemm if (mci->mci_out == NULL) 2715c2aa98e2SPeter Wemm { 2716c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer output channel, fd=%d", 2717c2aa98e2SPeter Wemm mpvect[1]); 2718c2aa98e2SPeter Wemm (void) close(mpvect[1]); 2719c2aa98e2SPeter Wemm (void) close(rpvect[0]); 2720c2aa98e2SPeter Wemm (void) close(rpvect[1]); 2721c2aa98e2SPeter Wemm rcode = EX_OSERR; 2722c2aa98e2SPeter Wemm goto give_up; 2723c2aa98e2SPeter Wemm } 272406f25ae9SGregory Neil Shapiro 2725c2aa98e2SPeter Wemm (void) close(rpvect[1]); 272640266059SGregory Neil Shapiro mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 272740266059SGregory Neil Shapiro (void *) &(rpvect[0]), SM_IO_RDONLY, 272840266059SGregory Neil Shapiro NULL); 2729c2aa98e2SPeter Wemm if (mci->mci_in == NULL) 2730c2aa98e2SPeter Wemm { 2731c2aa98e2SPeter Wemm syserr("deliver: cannot create mailer input channel, fd=%d", 2732c2aa98e2SPeter Wemm mpvect[1]); 2733c2aa98e2SPeter Wemm (void) close(rpvect[0]); 273440266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 2735c2aa98e2SPeter Wemm mci->mci_out = NULL; 2736c2aa98e2SPeter Wemm rcode = EX_OSERR; 2737c2aa98e2SPeter Wemm goto give_up; 2738c2aa98e2SPeter Wemm } 2739c2aa98e2SPeter Wemm } 2740c2aa98e2SPeter Wemm 2741c2aa98e2SPeter Wemm /* 2742c2aa98e2SPeter Wemm ** If we are in SMTP opening state, send initial protocol. 2743c2aa98e2SPeter Wemm */ 2744c2aa98e2SPeter Wemm 2745c2aa98e2SPeter Wemm if (bitnset(M_7BITS, m->m_flags) && 2746c2aa98e2SPeter Wemm (!clever || mci->mci_state == MCIS_OPENING)) 2747c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_7BIT; 2748c2aa98e2SPeter Wemm if (clever && mci->mci_state != MCIS_CLOSED) 2749c2aa98e2SPeter Wemm { 275040266059SGregory Neil Shapiro # if STARTTLS || SASL 275140266059SGregory Neil Shapiro int dotpos; 275240266059SGregory Neil Shapiro char *srvname; 275340266059SGregory Neil Shapiro extern SOCKADDR CurHostAddr; 275440266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 275540266059SGregory Neil Shapiro 275640266059SGregory Neil Shapiro # if SASL 2757193538b7SGregory Neil Shapiro # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 275840266059SGregory Neil Shapiro # endif /* SASL */ 275906f25ae9SGregory Neil Shapiro # if STARTTLS 2760193538b7SGregory Neil Shapiro # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 276106f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 2762193538b7SGregory Neil Shapiro # define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 2763193538b7SGregory Neil Shapiro # define SET_HELO(f) f |= MCIF_ONLY_EHLO 2764193538b7SGregory Neil Shapiro # define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 2765c2aa98e2SPeter Wemm 276640266059SGregory Neil Shapiro # if STARTTLS || SASL 276740266059SGregory Neil Shapiro /* don't use CurHostName, it is changed in many places */ 2768602a2b1bSGregory Neil Shapiro if (mci->mci_host != NULL) 2769602a2b1bSGregory Neil Shapiro { 2770602a2b1bSGregory Neil Shapiro srvname = mci->mci_host; 2771602a2b1bSGregory Neil Shapiro dotpos = strlen(srvname) - 1; 2772602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2773602a2b1bSGregory Neil Shapiro { 2774602a2b1bSGregory Neil Shapiro if (srvname[dotpos] == '.') 2775602a2b1bSGregory Neil Shapiro srvname[dotpos] = '\0'; 2776602a2b1bSGregory Neil Shapiro else 2777602a2b1bSGregory Neil Shapiro dotpos = -1; 2778602a2b1bSGregory Neil Shapiro } 2779602a2b1bSGregory Neil Shapiro } 278040266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 2781602a2b1bSGregory Neil Shapiro { 278240266059SGregory Neil Shapiro srvname = mci->mci_mailer->m_name; 2783602a2b1bSGregory Neil Shapiro dotpos = -1; 2784602a2b1bSGregory Neil Shapiro } 278506f25ae9SGregory Neil Shapiro else 278606f25ae9SGregory Neil Shapiro { 278740266059SGregory Neil Shapiro srvname = "local"; 278840266059SGregory Neil Shapiro dotpos = -1; 2789193538b7SGregory Neil Shapiro } 279006f25ae9SGregory Neil Shapiro 279140266059SGregory Neil Shapiro /* don't set {server_name} to NULL or "": see getauth() */ 279240266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"), 279340266059SGregory Neil Shapiro srvname); 279440266059SGregory Neil Shapiro 279540266059SGregory Neil Shapiro /* CurHostAddr is set by makeconnection() and mci_get() */ 279640266059SGregory Neil Shapiro if (CurHostAddr.sa.sa_family != 0) 279740266059SGregory Neil Shapiro { 279840266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_TEMP, 279940266059SGregory Neil Shapiro macid("{server_addr}"), 280040266059SGregory Neil Shapiro anynet_ntoa(&CurHostAddr)); 280140266059SGregory Neil Shapiro } 280240266059SGregory Neil Shapiro else if (mci->mci_mailer != NULL) 280340266059SGregory Neil Shapiro { 280440266059SGregory Neil Shapiro /* mailer name is unique, use it as address */ 280540266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 280640266059SGregory Neil Shapiro macid("{server_addr}"), 280740266059SGregory Neil Shapiro mci->mci_mailer->m_name); 280840266059SGregory Neil Shapiro } 280940266059SGregory Neil Shapiro else 281040266059SGregory Neil Shapiro { 281140266059SGregory Neil Shapiro /* don't set it to NULL or "": see getauth() */ 281240266059SGregory Neil Shapiro macdefine(&mci->mci_macro, A_PERM, 281340266059SGregory Neil Shapiro macid("{server_addr}"), "0"); 281440266059SGregory Neil Shapiro } 281540266059SGregory Neil Shapiro 281640266059SGregory Neil Shapiro /* undo change of srvname (mci->mci_host) */ 2817602a2b1bSGregory Neil Shapiro if (dotpos >= 0) 2818602a2b1bSGregory Neil Shapiro srvname[dotpos] = '.'; 281940266059SGregory Neil Shapiro 282040266059SGregory Neil Shapiro reconnect: /* after switching to an encrypted connection */ 282140266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 282240266059SGregory Neil Shapiro 282340266059SGregory Neil Shapiro /* set the current connection information */ 282440266059SGregory Neil Shapiro e->e_mci = mci; 282540266059SGregory Neil Shapiro # if SASL 282640266059SGregory Neil Shapiro mci->mci_saslcap = NULL; 282740266059SGregory Neil Shapiro # endif /* SASL */ 282840266059SGregory Neil Shapiro smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 282940266059SGregory Neil Shapiro CLR_HELO(mci->mci_flags); 283040266059SGregory Neil Shapiro 283140266059SGregory Neil Shapiro if (IS_DLVR_RETURN(e)) 283240266059SGregory Neil Shapiro { 283340266059SGregory Neil Shapiro /* 283440266059SGregory Neil Shapiro ** Check whether other side can deliver e-mail 283540266059SGregory Neil Shapiro ** fast enough 283640266059SGregory Neil Shapiro */ 283740266059SGregory Neil Shapiro 283840266059SGregory Neil Shapiro if (!bitset(MCIF_DLVR_BY, mci->mci_flags)) 283940266059SGregory Neil Shapiro { 284040266059SGregory Neil Shapiro e->e_status = "5.4.7"; 284140266059SGregory Neil Shapiro usrerrenh(e->e_status, 284240266059SGregory Neil Shapiro "554 Server does not support Deliver By"); 284340266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 284440266059SGregory Neil Shapiro goto give_up; 284540266059SGregory Neil Shapiro } 284640266059SGregory Neil Shapiro if (e->e_deliver_by > 0 && 284740266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime) < 284840266059SGregory Neil Shapiro mci->mci_min_by) 284940266059SGregory Neil Shapiro { 285040266059SGregory Neil Shapiro e->e_status = "5.4.7"; 285140266059SGregory Neil Shapiro usrerrenh(e->e_status, 285240266059SGregory Neil Shapiro "554 Message can't be delivered in time; %ld < %ld", 285340266059SGregory Neil Shapiro e->e_deliver_by - (curtime() - e->e_ctime), 285440266059SGregory Neil Shapiro mci->mci_min_by); 285540266059SGregory Neil Shapiro rcode = EX_UNAVAILABLE; 285640266059SGregory Neil Shapiro goto give_up; 285740266059SGregory Neil Shapiro } 285840266059SGregory Neil Shapiro } 285940266059SGregory Neil Shapiro 286040266059SGregory Neil Shapiro # if STARTTLS 286140266059SGregory Neil Shapiro /* first TLS then AUTH to provide a security layer */ 286240266059SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 286340266059SGregory Neil Shapiro !DONE_STARTTLS(mci->mci_flags)) 286440266059SGregory Neil Shapiro { 286540266059SGregory Neil Shapiro int olderrors; 286640266059SGregory Neil Shapiro bool usetls; 286740266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 286840266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 286940266059SGregory Neil Shapiro char *host = NULL; 287040266059SGregory Neil Shapiro 287140266059SGregory Neil Shapiro rcode = EX_OK; 287240266059SGregory Neil Shapiro usetls = bitset(MCIF_TLS, mci->mci_flags); 287340266059SGregory Neil Shapiro if (usetls) 287440266059SGregory Neil Shapiro usetls = !iscltflgset(e, D_NOTLS); 287540266059SGregory Neil Shapiro 287640266059SGregory Neil Shapiro if (usetls) 287740266059SGregory Neil Shapiro { 287840266059SGregory Neil Shapiro host = macvalue(macid("{server_name}"), e); 287940266059SGregory Neil Shapiro olderrors = Errors; 288040266059SGregory Neil Shapiro QuickAbort = false; 288140266059SGregory Neil Shapiro SuprErrs = true; 288240266059SGregory Neil Shapiro if (rscheck("try_tls", host, NULL, e, true, 288340266059SGregory Neil Shapiro false, 7, host, NOQID) != EX_OK 288440266059SGregory Neil Shapiro || Errors > olderrors) 288540266059SGregory Neil Shapiro usetls = false; 288640266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 288740266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 288840266059SGregory Neil Shapiro } 288940266059SGregory Neil Shapiro 289006f25ae9SGregory Neil Shapiro if (usetls) 289106f25ae9SGregory Neil Shapiro { 289206f25ae9SGregory Neil Shapiro if ((rcode = starttls(m, mci, e)) == EX_OK) 289306f25ae9SGregory Neil Shapiro { 289406f25ae9SGregory Neil Shapiro /* start again without STARTTLS */ 289506f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_TLSACT; 289606f25ae9SGregory Neil Shapiro } 289706f25ae9SGregory Neil Shapiro else 289806f25ae9SGregory Neil Shapiro { 289906f25ae9SGregory Neil Shapiro char *s; 290006f25ae9SGregory Neil Shapiro 290106f25ae9SGregory Neil Shapiro /* 290206f25ae9SGregory Neil Shapiro ** TLS negotation failed, what to do? 290306f25ae9SGregory Neil Shapiro ** fall back to unencrypted connection 290406f25ae9SGregory Neil Shapiro ** or abort? How to decide? 290506f25ae9SGregory Neil Shapiro ** set a macro and call a ruleset. 290606f25ae9SGregory Neil Shapiro */ 290740266059SGregory Neil Shapiro 290806f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLS; 290906f25ae9SGregory Neil Shapiro switch (rcode) 291006f25ae9SGregory Neil Shapiro { 291106f25ae9SGregory Neil Shapiro case EX_TEMPFAIL: 291206f25ae9SGregory Neil Shapiro s = "TEMP"; 291306f25ae9SGregory Neil Shapiro break; 291406f25ae9SGregory Neil Shapiro case EX_USAGE: 291506f25ae9SGregory Neil Shapiro s = "USAGE"; 291606f25ae9SGregory Neil Shapiro break; 291706f25ae9SGregory Neil Shapiro case EX_PROTOCOL: 291806f25ae9SGregory Neil Shapiro s = "PROTOCOL"; 291906f25ae9SGregory Neil Shapiro break; 292006f25ae9SGregory Neil Shapiro case EX_SOFTWARE: 292106f25ae9SGregory Neil Shapiro s = "SOFTWARE"; 292206f25ae9SGregory Neil Shapiro break; 292306f25ae9SGregory Neil Shapiro 292406f25ae9SGregory Neil Shapiro /* everything else is a failure */ 292506f25ae9SGregory Neil Shapiro default: 292606f25ae9SGregory Neil Shapiro s = "FAILURE"; 292706f25ae9SGregory Neil Shapiro rcode = EX_TEMPFAIL; 292806f25ae9SGregory Neil Shapiro } 292940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 293040266059SGregory Neil Shapiro macid("{verify}"), s); 293106f25ae9SGregory Neil Shapiro } 293206f25ae9SGregory Neil Shapiro } 293306f25ae9SGregory Neil Shapiro else 293440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 293540266059SGregory Neil Shapiro macid("{verify}"), "NONE"); 293606f25ae9SGregory Neil Shapiro olderrors = Errors; 293740266059SGregory Neil Shapiro QuickAbort = false; 293840266059SGregory Neil Shapiro SuprErrs = true; 293906f25ae9SGregory Neil Shapiro 294006f25ae9SGregory Neil Shapiro /* 294106f25ae9SGregory Neil Shapiro ** rcode == EX_SOFTWARE is special: 294206f25ae9SGregory Neil Shapiro ** the TLS negotation failed 294306f25ae9SGregory Neil Shapiro ** we have to drop the connection no matter what 294406f25ae9SGregory Neil Shapiro ** However, we call tls_server to give it the chance 294506f25ae9SGregory Neil Shapiro ** to log the problem and return an appropriate 294606f25ae9SGregory Neil Shapiro ** error code. 294706f25ae9SGregory Neil Shapiro */ 294840266059SGregory Neil Shapiro 294906f25ae9SGregory Neil Shapiro if (rscheck("tls_server", 295040266059SGregory Neil Shapiro macvalue(macid("{verify}"), e), 295140266059SGregory Neil Shapiro NULL, e, true, true, 5, host, 295240266059SGregory Neil Shapiro NOQID) != EX_OK || 295306f25ae9SGregory Neil Shapiro Errors > olderrors || 295406f25ae9SGregory Neil Shapiro rcode == EX_SOFTWARE) 295506f25ae9SGregory Neil Shapiro { 295606f25ae9SGregory Neil Shapiro char enhsc[ENHSCLEN]; 295706f25ae9SGregory Neil Shapiro extern char MsgBuf[]; 295806f25ae9SGregory Neil Shapiro 295906f25ae9SGregory Neil Shapiro if (ISSMTPCODE(MsgBuf) && 296006f25ae9SGregory Neil Shapiro extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 296106f25ae9SGregory Neil Shapiro { 296240266059SGregory Neil Shapiro p = sm_rpool_strdup_x(e->e_rpool, 296340266059SGregory Neil Shapiro MsgBuf); 296406f25ae9SGregory Neil Shapiro } 296506f25ae9SGregory Neil Shapiro else 296606f25ae9SGregory Neil Shapiro { 296706f25ae9SGregory Neil Shapiro p = "403 4.7.0 server not authenticated."; 296840266059SGregory Neil Shapiro (void) sm_strlcpy(enhsc, "4.7.0", 296906f25ae9SGregory Neil Shapiro sizeof enhsc); 297006f25ae9SGregory Neil Shapiro } 297106f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 297206f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 297306f25ae9SGregory Neil Shapiro 297406f25ae9SGregory Neil Shapiro if (rcode == EX_SOFTWARE) 297506f25ae9SGregory Neil Shapiro { 297606f25ae9SGregory Neil Shapiro /* drop the connection */ 297706f25ae9SGregory Neil Shapiro mci->mci_state = MCIS_QUITING; 297806f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 297906f25ae9SGregory Neil Shapiro { 298040266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, 298140266059SGregory Neil Shapiro SM_TIME_DEFAULT); 298206f25ae9SGregory Neil Shapiro mci->mci_in = NULL; 298306f25ae9SGregory Neil Shapiro } 298406f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 298506f25ae9SGregory Neil Shapiro (void) endmailer(mci, e, pv); 298606f25ae9SGregory Neil Shapiro } 298706f25ae9SGregory Neil Shapiro else 298806f25ae9SGregory Neil Shapiro { 298906f25ae9SGregory Neil Shapiro /* abort transfer */ 299006f25ae9SGregory Neil Shapiro smtpquit(m, mci, e); 299106f25ae9SGregory Neil Shapiro } 299206f25ae9SGregory Neil Shapiro 2993193538b7SGregory Neil Shapiro /* avoid bogus error msg */ 2994193538b7SGregory Neil Shapiro mci->mci_errno = 0; 2995193538b7SGregory Neil Shapiro 299606f25ae9SGregory Neil Shapiro /* temp or permanent failure? */ 299706f25ae9SGregory Neil Shapiro rcode = (*p == '4') ? EX_TEMPFAIL 299806f25ae9SGregory Neil Shapiro : EX_UNAVAILABLE; 299940266059SGregory Neil Shapiro mci_setstat(mci, rcode, enhsc, p); 300006f25ae9SGregory Neil Shapiro 300106f25ae9SGregory Neil Shapiro /* 300206f25ae9SGregory Neil Shapiro ** hack to get the error message into 300306f25ae9SGregory Neil Shapiro ** the envelope (done in giveresponse()) 300406f25ae9SGregory Neil Shapiro */ 300540266059SGregory Neil Shapiro 300640266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, p, 300740266059SGregory Neil Shapiro sizeof SmtpError); 300806f25ae9SGregory Neil Shapiro } 300906f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort; 301006f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs; 3011193538b7SGregory Neil Shapiro if (DONE_STARTTLS(mci->mci_flags) && 3012193538b7SGregory Neil Shapiro mci->mci_state != MCIS_CLOSED) 301306f25ae9SGregory Neil Shapiro { 3014193538b7SGregory Neil Shapiro SET_HELO(mci->mci_flags); 301506f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 301606f25ae9SGregory Neil Shapiro goto reconnect; 301706f25ae9SGregory Neil Shapiro } 301806f25ae9SGregory Neil Shapiro } 301906f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 302006f25ae9SGregory Neil Shapiro # if SASL 302106f25ae9SGregory Neil Shapiro /* if other server supports authentication let's authenticate */ 302206f25ae9SGregory Neil Shapiro if (mci->mci_state != MCIS_CLOSED && 302306f25ae9SGregory Neil Shapiro mci->mci_saslcap != NULL && 302440266059SGregory Neil Shapiro !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH)) 302506f25ae9SGregory Neil Shapiro { 302640266059SGregory Neil Shapiro /* Should we require some minimum authentication? */ 302740266059SGregory Neil Shapiro if ((ret = smtpauth(m, mci, e)) == EX_OK) 302806f25ae9SGregory Neil Shapiro { 302906f25ae9SGregory Neil Shapiro int result; 303040266059SGregory Neil Shapiro sasl_ssf_t *ssf = NULL; 303106f25ae9SGregory Neil Shapiro 303240266059SGregory Neil Shapiro /* Get security strength (features) */ 303306f25ae9SGregory Neil Shapiro result = sasl_getprop(mci->mci_conn, SASL_SSF, 303494c01205SGregory Neil Shapiro # if SASL >= 20000 303594c01205SGregory Neil Shapiro (const void **) &ssf); 303694c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 303706f25ae9SGregory Neil Shapiro (void **) &ssf); 303894c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 303940266059SGregory Neil Shapiro 304040266059SGregory Neil Shapiro /* XXX authid? */ 304106f25ae9SGregory Neil Shapiro if (LogLevel > 9) 304206f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 304340266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, mech=%.16s, bits=%d", 304406f25ae9SGregory Neil Shapiro mci->mci_host, 304540266059SGregory Neil Shapiro macvalue(macid("{auth_type}"), e), 304640266059SGregory Neil Shapiro result == SASL_OK ? *ssf : 0); 30478774250cSGregory Neil Shapiro 304806f25ae9SGregory Neil Shapiro /* 304940266059SGregory Neil Shapiro ** Only switch to encrypted connection 305006f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated 305106f25ae9SGregory Neil Shapiro */ 305240266059SGregory Neil Shapiro 305306f25ae9SGregory Neil Shapiro if (result == SASL_OK && *ssf > 0) 305406f25ae9SGregory Neil Shapiro { 305506f25ae9SGregory Neil Shapiro /* 305640266059SGregory Neil Shapiro ** Convert I/O layer to use SASL. 305740266059SGregory Neil Shapiro ** If the call fails, the connection 305840266059SGregory Neil Shapiro ** is aborted. 305906f25ae9SGregory Neil Shapiro */ 306040266059SGregory Neil Shapiro 306140266059SGregory Neil Shapiro if (sfdcsasl(&mci->mci_in, 306240266059SGregory Neil Shapiro &mci->mci_out, 306306f25ae9SGregory Neil Shapiro mci->mci_conn) == 0) 306406f25ae9SGregory Neil Shapiro { 306506f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_EXTENS; 306640266059SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT| 306740266059SGregory Neil Shapiro MCIF_ONLY_EHLO; 306806f25ae9SGregory Neil Shapiro goto reconnect; 306906f25ae9SGregory Neil Shapiro } 307040266059SGregory Neil Shapiro syserr("AUTH TLS switch failed in client"); 307106f25ae9SGregory Neil Shapiro } 307206f25ae9SGregory Neil Shapiro /* else? XXX */ 307306f25ae9SGregory Neil Shapiro mci->mci_flags |= MCIF_AUTHACT; 307406f25ae9SGregory Neil Shapiro 307506f25ae9SGregory Neil Shapiro } 307640266059SGregory Neil Shapiro else if (ret == EX_TEMPFAIL) 307740266059SGregory Neil Shapiro { 307840266059SGregory Neil Shapiro if (LogLevel > 8) 307940266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 308040266059SGregory Neil Shapiro "AUTH=client, relay=%.100s, temporary failure, connection abort", 308140266059SGregory Neil Shapiro mci->mci_host); 308240266059SGregory Neil Shapiro smtpquit(m, mci, e); 308340266059SGregory Neil Shapiro 308440266059SGregory Neil Shapiro /* avoid bogus error msg */ 308540266059SGregory Neil Shapiro mci->mci_errno = 0; 308640266059SGregory Neil Shapiro rcode = EX_TEMPFAIL; 308740266059SGregory Neil Shapiro mci_setstat(mci, rcode, "4.7.1", p); 308840266059SGregory Neil Shapiro 308940266059SGregory Neil Shapiro /* 309040266059SGregory Neil Shapiro ** hack to get the error message into 309140266059SGregory Neil Shapiro ** the envelope (done in giveresponse()) 309240266059SGregory Neil Shapiro */ 309340266059SGregory Neil Shapiro 309440266059SGregory Neil Shapiro (void) sm_strlcpy(SmtpError, 309540266059SGregory Neil Shapiro "Temporary AUTH failure", 309640266059SGregory Neil Shapiro sizeof SmtpError); 309740266059SGregory Neil Shapiro } 309806f25ae9SGregory Neil Shapiro } 309906f25ae9SGregory Neil Shapiro # endif /* SASL */ 310006f25ae9SGregory Neil Shapiro } 310106f25ae9SGregory Neil Shapiro 3102c2aa98e2SPeter Wemm 3103c2aa98e2SPeter Wemm do_transfer: 3104c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 3105c2aa98e2SPeter Wemm mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 3106c2aa98e2SPeter Wemm 3107c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 3108c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 3109c2aa98e2SPeter Wemm bitnset(M_7BITS, m->m_flags)) 3110c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT8TO7; 3111c2aa98e2SPeter Wemm 3112c2aa98e2SPeter Wemm #if MIME7TO8 3113c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, m->m_flags) && 3114c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mci->mci_flags) && 3115c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 311640266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 311740266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 3118c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 3119c2aa98e2SPeter Wemm { 3120c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 3121c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 312240266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 3123c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 3124c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_CVT7TO8; 3125c2aa98e2SPeter Wemm } 312606f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 3127c2aa98e2SPeter Wemm 3128c2aa98e2SPeter Wemm if (tTd(11, 1)) 3129c2aa98e2SPeter Wemm { 313040266059SGregory Neil Shapiro sm_dprintf("openmailer: "); 313140266059SGregory Neil Shapiro mci_dump(mci, false); 3132c2aa98e2SPeter Wemm } 3133c2aa98e2SPeter Wemm 313440266059SGregory Neil Shapiro #if _FFR_CLIENT_SIZE 313540266059SGregory Neil Shapiro /* 313640266059SGregory Neil Shapiro ** See if we know the maximum size and 313740266059SGregory Neil Shapiro ** abort if the message is too big. 313840266059SGregory Neil Shapiro ** 313940266059SGregory Neil Shapiro ** NOTE: _FFR_CLIENT_SIZE is untested. 314040266059SGregory Neil Shapiro */ 314140266059SGregory Neil Shapiro 314240266059SGregory Neil Shapiro if (bitset(MCIF_SIZE, mci->mci_flags) && 314340266059SGregory Neil Shapiro mci->mci_maxsize > 0 && 314440266059SGregory Neil Shapiro e->e_msgsize > mci->mci_maxsize) 314540266059SGregory Neil Shapiro { 314640266059SGregory Neil Shapiro e->e_flags |= EF_NO_BODY_RETN; 314740266059SGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags)) 314840266059SGregory Neil Shapiro e->e_status = "5.2.3"; 314940266059SGregory Neil Shapiro else 315040266059SGregory Neil Shapiro e->e_status = "5.3.4"; 315140266059SGregory Neil Shapiro 315240266059SGregory Neil Shapiro usrerrenh(e->e_status, 315340266059SGregory Neil Shapiro "552 Message is too large; %ld bytes max", 315440266059SGregory Neil Shapiro mci->mci_maxsize); 315540266059SGregory Neil Shapiro rcode = EX_DATAERR; 315640266059SGregory Neil Shapiro 315740266059SGregory Neil Shapiro /* Need an e_message for error */ 315840266059SGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof SmtpError, 315940266059SGregory Neil Shapiro "Message is too large; %ld bytes max", 316040266059SGregory Neil Shapiro mci->mci_maxsize); 316140266059SGregory Neil Shapiro goto give_up; 316240266059SGregory Neil Shapiro } 316340266059SGregory Neil Shapiro #endif /* _FFR_CLIENT_SIZE */ 316440266059SGregory Neil Shapiro 3165c2aa98e2SPeter Wemm if (mci->mci_state != MCIS_OPEN) 3166c2aa98e2SPeter Wemm { 3167c2aa98e2SPeter Wemm /* couldn't open the mailer */ 3168c2aa98e2SPeter Wemm rcode = mci->mci_exitstat; 3169c2aa98e2SPeter Wemm errno = mci->mci_errno; 3170602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(mci->mci_herrno); 3171c2aa98e2SPeter Wemm if (rcode == EX_OK) 3172c2aa98e2SPeter Wemm { 3173c2aa98e2SPeter Wemm /* shouldn't happen */ 317406f25ae9SGregory Neil Shapiro syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 317540266059SGregory Neil Shapiro (unsigned long) mci, rcode, errno, 317640266059SGregory Neil Shapiro mci->mci_state, firstsig); 317740266059SGregory Neil Shapiro mci_dump_all(true); 3178c2aa98e2SPeter Wemm rcode = EX_SOFTWARE; 3179c2aa98e2SPeter Wemm } 318006f25ae9SGregory Neil Shapiro else if (nummxhosts > hostnum) 3181c2aa98e2SPeter Wemm { 3182c2aa98e2SPeter Wemm /* try next MX site */ 3183c2aa98e2SPeter Wemm goto tryhost; 3184c2aa98e2SPeter Wemm } 3185c2aa98e2SPeter Wemm } 3186c2aa98e2SPeter Wemm else if (!clever) 3187c2aa98e2SPeter Wemm { 3188c2aa98e2SPeter Wemm /* 3189c2aa98e2SPeter Wemm ** Format and send message. 3190c2aa98e2SPeter Wemm */ 3191c2aa98e2SPeter Wemm 3192c2aa98e2SPeter Wemm putfromline(mci, e); 31932e43090eSPeter Wemm (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 3194c2aa98e2SPeter Wemm (*e->e_putbody)(mci, e, NULL); 3195c2aa98e2SPeter Wemm 3196c2aa98e2SPeter Wemm /* get the exit status */ 3197c2aa98e2SPeter Wemm rcode = endmailer(mci, e, pv); 319840266059SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 3199602a2b1bSGregory Neil Shapiro { 3200602a2b1bSGregory Neil Shapiro /* 3201602a2b1bSGregory Neil Shapiro ** Need an e_message for mailq display. 3202602a2b1bSGregory Neil Shapiro ** We set SmtpError as 3203602a2b1bSGregory Neil Shapiro */ 3204602a2b1bSGregory Neil Shapiro 320540266059SGregory Neil Shapiro (void) sm_snprintf(SmtpError, sizeof SmtpError, 3206602a2b1bSGregory Neil Shapiro "%s mailer (%s) exited with EX_TEMPFAIL", 3207602a2b1bSGregory Neil Shapiro m->m_name, m->m_mailer); 3208602a2b1bSGregory Neil Shapiro } 3209c2aa98e2SPeter Wemm } 3210c2aa98e2SPeter Wemm else 3211c2aa98e2SPeter Wemm { 3212c2aa98e2SPeter Wemm /* 3213c2aa98e2SPeter Wemm ** Send the MAIL FROM: protocol 3214c2aa98e2SPeter Wemm */ 3215c2aa98e2SPeter Wemm 321640266059SGregory Neil Shapiro /* XXX this isn't pipelined... */ 3217c2aa98e2SPeter Wemm rcode = smtpmailfrom(m, mci, e); 3218c2aa98e2SPeter Wemm if (rcode == EX_OK) 3219c2aa98e2SPeter Wemm { 3220c2aa98e2SPeter Wemm register int i; 322140266059SGregory Neil Shapiro # if PIPELINING 322240266059SGregory Neil Shapiro ADDRESS *volatile pchain; 322340266059SGregory Neil Shapiro # endif /* PIPELINING */ 3224c2aa98e2SPeter Wemm 3225c2aa98e2SPeter Wemm /* send the recipient list */ 3226c2aa98e2SPeter Wemm tobuf[0] = '\0'; 322740266059SGregory Neil Shapiro mci->mci_retryrcpt = false; 322840266059SGregory Neil Shapiro mci->mci_tolist = tobuf; 322940266059SGregory Neil Shapiro # if PIPELINING 323040266059SGregory Neil Shapiro pchain = NULL; 323140266059SGregory Neil Shapiro mci->mci_nextaddr = NULL; 323240266059SGregory Neil Shapiro # endif /* PIPELINING */ 323306f25ae9SGregory Neil Shapiro 3234c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3235c2aa98e2SPeter Wemm { 323640266059SGregory Neil Shapiro if (!QS_IS_UNMARKED(to->q_state)) 3237c2aa98e2SPeter Wemm continue; 323806f25ae9SGregory Neil Shapiro 323940266059SGregory Neil Shapiro /* mark recipient state as "ok so far" */ 324040266059SGregory Neil Shapiro to->q_state = QS_OK; 324140266059SGregory Neil Shapiro e->e_to = to->q_paddr; 324206f25ae9SGregory Neil Shapiro # if STARTTLS 324306f25ae9SGregory Neil Shapiro i = rscheck("tls_rcpt", to->q_user, NULL, e, 324440266059SGregory Neil Shapiro true, true, 3, mci->mci_host, 324540266059SGregory Neil Shapiro e->e_id); 324606f25ae9SGregory Neil Shapiro if (i != EX_OK) 3247c2aa98e2SPeter Wemm { 324840266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 324940266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 325040266059SGregory Neil Shapiro ctladdr, xstart, e, to); 325140266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 325240266059SGregory Neil Shapiro { 325340266059SGregory Neil Shapiro mci->mci_retryrcpt = true; 325440266059SGregory Neil Shapiro to->q_state = QS_RETRY; 325540266059SGregory Neil Shapiro } 325606f25ae9SGregory Neil Shapiro continue; 325706f25ae9SGregory Neil Shapiro } 325806f25ae9SGregory Neil Shapiro # endif /* STARTTLS */ 325906f25ae9SGregory Neil Shapiro 326040266059SGregory Neil Shapiro i = smtprcpt(to, m, mci, e, ctladdr, xstart); 326140266059SGregory Neil Shapiro # if PIPELINING 326240266059SGregory Neil Shapiro if (i == EX_OK && 326340266059SGregory Neil Shapiro bitset(MCIF_PIPELINED, mci->mci_flags)) 326406f25ae9SGregory Neil Shapiro { 326540266059SGregory Neil Shapiro /* 326640266059SGregory Neil Shapiro ** Add new element to list of 326740266059SGregory Neil Shapiro ** recipients for pipelining. 326840266059SGregory Neil Shapiro */ 326940266059SGregory Neil Shapiro 327040266059SGregory Neil Shapiro to->q_pchain = NULL; 327140266059SGregory Neil Shapiro if (mci->mci_nextaddr == NULL) 327240266059SGregory Neil Shapiro mci->mci_nextaddr = to; 327340266059SGregory Neil Shapiro if (pchain == NULL) 327440266059SGregory Neil Shapiro pchain = to; 3275c2aa98e2SPeter Wemm else 3276c2aa98e2SPeter Wemm { 327740266059SGregory Neil Shapiro pchain->q_pchain = to; 327840266059SGregory Neil Shapiro pchain = pchain->q_pchain; 327940266059SGregory Neil Shapiro } 328040266059SGregory Neil Shapiro } 328140266059SGregory Neil Shapiro # endif /* PIPELINING */ 328240266059SGregory Neil Shapiro if (i != EX_OK) 328340266059SGregory Neil Shapiro { 328440266059SGregory Neil Shapiro markfailure(e, to, mci, i, false); 328540266059SGregory Neil Shapiro giveresponse(i, to->q_status, m, mci, 328640266059SGregory Neil Shapiro ctladdr, xstart, e, to); 328740266059SGregory Neil Shapiro if (i == EX_TEMPFAIL) 328840266059SGregory Neil Shapiro to->q_state = QS_RETRY; 3289c2aa98e2SPeter Wemm } 3290c2aa98e2SPeter Wemm } 3291c2aa98e2SPeter Wemm 329240266059SGregory Neil Shapiro /* No recipients in list and no missing responses? */ 329340266059SGregory Neil Shapiro if (tobuf[0] == '\0' 329440266059SGregory Neil Shapiro # if PIPELINING 329540266059SGregory Neil Shapiro && mci->mci_nextaddr == NULL 329640266059SGregory Neil Shapiro # endif /* PIPELINING */ 329740266059SGregory Neil Shapiro ) 3298c2aa98e2SPeter Wemm { 3299c2aa98e2SPeter Wemm rcode = EX_OK; 3300c2aa98e2SPeter Wemm e->e_to = NULL; 3301c2aa98e2SPeter Wemm if (bitset(MCIF_CACHED, mci->mci_flags)) 3302c2aa98e2SPeter Wemm smtprset(m, mci, e); 3303c2aa98e2SPeter Wemm } 3304c2aa98e2SPeter Wemm else 3305c2aa98e2SPeter Wemm { 3306c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 330740266059SGregory Neil Shapiro rcode = smtpdata(m, mci, e, ctladdr, xstart); 3308c2aa98e2SPeter Wemm } 3309c2aa98e2SPeter Wemm } 331006f25ae9SGregory Neil Shapiro if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 3311c2aa98e2SPeter Wemm { 3312c2aa98e2SPeter Wemm /* try next MX site */ 3313c2aa98e2SPeter Wemm goto tryhost; 3314c2aa98e2SPeter Wemm } 3315c2aa98e2SPeter Wemm } 3316c2aa98e2SPeter Wemm #if NAMED_BIND 3317c2aa98e2SPeter Wemm if (ConfigLevel < 2) 3318c2aa98e2SPeter Wemm _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 331906f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3320c2aa98e2SPeter Wemm 3321c2aa98e2SPeter Wemm if (tTd(62, 1)) 3322c2aa98e2SPeter Wemm checkfds("after delivery"); 3323c2aa98e2SPeter Wemm 3324c2aa98e2SPeter Wemm /* 3325c2aa98e2SPeter Wemm ** Do final status disposal. 3326c2aa98e2SPeter Wemm ** We check for something in tobuf for the SMTP case. 3327c2aa98e2SPeter Wemm ** If we got a temporary failure, arrange to queue the 3328c2aa98e2SPeter Wemm ** addressees. 3329c2aa98e2SPeter Wemm */ 3330c2aa98e2SPeter Wemm 3331c2aa98e2SPeter Wemm give_up: 3332c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3333c2aa98e2SPeter Wemm { 3334c2aa98e2SPeter Wemm lmtp_rcode = rcode; 3335c2aa98e2SPeter Wemm tobuf[0] = '\0'; 333640266059SGregory Neil Shapiro anyok = false; 333740266059SGregory Neil Shapiro strsize = 0; 3338c2aa98e2SPeter Wemm } 3339c2aa98e2SPeter Wemm else 3340c2aa98e2SPeter Wemm anyok = rcode == EX_OK; 3341c2aa98e2SPeter Wemm 3342c2aa98e2SPeter Wemm for (to = tochain; to != NULL; to = to->q_tchain) 3343c2aa98e2SPeter Wemm { 3344c2aa98e2SPeter Wemm /* see if address already marked */ 334506f25ae9SGregory Neil Shapiro if (!QS_IS_OK(to->q_state)) 3346c2aa98e2SPeter Wemm continue; 3347c2aa98e2SPeter Wemm 3348c2aa98e2SPeter Wemm /* if running LMTP, get the status for each address */ 3349c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3350c2aa98e2SPeter Wemm { 3351c2aa98e2SPeter Wemm if (lmtp_rcode == EX_OK) 3352c2aa98e2SPeter Wemm rcode = smtpgetstat(m, mci, e); 3353c2aa98e2SPeter Wemm if (rcode == EX_OK) 3354c2aa98e2SPeter Wemm { 335540266059SGregory Neil Shapiro strsize += sm_strlcat2(tobuf + strsize, ",", 335640266059SGregory Neil Shapiro to->q_paddr, 335740266059SGregory Neil Shapiro tobufsize - strsize); 335840266059SGregory Neil Shapiro SM_ASSERT(strsize < tobufsize); 335940266059SGregory Neil Shapiro anyok = true; 3360c2aa98e2SPeter Wemm } 3361c2aa98e2SPeter Wemm else 3362c2aa98e2SPeter Wemm { 3363c2aa98e2SPeter Wemm e->e_to = to->q_paddr; 336440266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 336506f25ae9SGregory Neil Shapiro giveresponse(rcode, to->q_status, m, mci, 336640266059SGregory Neil Shapiro ctladdr, xstart, e, to); 3367c2aa98e2SPeter Wemm e->e_to = tobuf + 1; 3368c2aa98e2SPeter Wemm continue; 3369c2aa98e2SPeter Wemm } 3370c2aa98e2SPeter Wemm } 3371c2aa98e2SPeter Wemm else 3372c2aa98e2SPeter Wemm { 3373c2aa98e2SPeter Wemm /* mark bad addresses */ 3374c2aa98e2SPeter Wemm if (rcode != EX_OK) 3375c2aa98e2SPeter Wemm { 3376c2aa98e2SPeter Wemm if (goodmxfound && rcode == EX_NOHOST) 3377c2aa98e2SPeter Wemm rcode = EX_TEMPFAIL; 337840266059SGregory Neil Shapiro markfailure(e, to, mci, rcode, true); 3379c2aa98e2SPeter Wemm continue; 3380c2aa98e2SPeter Wemm } 3381c2aa98e2SPeter Wemm } 3382c2aa98e2SPeter Wemm 3383c2aa98e2SPeter Wemm /* successful delivery */ 338406f25ae9SGregory Neil Shapiro to->q_state = QS_SENT; 3385c2aa98e2SPeter Wemm to->q_statdate = curtime(); 3386c2aa98e2SPeter Wemm e->e_nsent++; 338706f25ae9SGregory Neil Shapiro 338806f25ae9SGregory Neil Shapiro /* 338906f25ae9SGregory Neil Shapiro ** Checkpoint the send list every few addresses 339006f25ae9SGregory Neil Shapiro */ 339106f25ae9SGregory Neil Shapiro 339242e5d165SGregory Neil Shapiro if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 339306f25ae9SGregory Neil Shapiro { 339440266059SGregory Neil Shapiro queueup(e, false, false); 339506f25ae9SGregory Neil Shapiro e->e_nsent = 0; 339606f25ae9SGregory Neil Shapiro } 339706f25ae9SGregory Neil Shapiro 3398c2aa98e2SPeter Wemm if (bitnset(M_LOCALMAILER, m->m_flags) && 3399c2aa98e2SPeter Wemm bitset(QPINGONSUCCESS, to->q_flags)) 3400c2aa98e2SPeter Wemm { 3401c2aa98e2SPeter Wemm to->q_flags |= QDELIVERED; 3402c2aa98e2SPeter Wemm to->q_status = "2.1.5"; 340340266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 340440266059SGregory Neil Shapiro "%s... Successfully delivered\n", 3405c2aa98e2SPeter Wemm to->q_paddr); 3406c2aa98e2SPeter Wemm } 3407c2aa98e2SPeter Wemm else if (bitset(QPINGONSUCCESS, to->q_flags) && 3408c2aa98e2SPeter Wemm bitset(QPRIMARY, to->q_flags) && 3409c2aa98e2SPeter Wemm !bitset(MCIF_DSN, mci->mci_flags)) 3410c2aa98e2SPeter Wemm { 3411c2aa98e2SPeter Wemm to->q_flags |= QRELAYED; 341240266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 341340266059SGregory Neil Shapiro "%s... relayed; expect no further notifications\n", 341440266059SGregory Neil Shapiro to->q_paddr); 341540266059SGregory Neil Shapiro } 341640266059SGregory Neil Shapiro else if (IS_DLVR_NOTIFY(e) && 341740266059SGregory Neil Shapiro !bitset(MCIF_DLVR_BY, mci->mci_flags) && 341840266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags) && 341940266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 342040266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 342140266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 342240266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags))) 342340266059SGregory Neil Shapiro { 342440266059SGregory Neil Shapiro /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 342540266059SGregory Neil Shapiro to->q_flags |= QBYNRELAY; 342640266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 342740266059SGregory Neil Shapiro "%s... Deliver-by notify: relayed\n", 342840266059SGregory Neil Shapiro to->q_paddr); 342940266059SGregory Neil Shapiro } 343040266059SGregory Neil Shapiro else if (IS_DLVR_TRACE(e) && 343140266059SGregory Neil Shapiro (!bitset(QHASNOTIFY, to->q_flags) || 343240266059SGregory Neil Shapiro bitset(QPINGONSUCCESS, to->q_flags) || 343340266059SGregory Neil Shapiro bitset(QPINGONFAILURE, to->q_flags) || 343440266059SGregory Neil Shapiro bitset(QPINGONDELAY, to->q_flags)) && 343540266059SGregory Neil Shapiro bitset(QPRIMARY, to->q_flags)) 343640266059SGregory Neil Shapiro { 343740266059SGregory Neil Shapiro /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 343840266059SGregory Neil Shapiro to->q_flags |= QBYTRACE; 343940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 344040266059SGregory Neil Shapiro "%s... Deliver-By trace: relayed\n", 3441c2aa98e2SPeter Wemm to->q_paddr); 3442c2aa98e2SPeter Wemm } 3443c2aa98e2SPeter Wemm } 3444c2aa98e2SPeter Wemm 3445c2aa98e2SPeter Wemm if (bitnset(M_LMTP, m->m_flags)) 3446c2aa98e2SPeter Wemm { 3447c2aa98e2SPeter Wemm /* 3448c2aa98e2SPeter Wemm ** Global information applies to the last recipient only; 3449c2aa98e2SPeter Wemm ** clear it out to avoid bogus errors. 3450c2aa98e2SPeter Wemm */ 3451c2aa98e2SPeter Wemm 3452c2aa98e2SPeter Wemm rcode = EX_OK; 3453c2aa98e2SPeter Wemm e->e_statmsg = NULL; 3454c2aa98e2SPeter Wemm 3455c2aa98e2SPeter Wemm /* reset the mci state for the next transaction */ 345640266059SGregory Neil Shapiro if (mci != NULL && 345740266059SGregory Neil Shapiro (mci->mci_state == MCIS_MAIL || 345840266059SGregory Neil Shapiro mci->mci_state == MCIS_RCPT || 345940266059SGregory Neil Shapiro mci->mci_state == MCIS_DATA)) 3460c2aa98e2SPeter Wemm mci->mci_state = MCIS_OPEN; 3461c2aa98e2SPeter Wemm } 3462c2aa98e2SPeter Wemm 3463c2aa98e2SPeter Wemm if (tobuf[0] != '\0') 346440266059SGregory Neil Shapiro { 346540266059SGregory Neil Shapiro giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); 346640266059SGregory Neil Shapiro #if 0 346740266059SGregory Neil Shapiro /* 346840266059SGregory Neil Shapiro ** This code is disabled for now because I am not 346940266059SGregory Neil Shapiro ** sure that copying status from the first recipient 347040266059SGregory Neil Shapiro ** to all non-status'ed recipients is a good idea. 347140266059SGregory Neil Shapiro */ 347240266059SGregory Neil Shapiro 347340266059SGregory Neil Shapiro if (tochain->q_message != NULL && 347440266059SGregory Neil Shapiro !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 347540266059SGregory Neil Shapiro { 347640266059SGregory Neil Shapiro for (to = tochain->q_tchain; to != NULL; 347740266059SGregory Neil Shapiro to = to->q_tchain) 347840266059SGregory Neil Shapiro { 347940266059SGregory Neil Shapiro /* see if address already marked */ 348040266059SGregory Neil Shapiro if (QS_IS_QUEUEUP(to->q_state) && 348140266059SGregory Neil Shapiro to->q_message == NULL) 348240266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 348340266059SGregory Neil Shapiro tochain->q_message); 348440266059SGregory Neil Shapiro } 348540266059SGregory Neil Shapiro } 348640266059SGregory Neil Shapiro #endif /* 0 */ 348740266059SGregory Neil Shapiro } 3488c2aa98e2SPeter Wemm if (anyok) 348940266059SGregory Neil Shapiro markstats(e, tochain, STATS_NORMAL); 3490c2aa98e2SPeter Wemm mci_store_persistent(mci); 3491c2aa98e2SPeter Wemm 349240266059SGregory Neil Shapiro /* Some recipients were tempfailed, try them on the next host */ 349340266059SGregory Neil Shapiro if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 349440266059SGregory Neil Shapiro { 349540266059SGregory Neil Shapiro /* try next MX site */ 349640266059SGregory Neil Shapiro goto tryhost; 349740266059SGregory Neil Shapiro } 349840266059SGregory Neil Shapiro 3499c2aa98e2SPeter Wemm /* now close the connection */ 3500c2aa98e2SPeter Wemm if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 3501c2aa98e2SPeter Wemm !bitset(MCIF_CACHED, mci->mci_flags)) 3502c2aa98e2SPeter Wemm smtpquit(m, mci, e); 3503c2aa98e2SPeter Wemm 350440266059SGregory Neil Shapiro cleanup: ; 350540266059SGregory Neil Shapiro } 350640266059SGregory Neil Shapiro SM_FINALLY 350740266059SGregory Neil Shapiro { 3508c2aa98e2SPeter Wemm /* 3509c2aa98e2SPeter Wemm ** Restore state and return. 3510c2aa98e2SPeter Wemm */ 3511c2aa98e2SPeter Wemm #if XDEBUG 3512c2aa98e2SPeter Wemm char wbuf[MAXLINE]; 3513c2aa98e2SPeter Wemm 3514c2aa98e2SPeter Wemm /* make absolutely certain 0, 1, and 2 are in use */ 351540266059SGregory Neil Shapiro (void) sm_snprintf(wbuf, sizeof wbuf, 351640266059SGregory Neil Shapiro "%s... end of deliver(%s)", 3517c2aa98e2SPeter Wemm e->e_to == NULL ? "NO-TO-LIST" 351840266059SGregory Neil Shapiro : shortenstring(e->e_to, 351940266059SGregory Neil Shapiro MAXSHORTSTR), 3520c2aa98e2SPeter Wemm m->m_name); 3521c2aa98e2SPeter Wemm checkfd012(wbuf); 352206f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 3523c2aa98e2SPeter Wemm 3524c2aa98e2SPeter Wemm errno = 0; 352540266059SGregory Neil Shapiro 352640266059SGregory Neil Shapiro /* 352740266059SGregory Neil Shapiro ** It was originally necessary to set macro 'g' to NULL 352840266059SGregory Neil Shapiro ** because it previously pointed to an auto buffer. 352940266059SGregory Neil Shapiro ** We don't do this any more, so this may be unnecessary. 353040266059SGregory Neil Shapiro */ 353140266059SGregory Neil Shapiro 353240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 353306f25ae9SGregory Neil Shapiro e->e_to = NULL; 353440266059SGregory Neil Shapiro } 353540266059SGregory Neil Shapiro SM_END_TRY 353606f25ae9SGregory Neil Shapiro return rcode; 3537c2aa98e2SPeter Wemm } 353806f25ae9SGregory Neil Shapiro 353940266059SGregory Neil Shapiro /* 3540c2aa98e2SPeter Wemm ** MARKFAILURE -- mark a failure on a specific address. 3541c2aa98e2SPeter Wemm ** 3542c2aa98e2SPeter Wemm ** Parameters: 3543c2aa98e2SPeter Wemm ** e -- the envelope we are sending. 3544c2aa98e2SPeter Wemm ** q -- the address to mark. 3545c2aa98e2SPeter Wemm ** mci -- mailer connection information. 3546c2aa98e2SPeter Wemm ** rcode -- the code signifying the particular failure. 354706f25ae9SGregory Neil Shapiro ** ovr -- override an existing code? 3548c2aa98e2SPeter Wemm ** 3549c2aa98e2SPeter Wemm ** Returns: 3550c2aa98e2SPeter Wemm ** none. 3551c2aa98e2SPeter Wemm ** 3552c2aa98e2SPeter Wemm ** Side Effects: 3553c2aa98e2SPeter Wemm ** marks the address (and possibly the envelope) with the 3554c2aa98e2SPeter Wemm ** failure so that an error will be returned or 3555c2aa98e2SPeter Wemm ** the message will be queued, as appropriate. 3556c2aa98e2SPeter Wemm */ 3557c2aa98e2SPeter Wemm 355840266059SGregory Neil Shapiro void 355906f25ae9SGregory Neil Shapiro markfailure(e, q, mci, rcode, ovr) 3560c2aa98e2SPeter Wemm register ENVELOPE *e; 3561c2aa98e2SPeter Wemm register ADDRESS *q; 3562c2aa98e2SPeter Wemm register MCI *mci; 3563c2aa98e2SPeter Wemm int rcode; 356406f25ae9SGregory Neil Shapiro bool ovr; 3565c2aa98e2SPeter Wemm { 356640266059SGregory Neil Shapiro int save_errno = errno; 356706f25ae9SGregory Neil Shapiro char *status = NULL; 356806f25ae9SGregory Neil Shapiro char *rstatus = NULL; 3569c2aa98e2SPeter Wemm 3570c2aa98e2SPeter Wemm switch (rcode) 3571c2aa98e2SPeter Wemm { 3572c2aa98e2SPeter Wemm case EX_OK: 3573c2aa98e2SPeter Wemm break; 3574c2aa98e2SPeter Wemm 3575c2aa98e2SPeter Wemm case EX_TEMPFAIL: 3576c2aa98e2SPeter Wemm case EX_IOERR: 3577c2aa98e2SPeter Wemm case EX_OSERR: 357806f25ae9SGregory Neil Shapiro q->q_state = QS_QUEUEUP; 3579c2aa98e2SPeter Wemm break; 3580c2aa98e2SPeter Wemm 3581c2aa98e2SPeter Wemm default: 358206f25ae9SGregory Neil Shapiro q->q_state = QS_BADADDR; 3583c2aa98e2SPeter Wemm break; 3584c2aa98e2SPeter Wemm } 3585c2aa98e2SPeter Wemm 3586c2aa98e2SPeter Wemm /* find most specific error code possible */ 3587c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_status != NULL) 3588c2aa98e2SPeter Wemm { 358940266059SGregory Neil Shapiro status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 3590c2aa98e2SPeter Wemm if (mci->mci_rstatus != NULL) 359140266059SGregory Neil Shapiro rstatus = sm_rpool_strdup_x(e->e_rpool, 359240266059SGregory Neil Shapiro mci->mci_rstatus); 3593c2aa98e2SPeter Wemm else 359406f25ae9SGregory Neil Shapiro rstatus = NULL; 3595c2aa98e2SPeter Wemm } 3596c2aa98e2SPeter Wemm else if (e->e_status != NULL) 3597c2aa98e2SPeter Wemm { 359806f25ae9SGregory Neil Shapiro status = e->e_status; 359906f25ae9SGregory Neil Shapiro rstatus = NULL; 3600c2aa98e2SPeter Wemm } 3601c2aa98e2SPeter Wemm else 3602c2aa98e2SPeter Wemm { 3603c2aa98e2SPeter Wemm switch (rcode) 3604c2aa98e2SPeter Wemm { 3605c2aa98e2SPeter Wemm case EX_USAGE: 360606f25ae9SGregory Neil Shapiro status = "5.5.4"; 3607c2aa98e2SPeter Wemm break; 3608c2aa98e2SPeter Wemm 3609c2aa98e2SPeter Wemm case EX_DATAERR: 361006f25ae9SGregory Neil Shapiro status = "5.5.2"; 3611c2aa98e2SPeter Wemm break; 3612c2aa98e2SPeter Wemm 3613c2aa98e2SPeter Wemm case EX_NOUSER: 361406f25ae9SGregory Neil Shapiro status = "5.1.1"; 3615c2aa98e2SPeter Wemm break; 3616c2aa98e2SPeter Wemm 3617c2aa98e2SPeter Wemm case EX_NOHOST: 361806f25ae9SGregory Neil Shapiro status = "5.1.2"; 3619c2aa98e2SPeter Wemm break; 3620c2aa98e2SPeter Wemm 3621c2aa98e2SPeter Wemm case EX_NOINPUT: 3622c2aa98e2SPeter Wemm case EX_CANTCREAT: 3623c2aa98e2SPeter Wemm case EX_NOPERM: 362406f25ae9SGregory Neil Shapiro status = "5.3.0"; 3625c2aa98e2SPeter Wemm break; 3626c2aa98e2SPeter Wemm 3627c2aa98e2SPeter Wemm case EX_UNAVAILABLE: 3628c2aa98e2SPeter Wemm case EX_SOFTWARE: 3629c2aa98e2SPeter Wemm case EX_OSFILE: 3630c2aa98e2SPeter Wemm case EX_PROTOCOL: 3631c2aa98e2SPeter Wemm case EX_CONFIG: 363206f25ae9SGregory Neil Shapiro status = "5.5.0"; 3633c2aa98e2SPeter Wemm break; 3634c2aa98e2SPeter Wemm 3635c2aa98e2SPeter Wemm case EX_OSERR: 3636c2aa98e2SPeter Wemm case EX_IOERR: 363706f25ae9SGregory Neil Shapiro status = "4.5.0"; 3638c2aa98e2SPeter Wemm break; 3639c2aa98e2SPeter Wemm 3640c2aa98e2SPeter Wemm case EX_TEMPFAIL: 364106f25ae9SGregory Neil Shapiro status = "4.2.0"; 3642c2aa98e2SPeter Wemm break; 3643c2aa98e2SPeter Wemm } 3644c2aa98e2SPeter Wemm } 3645c2aa98e2SPeter Wemm 364606f25ae9SGregory Neil Shapiro /* new status? */ 364706f25ae9SGregory Neil Shapiro if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 364806f25ae9SGregory Neil Shapiro *q->q_status == '\0' || *q->q_status < *status)) 364906f25ae9SGregory Neil Shapiro { 365006f25ae9SGregory Neil Shapiro q->q_status = status; 365106f25ae9SGregory Neil Shapiro q->q_rstatus = rstatus; 365206f25ae9SGregory Neil Shapiro } 3653c2aa98e2SPeter Wemm if (rcode != EX_OK && q->q_rstatus == NULL && 3654c2aa98e2SPeter Wemm q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 365540266059SGregory Neil Shapiro sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 3656c2aa98e2SPeter Wemm { 365706f25ae9SGregory Neil Shapiro char buf[16]; 3658c2aa98e2SPeter Wemm 365940266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%d", rcode); 366040266059SGregory Neil Shapiro q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 3661c2aa98e2SPeter Wemm } 366206f25ae9SGregory Neil Shapiro 366306f25ae9SGregory Neil Shapiro q->q_statdate = curtime(); 366406f25ae9SGregory Neil Shapiro if (CurHostName != NULL && CurHostName[0] != '\0' && 366506f25ae9SGregory Neil Shapiro mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 366640266059SGregory Neil Shapiro q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 366740266059SGregory Neil Shapiro 366840266059SGregory Neil Shapiro /* restore errno */ 366940266059SGregory Neil Shapiro errno = save_errno; 3670c2aa98e2SPeter Wemm } 367140266059SGregory Neil Shapiro /* 3672c2aa98e2SPeter Wemm ** ENDMAILER -- Wait for mailer to terminate. 3673c2aa98e2SPeter Wemm ** 3674c2aa98e2SPeter Wemm ** We should never get fatal errors (e.g., segmentation 3675c2aa98e2SPeter Wemm ** violation), so we report those specially. For other 3676c2aa98e2SPeter Wemm ** errors, we choose a status message (into statmsg), 3677c2aa98e2SPeter Wemm ** and if it represents an error, we print it. 3678c2aa98e2SPeter Wemm ** 3679c2aa98e2SPeter Wemm ** Parameters: 368013058a91SGregory Neil Shapiro ** mci -- the mailer connection info. 3681c2aa98e2SPeter Wemm ** e -- the current envelope. 3682c2aa98e2SPeter Wemm ** pv -- the parameter vector that invoked the mailer 3683c2aa98e2SPeter Wemm ** (for error messages). 3684c2aa98e2SPeter Wemm ** 3685c2aa98e2SPeter Wemm ** Returns: 3686c2aa98e2SPeter Wemm ** exit code of mailer. 3687c2aa98e2SPeter Wemm ** 3688c2aa98e2SPeter Wemm ** Side Effects: 3689c2aa98e2SPeter Wemm ** none. 3690c2aa98e2SPeter Wemm */ 3691c2aa98e2SPeter Wemm 369206f25ae9SGregory Neil Shapiro static jmp_buf EndWaitTimeout; 369306f25ae9SGregory Neil Shapiro 369406f25ae9SGregory Neil Shapiro static void 369506f25ae9SGregory Neil Shapiro endwaittimeout() 369606f25ae9SGregory Neil Shapiro { 36978774250cSGregory Neil Shapiro /* 36988774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 36998774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 37008774250cSGregory Neil Shapiro ** DOING. 37018774250cSGregory Neil Shapiro */ 37028774250cSGregory Neil Shapiro 370306f25ae9SGregory Neil Shapiro errno = ETIMEDOUT; 370406f25ae9SGregory Neil Shapiro longjmp(EndWaitTimeout, 1); 370506f25ae9SGregory Neil Shapiro } 370606f25ae9SGregory Neil Shapiro 3707c2aa98e2SPeter Wemm int 3708c2aa98e2SPeter Wemm endmailer(mci, e, pv) 3709c2aa98e2SPeter Wemm register MCI *mci; 3710c2aa98e2SPeter Wemm register ENVELOPE *e; 3711c2aa98e2SPeter Wemm char **pv; 3712c2aa98e2SPeter Wemm { 3713c2aa98e2SPeter Wemm int st; 371406f25ae9SGregory Neil Shapiro int save_errno = errno; 371506f25ae9SGregory Neil Shapiro char buf[MAXLINE]; 371640266059SGregory Neil Shapiro SM_EVENT *ev = NULL; 371706f25ae9SGregory Neil Shapiro 3718c2aa98e2SPeter Wemm 3719c2aa98e2SPeter Wemm mci_unlock_host(mci); 3720c2aa98e2SPeter Wemm 37218774250cSGregory Neil Shapiro /* close output to mailer */ 37228774250cSGregory Neil Shapiro if (mci->mci_out != NULL) 372340266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 37248774250cSGregory Neil Shapiro 37258774250cSGregory Neil Shapiro /* copy any remaining input to transcript */ 37268774250cSGregory Neil Shapiro if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 37278774250cSGregory Neil Shapiro e->e_xfp != NULL) 37288774250cSGregory Neil Shapiro { 37298774250cSGregory Neil Shapiro while (sfgets(buf, sizeof buf, mci->mci_in, 37308774250cSGregory Neil Shapiro TimeOuts.to_quit, "Draining Input") != NULL) 373140266059SGregory Neil Shapiro (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 37328774250cSGregory Neil Shapiro } 37338774250cSGregory Neil Shapiro 373406f25ae9SGregory Neil Shapiro #if SASL 373540266059SGregory Neil Shapiro /* close SASL connection */ 373606f25ae9SGregory Neil Shapiro if (bitset(MCIF_AUTHACT, mci->mci_flags)) 373706f25ae9SGregory Neil Shapiro { 373806f25ae9SGregory Neil Shapiro sasl_dispose(&mci->mci_conn); 373906f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_AUTHACT; 374006f25ae9SGregory Neil Shapiro } 374106f25ae9SGregory Neil Shapiro #endif /* SASL */ 374206f25ae9SGregory Neil Shapiro 374306f25ae9SGregory Neil Shapiro #if STARTTLS 374406f25ae9SGregory Neil Shapiro /* shutdown TLS */ 374506f25ae9SGregory Neil Shapiro (void) endtlsclt(mci); 374606f25ae9SGregory Neil Shapiro #endif /* STARTTLS */ 374706f25ae9SGregory Neil Shapiro 374806f25ae9SGregory Neil Shapiro /* now close the input */ 374906f25ae9SGregory Neil Shapiro if (mci->mci_in != NULL) 375040266059SGregory Neil Shapiro (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 3751c2aa98e2SPeter Wemm mci->mci_in = mci->mci_out = NULL; 3752c2aa98e2SPeter Wemm mci->mci_state = MCIS_CLOSED; 3753c2aa98e2SPeter Wemm 375406f25ae9SGregory Neil Shapiro errno = save_errno; 375506f25ae9SGregory Neil Shapiro 3756c2aa98e2SPeter Wemm /* in the IPC case there is nothing to wait for */ 3757c2aa98e2SPeter Wemm if (mci->mci_pid == 0) 375806f25ae9SGregory Neil Shapiro return EX_OK; 3759c2aa98e2SPeter Wemm 376006f25ae9SGregory Neil Shapiro /* put a timeout around the wait */ 376106f25ae9SGregory Neil Shapiro if (mci->mci_mailer->m_wait > 0) 376206f25ae9SGregory Neil Shapiro { 376306f25ae9SGregory Neil Shapiro if (setjmp(EndWaitTimeout) == 0) 376440266059SGregory Neil Shapiro ev = sm_setevent(mci->mci_mailer->m_wait, 376506f25ae9SGregory Neil Shapiro endwaittimeout, 0); 376606f25ae9SGregory Neil Shapiro else 376706f25ae9SGregory Neil Shapiro { 376842e5d165SGregory Neil Shapiro syserr("endmailer %s: wait timeout (%ld)", 376906f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, 377042e5d165SGregory Neil Shapiro (long) mci->mci_mailer->m_wait); 377106f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 377206f25ae9SGregory Neil Shapiro } 377306f25ae9SGregory Neil Shapiro } 3774c2aa98e2SPeter Wemm 377506f25ae9SGregory Neil Shapiro /* wait for the mailer process, collect status */ 3776c2aa98e2SPeter Wemm st = waitfor(mci->mci_pid); 377706f25ae9SGregory Neil Shapiro save_errno = errno; 377806f25ae9SGregory Neil Shapiro if (ev != NULL) 377940266059SGregory Neil Shapiro sm_clrevent(ev); 378006f25ae9SGregory Neil Shapiro errno = save_errno; 378106f25ae9SGregory Neil Shapiro 3782c2aa98e2SPeter Wemm if (st == -1) 3783c2aa98e2SPeter Wemm { 3784c2aa98e2SPeter Wemm syserr("endmailer %s: wait", mci->mci_mailer->m_name); 378506f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 3786c2aa98e2SPeter Wemm } 3787c2aa98e2SPeter Wemm 3788c2aa98e2SPeter Wemm if (WIFEXITED(st)) 3789c2aa98e2SPeter Wemm { 3790c2aa98e2SPeter Wemm /* normal death -- return status */ 3791c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 3792c2aa98e2SPeter Wemm } 3793c2aa98e2SPeter Wemm 3794c2aa98e2SPeter Wemm /* it died a horrid death */ 379506f25ae9SGregory Neil Shapiro syserr("451 4.3.0 mailer %s died with signal %d%s", 379606f25ae9SGregory Neil Shapiro mci->mci_mailer->m_name, WTERMSIG(st), 379706f25ae9SGregory Neil Shapiro WCOREDUMP(st) ? " (core dumped)" : 379806f25ae9SGregory Neil Shapiro (WIFSTOPPED(st) ? " (stopped)" : "")); 3799c2aa98e2SPeter Wemm 3800c2aa98e2SPeter Wemm /* log the arguments */ 3801c2aa98e2SPeter Wemm if (pv != NULL && e->e_xfp != NULL) 3802c2aa98e2SPeter Wemm { 3803c2aa98e2SPeter Wemm register char **av; 3804c2aa98e2SPeter Wemm 380540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 3806c2aa98e2SPeter Wemm for (av = pv; *av != NULL; av++) 380740266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 380840266059SGregory Neil Shapiro *av); 380940266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 3810c2aa98e2SPeter Wemm } 3811c2aa98e2SPeter Wemm 3812c2aa98e2SPeter Wemm ExitStat = EX_TEMPFAIL; 381306f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 3814c2aa98e2SPeter Wemm } 381540266059SGregory Neil Shapiro /* 3816c2aa98e2SPeter Wemm ** GIVERESPONSE -- Interpret an error response from a mailer 3817c2aa98e2SPeter Wemm ** 3818c2aa98e2SPeter Wemm ** Parameters: 381906f25ae9SGregory Neil Shapiro ** status -- the status code from the mailer (high byte 3820c2aa98e2SPeter Wemm ** only; core dumps must have been taken care of 3821c2aa98e2SPeter Wemm ** already). 382206f25ae9SGregory Neil Shapiro ** dsn -- the DSN associated with the address, if any. 3823c2aa98e2SPeter Wemm ** m -- the mailer info for this mailer. 3824c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 3825c2aa98e2SPeter Wemm ** response is given before the connection is made. 3826c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the recipient 3827c2aa98e2SPeter Wemm ** address(es). 3828c2aa98e2SPeter Wemm ** xstart -- the transaction start time, for computing 3829c2aa98e2SPeter Wemm ** transaction delays. 3830c2aa98e2SPeter Wemm ** e -- the current envelope. 383140266059SGregory Neil Shapiro ** to -- the current recipient (NULL if none). 3832c2aa98e2SPeter Wemm ** 3833c2aa98e2SPeter Wemm ** Returns: 3834c2aa98e2SPeter Wemm ** none. 3835c2aa98e2SPeter Wemm ** 3836c2aa98e2SPeter Wemm ** Side Effects: 3837c2aa98e2SPeter Wemm ** Errors may be incremented. 3838c2aa98e2SPeter Wemm ** ExitStat may be set. 3839c2aa98e2SPeter Wemm */ 3840c2aa98e2SPeter Wemm 3841c2aa98e2SPeter Wemm void 384240266059SGregory Neil Shapiro giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 384306f25ae9SGregory Neil Shapiro int status; 384406f25ae9SGregory Neil Shapiro char *dsn; 3845c2aa98e2SPeter Wemm register MAILER *m; 3846c2aa98e2SPeter Wemm register MCI *mci; 3847c2aa98e2SPeter Wemm ADDRESS *ctladdr; 3848c2aa98e2SPeter Wemm time_t xstart; 3849c2aa98e2SPeter Wemm ENVELOPE *e; 385040266059SGregory Neil Shapiro ADDRESS *to; 3851c2aa98e2SPeter Wemm { 3852c2aa98e2SPeter Wemm register const char *statmsg; 385306f25ae9SGregory Neil Shapiro int errnum = errno; 385406f25ae9SGregory Neil Shapiro int off = 4; 385540266059SGregory Neil Shapiro bool usestat = false; 385606f25ae9SGregory Neil Shapiro char dsnbuf[ENHSCLEN]; 3857c2aa98e2SPeter Wemm char buf[MAXLINE]; 385840266059SGregory Neil Shapiro char *exmsg; 3859c2aa98e2SPeter Wemm 3860c2aa98e2SPeter Wemm if (e == NULL) 3861c2aa98e2SPeter Wemm syserr("giveresponse: null envelope"); 3862c2aa98e2SPeter Wemm 3863c2aa98e2SPeter Wemm /* 3864c2aa98e2SPeter Wemm ** Compute status message from code. 3865c2aa98e2SPeter Wemm */ 3866c2aa98e2SPeter Wemm 386740266059SGregory Neil Shapiro exmsg = sm_sysexmsg(status); 386806f25ae9SGregory Neil Shapiro if (status == 0) 3869c2aa98e2SPeter Wemm { 387006f25ae9SGregory Neil Shapiro statmsg = "250 2.0.0 Sent"; 3871c2aa98e2SPeter Wemm if (e->e_statmsg != NULL) 3872c2aa98e2SPeter Wemm { 387340266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s (%s)", 387406f25ae9SGregory Neil Shapiro statmsg, 387506f25ae9SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 3876c2aa98e2SPeter Wemm statmsg = buf; 3877c2aa98e2SPeter Wemm } 3878c2aa98e2SPeter Wemm } 387940266059SGregory Neil Shapiro else if (exmsg == NULL) 3880c2aa98e2SPeter Wemm { 388140266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, 388206f25ae9SGregory Neil Shapiro "554 5.3.0 unknown mailer error %d", 388306f25ae9SGregory Neil Shapiro status); 388406f25ae9SGregory Neil Shapiro status = EX_UNAVAILABLE; 3885c2aa98e2SPeter Wemm statmsg = buf; 388640266059SGregory Neil Shapiro usestat = true; 3887c2aa98e2SPeter Wemm } 388806f25ae9SGregory Neil Shapiro else if (status == EX_TEMPFAIL) 3889c2aa98e2SPeter Wemm { 3890c2aa98e2SPeter Wemm char *bp = buf; 3891c2aa98e2SPeter Wemm 389240266059SGregory Neil Shapiro (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 3893c2aa98e2SPeter Wemm bp += strlen(bp); 3894c2aa98e2SPeter Wemm #if NAMED_BIND 3895c2aa98e2SPeter Wemm if (h_errno == TRY_AGAIN) 389640266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 3897c2aa98e2SPeter Wemm else 389806f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3899c2aa98e2SPeter Wemm { 390006f25ae9SGregory Neil Shapiro if (errnum != 0) 390140266059SGregory Neil Shapiro statmsg = sm_errstring(errnum); 3902c2aa98e2SPeter Wemm else 3903c2aa98e2SPeter Wemm statmsg = SmtpError; 3904c2aa98e2SPeter Wemm } 3905c2aa98e2SPeter Wemm if (statmsg != NULL && statmsg[0] != '\0') 390606f25ae9SGregory Neil Shapiro { 390706f25ae9SGregory Neil Shapiro switch (errnum) 390806f25ae9SGregory Neil Shapiro { 390906f25ae9SGregory Neil Shapiro #ifdef ENETDOWN 391006f25ae9SGregory Neil Shapiro case ENETDOWN: /* Network is down */ 391106f25ae9SGregory Neil Shapiro #endif /* ENETDOWN */ 391206f25ae9SGregory Neil Shapiro #ifdef ENETUNREACH 391306f25ae9SGregory Neil Shapiro case ENETUNREACH: /* Network is unreachable */ 391406f25ae9SGregory Neil Shapiro #endif /* ENETUNREACH */ 391506f25ae9SGregory Neil Shapiro #ifdef ENETRESET 391606f25ae9SGregory Neil Shapiro case ENETRESET: /* Network dropped connection on reset */ 391706f25ae9SGregory Neil Shapiro #endif /* ENETRESET */ 391806f25ae9SGregory Neil Shapiro #ifdef ECONNABORTED 391906f25ae9SGregory Neil Shapiro case ECONNABORTED: /* Software caused connection abort */ 392006f25ae9SGregory Neil Shapiro #endif /* ECONNABORTED */ 392106f25ae9SGregory Neil Shapiro #ifdef EHOSTDOWN 392206f25ae9SGregory Neil Shapiro case EHOSTDOWN: /* Host is down */ 392306f25ae9SGregory Neil Shapiro #endif /* EHOSTDOWN */ 392406f25ae9SGregory Neil Shapiro #ifdef EHOSTUNREACH 392506f25ae9SGregory Neil Shapiro case EHOSTUNREACH: /* No route to host */ 392606f25ae9SGregory Neil Shapiro #endif /* EHOSTUNREACH */ 392706f25ae9SGregory Neil Shapiro if (mci->mci_host != NULL) 392806f25ae9SGregory Neil Shapiro { 392940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, 393040266059SGregory Neil Shapiro SPACELEFT(buf, bp), 393140266059SGregory Neil Shapiro 2, ": ", 393240266059SGregory Neil Shapiro mci->mci_host); 393306f25ae9SGregory Neil Shapiro bp += strlen(bp); 393406f25ae9SGregory Neil Shapiro } 393506f25ae9SGregory Neil Shapiro break; 393606f25ae9SGregory Neil Shapiro } 393740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 393840266059SGregory Neil Shapiro statmsg); 393940266059SGregory Neil Shapiro usestat = true; 394006f25ae9SGregory Neil Shapiro } 3941c2aa98e2SPeter Wemm statmsg = buf; 3942c2aa98e2SPeter Wemm } 3943c2aa98e2SPeter Wemm #if NAMED_BIND 394406f25ae9SGregory Neil Shapiro else if (status == EX_NOHOST && h_errno != 0) 3945c2aa98e2SPeter Wemm { 394640266059SGregory Neil Shapiro statmsg = sm_errstring(h_errno + E_DNSBASE); 394740266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1, 394840266059SGregory Neil Shapiro statmsg); 3949c2aa98e2SPeter Wemm statmsg = buf; 395040266059SGregory Neil Shapiro usestat = true; 3951c2aa98e2SPeter Wemm } 395206f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 3953c2aa98e2SPeter Wemm else 3954c2aa98e2SPeter Wemm { 395540266059SGregory Neil Shapiro statmsg = exmsg; 395606f25ae9SGregory Neil Shapiro if (*statmsg++ == ':' && errnum != 0) 3957c2aa98e2SPeter Wemm { 395840266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg, 395940266059SGregory Neil Shapiro sm_errstring(errnum)); 3960c2aa98e2SPeter Wemm statmsg = buf; 396140266059SGregory Neil Shapiro usestat = true; 3962c2aa98e2SPeter Wemm } 3963605302a5SGregory Neil Shapiro else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL) 3964605302a5SGregory Neil Shapiro { 3965605302a5SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "%s (%s)", statmsg, 3966605302a5SGregory Neil Shapiro shortenstring(e->e_statmsg, 403)); 3967605302a5SGregory Neil Shapiro statmsg = buf; 3968605302a5SGregory Neil Shapiro usestat = true; 3969605302a5SGregory Neil Shapiro } 3970c2aa98e2SPeter Wemm } 3971c2aa98e2SPeter Wemm 3972c2aa98e2SPeter Wemm /* 3973c2aa98e2SPeter Wemm ** Print the message as appropriate 3974c2aa98e2SPeter Wemm */ 3975c2aa98e2SPeter Wemm 397606f25ae9SGregory Neil Shapiro if (status == EX_OK || status == EX_TEMPFAIL) 3977c2aa98e2SPeter Wemm { 3978c2aa98e2SPeter Wemm extern char MsgBuf[]; 3979c2aa98e2SPeter Wemm 398006f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0) 398106f25ae9SGregory Neil Shapiro { 398206f25ae9SGregory Neil Shapiro if (dsn == NULL) 398306f25ae9SGregory Neil Shapiro { 398440266059SGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 398506f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 398606f25ae9SGregory Neil Shapiro dsn = dsnbuf; 398706f25ae9SGregory Neil Shapiro } 398806f25ae9SGregory Neil Shapiro off += 5; 398906f25ae9SGregory Neil Shapiro } 399006f25ae9SGregory Neil Shapiro else 399106f25ae9SGregory Neil Shapiro { 399206f25ae9SGregory Neil Shapiro off = 4; 399306f25ae9SGregory Neil Shapiro } 399406f25ae9SGregory Neil Shapiro message("%s", statmsg + off); 399506f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && e->e_xfp != NULL) 399640266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 399740266059SGregory Neil Shapiro &MsgBuf[4]); 3998c2aa98e2SPeter Wemm } 3999c2aa98e2SPeter Wemm else 4000c2aa98e2SPeter Wemm { 400106f25ae9SGregory Neil Shapiro char mbuf[ENHSCLEN + 4]; 4002c2aa98e2SPeter Wemm 4003c2aa98e2SPeter Wemm Errors++; 400406f25ae9SGregory Neil Shapiro if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 400506f25ae9SGregory Neil Shapiro off < sizeof mbuf - 4) 400606f25ae9SGregory Neil Shapiro { 400706f25ae9SGregory Neil Shapiro if (dsn == NULL) 400806f25ae9SGregory Neil Shapiro { 400940266059SGregory Neil Shapiro (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 401006f25ae9SGregory Neil Shapiro "%.*s", off, statmsg + 4); 401106f25ae9SGregory Neil Shapiro dsn = dsnbuf; 401206f25ae9SGregory Neil Shapiro } 401306f25ae9SGregory Neil Shapiro off += 5; 401440266059SGregory Neil Shapiro 401540266059SGregory Neil Shapiro /* copy only part of statmsg to mbuf */ 401640266059SGregory Neil Shapiro (void) sm_strlcpy(mbuf, statmsg, off); 401740266059SGregory Neil Shapiro (void) sm_strlcat(mbuf, " %s", sizeof mbuf); 401806f25ae9SGregory Neil Shapiro } 401906f25ae9SGregory Neil Shapiro else 402006f25ae9SGregory Neil Shapiro { 402106f25ae9SGregory Neil Shapiro dsnbuf[0] = '\0'; 402240266059SGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s", 402340266059SGregory Neil Shapiro statmsg); 402406f25ae9SGregory Neil Shapiro off = 4; 402506f25ae9SGregory Neil Shapiro } 402606f25ae9SGregory Neil Shapiro usrerr(mbuf, &statmsg[off]); 4027c2aa98e2SPeter Wemm } 4028c2aa98e2SPeter Wemm 4029c2aa98e2SPeter Wemm /* 4030c2aa98e2SPeter Wemm ** Final cleanup. 4031c2aa98e2SPeter Wemm ** Log a record of the transaction. Compute the new 4032c2aa98e2SPeter Wemm ** ExitStat -- if we already had an error, stick with 4033c2aa98e2SPeter Wemm ** that. 4034c2aa98e2SPeter Wemm */ 4035c2aa98e2SPeter Wemm 4036c2aa98e2SPeter Wemm if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 403706f25ae9SGregory Neil Shapiro LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 403806f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 4039c2aa98e2SPeter Wemm 4040c2aa98e2SPeter Wemm if (tTd(11, 2)) 404140266059SGregory Neil Shapiro sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 404206f25ae9SGregory Neil Shapiro status, 404306f25ae9SGregory Neil Shapiro dsn == NULL ? "<NULL>" : dsn, 404440266059SGregory Neil Shapiro e->e_message == NULL ? "<NULL>" : e->e_message, 404540266059SGregory Neil Shapiro errnum); 4046c2aa98e2SPeter Wemm 404706f25ae9SGregory Neil Shapiro if (status != EX_TEMPFAIL) 404806f25ae9SGregory Neil Shapiro setstat(status); 404906f25ae9SGregory Neil Shapiro if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 405040266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 405140266059SGregory Neil Shapiro if (status != EX_OK && to != NULL && to->q_message == NULL) 4052c2aa98e2SPeter Wemm { 405340266059SGregory Neil Shapiro if (!usestat && e->e_message != NULL) 405440266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 405540266059SGregory Neil Shapiro e->e_message); 405640266059SGregory Neil Shapiro else 405740266059SGregory Neil Shapiro to->q_message = sm_rpool_strdup_x(e->e_rpool, 405840266059SGregory Neil Shapiro statmsg + off); 4059c2aa98e2SPeter Wemm } 4060c2aa98e2SPeter Wemm errno = 0; 4061602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 4062c2aa98e2SPeter Wemm } 406340266059SGregory Neil Shapiro /* 4064c2aa98e2SPeter Wemm ** LOGDELIVERY -- log the delivery in the system log 4065c2aa98e2SPeter Wemm ** 4066c2aa98e2SPeter Wemm ** Care is taken to avoid logging lines that are too long, because 4067c2aa98e2SPeter Wemm ** some versions of syslog have an unfortunate proclivity for core 4068c2aa98e2SPeter Wemm ** dumping. This is a hack, to be sure, that is at best empirical. 4069c2aa98e2SPeter Wemm ** 4070c2aa98e2SPeter Wemm ** Parameters: 4071c2aa98e2SPeter Wemm ** m -- the mailer info. Can be NULL for initial queue. 4072c2aa98e2SPeter Wemm ** mci -- the mailer connection info -- can be NULL if the 407306f25ae9SGregory Neil Shapiro ** log is occurring when no connection is active. 407406f25ae9SGregory Neil Shapiro ** dsn -- the DSN attached to the status. 407506f25ae9SGregory Neil Shapiro ** status -- the message to print for the status. 4076c2aa98e2SPeter Wemm ** ctladdr -- the controlling address for the to list. 4077c2aa98e2SPeter Wemm ** xstart -- the transaction start time, used for 4078c2aa98e2SPeter Wemm ** computing transaction delay. 4079c2aa98e2SPeter Wemm ** e -- the current envelope. 4080c2aa98e2SPeter Wemm ** 4081c2aa98e2SPeter Wemm ** Returns: 4082c2aa98e2SPeter Wemm ** none 4083c2aa98e2SPeter Wemm ** 4084c2aa98e2SPeter Wemm ** Side Effects: 4085c2aa98e2SPeter Wemm ** none 4086c2aa98e2SPeter Wemm */ 4087c2aa98e2SPeter Wemm 4088c2aa98e2SPeter Wemm void 408906f25ae9SGregory Neil Shapiro logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 4090c2aa98e2SPeter Wemm MAILER *m; 4091c2aa98e2SPeter Wemm register MCI *mci; 409206f25ae9SGregory Neil Shapiro char *dsn; 409306f25ae9SGregory Neil Shapiro const char *status; 4094c2aa98e2SPeter Wemm ADDRESS *ctladdr; 4095c2aa98e2SPeter Wemm time_t xstart; 4096c2aa98e2SPeter Wemm register ENVELOPE *e; 4097c2aa98e2SPeter Wemm { 4098c2aa98e2SPeter Wemm register char *bp; 4099c2aa98e2SPeter Wemm register char *p; 4100c2aa98e2SPeter Wemm int l; 410140266059SGregory Neil Shapiro time_t now = curtime(); 4102c2aa98e2SPeter Wemm char buf[1024]; 4103c2aa98e2SPeter Wemm 4104c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 4105c2aa98e2SPeter Wemm /* ctladdr: max 106 bytes */ 4106c2aa98e2SPeter Wemm bp = buf; 4107c2aa98e2SPeter Wemm if (ctladdr != NULL) 4108c2aa98e2SPeter Wemm { 410940266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 4110c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4111c2aa98e2SPeter Wemm bp += strlen(bp); 4112c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4113c2aa98e2SPeter Wemm { 411440266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 411506f25ae9SGregory Neil Shapiro (int) ctladdr->q_uid, 411606f25ae9SGregory Neil Shapiro (int) ctladdr->q_gid); 4117c2aa98e2SPeter Wemm bp += strlen(bp); 4118c2aa98e2SPeter Wemm } 4119c2aa98e2SPeter Wemm } 4120c2aa98e2SPeter Wemm 4121c2aa98e2SPeter Wemm /* delay & xdelay: max 41 bytes */ 412240266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 412340266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4124c2aa98e2SPeter Wemm bp += strlen(bp); 4125c2aa98e2SPeter Wemm 4126c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4127c2aa98e2SPeter Wemm { 412840266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 412940266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4130c2aa98e2SPeter Wemm bp += strlen(bp); 4131c2aa98e2SPeter Wemm } 4132c2aa98e2SPeter Wemm 4133c2aa98e2SPeter Wemm /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 4134c2aa98e2SPeter Wemm if (m != NULL) 4135c2aa98e2SPeter Wemm { 413640266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 413740266059SGregory Neil Shapiro m->m_name); 4138c2aa98e2SPeter Wemm bp += strlen(bp); 4139c2aa98e2SPeter Wemm } 4140c2aa98e2SPeter Wemm 414106f25ae9SGregory Neil Shapiro /* pri: changes with each delivery attempt */ 414240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 414340266059SGregory Neil Shapiro e->e_msgpriority); 414406f25ae9SGregory Neil Shapiro bp += strlen(bp); 414506f25ae9SGregory Neil Shapiro 4146c2aa98e2SPeter Wemm /* relay: max 66 bytes for IPv4 addresses */ 4147c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4148c2aa98e2SPeter Wemm { 4149c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4150c2aa98e2SPeter Wemm 415140266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 4152c2aa98e2SPeter Wemm shortenstring(mci->mci_host, 40)); 4153c2aa98e2SPeter Wemm bp += strlen(bp); 4154c2aa98e2SPeter Wemm 4155c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 4156c2aa98e2SPeter Wemm { 415740266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 4158c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4159c2aa98e2SPeter Wemm } 4160c2aa98e2SPeter Wemm } 416140266059SGregory Neil Shapiro #if _FFR_QUARANTINE 416240266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 416340266059SGregory Neil Shapiro { 416440266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 416540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 416640266059SGregory Neil Shapiro ", quarantine=%s", 416740266059SGregory Neil Shapiro shortenstring(e->e_quarmsg, 40)); 416840266059SGregory Neil Shapiro } 416940266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 417006f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4171c2aa98e2SPeter Wemm { 4172c2aa98e2SPeter Wemm p = macvalue('h', e); 4173c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 4174c2aa98e2SPeter Wemm { 417540266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 417640266059SGregory Neil Shapiro ", relay=%s", shortenstring(p, 40)); 4177c2aa98e2SPeter Wemm } 4178c2aa98e2SPeter Wemm } 4179c2aa98e2SPeter Wemm bp += strlen(bp); 4180c2aa98e2SPeter Wemm 418106f25ae9SGregory Neil Shapiro /* dsn */ 418206f25ae9SGregory Neil Shapiro if (dsn != NULL && *dsn != '\0') 418306f25ae9SGregory Neil Shapiro { 418440266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 418506f25ae9SGregory Neil Shapiro shortenstring(dsn, ENHSCLEN)); 418606f25ae9SGregory Neil Shapiro bp += strlen(bp); 418706f25ae9SGregory Neil Shapiro } 418806f25ae9SGregory Neil Shapiro 4189c2aa98e2SPeter Wemm # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 4190c2aa98e2SPeter Wemm # if (STATLEN) < 63 4191c2aa98e2SPeter Wemm # undef STATLEN 4192c2aa98e2SPeter Wemm # define STATLEN 63 419306f25ae9SGregory Neil Shapiro # endif /* (STATLEN) < 63 */ 4194c2aa98e2SPeter Wemm # if (STATLEN) > 203 4195c2aa98e2SPeter Wemm # undef STATLEN 4196c2aa98e2SPeter Wemm # define STATLEN 203 419706f25ae9SGregory Neil Shapiro # endif /* (STATLEN) > 203 */ 4198c2aa98e2SPeter Wemm 4199c2aa98e2SPeter Wemm /* stat: max 210 bytes */ 4200c2aa98e2SPeter Wemm if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 4201c2aa98e2SPeter Wemm { 4202c2aa98e2SPeter Wemm /* desperation move -- truncate data */ 4203c2aa98e2SPeter Wemm bp = buf + sizeof buf - ((STATLEN) + 17); 420440266059SGregory Neil Shapiro (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 4205c2aa98e2SPeter Wemm bp += 3; 4206c2aa98e2SPeter Wemm } 4207c2aa98e2SPeter Wemm 420840266059SGregory Neil Shapiro (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 4209c2aa98e2SPeter Wemm bp += strlen(bp); 4210c2aa98e2SPeter Wemm 421140266059SGregory Neil Shapiro (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 421240266059SGregory Neil Shapiro SPACELEFT(buf, bp)); 4213c2aa98e2SPeter Wemm 4214c2aa98e2SPeter Wemm /* id, to: max 13 + TOBUFSIZE bytes */ 4215c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 100 - strlen(buf); 421640266059SGregory Neil Shapiro if (l < 0) 421740266059SGregory Neil Shapiro l = 0; 421806f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 421940266059SGregory Neil Shapiro while (strlen(p) >= l) 4220c2aa98e2SPeter Wemm { 422106f25ae9SGregory Neil Shapiro register char *q; 4222c2aa98e2SPeter Wemm 422306f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 422406f25ae9SGregory Neil Shapiro { 422506f25ae9SGregory Neil Shapiro if (*q == ',') 422606f25ae9SGregory Neil Shapiro break; 422706f25ae9SGregory Neil Shapiro } 422806f25ae9SGregory Neil Shapiro if (p == q) 422906f25ae9SGregory Neil Shapiro break; 423040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 423142e5d165SGregory Neil Shapiro (int) (++q - p), p, buf); 4232c2aa98e2SPeter Wemm p = q; 4233c2aa98e2SPeter Wemm } 423406f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 4235c2aa98e2SPeter Wemm 423606f25ae9SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 4237c2aa98e2SPeter Wemm 4238c2aa98e2SPeter Wemm l = SYSLOG_BUFSIZE - 85; 423940266059SGregory Neil Shapiro if (l < 0) 424040266059SGregory Neil Shapiro l = 0; 424106f25ae9SGregory Neil Shapiro p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 424240266059SGregory Neil Shapiro while (strlen(p) >= l) 4243c2aa98e2SPeter Wemm { 424406f25ae9SGregory Neil Shapiro register char *q; 4245c2aa98e2SPeter Wemm 424606f25ae9SGregory Neil Shapiro for (q = p + l; q > p; q--) 424706f25ae9SGregory Neil Shapiro { 424806f25ae9SGregory Neil Shapiro if (*q == ',') 424906f25ae9SGregory Neil Shapiro break; 425006f25ae9SGregory Neil Shapiro } 425106f25ae9SGregory Neil Shapiro if (p == q) 425206f25ae9SGregory Neil Shapiro break; 425306f25ae9SGregory Neil Shapiro 425440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 425542e5d165SGregory Neil Shapiro (int) (++q - p), p); 4256c2aa98e2SPeter Wemm p = q; 4257c2aa98e2SPeter Wemm } 425806f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 4259c2aa98e2SPeter Wemm 4260c2aa98e2SPeter Wemm if (ctladdr != NULL) 4261c2aa98e2SPeter Wemm { 4262c2aa98e2SPeter Wemm bp = buf; 426340266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 4264c2aa98e2SPeter Wemm shortenstring(ctladdr->q_paddr, 83)); 4265c2aa98e2SPeter Wemm bp += strlen(bp); 4266c2aa98e2SPeter Wemm if (bitset(QGOODUID, ctladdr->q_flags)) 4267c2aa98e2SPeter Wemm { 426840266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 4269c2aa98e2SPeter Wemm ctladdr->q_uid, ctladdr->q_gid); 4270c2aa98e2SPeter Wemm bp += strlen(bp); 4271c2aa98e2SPeter Wemm } 4272c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%s", buf); 4273c2aa98e2SPeter Wemm } 4274c2aa98e2SPeter Wemm bp = buf; 427540266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 427640266059SGregory Neil Shapiro pintvl(now - e->e_ctime, true)); 4277c2aa98e2SPeter Wemm bp += strlen(bp); 4278c2aa98e2SPeter Wemm if (xstart != (time_t) 0) 4279c2aa98e2SPeter Wemm { 428040266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 428140266059SGregory Neil Shapiro pintvl(now - xstart, true)); 4282c2aa98e2SPeter Wemm bp += strlen(bp); 4283c2aa98e2SPeter Wemm } 4284c2aa98e2SPeter Wemm 4285c2aa98e2SPeter Wemm if (m != NULL) 4286c2aa98e2SPeter Wemm { 428740266059SGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 428840266059SGregory Neil Shapiro m->m_name); 4289c2aa98e2SPeter Wemm bp += strlen(bp); 4290c2aa98e2SPeter Wemm } 4291c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4292c2aa98e2SPeter Wemm 4293c2aa98e2SPeter Wemm buf[0] = '\0'; 4294c2aa98e2SPeter Wemm bp = buf; 4295c2aa98e2SPeter Wemm if (mci != NULL && mci->mci_host != NULL) 4296c2aa98e2SPeter Wemm { 4297c2aa98e2SPeter Wemm extern SOCKADDR CurHostAddr; 4298c2aa98e2SPeter Wemm 429940266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 430040266059SGregory Neil Shapiro mci->mci_host); 4301c2aa98e2SPeter Wemm bp += strlen(bp); 4302c2aa98e2SPeter Wemm 4303c2aa98e2SPeter Wemm if (CurHostAddr.sa.sa_family != 0) 430440266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 430540266059SGregory Neil Shapiro " [%.100s]", 4306c2aa98e2SPeter Wemm anynet_ntoa(&CurHostAddr)); 4307c2aa98e2SPeter Wemm } 430840266059SGregory Neil Shapiro #if _FFR_QUARANTINE 430940266059SGregory Neil Shapiro else if (strcmp(status, "quarantined") == 0) 431040266059SGregory Neil Shapiro { 431140266059SGregory Neil Shapiro if (e->e_quarmsg != NULL) 431240266059SGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 431340266059SGregory Neil Shapiro ", quarantine=%.100s", 431440266059SGregory Neil Shapiro e->e_quarmsg); 431540266059SGregory Neil Shapiro } 431640266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 431706f25ae9SGregory Neil Shapiro else if (strcmp(status, "queued") != 0) 4318c2aa98e2SPeter Wemm { 4319c2aa98e2SPeter Wemm p = macvalue('h', e); 4320c2aa98e2SPeter Wemm if (p != NULL && p[0] != '\0') 432140266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p); 4322c2aa98e2SPeter Wemm } 4323c2aa98e2SPeter Wemm if (buf[0] != '\0') 4324c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 4325c2aa98e2SPeter Wemm 432606f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 432706f25ae9SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 4328c2aa98e2SPeter Wemm } 432940266059SGregory Neil Shapiro /* 4330c2aa98e2SPeter Wemm ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 4331c2aa98e2SPeter Wemm ** 4332c2aa98e2SPeter Wemm ** This can be made an arbitrary message separator by changing $l 4333c2aa98e2SPeter Wemm ** 4334c2aa98e2SPeter Wemm ** One of the ugliest hacks seen by human eyes is contained herein: 4335c2aa98e2SPeter Wemm ** UUCP wants those stupid "remote from <host>" lines. Why oh why 4336c2aa98e2SPeter Wemm ** does a well-meaning programmer such as myself have to deal with 4337c2aa98e2SPeter Wemm ** this kind of antique garbage???? 4338c2aa98e2SPeter Wemm ** 4339c2aa98e2SPeter Wemm ** Parameters: 4340c2aa98e2SPeter Wemm ** mci -- the connection information. 4341c2aa98e2SPeter Wemm ** e -- the envelope. 4342c2aa98e2SPeter Wemm ** 4343c2aa98e2SPeter Wemm ** Returns: 4344c2aa98e2SPeter Wemm ** none 4345c2aa98e2SPeter Wemm ** 4346c2aa98e2SPeter Wemm ** Side Effects: 4347c2aa98e2SPeter Wemm ** outputs some text to fp. 4348c2aa98e2SPeter Wemm */ 4349c2aa98e2SPeter Wemm 4350c2aa98e2SPeter Wemm void 4351c2aa98e2SPeter Wemm putfromline(mci, e) 4352c2aa98e2SPeter Wemm register MCI *mci; 4353c2aa98e2SPeter Wemm ENVELOPE *e; 4354c2aa98e2SPeter Wemm { 4355c2aa98e2SPeter Wemm char *template = UnixFromLine; 4356c2aa98e2SPeter Wemm char buf[MAXLINE]; 4357c2aa98e2SPeter Wemm char xbuf[MAXLINE]; 4358c2aa98e2SPeter Wemm 4359c2aa98e2SPeter Wemm if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 4360c2aa98e2SPeter Wemm return; 4361c2aa98e2SPeter Wemm 4362c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 4363c2aa98e2SPeter Wemm 4364c2aa98e2SPeter Wemm if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 4365c2aa98e2SPeter Wemm { 4366c2aa98e2SPeter Wemm char *bang; 4367c2aa98e2SPeter Wemm 4368c2aa98e2SPeter Wemm expand("\201g", buf, sizeof buf, e); 4369c2aa98e2SPeter Wemm bang = strchr(buf, '!'); 4370c2aa98e2SPeter Wemm if (bang == NULL) 4371c2aa98e2SPeter Wemm { 4372c2aa98e2SPeter Wemm char *at; 4373c2aa98e2SPeter Wemm char hname[MAXNAME]; 4374c2aa98e2SPeter Wemm 4375c2aa98e2SPeter Wemm /* 4376c2aa98e2SPeter Wemm ** If we can construct a UUCP path, do so 4377c2aa98e2SPeter Wemm */ 4378c2aa98e2SPeter Wemm 4379c2aa98e2SPeter Wemm at = strrchr(buf, '@'); 4380c2aa98e2SPeter Wemm if (at == NULL) 4381c2aa98e2SPeter Wemm { 4382c2aa98e2SPeter Wemm expand("\201k", hname, sizeof hname, e); 4383c2aa98e2SPeter Wemm at = hname; 4384c2aa98e2SPeter Wemm } 4385c2aa98e2SPeter Wemm else 4386c2aa98e2SPeter Wemm *at++ = '\0'; 438740266059SGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof xbuf, 4388c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4389c2aa98e2SPeter Wemm buf, at); 4390c2aa98e2SPeter Wemm } 4391c2aa98e2SPeter Wemm else 4392c2aa98e2SPeter Wemm { 4393c2aa98e2SPeter Wemm *bang++ = '\0'; 439440266059SGregory Neil Shapiro (void) sm_snprintf(xbuf, sizeof xbuf, 4395c2aa98e2SPeter Wemm "From %.800s \201d remote from %.100s\n", 4396c2aa98e2SPeter Wemm bang, buf); 4397c2aa98e2SPeter Wemm template = xbuf; 4398c2aa98e2SPeter Wemm } 4399c2aa98e2SPeter Wemm } 4400c2aa98e2SPeter Wemm expand(template, buf, sizeof buf, e); 4401c2aa98e2SPeter Wemm putxline(buf, strlen(buf), mci, PXLF_HEADER); 4402c2aa98e2SPeter Wemm } 440340266059SGregory Neil Shapiro /* 4404c2aa98e2SPeter Wemm ** PUTBODY -- put the body of a message. 4405c2aa98e2SPeter Wemm ** 4406c2aa98e2SPeter Wemm ** Parameters: 4407c2aa98e2SPeter Wemm ** mci -- the connection information. 4408c2aa98e2SPeter Wemm ** e -- the envelope to put out. 4409c2aa98e2SPeter Wemm ** separator -- if non-NULL, a message separator that must 4410c2aa98e2SPeter Wemm ** not be permitted in the resulting message. 4411c2aa98e2SPeter Wemm ** 4412c2aa98e2SPeter Wemm ** Returns: 4413c2aa98e2SPeter Wemm ** none. 4414c2aa98e2SPeter Wemm ** 4415c2aa98e2SPeter Wemm ** Side Effects: 4416c2aa98e2SPeter Wemm ** The message is written onto fp. 4417c2aa98e2SPeter Wemm */ 4418c2aa98e2SPeter Wemm 4419c2aa98e2SPeter Wemm /* values for output state variable */ 4420c2aa98e2SPeter Wemm #define OS_HEAD 0 /* at beginning of line */ 4421c2aa98e2SPeter Wemm #define OS_CR 1 /* read a carriage return */ 4422c2aa98e2SPeter Wemm #define OS_INLINE 2 /* putting rest of line */ 4423c2aa98e2SPeter Wemm 4424c2aa98e2SPeter Wemm void 4425c2aa98e2SPeter Wemm putbody(mci, e, separator) 4426c2aa98e2SPeter Wemm register MCI *mci; 4427c2aa98e2SPeter Wemm register ENVELOPE *e; 4428c2aa98e2SPeter Wemm char *separator; 4429c2aa98e2SPeter Wemm { 443040266059SGregory Neil Shapiro bool dead = false; 4431c2aa98e2SPeter Wemm char buf[MAXLINE]; 443240266059SGregory Neil Shapiro #if MIME8TO7 4433065a643dSPeter Wemm char *boundaries[MAXMIMENESTING + 1]; 443440266059SGregory Neil Shapiro #endif /* MIME8TO7 */ 4435c2aa98e2SPeter Wemm 4436c2aa98e2SPeter Wemm /* 4437c2aa98e2SPeter Wemm ** Output the body of the message 4438c2aa98e2SPeter Wemm */ 4439c2aa98e2SPeter Wemm 4440c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 4441c2aa98e2SPeter Wemm { 444240266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 4443c2aa98e2SPeter Wemm 444440266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 444540266059SGregory Neil Shapiro SM_IO_RDONLY, NULL); 4446c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 444706f25ae9SGregory Neil Shapiro { 444806f25ae9SGregory Neil Shapiro char *msg = "!putbody: Cannot open %s for %s from %s"; 444906f25ae9SGregory Neil Shapiro 445006f25ae9SGregory Neil Shapiro if (errno == ENOENT) 445106f25ae9SGregory Neil Shapiro msg++; 445206f25ae9SGregory Neil Shapiro syserr(msg, df, e->e_to, e->e_from.q_paddr); 445306f25ae9SGregory Neil Shapiro } 445440266059SGregory Neil Shapiro 4455c2aa98e2SPeter Wemm } 4456c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 4457c2aa98e2SPeter Wemm { 4458c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4459c2aa98e2SPeter Wemm { 4460c2aa98e2SPeter Wemm putline("", mci); 4461c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4462c2aa98e2SPeter Wemm } 4463c2aa98e2SPeter Wemm putline("<<< No Message Collected >>>", mci); 4464c2aa98e2SPeter Wemm goto endofmessage; 4465c2aa98e2SPeter Wemm } 446606f25ae9SGregory Neil Shapiro 4467c2aa98e2SPeter Wemm if (e->e_dfino == (ino_t) 0) 4468c2aa98e2SPeter Wemm { 4469c2aa98e2SPeter Wemm struct stat stbuf; 4470c2aa98e2SPeter Wemm 447140266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 447240266059SGregory Neil Shapiro < 0) 4473c2aa98e2SPeter Wemm e->e_dfino = -1; 4474c2aa98e2SPeter Wemm else 4475c2aa98e2SPeter Wemm { 4476c2aa98e2SPeter Wemm e->e_dfdev = stbuf.st_dev; 4477c2aa98e2SPeter Wemm e->e_dfino = stbuf.st_ino; 4478c2aa98e2SPeter Wemm } 4479c2aa98e2SPeter Wemm } 448006f25ae9SGregory Neil Shapiro 448140266059SGregory Neil Shapiro /* paranoia: the data file should always be in a rewound state */ 448206f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 4483c2aa98e2SPeter Wemm 4484c2aa98e2SPeter Wemm #if MIME8TO7 4485c2aa98e2SPeter Wemm if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 4486c2aa98e2SPeter Wemm { 4487c2aa98e2SPeter Wemm /* 4488c2aa98e2SPeter Wemm ** Do 8 to 7 bit MIME conversion. 4489c2aa98e2SPeter Wemm */ 4490c2aa98e2SPeter Wemm 4491c2aa98e2SPeter Wemm /* make sure it looks like a MIME message */ 4492c2aa98e2SPeter Wemm if (hvalue("MIME-Version", e->e_header) == NULL) 4493c2aa98e2SPeter Wemm putline("MIME-Version: 1.0", mci); 4494c2aa98e2SPeter Wemm 4495c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 4496c2aa98e2SPeter Wemm { 449740266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, 4498c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 4499c2aa98e2SPeter Wemm defcharset(e)); 4500c2aa98e2SPeter Wemm putline(buf, mci); 4501c2aa98e2SPeter Wemm } 4502c2aa98e2SPeter Wemm 4503c2aa98e2SPeter Wemm /* now do the hard work */ 4504c2aa98e2SPeter Wemm boundaries[0] = NULL; 4505c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 450606f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 4507c2aa98e2SPeter Wemm } 4508c2aa98e2SPeter Wemm # if MIME7TO8 4509c2aa98e2SPeter Wemm else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 4510c2aa98e2SPeter Wemm { 451106f25ae9SGregory Neil Shapiro (void) mime7to8(mci, e->e_header, e); 4512c2aa98e2SPeter Wemm } 451306f25ae9SGregory Neil Shapiro # endif /* MIME7TO8 */ 4514065a643dSPeter Wemm else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 4515065a643dSPeter Wemm { 451606f25ae9SGregory Neil Shapiro bool oldsuprerrs = SuprErrs; 451706f25ae9SGregory Neil Shapiro 4518065a643dSPeter Wemm /* Use mime8to7 to check multipart for MIME header overflows */ 4519065a643dSPeter Wemm boundaries[0] = NULL; 4520065a643dSPeter Wemm mci->mci_flags |= MCIF_INHEADER; 452106f25ae9SGregory Neil Shapiro 452206f25ae9SGregory Neil Shapiro /* 452306f25ae9SGregory Neil Shapiro ** If EF_DONT_MIME is set, we have a broken MIME message 452406f25ae9SGregory Neil Shapiro ** and don't want to generate a new bounce message whose 452506f25ae9SGregory Neil Shapiro ** body propagates the broken MIME. We can't just not call 452606f25ae9SGregory Neil Shapiro ** mime8to7() as is done above since we need the security 452706f25ae9SGregory Neil Shapiro ** checks. The best we can do is suppress the errors. 452806f25ae9SGregory Neil Shapiro */ 452906f25ae9SGregory Neil Shapiro 453006f25ae9SGregory Neil Shapiro if (bitset(EF_DONT_MIME, e->e_flags)) 453140266059SGregory Neil Shapiro SuprErrs = true; 453206f25ae9SGregory Neil Shapiro 453306f25ae9SGregory Neil Shapiro (void) mime8to7(mci, e->e_header, e, boundaries, 453406f25ae9SGregory Neil Shapiro M87F_OUTER|M87F_NO8TO7); 453506f25ae9SGregory Neil Shapiro 453606f25ae9SGregory Neil Shapiro /* restore SuprErrs */ 453706f25ae9SGregory Neil Shapiro SuprErrs = oldsuprerrs; 4538065a643dSPeter Wemm } 4539c2aa98e2SPeter Wemm else 454006f25ae9SGregory Neil Shapiro #endif /* MIME8TO7 */ 4541c2aa98e2SPeter Wemm { 4542c2aa98e2SPeter Wemm int ostate; 4543c2aa98e2SPeter Wemm register char *bp; 4544c2aa98e2SPeter Wemm register char *pbp; 4545c2aa98e2SPeter Wemm register int c; 4546c2aa98e2SPeter Wemm register char *xp; 4547c2aa98e2SPeter Wemm int padc; 4548c2aa98e2SPeter Wemm char *buflim; 4549c2aa98e2SPeter Wemm int pos = 0; 455006f25ae9SGregory Neil Shapiro char peekbuf[12]; 4551c2aa98e2SPeter Wemm 4552c2aa98e2SPeter Wemm if (bitset(MCIF_INHEADER, mci->mci_flags)) 4553c2aa98e2SPeter Wemm { 4554c2aa98e2SPeter Wemm putline("", mci); 4555c2aa98e2SPeter Wemm mci->mci_flags &= ~MCIF_INHEADER; 4556c2aa98e2SPeter Wemm } 4557c2aa98e2SPeter Wemm 4558c2aa98e2SPeter Wemm /* determine end of buffer; allow for short mailer lines */ 4559c2aa98e2SPeter Wemm buflim = &buf[sizeof buf - 1]; 4560c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 4561c2aa98e2SPeter Wemm mci->mci_mailer->m_linelimit < sizeof buf - 1) 4562c2aa98e2SPeter Wemm buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 4563c2aa98e2SPeter Wemm 4564c2aa98e2SPeter Wemm /* copy temp file to output with mapping */ 4565c2aa98e2SPeter Wemm ostate = OS_HEAD; 4566c2aa98e2SPeter Wemm bp = buf; 4567c2aa98e2SPeter Wemm pbp = peekbuf; 456840266059SGregory Neil Shapiro while (!sm_io_error(mci->mci_out) && !dead) 4569c2aa98e2SPeter Wemm { 4570c2aa98e2SPeter Wemm if (pbp > peekbuf) 4571c2aa98e2SPeter Wemm c = *--pbp; 457240266059SGregory Neil Shapiro else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 457340266059SGregory Neil Shapiro == SM_IO_EOF) 4574c2aa98e2SPeter Wemm break; 4575c2aa98e2SPeter Wemm if (bitset(MCIF_7BIT, mci->mci_flags)) 4576c2aa98e2SPeter Wemm c &= 0x7f; 4577c2aa98e2SPeter Wemm switch (ostate) 4578c2aa98e2SPeter Wemm { 4579c2aa98e2SPeter Wemm case OS_HEAD: 4580c2aa98e2SPeter Wemm if (c == '\0' && 458140266059SGregory Neil Shapiro bitnset(M_NONULLS, 458240266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4583c2aa98e2SPeter Wemm break; 4584c2aa98e2SPeter Wemm if (c != '\r' && c != '\n' && bp < buflim) 4585c2aa98e2SPeter Wemm { 4586c2aa98e2SPeter Wemm *bp++ = c; 4587c2aa98e2SPeter Wemm break; 4588c2aa98e2SPeter Wemm } 4589c2aa98e2SPeter Wemm 4590c2aa98e2SPeter Wemm /* check beginning of line for special cases */ 4591c2aa98e2SPeter Wemm *bp = '\0'; 4592c2aa98e2SPeter Wemm pos = 0; 459340266059SGregory Neil Shapiro padc = SM_IO_EOF; 4594c2aa98e2SPeter Wemm if (buf[0] == 'F' && 459540266059SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 459640266059SGregory Neil Shapiro && strncmp(buf, "From ", 5) == 0) 4597c2aa98e2SPeter Wemm { 4598c2aa98e2SPeter Wemm padc = '>'; 4599c2aa98e2SPeter Wemm } 4600c2aa98e2SPeter Wemm if (buf[0] == '-' && buf[1] == '-' && 4601c2aa98e2SPeter Wemm separator != NULL) 4602c2aa98e2SPeter Wemm { 4603c2aa98e2SPeter Wemm /* possible separator */ 4604c2aa98e2SPeter Wemm int sl = strlen(separator); 4605c2aa98e2SPeter Wemm 460640266059SGregory Neil Shapiro if (strncmp(&buf[2], separator, sl) 460740266059SGregory Neil Shapiro == 0) 4608c2aa98e2SPeter Wemm padc = ' '; 4609c2aa98e2SPeter Wemm } 4610c2aa98e2SPeter Wemm if (buf[0] == '.' && 4611c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 4612c2aa98e2SPeter Wemm { 4613c2aa98e2SPeter Wemm padc = '.'; 4614c2aa98e2SPeter Wemm } 4615c2aa98e2SPeter Wemm 4616c2aa98e2SPeter Wemm /* now copy out saved line */ 4617c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4618c2aa98e2SPeter Wemm { 461940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 462040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 462140266059SGregory Neil Shapiro "%05d >>> ", 462240266059SGregory Neil Shapiro (int) CurrentPid); 462340266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 462440266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 462540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 462640266059SGregory Neil Shapiro padc); 4627c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 462840266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 462940266059SGregory Neil Shapiro SM_TIME_DEFAULT, 463040266059SGregory Neil Shapiro (unsigned char) *xp); 4631c2aa98e2SPeter Wemm if (c == '\n') 463240266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 463340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 463440266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4635c2aa98e2SPeter Wemm } 463640266059SGregory Neil Shapiro if (padc != SM_IO_EOF) 4637c2aa98e2SPeter Wemm { 463840266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 463940266059SGregory Neil Shapiro SM_TIME_DEFAULT, padc) 464040266059SGregory Neil Shapiro == SM_IO_EOF) 464106f25ae9SGregory Neil Shapiro { 464240266059SGregory Neil Shapiro dead = true; 464306f25ae9SGregory Neil Shapiro continue; 464406f25ae9SGregory Neil Shapiro } 4645193538b7SGregory Neil Shapiro else 4646193538b7SGregory Neil Shapiro { 4647193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 464840266059SGregory Neil Shapiro DataProgress = true; 4649193538b7SGregory Neil Shapiro } 4650c2aa98e2SPeter Wemm pos++; 4651c2aa98e2SPeter Wemm } 4652c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4653c2aa98e2SPeter Wemm { 465440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 465540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 465640266059SGregory Neil Shapiro (unsigned char) *xp) 465740266059SGregory Neil Shapiro == SM_IO_EOF) 465806f25ae9SGregory Neil Shapiro { 465940266059SGregory Neil Shapiro dead = true; 466006f25ae9SGregory Neil Shapiro break; 4661c2aa98e2SPeter Wemm } 4662193538b7SGregory Neil Shapiro else 4663193538b7SGregory Neil Shapiro { 466406f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 466540266059SGregory Neil Shapiro DataProgress = true; 466606f25ae9SGregory Neil Shapiro } 4667193538b7SGregory Neil Shapiro } 466806f25ae9SGregory Neil Shapiro if (dead) 466906f25ae9SGregory Neil Shapiro continue; 4670c2aa98e2SPeter Wemm if (c == '\n') 4671c2aa98e2SPeter Wemm { 467240266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 467340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 467440266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 467540266059SGregory Neil Shapiro == SM_IO_EOF) 467606f25ae9SGregory Neil Shapiro break; 4677193538b7SGregory Neil Shapiro else 4678193538b7SGregory Neil Shapiro { 4679193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 468040266059SGregory Neil Shapiro DataProgress = true; 4681193538b7SGregory Neil Shapiro } 4682c2aa98e2SPeter Wemm pos = 0; 4683c2aa98e2SPeter Wemm } 4684c2aa98e2SPeter Wemm else 4685c2aa98e2SPeter Wemm { 4686c2aa98e2SPeter Wemm pos += bp - buf; 4687c2aa98e2SPeter Wemm if (c != '\r') 4688c2aa98e2SPeter Wemm *pbp++ = c; 4689c2aa98e2SPeter Wemm } 469006f25ae9SGregory Neil Shapiro 4691c2aa98e2SPeter Wemm bp = buf; 4692c2aa98e2SPeter Wemm 4693c2aa98e2SPeter Wemm /* determine next state */ 4694c2aa98e2SPeter Wemm if (c == '\n') 4695c2aa98e2SPeter Wemm ostate = OS_HEAD; 4696c2aa98e2SPeter Wemm else if (c == '\r') 4697c2aa98e2SPeter Wemm ostate = OS_CR; 4698c2aa98e2SPeter Wemm else 4699c2aa98e2SPeter Wemm ostate = OS_INLINE; 4700c2aa98e2SPeter Wemm continue; 4701c2aa98e2SPeter Wemm 4702c2aa98e2SPeter Wemm case OS_CR: 4703c2aa98e2SPeter Wemm if (c == '\n') 4704c2aa98e2SPeter Wemm { 4705c2aa98e2SPeter Wemm /* got CRLF */ 470640266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 470740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 470840266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 470940266059SGregory Neil Shapiro == SM_IO_EOF) 471006f25ae9SGregory Neil Shapiro continue; 4711193538b7SGregory Neil Shapiro else 4712193538b7SGregory Neil Shapiro { 471306f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 471440266059SGregory Neil Shapiro DataProgress = true; 4715193538b7SGregory Neil Shapiro } 471606f25ae9SGregory Neil Shapiro 4717c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4718c2aa98e2SPeter Wemm { 471940266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 472040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 472140266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 4722c2aa98e2SPeter Wemm } 4723c2aa98e2SPeter Wemm ostate = OS_HEAD; 4724c2aa98e2SPeter Wemm continue; 4725c2aa98e2SPeter Wemm } 4726c2aa98e2SPeter Wemm 4727c2aa98e2SPeter Wemm /* had a naked carriage return */ 4728c2aa98e2SPeter Wemm *pbp++ = c; 4729c2aa98e2SPeter Wemm c = '\r'; 4730c2aa98e2SPeter Wemm ostate = OS_INLINE; 4731c2aa98e2SPeter Wemm goto putch; 4732c2aa98e2SPeter Wemm 4733c2aa98e2SPeter Wemm case OS_INLINE: 4734c2aa98e2SPeter Wemm if (c == '\r') 4735c2aa98e2SPeter Wemm { 4736c2aa98e2SPeter Wemm ostate = OS_CR; 4737c2aa98e2SPeter Wemm continue; 4738c2aa98e2SPeter Wemm } 4739c2aa98e2SPeter Wemm if (c == '\0' && 474040266059SGregory Neil Shapiro bitnset(M_NONULLS, 474140266059SGregory Neil Shapiro mci->mci_mailer->m_flags)) 4742c2aa98e2SPeter Wemm break; 4743c2aa98e2SPeter Wemm putch: 4744c2aa98e2SPeter Wemm if (mci->mci_mailer->m_linelimit > 0 && 474506f25ae9SGregory Neil Shapiro pos >= mci->mci_mailer->m_linelimit - 1 && 4746c2aa98e2SPeter Wemm c != '\n') 4747c2aa98e2SPeter Wemm { 474806f25ae9SGregory Neil Shapiro int d; 474906f25ae9SGregory Neil Shapiro 475006f25ae9SGregory Neil Shapiro /* check next character for EOL */ 475106f25ae9SGregory Neil Shapiro if (pbp > peekbuf) 475206f25ae9SGregory Neil Shapiro d = *(pbp - 1); 475340266059SGregory Neil Shapiro else if ((d = sm_io_getc(e->e_dfp, 475440266059SGregory Neil Shapiro SM_TIME_DEFAULT)) 475540266059SGregory Neil Shapiro != SM_IO_EOF) 475606f25ae9SGregory Neil Shapiro *pbp++ = d; 475706f25ae9SGregory Neil Shapiro 475840266059SGregory Neil Shapiro if (d == '\n' || d == SM_IO_EOF) 475906f25ae9SGregory Neil Shapiro { 476006f25ae9SGregory Neil Shapiro if (TrafficLogFile != NULL) 476140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 476240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 476340266059SGregory Neil Shapiro (unsigned char) c); 476440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 476540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 476640266059SGregory Neil Shapiro (unsigned char) c) 476740266059SGregory Neil Shapiro == SM_IO_EOF) 476806f25ae9SGregory Neil Shapiro { 476940266059SGregory Neil Shapiro dead = true; 477006f25ae9SGregory Neil Shapiro continue; 477106f25ae9SGregory Neil Shapiro } 4772193538b7SGregory Neil Shapiro else 4773193538b7SGregory Neil Shapiro { 4774193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 477540266059SGregory Neil Shapiro DataProgress = true; 4776193538b7SGregory Neil Shapiro } 477706f25ae9SGregory Neil Shapiro pos++; 477806f25ae9SGregory Neil Shapiro continue; 477906f25ae9SGregory Neil Shapiro } 478006f25ae9SGregory Neil Shapiro 478140266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 478240266059SGregory Neil Shapiro SM_TIME_DEFAULT, '!') 478340266059SGregory Neil Shapiro == SM_IO_EOF || 478440266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out, 478540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 478640266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 478740266059SGregory Neil Shapiro == SM_IO_EOF) 478806f25ae9SGregory Neil Shapiro { 478940266059SGregory Neil Shapiro dead = true; 479006f25ae9SGregory Neil Shapiro continue; 479106f25ae9SGregory Neil Shapiro } 4792193538b7SGregory Neil Shapiro else 4793193538b7SGregory Neil Shapiro { 479406f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 479540266059SGregory Neil Shapiro DataProgress = true; 4796193538b7SGregory Neil Shapiro } 479706f25ae9SGregory Neil Shapiro 4798c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4799c2aa98e2SPeter Wemm { 480040266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 480140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 480240266059SGregory Neil Shapiro "!%s", 4803c2aa98e2SPeter Wemm mci->mci_mailer->m_eol); 4804c2aa98e2SPeter Wemm } 4805c2aa98e2SPeter Wemm ostate = OS_HEAD; 4806c2aa98e2SPeter Wemm *pbp++ = c; 4807c2aa98e2SPeter Wemm continue; 4808c2aa98e2SPeter Wemm } 4809c2aa98e2SPeter Wemm if (c == '\n') 4810c2aa98e2SPeter Wemm { 4811c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 481240266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 481340266059SGregory Neil Shapiro SM_TIME_DEFAULT, 481440266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 481540266059SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, 481640266059SGregory Neil Shapiro SM_TIME_DEFAULT, 481740266059SGregory Neil Shapiro mci->mci_mailer->m_eol) 481840266059SGregory Neil Shapiro == SM_IO_EOF) 481906f25ae9SGregory Neil Shapiro continue; 4820193538b7SGregory Neil Shapiro else 4821193538b7SGregory Neil Shapiro { 4822193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 482340266059SGregory Neil Shapiro DataProgress = true; 4824193538b7SGregory Neil Shapiro } 4825c2aa98e2SPeter Wemm pos = 0; 4826c2aa98e2SPeter Wemm ostate = OS_HEAD; 4827c2aa98e2SPeter Wemm } 4828c2aa98e2SPeter Wemm else 4829c2aa98e2SPeter Wemm { 4830c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 483140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 483240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 483340266059SGregory Neil Shapiro (unsigned char) c); 483440266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, 483540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 483640266059SGregory Neil Shapiro (unsigned char) c) 483740266059SGregory Neil Shapiro == SM_IO_EOF) 483806f25ae9SGregory Neil Shapiro { 483940266059SGregory Neil Shapiro dead = true; 484006f25ae9SGregory Neil Shapiro continue; 484106f25ae9SGregory Neil Shapiro } 4842193538b7SGregory Neil Shapiro else 4843193538b7SGregory Neil Shapiro { 4844193538b7SGregory Neil Shapiro /* record progress for DATA timeout */ 484540266059SGregory Neil Shapiro DataProgress = true; 4846193538b7SGregory Neil Shapiro } 4847c2aa98e2SPeter Wemm pos++; 4848c2aa98e2SPeter Wemm ostate = OS_INLINE; 4849c2aa98e2SPeter Wemm } 4850c2aa98e2SPeter Wemm break; 4851c2aa98e2SPeter Wemm } 4852c2aa98e2SPeter Wemm } 4853c2aa98e2SPeter Wemm 4854c2aa98e2SPeter Wemm /* make sure we are at the beginning of a line */ 4855c2aa98e2SPeter Wemm if (bp > buf) 4856c2aa98e2SPeter Wemm { 4857c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 4858c2aa98e2SPeter Wemm { 4859c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 486040266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 486140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 486240266059SGregory Neil Shapiro (unsigned char) *xp); 4863c2aa98e2SPeter Wemm } 4864c2aa98e2SPeter Wemm for (xp = buf; xp < bp; xp++) 4865c2aa98e2SPeter Wemm { 486640266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 486740266059SGregory Neil Shapiro (unsigned char) *xp) 486840266059SGregory Neil Shapiro == SM_IO_EOF) 486906f25ae9SGregory Neil Shapiro { 487040266059SGregory Neil Shapiro dead = true; 487106f25ae9SGregory Neil Shapiro break; 487206f25ae9SGregory Neil Shapiro } 4873193538b7SGregory Neil Shapiro else 4874193538b7SGregory Neil Shapiro { 487506f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 487640266059SGregory Neil Shapiro DataProgress = true; 4877c2aa98e2SPeter Wemm } 4878193538b7SGregory Neil Shapiro } 4879c2aa98e2SPeter Wemm pos += bp - buf; 4880c2aa98e2SPeter Wemm } 488106f25ae9SGregory Neil Shapiro if (!dead && pos > 0) 4882c2aa98e2SPeter Wemm { 4883c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 488440266059SGregory Neil Shapiro (void) sm_io_fputs(TrafficLogFile, 488540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 488640266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 488740266059SGregory Neil Shapiro (void) sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 488840266059SGregory Neil Shapiro mci->mci_mailer->m_eol); 488906f25ae9SGregory Neil Shapiro 489006f25ae9SGregory Neil Shapiro /* record progress for DATA timeout */ 489140266059SGregory Neil Shapiro DataProgress = true; 4892c2aa98e2SPeter Wemm } 4893c2aa98e2SPeter Wemm } 4894c2aa98e2SPeter Wemm 489540266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp)) 4896c2aa98e2SPeter Wemm { 489740266059SGregory Neil Shapiro syserr("putbody: %s/%cf%s: read error", 489840266059SGregory Neil Shapiro qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 489940266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 4900c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4901c2aa98e2SPeter Wemm } 4902c2aa98e2SPeter Wemm 4903c2aa98e2SPeter Wemm endofmessage: 490406f25ae9SGregory Neil Shapiro /* 490506f25ae9SGregory Neil Shapiro ** Since mailfile() uses e_dfp in a child process, 490606f25ae9SGregory Neil Shapiro ** the file offset in the stdio library for the 490706f25ae9SGregory Neil Shapiro ** parent process will not agree with the in-kernel 490806f25ae9SGregory Neil Shapiro ** file offset since the file descriptor is shared 490906f25ae9SGregory Neil Shapiro ** between the processes. Therefore, it is vital 491006f25ae9SGregory Neil Shapiro ** that the file always be rewound. This forces the 491106f25ae9SGregory Neil Shapiro ** kernel offset (lseek) and stdio library (ftell) 491206f25ae9SGregory Neil Shapiro ** offset to match. 491306f25ae9SGregory Neil Shapiro */ 491406f25ae9SGregory Neil Shapiro 491506f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) 491606f25ae9SGregory Neil Shapiro (void) bfrewind(e->e_dfp); 491706f25ae9SGregory Neil Shapiro 4918c2aa98e2SPeter Wemm /* some mailers want extra blank line at end of message */ 491906f25ae9SGregory Neil Shapiro if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 4920c2aa98e2SPeter Wemm buf[0] != '\0' && buf[0] != '\n') 4921c2aa98e2SPeter Wemm putline("", mci); 4922c2aa98e2SPeter Wemm 492340266059SGregory Neil Shapiro (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 492440266059SGregory Neil Shapiro if (sm_io_error(mci->mci_out) && errno != EPIPE) 4925c2aa98e2SPeter Wemm { 4926c2aa98e2SPeter Wemm syserr("putbody: write error"); 4927c2aa98e2SPeter Wemm ExitStat = EX_IOERR; 4928c2aa98e2SPeter Wemm } 492906f25ae9SGregory Neil Shapiro 4930c2aa98e2SPeter Wemm errno = 0; 4931c2aa98e2SPeter Wemm } 493240266059SGregory Neil Shapiro /* 4933c2aa98e2SPeter Wemm ** MAILFILE -- Send a message to a file. 4934c2aa98e2SPeter Wemm ** 493540266059SGregory Neil Shapiro ** If the file has the set-user-ID/set-group-ID bits set, but NO 493640266059SGregory Neil Shapiro ** execute bits, sendmail will try to become the owner of that file 4937c2aa98e2SPeter Wemm ** rather than the real user. Obviously, this only works if 4938c2aa98e2SPeter Wemm ** sendmail runs as root. 4939c2aa98e2SPeter Wemm ** 4940c2aa98e2SPeter Wemm ** This could be done as a subordinate mailer, except that it 4941c2aa98e2SPeter Wemm ** is used implicitly to save messages in ~/dead.letter. We 4942c2aa98e2SPeter Wemm ** view this as being sufficiently important as to include it 4943c2aa98e2SPeter Wemm ** here. For example, if the system is dying, we shouldn't have 4944c2aa98e2SPeter Wemm ** to create another process plus some pipes to save the message. 4945c2aa98e2SPeter Wemm ** 4946c2aa98e2SPeter Wemm ** Parameters: 4947c2aa98e2SPeter Wemm ** filename -- the name of the file to send to. 4948c2aa98e2SPeter Wemm ** mailer -- mailer definition for recipient -- if NULL, 4949c2aa98e2SPeter Wemm ** use FileMailer. 4950c2aa98e2SPeter Wemm ** ctladdr -- the controlling address header -- includes 4951c2aa98e2SPeter Wemm ** the userid/groupid to be when sending. 4952c2aa98e2SPeter Wemm ** sfflags -- flags for opening. 4953c2aa98e2SPeter Wemm ** e -- the current envelope. 4954c2aa98e2SPeter Wemm ** 4955c2aa98e2SPeter Wemm ** Returns: 4956c2aa98e2SPeter Wemm ** The exit code associated with the operation. 4957c2aa98e2SPeter Wemm ** 4958c2aa98e2SPeter Wemm ** Side Effects: 4959c2aa98e2SPeter Wemm ** none. 4960c2aa98e2SPeter Wemm */ 4961c2aa98e2SPeter Wemm 496240266059SGregory Neil Shapiro # define RETURN(st) exit(st); 496340266059SGregory Neil Shapiro 4964c2aa98e2SPeter Wemm static jmp_buf CtxMailfileTimeout; 4965c2aa98e2SPeter Wemm 4966c2aa98e2SPeter Wemm int 4967c2aa98e2SPeter Wemm mailfile(filename, mailer, ctladdr, sfflags, e) 4968c2aa98e2SPeter Wemm char *volatile filename; 4969c2aa98e2SPeter Wemm MAILER *volatile mailer; 4970c2aa98e2SPeter Wemm ADDRESS *ctladdr; 497106f25ae9SGregory Neil Shapiro volatile long sfflags; 4972c2aa98e2SPeter Wemm register ENVELOPE *e; 4973c2aa98e2SPeter Wemm { 497440266059SGregory Neil Shapiro register SM_FILE_T *f; 4975c2aa98e2SPeter Wemm register pid_t pid = -1; 497606f25ae9SGregory Neil Shapiro volatile int mode; 497706f25ae9SGregory Neil Shapiro int len; 497806f25ae9SGregory Neil Shapiro off_t curoff; 4979c2aa98e2SPeter Wemm bool suidwarn = geteuid() == 0; 4980c2aa98e2SPeter Wemm char *p; 498106f25ae9SGregory Neil Shapiro char *volatile realfile; 498240266059SGregory Neil Shapiro SM_EVENT *ev; 498394c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 498494c01205SGregory Neil Shapiro char targetfile[MAXPATHLEN]; 4985c2aa98e2SPeter Wemm 4986c2aa98e2SPeter Wemm if (tTd(11, 1)) 4987c2aa98e2SPeter Wemm { 498840266059SGregory Neil Shapiro sm_dprintf("mailfile %s\n ctladdr=", filename); 498940266059SGregory Neil Shapiro printaddr(ctladdr, false); 4990c2aa98e2SPeter Wemm } 4991c2aa98e2SPeter Wemm 4992c2aa98e2SPeter Wemm if (mailer == NULL) 4993c2aa98e2SPeter Wemm mailer = FileMailer; 4994c2aa98e2SPeter Wemm 4995c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 499640266059SGregory Neil Shapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 4997c2aa98e2SPeter Wemm 4998c2aa98e2SPeter Wemm /* 4999c2aa98e2SPeter Wemm ** Special case /dev/null. This allows us to restrict file 5000c2aa98e2SPeter Wemm ** delivery to regular files only. 5001c2aa98e2SPeter Wemm */ 5002c2aa98e2SPeter Wemm 500340266059SGregory Neil Shapiro if (sm_path_isdevnull(filename)) 5004c2aa98e2SPeter Wemm return EX_OK; 5005c2aa98e2SPeter Wemm 5006c2aa98e2SPeter Wemm /* check for 8-bit available */ 5007c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5008c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags) && 5009c2aa98e2SPeter Wemm (bitset(EF_DONT_MIME, e->e_flags) || 5010c2aa98e2SPeter Wemm !(bitset(MM_MIME8BIT, MimeMode) || 5011c2aa98e2SPeter Wemm (bitset(EF_IS_MIME, e->e_flags) && 5012c2aa98e2SPeter Wemm bitset(MM_CVTMIME, MimeMode))))) 5013c2aa98e2SPeter Wemm { 5014c2aa98e2SPeter Wemm e->e_status = "5.6.3"; 501506f25ae9SGregory Neil Shapiro usrerrenh(e->e_status, 501606f25ae9SGregory Neil Shapiro "554 Cannot send 8-bit data to 7-bit destination"); 501740266059SGregory Neil Shapiro errno = 0; 501806f25ae9SGregory Neil Shapiro return EX_DATAERR; 501906f25ae9SGregory Neil Shapiro } 502006f25ae9SGregory Neil Shapiro 502106f25ae9SGregory Neil Shapiro /* Find the actual file */ 502206f25ae9SGregory Neil Shapiro if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 502306f25ae9SGregory Neil Shapiro { 502406f25ae9SGregory Neil Shapiro len = strlen(SafeFileEnv); 502506f25ae9SGregory Neil Shapiro 502606f25ae9SGregory Neil Shapiro if (strncmp(SafeFileEnv, filename, len) == 0) 502706f25ae9SGregory Neil Shapiro filename += len; 502806f25ae9SGregory Neil Shapiro 502940266059SGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof targetfile) 503006f25ae9SGregory Neil Shapiro { 503106f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 503206f25ae9SGregory Neil Shapiro SafeFileEnv, filename); 503306f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 503406f25ae9SGregory Neil Shapiro } 503540266059SGregory Neil Shapiro (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile); 503606f25ae9SGregory Neil Shapiro realfile = targetfile + len; 503706f25ae9SGregory Neil Shapiro if (*filename == '/') 503806f25ae9SGregory Neil Shapiro filename++; 5039605302a5SGregory Neil Shapiro if (*filename != '\0') 5040605302a5SGregory Neil Shapiro { 5041605302a5SGregory Neil Shapiro /* paranoia: trailing / should be removed in readcf */ 5042605302a5SGregory Neil Shapiro if (targetfile[len - 1] != '/') 5043605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, 5044605302a5SGregory Neil Shapiro "/", sizeof targetfile); 5045605302a5SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 5046605302a5SGregory Neil Shapiro sizeof targetfile); 5047605302a5SGregory Neil Shapiro } 504806f25ae9SGregory Neil Shapiro } 504906f25ae9SGregory Neil Shapiro else if (mailer->m_rootdir != NULL) 505006f25ae9SGregory Neil Shapiro { 505106f25ae9SGregory Neil Shapiro expand(mailer->m_rootdir, targetfile, sizeof targetfile, e); 505206f25ae9SGregory Neil Shapiro len = strlen(targetfile); 505306f25ae9SGregory Neil Shapiro 505406f25ae9SGregory Neil Shapiro if (strncmp(targetfile, filename, len) == 0) 505506f25ae9SGregory Neil Shapiro filename += len; 505606f25ae9SGregory Neil Shapiro 505740266059SGregory Neil Shapiro if (len + strlen(filename) + 1 >= sizeof targetfile) 505806f25ae9SGregory Neil Shapiro { 505906f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s/%s)", 506006f25ae9SGregory Neil Shapiro targetfile, filename); 506106f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 506206f25ae9SGregory Neil Shapiro } 506306f25ae9SGregory Neil Shapiro realfile = targetfile + len; 506406f25ae9SGregory Neil Shapiro if (targetfile[len - 1] != '/') 506540266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, "/", sizeof targetfile); 506606f25ae9SGregory Neil Shapiro if (*filename == '/') 506740266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename + 1, 506806f25ae9SGregory Neil Shapiro sizeof targetfile); 506906f25ae9SGregory Neil Shapiro else 507040266059SGregory Neil Shapiro (void) sm_strlcat(targetfile, filename, 507140266059SGregory Neil Shapiro sizeof targetfile); 507206f25ae9SGregory Neil Shapiro } 507306f25ae9SGregory Neil Shapiro else 507406f25ae9SGregory Neil Shapiro { 507540266059SGregory Neil Shapiro if (sm_strlcpy(targetfile, filename, sizeof targetfile) >= 507640266059SGregory Neil Shapiro sizeof targetfile) 507706f25ae9SGregory Neil Shapiro { 507806f25ae9SGregory Neil Shapiro syserr("mailfile: filename too long (%s)", filename); 507906f25ae9SGregory Neil Shapiro return EX_CANTCREAT; 508006f25ae9SGregory Neil Shapiro } 508106f25ae9SGregory Neil Shapiro realfile = targetfile; 5082c2aa98e2SPeter Wemm } 5083c2aa98e2SPeter Wemm 5084c2aa98e2SPeter Wemm /* 5085c2aa98e2SPeter Wemm ** Fork so we can change permissions here. 5086c2aa98e2SPeter Wemm ** Note that we MUST use fork, not vfork, because of 5087c2aa98e2SPeter Wemm ** the complications of calling subroutines, etc. 5088c2aa98e2SPeter Wemm */ 5089c2aa98e2SPeter Wemm 5090605302a5SGregory Neil Shapiro 5091605302a5SGregory Neil Shapiro /* 5092605302a5SGregory Neil Shapiro ** Dispose of SIGCHLD signal catchers that may be laying 5093605302a5SGregory Neil Shapiro ** around so that the waitfor() below will get it. 5094605302a5SGregory Neil Shapiro */ 5095605302a5SGregory Neil Shapiro 5096605302a5SGregory Neil Shapiro (void) sm_signal(SIGCHLD, SIG_DFL); 5097605302a5SGregory Neil Shapiro 5098c2aa98e2SPeter Wemm DOFORK(fork); 5099c2aa98e2SPeter Wemm 5100c2aa98e2SPeter Wemm if (pid < 0) 510106f25ae9SGregory Neil Shapiro return EX_OSERR; 5102c2aa98e2SPeter Wemm else if (pid == 0) 5103c2aa98e2SPeter Wemm { 5104c2aa98e2SPeter Wemm /* child -- actually write to file */ 5105c2aa98e2SPeter Wemm struct stat stb; 5106c2aa98e2SPeter Wemm MCI mcibuf; 5107065a643dSPeter Wemm int err; 5108c2aa98e2SPeter Wemm volatile int oflags = O_WRONLY|O_APPEND; 5109c2aa98e2SPeter Wemm 51108774250cSGregory Neil Shapiro /* Reset global flags */ 51118774250cSGregory Neil Shapiro RestartRequest = NULL; 511240266059SGregory Neil Shapiro RestartWorkGroup = false; 51138774250cSGregory Neil Shapiro ShutdownRequest = NULL; 51148774250cSGregory Neil Shapiro PendingSignal = 0; 511540266059SGregory Neil Shapiro CurrentPid = getpid(); 51168774250cSGregory Neil Shapiro 5117c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 511840266059SGregory Neil Shapiro (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 511940266059SGregory Neil Shapiro NULL)); 5120c2aa98e2SPeter Wemm 512140266059SGregory Neil Shapiro (void) sm_signal(SIGINT, SIG_DFL); 512240266059SGregory Neil Shapiro (void) sm_signal(SIGHUP, SIG_DFL); 512340266059SGregory Neil Shapiro (void) sm_signal(SIGTERM, SIG_DFL); 5124c2aa98e2SPeter Wemm (void) umask(OldUmask); 5125c2aa98e2SPeter Wemm e->e_to = filename; 5126c2aa98e2SPeter Wemm ExitStat = EX_OK; 5127c2aa98e2SPeter Wemm 5128c2aa98e2SPeter Wemm if (setjmp(CtxMailfileTimeout) != 0) 5129c2aa98e2SPeter Wemm { 513040266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 5131c2aa98e2SPeter Wemm } 5132c2aa98e2SPeter Wemm 5133c2aa98e2SPeter Wemm if (TimeOuts.to_fileopen > 0) 513440266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 513540266059SGregory Neil Shapiro 0); 5136c2aa98e2SPeter Wemm else 5137c2aa98e2SPeter Wemm ev = NULL; 5138c2aa98e2SPeter Wemm 513940266059SGregory Neil Shapiro /* check file mode to see if set-user-ID */ 514006f25ae9SGregory Neil Shapiro if (stat(targetfile, &stb) < 0) 5141c2aa98e2SPeter Wemm mode = FileMode; 514206f25ae9SGregory Neil Shapiro else 5143c2aa98e2SPeter Wemm mode = stb.st_mode; 5144c2aa98e2SPeter Wemm 5145c2aa98e2SPeter Wemm /* limit the errors to those actually caused in the child */ 5146c2aa98e2SPeter Wemm errno = 0; 5147c2aa98e2SPeter Wemm ExitStat = EX_OK; 5148c2aa98e2SPeter Wemm 514906f25ae9SGregory Neil Shapiro /* Allow alias expansions to use the S_IS{U,G}ID bits */ 515006f25ae9SGregory Neil Shapiro if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 515106f25ae9SGregory Neil Shapiro bitset(SFF_RUNASREALUID, sfflags)) 5152c2aa98e2SPeter Wemm { 515340266059SGregory Neil Shapiro /* ignore set-user-ID and set-group-ID bits */ 5154c2aa98e2SPeter Wemm mode &= ~(S_ISGID|S_ISUID); 515506f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 515640266059SGregory Neil Shapiro sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 5157c2aa98e2SPeter Wemm } 5158c2aa98e2SPeter Wemm 515940266059SGregory Neil Shapiro /* we have to open the data file BEFORE setuid() */ 5160c2aa98e2SPeter Wemm if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 5161c2aa98e2SPeter Wemm { 516240266059SGregory Neil Shapiro char *df = queuename(e, DATAFL_LETTER); 5163c2aa98e2SPeter Wemm 516440266059SGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 516540266059SGregory Neil Shapiro SM_IO_RDONLY, NULL); 5166c2aa98e2SPeter Wemm if (e->e_dfp == NULL) 5167c2aa98e2SPeter Wemm { 5168c2aa98e2SPeter Wemm syserr("mailfile: Cannot open %s for %s from %s", 5169c2aa98e2SPeter Wemm df, e->e_to, e->e_from.q_paddr); 5170c2aa98e2SPeter Wemm } 5171c2aa98e2SPeter Wemm } 5172c2aa98e2SPeter Wemm 5173c2aa98e2SPeter Wemm /* select a new user to run as */ 5174c2aa98e2SPeter Wemm if (!bitset(SFF_RUNASREALUID, sfflags)) 5175c2aa98e2SPeter Wemm { 5176c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 5177c2aa98e2SPeter Wemm { 5178c2aa98e2SPeter Wemm RealUserName = NULL; 5179c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 518006f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && RealUid != RunAsUid) 518106f25ae9SGregory Neil Shapiro { 518206f25ae9SGregory Neil Shapiro /* Only root can change the uid */ 518340266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", 518440266059SGregory Neil Shapiro (int) RunAsUid, (int) RealUid); 518540266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 518606f25ae9SGregory Neil Shapiro } 5187c2aa98e2SPeter Wemm } 5188c2aa98e2SPeter Wemm else if (bitset(S_ISUID, mode)) 5189c2aa98e2SPeter Wemm { 5190c2aa98e2SPeter Wemm RealUserName = NULL; 5191c2aa98e2SPeter Wemm RealUid = stb.st_uid; 5192c2aa98e2SPeter Wemm } 5193c2aa98e2SPeter Wemm else if (ctladdr != NULL && ctladdr->q_uid != 0) 5194c2aa98e2SPeter Wemm { 5195c2aa98e2SPeter Wemm if (ctladdr->q_ruser != NULL) 5196c2aa98e2SPeter Wemm RealUserName = ctladdr->q_ruser; 5197c2aa98e2SPeter Wemm else 5198c2aa98e2SPeter Wemm RealUserName = ctladdr->q_user; 5199c2aa98e2SPeter Wemm RealUid = ctladdr->q_uid; 5200c2aa98e2SPeter Wemm } 5201c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_uid != 0) 5202c2aa98e2SPeter Wemm { 5203c2aa98e2SPeter Wemm RealUserName = DefUser; 5204c2aa98e2SPeter Wemm RealUid = mailer->m_uid; 5205c2aa98e2SPeter Wemm } 5206c2aa98e2SPeter Wemm else 5207c2aa98e2SPeter Wemm { 5208c2aa98e2SPeter Wemm RealUserName = DefUser; 5209c2aa98e2SPeter Wemm RealUid = DefUid; 5210c2aa98e2SPeter Wemm } 5211c2aa98e2SPeter Wemm 5212c2aa98e2SPeter Wemm /* select a new group to run as */ 5213c2aa98e2SPeter Wemm if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 521406f25ae9SGregory Neil Shapiro { 5215c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 521606f25ae9SGregory Neil Shapiro if (RunAsUid != 0 && 521706f25ae9SGregory Neil Shapiro (RealGid != getgid() || 521806f25ae9SGregory Neil Shapiro RealGid != getegid())) 521906f25ae9SGregory Neil Shapiro { 522006f25ae9SGregory Neil Shapiro /* Only root can change the gid */ 522140266059SGregory Neil Shapiro syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", 522240266059SGregory Neil Shapiro (int) RealGid, (int) RunAsUid, 522340266059SGregory Neil Shapiro (int) getgid(), (int) getegid()); 522440266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 522506f25ae9SGregory Neil Shapiro } 522606f25ae9SGregory Neil Shapiro } 5227c2aa98e2SPeter Wemm else if (bitset(S_ISGID, mode)) 5228c2aa98e2SPeter Wemm RealGid = stb.st_gid; 522906f25ae9SGregory Neil Shapiro else if (ctladdr != NULL && 523006f25ae9SGregory Neil Shapiro ctladdr->q_uid == DefUid && 523106f25ae9SGregory Neil Shapiro ctladdr->q_gid == 0) 5232193538b7SGregory Neil Shapiro { 5233193538b7SGregory Neil Shapiro /* 5234193538b7SGregory Neil Shapiro ** Special case: This means it is an 5235193538b7SGregory Neil Shapiro ** alias and we should act as DefaultUser. 5236193538b7SGregory Neil Shapiro ** See alias()'s comments. 5237193538b7SGregory Neil Shapiro */ 5238193538b7SGregory Neil Shapiro 523906f25ae9SGregory Neil Shapiro RealGid = DefGid; 5240193538b7SGregory Neil Shapiro RealUserName = DefUser; 5241193538b7SGregory Neil Shapiro } 5242193538b7SGregory Neil Shapiro else if (ctladdr != NULL && ctladdr->q_uid != 0) 5243193538b7SGregory Neil Shapiro RealGid = ctladdr->q_gid; 5244c2aa98e2SPeter Wemm else if (mailer != NULL && mailer->m_gid != 0) 5245c2aa98e2SPeter Wemm RealGid = mailer->m_gid; 5246c2aa98e2SPeter Wemm else 5247c2aa98e2SPeter Wemm RealGid = DefGid; 5248c2aa98e2SPeter Wemm } 5249c2aa98e2SPeter Wemm 5250c2aa98e2SPeter Wemm /* last ditch */ 5251c2aa98e2SPeter Wemm if (!bitset(SFF_ROOTOK, sfflags)) 5252c2aa98e2SPeter Wemm { 5253c2aa98e2SPeter Wemm if (RealUid == 0) 5254c2aa98e2SPeter Wemm RealUid = DefUid; 5255c2aa98e2SPeter Wemm if (RealGid == 0) 5256c2aa98e2SPeter Wemm RealGid = DefGid; 5257c2aa98e2SPeter Wemm } 5258c2aa98e2SPeter Wemm 5259c2aa98e2SPeter Wemm /* set group id list (needs /etc/group access) */ 5260c2aa98e2SPeter Wemm if (RealUserName != NULL && !DontInitGroups) 5261c2aa98e2SPeter Wemm { 5262c2aa98e2SPeter Wemm if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 526306f25ae9SGregory Neil Shapiro { 5264c2aa98e2SPeter Wemm syserr("mailfile: initgroups(%s, %d) failed", 5265c2aa98e2SPeter Wemm RealUserName, RealGid); 526640266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 526706f25ae9SGregory Neil Shapiro } 5268c2aa98e2SPeter Wemm } 5269c2aa98e2SPeter Wemm else 5270c2aa98e2SPeter Wemm { 5271c2aa98e2SPeter Wemm GIDSET_T gidset[1]; 5272c2aa98e2SPeter Wemm 5273c2aa98e2SPeter Wemm gidset[0] = RealGid; 5274c2aa98e2SPeter Wemm if (setgroups(1, gidset) == -1 && suidwarn) 527506f25ae9SGregory Neil Shapiro { 5276c2aa98e2SPeter Wemm syserr("mailfile: setgroups() failed"); 527740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 527806f25ae9SGregory Neil Shapiro } 5279c2aa98e2SPeter Wemm } 5280c2aa98e2SPeter Wemm 528106f25ae9SGregory Neil Shapiro /* 528206f25ae9SGregory Neil Shapiro ** If you have a safe environment, go into it. 528306f25ae9SGregory Neil Shapiro */ 5284c2aa98e2SPeter Wemm 528506f25ae9SGregory Neil Shapiro if (realfile != targetfile) 528606f25ae9SGregory Neil Shapiro { 5287605302a5SGregory Neil Shapiro char save; 5288605302a5SGregory Neil Shapiro 5289605302a5SGregory Neil Shapiro save = *realfile; 529006f25ae9SGregory Neil Shapiro *realfile = '\0'; 529106f25ae9SGregory Neil Shapiro if (tTd(11, 20)) 529240266059SGregory Neil Shapiro sm_dprintf("mailfile: chroot %s\n", targetfile); 529306f25ae9SGregory Neil Shapiro if (chroot(targetfile) < 0) 5294c2aa98e2SPeter Wemm { 5295c2aa98e2SPeter Wemm syserr("mailfile: Cannot chroot(%s)", 529606f25ae9SGregory Neil Shapiro targetfile); 529740266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5298c2aa98e2SPeter Wemm } 5299605302a5SGregory Neil Shapiro *realfile = save; 5300c2aa98e2SPeter Wemm } 530106f25ae9SGregory Neil Shapiro 530206f25ae9SGregory Neil Shapiro if (tTd(11, 40)) 530340266059SGregory Neil Shapiro sm_dprintf("mailfile: deliver to %s\n", realfile); 530406f25ae9SGregory Neil Shapiro 5305c2aa98e2SPeter Wemm if (chdir("/") < 0) 530606f25ae9SGregory Neil Shapiro { 5307c2aa98e2SPeter Wemm syserr("mailfile: cannot chdir(/)"); 530840266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 530906f25ae9SGregory Neil Shapiro } 5310c2aa98e2SPeter Wemm 5311c2aa98e2SPeter Wemm /* now reset the group and user ids */ 5312c2aa98e2SPeter Wemm endpwent(); 531340266059SGregory Neil Shapiro sm_mbdb_terminate(); 5314c2aa98e2SPeter Wemm if (setgid(RealGid) < 0 && suidwarn) 531506f25ae9SGregory Neil Shapiro { 5316c2aa98e2SPeter Wemm syserr("mailfile: setgid(%ld) failed", (long) RealGid); 531740266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 531806f25ae9SGregory Neil Shapiro } 5319c2aa98e2SPeter Wemm vendor_set_uid(RealUid); 5320c2aa98e2SPeter Wemm if (setuid(RealUid) < 0 && suidwarn) 532106f25ae9SGregory Neil Shapiro { 5322c2aa98e2SPeter Wemm syserr("mailfile: setuid(%ld) failed", (long) RealUid); 532340266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 532406f25ae9SGregory Neil Shapiro } 532506f25ae9SGregory Neil Shapiro 532606f25ae9SGregory Neil Shapiro if (tTd(11, 2)) 532740266059SGregory Neil Shapiro sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 532806f25ae9SGregory Neil Shapiro (int) getuid(), (int) geteuid(), 532906f25ae9SGregory Neil Shapiro (int) getgid(), (int) getegid()); 533006f25ae9SGregory Neil Shapiro 5331c2aa98e2SPeter Wemm 5332c2aa98e2SPeter Wemm /* move into some "safe" directory */ 5333c2aa98e2SPeter Wemm if (mailer->m_execdir != NULL) 5334c2aa98e2SPeter Wemm { 5335c2aa98e2SPeter Wemm char *q; 5336c2aa98e2SPeter Wemm 5337c2aa98e2SPeter Wemm for (p = mailer->m_execdir; p != NULL; p = q) 5338c2aa98e2SPeter Wemm { 5339c2aa98e2SPeter Wemm q = strchr(p, ':'); 5340c2aa98e2SPeter Wemm if (q != NULL) 5341c2aa98e2SPeter Wemm *q = '\0'; 5342c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 5343c2aa98e2SPeter Wemm if (q != NULL) 5344c2aa98e2SPeter Wemm *q++ = ':'; 5345c2aa98e2SPeter Wemm if (tTd(11, 20)) 534640266059SGregory Neil Shapiro sm_dprintf("mailfile: trydir %s\n", 534740266059SGregory Neil Shapiro buf); 5348c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 5349c2aa98e2SPeter Wemm break; 5350c2aa98e2SPeter Wemm } 5351c2aa98e2SPeter Wemm } 5352c2aa98e2SPeter Wemm 535306f25ae9SGregory Neil Shapiro /* 535406f25ae9SGregory Neil Shapiro ** Recheck the file after we have assumed the ID of the 535506f25ae9SGregory Neil Shapiro ** delivery user to make sure we can deliver to it as 535606f25ae9SGregory Neil Shapiro ** that user. This is necessary if sendmail is running 535706f25ae9SGregory Neil Shapiro ** as root and the file is on an NFS mount which treats 535806f25ae9SGregory Neil Shapiro ** root as nobody. 535906f25ae9SGregory Neil Shapiro */ 536006f25ae9SGregory Neil Shapiro 536106f25ae9SGregory Neil Shapiro #if HASLSTAT 536206f25ae9SGregory Neil Shapiro if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 536306f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 536406f25ae9SGregory Neil Shapiro else 536506f25ae9SGregory Neil Shapiro err = lstat(realfile, &stb); 536606f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 536706f25ae9SGregory Neil Shapiro err = stat(realfile, &stb); 536806f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 536906f25ae9SGregory Neil Shapiro 537006f25ae9SGregory Neil Shapiro if (err < 0) 537106f25ae9SGregory Neil Shapiro { 537206f25ae9SGregory Neil Shapiro stb.st_mode = ST_MODE_NOFILE; 537306f25ae9SGregory Neil Shapiro mode = FileMode; 537406f25ae9SGregory Neil Shapiro oflags |= O_CREAT|O_EXCL; 537506f25ae9SGregory Neil Shapiro } 537606f25ae9SGregory Neil Shapiro else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 537706f25ae9SGregory Neil Shapiro (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 537806f25ae9SGregory Neil Shapiro DontBlameSendmail) && 537906f25ae9SGregory Neil Shapiro stb.st_nlink != 1) || 538006f25ae9SGregory Neil Shapiro (realfile != targetfile && !S_ISREG(mode))) 538106f25ae9SGregory Neil Shapiro exit(EX_CANTCREAT); 538206f25ae9SGregory Neil Shapiro else 538306f25ae9SGregory Neil Shapiro mode = stb.st_mode; 538406f25ae9SGregory Neil Shapiro 538506f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 5386c2aa98e2SPeter Wemm sfflags |= SFF_NOSLINK; 538706f25ae9SGregory Neil Shapiro if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 5388c2aa98e2SPeter Wemm sfflags |= SFF_NOHLINK; 5389c2aa98e2SPeter Wemm sfflags &= ~SFF_OPENASROOT; 539006f25ae9SGregory Neil Shapiro f = safefopen(realfile, oflags, mode, sfflags); 5391c2aa98e2SPeter Wemm if (f == NULL) 5392c2aa98e2SPeter Wemm { 539306f25ae9SGregory Neil Shapiro if (transienterror(errno)) 539406f25ae9SGregory Neil Shapiro { 539506f25ae9SGregory Neil Shapiro usrerr("454 4.3.0 cannot open %s: %s", 539606f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 539740266059SGregory Neil Shapiro sm_errstring(errno)); 539840266059SGregory Neil Shapiro RETURN(EX_TEMPFAIL); 539906f25ae9SGregory Neil Shapiro } 540006f25ae9SGregory Neil Shapiro else 540106f25ae9SGregory Neil Shapiro { 540206f25ae9SGregory Neil Shapiro usrerr("554 5.3.0 cannot open %s: %s", 540306f25ae9SGregory Neil Shapiro shortenstring(realfile, MAXSHORTSTR), 540440266059SGregory Neil Shapiro sm_errstring(errno)); 540540266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5406c2aa98e2SPeter Wemm } 540706f25ae9SGregory Neil Shapiro } 540840266059SGregory Neil Shapiro if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 540940266059SGregory Neil Shapiro &stb)) 5410c2aa98e2SPeter Wemm { 541106f25ae9SGregory Neil Shapiro syserr("554 5.3.0 file changed after open"); 541240266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5413c2aa98e2SPeter Wemm } 541440266059SGregory Neil Shapiro if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 5415c2aa98e2SPeter Wemm { 541640266059SGregory Neil Shapiro syserr("554 5.3.0 cannot fstat %s", 541740266059SGregory Neil Shapiro sm_errstring(errno)); 541840266059SGregory Neil Shapiro RETURN(EX_CANTCREAT); 5419c2aa98e2SPeter Wemm } 5420c2aa98e2SPeter Wemm 542106f25ae9SGregory Neil Shapiro curoff = stb.st_size; 542206f25ae9SGregory Neil Shapiro 5423c2aa98e2SPeter Wemm if (ev != NULL) 542440266059SGregory Neil Shapiro sm_clrevent(ev); 5425c2aa98e2SPeter Wemm 542606f25ae9SGregory Neil Shapiro memset(&mcibuf, '\0', sizeof mcibuf); 5427c2aa98e2SPeter Wemm mcibuf.mci_mailer = mailer; 5428c2aa98e2SPeter Wemm mcibuf.mci_out = f; 5429c2aa98e2SPeter Wemm if (bitnset(M_7BITS, mailer->m_flags)) 5430c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_7BIT; 5431c2aa98e2SPeter Wemm 5432c2aa98e2SPeter Wemm /* clear out per-message flags from connection structure */ 5433c2aa98e2SPeter Wemm mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 5434c2aa98e2SPeter Wemm 5435c2aa98e2SPeter Wemm if (bitset(EF_HAS8BIT, e->e_flags) && 5436c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 5437c2aa98e2SPeter Wemm bitnset(M_7BITS, mailer->m_flags)) 5438c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT8TO7; 5439c2aa98e2SPeter Wemm 5440c2aa98e2SPeter Wemm #if MIME7TO8 5441c2aa98e2SPeter Wemm if (bitnset(M_MAKE8BIT, mailer->m_flags) && 5442c2aa98e2SPeter Wemm !bitset(MCIF_7BIT, mcibuf.mci_flags) && 5443c2aa98e2SPeter Wemm (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 544440266059SGregory Neil Shapiro (sm_strcasecmp(p, "quoted-printable") == 0 || 544540266059SGregory Neil Shapiro sm_strcasecmp(p, "base64") == 0) && 5446c2aa98e2SPeter Wemm (p = hvalue("Content-Type", e->e_header)) != NULL) 5447c2aa98e2SPeter Wemm { 5448c2aa98e2SPeter Wemm /* may want to convert 7 -> 8 */ 5449c2aa98e2SPeter Wemm /* XXX should really parse it here -- and use a class XXX */ 545040266059SGregory Neil Shapiro if (sm_strncasecmp(p, "text/plain", 10) == 0 && 5451c2aa98e2SPeter Wemm (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 5452c2aa98e2SPeter Wemm mcibuf.mci_flags |= MCIF_CVT7TO8; 5453c2aa98e2SPeter Wemm } 545406f25ae9SGregory Neil Shapiro #endif /* MIME7TO8 */ 5455c2aa98e2SPeter Wemm 5456c2aa98e2SPeter Wemm putfromline(&mcibuf, e); 54572e43090eSPeter Wemm (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER); 5458c2aa98e2SPeter Wemm (*e->e_putbody)(&mcibuf, e, NULL); 5459c2aa98e2SPeter Wemm putline("\n", &mcibuf); 546040266059SGregory Neil Shapiro if (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 546140266059SGregory Neil Shapiro (SuperSafe != SAFE_NO && 546240266059SGregory Neil Shapiro fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 546340266059SGregory Neil Shapiro sm_io_error(f)) 5464c2aa98e2SPeter Wemm { 5465c2aa98e2SPeter Wemm setstat(EX_IOERR); 546606f25ae9SGregory Neil Shapiro #if !NOFTRUNCATE 546740266059SGregory Neil Shapiro (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 546840266059SGregory Neil Shapiro curoff); 546906f25ae9SGregory Neil Shapiro #endif /* !NOFTRUNCATE */ 5470c2aa98e2SPeter Wemm } 5471c2aa98e2SPeter Wemm 5472c2aa98e2SPeter Wemm /* reset ISUID & ISGID bits for paranoid systems */ 5473c2aa98e2SPeter Wemm #if HASFCHMOD 547440266059SGregory Neil Shapiro (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 547540266059SGregory Neil Shapiro (MODE_T) mode); 547606f25ae9SGregory Neil Shapiro #else /* HASFCHMOD */ 547706f25ae9SGregory Neil Shapiro (void) chmod(filename, (MODE_T) mode); 547806f25ae9SGregory Neil Shapiro #endif /* HASFCHMOD */ 547940266059SGregory Neil Shapiro if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 548006f25ae9SGregory Neil Shapiro setstat(EX_IOERR); 548140266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 548206f25ae9SGregory Neil Shapiro (void) setuid(RealUid); 5483c2aa98e2SPeter Wemm exit(ExitStat); 5484c2aa98e2SPeter Wemm /* NOTREACHED */ 5485c2aa98e2SPeter Wemm } 5486c2aa98e2SPeter Wemm else 5487c2aa98e2SPeter Wemm { 5488c2aa98e2SPeter Wemm /* parent -- wait for exit status */ 5489c2aa98e2SPeter Wemm int st; 5490c2aa98e2SPeter Wemm 5491c2aa98e2SPeter Wemm st = waitfor(pid); 5492c2aa98e2SPeter Wemm if (st == -1) 5493c2aa98e2SPeter Wemm { 5494c2aa98e2SPeter Wemm syserr("mailfile: %s: wait", mailer->m_name); 549506f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 5496c2aa98e2SPeter Wemm } 5497c2aa98e2SPeter Wemm if (WIFEXITED(st)) 549840266059SGregory Neil Shapiro { 549940266059SGregory Neil Shapiro errno = 0; 5500c2aa98e2SPeter Wemm return (WEXITSTATUS(st)); 550140266059SGregory Neil Shapiro } 5502c2aa98e2SPeter Wemm else 5503c2aa98e2SPeter Wemm { 5504c2aa98e2SPeter Wemm syserr("mailfile: %s: child died on signal %d", 5505c2aa98e2SPeter Wemm mailer->m_name, st); 550606f25ae9SGregory Neil Shapiro return EX_UNAVAILABLE; 5507c2aa98e2SPeter Wemm } 5508c2aa98e2SPeter Wemm /* NOTREACHED */ 5509c2aa98e2SPeter Wemm } 5510c2aa98e2SPeter Wemm return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 5511c2aa98e2SPeter Wemm } 5512c2aa98e2SPeter Wemm 5513c2aa98e2SPeter Wemm static void 5514c2aa98e2SPeter Wemm mailfiletimeout() 5515c2aa98e2SPeter Wemm { 55168774250cSGregory Neil Shapiro /* 55178774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 55188774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 55198774250cSGregory Neil Shapiro ** DOING. 55208774250cSGregory Neil Shapiro */ 55218774250cSGregory Neil Shapiro 55228774250cSGregory Neil Shapiro errno = ETIMEDOUT; 5523c2aa98e2SPeter Wemm longjmp(CtxMailfileTimeout, 1); 5524c2aa98e2SPeter Wemm } 552540266059SGregory Neil Shapiro /* 5526c2aa98e2SPeter Wemm ** HOSTSIGNATURE -- return the "signature" for a host. 5527c2aa98e2SPeter Wemm ** 5528c2aa98e2SPeter Wemm ** The signature describes how we are going to send this -- it 5529c2aa98e2SPeter Wemm ** can be just the hostname (for non-Internet hosts) or can be 5530c2aa98e2SPeter Wemm ** an ordered list of MX hosts. 5531c2aa98e2SPeter Wemm ** 5532c2aa98e2SPeter Wemm ** Parameters: 5533c2aa98e2SPeter Wemm ** m -- the mailer describing this host. 5534c2aa98e2SPeter Wemm ** host -- the host name. 5535c2aa98e2SPeter Wemm ** 5536c2aa98e2SPeter Wemm ** Returns: 5537c2aa98e2SPeter Wemm ** The signature for this host. 5538c2aa98e2SPeter Wemm ** 5539c2aa98e2SPeter Wemm ** Side Effects: 5540c2aa98e2SPeter Wemm ** Can tweak the symbol table. 5541c2aa98e2SPeter Wemm */ 554240266059SGregory Neil Shapiro 554306f25ae9SGregory Neil Shapiro #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 5544c2aa98e2SPeter Wemm 554540266059SGregory Neil Shapiro char * 554606f25ae9SGregory Neil Shapiro hostsignature(m, host) 5547c2aa98e2SPeter Wemm register MAILER *m; 5548c2aa98e2SPeter Wemm char *host; 5549c2aa98e2SPeter Wemm { 5550c2aa98e2SPeter Wemm register char *p; 5551c2aa98e2SPeter Wemm register STAB *s; 555240266059SGregory Neil Shapiro time_t now; 555306f25ae9SGregory Neil Shapiro #if NAMED_BIND 555406f25ae9SGregory Neil Shapiro char sep = ':'; 555506f25ae9SGregory Neil Shapiro char prevsep = ':'; 5556c2aa98e2SPeter Wemm int i; 5557c2aa98e2SPeter Wemm int len; 5558c2aa98e2SPeter Wemm int nmx; 555906f25ae9SGregory Neil Shapiro int hl; 5560c2aa98e2SPeter Wemm char *hp; 5561c2aa98e2SPeter Wemm char *endp; 5562c2aa98e2SPeter Wemm int oldoptions = _res.options; 5563c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 556440266059SGregory Neil Shapiro unsigned short mxprefs[MAXMXHOSTS + 1]; 556506f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 556606f25ae9SGregory Neil Shapiro 556706f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 556840266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s)\n", host); 556906f25ae9SGregory Neil Shapiro 557006f25ae9SGregory Neil Shapiro /* 55718774250cSGregory Neil Shapiro ** If local delivery (and not remote), just return a constant. 557206f25ae9SGregory Neil Shapiro */ 557306f25ae9SGregory Neil Shapiro 55748774250cSGregory Neil Shapiro if (bitnset(M_LOCALMAILER, m->m_flags) && 557540266059SGregory Neil Shapiro strcmp(m->m_mailer, "[IPC]") != 0 && 557640266059SGregory Neil Shapiro !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 557706f25ae9SGregory Neil Shapiro return "localhost"; 5578c2aa98e2SPeter Wemm 5579c2aa98e2SPeter Wemm /* 5580c2aa98e2SPeter Wemm ** Check to see if this uses IPC -- if not, it can't have MX records. 5581c2aa98e2SPeter Wemm */ 5582c2aa98e2SPeter Wemm 558340266059SGregory Neil Shapiro if (strcmp(m->m_mailer, "[IPC]") != 0 || 558440266059SGregory Neil Shapiro CurEnv->e_sendmode == SM_DEFER) 5585c2aa98e2SPeter Wemm { 558640266059SGregory Neil Shapiro /* just an ordinary mailer or deferred mode */ 5587c2aa98e2SPeter Wemm return host; 5588c2aa98e2SPeter Wemm } 558906f25ae9SGregory Neil Shapiro #if NETUNIX 559006f25ae9SGregory Neil Shapiro else if (m->m_argv[0] != NULL && 559106f25ae9SGregory Neil Shapiro strcmp(m->m_argv[0], "FILE") == 0) 559206f25ae9SGregory Neil Shapiro { 559306f25ae9SGregory Neil Shapiro /* rendezvous in the file system, no MX records */ 559406f25ae9SGregory Neil Shapiro return host; 559506f25ae9SGregory Neil Shapiro } 559606f25ae9SGregory Neil Shapiro #endif /* NETUNIX */ 5597c2aa98e2SPeter Wemm 5598c2aa98e2SPeter Wemm /* 5599c2aa98e2SPeter Wemm ** Look it up in the symbol table. 5600c2aa98e2SPeter Wemm */ 5601c2aa98e2SPeter Wemm 560240266059SGregory Neil Shapiro now = curtime(); 5603c2aa98e2SPeter Wemm s = stab(host, ST_HOSTSIG, ST_ENTER); 560440266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 560540266059SGregory Neil Shapiro { 560640266059SGregory Neil Shapiro if (s->s_hostsig.hs_exp >= now) 560706f25ae9SGregory Neil Shapiro { 560806f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 560940266059SGregory Neil Shapiro sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 561040266059SGregory Neil Shapiro s->s_hostsig.hs_sig); 561140266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 561206f25ae9SGregory Neil Shapiro } 5613c2aa98e2SPeter Wemm 561440266059SGregory Neil Shapiro /* signature is expired: clear it */ 561540266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); 561640266059SGregory Neil Shapiro s->s_hostsig.hs_sig = NULL; 561740266059SGregory Neil Shapiro } 561840266059SGregory Neil Shapiro 561940266059SGregory Neil Shapiro /* set default TTL */ 562040266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 562140266059SGregory Neil Shapiro 5622c2aa98e2SPeter Wemm /* 562340266059SGregory Neil Shapiro ** Not already there or expired -- create a signature. 5624c2aa98e2SPeter Wemm */ 5625c2aa98e2SPeter Wemm 5626c2aa98e2SPeter Wemm #if NAMED_BIND 5627c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5628c2aa98e2SPeter Wemm _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 5629c2aa98e2SPeter Wemm 5630c2aa98e2SPeter Wemm for (hp = host; hp != NULL; hp = endp) 5631c2aa98e2SPeter Wemm { 563206f25ae9SGregory Neil Shapiro #if NETINET6 563306f25ae9SGregory Neil Shapiro if (*hp == '[') 563406f25ae9SGregory Neil Shapiro { 563506f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 5636c2aa98e2SPeter Wemm if (endp != NULL) 563706f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 563806f25ae9SGregory Neil Shapiro } 563906f25ae9SGregory Neil Shapiro else 564006f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 564106f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 564206f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 564306f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 564406f25ae9SGregory Neil Shapiro if (endp != NULL) 564506f25ae9SGregory Neil Shapiro { 564606f25ae9SGregory Neil Shapiro sep = *endp; 5647c2aa98e2SPeter Wemm *endp = '\0'; 564806f25ae9SGregory Neil Shapiro } 5649c2aa98e2SPeter Wemm 5650c2aa98e2SPeter Wemm if (bitnset(M_NOMX, m->m_flags)) 5651c2aa98e2SPeter Wemm { 5652c2aa98e2SPeter Wemm /* skip MX lookups */ 5653c2aa98e2SPeter Wemm nmx = 1; 5654c2aa98e2SPeter Wemm mxhosts[0] = hp; 5655c2aa98e2SPeter Wemm } 5656c2aa98e2SPeter Wemm else 5657c2aa98e2SPeter Wemm { 5658c2aa98e2SPeter Wemm auto int rcode; 565940266059SGregory Neil Shapiro int ttl; 5660c2aa98e2SPeter Wemm 566140266059SGregory Neil Shapiro nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true, 566240266059SGregory Neil Shapiro &ttl); 5663c2aa98e2SPeter Wemm if (nmx <= 0) 5664c2aa98e2SPeter Wemm { 566513058a91SGregory Neil Shapiro int save_errno; 5666c2aa98e2SPeter Wemm register MCI *mci; 5667c2aa98e2SPeter Wemm 5668c2aa98e2SPeter Wemm /* update the connection info for this host */ 566913058a91SGregory Neil Shapiro save_errno = errno; 5670c2aa98e2SPeter Wemm mci = mci_get(hp, m); 567113058a91SGregory Neil Shapiro mci->mci_errno = save_errno; 5672c2aa98e2SPeter Wemm mci->mci_herrno = h_errno; 5673193538b7SGregory Neil Shapiro mci->mci_lastuse = now; 567406f25ae9SGregory Neil Shapiro if (rcode == EX_NOHOST) 567506f25ae9SGregory Neil Shapiro mci_setstat(mci, rcode, "5.1.2", 567606f25ae9SGregory Neil Shapiro "550 Host unknown"); 567706f25ae9SGregory Neil Shapiro else 5678c2aa98e2SPeter Wemm mci_setstat(mci, rcode, NULL, NULL); 5679c2aa98e2SPeter Wemm 5680c2aa98e2SPeter Wemm /* use the original host name as signature */ 5681c2aa98e2SPeter Wemm nmx = 1; 5682c2aa98e2SPeter Wemm mxhosts[0] = hp; 5683c2aa98e2SPeter Wemm } 568406f25ae9SGregory Neil Shapiro if (tTd(17, 3)) 568540266059SGregory Neil Shapiro sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 568606f25ae9SGregory Neil Shapiro nmx, mxhosts[0]); 568740266059SGregory Neil Shapiro 568840266059SGregory Neil Shapiro /* 568940266059SGregory Neil Shapiro ** Set new TTL: we use only one! 569040266059SGregory Neil Shapiro ** We could try to use the minimum instead. 569140266059SGregory Neil Shapiro */ 569240266059SGregory Neil Shapiro 569340266059SGregory Neil Shapiro s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 5694c2aa98e2SPeter Wemm } 5695c2aa98e2SPeter Wemm 5696c2aa98e2SPeter Wemm len = 0; 5697c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5698c2aa98e2SPeter Wemm len += strlen(mxhosts[i]) + 1; 569940266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 570040266059SGregory Neil Shapiro len += strlen(s->s_hostsig.hs_sig) + 1; 570140266059SGregory Neil Shapiro if (len < 0 || len >= MAXHOSTSIGNATURE) 570206f25ae9SGregory Neil Shapiro { 570306f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 570406f25ae9SGregory Neil Shapiro host, MAXHOSTSIGNATURE, len); 570506f25ae9SGregory Neil Shapiro len = MAXHOSTSIGNATURE; 570606f25ae9SGregory Neil Shapiro } 570740266059SGregory Neil Shapiro p = sm_pmalloc_x(len); 570840266059SGregory Neil Shapiro if (s->s_hostsig.hs_sig != NULL) 5709c2aa98e2SPeter Wemm { 571040266059SGregory Neil Shapiro (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 571140266059SGregory Neil Shapiro sm_free(s->s_hostsig.hs_sig); /* XXX */ 571240266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 571306f25ae9SGregory Neil Shapiro hl = strlen(p); 571406f25ae9SGregory Neil Shapiro p += hl; 571506f25ae9SGregory Neil Shapiro *p++ = prevsep; 571606f25ae9SGregory Neil Shapiro len -= hl + 1; 5717c2aa98e2SPeter Wemm } 5718c2aa98e2SPeter Wemm else 571940266059SGregory Neil Shapiro s->s_hostsig.hs_sig = p; 5720c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 5721c2aa98e2SPeter Wemm { 572206f25ae9SGregory Neil Shapiro hl = strlen(mxhosts[i]); 572306f25ae9SGregory Neil Shapiro if (len - 1 < hl || len <= 1) 572406f25ae9SGregory Neil Shapiro { 572506f25ae9SGregory Neil Shapiro /* force to drop out of outer loop */ 572606f25ae9SGregory Neil Shapiro len = -1; 572706f25ae9SGregory Neil Shapiro break; 5728c2aa98e2SPeter Wemm } 572906f25ae9SGregory Neil Shapiro if (i != 0) 573006f25ae9SGregory Neil Shapiro { 573106f25ae9SGregory Neil Shapiro if (mxprefs[i] == mxprefs[i - 1]) 573206f25ae9SGregory Neil Shapiro *p++ = ','; 573306f25ae9SGregory Neil Shapiro else 573406f25ae9SGregory Neil Shapiro *p++ = ':'; 573506f25ae9SGregory Neil Shapiro len--; 573606f25ae9SGregory Neil Shapiro } 573740266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], len); 573806f25ae9SGregory Neil Shapiro p += hl; 573906f25ae9SGregory Neil Shapiro len -= hl; 574006f25ae9SGregory Neil Shapiro } 574106f25ae9SGregory Neil Shapiro 574206f25ae9SGregory Neil Shapiro /* 574306f25ae9SGregory Neil Shapiro ** break out of loop if len exceeded MAXHOSTSIGNATURE 574406f25ae9SGregory Neil Shapiro ** because we won't have more space for further hosts 574506f25ae9SGregory Neil Shapiro ** anyway (separated by : in the .cf file). 574606f25ae9SGregory Neil Shapiro */ 574706f25ae9SGregory Neil Shapiro 574806f25ae9SGregory Neil Shapiro if (len < 0) 574906f25ae9SGregory Neil Shapiro break; 5750c2aa98e2SPeter Wemm if (endp != NULL) 575106f25ae9SGregory Neil Shapiro *endp++ = sep; 575206f25ae9SGregory Neil Shapiro prevsep = sep; 5753c2aa98e2SPeter Wemm } 575440266059SGregory Neil Shapiro makelower(s->s_hostsig.hs_sig); 5755c2aa98e2SPeter Wemm if (ConfigLevel < 2) 5756c2aa98e2SPeter Wemm _res.options = oldoptions; 575706f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 5758c2aa98e2SPeter Wemm /* not using BIND -- the signature is just the host name */ 575940266059SGregory Neil Shapiro /* 576040266059SGregory Neil Shapiro ** 'host' points to storage that will be freed after we are 576140266059SGregory Neil Shapiro ** done processing the current envelope, so we copy it. 576240266059SGregory Neil Shapiro */ 576340266059SGregory Neil Shapiro s->s_hostsig.hs_sig = sm_pstrdup_x(host); 576406f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 5765c2aa98e2SPeter Wemm if (tTd(17, 1)) 576640266059SGregory Neil Shapiro sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 576740266059SGregory Neil Shapiro return s->s_hostsig.hs_sig; 5768c2aa98e2SPeter Wemm } 576940266059SGregory Neil Shapiro /* 577006f25ae9SGregory Neil Shapiro ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 577106f25ae9SGregory Neil Shapiro ** 577206f25ae9SGregory Neil Shapiro ** The signature describes how we are going to send this -- it 577306f25ae9SGregory Neil Shapiro ** can be just the hostname (for non-Internet hosts) or can be 577406f25ae9SGregory Neil Shapiro ** an ordered list of MX hosts which must be randomized for equal 577506f25ae9SGregory Neil Shapiro ** MX preference values. 577606f25ae9SGregory Neil Shapiro ** 577706f25ae9SGregory Neil Shapiro ** Parameters: 577806f25ae9SGregory Neil Shapiro ** sig -- the host signature. 577906f25ae9SGregory Neil Shapiro ** mxhosts -- array to populate. 578040266059SGregory Neil Shapiro ** mailer -- mailer. 578106f25ae9SGregory Neil Shapiro ** 578206f25ae9SGregory Neil Shapiro ** Returns: 578306f25ae9SGregory Neil Shapiro ** The number of hosts inserted into mxhosts array. 578406f25ae9SGregory Neil Shapiro ** 578506f25ae9SGregory Neil Shapiro ** Side Effects: 578606f25ae9SGregory Neil Shapiro ** Randomizes equal MX preference hosts in mxhosts. 578706f25ae9SGregory Neil Shapiro */ 578806f25ae9SGregory Neil Shapiro 578906f25ae9SGregory Neil Shapiro static int 579006f25ae9SGregory Neil Shapiro parse_hostsignature(sig, mxhosts, mailer) 579106f25ae9SGregory Neil Shapiro char *sig; 579206f25ae9SGregory Neil Shapiro char **mxhosts; 579306f25ae9SGregory Neil Shapiro MAILER *mailer; 579406f25ae9SGregory Neil Shapiro { 579540266059SGregory Neil Shapiro unsigned short curpref = 0; 579640266059SGregory Neil Shapiro int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 579706f25ae9SGregory Neil Shapiro char *hp, *endp; 579840266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 579906f25ae9SGregory Neil Shapiro long rndm[MAXMXHOSTS]; 580006f25ae9SGregory Neil Shapiro 580106f25ae9SGregory Neil Shapiro for (hp = sig; hp != NULL; hp = endp) 580206f25ae9SGregory Neil Shapiro { 580306f25ae9SGregory Neil Shapiro char sep = ':'; 580406f25ae9SGregory Neil Shapiro 580506f25ae9SGregory Neil Shapiro #if NETINET6 580606f25ae9SGregory Neil Shapiro if (*hp == '[') 580706f25ae9SGregory Neil Shapiro { 580806f25ae9SGregory Neil Shapiro endp = strchr(hp + 1, ']'); 580906f25ae9SGregory Neil Shapiro if (endp != NULL) 581006f25ae9SGregory Neil Shapiro endp = strpbrk(endp + 1, ":,"); 581106f25ae9SGregory Neil Shapiro } 581206f25ae9SGregory Neil Shapiro else 581306f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 581406f25ae9SGregory Neil Shapiro #else /* NETINET6 */ 581506f25ae9SGregory Neil Shapiro endp = strpbrk(hp, ":,"); 581606f25ae9SGregory Neil Shapiro #endif /* NETINET6 */ 581706f25ae9SGregory Neil Shapiro if (endp != NULL) 581806f25ae9SGregory Neil Shapiro { 581906f25ae9SGregory Neil Shapiro sep = *endp; 582006f25ae9SGregory Neil Shapiro *endp = '\0'; 582106f25ae9SGregory Neil Shapiro } 582206f25ae9SGregory Neil Shapiro 582306f25ae9SGregory Neil Shapiro mxhosts[nmx] = hp; 582406f25ae9SGregory Neil Shapiro prefer[nmx] = curpref; 582506f25ae9SGregory Neil Shapiro if (mci_match(hp, mailer)) 582606f25ae9SGregory Neil Shapiro rndm[nmx] = 0; 582706f25ae9SGregory Neil Shapiro else 582806f25ae9SGregory Neil Shapiro rndm[nmx] = get_random(); 582906f25ae9SGregory Neil Shapiro 583006f25ae9SGregory Neil Shapiro if (endp != NULL) 583106f25ae9SGregory Neil Shapiro { 583206f25ae9SGregory Neil Shapiro /* 583306f25ae9SGregory Neil Shapiro ** Since we don't have the original MX prefs, 583406f25ae9SGregory Neil Shapiro ** make our own. If the separator is a ':', that 583506f25ae9SGregory Neil Shapiro ** means the preference for the next host will be 583606f25ae9SGregory Neil Shapiro ** higher than this one, so simply increment curpref. 583706f25ae9SGregory Neil Shapiro */ 583806f25ae9SGregory Neil Shapiro 583906f25ae9SGregory Neil Shapiro if (sep == ':') 584006f25ae9SGregory Neil Shapiro curpref++; 584106f25ae9SGregory Neil Shapiro 584206f25ae9SGregory Neil Shapiro *endp++ = sep; 584306f25ae9SGregory Neil Shapiro } 584406f25ae9SGregory Neil Shapiro if (++nmx >= MAXMXHOSTS) 584506f25ae9SGregory Neil Shapiro break; 584606f25ae9SGregory Neil Shapiro } 584706f25ae9SGregory Neil Shapiro 584806f25ae9SGregory Neil Shapiro /* sort the records using the random factor for equal preferences */ 584906f25ae9SGregory Neil Shapiro for (i = 0; i < nmx; i++) 585006f25ae9SGregory Neil Shapiro { 585106f25ae9SGregory Neil Shapiro for (j = i + 1; j < nmx; j++) 585206f25ae9SGregory Neil Shapiro { 585306f25ae9SGregory Neil Shapiro /* 585406f25ae9SGregory Neil Shapiro ** List is already sorted by MX preference, only 585506f25ae9SGregory Neil Shapiro ** need to look for equal preference MX records 585606f25ae9SGregory Neil Shapiro */ 585706f25ae9SGregory Neil Shapiro 585806f25ae9SGregory Neil Shapiro if (prefer[i] < prefer[j]) 585906f25ae9SGregory Neil Shapiro break; 586006f25ae9SGregory Neil Shapiro 586106f25ae9SGregory Neil Shapiro if (prefer[i] > prefer[j] || 586206f25ae9SGregory Neil Shapiro (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 586306f25ae9SGregory Neil Shapiro { 586440266059SGregory Neil Shapiro register unsigned short tempp; 586506f25ae9SGregory Neil Shapiro register long tempr; 586606f25ae9SGregory Neil Shapiro register char *temp1; 586706f25ae9SGregory Neil Shapiro 586806f25ae9SGregory Neil Shapiro tempp = prefer[i]; 586906f25ae9SGregory Neil Shapiro prefer[i] = prefer[j]; 587006f25ae9SGregory Neil Shapiro prefer[j] = tempp; 587106f25ae9SGregory Neil Shapiro temp1 = mxhosts[i]; 587206f25ae9SGregory Neil Shapiro mxhosts[i] = mxhosts[j]; 587306f25ae9SGregory Neil Shapiro mxhosts[j] = temp1; 587406f25ae9SGregory Neil Shapiro tempr = rndm[i]; 587506f25ae9SGregory Neil Shapiro rndm[i] = rndm[j]; 587606f25ae9SGregory Neil Shapiro rndm[j] = tempr; 587706f25ae9SGregory Neil Shapiro } 587806f25ae9SGregory Neil Shapiro } 587906f25ae9SGregory Neil Shapiro } 588006f25ae9SGregory Neil Shapiro return nmx; 588106f25ae9SGregory Neil Shapiro } 588206f25ae9SGregory Neil Shapiro 588306f25ae9SGregory Neil Shapiro # if STARTTLS 588406f25ae9SGregory Neil Shapiro static SSL_CTX *clt_ctx = NULL; 588540266059SGregory Neil Shapiro static bool tls_ok_clt = true; 588606f25ae9SGregory Neil Shapiro 588740266059SGregory Neil Shapiro /* 588840266059SGregory Neil Shapiro ** SETCLTTLS -- client side TLS: allow/disallow. 588940266059SGregory Neil Shapiro ** 589040266059SGregory Neil Shapiro ** Parameters: 589140266059SGregory Neil Shapiro ** tls_ok -- should tls be done? 589240266059SGregory Neil Shapiro ** 589340266059SGregory Neil Shapiro ** Returns: 589440266059SGregory Neil Shapiro ** none. 589540266059SGregory Neil Shapiro ** 589640266059SGregory Neil Shapiro ** Side Effects: 589740266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 589840266059SGregory Neil Shapiro */ 589940266059SGregory Neil Shapiro 590040266059SGregory Neil Shapiro void 590140266059SGregory Neil Shapiro setclttls(tls_ok) 590240266059SGregory Neil Shapiro bool tls_ok; 590340266059SGregory Neil Shapiro { 590440266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 590540266059SGregory Neil Shapiro return; 590640266059SGregory Neil Shapiro } 590740266059SGregory Neil Shapiro /* 590806f25ae9SGregory Neil Shapiro ** INITCLTTLS -- initialize client side TLS 590906f25ae9SGregory Neil Shapiro ** 591006f25ae9SGregory Neil Shapiro ** Parameters: 591140266059SGregory Neil Shapiro ** tls_ok -- should tls initialization be done? 591206f25ae9SGregory Neil Shapiro ** 591306f25ae9SGregory Neil Shapiro ** Returns: 591406f25ae9SGregory Neil Shapiro ** succeeded? 591540266059SGregory Neil Shapiro ** 591640266059SGregory Neil Shapiro ** Side Effects: 591740266059SGregory Neil Shapiro ** sets tls_ok_clt (static variable in this module) 591806f25ae9SGregory Neil Shapiro */ 591906f25ae9SGregory Neil Shapiro 592006f25ae9SGregory Neil Shapiro bool 592140266059SGregory Neil Shapiro initclttls(tls_ok) 592240266059SGregory Neil Shapiro bool tls_ok; 592306f25ae9SGregory Neil Shapiro { 592440266059SGregory Neil Shapiro if (!tls_ok_clt) 592540266059SGregory Neil Shapiro return false; 592640266059SGregory Neil Shapiro tls_ok_clt = tls_ok; 592740266059SGregory Neil Shapiro if (!tls_ok_clt) 592840266059SGregory Neil Shapiro return false; 592906f25ae9SGregory Neil Shapiro if (clt_ctx != NULL) 593040266059SGregory Neil Shapiro return true; /* already done */ 593140266059SGregory Neil Shapiro tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCERTfile, 593240266059SGregory Neil Shapiro Cltkeyfile, CACERTpath, CACERTfile, DHParams); 593340266059SGregory Neil Shapiro return tls_ok_clt; 593406f25ae9SGregory Neil Shapiro } 593506f25ae9SGregory Neil Shapiro 593640266059SGregory Neil Shapiro /* 593706f25ae9SGregory Neil Shapiro ** STARTTLS -- try to start secure connection (client side) 593806f25ae9SGregory Neil Shapiro ** 593906f25ae9SGregory Neil Shapiro ** Parameters: 594006f25ae9SGregory Neil Shapiro ** m -- the mailer. 594106f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 594206f25ae9SGregory Neil Shapiro ** e -- the envelope. 594306f25ae9SGregory Neil Shapiro ** 594406f25ae9SGregory Neil Shapiro ** Returns: 594506f25ae9SGregory Neil Shapiro ** success? 594606f25ae9SGregory Neil Shapiro ** (maybe this should be some other code than EX_ 594706f25ae9SGregory Neil Shapiro ** that denotes which stage failed.) 594806f25ae9SGregory Neil Shapiro */ 594906f25ae9SGregory Neil Shapiro 595006f25ae9SGregory Neil Shapiro static int 595106f25ae9SGregory Neil Shapiro starttls(m, mci, e) 595206f25ae9SGregory Neil Shapiro MAILER *m; 595306f25ae9SGregory Neil Shapiro MCI *mci; 595406f25ae9SGregory Neil Shapiro ENVELOPE *e; 595506f25ae9SGregory Neil Shapiro { 595606f25ae9SGregory Neil Shapiro int smtpresult; 595742e5d165SGregory Neil Shapiro int result = 0; 595842e5d165SGregory Neil Shapiro int rfd, wfd; 595906f25ae9SGregory Neil Shapiro SSL *clt_ssl = NULL; 596040266059SGregory Neil Shapiro time_t tlsstart; 596106f25ae9SGregory Neil Shapiro 596240266059SGregory Neil Shapiro if (clt_ctx == NULL && !initclttls(true)) 596342e5d165SGregory Neil Shapiro return EX_TEMPFAIL; 596406f25ae9SGregory Neil Shapiro smtpmessage("STARTTLS", m, mci); 596506f25ae9SGregory Neil Shapiro 596606f25ae9SGregory Neil Shapiro /* get the reply */ 596740266059SGregory Neil Shapiro smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL); 596806f25ae9SGregory Neil Shapiro 596906f25ae9SGregory Neil Shapiro /* check return code from server */ 597006f25ae9SGregory Neil Shapiro if (smtpresult == 454) 597106f25ae9SGregory Neil Shapiro return EX_TEMPFAIL; 597206f25ae9SGregory Neil Shapiro if (smtpresult == 501) 597306f25ae9SGregory Neil Shapiro return EX_USAGE; 597406f25ae9SGregory Neil Shapiro if (smtpresult == -1) 597506f25ae9SGregory Neil Shapiro return smtpresult; 597606f25ae9SGregory Neil Shapiro if (smtpresult != 220) 597706f25ae9SGregory Neil Shapiro return EX_PROTOCOL; 597806f25ae9SGregory Neil Shapiro 597906f25ae9SGregory Neil Shapiro if (LogLevel > 13) 598040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 598106f25ae9SGregory Neil Shapiro 598206f25ae9SGregory Neil Shapiro /* start connection */ 598306f25ae9SGregory Neil Shapiro if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 598406f25ae9SGregory Neil Shapiro { 598506f25ae9SGregory Neil Shapiro if (LogLevel > 5) 598606f25ae9SGregory Neil Shapiro { 598740266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 598840266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_new failed"); 598906f25ae9SGregory Neil Shapiro if (LogLevel > 9) 599040266059SGregory Neil Shapiro tlslogerr("client"); 599106f25ae9SGregory Neil Shapiro } 599206f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 599306f25ae9SGregory Neil Shapiro } 599406f25ae9SGregory Neil Shapiro 599540266059SGregory Neil Shapiro rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 599640266059SGregory Neil Shapiro wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 599742e5d165SGregory Neil Shapiro 599806f25ae9SGregory Neil Shapiro /* SSL_clear(clt_ssl); ? */ 599942e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 || 600040266059SGregory Neil Shapiro (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 600140266059SGregory Neil Shapiro (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 600206f25ae9SGregory Neil Shapiro { 600306f25ae9SGregory Neil Shapiro if (LogLevel > 5) 600406f25ae9SGregory Neil Shapiro { 600540266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 600640266059SGregory Neil Shapiro "STARTTLS=client, error: SSL_set_xfd failed=%d", 600740266059SGregory Neil Shapiro result); 600806f25ae9SGregory Neil Shapiro if (LogLevel > 9) 600940266059SGregory Neil Shapiro tlslogerr("client"); 601006f25ae9SGregory Neil Shapiro } 601106f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 601206f25ae9SGregory Neil Shapiro } 601306f25ae9SGregory Neil Shapiro SSL_set_connect_state(clt_ssl); 601440266059SGregory Neil Shapiro tlsstart = curtime(); 601540266059SGregory Neil Shapiro 601640266059SGregory Neil Shapiro ssl_retry: 601706f25ae9SGregory Neil Shapiro if ((result = SSL_connect(clt_ssl)) <= 0) 601806f25ae9SGregory Neil Shapiro { 601906f25ae9SGregory Neil Shapiro int i; 602040266059SGregory Neil Shapiro bool timedout; 602140266059SGregory Neil Shapiro time_t left; 602240266059SGregory Neil Shapiro time_t now = curtime(); 602340266059SGregory Neil Shapiro struct timeval tv; 602406f25ae9SGregory Neil Shapiro 602506f25ae9SGregory Neil Shapiro /* what to do in this case? */ 602606f25ae9SGregory Neil Shapiro i = SSL_get_error(clt_ssl, result); 602740266059SGregory Neil Shapiro 602840266059SGregory Neil Shapiro /* 602940266059SGregory Neil Shapiro ** For SSL_ERROR_WANT_{READ,WRITE}: 603040266059SGregory Neil Shapiro ** There is not a complete SSL record available yet 603140266059SGregory Neil Shapiro ** or there is only a partial SSL record removed from 603240266059SGregory Neil Shapiro ** the network (socket) buffer into the SSL buffer. 603340266059SGregory Neil Shapiro ** The SSL_connect will only succeed when a full 603440266059SGregory Neil Shapiro ** SSL record is available (assuming a "real" error 603540266059SGregory Neil Shapiro ** doesn't happen). To handle when a "real" error 603640266059SGregory Neil Shapiro ** does happen the select is set for exceptions too. 603740266059SGregory Neil Shapiro ** The connection may be re-negotiated during this time 603840266059SGregory Neil Shapiro ** so both read and write "want errors" need to be handled. 603940266059SGregory Neil Shapiro ** A select() exception loops back so that a proper SSL 604040266059SGregory Neil Shapiro ** error message can be gotten. 604140266059SGregory Neil Shapiro */ 604240266059SGregory Neil Shapiro 604340266059SGregory Neil Shapiro left = TimeOuts.to_starttls - (now - tlsstart); 604440266059SGregory Neil Shapiro timedout = left <= 0; 604540266059SGregory Neil Shapiro if (!timedout) 604640266059SGregory Neil Shapiro { 604740266059SGregory Neil Shapiro tv.tv_sec = left; 604840266059SGregory Neil Shapiro tv.tv_usec = 0; 604940266059SGregory Neil Shapiro } 605040266059SGregory Neil Shapiro 605140266059SGregory Neil Shapiro if (!timedout && i == SSL_ERROR_WANT_READ) 605240266059SGregory Neil Shapiro { 605340266059SGregory Neil Shapiro fd_set ssl_maskr, ssl_maskx; 605440266059SGregory Neil Shapiro 605540266059SGregory Neil Shapiro FD_ZERO(&ssl_maskr); 605640266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskr); 605740266059SGregory Neil Shapiro FD_ZERO(&ssl_maskx); 605840266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 605940266059SGregory Neil Shapiro if (select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, &tv) 606040266059SGregory Neil Shapiro > 0) 606140266059SGregory Neil Shapiro goto ssl_retry; 606240266059SGregory Neil Shapiro } 606340266059SGregory Neil Shapiro if (!timedout && i == SSL_ERROR_WANT_WRITE) 606440266059SGregory Neil Shapiro { 606540266059SGregory Neil Shapiro fd_set ssl_maskw, ssl_maskx; 606640266059SGregory Neil Shapiro 606740266059SGregory Neil Shapiro FD_ZERO(&ssl_maskw); 606840266059SGregory Neil Shapiro FD_SET(wfd, &ssl_maskw); 606940266059SGregory Neil Shapiro FD_ZERO(&ssl_maskx); 607040266059SGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 607140266059SGregory Neil Shapiro if (select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, &tv) 607240266059SGregory Neil Shapiro > 0) 607340266059SGregory Neil Shapiro goto ssl_retry; 607440266059SGregory Neil Shapiro } 607506f25ae9SGregory Neil Shapiro if (LogLevel > 5) 607606f25ae9SGregory Neil Shapiro { 607706f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 607840266059SGregory Neil Shapiro "STARTTLS=client, error: connect failed=%d, SSL_error=%d, timedout=%d", 607940266059SGregory Neil Shapiro result, i, (int) timedout); 608040266059SGregory Neil Shapiro if (LogLevel > 8) 608140266059SGregory Neil Shapiro tlslogerr("client"); 608206f25ae9SGregory Neil Shapiro } 608306f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 608406f25ae9SGregory Neil Shapiro clt_ssl = NULL; 608506f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 608606f25ae9SGregory Neil Shapiro } 608706f25ae9SGregory Neil Shapiro mci->mci_ssl = clt_ssl; 608840266059SGregory Neil Shapiro result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 608940266059SGregory Neil Shapiro &mci->mci_macro, true); 609006f25ae9SGregory Neil Shapiro 609140266059SGregory Neil Shapiro /* switch to use TLS... */ 609206f25ae9SGregory Neil Shapiro if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 609306f25ae9SGregory Neil Shapiro return EX_OK; 609406f25ae9SGregory Neil Shapiro 609506f25ae9SGregory Neil Shapiro /* failure */ 609606f25ae9SGregory Neil Shapiro SSL_free(clt_ssl); 609706f25ae9SGregory Neil Shapiro clt_ssl = NULL; 609806f25ae9SGregory Neil Shapiro return EX_SOFTWARE; 609906f25ae9SGregory Neil Shapiro } 610040266059SGregory Neil Shapiro /* 610106f25ae9SGregory Neil Shapiro ** ENDTLSCLT -- shutdown secure connection (client side) 610206f25ae9SGregory Neil Shapiro ** 610306f25ae9SGregory Neil Shapiro ** Parameters: 610406f25ae9SGregory Neil Shapiro ** mci -- the mailer connection info. 610506f25ae9SGregory Neil Shapiro ** 610606f25ae9SGregory Neil Shapiro ** Returns: 610706f25ae9SGregory Neil Shapiro ** success? 610806f25ae9SGregory Neil Shapiro */ 610940266059SGregory Neil Shapiro 611040266059SGregory Neil Shapiro static int 611106f25ae9SGregory Neil Shapiro endtlsclt(mci) 611206f25ae9SGregory Neil Shapiro MCI *mci; 611306f25ae9SGregory Neil Shapiro { 611406f25ae9SGregory Neil Shapiro int r; 611506f25ae9SGregory Neil Shapiro 611606f25ae9SGregory Neil Shapiro if (!bitset(MCIF_TLSACT, mci->mci_flags)) 611706f25ae9SGregory Neil Shapiro return EX_OK; 611806f25ae9SGregory Neil Shapiro r = endtls(mci->mci_ssl, "client"); 611906f25ae9SGregory Neil Shapiro mci->mci_flags &= ~MCIF_TLSACT; 612006f25ae9SGregory Neil Shapiro return r; 612106f25ae9SGregory Neil Shapiro } 612240266059SGregory Neil Shapiro # endif /* STARTTLS */ 612340266059SGregory Neil Shapiro # if STARTTLS || SASL 612440266059SGregory Neil Shapiro /* 612540266059SGregory Neil Shapiro ** ISCLTFLGSET -- check whether client flag is set. 612606f25ae9SGregory Neil Shapiro ** 612706f25ae9SGregory Neil Shapiro ** Parameters: 612840266059SGregory Neil Shapiro ** e -- envelope. 612940266059SGregory Neil Shapiro ** flag -- flag to check in {client_flags} 613006f25ae9SGregory Neil Shapiro ** 613106f25ae9SGregory Neil Shapiro ** Returns: 613240266059SGregory Neil Shapiro ** true iff flag is set. 613306f25ae9SGregory Neil Shapiro */ 613406f25ae9SGregory Neil Shapiro 613540266059SGregory Neil Shapiro static bool 613640266059SGregory Neil Shapiro iscltflgset(e, flag) 613740266059SGregory Neil Shapiro ENVELOPE *e; 613840266059SGregory Neil Shapiro int flag; 613906f25ae9SGregory Neil Shapiro { 614040266059SGregory Neil Shapiro char *p; 6141602a2b1bSGregory Neil Shapiro 614240266059SGregory Neil Shapiro p = macvalue(macid("{client_flags}"), e); 614340266059SGregory Neil Shapiro if (p == NULL) 614440266059SGregory Neil Shapiro return false; 614540266059SGregory Neil Shapiro for (; *p != '\0'; p++) 614606f25ae9SGregory Neil Shapiro { 614740266059SGregory Neil Shapiro /* look for just this one flag */ 614840266059SGregory Neil Shapiro if (*p == (char) flag) 614940266059SGregory Neil Shapiro return true; 615006f25ae9SGregory Neil Shapiro } 615140266059SGregory Neil Shapiro return false; 615206f25ae9SGregory Neil Shapiro } 615340266059SGregory Neil Shapiro # endif /* STARTTLS || SASL */ 6154