17c478bd9Sstevel@tonic-gate /* 2445f2479Sjbeck * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 107c478bd9Sstevel@tonic-gate * the sendmail distribution. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate */ 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #include <sendmail.h> 1749218d4fSjbeck #include <sm/time.h> 187c478bd9Sstevel@tonic-gate 19*3ee0e492Sjbeck SM_RCSID("@(#)$Id: deliver.c,v 8.1003.2.1 2006/05/23 01:32:08 ca Exp $") 207c478bd9Sstevel@tonic-gate 217c478bd9Sstevel@tonic-gate #if HASSETUSERCONTEXT 227c478bd9Sstevel@tonic-gate # include <login_cap.h> 237c478bd9Sstevel@tonic-gate #endif /* HASSETUSERCONTEXT */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #if NETINET || NETINET6 267c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 277c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #if STARTTLS || SASL 307c478bd9Sstevel@tonic-gate # include "sfsasl.h" 317c478bd9Sstevel@tonic-gate #endif /* STARTTLS || SASL */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate static int deliver __P((ENVELOPE *, ADDRESS *)); 347c478bd9Sstevel@tonic-gate static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); 357c478bd9Sstevel@tonic-gate static void mailfiletimeout __P((int)); 367c478bd9Sstevel@tonic-gate static void endwaittimeout __P((int)); 377c478bd9Sstevel@tonic-gate static int parse_hostsignature __P((char *, char **, MAILER *)); 387c478bd9Sstevel@tonic-gate static void sendenvelope __P((ENVELOPE *, int)); 397c478bd9Sstevel@tonic-gate extern MCI *mci_new __P((SM_RPOOL_T *)); 407c478bd9Sstevel@tonic-gate static int coloncmp __P((const char *, const char *)); 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #if STARTTLS 437c478bd9Sstevel@tonic-gate static int starttls __P((MAILER *, MCI *, ENVELOPE *)); 447c478bd9Sstevel@tonic-gate static int endtlsclt __P((MCI *)); 457c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 467c478bd9Sstevel@tonic-gate # if STARTTLS || SASL 477c478bd9Sstevel@tonic-gate static bool iscltflgset __P((ENVELOPE *, int)); 487c478bd9Sstevel@tonic-gate # endif /* STARTTLS || SASL */ 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate ** SENDALL -- actually send all the messages. 527c478bd9Sstevel@tonic-gate ** 537c478bd9Sstevel@tonic-gate ** Parameters: 547c478bd9Sstevel@tonic-gate ** e -- the envelope to send. 557c478bd9Sstevel@tonic-gate ** mode -- the delivery mode to use. If SM_DEFAULT, use 567c478bd9Sstevel@tonic-gate ** the current e->e_sendmode. 577c478bd9Sstevel@tonic-gate ** 587c478bd9Sstevel@tonic-gate ** Returns: 597c478bd9Sstevel@tonic-gate ** none. 607c478bd9Sstevel@tonic-gate ** 617c478bd9Sstevel@tonic-gate ** Side Effects: 627c478bd9Sstevel@tonic-gate ** Scans the send lists and sends everything it finds. 637c478bd9Sstevel@tonic-gate ** Delivers any appropriate error messages. 647c478bd9Sstevel@tonic-gate ** If we are running in a non-interactive mode, takes the 657c478bd9Sstevel@tonic-gate ** appropriate action. 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate void 697c478bd9Sstevel@tonic-gate sendall(e, mode) 707c478bd9Sstevel@tonic-gate ENVELOPE *e; 717c478bd9Sstevel@tonic-gate int mode; 727c478bd9Sstevel@tonic-gate { 737c478bd9Sstevel@tonic-gate register ADDRESS *q; 747c478bd9Sstevel@tonic-gate char *owner; 757c478bd9Sstevel@tonic-gate int otherowners; 767c478bd9Sstevel@tonic-gate int save_errno; 777c478bd9Sstevel@tonic-gate register ENVELOPE *ee; 787c478bd9Sstevel@tonic-gate ENVELOPE *splitenv = NULL; 797c478bd9Sstevel@tonic-gate int oldverbose = Verbose; 807c478bd9Sstevel@tonic-gate bool somedeliveries = false, expensive = false; 817c478bd9Sstevel@tonic-gate pid_t pid; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate ** If this message is to be discarded, don't bother sending 857c478bd9Sstevel@tonic-gate ** the message at all. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate if (bitset(EF_DISCARD, e->e_flags)) 897c478bd9Sstevel@tonic-gate { 907c478bd9Sstevel@tonic-gate if (tTd(13, 1)) 917c478bd9Sstevel@tonic-gate sm_dprintf("sendall: discarding id %s\n", e->e_id); 927c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 937c478bd9Sstevel@tonic-gate if (LogLevel > 9) 947c478bd9Sstevel@tonic-gate logundelrcpts(e, "discarded", 9, true); 957c478bd9Sstevel@tonic-gate else if (LogLevel > 4) 967c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "discarded"); 977c478bd9Sstevel@tonic-gate markstats(e, NULL, STATS_REJECT); 987c478bd9Sstevel@tonic-gate return; 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate ** If we have had global, fatal errors, don't bother sending 1037c478bd9Sstevel@tonic-gate ** the message at all if we are in SMTP mode. Local errors 1047c478bd9Sstevel@tonic-gate ** (e.g., a single address failing) will still cause the other 1057c478bd9Sstevel@tonic-gate ** addresses to be sent. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate if (bitset(EF_FATALERRS, e->e_flags) && 1097c478bd9Sstevel@tonic-gate (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 1127c478bd9Sstevel@tonic-gate return; 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* determine actual delivery mode */ 1167c478bd9Sstevel@tonic-gate if (mode == SM_DEFAULT) 1177c478bd9Sstevel@tonic-gate { 1187c478bd9Sstevel@tonic-gate mode = e->e_sendmode; 1197c478bd9Sstevel@tonic-gate if (mode != SM_VERIFY && mode != SM_DEFER && 1207c478bd9Sstevel@tonic-gate shouldqueue(e->e_msgpriority, e->e_ctime)) 1217c478bd9Sstevel@tonic-gate mode = SM_QUEUE; 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (tTd(13, 1)) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ", 1277c478bd9Sstevel@tonic-gate mode, e->e_id); 1287c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &e->e_from, false); 1297c478bd9Sstevel@tonic-gate sm_dprintf("\te_flags = "); 1307c478bd9Sstevel@tonic-gate printenvflags(e); 1317c478bd9Sstevel@tonic-gate sm_dprintf("sendqueue:\n"); 1327c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate ** Do any preprocessing necessary for the mode we are running. 1377c478bd9Sstevel@tonic-gate ** Check to make sure the hop count is reasonable. 1387c478bd9Sstevel@tonic-gate ** Delete sends to the sender in mailing lists. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate CurEnv = e; 1427c478bd9Sstevel@tonic-gate if (tTd(62, 1)) 1437c478bd9Sstevel@tonic-gate checkfds(NULL); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (e->e_hopcount > MaxHopCount) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate char *recip; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate if (e->e_sendqueue != NULL && 1507c478bd9Sstevel@tonic-gate e->e_sendqueue->q_paddr != NULL) 1517c478bd9Sstevel@tonic-gate recip = e->e_sendqueue->q_paddr; 1527c478bd9Sstevel@tonic-gate else 1537c478bd9Sstevel@tonic-gate recip = "(nobody)"; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate errno = 0; 1567c478bd9Sstevel@tonic-gate queueup(e, WILL_BE_QUEUED(mode), false); 1577c478bd9Sstevel@tonic-gate e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 1587c478bd9Sstevel@tonic-gate ExitStat = EX_UNAVAILABLE; 1597c478bd9Sstevel@tonic-gate syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s", 1607c478bd9Sstevel@tonic-gate e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 1617c478bd9Sstevel@tonic-gate RealHostName == NULL ? "localhost" : RealHostName, 1627c478bd9Sstevel@tonic-gate recip); 1637c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 1667c478bd9Sstevel@tonic-gate continue; 1677c478bd9Sstevel@tonic-gate q->q_state = QS_BADADDR; 1687c478bd9Sstevel@tonic-gate q->q_status = "5.4.6"; 1697c478bd9Sstevel@tonic-gate q->q_rstatus = "554 5.4.6 Too many hops"; 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate return; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate ** Do sender deletion. 1767c478bd9Sstevel@tonic-gate ** 1777c478bd9Sstevel@tonic-gate ** If the sender should be queued up, skip this. 1787c478bd9Sstevel@tonic-gate ** This can happen if the name server is hosed when you 1797c478bd9Sstevel@tonic-gate ** are trying to send mail. The result is that the sender 1807c478bd9Sstevel@tonic-gate ** is instantiated in the queue as a recipient. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (!bitset(EF_METOO, e->e_flags) && 1847c478bd9Sstevel@tonic-gate !QS_IS_QUEUEUP(e->e_from.q_state)) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate if (tTd(13, 5)) 1877c478bd9Sstevel@tonic-gate { 1887c478bd9Sstevel@tonic-gate sm_dprintf("sendall: QS_SENDER "); 1897c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &e->e_from, false); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate e->e_from.q_state = QS_SENDER; 1927c478bd9Sstevel@tonic-gate (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate ** Handle alias owners. 1977c478bd9Sstevel@tonic-gate ** 1987c478bd9Sstevel@tonic-gate ** We scan up the q_alias chain looking for owners. 1997c478bd9Sstevel@tonic-gate ** We discard owners that are the same as the return path. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate register struct address *a; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 2077c478bd9Sstevel@tonic-gate continue; 2087c478bd9Sstevel@tonic-gate if (a != NULL) 2097c478bd9Sstevel@tonic-gate q->q_owner = a->q_owner; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate if (q->q_owner != NULL && 2127c478bd9Sstevel@tonic-gate !QS_IS_DEAD(q->q_state) && 2137c478bd9Sstevel@tonic-gate strcmp(q->q_owner, e->e_from.q_paddr) == 0) 2147c478bd9Sstevel@tonic-gate q->q_owner = NULL; 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate if (tTd(13, 25)) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate sm_dprintf("\nAfter first owner pass, sendq =\n"); 2207c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate owner = ""; 2247c478bd9Sstevel@tonic-gate otherowners = 1; 2257c478bd9Sstevel@tonic-gate while (owner != NULL && otherowners > 0) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate if (tTd(13, 28)) 2287c478bd9Sstevel@tonic-gate sm_dprintf("owner = \"%s\", otherowners = %d\n", 2297c478bd9Sstevel@tonic-gate owner, otherowners); 2307c478bd9Sstevel@tonic-gate owner = NULL; 2317c478bd9Sstevel@tonic-gate otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate sm_dprintf("Checking "); 2387c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate if (QS_IS_DEAD(q->q_state)) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 2437c478bd9Sstevel@tonic-gate sm_dprintf(" ... QS_IS_DEAD\n"); 2447c478bd9Sstevel@tonic-gate continue; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if (tTd(13, 29) && !tTd(13, 30)) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate sm_dprintf("Checking "); 2497c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (q->q_owner != NULL) 2537c478bd9Sstevel@tonic-gate { 2547c478bd9Sstevel@tonic-gate if (owner == NULL) 2557c478bd9Sstevel@tonic-gate { 2567c478bd9Sstevel@tonic-gate if (tTd(13, 40)) 2577c478bd9Sstevel@tonic-gate sm_dprintf(" ... First owner = \"%s\"\n", 2587c478bd9Sstevel@tonic-gate q->q_owner); 2597c478bd9Sstevel@tonic-gate owner = q->q_owner; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate else if (owner != q->q_owner) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate if (strcmp(owner, q->q_owner) == 0) 2647c478bd9Sstevel@tonic-gate { 2657c478bd9Sstevel@tonic-gate if (tTd(13, 40)) 2667c478bd9Sstevel@tonic-gate sm_dprintf(" ... Same owner = \"%s\"\n", 2677c478bd9Sstevel@tonic-gate owner); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* make future comparisons cheap */ 2707c478bd9Sstevel@tonic-gate q->q_owner = owner; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate else 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate if (tTd(13, 40)) 2757c478bd9Sstevel@tonic-gate sm_dprintf(" ... Another owner \"%s\"\n", 2767c478bd9Sstevel@tonic-gate q->q_owner); 2777c478bd9Sstevel@tonic-gate otherowners++; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate owner = q->q_owner; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate else if (tTd(13, 40)) 2827c478bd9Sstevel@tonic-gate sm_dprintf(" ... Same owner = \"%s\"\n", 2837c478bd9Sstevel@tonic-gate owner); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate else 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate if (tTd(13, 40)) 2887c478bd9Sstevel@tonic-gate sm_dprintf(" ... Null owner\n"); 2897c478bd9Sstevel@tonic-gate otherowners++; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(q->q_state)) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 2957c478bd9Sstevel@tonic-gate sm_dprintf(" ... QS_IS_BADADDR\n"); 2967c478bd9Sstevel@tonic-gate continue; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (QS_IS_QUEUEUP(q->q_state)) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate MAILER *m = q->q_mailer; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* 3047c478bd9Sstevel@tonic-gate ** If we have temporary address failures 3057c478bd9Sstevel@tonic-gate ** (e.g., dns failure) and a fallback MX is 3067c478bd9Sstevel@tonic-gate ** set, send directly to the fallback MX host. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (FallbackMX != NULL && 3107c478bd9Sstevel@tonic-gate !wordinclass(FallbackMX, 'w') && 3117c478bd9Sstevel@tonic-gate mode != SM_VERIFY && 3127c478bd9Sstevel@tonic-gate !bitnset(M_NOMX, m->m_flags) && 3137c478bd9Sstevel@tonic-gate strcmp(m->m_mailer, "[IPC]") == 0 && 3147c478bd9Sstevel@tonic-gate m->m_argv[0] != NULL && 3157c478bd9Sstevel@tonic-gate strcmp(m->m_argv[0], "TCP") == 0) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate int len; 3187c478bd9Sstevel@tonic-gate char *p; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3217c478bd9Sstevel@tonic-gate sm_dprintf(" ... FallbackMX\n"); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate len = strlen(FallbackMX) + 1; 3247c478bd9Sstevel@tonic-gate p = sm_rpool_malloc_x(e->e_rpool, len); 3257c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, FallbackMX, len); 3267c478bd9Sstevel@tonic-gate q->q_state = QS_OK; 3277c478bd9Sstevel@tonic-gate q->q_host = p; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate else 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3327c478bd9Sstevel@tonic-gate sm_dprintf(" ... QS_IS_QUEUEUP\n"); 3337c478bd9Sstevel@tonic-gate continue; 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate ** If this mailer is expensive, and if we don't 3397c478bd9Sstevel@tonic-gate ** want to make connections now, just mark these 3407c478bd9Sstevel@tonic-gate ** addresses and return. This is useful if we 3417c478bd9Sstevel@tonic-gate ** want to batch connections to reduce load. This 3427c478bd9Sstevel@tonic-gate ** will cause the messages to be queued up, and a 3437c478bd9Sstevel@tonic-gate ** daemon will come along to send the messages later. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (NoConnect && !Verbose && 3477c478bd9Sstevel@tonic-gate bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3507c478bd9Sstevel@tonic-gate sm_dprintf(" ... expensive\n"); 3517c478bd9Sstevel@tonic-gate q->q_state = QS_QUEUEUP; 3527c478bd9Sstevel@tonic-gate expensive = true; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate else if (bitnset(M_HOLD, q->q_mailer->m_flags) && 3557c478bd9Sstevel@tonic-gate QueueLimitId == NULL && 3567c478bd9Sstevel@tonic-gate QueueLimitSender == NULL && 3577c478bd9Sstevel@tonic-gate QueueLimitRecipient == NULL) 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3607c478bd9Sstevel@tonic-gate sm_dprintf(" ... hold\n"); 3617c478bd9Sstevel@tonic-gate q->q_state = QS_QUEUEUP; 3627c478bd9Sstevel@tonic-gate expensive = true; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE && 3657c478bd9Sstevel@tonic-gate e->e_quarmsg != NULL) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3687c478bd9Sstevel@tonic-gate sm_dprintf(" ... quarantine: %s\n", 3697c478bd9Sstevel@tonic-gate e->e_quarmsg); 3707c478bd9Sstevel@tonic-gate q->q_state = QS_QUEUEUP; 3717c478bd9Sstevel@tonic-gate expensive = true; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate else 3747c478bd9Sstevel@tonic-gate { 3757c478bd9Sstevel@tonic-gate if (tTd(13, 30)) 3767c478bd9Sstevel@tonic-gate sm_dprintf(" ... deliverable\n"); 3777c478bd9Sstevel@tonic-gate somedeliveries = true; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (owner != NULL && otherowners > 0) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate ** Split this envelope into two. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, 3887c478bd9Sstevel@tonic-gate sizeof *ee); 3897c478bd9Sstevel@tonic-gate STRUCTCOPY(*e, *ee); 3907c478bd9Sstevel@tonic-gate ee->e_message = NULL; 3917c478bd9Sstevel@tonic-gate ee->e_id = NULL; 3927c478bd9Sstevel@tonic-gate assign_queueid(ee); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate if (tTd(13, 1)) 3957c478bd9Sstevel@tonic-gate sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", 3967c478bd9Sstevel@tonic-gate e->e_id, ee->e_id, owner, 3977c478bd9Sstevel@tonic-gate otherowners); 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate ee->e_header = copyheader(e->e_header, ee->e_rpool); 4007c478bd9Sstevel@tonic-gate ee->e_sendqueue = copyqueue(e->e_sendqueue, 4017c478bd9Sstevel@tonic-gate ee->e_rpool); 4027c478bd9Sstevel@tonic-gate ee->e_errorqueue = copyqueue(e->e_errorqueue, 4037c478bd9Sstevel@tonic-gate ee->e_rpool); 4047c478bd9Sstevel@tonic-gate ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 4057c478bd9Sstevel@tonic-gate ee->e_flags |= EF_NORECEIPT; 4067c478bd9Sstevel@tonic-gate setsender(owner, ee, NULL, '\0', true); 4077c478bd9Sstevel@tonic-gate if (tTd(13, 5)) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate sm_dprintf("sendall(split): QS_SENDER "); 4107c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &ee->e_from, false); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate ee->e_from.q_state = QS_SENDER; 4137c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 4147c478bd9Sstevel@tonic-gate ee->e_lockfp = NULL; 4157c478bd9Sstevel@tonic-gate ee->e_xfp = NULL; 4167c478bd9Sstevel@tonic-gate ee->e_qgrp = e->e_qgrp; 4177c478bd9Sstevel@tonic-gate ee->e_qdir = e->e_qdir; 4187c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL; 4197c478bd9Sstevel@tonic-gate ee->e_sibling = splitenv; 4207c478bd9Sstevel@tonic-gate ee->e_statmsg = NULL; 4217c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 4227c478bd9Sstevel@tonic-gate ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, 4237c478bd9Sstevel@tonic-gate e->e_quarmsg); 4247c478bd9Sstevel@tonic-gate splitenv = ee; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate if (q->q_owner == owner) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate q->q_state = QS_CLONED; 4317c478bd9Sstevel@tonic-gate if (tTd(13, 6)) 4327c478bd9Sstevel@tonic-gate sm_dprintf("\t... stripping %s from original envelope\n", 4337c478bd9Sstevel@tonic-gate q->q_paddr); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 4377c478bd9Sstevel@tonic-gate { 4387c478bd9Sstevel@tonic-gate if (q->q_owner != owner) 4397c478bd9Sstevel@tonic-gate { 4407c478bd9Sstevel@tonic-gate q->q_state = QS_CLONED; 4417c478bd9Sstevel@tonic-gate if (tTd(13, 6)) 4427c478bd9Sstevel@tonic-gate sm_dprintf("\t... dropping %s from cloned envelope\n", 4437c478bd9Sstevel@tonic-gate q->q_paddr); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate else 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate /* clear DSN parameters */ 4487c478bd9Sstevel@tonic-gate q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); 4497c478bd9Sstevel@tonic-gate q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; 4507c478bd9Sstevel@tonic-gate if (tTd(13, 6)) 4517c478bd9Sstevel@tonic-gate sm_dprintf("\t... moving %s to cloned envelope\n", 4527c478bd9Sstevel@tonic-gate q->q_paddr); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 4577c478bd9Sstevel@tonic-gate dup_queue_file(e, ee, DATAFL_LETTER); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate ** Give the split envelope access to the parent 4617c478bd9Sstevel@tonic-gate ** transcript file for errors obtained while 4627c478bd9Sstevel@tonic-gate ** processing the recipients (done before the 4637c478bd9Sstevel@tonic-gate ** envelope splitting). 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 4677c478bd9Sstevel@tonic-gate ee->e_xfp = sm_io_dup(e->e_xfp); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* failed to dup e->e_xfp, start a new transcript */ 4707c478bd9Sstevel@tonic-gate if (ee->e_xfp == NULL) 4717c478bd9Sstevel@tonic-gate openxscript(ee); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate if (mode != SM_VERIFY && LogLevel > 4) 4747c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 4757c478bd9Sstevel@tonic-gate "%s: clone: owner=%s", 4767c478bd9Sstevel@tonic-gate ee->e_id, owner); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (owner != NULL) 4817c478bd9Sstevel@tonic-gate { 4827c478bd9Sstevel@tonic-gate setsender(owner, e, NULL, '\0', true); 4837c478bd9Sstevel@tonic-gate if (tTd(13, 5)) 4847c478bd9Sstevel@tonic-gate { 4857c478bd9Sstevel@tonic-gate sm_dprintf("sendall(owner): QS_SENDER "); 4867c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &e->e_from, false); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate e->e_from.q_state = QS_SENDER; 4897c478bd9Sstevel@tonic-gate e->e_errormode = EM_MAIL; 4907c478bd9Sstevel@tonic-gate e->e_flags |= EF_NORECEIPT; 4917c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_FATALERRS; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* if nothing to be delivered, just queue up everything */ 4957c478bd9Sstevel@tonic-gate if (!somedeliveries && !WILL_BE_QUEUED(mode) && 4967c478bd9Sstevel@tonic-gate mode != SM_VERIFY) 4977c478bd9Sstevel@tonic-gate { 4987c478bd9Sstevel@tonic-gate time_t now; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if (tTd(13, 29)) 5017c478bd9Sstevel@tonic-gate sm_dprintf("No deliveries: auto-queuing\n"); 5027c478bd9Sstevel@tonic-gate mode = SM_QUEUE; 5037c478bd9Sstevel@tonic-gate now = curtime(); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* treat this as a delivery in terms of counting tries */ 5067c478bd9Sstevel@tonic-gate e->e_dtime = now; 5077c478bd9Sstevel@tonic-gate if (!expensive) 5087c478bd9Sstevel@tonic-gate e->e_ntries++; 5097c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate ee->e_dtime = now; 5127c478bd9Sstevel@tonic-gate if (!expensive) 5137c478bd9Sstevel@tonic-gate ee->e_ntries++; 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || 5187c478bd9Sstevel@tonic-gate (mode != SM_VERIFY && 5197c478bd9Sstevel@tonic-gate (SuperSafe == SAFE_REALLY || 5207c478bd9Sstevel@tonic-gate SuperSafe == SAFE_REALLY_POSTMILTER))) && 5217c478bd9Sstevel@tonic-gate (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate bool msync; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate ** Be sure everything is instantiated in the queue. 5277c478bd9Sstevel@tonic-gate ** Split envelopes first in case the machine crashes. 5287c478bd9Sstevel@tonic-gate ** If the original were done first, we may lose 5297c478bd9Sstevel@tonic-gate ** recipients. 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate #if !HASFLOCK 5337c478bd9Sstevel@tonic-gate msync = false; 5347c478bd9Sstevel@tonic-gate #else /* !HASFLOCK */ 5357c478bd9Sstevel@tonic-gate msync = mode == SM_FORK; 5367c478bd9Sstevel@tonic-gate #endif /* !HASFLOCK */ 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 5397c478bd9Sstevel@tonic-gate queueup(ee, WILL_BE_QUEUED(mode), msync); 5407c478bd9Sstevel@tonic-gate queueup(e, WILL_BE_QUEUED(mode), msync); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate if (tTd(62, 10)) 5447c478bd9Sstevel@tonic-gate checkfds("after envelope splitting"); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate ** If we belong in background, fork now. 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate if (tTd(13, 20)) 5517c478bd9Sstevel@tonic-gate { 5527c478bd9Sstevel@tonic-gate sm_dprintf("sendall: final mode = %c\n", mode); 5537c478bd9Sstevel@tonic-gate if (tTd(13, 21)) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate sm_dprintf("\n================ Final Send Queue(s) =====================\n"); 5567c478bd9Sstevel@tonic-gate sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 5577c478bd9Sstevel@tonic-gate e->e_id, e->e_from.q_paddr); 5587c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), e->e_sendqueue, true); 5597c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", 5627c478bd9Sstevel@tonic-gate ee->e_id, ee->e_from.q_paddr); 5637c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ee->e_sendqueue, true); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate sm_dprintf("==========================================================\n\n"); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate switch (mode) 5697c478bd9Sstevel@tonic-gate { 5707c478bd9Sstevel@tonic-gate case SM_VERIFY: 5717c478bd9Sstevel@tonic-gate Verbose = 2; 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate case SM_QUEUE: 5757c478bd9Sstevel@tonic-gate case SM_DEFER: 5767c478bd9Sstevel@tonic-gate #if HASFLOCK 5777c478bd9Sstevel@tonic-gate queueonly: 5787c478bd9Sstevel@tonic-gate #endif /* HASFLOCK */ 5797c478bd9Sstevel@tonic-gate if (e->e_nrcpts > 0) 5807c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 5817c478bd9Sstevel@tonic-gate dropenvelope(e, splitenv != NULL, true); 5827c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate if (ee->e_nrcpts > 0) 5857c478bd9Sstevel@tonic-gate ee->e_flags |= EF_INQUEUE; 5867c478bd9Sstevel@tonic-gate dropenvelope(ee, false, true); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate return; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate case SM_FORK: 5917c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 5927c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate #if !HASFLOCK 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate ** Since fcntl locking has the interesting semantic that 5977c478bd9Sstevel@tonic-gate ** the lock is owned by a process, not by an open file 5987c478bd9Sstevel@tonic-gate ** descriptor, we have to flush this to the queue, and 5997c478bd9Sstevel@tonic-gate ** then restart from scratch in the child. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate { 6037c478bd9Sstevel@tonic-gate /* save id for future use */ 6047c478bd9Sstevel@tonic-gate char *qid = e->e_id; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* now drop the envelope in the parent */ 6077c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 6087c478bd9Sstevel@tonic-gate dropenvelope(e, splitenv != NULL, false); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* arrange to reacquire lock after fork */ 6117c478bd9Sstevel@tonic-gate e->e_id = qid; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate /* save id for future use */ 6177c478bd9Sstevel@tonic-gate char *qid = ee->e_id; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* drop envelope in parent */ 6207c478bd9Sstevel@tonic-gate ee->e_flags |= EF_INQUEUE; 6217c478bd9Sstevel@tonic-gate dropenvelope(ee, false, false); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* and save qid for reacquisition */ 6247c478bd9Sstevel@tonic-gate ee->e_id = qid; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate #endif /* !HASFLOCK */ 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate ** Since the delivery may happen in a child and the parent 6317c478bd9Sstevel@tonic-gate ** does not wait, the parent may close the maps thereby 6327c478bd9Sstevel@tonic-gate ** removing any shared memory used by the map. Therefore, 6337c478bd9Sstevel@tonic-gate ** close the maps now so the child will dynamically open 6347c478bd9Sstevel@tonic-gate ** them if necessary. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate closemaps(false); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate pid = fork(); 6407c478bd9Sstevel@tonic-gate if (pid < 0) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate syserr("deliver: fork 1"); 6437c478bd9Sstevel@tonic-gate #if HASFLOCK 6447c478bd9Sstevel@tonic-gate goto queueonly; 6457c478bd9Sstevel@tonic-gate #else /* HASFLOCK */ 6467c478bd9Sstevel@tonic-gate e->e_id = NULL; 6477c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 6487c478bd9Sstevel@tonic-gate ee->e_id = NULL; 6497c478bd9Sstevel@tonic-gate return; 6507c478bd9Sstevel@tonic-gate #endif /* HASFLOCK */ 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate else if (pid > 0) 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate #if HASFLOCK 6557c478bd9Sstevel@tonic-gate /* be sure we leave the temp files to our child */ 6567c478bd9Sstevel@tonic-gate /* close any random open files in the envelope */ 6577c478bd9Sstevel@tonic-gate closexscript(e); 6587c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 6597c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 6607c478bd9Sstevel@tonic-gate e->e_dfp = NULL; 6617c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* can't call unlockqueue to avoid unlink of xfp */ 6647c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 6657c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT); 6667c478bd9Sstevel@tonic-gate else 6677c478bd9Sstevel@tonic-gate syserr("%s: sendall: null lockfp", e->e_id); 6687c478bd9Sstevel@tonic-gate e->e_lockfp = NULL; 6697c478bd9Sstevel@tonic-gate #endif /* HASFLOCK */ 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* make sure the parent doesn't own the envelope */ 6727c478bd9Sstevel@tonic-gate e->e_id = NULL; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate #if USE_DOUBLE_FORK 6757c478bd9Sstevel@tonic-gate /* catch intermediate zombie */ 6767c478bd9Sstevel@tonic-gate (void) waitfor(pid); 6777c478bd9Sstevel@tonic-gate #endif /* USE_DOUBLE_FORK */ 6787c478bd9Sstevel@tonic-gate return; 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* Reset global flags */ 6827c478bd9Sstevel@tonic-gate RestartRequest = NULL; 6837c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 6847c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 6857c478bd9Sstevel@tonic-gate PendingSignal = 0; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 6897c478bd9Sstevel@tonic-gate ** handler for child process. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate /* 6957c478bd9Sstevel@tonic-gate ** Since we have accepted responsbility for the message, 6967c478bd9Sstevel@tonic-gate ** change the SIGTERM handler. intsig() (the old handler) 6977c478bd9Sstevel@tonic-gate ** would remove the envelope if this was a command line 6987c478bd9Sstevel@tonic-gate ** message submission. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, SIG_DFL); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate #if USE_DOUBLE_FORK 7047c478bd9Sstevel@tonic-gate /* double fork to avoid zombies */ 7057c478bd9Sstevel@tonic-gate pid = fork(); 7067c478bd9Sstevel@tonic-gate if (pid > 0) 7077c478bd9Sstevel@tonic-gate exit(EX_OK); 7087c478bd9Sstevel@tonic-gate save_errno = errno; 7097c478bd9Sstevel@tonic-gate #endif /* USE_DOUBLE_FORK */ 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* be sure we are immune from the terminal */ 7147c478bd9Sstevel@tonic-gate disconnect(2, e); 7157c478bd9Sstevel@tonic-gate clearstats(); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* prevent parent from waiting if there was an error */ 7187c478bd9Sstevel@tonic-gate if (pid < 0) 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate errno = save_errno; 7217c478bd9Sstevel@tonic-gate syserr("deliver: fork 2"); 7227c478bd9Sstevel@tonic-gate #if HASFLOCK 7237c478bd9Sstevel@tonic-gate e->e_flags |= EF_INQUEUE; 7247c478bd9Sstevel@tonic-gate #else /* HASFLOCK */ 7257c478bd9Sstevel@tonic-gate e->e_id = NULL; 7267c478bd9Sstevel@tonic-gate #endif /* HASFLOCK */ 7277c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* be sure to give error messages in child */ 7317c478bd9Sstevel@tonic-gate QuickAbort = false; 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate ** Close any cached connections. 7357c478bd9Sstevel@tonic-gate ** 7367c478bd9Sstevel@tonic-gate ** We don't send the QUIT protocol because the parent 7377c478bd9Sstevel@tonic-gate ** still knows about the connection. 7387c478bd9Sstevel@tonic-gate ** 7397c478bd9Sstevel@tonic-gate ** This should only happen when delivering an error 7407c478bd9Sstevel@tonic-gate ** message. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate mci_flush(false, NULL); 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate #if HASFLOCK 7467c478bd9Sstevel@tonic-gate break; 7477c478bd9Sstevel@tonic-gate #else /* HASFLOCK */ 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* 7507c478bd9Sstevel@tonic-gate ** Now reacquire and run the various queue files. 7517c478bd9Sstevel@tonic-gate */ 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 7547c478bd9Sstevel@tonic-gate { 7557c478bd9Sstevel@tonic-gate ENVELOPE *sibling = ee->e_sibling; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id, 7587c478bd9Sstevel@tonic-gate false, false, ee); 7597c478bd9Sstevel@tonic-gate ee->e_sibling = sibling; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate (void) dowork(e->e_qgrp, e->e_qdir, e->e_id, 7627c478bd9Sstevel@tonic-gate false, false, e); 7637c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 7647c478bd9Sstevel@tonic-gate #endif /* HASFLOCK */ 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate sendenvelope(e, mode); 7687c478bd9Sstevel@tonic-gate dropenvelope(e, true, true); 7697c478bd9Sstevel@tonic-gate for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 7707c478bd9Sstevel@tonic-gate { 7717c478bd9Sstevel@tonic-gate CurEnv = ee; 7727c478bd9Sstevel@tonic-gate if (mode != SM_VERIFY) 7737c478bd9Sstevel@tonic-gate openxscript(ee); 7747c478bd9Sstevel@tonic-gate sendenvelope(ee, mode); 7757c478bd9Sstevel@tonic-gate dropenvelope(ee, true, true); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate CurEnv = e; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate Verbose = oldverbose; 7807c478bd9Sstevel@tonic-gate if (mode == SM_FORK) 7817c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate static void 7857c478bd9Sstevel@tonic-gate sendenvelope(e, mode) 7867c478bd9Sstevel@tonic-gate register ENVELOPE *e; 7877c478bd9Sstevel@tonic-gate int mode; 7887c478bd9Sstevel@tonic-gate { 7897c478bd9Sstevel@tonic-gate register ADDRESS *q; 7907c478bd9Sstevel@tonic-gate bool didany; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate if (tTd(13, 10)) 7937c478bd9Sstevel@tonic-gate sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n", 7947c478bd9Sstevel@tonic-gate e->e_id == NULL ? "[NOQUEUE]" : e->e_id, 7957c478bd9Sstevel@tonic-gate e->e_flags); 7967c478bd9Sstevel@tonic-gate if (LogLevel > 80) 7977c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 7987c478bd9Sstevel@tonic-gate "sendenvelope, flags=0x%lx", 7997c478bd9Sstevel@tonic-gate e->e_flags); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate ** If we have had global, fatal errors, don't bother sending 8037c478bd9Sstevel@tonic-gate ** the message at all if we are in SMTP mode. Local errors 8047c478bd9Sstevel@tonic-gate ** (e.g., a single address failing) will still cause the other 8057c478bd9Sstevel@tonic-gate ** addresses to be sent. 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate if (bitset(EF_FATALERRS, e->e_flags) && 8097c478bd9Sstevel@tonic-gate (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 8127c478bd9Sstevel@tonic-gate return; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* 8167c478bd9Sstevel@tonic-gate ** Don't attempt deliveries if we want to bounce now 8177c478bd9Sstevel@tonic-gate ** or if deliver-by time is exceeded. 8187c478bd9Sstevel@tonic-gate */ 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (!bitset(EF_RESPONSE, e->e_flags) && 8217c478bd9Sstevel@tonic-gate (TimeOuts.to_q_return[e->e_timeoutclass] == NOW || 8227c478bd9Sstevel@tonic-gate (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 && 8237c478bd9Sstevel@tonic-gate curtime() > e->e_ctime + e->e_deliver_by))) 8247c478bd9Sstevel@tonic-gate return; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate ** Run through the list and send everything. 8287c478bd9Sstevel@tonic-gate ** 8297c478bd9Sstevel@tonic-gate ** Set EF_GLOBALERRS so that error messages during delivery 8307c478bd9Sstevel@tonic-gate ** result in returned mail. 8317c478bd9Sstevel@tonic-gate */ 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate e->e_nsent = 0; 8347c478bd9Sstevel@tonic-gate e->e_flags |= EF_GLOBALERRS; 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid); 8377c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype); 8387c478bd9Sstevel@tonic-gate didany = false; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (!bitset(EF_SPLIT, e->e_flags)) 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate ENVELOPE *oldsib; 8437c478bd9Sstevel@tonic-gate ENVELOPE *ee; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate /* 8467c478bd9Sstevel@tonic-gate ** Save old sibling and set it to NULL to avoid 8477c478bd9Sstevel@tonic-gate ** queueing up the same envelopes again. 8487c478bd9Sstevel@tonic-gate ** This requires that envelopes in that list have 8497c478bd9Sstevel@tonic-gate ** been take care of before (or at some other place). 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate oldsib = e->e_sibling; 8537c478bd9Sstevel@tonic-gate e->e_sibling = NULL; 8547c478bd9Sstevel@tonic-gate if (!split_by_recipient(e) && 8557c478bd9Sstevel@tonic-gate bitset(EF_FATALERRS, e->e_flags)) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 8587c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 8597c478bd9Sstevel@tonic-gate return; 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 8627c478bd9Sstevel@tonic-gate queueup(ee, false, true); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* clean up */ 8657c478bd9Sstevel@tonic-gate for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) 8667c478bd9Sstevel@tonic-gate { 8677c478bd9Sstevel@tonic-gate /* now unlock the job */ 8687c478bd9Sstevel@tonic-gate closexscript(ee); 8697c478bd9Sstevel@tonic-gate unlockqueue(ee); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* this envelope is marked unused */ 8727c478bd9Sstevel@tonic-gate if (ee->e_dfp != NULL) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 8757c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate ee->e_id = NULL; 8787c478bd9Sstevel@tonic-gate ee->e_flags &= ~EF_HAS_DF; 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate e->e_sibling = oldsib; 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* now run through the queue */ 8847c478bd9Sstevel@tonic-gate for (q = e->e_sendqueue; q != NULL; q = q->q_next) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate #if XDEBUG 8877c478bd9Sstevel@tonic-gate char wbuf[MAXNAME + 20]; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate (void) sm_snprintf(wbuf, sizeof wbuf, "sendall(%.*s)", 8907c478bd9Sstevel@tonic-gate MAXNAME, q->q_paddr); 8917c478bd9Sstevel@tonic-gate checkfd012(wbuf); 8927c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 8937c478bd9Sstevel@tonic-gate if (mode == SM_VERIFY) 8947c478bd9Sstevel@tonic-gate { 8957c478bd9Sstevel@tonic-gate e->e_to = q->q_paddr; 8967c478bd9Sstevel@tonic-gate if (QS_IS_SENDABLE(q->q_state)) 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate if (q->q_host != NULL && q->q_host[0] != '\0') 8997c478bd9Sstevel@tonic-gate message("deliverable: mailer %s, host %s, user %s", 9007c478bd9Sstevel@tonic-gate q->q_mailer->m_name, 9017c478bd9Sstevel@tonic-gate q->q_host, 9027c478bd9Sstevel@tonic-gate q->q_user); 9037c478bd9Sstevel@tonic-gate else 9047c478bd9Sstevel@tonic-gate message("deliverable: mailer %s, user %s", 9057c478bd9Sstevel@tonic-gate q->q_mailer->m_name, 9067c478bd9Sstevel@tonic-gate q->q_user); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate else if (QS_IS_OK(q->q_state)) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate ** Checkpoint the send list every few addresses 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate if (CheckpointInterval > 0 && 9167c478bd9Sstevel@tonic-gate e->e_nsent >= CheckpointInterval) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate queueup(e, false, false); 9197c478bd9Sstevel@tonic-gate e->e_nsent = 0; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate (void) deliver(e, q); 9227c478bd9Sstevel@tonic-gate didany = true; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate if (didany) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate e->e_dtime = curtime(); 9287c478bd9Sstevel@tonic-gate e->e_ntries++; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate #if XDEBUG 9327c478bd9Sstevel@tonic-gate checkfd012("end of sendenvelope"); 9337c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate #if REQUIRES_DIR_FSYNC 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate ** SYNC_DIR -- fsync a directory based on a filename 9397c478bd9Sstevel@tonic-gate ** 9407c478bd9Sstevel@tonic-gate ** Parameters: 9417c478bd9Sstevel@tonic-gate ** filename -- path of file 9427c478bd9Sstevel@tonic-gate ** panic -- panic? 9437c478bd9Sstevel@tonic-gate ** 9447c478bd9Sstevel@tonic-gate ** Returns: 9457c478bd9Sstevel@tonic-gate ** none 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate void 9497c478bd9Sstevel@tonic-gate sync_dir(filename, panic) 9507c478bd9Sstevel@tonic-gate char *filename; 9517c478bd9Sstevel@tonic-gate bool panic; 9527c478bd9Sstevel@tonic-gate { 9537c478bd9Sstevel@tonic-gate int dirfd; 9547c478bd9Sstevel@tonic-gate char *dirp; 9557c478bd9Sstevel@tonic-gate char dir[MAXPATHLEN]; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (!RequiresDirfsync) 9587c478bd9Sstevel@tonic-gate return; 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* filesystems which require the directory be synced */ 9617c478bd9Sstevel@tonic-gate dirp = strrchr(filename, '/'); 9627c478bd9Sstevel@tonic-gate if (dirp != NULL) 9637c478bd9Sstevel@tonic-gate { 9647c478bd9Sstevel@tonic-gate if (sm_strlcpy(dir, filename, sizeof dir) >= sizeof dir) 9657c478bd9Sstevel@tonic-gate return; 9667c478bd9Sstevel@tonic-gate dir[dirp - filename] = '\0'; 9677c478bd9Sstevel@tonic-gate dirp = dir; 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate else 9707c478bd9Sstevel@tonic-gate dirp = "."; 9717c478bd9Sstevel@tonic-gate dirfd = open(dirp, O_RDONLY, 0700); 9727c478bd9Sstevel@tonic-gate if (tTd(40,32)) 9737c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)", 9747c478bd9Sstevel@tonic-gate dirp, dirfd); 9757c478bd9Sstevel@tonic-gate if (dirfd >= 0) 9767c478bd9Sstevel@tonic-gate { 9777c478bd9Sstevel@tonic-gate if (fsync(dirfd) < 0) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate if (panic) 9807c478bd9Sstevel@tonic-gate syserr("!sync_dir: cannot fsync directory %s", 9817c478bd9Sstevel@tonic-gate dirp); 9827c478bd9Sstevel@tonic-gate else if (LogLevel > 1) 9837c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 9847c478bd9Sstevel@tonic-gate "sync_dir: cannot fsync directory %s: %s", 9857c478bd9Sstevel@tonic-gate dirp, sm_errstring(errno)); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate (void) close(dirfd); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate #endif /* REQUIRES_DIR_FSYNC */ 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate ** DUP_QUEUE_FILE -- duplicate a queue file into a split queue 9937c478bd9Sstevel@tonic-gate ** 9947c478bd9Sstevel@tonic-gate ** Parameters: 9957c478bd9Sstevel@tonic-gate ** e -- the existing envelope 9967c478bd9Sstevel@tonic-gate ** ee -- the new envelope 9977c478bd9Sstevel@tonic-gate ** type -- the queue file type (e.g., DATAFL_LETTER) 9987c478bd9Sstevel@tonic-gate ** 9997c478bd9Sstevel@tonic-gate ** Returns: 10007c478bd9Sstevel@tonic-gate ** none 10017c478bd9Sstevel@tonic-gate */ 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate static void 10047c478bd9Sstevel@tonic-gate dup_queue_file(e, ee, type) 10057c478bd9Sstevel@tonic-gate ENVELOPE *e, *ee; 10067c478bd9Sstevel@tonic-gate int type; 10077c478bd9Sstevel@tonic-gate { 10087c478bd9Sstevel@tonic-gate char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN]; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 10117c478bd9Sstevel@tonic-gate ee->e_xfp = NULL; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate ** Make sure both are in the same directory. 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate (void) sm_strlcpy(f1buf, queuename(e, type), sizeof f1buf); 10187c478bd9Sstevel@tonic-gate (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof f2buf); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* Force the df to disk if it's not there yet */ 10217c478bd9Sstevel@tonic-gate if (type == DATAFL_LETTER && e->e_dfp != NULL && 10227c478bd9Sstevel@tonic-gate sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && 10237c478bd9Sstevel@tonic-gate errno != EINVAL) 10247c478bd9Sstevel@tonic-gate { 10257c478bd9Sstevel@tonic-gate syserr("!dup_queue_file: can't commit %s", f1buf); 10267c478bd9Sstevel@tonic-gate /* NOTREACHED */ 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate if (link(f1buf, f2buf) < 0) 10307c478bd9Sstevel@tonic-gate { 10317c478bd9Sstevel@tonic-gate int save_errno = errno; 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate syserr("sendall: link(%s, %s)", f1buf, f2buf); 10347c478bd9Sstevel@tonic-gate if (save_errno == EEXIST) 10357c478bd9Sstevel@tonic-gate { 10367c478bd9Sstevel@tonic-gate if (unlink(f2buf) < 0) 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate syserr("!sendall: unlink(%s): permanent", 10397c478bd9Sstevel@tonic-gate f2buf); 10407c478bd9Sstevel@tonic-gate /* NOTREACHED */ 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate if (link(f1buf, f2buf) < 0) 10437c478bd9Sstevel@tonic-gate { 10447c478bd9Sstevel@tonic-gate syserr("!sendall: link(%s, %s): permanent", 10457c478bd9Sstevel@tonic-gate f1buf, f2buf); 10467c478bd9Sstevel@tonic-gate /* NOTREACHED */ 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate SYNC_DIR(f2buf, true); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate ** DOFORK -- do a fork, retrying a couple of times on failure. 10547c478bd9Sstevel@tonic-gate ** 10557c478bd9Sstevel@tonic-gate ** This MUST be a macro, since after a vfork we are running 10567c478bd9Sstevel@tonic-gate ** two processes on the same stack!!! 10577c478bd9Sstevel@tonic-gate ** 10587c478bd9Sstevel@tonic-gate ** Parameters: 10597c478bd9Sstevel@tonic-gate ** none. 10607c478bd9Sstevel@tonic-gate ** 10617c478bd9Sstevel@tonic-gate ** Returns: 10627c478bd9Sstevel@tonic-gate ** From a macro??? You've got to be kidding! 10637c478bd9Sstevel@tonic-gate ** 10647c478bd9Sstevel@tonic-gate ** Side Effects: 10657c478bd9Sstevel@tonic-gate ** Modifies the ==> LOCAL <== variable 'pid', leaving: 10667c478bd9Sstevel@tonic-gate ** pid of child in parent, zero in child. 10677c478bd9Sstevel@tonic-gate ** -1 on unrecoverable error. 10687c478bd9Sstevel@tonic-gate ** 10697c478bd9Sstevel@tonic-gate ** Notes: 10707c478bd9Sstevel@tonic-gate ** I'm awfully sorry this looks so awful. That's 10717c478bd9Sstevel@tonic-gate ** vfork for you..... 10727c478bd9Sstevel@tonic-gate */ 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate #define NFORKTRIES 5 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate #ifndef FORK 10777c478bd9Sstevel@tonic-gate # define FORK fork 10787c478bd9Sstevel@tonic-gate #endif /* ! FORK */ 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate #define DOFORK(fORKfN) \ 10817c478bd9Sstevel@tonic-gate {\ 10827c478bd9Sstevel@tonic-gate register int i;\ 10837c478bd9Sstevel@tonic-gate \ 10847c478bd9Sstevel@tonic-gate for (i = NFORKTRIES; --i >= 0; )\ 10857c478bd9Sstevel@tonic-gate {\ 10867c478bd9Sstevel@tonic-gate pid = fORKfN();\ 10877c478bd9Sstevel@tonic-gate if (pid >= 0)\ 10887c478bd9Sstevel@tonic-gate break;\ 10897c478bd9Sstevel@tonic-gate if (i > 0)\ 10907c478bd9Sstevel@tonic-gate (void) sleep((unsigned) NFORKTRIES - i);\ 10917c478bd9Sstevel@tonic-gate }\ 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate /* 10947c478bd9Sstevel@tonic-gate ** DOFORK -- simple fork interface to DOFORK. 10957c478bd9Sstevel@tonic-gate ** 10967c478bd9Sstevel@tonic-gate ** Parameters: 10977c478bd9Sstevel@tonic-gate ** none. 10987c478bd9Sstevel@tonic-gate ** 10997c478bd9Sstevel@tonic-gate ** Returns: 11007c478bd9Sstevel@tonic-gate ** pid of child in parent. 11017c478bd9Sstevel@tonic-gate ** zero in child. 11027c478bd9Sstevel@tonic-gate ** -1 on error. 11037c478bd9Sstevel@tonic-gate ** 11047c478bd9Sstevel@tonic-gate ** Side Effects: 11057c478bd9Sstevel@tonic-gate ** returns twice, once in parent and once in child. 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate pid_t 11097c478bd9Sstevel@tonic-gate dofork() 11107c478bd9Sstevel@tonic-gate { 11117c478bd9Sstevel@tonic-gate register pid_t pid = -1; 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate DOFORK(fork); 11147c478bd9Sstevel@tonic-gate return pid; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate ** COLONCMP -- compare host-signatures up to first ':' or EOS 11197c478bd9Sstevel@tonic-gate ** 11207c478bd9Sstevel@tonic-gate ** This takes two strings which happen to be host-signatures and 11217c478bd9Sstevel@tonic-gate ** compares them. If the lowest preference portions of the MX-RR's 11227c478bd9Sstevel@tonic-gate ** match (up to ':' or EOS, whichever is first), then we have 11237c478bd9Sstevel@tonic-gate ** match. This is used for coattail-piggybacking messages during 11247c478bd9Sstevel@tonic-gate ** message delivery. 11257c478bd9Sstevel@tonic-gate ** If the signatures are the same up to the first ':' the remainder of 11267c478bd9Sstevel@tonic-gate ** the signatures are then compared with a normal strcmp(). This saves 11277c478bd9Sstevel@tonic-gate ** re-examining the first part of the signatures. 11287c478bd9Sstevel@tonic-gate ** 11297c478bd9Sstevel@tonic-gate ** Parameters: 11307c478bd9Sstevel@tonic-gate ** a - first host-signature 11317c478bd9Sstevel@tonic-gate ** b - second host-signature 11327c478bd9Sstevel@tonic-gate ** 11337c478bd9Sstevel@tonic-gate ** Returns: 11347c478bd9Sstevel@tonic-gate ** HS_MATCH_NO -- no "match". 11357c478bd9Sstevel@tonic-gate ** HS_MATCH_FIRST -- "match" for the first MX preference 11367c478bd9Sstevel@tonic-gate ** (up to the first colon (':')). 11377c478bd9Sstevel@tonic-gate ** HS_MATCH_FULL -- match for the entire MX record. 11387c478bd9Sstevel@tonic-gate ** 11397c478bd9Sstevel@tonic-gate ** Side Effects: 11407c478bd9Sstevel@tonic-gate ** none. 11417c478bd9Sstevel@tonic-gate */ 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate #define HS_MATCH_NO 0 11447c478bd9Sstevel@tonic-gate #define HS_MATCH_FIRST 1 11457c478bd9Sstevel@tonic-gate #define HS_MATCH_FULL 2 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate static int 11487c478bd9Sstevel@tonic-gate coloncmp(a, b) 11497c478bd9Sstevel@tonic-gate register const char *a; 11507c478bd9Sstevel@tonic-gate register const char *b; 11517c478bd9Sstevel@tonic-gate { 11527c478bd9Sstevel@tonic-gate int ret = HS_MATCH_NO; 11537c478bd9Sstevel@tonic-gate int braclev = 0; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate while (*a == *b++) 11567c478bd9Sstevel@tonic-gate { 11577c478bd9Sstevel@tonic-gate /* Need to account for IPv6 bracketed addresses */ 11587c478bd9Sstevel@tonic-gate if (*a == '[') 11597c478bd9Sstevel@tonic-gate braclev++; 11607c478bd9Sstevel@tonic-gate else if (*a == ']' && braclev > 0) 11617c478bd9Sstevel@tonic-gate braclev--; 11627c478bd9Sstevel@tonic-gate else if (*a == ':' && braclev <= 0) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate ret = HS_MATCH_FIRST; 11657c478bd9Sstevel@tonic-gate a++; 11667c478bd9Sstevel@tonic-gate break; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate else if (*a == '\0') 11697c478bd9Sstevel@tonic-gate return HS_MATCH_FULL; /* a full match */ 11707c478bd9Sstevel@tonic-gate a++; 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate if (ret == HS_MATCH_NO && 11737c478bd9Sstevel@tonic-gate braclev <= 0 && 11747c478bd9Sstevel@tonic-gate ((*a == '\0' && *(b - 1) == ':') || 11757c478bd9Sstevel@tonic-gate (*a == ':' && *(b - 1) == '\0'))) 11767c478bd9Sstevel@tonic-gate return HS_MATCH_FIRST; 11777c478bd9Sstevel@tonic-gate if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0) 11787c478bd9Sstevel@tonic-gate return HS_MATCH_FULL; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate return ret; 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* 11847c478bd9Sstevel@tonic-gate ** SHOULD_TRY_FBSH -- Should try FallbackSmartHost? 11857c478bd9Sstevel@tonic-gate ** 11867c478bd9Sstevel@tonic-gate ** Parameters: 11877c478bd9Sstevel@tonic-gate ** e -- envelope 11887c478bd9Sstevel@tonic-gate ** tried_fallbacksmarthost -- has been tried already? (in/out) 11897c478bd9Sstevel@tonic-gate ** hostbuf -- buffer for hostname (expand FallbackSmartHost) (out) 11907c478bd9Sstevel@tonic-gate ** hbsz -- size of hostbuf 11917c478bd9Sstevel@tonic-gate ** status -- current delivery status 11927c478bd9Sstevel@tonic-gate ** 11937c478bd9Sstevel@tonic-gate ** Returns: 11947c478bd9Sstevel@tonic-gate ** true iff FallbackSmartHost should be tried. 11957c478bd9Sstevel@tonic-gate */ 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate static bool 11987c478bd9Sstevel@tonic-gate should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status) 11997c478bd9Sstevel@tonic-gate ENVELOPE *e; 12007c478bd9Sstevel@tonic-gate bool *tried_fallbacksmarthost; 12017c478bd9Sstevel@tonic-gate char *hostbuf; 12027c478bd9Sstevel@tonic-gate size_t hbsz; 12037c478bd9Sstevel@tonic-gate int status; 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate /* 120649218d4fSjbeck ** If the host was not found or a temporary failure occurred 120749218d4fSjbeck ** and a FallbackSmartHost is defined (and we have not yet 120849218d4fSjbeck ** tried it), then make one last try with it as the host. 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate 121149218d4fSjbeck if ((status == EX_NOHOST || status == EX_TEMPFAIL) && 121249218d4fSjbeck FallbackSmartHost != NULL && !*tried_fallbacksmarthost) 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate *tried_fallbacksmarthost = true; 12157c478bd9Sstevel@tonic-gate expand(FallbackSmartHost, hostbuf, hbsz, e); 12167c478bd9Sstevel@tonic-gate if (!wordinclass(hostbuf, 'w')) 12177c478bd9Sstevel@tonic-gate { 12187c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 12197c478bd9Sstevel@tonic-gate sm_dprintf("one last try with FallbackSmartHost %s\n", 12207c478bd9Sstevel@tonic-gate hostbuf); 12217c478bd9Sstevel@tonic-gate return true; 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate return false; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate /* 12277c478bd9Sstevel@tonic-gate ** DELIVER -- Deliver a message to a list of addresses. 12287c478bd9Sstevel@tonic-gate ** 12297c478bd9Sstevel@tonic-gate ** This routine delivers to everyone on the same host as the 12307c478bd9Sstevel@tonic-gate ** user on the head of the list. It is clever about mailers 12317c478bd9Sstevel@tonic-gate ** that don't handle multiple users. It is NOT guaranteed 12327c478bd9Sstevel@tonic-gate ** that it will deliver to all these addresses however -- so 12337c478bd9Sstevel@tonic-gate ** deliver should be called once for each address on the 12347c478bd9Sstevel@tonic-gate ** list. 12357c478bd9Sstevel@tonic-gate ** Deliver tries to be as opportunistic as possible about piggybacking 12367c478bd9Sstevel@tonic-gate ** messages. Some definitions to make understanding easier follow below. 12377c478bd9Sstevel@tonic-gate ** Piggybacking occurs when an existing connection to a mail host can 12387c478bd9Sstevel@tonic-gate ** be used to send the same message to more than one recipient at the 12397c478bd9Sstevel@tonic-gate ** same time. So "no piggybacking" means one message for one recipient 12407c478bd9Sstevel@tonic-gate ** per connection. "Intentional piggybacking" happens when the 12417c478bd9Sstevel@tonic-gate ** recipients' host address (not the mail host address) is used to 12427c478bd9Sstevel@tonic-gate ** attempt piggybacking. Recipients with the same host address 12437c478bd9Sstevel@tonic-gate ** have the same mail host. "Coincidental piggybacking" relies on 12447c478bd9Sstevel@tonic-gate ** piggybacking based on all the mail host addresses in the MX-RR. This 12457c478bd9Sstevel@tonic-gate ** is "coincidental" in the fact it could not be predicted until the 12467c478bd9Sstevel@tonic-gate ** MX Resource Records for the hosts were obtained and examined. For 12477c478bd9Sstevel@tonic-gate ** example (preference order and equivalence is important, not values): 12487c478bd9Sstevel@tonic-gate ** domain1 IN MX 10 mxhost-A 12497c478bd9Sstevel@tonic-gate ** IN MX 20 mxhost-B 12507c478bd9Sstevel@tonic-gate ** domain2 IN MX 4 mxhost-A 12517c478bd9Sstevel@tonic-gate ** IN MX 8 mxhost-B 12527c478bd9Sstevel@tonic-gate ** Domain1 and domain2 can piggyback the same message to mxhost-A or 12537c478bd9Sstevel@tonic-gate ** mxhost-B (if mxhost-A cannot be reached). 12547c478bd9Sstevel@tonic-gate ** "Coattail piggybacking" relaxes the strictness of "coincidental 12557c478bd9Sstevel@tonic-gate ** piggybacking" in the hope that most significant (lowest value) 12567c478bd9Sstevel@tonic-gate ** MX preference host(s) can create more piggybacking. For example 12577c478bd9Sstevel@tonic-gate ** (again, preference order and equivalence is important, not values): 12587c478bd9Sstevel@tonic-gate ** domain3 IN MX 100 mxhost-C 12597c478bd9Sstevel@tonic-gate ** IN MX 100 mxhost-D 12607c478bd9Sstevel@tonic-gate ** IN MX 200 mxhost-E 12617c478bd9Sstevel@tonic-gate ** domain4 IN MX 50 mxhost-C 12627c478bd9Sstevel@tonic-gate ** IN MX 50 mxhost-D 12637c478bd9Sstevel@tonic-gate ** IN MX 80 mxhost-F 12647c478bd9Sstevel@tonic-gate ** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C 12657c478bd9Sstevel@tonic-gate ** is available. Same with mxhost-D because in both RR's the preference 12667c478bd9Sstevel@tonic-gate ** value is the same as mxhost-C, respectively. 12677c478bd9Sstevel@tonic-gate ** So deliver attempts coattail piggybacking when possible. If the 12687c478bd9Sstevel@tonic-gate ** first MX preference level hosts cannot be used then the piggybacking 12697c478bd9Sstevel@tonic-gate ** reverts to coincidental piggybacking. Using the above example you 12707c478bd9Sstevel@tonic-gate ** cannot deliver to mxhost-F for domain3 regardless of preference value. 12717c478bd9Sstevel@tonic-gate ** ("Coattail" from "riding on the coattails of your predecessor" meaning 12727c478bd9Sstevel@tonic-gate ** gaining benefit from a predecessor effort with no or little addition 12737c478bd9Sstevel@tonic-gate ** effort. The predecessor here being the preceding MX RR). 12747c478bd9Sstevel@tonic-gate ** 12757c478bd9Sstevel@tonic-gate ** Parameters: 12767c478bd9Sstevel@tonic-gate ** e -- the envelope to deliver. 12777c478bd9Sstevel@tonic-gate ** firstto -- head of the address list to deliver to. 12787c478bd9Sstevel@tonic-gate ** 12797c478bd9Sstevel@tonic-gate ** Returns: 12807c478bd9Sstevel@tonic-gate ** zero -- successfully delivered. 12817c478bd9Sstevel@tonic-gate ** else -- some failure, see ExitStat for more info. 12827c478bd9Sstevel@tonic-gate ** 12837c478bd9Sstevel@tonic-gate ** Side Effects: 12847c478bd9Sstevel@tonic-gate ** The standard input is passed off to someone. 12857c478bd9Sstevel@tonic-gate */ 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate static int 12887c478bd9Sstevel@tonic-gate deliver(e, firstto) 12897c478bd9Sstevel@tonic-gate register ENVELOPE *e; 12907c478bd9Sstevel@tonic-gate ADDRESS *firstto; 12917c478bd9Sstevel@tonic-gate { 12927c478bd9Sstevel@tonic-gate char *host; /* host being sent to */ 12937c478bd9Sstevel@tonic-gate char *user; /* user being sent to */ 12947c478bd9Sstevel@tonic-gate char **pvp; 12957c478bd9Sstevel@tonic-gate register char **mvp; 12967c478bd9Sstevel@tonic-gate register char *p; 12977c478bd9Sstevel@tonic-gate register MAILER *m; /* mailer for this recipient */ 12987c478bd9Sstevel@tonic-gate ADDRESS *volatile ctladdr; 12997c478bd9Sstevel@tonic-gate #if HASSETUSERCONTEXT 13007c478bd9Sstevel@tonic-gate ADDRESS *volatile contextaddr = NULL; 13017c478bd9Sstevel@tonic-gate #endif /* HASSETUSERCONTEXT */ 13027c478bd9Sstevel@tonic-gate register MCI *volatile mci; 13037c478bd9Sstevel@tonic-gate register ADDRESS *SM_NONVOLATILE to = firstto; 13047c478bd9Sstevel@tonic-gate volatile bool clever = false; /* running user smtp to this mailer */ 13057c478bd9Sstevel@tonic-gate ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */ 13067c478bd9Sstevel@tonic-gate int rcode; /* response code */ 13077c478bd9Sstevel@tonic-gate SM_NONVOLATILE int lmtp_rcode = EX_OK; 13087c478bd9Sstevel@tonic-gate SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */ 13097c478bd9Sstevel@tonic-gate SM_NONVOLATILE int hostnum = 0; /* current MX host index */ 13107c478bd9Sstevel@tonic-gate char *firstsig; /* signature of firstto */ 13117c478bd9Sstevel@tonic-gate volatile pid_t pid = -1; 13127c478bd9Sstevel@tonic-gate char *volatile curhost; 13137c478bd9Sstevel@tonic-gate SM_NONVOLATILE unsigned short port = 0; 13147c478bd9Sstevel@tonic-gate SM_NONVOLATILE time_t enough = 0; 13157c478bd9Sstevel@tonic-gate #if NETUNIX 13167c478bd9Sstevel@tonic-gate char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */ 13177c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 13187c478bd9Sstevel@tonic-gate time_t xstart; 13197c478bd9Sstevel@tonic-gate bool suidwarn; 13207c478bd9Sstevel@tonic-gate bool anyok; /* at least one address was OK */ 13217c478bd9Sstevel@tonic-gate SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ 13227c478bd9Sstevel@tonic-gate bool ovr; 13237c478bd9Sstevel@tonic-gate bool quarantine; 13247c478bd9Sstevel@tonic-gate int strsize; 13257c478bd9Sstevel@tonic-gate int rcptcount; 13267c478bd9Sstevel@tonic-gate int ret; 13277c478bd9Sstevel@tonic-gate static int tobufsize = 0; 13287c478bd9Sstevel@tonic-gate static char *tobuf = NULL; 13297c478bd9Sstevel@tonic-gate char *rpath; /* translated return path */ 13307c478bd9Sstevel@tonic-gate int mpvect[2]; 13317c478bd9Sstevel@tonic-gate int rpvect[2]; 13327c478bd9Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 13337c478bd9Sstevel@tonic-gate char *pv[MAXPV + 1]; 13347c478bd9Sstevel@tonic-gate char buf[MAXNAME + 1]; 13357c478bd9Sstevel@tonic-gate char cbuf[MAXPATHLEN]; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate errno = 0; 13387c478bd9Sstevel@tonic-gate if (!QS_IS_OK(to->q_state)) 13397c478bd9Sstevel@tonic-gate return 0; 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate suidwarn = geteuid() == 0; 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate m = to->q_mailer; 13447c478bd9Sstevel@tonic-gate host = to->q_host; 13457c478bd9Sstevel@tonic-gate CurEnv = e; /* just in case */ 13467c478bd9Sstevel@tonic-gate e->e_statmsg = NULL; 13477c478bd9Sstevel@tonic-gate SmtpError[0] = '\0'; 13487c478bd9Sstevel@tonic-gate xstart = curtime(); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate if (tTd(10, 1)) 13517c478bd9Sstevel@tonic-gate sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 13527c478bd9Sstevel@tonic-gate e->e_id, m->m_name, host, to->q_user); 13537c478bd9Sstevel@tonic-gate if (tTd(10, 100)) 13547c478bd9Sstevel@tonic-gate printopenfds(false); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate ** Clear {client_*} macros if this is a bounce message to 13587c478bd9Sstevel@tonic-gate ** prevent rejection by check_compat ruleset. 13597c478bd9Sstevel@tonic-gate */ 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags)) 13627c478bd9Sstevel@tonic-gate { 13637c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); 13647c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), ""); 13657c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); 13667c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); 13677c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate SM_TRY 13717c478bd9Sstevel@tonic-gate { 13727c478bd9Sstevel@tonic-gate ADDRESS *skip_back = NULL; 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate /* 13757c478bd9Sstevel@tonic-gate ** Do initial argv setup. 13767c478bd9Sstevel@tonic-gate ** Insert the mailer name. Notice that $x expansion is 13777c478bd9Sstevel@tonic-gate ** NOT done on the mailer name. Then, if the mailer has 13787c478bd9Sstevel@tonic-gate ** a picky -f flag, we insert it as appropriate. This 13797c478bd9Sstevel@tonic-gate ** code does not check for 'pv' overflow; this places a 13807c478bd9Sstevel@tonic-gate ** manifest lower limit of 4 for MAXPV. 13817c478bd9Sstevel@tonic-gate ** The from address rewrite is expected to make 13827c478bd9Sstevel@tonic-gate ** the address relative to the other end. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* rewrite from address, using rewriting rules */ 13867c478bd9Sstevel@tonic-gate rcode = EX_OK; 13877c478bd9Sstevel@tonic-gate if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 13887c478bd9Sstevel@tonic-gate p = e->e_sender; 13897c478bd9Sstevel@tonic-gate else 13907c478bd9Sstevel@tonic-gate p = e->e_from.q_paddr; 13917c478bd9Sstevel@tonic-gate rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); 13927c478bd9Sstevel@tonic-gate if (strlen(rpath) > MAXSHORTSTR) 13937c478bd9Sstevel@tonic-gate { 13947c478bd9Sstevel@tonic-gate rpath = shortenstring(rpath, MAXSHORTSTR); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* avoid bogus errno */ 13977c478bd9Sstevel@tonic-gate errno = 0; 13987c478bd9Sstevel@tonic-gate syserr("remotename: huge return path %s", rpath); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate rpath = sm_rpool_strdup_x(e->e_rpool, rpath); 14017c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', rpath); 14027c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'h', host); 14037c478bd9Sstevel@tonic-gate Errors = 0; 14047c478bd9Sstevel@tonic-gate pvp = pv; 14057c478bd9Sstevel@tonic-gate *pvp++ = m->m_argv[0]; 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /* ignore long term host status information if mailer flag W is set */ 14087c478bd9Sstevel@tonic-gate if (bitnset(M_NOHOSTSTAT, m->m_flags)) 14097c478bd9Sstevel@tonic-gate IgnoreHostStatus = true; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /* insert -f or -r flag as appropriate */ 14127c478bd9Sstevel@tonic-gate if (FromFlag && 14137c478bd9Sstevel@tonic-gate (bitnset(M_FOPT, m->m_flags) || 14147c478bd9Sstevel@tonic-gate bitnset(M_ROPT, m->m_flags))) 14157c478bd9Sstevel@tonic-gate { 14167c478bd9Sstevel@tonic-gate if (bitnset(M_FOPT, m->m_flags)) 14177c478bd9Sstevel@tonic-gate *pvp++ = "-f"; 14187c478bd9Sstevel@tonic-gate else 14197c478bd9Sstevel@tonic-gate *pvp++ = "-r"; 14207c478bd9Sstevel@tonic-gate *pvp++ = rpath; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate ** Append the other fixed parts of the argv. These run 14257c478bd9Sstevel@tonic-gate ** up to the first entry containing "$u". There can only 14267c478bd9Sstevel@tonic-gate ** be one of these, and there are only a few more slots 14277c478bd9Sstevel@tonic-gate ** in the pv after it. 14287c478bd9Sstevel@tonic-gate */ 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 14317c478bd9Sstevel@tonic-gate { 14327c478bd9Sstevel@tonic-gate /* can't use strchr here because of sign extension problems */ 14337c478bd9Sstevel@tonic-gate while (*p != '\0') 14347c478bd9Sstevel@tonic-gate { 14357c478bd9Sstevel@tonic-gate if ((*p++ & 0377) == MACROEXPAND) 14367c478bd9Sstevel@tonic-gate { 14377c478bd9Sstevel@tonic-gate if (*p == 'u') 14387c478bd9Sstevel@tonic-gate break; 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate if (*p != '\0') 14437c478bd9Sstevel@tonic-gate break; 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate /* this entry is safe -- go ahead and process it */ 14467c478bd9Sstevel@tonic-gate expand(*mvp, buf, sizeof buf, e); 14477c478bd9Sstevel@tonic-gate *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 14487c478bd9Sstevel@tonic-gate if (pvp >= &pv[MAXPV - 3]) 14497c478bd9Sstevel@tonic-gate { 14507c478bd9Sstevel@tonic-gate syserr("554 5.3.5 Too many parameters to %s before $u", 14517c478bd9Sstevel@tonic-gate pv[0]); 14527c478bd9Sstevel@tonic-gate rcode = -1; 14537c478bd9Sstevel@tonic-gate goto cleanup; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate ** If we have no substitution for the user name in the argument 14597c478bd9Sstevel@tonic-gate ** list, we know that we must supply the names otherwise -- and 14607c478bd9Sstevel@tonic-gate ** SMTP is the answer!! 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (*mvp == NULL) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate /* running LMTP or SMTP */ 14667c478bd9Sstevel@tonic-gate clever = true; 14677c478bd9Sstevel@tonic-gate *pvp = NULL; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate else if (bitnset(M_LMTP, m->m_flags)) 14707c478bd9Sstevel@tonic-gate { 14717c478bd9Sstevel@tonic-gate /* not running LMTP */ 14727c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NULL, 14737c478bd9Sstevel@tonic-gate "Warning: mailer %s: LMTP flag (F=z) turned off", 14747c478bd9Sstevel@tonic-gate m->m_name); 14757c478bd9Sstevel@tonic-gate clrbitn(M_LMTP, m->m_flags); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate ** At this point *mvp points to the argument with $u. We 14807c478bd9Sstevel@tonic-gate ** run through our address list and append all the addresses 14817c478bd9Sstevel@tonic-gate ** we can. If we run out of space, do not fret! We can 14827c478bd9Sstevel@tonic-gate ** always send another copy later. 14837c478bd9Sstevel@tonic-gate */ 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate e->e_to = NULL; 14867c478bd9Sstevel@tonic-gate strsize = 2; 14877c478bd9Sstevel@tonic-gate rcptcount = 0; 14887c478bd9Sstevel@tonic-gate ctladdr = NULL; 14897c478bd9Sstevel@tonic-gate if (firstto->q_signature == NULL) 14907c478bd9Sstevel@tonic-gate firstto->q_signature = hostsignature(firstto->q_mailer, 14917c478bd9Sstevel@tonic-gate firstto->q_host); 14927c478bd9Sstevel@tonic-gate firstsig = firstto->q_signature; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate for (; to != NULL; to = to->q_next) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate /* avoid sending multiple recipients to dumb mailers */ 14977c478bd9Sstevel@tonic-gate if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) 14987c478bd9Sstevel@tonic-gate break; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* if already sent or not for this host, don't send */ 15017c478bd9Sstevel@tonic-gate if (!QS_IS_OK(to->q_state)) /* already sent; look at next */ 15027c478bd9Sstevel@tonic-gate continue; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate ** Must be same mailer to keep grouping rcpts. 15067c478bd9Sstevel@tonic-gate ** If mailers don't match: continue; sendqueue is not 15077c478bd9Sstevel@tonic-gate ** sorted by mailers, so don't break; 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate if (to->q_mailer != firstto->q_mailer) 15117c478bd9Sstevel@tonic-gate continue; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate if (to->q_signature == NULL) /* for safety */ 15147c478bd9Sstevel@tonic-gate to->q_signature = hostsignature(to->q_mailer, 15157c478bd9Sstevel@tonic-gate to->q_host); 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate /* 15187c478bd9Sstevel@tonic-gate ** This is for coincidental and tailcoat piggybacking messages 15197c478bd9Sstevel@tonic-gate ** to the same mail host. While the signatures are identical 15207c478bd9Sstevel@tonic-gate ** (that's the MX-RR's are identical) we can do coincidental 15217c478bd9Sstevel@tonic-gate ** piggybacking. We try hard for coattail piggybacking 15227c478bd9Sstevel@tonic-gate ** with the same mail host when the next recipient has the 15237c478bd9Sstevel@tonic-gate ** same host at lowest preference. It may be that this 15247c478bd9Sstevel@tonic-gate ** won't work out, so 'skip_back' is maintained if a backup 15257c478bd9Sstevel@tonic-gate ** to coincidental piggybacking or full signature must happen. 15267c478bd9Sstevel@tonic-gate */ 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate ret = firstto == to ? HS_MATCH_FULL : 15297c478bd9Sstevel@tonic-gate coloncmp(to->q_signature, firstsig); 15307c478bd9Sstevel@tonic-gate if (ret == HS_MATCH_FULL) 15317c478bd9Sstevel@tonic-gate skip_back = to; 15327c478bd9Sstevel@tonic-gate else if (ret == HS_MATCH_NO) 15337c478bd9Sstevel@tonic-gate break; 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate if (!clever) 15367c478bd9Sstevel@tonic-gate { 15377c478bd9Sstevel@tonic-gate /* avoid overflowing tobuf */ 15387c478bd9Sstevel@tonic-gate strsize += strlen(to->q_paddr) + 1; 15397c478bd9Sstevel@tonic-gate if (strsize > TOBUFSIZE) 15407c478bd9Sstevel@tonic-gate break; 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate if (++rcptcount > to->q_mailer->m_maxrcpt) 15447c478bd9Sstevel@tonic-gate break; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if (tTd(10, 1)) 15477c478bd9Sstevel@tonic-gate { 15487c478bd9Sstevel@tonic-gate sm_dprintf("\nsend to "); 15497c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), to, false); 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate /* compute effective uid/gid when sending */ 15537c478bd9Sstevel@tonic-gate if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 15547c478bd9Sstevel@tonic-gate # if HASSETUSERCONTEXT 15557c478bd9Sstevel@tonic-gate contextaddr = ctladdr = getctladdr(to); 15567c478bd9Sstevel@tonic-gate # else /* HASSETUSERCONTEXT */ 15577c478bd9Sstevel@tonic-gate ctladdr = getctladdr(to); 15587c478bd9Sstevel@tonic-gate # endif /* HASSETUSERCONTEXT */ 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate if (tTd(10, 2)) 15617c478bd9Sstevel@tonic-gate { 15627c478bd9Sstevel@tonic-gate sm_dprintf("ctladdr="); 15637c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate user = to->q_user; 15677c478bd9Sstevel@tonic-gate e->e_to = to->q_paddr; 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate ** Check to see that these people are allowed to 15717c478bd9Sstevel@tonic-gate ** talk to each other. 15727c478bd9Sstevel@tonic-gate ** Check also for overflow of e_msgsize. 15737c478bd9Sstevel@tonic-gate */ 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (m->m_maxsize != 0 && 15767c478bd9Sstevel@tonic-gate (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) 15777c478bd9Sstevel@tonic-gate { 15787c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 15797c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) 15807c478bd9Sstevel@tonic-gate to->q_status = "5.2.3"; 15817c478bd9Sstevel@tonic-gate else 15827c478bd9Sstevel@tonic-gate to->q_status = "5.3.4"; 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* set to->q_rstatus = NULL; or to the following? */ 15857c478bd9Sstevel@tonic-gate usrerrenh(to->q_status, 15867c478bd9Sstevel@tonic-gate "552 Message is too large; %ld bytes max", 15877c478bd9Sstevel@tonic-gate m->m_maxsize); 15887c478bd9Sstevel@tonic-gate markfailure(e, to, NULL, EX_UNAVAILABLE, false); 15897c478bd9Sstevel@tonic-gate giveresponse(EX_UNAVAILABLE, to->q_status, m, 15907c478bd9Sstevel@tonic-gate NULL, ctladdr, xstart, e, to); 15917c478bd9Sstevel@tonic-gate continue; 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 15947c478bd9Sstevel@tonic-gate ovr = true; 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate /* do config file checking of compatibility */ 15977c478bd9Sstevel@tonic-gate quarantine = (e->e_quarmsg != NULL); 15987c478bd9Sstevel@tonic-gate rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, 15997c478bd9Sstevel@tonic-gate e, RSF_RMCOMM|RSF_COUNT, 3, NULL, 16007c478bd9Sstevel@tonic-gate e->e_id); 16017c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 16027c478bd9Sstevel@tonic-gate { 16037c478bd9Sstevel@tonic-gate /* do in-code checking if not discarding */ 16047c478bd9Sstevel@tonic-gate if (!bitset(EF_DISCARD, e->e_flags)) 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate rcode = checkcompat(to, e); 16077c478bd9Sstevel@tonic-gate ovr = false; 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate if (rcode != EX_OK) 16117c478bd9Sstevel@tonic-gate { 16127c478bd9Sstevel@tonic-gate markfailure(e, to, NULL, rcode, ovr); 16137c478bd9Sstevel@tonic-gate giveresponse(rcode, to->q_status, m, 16147c478bd9Sstevel@tonic-gate NULL, ctladdr, xstart, e, to); 16157c478bd9Sstevel@tonic-gate continue; 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate if (!quarantine && e->e_quarmsg != NULL) 16187c478bd9Sstevel@tonic-gate { 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate ** check_compat or checkcompat() has tried 16217c478bd9Sstevel@tonic-gate ** to quarantine but that isn't supported. 16227c478bd9Sstevel@tonic-gate ** Revert the attempt. 16237c478bd9Sstevel@tonic-gate */ 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate e->e_quarmsg = NULL; 16267c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 16277c478bd9Sstevel@tonic-gate macid("{quarantine}"), ""); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate if (bitset(EF_DISCARD, e->e_flags)) 16307c478bd9Sstevel@tonic-gate { 16317c478bd9Sstevel@tonic-gate if (tTd(10, 5)) 16327c478bd9Sstevel@tonic-gate { 16337c478bd9Sstevel@tonic-gate sm_dprintf("deliver: discarding recipient "); 16347c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), to, false); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate /* pretend the message was sent */ 16387c478bd9Sstevel@tonic-gate /* XXX should we log something here? */ 16397c478bd9Sstevel@tonic-gate to->q_state = QS_DISCARDED; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate /* 16427c478bd9Sstevel@tonic-gate ** Remove discard bit to prevent discard of 16437c478bd9Sstevel@tonic-gate ** future recipients. This is safe because the 16447c478bd9Sstevel@tonic-gate ** true "global discard" has been handled before 16457c478bd9Sstevel@tonic-gate ** we get here. 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_DISCARD; 16497c478bd9Sstevel@tonic-gate continue; 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate ** Strip quote bits from names if the mailer is dumb 16547c478bd9Sstevel@tonic-gate ** about them. 16557c478bd9Sstevel@tonic-gate */ 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate if (bitnset(M_STRIPQ, m->m_flags)) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate stripquotes(user); 16607c478bd9Sstevel@tonic-gate stripquotes(host); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate ** Strip all leading backslashes if requested and the 16657c478bd9Sstevel@tonic-gate ** next character is alphanumerical (the latter can 16667c478bd9Sstevel@tonic-gate ** probably relaxed a bit, see RFC2821). 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\') 16707c478bd9Sstevel@tonic-gate stripbackslash(user); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* hack attack -- delivermail compatibility */ 16737c478bd9Sstevel@tonic-gate if (m == ProgMailer && *user == '|') 16747c478bd9Sstevel@tonic-gate user++; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* 16777c478bd9Sstevel@tonic-gate ** If an error message has already been given, don't 16787c478bd9Sstevel@tonic-gate ** bother to send to this address. 16797c478bd9Sstevel@tonic-gate ** 16807c478bd9Sstevel@tonic-gate ** >>>>>>>>>> This clause assumes that the local mailer 16817c478bd9Sstevel@tonic-gate ** >> NOTE >> cannot do any further aliasing; that 16827c478bd9Sstevel@tonic-gate ** >>>>>>>>>> function is subsumed by sendmail. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate if (!QS_IS_OK(to->q_state)) 16867c478bd9Sstevel@tonic-gate continue; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* 16897c478bd9Sstevel@tonic-gate ** See if this user name is "special". 16907c478bd9Sstevel@tonic-gate ** If the user name has a slash in it, assume that this 16917c478bd9Sstevel@tonic-gate ** is a file -- send it off without further ado. Note 16927c478bd9Sstevel@tonic-gate ** that this type of addresses is not processed along 16937c478bd9Sstevel@tonic-gate ** with the others, so we fudge on the To person. 16947c478bd9Sstevel@tonic-gate */ 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate if (strcmp(m->m_mailer, "[FILE]") == 0) 16977c478bd9Sstevel@tonic-gate { 16987c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', user); 16997c478bd9Sstevel@tonic-gate p = to->q_home; 17007c478bd9Sstevel@tonic-gate if (p == NULL && ctladdr != NULL) 17017c478bd9Sstevel@tonic-gate p = ctladdr->q_home; 17027c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'z', p); 17037c478bd9Sstevel@tonic-gate expand(m->m_argv[1], buf, sizeof buf, e); 17047c478bd9Sstevel@tonic-gate if (strlen(buf) > 0) 17057c478bd9Sstevel@tonic-gate rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e); 17067c478bd9Sstevel@tonic-gate else 17077c478bd9Sstevel@tonic-gate { 17087c478bd9Sstevel@tonic-gate syserr("empty filename specification for mailer %s", 17097c478bd9Sstevel@tonic-gate m->m_name); 17107c478bd9Sstevel@tonic-gate rcode = EX_CONFIG; 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate giveresponse(rcode, to->q_status, m, NULL, 17137c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 17147c478bd9Sstevel@tonic-gate markfailure(e, to, NULL, rcode, true); 17157c478bd9Sstevel@tonic-gate e->e_nsent++; 17167c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 17177c478bd9Sstevel@tonic-gate { 17187c478bd9Sstevel@tonic-gate to->q_state = QS_SENT; 17197c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) && 17207c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags)) 17217c478bd9Sstevel@tonic-gate { 17227c478bd9Sstevel@tonic-gate to->q_flags |= QDELIVERED; 17237c478bd9Sstevel@tonic-gate to->q_status = "2.1.5"; 17247c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, 17257c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 17267c478bd9Sstevel@tonic-gate "%s... Successfully delivered\n", 17277c478bd9Sstevel@tonic-gate to->q_paddr); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate to->q_statdate = curtime(); 17317c478bd9Sstevel@tonic-gate markstats(e, to, STATS_NORMAL); 17327c478bd9Sstevel@tonic-gate continue; 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate ** Address is verified -- add this user to mailer 17377c478bd9Sstevel@tonic-gate ** argv, and add it to the print list of recipients. 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate /* link together the chain of recipients */ 17417c478bd9Sstevel@tonic-gate to->q_tchain = tochain; 17427c478bd9Sstevel@tonic-gate tochain = to; 17437c478bd9Sstevel@tonic-gate e->e_to = "[CHAIN]"; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */ 17467c478bd9Sstevel@tonic-gate p = to->q_home; 17477c478bd9Sstevel@tonic-gate if (p == NULL && ctladdr != NULL) 17487c478bd9Sstevel@tonic-gate p = ctladdr->q_home; 17497c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */ 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate /* set the ${dsn_notify} macro if applicable */ 17527c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, to->q_flags)) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate char notify[MAXLINE]; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate notify[0] = '\0'; 17577c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, to->q_flags)) 17587c478bd9Sstevel@tonic-gate (void) sm_strlcat(notify, "SUCCESS,", 17597c478bd9Sstevel@tonic-gate sizeof notify); 17607c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, to->q_flags)) 17617c478bd9Sstevel@tonic-gate (void) sm_strlcat(notify, "FAILURE,", 17627c478bd9Sstevel@tonic-gate sizeof notify); 17637c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, to->q_flags)) 17647c478bd9Sstevel@tonic-gate (void) sm_strlcat(notify, "DELAY,", 17657c478bd9Sstevel@tonic-gate sizeof notify); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate /* Set to NEVER or drop trailing comma */ 17687c478bd9Sstevel@tonic-gate if (notify[0] == '\0') 17697c478bd9Sstevel@tonic-gate (void) sm_strlcat(notify, "NEVER", 17707c478bd9Sstevel@tonic-gate sizeof notify); 17717c478bd9Sstevel@tonic-gate else 17727c478bd9Sstevel@tonic-gate notify[strlen(notify) - 1] = '\0'; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 17757c478bd9Sstevel@tonic-gate macid("{dsn_notify}"), notify); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate else 17787c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 17797c478bd9Sstevel@tonic-gate macid("{dsn_notify}"), NULL); 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate ** Expand out this user into argument list. 17837c478bd9Sstevel@tonic-gate */ 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate if (!clever) 17867c478bd9Sstevel@tonic-gate { 17877c478bd9Sstevel@tonic-gate expand(*mvp, buf, sizeof buf, e); 17887c478bd9Sstevel@tonic-gate *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 17897c478bd9Sstevel@tonic-gate if (pvp >= &pv[MAXPV - 2]) 17907c478bd9Sstevel@tonic-gate { 17917c478bd9Sstevel@tonic-gate /* allow some space for trailing parms */ 17927c478bd9Sstevel@tonic-gate break; 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate /* see if any addresses still exist */ 17987c478bd9Sstevel@tonic-gate if (tochain == NULL) 17997c478bd9Sstevel@tonic-gate { 18007c478bd9Sstevel@tonic-gate rcode = 0; 18017c478bd9Sstevel@tonic-gate goto cleanup; 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate /* print out messages as full list */ 18057c478bd9Sstevel@tonic-gate strsize = 1; 18067c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 18077c478bd9Sstevel@tonic-gate strsize += strlen(to->q_paddr) + 1; 18087c478bd9Sstevel@tonic-gate if (strsize < TOBUFSIZE) 18097c478bd9Sstevel@tonic-gate strsize = TOBUFSIZE; 18107c478bd9Sstevel@tonic-gate if (strsize > tobufsize) 18117c478bd9Sstevel@tonic-gate { 18127c478bd9Sstevel@tonic-gate SM_FREE_CLR(tobuf); 18137c478bd9Sstevel@tonic-gate tobuf = sm_pmalloc_x(strsize); 18147c478bd9Sstevel@tonic-gate tobufsize = strsize; 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate p = tobuf; 18177c478bd9Sstevel@tonic-gate *p = '\0'; 18187c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2, 18217c478bd9Sstevel@tonic-gate ",", to->q_paddr); 18227c478bd9Sstevel@tonic-gate p += strlen(p); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate e->e_to = tobuf + 1; 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate ** Fill out any parameters after the $u parameter. 18287c478bd9Sstevel@tonic-gate */ 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate if (!clever) 18317c478bd9Sstevel@tonic-gate { 18327c478bd9Sstevel@tonic-gate while (*++mvp != NULL) 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate expand(*mvp, buf, sizeof buf, e); 18357c478bd9Sstevel@tonic-gate *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf); 18367c478bd9Sstevel@tonic-gate if (pvp >= &pv[MAXPV]) 18377c478bd9Sstevel@tonic-gate syserr("554 5.3.0 deliver: pv overflow after $u for %s", 18387c478bd9Sstevel@tonic-gate pv[0]); 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate *pvp++ = NULL; 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate /* 18447c478bd9Sstevel@tonic-gate ** Call the mailer. 18457c478bd9Sstevel@tonic-gate ** The argument vector gets built, pipes 18467c478bd9Sstevel@tonic-gate ** are created as necessary, and we fork & exec as 18477c478bd9Sstevel@tonic-gate ** appropriate. 18487c478bd9Sstevel@tonic-gate ** If we are running SMTP, we just need to clean up. 18497c478bd9Sstevel@tonic-gate */ 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* XXX this seems a bit wierd */ 18527c478bd9Sstevel@tonic-gate if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 18537c478bd9Sstevel@tonic-gate bitset(QGOODUID, e->e_from.q_flags)) 18547c478bd9Sstevel@tonic-gate ctladdr = &e->e_from; 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate #if NAMED_BIND 18577c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 18587c478bd9Sstevel@tonic-gate _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 18597c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 18627c478bd9Sstevel@tonic-gate { 18637c478bd9Sstevel@tonic-gate sm_dprintf("openmailer:"); 18647c478bd9Sstevel@tonic-gate printav(sm_debug_file(), pv); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate errno = 0; 18677c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 18687c478bd9Sstevel@tonic-gate CurHostName = NULL; 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate /* 18717c478bd9Sstevel@tonic-gate ** Deal with the special case of mail handled through an IPC 18727c478bd9Sstevel@tonic-gate ** connection. 18737c478bd9Sstevel@tonic-gate ** In this case we don't actually fork. We must be 18747c478bd9Sstevel@tonic-gate ** running SMTP for this to work. We will return a 18757c478bd9Sstevel@tonic-gate ** zero pid to indicate that we are running IPC. 18767c478bd9Sstevel@tonic-gate ** We also handle a debug version that just talks to stdin/out. 18777c478bd9Sstevel@tonic-gate */ 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate curhost = NULL; 18807c478bd9Sstevel@tonic-gate SmtpPhase = NULL; 18817c478bd9Sstevel@tonic-gate mci = NULL; 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate #if XDEBUG 18847c478bd9Sstevel@tonic-gate { 18857c478bd9Sstevel@tonic-gate char wbuf[MAXLINE]; 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate /* make absolutely certain 0, 1, and 2 are in use */ 18887c478bd9Sstevel@tonic-gate (void) sm_snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)", 18897c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 18907c478bd9Sstevel@tonic-gate m->m_name); 18917c478bd9Sstevel@tonic-gate checkfd012(wbuf); 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate /* check for 8-bit available */ 18967c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 18977c478bd9Sstevel@tonic-gate bitnset(M_7BITS, m->m_flags) && 18987c478bd9Sstevel@tonic-gate (bitset(EF_DONT_MIME, e->e_flags) || 18997c478bd9Sstevel@tonic-gate !(bitset(MM_MIME8BIT, MimeMode) || 19007c478bd9Sstevel@tonic-gate (bitset(EF_IS_MIME, e->e_flags) && 19017c478bd9Sstevel@tonic-gate bitset(MM_CVTMIME, MimeMode))))) 19027c478bd9Sstevel@tonic-gate { 19037c478bd9Sstevel@tonic-gate e->e_status = "5.6.3"; 19047c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 19057c478bd9Sstevel@tonic-gate "554 Cannot send 8-bit data to 7-bit destination"); 19067c478bd9Sstevel@tonic-gate rcode = EX_DATAERR; 19077c478bd9Sstevel@tonic-gate goto give_up; 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate if (tTd(62, 8)) 19117c478bd9Sstevel@tonic-gate checkfds("before delivery"); 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate /* check for Local Person Communication -- not for mortals!!! */ 19147c478bd9Sstevel@tonic-gate if (strcmp(m->m_mailer, "[LPC]") == 0) 19157c478bd9Sstevel@tonic-gate { 19167c478bd9Sstevel@tonic-gate if (clever) 19177c478bd9Sstevel@tonic-gate { 19187c478bd9Sstevel@tonic-gate /* flush any expired connections */ 19197c478bd9Sstevel@tonic-gate (void) mci_scan(NULL); 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate /* try to get a cached connection or just a slot */ 19227c478bd9Sstevel@tonic-gate mci = mci_get(m->m_name, m); 19237c478bd9Sstevel@tonic-gate if (mci->mci_host == NULL) 19247c478bd9Sstevel@tonic-gate mci->mci_host = m->m_name; 19257c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; 19267c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED) 19277c478bd9Sstevel@tonic-gate { 19287c478bd9Sstevel@tonic-gate message("Using cached SMTP/LPC connection for %s...", 19297c478bd9Sstevel@tonic-gate m->m_name); 19307c478bd9Sstevel@tonic-gate mci->mci_deliveries++; 19317c478bd9Sstevel@tonic-gate goto do_transfer; 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate else 19357c478bd9Sstevel@tonic-gate { 19367c478bd9Sstevel@tonic-gate mci = mci_new(e->e_rpool); 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate mci->mci_in = smioin; 19397c478bd9Sstevel@tonic-gate mci->mci_out = smioout; 19407c478bd9Sstevel@tonic-gate mci->mci_mailer = m; 19417c478bd9Sstevel@tonic-gate mci->mci_host = m->m_name; 19427c478bd9Sstevel@tonic-gate if (clever) 19437c478bd9Sstevel@tonic-gate { 19447c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPENING; 19457c478bd9Sstevel@tonic-gate mci_cache(mci); 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate else 19487c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate else if (strcmp(m->m_mailer, "[IPC]") == 0) 19517c478bd9Sstevel@tonic-gate { 19527c478bd9Sstevel@tonic-gate register int i; 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 19557c478bd9Sstevel@tonic-gate { 19567c478bd9Sstevel@tonic-gate syserr("null destination for %s mailer", m->m_mailer); 19577c478bd9Sstevel@tonic-gate rcode = EX_CONFIG; 19587c478bd9Sstevel@tonic-gate goto give_up; 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate # if NETUNIX 19627c478bd9Sstevel@tonic-gate if (strcmp(pv[0], "FILE") == 0) 19637c478bd9Sstevel@tonic-gate { 19647c478bd9Sstevel@tonic-gate curhost = CurHostName = "localhost"; 19657c478bd9Sstevel@tonic-gate mux_path = pv[1]; 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate else 19687c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 19697c478bd9Sstevel@tonic-gate { 19707c478bd9Sstevel@tonic-gate CurHostName = pv[1]; 19717c478bd9Sstevel@tonic-gate curhost = hostsignature(m, pv[1]); 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate if (curhost == NULL || curhost[0] == '\0') 19757c478bd9Sstevel@tonic-gate { 19767c478bd9Sstevel@tonic-gate syserr("null host signature for %s", pv[1]); 19777c478bd9Sstevel@tonic-gate rcode = EX_CONFIG; 19787c478bd9Sstevel@tonic-gate goto give_up; 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate if (!clever) 19827c478bd9Sstevel@tonic-gate { 19837c478bd9Sstevel@tonic-gate syserr("554 5.3.5 non-clever IPC"); 19847c478bd9Sstevel@tonic-gate rcode = EX_CONFIG; 19857c478bd9Sstevel@tonic-gate goto give_up; 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate if (pv[2] != NULL 19887c478bd9Sstevel@tonic-gate # if NETUNIX 19897c478bd9Sstevel@tonic-gate && mux_path == NULL 19907c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 19917c478bd9Sstevel@tonic-gate ) 19927c478bd9Sstevel@tonic-gate { 19937c478bd9Sstevel@tonic-gate port = htons((unsigned short) atoi(pv[2])); 19947c478bd9Sstevel@tonic-gate if (port == 0) 19957c478bd9Sstevel@tonic-gate { 19967c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME 19977c478bd9Sstevel@tonic-gate syserr("Invalid port number: %s", pv[2]); 19987c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */ 19997c478bd9Sstevel@tonic-gate struct servent *sp = getservbyname(pv[2], "tcp"); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate if (sp == NULL) 20027c478bd9Sstevel@tonic-gate syserr("Service %s unknown", pv[2]); 20037c478bd9Sstevel@tonic-gate else 20047c478bd9Sstevel@tonic-gate port = sp->s_port; 20057c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */ 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate nummxhosts = parse_hostsignature(curhost, mxhosts, m); 20107c478bd9Sstevel@tonic-gate if (TimeOuts.to_aconnect > 0) 20117c478bd9Sstevel@tonic-gate enough = curtime() + TimeOuts.to_aconnect; 20127c478bd9Sstevel@tonic-gate tryhost: 20137c478bd9Sstevel@tonic-gate while (hostnum < nummxhosts) 20147c478bd9Sstevel@tonic-gate { 20157c478bd9Sstevel@tonic-gate char sep = ':'; 20167c478bd9Sstevel@tonic-gate char *endp; 20177c478bd9Sstevel@tonic-gate static char hostbuf[MAXNAME + 1]; 20187c478bd9Sstevel@tonic-gate bool tried_fallbacksmarthost = false; 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate # if NETINET6 20217c478bd9Sstevel@tonic-gate if (*mxhosts[hostnum] == '[') 20227c478bd9Sstevel@tonic-gate { 20237c478bd9Sstevel@tonic-gate endp = strchr(mxhosts[hostnum] + 1, ']'); 20247c478bd9Sstevel@tonic-gate if (endp != NULL) 20257c478bd9Sstevel@tonic-gate endp = strpbrk(endp + 1, ":,"); 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate else 20287c478bd9Sstevel@tonic-gate endp = strpbrk(mxhosts[hostnum], ":,"); 20297c478bd9Sstevel@tonic-gate # else /* NETINET6 */ 20307c478bd9Sstevel@tonic-gate endp = strpbrk(mxhosts[hostnum], ":,"); 20317c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 20327c478bd9Sstevel@tonic-gate if (endp != NULL) 20337c478bd9Sstevel@tonic-gate { 20347c478bd9Sstevel@tonic-gate sep = *endp; 20357c478bd9Sstevel@tonic-gate *endp = '\0'; 20367c478bd9Sstevel@tonic-gate } 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate if (hostnum == 1 && skip_back != NULL) 20397c478bd9Sstevel@tonic-gate { 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate ** Coattail piggybacking is no longer an 20427c478bd9Sstevel@tonic-gate ** option with the mail host next to be tried 20437c478bd9Sstevel@tonic-gate ** no longer the lowest MX preference 20447c478bd9Sstevel@tonic-gate ** (hostnum == 1 meaning we're on the second 20457c478bd9Sstevel@tonic-gate ** preference). We do not try to coattail 20467c478bd9Sstevel@tonic-gate ** piggyback more than the first MX preference. 20477c478bd9Sstevel@tonic-gate ** Revert 'tochain' to last location for 20487c478bd9Sstevel@tonic-gate ** coincidental piggybacking. This works this 20497c478bd9Sstevel@tonic-gate ** easily because the q_tchain kept getting 20507c478bd9Sstevel@tonic-gate ** added to the top of the linked list. 20517c478bd9Sstevel@tonic-gate */ 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate tochain = skip_back; 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate if (*mxhosts[hostnum] == '\0') 20577c478bd9Sstevel@tonic-gate { 20587c478bd9Sstevel@tonic-gate syserr("deliver: null host name in signature"); 20597c478bd9Sstevel@tonic-gate hostnum++; 20607c478bd9Sstevel@tonic-gate if (endp != NULL) 20617c478bd9Sstevel@tonic-gate *endp = sep; 20627c478bd9Sstevel@tonic-gate continue; 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate (void) sm_strlcpy(hostbuf, mxhosts[hostnum], 20657c478bd9Sstevel@tonic-gate sizeof hostbuf); 20667c478bd9Sstevel@tonic-gate hostnum++; 20677c478bd9Sstevel@tonic-gate if (endp != NULL) 20687c478bd9Sstevel@tonic-gate *endp = sep; 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate one_last_try: 20717c478bd9Sstevel@tonic-gate /* see if we already know that this host is fried */ 20727c478bd9Sstevel@tonic-gate CurHostName = hostbuf; 20737c478bd9Sstevel@tonic-gate mci = mci_get(hostbuf, m); 20747c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED) 20757c478bd9Sstevel@tonic-gate { 20767c478bd9Sstevel@tonic-gate char *type; 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 20797c478bd9Sstevel@tonic-gate { 20807c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: "); 20817c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false); 20827c478bd9Sstevel@tonic-gate } 20837c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; 20847c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 20857c478bd9Sstevel@tonic-gate type = "L"; 20867c478bd9Sstevel@tonic-gate else if (bitset(MCIF_ESMTP, mci->mci_flags)) 20877c478bd9Sstevel@tonic-gate type = "ES"; 20887c478bd9Sstevel@tonic-gate else 20897c478bd9Sstevel@tonic-gate type = "S"; 20907c478bd9Sstevel@tonic-gate message("Using cached %sMTP connection to %s via %s...", 20917c478bd9Sstevel@tonic-gate type, hostbuf, m->m_name); 20927c478bd9Sstevel@tonic-gate mci->mci_deliveries++; 20937c478bd9Sstevel@tonic-gate break; 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate mci->mci_mailer = m; 20967c478bd9Sstevel@tonic-gate if (mci->mci_exitstat != EX_OK) 20977c478bd9Sstevel@tonic-gate { 20987c478bd9Sstevel@tonic-gate if (mci->mci_exitstat == EX_TEMPFAIL) 20997c478bd9Sstevel@tonic-gate goodmxfound = true; 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate /* Try FallbackSmartHost? */ 21027c478bd9Sstevel@tonic-gate if (should_try_fbsh(e, &tried_fallbacksmarthost, 21037c478bd9Sstevel@tonic-gate hostbuf, sizeof hostbuf, 21047c478bd9Sstevel@tonic-gate mci->mci_exitstat)) 21057c478bd9Sstevel@tonic-gate goto one_last_try; 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate continue; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate if (mci_lock_host(mci) != EX_OK) 21117c478bd9Sstevel@tonic-gate { 21127c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 21137c478bd9Sstevel@tonic-gate goodmxfound = true; 21147c478bd9Sstevel@tonic-gate continue; 21157c478bd9Sstevel@tonic-gate } 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate /* try the connection */ 21187c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s", 21197c478bd9Sstevel@tonic-gate qid_printname(e), 21207c478bd9Sstevel@tonic-gate hostbuf, "user open"); 21217c478bd9Sstevel@tonic-gate # if NETUNIX 21227c478bd9Sstevel@tonic-gate if (mux_path != NULL) 21237c478bd9Sstevel@tonic-gate { 21247c478bd9Sstevel@tonic-gate message("Connecting to %s via %s...", 21257c478bd9Sstevel@tonic-gate mux_path, m->m_name); 21267c478bd9Sstevel@tonic-gate i = makeconnection_ds((char *) mux_path, mci); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate else 21297c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 21307c478bd9Sstevel@tonic-gate { 21317c478bd9Sstevel@tonic-gate if (port == 0) 21327c478bd9Sstevel@tonic-gate message("Connecting to %s via %s...", 21337c478bd9Sstevel@tonic-gate hostbuf, m->m_name); 21347c478bd9Sstevel@tonic-gate else 21357c478bd9Sstevel@tonic-gate message("Connecting to %s port %d via %s...", 21367c478bd9Sstevel@tonic-gate hostbuf, ntohs(port), 21377c478bd9Sstevel@tonic-gate m->m_name); 21387c478bd9Sstevel@tonic-gate i = makeconnection(hostbuf, port, mci, e, 21397c478bd9Sstevel@tonic-gate enough); 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate mci->mci_errno = errno; 21427c478bd9Sstevel@tonic-gate mci->mci_lastuse = curtime(); 21437c478bd9Sstevel@tonic-gate mci->mci_deliveries = 0; 21447c478bd9Sstevel@tonic-gate mci->mci_exitstat = i; 21457c478bd9Sstevel@tonic-gate # if NAMED_BIND 21467c478bd9Sstevel@tonic-gate mci->mci_herrno = h_errno; 21477c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */ 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate /* 21507c478bd9Sstevel@tonic-gate ** Have we tried long enough to get a connection? 21517c478bd9Sstevel@tonic-gate ** If yes, skip to the fallback MX hosts 21527c478bd9Sstevel@tonic-gate ** (if existent). 21537c478bd9Sstevel@tonic-gate */ 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate if (enough > 0 && mci->mci_lastuse >= enough) 21567c478bd9Sstevel@tonic-gate { 21577c478bd9Sstevel@tonic-gate int h; 21587c478bd9Sstevel@tonic-gate # if NAMED_BIND 21597c478bd9Sstevel@tonic-gate extern int NumFallbackMXHosts; 21607c478bd9Sstevel@tonic-gate # else /* NAMED_BIND */ 21617c478bd9Sstevel@tonic-gate const int NumFallbackMXHosts = 0; 21627c478bd9Sstevel@tonic-gate # endif /* NAMED_BIND */ 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate if (hostnum < nummxhosts && LogLevel > 9) 21657c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 21667c478bd9Sstevel@tonic-gate "Timeout.to_aconnect occurred before exhausting all addresses"); 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate /* turn off timeout if fallback available */ 21697c478bd9Sstevel@tonic-gate if (NumFallbackMXHosts > 0) 21707c478bd9Sstevel@tonic-gate enough = 0; 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate /* skip to a fallback MX host */ 21737c478bd9Sstevel@tonic-gate h = nummxhosts - NumFallbackMXHosts; 21747c478bd9Sstevel@tonic-gate if (hostnum < h) 21757c478bd9Sstevel@tonic-gate hostnum = h; 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate if (i == EX_OK) 21787c478bd9Sstevel@tonic-gate { 21797c478bd9Sstevel@tonic-gate goodmxfound = true; 21807c478bd9Sstevel@tonic-gate markstats(e, firstto, STATS_CONNECT); 21817c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPENING; 21827c478bd9Sstevel@tonic-gate mci_cache(mci); 21837c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 21847c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 21857c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 21867c478bd9Sstevel@tonic-gate "%05d === CONNECT %s\n", 21877c478bd9Sstevel@tonic-gate (int) CurrentPid, 21887c478bd9Sstevel@tonic-gate hostbuf); 21897c478bd9Sstevel@tonic-gate break; 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate else 21927c478bd9Sstevel@tonic-gate { 21937c478bd9Sstevel@tonic-gate /* Try FallbackSmartHost? */ 21947c478bd9Sstevel@tonic-gate if (should_try_fbsh(e, &tried_fallbacksmarthost, 21957c478bd9Sstevel@tonic-gate hostbuf, sizeof hostbuf, i)) 21967c478bd9Sstevel@tonic-gate goto one_last_try; 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 21997c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", 22007c478bd9Sstevel@tonic-gate i, errno); 22017c478bd9Sstevel@tonic-gate if (i == EX_TEMPFAIL) 22027c478bd9Sstevel@tonic-gate goodmxfound = true; 22037c478bd9Sstevel@tonic-gate mci_unlock_host(mci); 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate /* enter status of this host */ 22077c478bd9Sstevel@tonic-gate setstat(i); 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate /* should print some message here for -v mode */ 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate if (mci == NULL) 22127c478bd9Sstevel@tonic-gate { 22137c478bd9Sstevel@tonic-gate syserr("deliver: no host name"); 22147c478bd9Sstevel@tonic-gate rcode = EX_SOFTWARE; 22157c478bd9Sstevel@tonic-gate goto give_up; 22167c478bd9Sstevel@tonic-gate } 22177c478bd9Sstevel@tonic-gate mci->mci_pid = 0; 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate else 22207c478bd9Sstevel@tonic-gate { 22217c478bd9Sstevel@tonic-gate /* flush any expired connections */ 22227c478bd9Sstevel@tonic-gate (void) mci_scan(NULL); 22237c478bd9Sstevel@tonic-gate mci = NULL; 22247c478bd9Sstevel@tonic-gate 22257c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 22267c478bd9Sstevel@tonic-gate { 22277c478bd9Sstevel@tonic-gate /* try to get a cached connection */ 22287c478bd9Sstevel@tonic-gate mci = mci_get(m->m_name, m); 22297c478bd9Sstevel@tonic-gate if (mci->mci_host == NULL) 22307c478bd9Sstevel@tonic-gate mci->mci_host = m->m_name; 22317c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; 22327c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED) 22337c478bd9Sstevel@tonic-gate { 22347c478bd9Sstevel@tonic-gate message("Using cached LMTP connection for %s...", 22357c478bd9Sstevel@tonic-gate m->m_name); 22367c478bd9Sstevel@tonic-gate mci->mci_deliveries++; 22377c478bd9Sstevel@tonic-gate goto do_transfer; 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate /* announce the connection to verbose listeners */ 22427c478bd9Sstevel@tonic-gate if (host == NULL || host[0] == '\0') 22437c478bd9Sstevel@tonic-gate message("Connecting to %s...", m->m_name); 22447c478bd9Sstevel@tonic-gate else 22457c478bd9Sstevel@tonic-gate message("Connecting to %s via %s...", host, m->m_name); 22467c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 22477c478bd9Sstevel@tonic-gate { 22487c478bd9Sstevel@tonic-gate char **av; 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 22517c478bd9Sstevel@tonic-gate "%05d === EXEC", (int) CurrentPid); 22527c478bd9Sstevel@tonic-gate for (av = pv; *av != NULL; av++) 22537c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 22547c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, " %s", 22557c478bd9Sstevel@tonic-gate *av); 22567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 22577c478bd9Sstevel@tonic-gate "\n"); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate #if XDEBUG 22617c478bd9Sstevel@tonic-gate checkfd012("before creating mail pipe"); 22627c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* create a pipe to shove the mail through */ 22657c478bd9Sstevel@tonic-gate if (pipe(mpvect) < 0) 22667c478bd9Sstevel@tonic-gate { 22677c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): pipe (to mailer)", 22687c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 22697c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 22707c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: NULL\n"); 22717c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 22727c478bd9Sstevel@tonic-gate goto give_up; 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate #if XDEBUG 22767c478bd9Sstevel@tonic-gate /* make sure we didn't get one of the standard I/O files */ 22777c478bd9Sstevel@tonic-gate if (mpvect[0] < 3 || mpvect[1] < 3) 22787c478bd9Sstevel@tonic-gate { 22797c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): bogus mpvect %d %d", 22807c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), m->m_name, 22817c478bd9Sstevel@tonic-gate mpvect[0], mpvect[1]); 22827c478bd9Sstevel@tonic-gate printopenfds(true); 22837c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 22847c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: NULL\n"); 22857c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 22867c478bd9Sstevel@tonic-gate goto give_up; 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate /* make sure system call isn't dead meat */ 22907c478bd9Sstevel@tonic-gate checkfdopen(mpvect[0], "mpvect[0]"); 22917c478bd9Sstevel@tonic-gate checkfdopen(mpvect[1], "mpvect[1]"); 22927c478bd9Sstevel@tonic-gate if (mpvect[0] == mpvect[1] || 22937c478bd9Sstevel@tonic-gate (e->e_lockfp != NULL && 22947c478bd9Sstevel@tonic-gate (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 22957c478bd9Sstevel@tonic-gate NULL) || 22967c478bd9Sstevel@tonic-gate mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 22977c478bd9Sstevel@tonic-gate NULL)))) 22987c478bd9Sstevel@tonic-gate { 22997c478bd9Sstevel@tonic-gate if (e->e_lockfp == NULL) 23007c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): overlapping mpvect %d %d", 23017c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 23027c478bd9Sstevel@tonic-gate m->m_name, mpvect[0], mpvect[1]); 23037c478bd9Sstevel@tonic-gate else 23047c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", 23057c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 23067c478bd9Sstevel@tonic-gate m->m_name, mpvect[0], mpvect[1], 23077c478bd9Sstevel@tonic-gate sm_io_getinfo(e->e_lockfp, 23087c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL)); 23097c478bd9Sstevel@tonic-gate } 23107c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate /* create a return pipe */ 23137c478bd9Sstevel@tonic-gate if (pipe(rpvect) < 0) 23147c478bd9Sstevel@tonic-gate { 23157c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): pipe (from mailer)", 23167c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 23177c478bd9Sstevel@tonic-gate m->m_name); 23187c478bd9Sstevel@tonic-gate (void) close(mpvect[0]); 23197c478bd9Sstevel@tonic-gate (void) close(mpvect[1]); 23207c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 23217c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: NULL\n"); 23227c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 23237c478bd9Sstevel@tonic-gate goto give_up; 23247c478bd9Sstevel@tonic-gate } 23257c478bd9Sstevel@tonic-gate #if XDEBUG 23267c478bd9Sstevel@tonic-gate checkfdopen(rpvect[0], "rpvect[0]"); 23277c478bd9Sstevel@tonic-gate checkfdopen(rpvect[1], "rpvect[1]"); 23287c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate /* 23317c478bd9Sstevel@tonic-gate ** Actually fork the mailer process. 23327c478bd9Sstevel@tonic-gate ** DOFORK is clever about retrying. 23337c478bd9Sstevel@tonic-gate ** 23347c478bd9Sstevel@tonic-gate ** Dispose of SIGCHLD signal catchers that may be laying 23357c478bd9Sstevel@tonic-gate ** around so that endmailer will get it. 23367c478bd9Sstevel@tonic-gate */ 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) /* for debugging */ 23397c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 23407c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 23417c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate DOFORK(FORK); 23457c478bd9Sstevel@tonic-gate /* pid is set by DOFORK */ 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate if (pid < 0) 23487c478bd9Sstevel@tonic-gate { 23497c478bd9Sstevel@tonic-gate /* failure */ 23507c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): cannot fork", 23517c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), m->m_name); 23527c478bd9Sstevel@tonic-gate (void) close(mpvect[0]); 23537c478bd9Sstevel@tonic-gate (void) close(mpvect[1]); 23547c478bd9Sstevel@tonic-gate (void) close(rpvect[0]); 23557c478bd9Sstevel@tonic-gate (void) close(rpvect[1]); 23567c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 23577c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: NULL\n"); 23587c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 23597c478bd9Sstevel@tonic-gate goto give_up; 23607c478bd9Sstevel@tonic-gate } 23617c478bd9Sstevel@tonic-gate else if (pid == 0) 23627c478bd9Sstevel@tonic-gate { 23637c478bd9Sstevel@tonic-gate int save_errno; 23647c478bd9Sstevel@tonic-gate int sff; 23657c478bd9Sstevel@tonic-gate int new_euid = NO_UID; 23667c478bd9Sstevel@tonic-gate int new_ruid = NO_UID; 23677c478bd9Sstevel@tonic-gate int new_gid = NO_GID; 23687c478bd9Sstevel@tonic-gate char *user = NULL; 23697c478bd9Sstevel@tonic-gate struct stat stb; 23707c478bd9Sstevel@tonic-gate extern int DtableSize; 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 23737c478bd9Sstevel@tonic-gate 23747c478bd9Sstevel@tonic-gate /* clear the events to turn off SIGALRMs */ 23757c478bd9Sstevel@tonic-gate sm_clear_events(); 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate /* Reset global flags */ 23787c478bd9Sstevel@tonic-gate RestartRequest = NULL; 23797c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 23807c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 23817c478bd9Sstevel@tonic-gate PendingSignal = 0; 23827c478bd9Sstevel@tonic-gate 23837c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 23847c478bd9Sstevel@tonic-gate (void) close(sm_io_getinfo(e->e_lockfp, 23857c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, 23867c478bd9Sstevel@tonic-gate NULL)); 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate /* child -- set up input & exec mailer */ 23897c478bd9Sstevel@tonic-gate (void) sm_signal(SIGALRM, sm_signal_noop); 23907c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 23917c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_IGN); 23927c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, SIG_IGN); 23937c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, SIG_DFL); 23947c478bd9Sstevel@tonic-gate # ifdef SIGUSR1 23957c478bd9Sstevel@tonic-gate (void) sm_signal(SIGUSR1, sm_signal_noop); 23967c478bd9Sstevel@tonic-gate # endif /* SIGUSR1 */ 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 23997c478bd9Sstevel@tonic-gate stb.st_mode = 0; 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate # if HASSETUSERCONTEXT 24027c478bd9Sstevel@tonic-gate /* 24037c478bd9Sstevel@tonic-gate ** Set user resources. 24047c478bd9Sstevel@tonic-gate */ 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate if (contextaddr != NULL) 24077c478bd9Sstevel@tonic-gate { 24087c478bd9Sstevel@tonic-gate int sucflags; 24097c478bd9Sstevel@tonic-gate struct passwd *pwd; 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate if (contextaddr->q_ruser != NULL) 24127c478bd9Sstevel@tonic-gate pwd = sm_getpwnam(contextaddr->q_ruser); 24137c478bd9Sstevel@tonic-gate else 24147c478bd9Sstevel@tonic-gate pwd = sm_getpwnam(contextaddr->q_user); 24157c478bd9Sstevel@tonic-gate sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; 24167c478bd9Sstevel@tonic-gate #ifdef LOGIN_SETMAC 24177c478bd9Sstevel@tonic-gate sucflags |= LOGIN_SETMAC; 24187c478bd9Sstevel@tonic-gate #endif /* LOGIN_SETMAC */ 24197c478bd9Sstevel@tonic-gate if (pwd != NULL && 24207c478bd9Sstevel@tonic-gate setusercontext(NULL, pwd, pwd->pw_uid, 24217c478bd9Sstevel@tonic-gate sucflags) == -1 && 24227c478bd9Sstevel@tonic-gate suidwarn) 24237c478bd9Sstevel@tonic-gate { 24247c478bd9Sstevel@tonic-gate syserr("openmailer: setusercontext() failed"); 24257c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 24267c478bd9Sstevel@tonic-gate } 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate # endif /* HASSETUSERCONTEXT */ 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate #if HASNICE 24317c478bd9Sstevel@tonic-gate /* tweak niceness */ 24327c478bd9Sstevel@tonic-gate if (m->m_nice != 0) 24337c478bd9Sstevel@tonic-gate (void) nice(m->m_nice); 24347c478bd9Sstevel@tonic-gate #endif /* HASNICE */ 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate /* reset group id */ 24377c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, m->m_flags)) 24387c478bd9Sstevel@tonic-gate { 24397c478bd9Sstevel@tonic-gate if (m->m_gid == NO_GID) 24407c478bd9Sstevel@tonic-gate new_gid = RunAsGid; 24417c478bd9Sstevel@tonic-gate else 24427c478bd9Sstevel@tonic-gate new_gid = m->m_gid; 24437c478bd9Sstevel@tonic-gate } 24447c478bd9Sstevel@tonic-gate else if (bitset(S_ISGID, stb.st_mode)) 24457c478bd9Sstevel@tonic-gate new_gid = stb.st_gid; 24467c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_gid != 0) 24477c478bd9Sstevel@tonic-gate { 24487c478bd9Sstevel@tonic-gate if (!DontInitGroups) 24497c478bd9Sstevel@tonic-gate { 24507c478bd9Sstevel@tonic-gate user = ctladdr->q_ruser; 24517c478bd9Sstevel@tonic-gate if (user == NULL) 24527c478bd9Sstevel@tonic-gate user = ctladdr->q_user; 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate if (initgroups(user, 24557c478bd9Sstevel@tonic-gate ctladdr->q_gid) == -1 24567c478bd9Sstevel@tonic-gate && suidwarn) 24577c478bd9Sstevel@tonic-gate { 24587c478bd9Sstevel@tonic-gate syserr("openmailer: initgroups(%s, %d) failed", 24597c478bd9Sstevel@tonic-gate user, ctladdr->q_gid); 24607c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 24617c478bd9Sstevel@tonic-gate } 24627c478bd9Sstevel@tonic-gate } 24637c478bd9Sstevel@tonic-gate else 24647c478bd9Sstevel@tonic-gate { 24657c478bd9Sstevel@tonic-gate GIDSET_T gidset[1]; 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate gidset[0] = ctladdr->q_gid; 24687c478bd9Sstevel@tonic-gate if (setgroups(1, gidset) == -1 24697c478bd9Sstevel@tonic-gate && suidwarn) 24707c478bd9Sstevel@tonic-gate { 24717c478bd9Sstevel@tonic-gate syserr("openmailer: setgroups() failed"); 24727c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate } 24757c478bd9Sstevel@tonic-gate new_gid = ctladdr->q_gid; 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate else 24787c478bd9Sstevel@tonic-gate { 24797c478bd9Sstevel@tonic-gate if (!DontInitGroups) 24807c478bd9Sstevel@tonic-gate { 24817c478bd9Sstevel@tonic-gate user = DefUser; 24827c478bd9Sstevel@tonic-gate if (initgroups(DefUser, DefGid) == -1 && 24837c478bd9Sstevel@tonic-gate suidwarn) 24847c478bd9Sstevel@tonic-gate { 24857c478bd9Sstevel@tonic-gate syserr("openmailer: initgroups(%s, %d) failed", 24867c478bd9Sstevel@tonic-gate DefUser, DefGid); 24877c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate } 24907c478bd9Sstevel@tonic-gate else 24917c478bd9Sstevel@tonic-gate { 24927c478bd9Sstevel@tonic-gate GIDSET_T gidset[1]; 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate gidset[0] = DefGid; 24957c478bd9Sstevel@tonic-gate if (setgroups(1, gidset) == -1 24967c478bd9Sstevel@tonic-gate && suidwarn) 24977c478bd9Sstevel@tonic-gate { 24987c478bd9Sstevel@tonic-gate syserr("openmailer: setgroups() failed"); 24997c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate } 25027c478bd9Sstevel@tonic-gate if (m->m_gid == NO_GID) 25037c478bd9Sstevel@tonic-gate new_gid = DefGid; 25047c478bd9Sstevel@tonic-gate else 25057c478bd9Sstevel@tonic-gate new_gid = m->m_gid; 25067c478bd9Sstevel@tonic-gate } 25077c478bd9Sstevel@tonic-gate if (new_gid != NO_GID) 25087c478bd9Sstevel@tonic-gate { 25097c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && 25107c478bd9Sstevel@tonic-gate bitnset(M_SPECIFIC_UID, m->m_flags) && 25117c478bd9Sstevel@tonic-gate new_gid != getgid() && 25127c478bd9Sstevel@tonic-gate new_gid != getegid()) 25137c478bd9Sstevel@tonic-gate { 25147c478bd9Sstevel@tonic-gate /* Only root can change the gid */ 25157c478bd9Sstevel@tonic-gate syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d", 25167c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) new_gid, 25177c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 25187c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 25197c478bd9Sstevel@tonic-gate } 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate if (setgid(new_gid) < 0 && suidwarn) 25227c478bd9Sstevel@tonic-gate { 25237c478bd9Sstevel@tonic-gate syserr("openmailer: setgid(%ld) failed", 25247c478bd9Sstevel@tonic-gate (long) new_gid); 25257c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 25267c478bd9Sstevel@tonic-gate } 25277c478bd9Sstevel@tonic-gate } 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate /* change root to some "safe" directory */ 25307c478bd9Sstevel@tonic-gate if (m->m_rootdir != NULL) 25317c478bd9Sstevel@tonic-gate { 25327c478bd9Sstevel@tonic-gate expand(m->m_rootdir, cbuf, sizeof cbuf, e); 25337c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 25347c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: chroot %s\n", 25357c478bd9Sstevel@tonic-gate cbuf); 25367c478bd9Sstevel@tonic-gate if (chroot(cbuf) < 0) 25377c478bd9Sstevel@tonic-gate { 25387c478bd9Sstevel@tonic-gate syserr("openmailer: Cannot chroot(%s)", 25397c478bd9Sstevel@tonic-gate cbuf); 25407c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 25417c478bd9Sstevel@tonic-gate } 25427c478bd9Sstevel@tonic-gate if (chdir("/") < 0) 25437c478bd9Sstevel@tonic-gate { 25447c478bd9Sstevel@tonic-gate syserr("openmailer: cannot chdir(/)"); 25457c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 25467c478bd9Sstevel@tonic-gate } 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate /* reset user id */ 25507c478bd9Sstevel@tonic-gate endpwent(); 25517c478bd9Sstevel@tonic-gate sm_mbdb_terminate(); 25527c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, m->m_flags)) 25537c478bd9Sstevel@tonic-gate { 25547c478bd9Sstevel@tonic-gate if (m->m_uid == NO_UID) 25557c478bd9Sstevel@tonic-gate new_euid = RunAsUid; 25567c478bd9Sstevel@tonic-gate else 25577c478bd9Sstevel@tonic-gate new_euid = m->m_uid; 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate /* 25607c478bd9Sstevel@tonic-gate ** Undo the effects of the uid change in main 25617c478bd9Sstevel@tonic-gate ** for signal handling. The real uid may 25627c478bd9Sstevel@tonic-gate ** be used by mailer in adding a "From " 25637c478bd9Sstevel@tonic-gate ** line. 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate if (RealUid != 0 && RealUid != getuid()) 25677c478bd9Sstevel@tonic-gate { 25687c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETEUID 25697c478bd9Sstevel@tonic-gate # if HASSETREUID 25707c478bd9Sstevel@tonic-gate if (setreuid(RealUid, geteuid()) < 0) 25717c478bd9Sstevel@tonic-gate { 25727c478bd9Sstevel@tonic-gate syserr("openmailer: setreuid(%d, %d) failed", 25737c478bd9Sstevel@tonic-gate (int) RealUid, (int) geteuid()); 25747c478bd9Sstevel@tonic-gate exit(EX_OSERR); 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate # endif /* HASSETREUID */ 25777c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 25787c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETREUID 25797c478bd9Sstevel@tonic-gate new_ruid = RealUid; 25807c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate else if (bitset(S_ISUID, stb.st_mode)) 25847c478bd9Sstevel@tonic-gate new_ruid = stb.st_uid; 25857c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_uid != 0) 25867c478bd9Sstevel@tonic-gate new_ruid = ctladdr->q_uid; 25877c478bd9Sstevel@tonic-gate else if (m->m_uid != NO_UID) 25887c478bd9Sstevel@tonic-gate new_ruid = m->m_uid; 25897c478bd9Sstevel@tonic-gate else 25907c478bd9Sstevel@tonic-gate new_ruid = DefUid; 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate # if _FFR_USE_SETLOGIN 25937c478bd9Sstevel@tonic-gate /* run disconnected from terminal and set login name */ 25947c478bd9Sstevel@tonic-gate if (setsid() >= 0 && 25957c478bd9Sstevel@tonic-gate ctladdr != NULL && ctladdr->q_uid != 0 && 25967c478bd9Sstevel@tonic-gate new_euid == ctladdr->q_uid) 25977c478bd9Sstevel@tonic-gate { 25987c478bd9Sstevel@tonic-gate struct passwd *pwd; 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate pwd = sm_getpwuid(ctladdr->q_uid); 26017c478bd9Sstevel@tonic-gate if (pwd != NULL && suidwarn) 26027c478bd9Sstevel@tonic-gate (void) setlogin(pwd->pw_name); 26037c478bd9Sstevel@tonic-gate endpwent(); 26047c478bd9Sstevel@tonic-gate } 26057c478bd9Sstevel@tonic-gate # endif /* _FFR_USE_SETLOGIN */ 26067c478bd9Sstevel@tonic-gate 26077c478bd9Sstevel@tonic-gate if (new_euid != NO_UID) 26087c478bd9Sstevel@tonic-gate { 26097c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && new_euid != RunAsUid) 26107c478bd9Sstevel@tonic-gate { 26117c478bd9Sstevel@tonic-gate /* Only root can change the uid */ 26127c478bd9Sstevel@tonic-gate syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d", 26137c478bd9Sstevel@tonic-gate (int) new_euid, (int) RunAsUid); 26147c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate vendor_set_uid(new_euid); 26187c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETEUID 26197c478bd9Sstevel@tonic-gate if (seteuid(new_euid) < 0 && suidwarn) 26207c478bd9Sstevel@tonic-gate { 26217c478bd9Sstevel@tonic-gate syserr("openmailer: seteuid(%ld) failed", 26227c478bd9Sstevel@tonic-gate (long) new_euid); 26237c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 26267c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETREUID 26277c478bd9Sstevel@tonic-gate if (setreuid(new_ruid, new_euid) < 0 && suidwarn) 26287c478bd9Sstevel@tonic-gate { 26297c478bd9Sstevel@tonic-gate syserr("openmailer: setreuid(%ld, %ld) failed", 26307c478bd9Sstevel@tonic-gate (long) new_ruid, (long) new_euid); 26317c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 26347c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETUID 26357c478bd9Sstevel@tonic-gate if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) 26367c478bd9Sstevel@tonic-gate { 26377c478bd9Sstevel@tonic-gate syserr("openmailer: setuid(%ld) failed", 26387c478bd9Sstevel@tonic-gate (long) new_euid); 26397c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 26407c478bd9Sstevel@tonic-gate } 26417c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETUID */ 26427c478bd9Sstevel@tonic-gate } 26437c478bd9Sstevel@tonic-gate else if (new_ruid != NO_UID) 26447c478bd9Sstevel@tonic-gate { 26457c478bd9Sstevel@tonic-gate vendor_set_uid(new_ruid); 26467c478bd9Sstevel@tonic-gate if (setuid(new_ruid) < 0 && suidwarn) 26477c478bd9Sstevel@tonic-gate { 26487c478bd9Sstevel@tonic-gate syserr("openmailer: setuid(%ld) failed", 26497c478bd9Sstevel@tonic-gate (long) new_ruid); 26507c478bd9Sstevel@tonic-gate exit(EX_TEMPFAIL); 26517c478bd9Sstevel@tonic-gate } 26527c478bd9Sstevel@tonic-gate } 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate if (tTd(11, 2)) 26557c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", 26567c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid(), 26577c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate /* move into some "safe" directory */ 26607c478bd9Sstevel@tonic-gate if (m->m_execdir != NULL) 26617c478bd9Sstevel@tonic-gate { 26627c478bd9Sstevel@tonic-gate char *q; 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate for (p = m->m_execdir; p != NULL; p = q) 26657c478bd9Sstevel@tonic-gate { 26667c478bd9Sstevel@tonic-gate q = strchr(p, ':'); 26677c478bd9Sstevel@tonic-gate if (q != NULL) 26687c478bd9Sstevel@tonic-gate *q = '\0'; 26697c478bd9Sstevel@tonic-gate expand(p, cbuf, sizeof cbuf, e); 26707c478bd9Sstevel@tonic-gate if (q != NULL) 26717c478bd9Sstevel@tonic-gate *q++ = ':'; 26727c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 26737c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: trydir %s\n", 26747c478bd9Sstevel@tonic-gate cbuf); 26757c478bd9Sstevel@tonic-gate if (cbuf[0] != '\0' && 26767c478bd9Sstevel@tonic-gate chdir(cbuf) >= 0) 26777c478bd9Sstevel@tonic-gate break; 26787c478bd9Sstevel@tonic-gate } 26797c478bd9Sstevel@tonic-gate } 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate /* Check safety of program to be run */ 26827c478bd9Sstevel@tonic-gate sff = SFF_ROOTOK|SFF_EXECOK; 26837c478bd9Sstevel@tonic-gate if (!bitnset(DBS_RUNWRITABLEPROGRAM, 26847c478bd9Sstevel@tonic-gate DontBlameSendmail)) 26857c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES|SFF_NOWWFILES; 26867c478bd9Sstevel@tonic-gate if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, 26877c478bd9Sstevel@tonic-gate DontBlameSendmail)) 26887c478bd9Sstevel@tonic-gate sff |= SFF_NOPATHCHECK; 26897c478bd9Sstevel@tonic-gate else 26907c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH; 26917c478bd9Sstevel@tonic-gate ret = safefile(m->m_mailer, getuid(), getgid(), 26927c478bd9Sstevel@tonic-gate user, sff, 0, NULL); 26937c478bd9Sstevel@tonic-gate if (ret != 0) 26947c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 26957c478bd9Sstevel@tonic-gate "Warning: program %s unsafe: %s", 26967c478bd9Sstevel@tonic-gate m->m_mailer, sm_errstring(ret)); 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate /* arrange to filter std & diag output of command */ 26997c478bd9Sstevel@tonic-gate (void) close(rpvect[0]); 27007c478bd9Sstevel@tonic-gate if (dup2(rpvect[1], STDOUT_FILENO) < 0) 27017c478bd9Sstevel@tonic-gate { 27027c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 27037c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 27047c478bd9Sstevel@tonic-gate m->m_name, rpvect[1]); 27057c478bd9Sstevel@tonic-gate _exit(EX_OSERR); 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate (void) close(rpvect[1]); 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 27107c478bd9Sstevel@tonic-gate { 27117c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): cannot dup stdout for stderr", 27127c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 27137c478bd9Sstevel@tonic-gate m->m_name); 27147c478bd9Sstevel@tonic-gate _exit(EX_OSERR); 27157c478bd9Sstevel@tonic-gate } 27167c478bd9Sstevel@tonic-gate 27177c478bd9Sstevel@tonic-gate /* arrange to get standard input */ 27187c478bd9Sstevel@tonic-gate (void) close(mpvect[1]); 27197c478bd9Sstevel@tonic-gate if (dup2(mpvect[0], STDIN_FILENO) < 0) 27207c478bd9Sstevel@tonic-gate { 27217c478bd9Sstevel@tonic-gate syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 27227c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR), 27237c478bd9Sstevel@tonic-gate m->m_name, mpvect[0]); 27247c478bd9Sstevel@tonic-gate _exit(EX_OSERR); 27257c478bd9Sstevel@tonic-gate } 27267c478bd9Sstevel@tonic-gate (void) close(mpvect[0]); 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate /* arrange for all the files to be closed */ 27297c478bd9Sstevel@tonic-gate sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate # if !_FFR_USE_SETLOGIN 27327c478bd9Sstevel@tonic-gate /* run disconnected from terminal */ 27337c478bd9Sstevel@tonic-gate (void) setsid(); 27347c478bd9Sstevel@tonic-gate # endif /* !_FFR_USE_SETLOGIN */ 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate /* try to execute the mailer */ 27377c478bd9Sstevel@tonic-gate (void) execve(m->m_mailer, (ARGV_T) pv, 27387c478bd9Sstevel@tonic-gate (ARGV_T) UserEnviron); 27397c478bd9Sstevel@tonic-gate save_errno = errno; 27407c478bd9Sstevel@tonic-gate syserr("Cannot exec %s", m->m_mailer); 27417c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) || 27427c478bd9Sstevel@tonic-gate transienterror(save_errno)) 27437c478bd9Sstevel@tonic-gate _exit(EX_OSERR); 27447c478bd9Sstevel@tonic-gate _exit(EX_UNAVAILABLE); 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate /* 27487c478bd9Sstevel@tonic-gate ** Set up return value. 27497c478bd9Sstevel@tonic-gate */ 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate if (mci == NULL) 27527c478bd9Sstevel@tonic-gate { 27537c478bd9Sstevel@tonic-gate if (clever) 27547c478bd9Sstevel@tonic-gate { 27557c478bd9Sstevel@tonic-gate /* 27567c478bd9Sstevel@tonic-gate ** Allocate from general heap, not 27577c478bd9Sstevel@tonic-gate ** envelope rpool, because this mci 27587c478bd9Sstevel@tonic-gate ** is going to be cached. 27597c478bd9Sstevel@tonic-gate */ 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate mci = mci_new(NULL); 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate else 27647c478bd9Sstevel@tonic-gate { 27657c478bd9Sstevel@tonic-gate /* 27667c478bd9Sstevel@tonic-gate ** Prevent a storage leak by allocating 27677c478bd9Sstevel@tonic-gate ** this from the envelope rpool. 27687c478bd9Sstevel@tonic-gate */ 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate mci = mci_new(e->e_rpool); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate } 27737c478bd9Sstevel@tonic-gate mci->mci_mailer = m; 27747c478bd9Sstevel@tonic-gate if (clever) 27757c478bd9Sstevel@tonic-gate { 27767c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPENING; 27777c478bd9Sstevel@tonic-gate mci_cache(mci); 27787c478bd9Sstevel@tonic-gate } 27797c478bd9Sstevel@tonic-gate else 27807c478bd9Sstevel@tonic-gate { 27817c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN; 27827c478bd9Sstevel@tonic-gate } 27837c478bd9Sstevel@tonic-gate mci->mci_pid = pid; 27847c478bd9Sstevel@tonic-gate (void) close(mpvect[0]); 27857c478bd9Sstevel@tonic-gate mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 27867c478bd9Sstevel@tonic-gate (void *) &(mpvect[1]), SM_IO_WRONLY_B, 27877c478bd9Sstevel@tonic-gate NULL); 27887c478bd9Sstevel@tonic-gate if (mci->mci_out == NULL) 27897c478bd9Sstevel@tonic-gate { 27907c478bd9Sstevel@tonic-gate syserr("deliver: cannot create mailer output channel, fd=%d", 27917c478bd9Sstevel@tonic-gate mpvect[1]); 27927c478bd9Sstevel@tonic-gate (void) close(mpvect[1]); 27937c478bd9Sstevel@tonic-gate (void) close(rpvect[0]); 27947c478bd9Sstevel@tonic-gate (void) close(rpvect[1]); 27957c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 27967c478bd9Sstevel@tonic-gate goto give_up; 27977c478bd9Sstevel@tonic-gate } 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate (void) close(rpvect[1]); 28007c478bd9Sstevel@tonic-gate mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 28017c478bd9Sstevel@tonic-gate (void *) &(rpvect[0]), SM_IO_RDONLY_B, 28027c478bd9Sstevel@tonic-gate NULL); 28037c478bd9Sstevel@tonic-gate if (mci->mci_in == NULL) 28047c478bd9Sstevel@tonic-gate { 28057c478bd9Sstevel@tonic-gate syserr("deliver: cannot create mailer input channel, fd=%d", 28067c478bd9Sstevel@tonic-gate mpvect[1]); 28077c478bd9Sstevel@tonic-gate (void) close(rpvect[0]); 28087c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 28097c478bd9Sstevel@tonic-gate mci->mci_out = NULL; 28107c478bd9Sstevel@tonic-gate rcode = EX_OSERR; 28117c478bd9Sstevel@tonic-gate goto give_up; 28127c478bd9Sstevel@tonic-gate } 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate ** If we are in SMTP opening state, send initial protocol. 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate if (bitnset(M_7BITS, m->m_flags) && 28207c478bd9Sstevel@tonic-gate (!clever || mci->mci_state == MCIS_OPENING)) 28217c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_7BIT; 28227c478bd9Sstevel@tonic-gate if (clever && mci->mci_state != MCIS_CLOSED) 28237c478bd9Sstevel@tonic-gate { 28247c478bd9Sstevel@tonic-gate # if STARTTLS || SASL 28257c478bd9Sstevel@tonic-gate int dotpos; 28267c478bd9Sstevel@tonic-gate char *srvname; 28277c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr; 28287c478bd9Sstevel@tonic-gate # endif /* STARTTLS || SASL */ 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate # if SASL 28317c478bd9Sstevel@tonic-gate # define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) 28327c478bd9Sstevel@tonic-gate # endif /* SASL */ 28337c478bd9Sstevel@tonic-gate # if STARTTLS 28347c478bd9Sstevel@tonic-gate # define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) 28357c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 28367c478bd9Sstevel@tonic-gate # define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) 28377c478bd9Sstevel@tonic-gate # define SET_HELO(f) f |= MCIF_ONLY_EHLO 28387c478bd9Sstevel@tonic-gate # define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate # if STARTTLS || SASL 28417c478bd9Sstevel@tonic-gate /* don't use CurHostName, it is changed in many places */ 28427c478bd9Sstevel@tonic-gate if (mci->mci_host != NULL) 28437c478bd9Sstevel@tonic-gate { 28447c478bd9Sstevel@tonic-gate srvname = mci->mci_host; 28457c478bd9Sstevel@tonic-gate dotpos = strlen(srvname) - 1; 28467c478bd9Sstevel@tonic-gate if (dotpos >= 0) 28477c478bd9Sstevel@tonic-gate { 28487c478bd9Sstevel@tonic-gate if (srvname[dotpos] == '.') 28497c478bd9Sstevel@tonic-gate srvname[dotpos] = '\0'; 28507c478bd9Sstevel@tonic-gate else 28517c478bd9Sstevel@tonic-gate dotpos = -1; 28527c478bd9Sstevel@tonic-gate } 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate else if (mci->mci_mailer != NULL) 28557c478bd9Sstevel@tonic-gate { 28567c478bd9Sstevel@tonic-gate srvname = mci->mci_mailer->m_name; 28577c478bd9Sstevel@tonic-gate dotpos = -1; 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate else 28607c478bd9Sstevel@tonic-gate { 28617c478bd9Sstevel@tonic-gate srvname = "local"; 28627c478bd9Sstevel@tonic-gate dotpos = -1; 28637c478bd9Sstevel@tonic-gate } 28647c478bd9Sstevel@tonic-gate 28657c478bd9Sstevel@tonic-gate /* don't set {server_name} to NULL or "": see getauth() */ 28667c478bd9Sstevel@tonic-gate macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"), 28677c478bd9Sstevel@tonic-gate srvname); 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate /* CurHostAddr is set by makeconnection() and mci_get() */ 28707c478bd9Sstevel@tonic-gate if (CurHostAddr.sa.sa_family != 0) 28717c478bd9Sstevel@tonic-gate { 28727c478bd9Sstevel@tonic-gate macdefine(&mci->mci_macro, A_TEMP, 28737c478bd9Sstevel@tonic-gate macid("{server_addr}"), 28747c478bd9Sstevel@tonic-gate anynet_ntoa(&CurHostAddr)); 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate else if (mci->mci_mailer != NULL) 28777c478bd9Sstevel@tonic-gate { 28787c478bd9Sstevel@tonic-gate /* mailer name is unique, use it as address */ 28797c478bd9Sstevel@tonic-gate macdefine(&mci->mci_macro, A_PERM, 28807c478bd9Sstevel@tonic-gate macid("{server_addr}"), 28817c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name); 28827c478bd9Sstevel@tonic-gate } 28837c478bd9Sstevel@tonic-gate else 28847c478bd9Sstevel@tonic-gate { 28857c478bd9Sstevel@tonic-gate /* don't set it to NULL or "": see getauth() */ 28867c478bd9Sstevel@tonic-gate macdefine(&mci->mci_macro, A_PERM, 28877c478bd9Sstevel@tonic-gate macid("{server_addr}"), "0"); 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate /* undo change of srvname (mci->mci_host) */ 28917c478bd9Sstevel@tonic-gate if (dotpos >= 0) 28927c478bd9Sstevel@tonic-gate srvname[dotpos] = '.'; 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate reconnect: /* after switching to an encrypted connection */ 28957c478bd9Sstevel@tonic-gate # endif /* STARTTLS || SASL */ 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate /* set the current connection information */ 28987c478bd9Sstevel@tonic-gate e->e_mci = mci; 28997c478bd9Sstevel@tonic-gate # if SASL 29007c478bd9Sstevel@tonic-gate mci->mci_saslcap = NULL; 29017c478bd9Sstevel@tonic-gate # endif /* SASL */ 29027c478bd9Sstevel@tonic-gate smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); 29037c478bd9Sstevel@tonic-gate CLR_HELO(mci->mci_flags); 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate if (IS_DLVR_RETURN(e)) 29067c478bd9Sstevel@tonic-gate { 29077c478bd9Sstevel@tonic-gate /* 29087c478bd9Sstevel@tonic-gate ** Check whether other side can deliver e-mail 29097c478bd9Sstevel@tonic-gate ** fast enough 29107c478bd9Sstevel@tonic-gate */ 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate if (!bitset(MCIF_DLVR_BY, mci->mci_flags)) 29137c478bd9Sstevel@tonic-gate { 29147c478bd9Sstevel@tonic-gate e->e_status = "5.4.7"; 29157c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 29167c478bd9Sstevel@tonic-gate "554 Server does not support Deliver By"); 29177c478bd9Sstevel@tonic-gate rcode = EX_UNAVAILABLE; 29187c478bd9Sstevel@tonic-gate goto give_up; 29197c478bd9Sstevel@tonic-gate } 29207c478bd9Sstevel@tonic-gate if (e->e_deliver_by > 0 && 29217c478bd9Sstevel@tonic-gate e->e_deliver_by - (curtime() - e->e_ctime) < 29227c478bd9Sstevel@tonic-gate mci->mci_min_by) 29237c478bd9Sstevel@tonic-gate { 29247c478bd9Sstevel@tonic-gate e->e_status = "5.4.7"; 29257c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 29267c478bd9Sstevel@tonic-gate "554 Message can't be delivered in time; %ld < %ld", 29277c478bd9Sstevel@tonic-gate e->e_deliver_by - (curtime() - e->e_ctime), 29287c478bd9Sstevel@tonic-gate mci->mci_min_by); 29297c478bd9Sstevel@tonic-gate rcode = EX_UNAVAILABLE; 29307c478bd9Sstevel@tonic-gate goto give_up; 29317c478bd9Sstevel@tonic-gate } 29327c478bd9Sstevel@tonic-gate } 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate # if STARTTLS 29357c478bd9Sstevel@tonic-gate /* first TLS then AUTH to provide a security layer */ 29367c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED && 29377c478bd9Sstevel@tonic-gate !DONE_STARTTLS(mci->mci_flags)) 29387c478bd9Sstevel@tonic-gate { 29397c478bd9Sstevel@tonic-gate int olderrors; 29407c478bd9Sstevel@tonic-gate bool usetls; 29417c478bd9Sstevel@tonic-gate bool saveQuickAbort = QuickAbort; 29427c478bd9Sstevel@tonic-gate bool saveSuprErrs = SuprErrs; 29437c478bd9Sstevel@tonic-gate char *host = NULL; 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate rcode = EX_OK; 29467c478bd9Sstevel@tonic-gate usetls = bitset(MCIF_TLS, mci->mci_flags); 29477c478bd9Sstevel@tonic-gate if (usetls) 29487c478bd9Sstevel@tonic-gate usetls = !iscltflgset(e, D_NOTLS); 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate if (usetls) 29517c478bd9Sstevel@tonic-gate { 29527c478bd9Sstevel@tonic-gate host = macvalue(macid("{server_name}"), e); 29537c478bd9Sstevel@tonic-gate olderrors = Errors; 29547c478bd9Sstevel@tonic-gate QuickAbort = false; 29557c478bd9Sstevel@tonic-gate SuprErrs = true; 29567c478bd9Sstevel@tonic-gate if (rscheck("try_tls", host, NULL, e, 29577c478bd9Sstevel@tonic-gate RSF_RMCOMM, 7, host, NOQID) != EX_OK 29587c478bd9Sstevel@tonic-gate || Errors > olderrors) 29597c478bd9Sstevel@tonic-gate usetls = false; 29607c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs; 29617c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort; 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate if (usetls) 29657c478bd9Sstevel@tonic-gate { 29667c478bd9Sstevel@tonic-gate if ((rcode = starttls(m, mci, e)) == EX_OK) 29677c478bd9Sstevel@tonic-gate { 29687c478bd9Sstevel@tonic-gate /* start again without STARTTLS */ 29697c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_TLSACT; 29707c478bd9Sstevel@tonic-gate } 29717c478bd9Sstevel@tonic-gate else 29727c478bd9Sstevel@tonic-gate { 29737c478bd9Sstevel@tonic-gate char *s; 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate /* 29767c478bd9Sstevel@tonic-gate ** TLS negotation failed, what to do? 29777c478bd9Sstevel@tonic-gate ** fall back to unencrypted connection 29787c478bd9Sstevel@tonic-gate ** or abort? How to decide? 29797c478bd9Sstevel@tonic-gate ** set a macro and call a ruleset. 29807c478bd9Sstevel@tonic-gate */ 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_TLS; 29837c478bd9Sstevel@tonic-gate switch (rcode) 29847c478bd9Sstevel@tonic-gate { 29857c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 29867c478bd9Sstevel@tonic-gate s = "TEMP"; 29877c478bd9Sstevel@tonic-gate break; 29887c478bd9Sstevel@tonic-gate case EX_USAGE: 29897c478bd9Sstevel@tonic-gate s = "USAGE"; 29907c478bd9Sstevel@tonic-gate break; 29917c478bd9Sstevel@tonic-gate case EX_PROTOCOL: 29927c478bd9Sstevel@tonic-gate s = "PROTOCOL"; 29937c478bd9Sstevel@tonic-gate break; 29947c478bd9Sstevel@tonic-gate case EX_SOFTWARE: 29957c478bd9Sstevel@tonic-gate s = "SOFTWARE"; 29967c478bd9Sstevel@tonic-gate break; 2997445f2479Sjbeck case EX_UNAVAILABLE: 2998445f2479Sjbeck s = "NONE"; 2999445f2479Sjbeck break; 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate /* everything else is a failure */ 30027c478bd9Sstevel@tonic-gate default: 30037c478bd9Sstevel@tonic-gate s = "FAILURE"; 30047c478bd9Sstevel@tonic-gate rcode = EX_TEMPFAIL; 30057c478bd9Sstevel@tonic-gate } 30067c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 30077c478bd9Sstevel@tonic-gate macid("{verify}"), s); 30087c478bd9Sstevel@tonic-gate } 30097c478bd9Sstevel@tonic-gate } 30107c478bd9Sstevel@tonic-gate else 30117c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 30127c478bd9Sstevel@tonic-gate macid("{verify}"), "NONE"); 30137c478bd9Sstevel@tonic-gate olderrors = Errors; 30147c478bd9Sstevel@tonic-gate QuickAbort = false; 30157c478bd9Sstevel@tonic-gate SuprErrs = true; 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate /* 30187c478bd9Sstevel@tonic-gate ** rcode == EX_SOFTWARE is special: 30197c478bd9Sstevel@tonic-gate ** the TLS negotation failed 30207c478bd9Sstevel@tonic-gate ** we have to drop the connection no matter what 30217c478bd9Sstevel@tonic-gate ** However, we call tls_server to give it the chance 30227c478bd9Sstevel@tonic-gate ** to log the problem and return an appropriate 30237c478bd9Sstevel@tonic-gate ** error code. 30247c478bd9Sstevel@tonic-gate */ 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate if (rscheck("tls_server", 30277c478bd9Sstevel@tonic-gate macvalue(macid("{verify}"), e), 30287c478bd9Sstevel@tonic-gate NULL, e, RSF_RMCOMM|RSF_COUNT, 5, 30297c478bd9Sstevel@tonic-gate host, NOQID) != EX_OK || 30307c478bd9Sstevel@tonic-gate Errors > olderrors || 30317c478bd9Sstevel@tonic-gate rcode == EX_SOFTWARE) 30327c478bd9Sstevel@tonic-gate { 30337c478bd9Sstevel@tonic-gate char enhsc[ENHSCLEN]; 30347c478bd9Sstevel@tonic-gate extern char MsgBuf[]; 30357c478bd9Sstevel@tonic-gate 30367c478bd9Sstevel@tonic-gate if (ISSMTPCODE(MsgBuf) && 30377c478bd9Sstevel@tonic-gate extenhsc(MsgBuf + 4, ' ', enhsc) > 0) 30387c478bd9Sstevel@tonic-gate { 30397c478bd9Sstevel@tonic-gate p = sm_rpool_strdup_x(e->e_rpool, 30407c478bd9Sstevel@tonic-gate MsgBuf); 30417c478bd9Sstevel@tonic-gate } 30427c478bd9Sstevel@tonic-gate else 30437c478bd9Sstevel@tonic-gate { 30447c478bd9Sstevel@tonic-gate p = "403 4.7.0 server not authenticated."; 30457c478bd9Sstevel@tonic-gate (void) sm_strlcpy(enhsc, "4.7.0", 30467c478bd9Sstevel@tonic-gate sizeof enhsc); 30477c478bd9Sstevel@tonic-gate } 30487c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs; 30497c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort; 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate if (rcode == EX_SOFTWARE) 30527c478bd9Sstevel@tonic-gate { 30537c478bd9Sstevel@tonic-gate /* drop the connection */ 30547c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_QUITING; 30557c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL) 30567c478bd9Sstevel@tonic-gate { 30577c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_in, 30587c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT); 30597c478bd9Sstevel@tonic-gate mci->mci_in = NULL; 30607c478bd9Sstevel@tonic-gate } 30617c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_TLSACT; 30627c478bd9Sstevel@tonic-gate (void) endmailer(mci, e, pv); 30637c478bd9Sstevel@tonic-gate } 30647c478bd9Sstevel@tonic-gate else 30657c478bd9Sstevel@tonic-gate { 30667c478bd9Sstevel@tonic-gate /* abort transfer */ 30677c478bd9Sstevel@tonic-gate smtpquit(m, mci, e); 30687c478bd9Sstevel@tonic-gate } 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate /* avoid bogus error msg */ 30717c478bd9Sstevel@tonic-gate mci->mci_errno = 0; 30727c478bd9Sstevel@tonic-gate 30737c478bd9Sstevel@tonic-gate /* temp or permanent failure? */ 30747c478bd9Sstevel@tonic-gate rcode = (*p == '4') ? EX_TEMPFAIL 30757c478bd9Sstevel@tonic-gate : EX_UNAVAILABLE; 30767c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, enhsc, p); 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate /* 30797c478bd9Sstevel@tonic-gate ** hack to get the error message into 30807c478bd9Sstevel@tonic-gate ** the envelope (done in giveresponse()) 30817c478bd9Sstevel@tonic-gate */ 30827c478bd9Sstevel@tonic-gate 30837c478bd9Sstevel@tonic-gate (void) sm_strlcpy(SmtpError, p, 30847c478bd9Sstevel@tonic-gate sizeof SmtpError); 30857c478bd9Sstevel@tonic-gate } 30867c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort; 30877c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs; 30887c478bd9Sstevel@tonic-gate if (DONE_STARTTLS(mci->mci_flags) && 30897c478bd9Sstevel@tonic-gate mci->mci_state != MCIS_CLOSED) 30907c478bd9Sstevel@tonic-gate { 30917c478bd9Sstevel@tonic-gate SET_HELO(mci->mci_flags); 30927c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_EXTENS; 30937c478bd9Sstevel@tonic-gate goto reconnect; 30947c478bd9Sstevel@tonic-gate } 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 30977c478bd9Sstevel@tonic-gate # if SASL 30987c478bd9Sstevel@tonic-gate /* if other server supports authentication let's authenticate */ 30997c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED && 31007c478bd9Sstevel@tonic-gate mci->mci_saslcap != NULL && 31017c478bd9Sstevel@tonic-gate !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH)) 31027c478bd9Sstevel@tonic-gate { 31037c478bd9Sstevel@tonic-gate /* Should we require some minimum authentication? */ 31047c478bd9Sstevel@tonic-gate if ((ret = smtpauth(m, mci, e)) == EX_OK) 31057c478bd9Sstevel@tonic-gate { 31067c478bd9Sstevel@tonic-gate int result; 31077c478bd9Sstevel@tonic-gate sasl_ssf_t *ssf = NULL; 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate /* Get security strength (features) */ 31107c478bd9Sstevel@tonic-gate result = sasl_getprop(mci->mci_conn, SASL_SSF, 31117c478bd9Sstevel@tonic-gate # if SASL >= 20000 31127c478bd9Sstevel@tonic-gate (const void **) &ssf); 31137c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 31147c478bd9Sstevel@tonic-gate (void **) &ssf); 31157c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 31167c478bd9Sstevel@tonic-gate 31177c478bd9Sstevel@tonic-gate /* XXX authid? */ 31187c478bd9Sstevel@tonic-gate if (LogLevel > 9) 31197c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 31207c478bd9Sstevel@tonic-gate "AUTH=client, relay=%.100s, mech=%.16s, bits=%d", 31217c478bd9Sstevel@tonic-gate mci->mci_host, 31227c478bd9Sstevel@tonic-gate macvalue(macid("{auth_type}"), e), 31237c478bd9Sstevel@tonic-gate result == SASL_OK ? *ssf : 0); 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate /* 31267c478bd9Sstevel@tonic-gate ** Only switch to encrypted connection 31277c478bd9Sstevel@tonic-gate ** if a security layer has been negotiated 31287c478bd9Sstevel@tonic-gate */ 31297c478bd9Sstevel@tonic-gate 31307c478bd9Sstevel@tonic-gate if (result == SASL_OK && *ssf > 0) 31317c478bd9Sstevel@tonic-gate { 3132*3ee0e492Sjbeck int tmo; 3133*3ee0e492Sjbeck 31347c478bd9Sstevel@tonic-gate /* 31357c478bd9Sstevel@tonic-gate ** Convert I/O layer to use SASL. 31367c478bd9Sstevel@tonic-gate ** If the call fails, the connection 31377c478bd9Sstevel@tonic-gate ** is aborted. 31387c478bd9Sstevel@tonic-gate */ 31397c478bd9Sstevel@tonic-gate 3140*3ee0e492Sjbeck tmo = DATA_PROGRESS_TIMEOUT * 1000; 31417c478bd9Sstevel@tonic-gate if (sfdcsasl(&mci->mci_in, 31427c478bd9Sstevel@tonic-gate &mci->mci_out, 3143*3ee0e492Sjbeck mci->mci_conn, tmo) == 0) 31447c478bd9Sstevel@tonic-gate { 31457c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_EXTENS; 31467c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTHACT| 31477c478bd9Sstevel@tonic-gate MCIF_ONLY_EHLO; 31487c478bd9Sstevel@tonic-gate goto reconnect; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate syserr("AUTH TLS switch failed in client"); 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate /* else? XXX */ 31537c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTHACT; 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate else if (ret == EX_TEMPFAIL) 31577c478bd9Sstevel@tonic-gate { 31587c478bd9Sstevel@tonic-gate if (LogLevel > 8) 31597c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 31607c478bd9Sstevel@tonic-gate "AUTH=client, relay=%.100s, temporary failure, connection abort", 31617c478bd9Sstevel@tonic-gate mci->mci_host); 31627c478bd9Sstevel@tonic-gate smtpquit(m, mci, e); 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate /* avoid bogus error msg */ 31657c478bd9Sstevel@tonic-gate mci->mci_errno = 0; 31667c478bd9Sstevel@tonic-gate rcode = EX_TEMPFAIL; 31677c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, "4.3.0", p); 31687c478bd9Sstevel@tonic-gate 31697c478bd9Sstevel@tonic-gate /* 31707c478bd9Sstevel@tonic-gate ** hack to get the error message into 31717c478bd9Sstevel@tonic-gate ** the envelope (done in giveresponse()) 31727c478bd9Sstevel@tonic-gate */ 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate (void) sm_strlcpy(SmtpError, 31757c478bd9Sstevel@tonic-gate "Temporary AUTH failure", 31767c478bd9Sstevel@tonic-gate sizeof SmtpError); 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate } 31797c478bd9Sstevel@tonic-gate # endif /* SASL */ 31807c478bd9Sstevel@tonic-gate } 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate do_transfer: 31847c478bd9Sstevel@tonic-gate /* clear out per-message flags from connection structure */ 31857c478bd9Sstevel@tonic-gate mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 31887c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) && 31897c478bd9Sstevel@tonic-gate bitnset(M_7BITS, m->m_flags)) 31907c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CVT8TO7; 31917c478bd9Sstevel@tonic-gate 31927c478bd9Sstevel@tonic-gate #if MIME7TO8 31937c478bd9Sstevel@tonic-gate if (bitnset(M_MAKE8BIT, m->m_flags) && 31947c478bd9Sstevel@tonic-gate !bitset(MCIF_7BIT, mci->mci_flags) && 31957c478bd9Sstevel@tonic-gate (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 31967c478bd9Sstevel@tonic-gate (sm_strcasecmp(p, "quoted-printable") == 0 || 31977c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "base64") == 0) && 31987c478bd9Sstevel@tonic-gate (p = hvalue("Content-Type", e->e_header)) != NULL) 31997c478bd9Sstevel@tonic-gate { 32007c478bd9Sstevel@tonic-gate /* may want to convert 7 -> 8 */ 32017c478bd9Sstevel@tonic-gate /* XXX should really parse it here -- and use a class XXX */ 32027c478bd9Sstevel@tonic-gate if (sm_strncasecmp(p, "text/plain", 10) == 0 && 32037c478bd9Sstevel@tonic-gate (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 32047c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CVT7TO8; 32057c478bd9Sstevel@tonic-gate } 32067c478bd9Sstevel@tonic-gate #endif /* MIME7TO8 */ 32077c478bd9Sstevel@tonic-gate 32087c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 32097c478bd9Sstevel@tonic-gate { 32107c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: "); 32117c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false); 32127c478bd9Sstevel@tonic-gate } 32137c478bd9Sstevel@tonic-gate 32147c478bd9Sstevel@tonic-gate #if _FFR_CLIENT_SIZE 32157c478bd9Sstevel@tonic-gate /* 32167c478bd9Sstevel@tonic-gate ** See if we know the maximum size and 32177c478bd9Sstevel@tonic-gate ** abort if the message is too big. 32187c478bd9Sstevel@tonic-gate ** 32197c478bd9Sstevel@tonic-gate ** NOTE: _FFR_CLIENT_SIZE is untested. 32207c478bd9Sstevel@tonic-gate */ 32217c478bd9Sstevel@tonic-gate 32227c478bd9Sstevel@tonic-gate if (bitset(MCIF_SIZE, mci->mci_flags) && 32237c478bd9Sstevel@tonic-gate mci->mci_maxsize > 0 && 32247c478bd9Sstevel@tonic-gate e->e_msgsize > mci->mci_maxsize) 32257c478bd9Sstevel@tonic-gate { 32267c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 32277c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags)) 32287c478bd9Sstevel@tonic-gate e->e_status = "5.2.3"; 32297c478bd9Sstevel@tonic-gate else 32307c478bd9Sstevel@tonic-gate e->e_status = "5.3.4"; 32317c478bd9Sstevel@tonic-gate 32327c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 32337c478bd9Sstevel@tonic-gate "552 Message is too large; %ld bytes max", 32347c478bd9Sstevel@tonic-gate mci->mci_maxsize); 32357c478bd9Sstevel@tonic-gate rcode = EX_DATAERR; 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* Need an e_message for error */ 32387c478bd9Sstevel@tonic-gate (void) sm_snprintf(SmtpError, sizeof SmtpError, 32397c478bd9Sstevel@tonic-gate "Message is too large; %ld bytes max", 32407c478bd9Sstevel@tonic-gate mci->mci_maxsize); 32417c478bd9Sstevel@tonic-gate goto give_up; 32427c478bd9Sstevel@tonic-gate } 32437c478bd9Sstevel@tonic-gate #endif /* _FFR_CLIENT_SIZE */ 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_OPEN) 32467c478bd9Sstevel@tonic-gate { 32477c478bd9Sstevel@tonic-gate /* couldn't open the mailer */ 32487c478bd9Sstevel@tonic-gate rcode = mci->mci_exitstat; 32497c478bd9Sstevel@tonic-gate errno = mci->mci_errno; 32507c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(mci->mci_herrno); 32517c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 32527c478bd9Sstevel@tonic-gate { 32537c478bd9Sstevel@tonic-gate /* shouldn't happen */ 32547c478bd9Sstevel@tonic-gate syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 32557c478bd9Sstevel@tonic-gate (unsigned long) mci, rcode, errno, 32567c478bd9Sstevel@tonic-gate mci->mci_state, firstsig); 32577c478bd9Sstevel@tonic-gate mci_dump_all(smioout, true); 32587c478bd9Sstevel@tonic-gate rcode = EX_SOFTWARE; 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate else if (nummxhosts > hostnum) 32617c478bd9Sstevel@tonic-gate { 32627c478bd9Sstevel@tonic-gate /* try next MX site */ 32637c478bd9Sstevel@tonic-gate goto tryhost; 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate else if (!clever) 32677c478bd9Sstevel@tonic-gate { 3268445f2479Sjbeck bool ok; 3269445f2479Sjbeck 32707c478bd9Sstevel@tonic-gate /* 32717c478bd9Sstevel@tonic-gate ** Format and send message. 32727c478bd9Sstevel@tonic-gate */ 32737c478bd9Sstevel@tonic-gate 3274445f2479Sjbeck rcode = EX_OK; 3275445f2479Sjbeck errno = 0; 3276445f2479Sjbeck ok = putfromline(mci, e); 3277445f2479Sjbeck if (ok) 3278445f2479Sjbeck ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 3279445f2479Sjbeck if (ok) 3280445f2479Sjbeck ok = (*e->e_putbody)(mci, e, NULL); 32817c478bd9Sstevel@tonic-gate 3282445f2479Sjbeck /* 3283445f2479Sjbeck ** Ignore an I/O error that was caused by EPIPE. 3284445f2479Sjbeck ** Some broken mailers don't read the entire body 3285445f2479Sjbeck ** but just exit() thus causing an I/O error. 3286445f2479Sjbeck */ 3287445f2479Sjbeck 3288445f2479Sjbeck if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE)) 3289445f2479Sjbeck ok = true; 3290445f2479Sjbeck 3291445f2479Sjbeck /* (always) get the exit status */ 32927c478bd9Sstevel@tonic-gate rcode = endmailer(mci, e, pv); 3293445f2479Sjbeck if (!ok) 3294445f2479Sjbeck rcode = EX_TEMPFAIL; 32957c478bd9Sstevel@tonic-gate if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 32967c478bd9Sstevel@tonic-gate { 32977c478bd9Sstevel@tonic-gate /* 32987c478bd9Sstevel@tonic-gate ** Need an e_message for mailq display. 32997c478bd9Sstevel@tonic-gate ** We set SmtpError as 33007c478bd9Sstevel@tonic-gate */ 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate (void) sm_snprintf(SmtpError, sizeof SmtpError, 33037c478bd9Sstevel@tonic-gate "%s mailer (%s) exited with EX_TEMPFAIL", 33047c478bd9Sstevel@tonic-gate m->m_name, m->m_mailer); 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate else 33087c478bd9Sstevel@tonic-gate { 33097c478bd9Sstevel@tonic-gate /* 33107c478bd9Sstevel@tonic-gate ** Send the MAIL FROM: protocol 33117c478bd9Sstevel@tonic-gate */ 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate /* XXX this isn't pipelined... */ 33147c478bd9Sstevel@tonic-gate rcode = smtpmailfrom(m, mci, e); 33157c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 33167c478bd9Sstevel@tonic-gate { 33177c478bd9Sstevel@tonic-gate register int i; 33187c478bd9Sstevel@tonic-gate # if PIPELINING 33197c478bd9Sstevel@tonic-gate ADDRESS *volatile pchain; 33207c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate /* send the recipient list */ 33237c478bd9Sstevel@tonic-gate tobuf[0] = '\0'; 33247c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = false; 33257c478bd9Sstevel@tonic-gate mci->mci_tolist = tobuf; 33267c478bd9Sstevel@tonic-gate # if PIPELINING 33277c478bd9Sstevel@tonic-gate pchain = NULL; 33287c478bd9Sstevel@tonic-gate mci->mci_nextaddr = NULL; 33297c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33307c478bd9Sstevel@tonic-gate 33317c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 33327c478bd9Sstevel@tonic-gate { 33337c478bd9Sstevel@tonic-gate if (!QS_IS_UNMARKED(to->q_state)) 33347c478bd9Sstevel@tonic-gate continue; 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate /* mark recipient state as "ok so far" */ 33377c478bd9Sstevel@tonic-gate to->q_state = QS_OK; 33387c478bd9Sstevel@tonic-gate e->e_to = to->q_paddr; 33397c478bd9Sstevel@tonic-gate # if STARTTLS 33407c478bd9Sstevel@tonic-gate i = rscheck("tls_rcpt", to->q_user, NULL, e, 33417c478bd9Sstevel@tonic-gate RSF_RMCOMM|RSF_COUNT, 3, 33427c478bd9Sstevel@tonic-gate mci->mci_host, e->e_id); 33437c478bd9Sstevel@tonic-gate if (i != EX_OK) 33447c478bd9Sstevel@tonic-gate { 33457c478bd9Sstevel@tonic-gate markfailure(e, to, mci, i, false); 33467c478bd9Sstevel@tonic-gate giveresponse(i, to->q_status, m, mci, 33477c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 33487c478bd9Sstevel@tonic-gate if (i == EX_TEMPFAIL) 33497c478bd9Sstevel@tonic-gate { 33507c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = true; 33517c478bd9Sstevel@tonic-gate to->q_state = QS_RETRY; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate continue; 33547c478bd9Sstevel@tonic-gate } 33557c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate i = smtprcpt(to, m, mci, e, ctladdr, xstart); 33587c478bd9Sstevel@tonic-gate # if PIPELINING 33597c478bd9Sstevel@tonic-gate if (i == EX_OK && 33607c478bd9Sstevel@tonic-gate bitset(MCIF_PIPELINED, mci->mci_flags)) 33617c478bd9Sstevel@tonic-gate { 33627c478bd9Sstevel@tonic-gate /* 33637c478bd9Sstevel@tonic-gate ** Add new element to list of 33647c478bd9Sstevel@tonic-gate ** recipients for pipelining. 33657c478bd9Sstevel@tonic-gate */ 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate to->q_pchain = NULL; 33687c478bd9Sstevel@tonic-gate if (mci->mci_nextaddr == NULL) 33697c478bd9Sstevel@tonic-gate mci->mci_nextaddr = to; 33707c478bd9Sstevel@tonic-gate if (pchain == NULL) 33717c478bd9Sstevel@tonic-gate pchain = to; 33727c478bd9Sstevel@tonic-gate else 33737c478bd9Sstevel@tonic-gate { 33747c478bd9Sstevel@tonic-gate pchain->q_pchain = to; 33757c478bd9Sstevel@tonic-gate pchain = pchain->q_pchain; 33767c478bd9Sstevel@tonic-gate } 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33797c478bd9Sstevel@tonic-gate if (i != EX_OK) 33807c478bd9Sstevel@tonic-gate { 33817c478bd9Sstevel@tonic-gate markfailure(e, to, mci, i, false); 33827c478bd9Sstevel@tonic-gate giveresponse(i, to->q_status, m, mci, 33837c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 33847c478bd9Sstevel@tonic-gate if (i == EX_TEMPFAIL) 33857c478bd9Sstevel@tonic-gate to->q_state = QS_RETRY; 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate /* No recipients in list and no missing responses? */ 33907c478bd9Sstevel@tonic-gate if (tobuf[0] == '\0' 33917c478bd9Sstevel@tonic-gate # if PIPELINING 33927c478bd9Sstevel@tonic-gate && mci->mci_nextaddr == NULL 33937c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33947c478bd9Sstevel@tonic-gate ) 33957c478bd9Sstevel@tonic-gate { 33967c478bd9Sstevel@tonic-gate rcode = EX_OK; 33977c478bd9Sstevel@tonic-gate e->e_to = NULL; 33987c478bd9Sstevel@tonic-gate if (bitset(MCIF_CACHED, mci->mci_flags)) 33997c478bd9Sstevel@tonic-gate smtprset(m, mci, e); 34007c478bd9Sstevel@tonic-gate } 34017c478bd9Sstevel@tonic-gate else 34027c478bd9Sstevel@tonic-gate { 34037c478bd9Sstevel@tonic-gate e->e_to = tobuf + 1; 34047c478bd9Sstevel@tonic-gate rcode = smtpdata(m, mci, e, ctladdr, xstart); 34057c478bd9Sstevel@tonic-gate } 34067c478bd9Sstevel@tonic-gate } 34077c478bd9Sstevel@tonic-gate if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 34087c478bd9Sstevel@tonic-gate { 34097c478bd9Sstevel@tonic-gate /* try next MX site */ 34107c478bd9Sstevel@tonic-gate goto tryhost; 34117c478bd9Sstevel@tonic-gate } 34127c478bd9Sstevel@tonic-gate } 34137c478bd9Sstevel@tonic-gate #if NAMED_BIND 34147c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 34157c478bd9Sstevel@tonic-gate _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 34167c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate if (tTd(62, 1)) 34197c478bd9Sstevel@tonic-gate checkfds("after delivery"); 34207c478bd9Sstevel@tonic-gate 34217c478bd9Sstevel@tonic-gate /* 34227c478bd9Sstevel@tonic-gate ** Do final status disposal. 34237c478bd9Sstevel@tonic-gate ** We check for something in tobuf for the SMTP case. 34247c478bd9Sstevel@tonic-gate ** If we got a temporary failure, arrange to queue the 34257c478bd9Sstevel@tonic-gate ** addressees. 34267c478bd9Sstevel@tonic-gate */ 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate give_up: 34297c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 34307c478bd9Sstevel@tonic-gate { 34317c478bd9Sstevel@tonic-gate lmtp_rcode = rcode; 34327c478bd9Sstevel@tonic-gate tobuf[0] = '\0'; 34337c478bd9Sstevel@tonic-gate anyok = false; 34347c478bd9Sstevel@tonic-gate strsize = 0; 34357c478bd9Sstevel@tonic-gate } 34367c478bd9Sstevel@tonic-gate else 34377c478bd9Sstevel@tonic-gate anyok = rcode == EX_OK; 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 34407c478bd9Sstevel@tonic-gate { 34417c478bd9Sstevel@tonic-gate /* see if address already marked */ 34427c478bd9Sstevel@tonic-gate if (!QS_IS_OK(to->q_state)) 34437c478bd9Sstevel@tonic-gate continue; 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate /* if running LMTP, get the status for each address */ 34467c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 34477c478bd9Sstevel@tonic-gate { 34487c478bd9Sstevel@tonic-gate if (lmtp_rcode == EX_OK) 34497c478bd9Sstevel@tonic-gate rcode = smtpgetstat(m, mci, e); 34507c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 34517c478bd9Sstevel@tonic-gate { 34527c478bd9Sstevel@tonic-gate strsize += sm_strlcat2(tobuf + strsize, ",", 34537c478bd9Sstevel@tonic-gate to->q_paddr, 34547c478bd9Sstevel@tonic-gate tobufsize - strsize); 34557c478bd9Sstevel@tonic-gate SM_ASSERT(strsize < tobufsize); 34567c478bd9Sstevel@tonic-gate anyok = true; 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate else 34597c478bd9Sstevel@tonic-gate { 34607c478bd9Sstevel@tonic-gate e->e_to = to->q_paddr; 34617c478bd9Sstevel@tonic-gate markfailure(e, to, mci, rcode, true); 34627c478bd9Sstevel@tonic-gate giveresponse(rcode, to->q_status, m, mci, 34637c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 34647c478bd9Sstevel@tonic-gate e->e_to = tobuf + 1; 34657c478bd9Sstevel@tonic-gate continue; 34667c478bd9Sstevel@tonic-gate } 34677c478bd9Sstevel@tonic-gate } 34687c478bd9Sstevel@tonic-gate else 34697c478bd9Sstevel@tonic-gate { 34707c478bd9Sstevel@tonic-gate /* mark bad addresses */ 34717c478bd9Sstevel@tonic-gate if (rcode != EX_OK) 34727c478bd9Sstevel@tonic-gate { 34737c478bd9Sstevel@tonic-gate if (goodmxfound && rcode == EX_NOHOST) 34747c478bd9Sstevel@tonic-gate rcode = EX_TEMPFAIL; 34757c478bd9Sstevel@tonic-gate markfailure(e, to, mci, rcode, true); 34767c478bd9Sstevel@tonic-gate continue; 34777c478bd9Sstevel@tonic-gate } 34787c478bd9Sstevel@tonic-gate } 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate /* successful delivery */ 34817c478bd9Sstevel@tonic-gate to->q_state = QS_SENT; 34827c478bd9Sstevel@tonic-gate to->q_statdate = curtime(); 34837c478bd9Sstevel@tonic-gate e->e_nsent++; 34847c478bd9Sstevel@tonic-gate 34857c478bd9Sstevel@tonic-gate /* 34867c478bd9Sstevel@tonic-gate ** Checkpoint the send list every few addresses 34877c478bd9Sstevel@tonic-gate */ 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 34907c478bd9Sstevel@tonic-gate { 34917c478bd9Sstevel@tonic-gate queueup(e, false, false); 34927c478bd9Sstevel@tonic-gate e->e_nsent = 0; 34937c478bd9Sstevel@tonic-gate } 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) && 34967c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags)) 34977c478bd9Sstevel@tonic-gate { 34987c478bd9Sstevel@tonic-gate to->q_flags |= QDELIVERED; 34997c478bd9Sstevel@tonic-gate to->q_status = "2.1.5"; 35007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35017c478bd9Sstevel@tonic-gate "%s... Successfully delivered\n", 35027c478bd9Sstevel@tonic-gate to->q_paddr); 35037c478bd9Sstevel@tonic-gate } 35047c478bd9Sstevel@tonic-gate else if (bitset(QPINGONSUCCESS, to->q_flags) && 35057c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags) && 35067c478bd9Sstevel@tonic-gate !bitset(MCIF_DSN, mci->mci_flags)) 35077c478bd9Sstevel@tonic-gate { 35087c478bd9Sstevel@tonic-gate to->q_flags |= QRELAYED; 35097c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35107c478bd9Sstevel@tonic-gate "%s... relayed; expect no further notifications\n", 35117c478bd9Sstevel@tonic-gate to->q_paddr); 35127c478bd9Sstevel@tonic-gate } 35137c478bd9Sstevel@tonic-gate else if (IS_DLVR_NOTIFY(e) && 35147c478bd9Sstevel@tonic-gate !bitset(MCIF_DLVR_BY, mci->mci_flags) && 35157c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags) && 35167c478bd9Sstevel@tonic-gate (!bitset(QHASNOTIFY, to->q_flags) || 35177c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags) || 35187c478bd9Sstevel@tonic-gate bitset(QPINGONFAILURE, to->q_flags) || 35197c478bd9Sstevel@tonic-gate bitset(QPINGONDELAY, to->q_flags))) 35207c478bd9Sstevel@tonic-gate { 35217c478bd9Sstevel@tonic-gate /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 35227c478bd9Sstevel@tonic-gate to->q_flags |= QBYNRELAY; 35237c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35247c478bd9Sstevel@tonic-gate "%s... Deliver-by notify: relayed\n", 35257c478bd9Sstevel@tonic-gate to->q_paddr); 35267c478bd9Sstevel@tonic-gate } 35277c478bd9Sstevel@tonic-gate else if (IS_DLVR_TRACE(e) && 35287c478bd9Sstevel@tonic-gate (!bitset(QHASNOTIFY, to->q_flags) || 35297c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags) || 35307c478bd9Sstevel@tonic-gate bitset(QPINGONFAILURE, to->q_flags) || 35317c478bd9Sstevel@tonic-gate bitset(QPINGONDELAY, to->q_flags)) && 35327c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags)) 35337c478bd9Sstevel@tonic-gate { 35347c478bd9Sstevel@tonic-gate /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 35357c478bd9Sstevel@tonic-gate to->q_flags |= QBYTRACE; 35367c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35377c478bd9Sstevel@tonic-gate "%s... Deliver-By trace: relayed\n", 35387c478bd9Sstevel@tonic-gate to->q_paddr); 35397c478bd9Sstevel@tonic-gate } 35407c478bd9Sstevel@tonic-gate } 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 35437c478bd9Sstevel@tonic-gate { 35447c478bd9Sstevel@tonic-gate /* 35457c478bd9Sstevel@tonic-gate ** Global information applies to the last recipient only; 35467c478bd9Sstevel@tonic-gate ** clear it out to avoid bogus errors. 35477c478bd9Sstevel@tonic-gate */ 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate rcode = EX_OK; 35507c478bd9Sstevel@tonic-gate e->e_statmsg = NULL; 35517c478bd9Sstevel@tonic-gate 35527c478bd9Sstevel@tonic-gate /* reset the mci state for the next transaction */ 35537c478bd9Sstevel@tonic-gate if (mci != NULL && 35547c478bd9Sstevel@tonic-gate (mci->mci_state == MCIS_MAIL || 35557c478bd9Sstevel@tonic-gate mci->mci_state == MCIS_RCPT || 35567c478bd9Sstevel@tonic-gate mci->mci_state == MCIS_DATA)) 35577c478bd9Sstevel@tonic-gate { 35587c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN; 35597c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "idle"; 35607c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s: %s", CurHostName, 35617c478bd9Sstevel@tonic-gate mci->mci_phase); 35627c478bd9Sstevel@tonic-gate } 35637c478bd9Sstevel@tonic-gate } 35647c478bd9Sstevel@tonic-gate 35657c478bd9Sstevel@tonic-gate if (tobuf[0] != '\0') 35667c478bd9Sstevel@tonic-gate { 35677c478bd9Sstevel@tonic-gate giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); 35687c478bd9Sstevel@tonic-gate #if 0 35697c478bd9Sstevel@tonic-gate /* 35707c478bd9Sstevel@tonic-gate ** This code is disabled for now because I am not 35717c478bd9Sstevel@tonic-gate ** sure that copying status from the first recipient 35727c478bd9Sstevel@tonic-gate ** to all non-status'ed recipients is a good idea. 35737c478bd9Sstevel@tonic-gate */ 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate if (tochain->q_message != NULL && 35767c478bd9Sstevel@tonic-gate !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 35777c478bd9Sstevel@tonic-gate { 35787c478bd9Sstevel@tonic-gate for (to = tochain->q_tchain; to != NULL; 35797c478bd9Sstevel@tonic-gate to = to->q_tchain) 35807c478bd9Sstevel@tonic-gate { 35817c478bd9Sstevel@tonic-gate /* see if address already marked */ 35827c478bd9Sstevel@tonic-gate if (QS_IS_QUEUEUP(to->q_state) && 35837c478bd9Sstevel@tonic-gate to->q_message == NULL) 35847c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 35857c478bd9Sstevel@tonic-gate tochain->q_message); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate } 35887c478bd9Sstevel@tonic-gate #endif /* 0 */ 35897c478bd9Sstevel@tonic-gate } 35907c478bd9Sstevel@tonic-gate if (anyok) 35917c478bd9Sstevel@tonic-gate markstats(e, tochain, STATS_NORMAL); 35927c478bd9Sstevel@tonic-gate mci_store_persistent(mci); 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate /* Some recipients were tempfailed, try them on the next host */ 35957c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 35967c478bd9Sstevel@tonic-gate { 35977c478bd9Sstevel@tonic-gate /* try next MX site */ 35987c478bd9Sstevel@tonic-gate goto tryhost; 35997c478bd9Sstevel@tonic-gate } 36007c478bd9Sstevel@tonic-gate 36017c478bd9Sstevel@tonic-gate /* now close the connection */ 36027c478bd9Sstevel@tonic-gate if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 36037c478bd9Sstevel@tonic-gate !bitset(MCIF_CACHED, mci->mci_flags)) 36047c478bd9Sstevel@tonic-gate smtpquit(m, mci, e); 36057c478bd9Sstevel@tonic-gate 36067c478bd9Sstevel@tonic-gate cleanup: ; 36077c478bd9Sstevel@tonic-gate } 36087c478bd9Sstevel@tonic-gate SM_FINALLY 36097c478bd9Sstevel@tonic-gate { 36107c478bd9Sstevel@tonic-gate /* 36117c478bd9Sstevel@tonic-gate ** Restore state and return. 36127c478bd9Sstevel@tonic-gate */ 36137c478bd9Sstevel@tonic-gate #if XDEBUG 36147c478bd9Sstevel@tonic-gate char wbuf[MAXLINE]; 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate /* make absolutely certain 0, 1, and 2 are in use */ 36177c478bd9Sstevel@tonic-gate (void) sm_snprintf(wbuf, sizeof wbuf, 36187c478bd9Sstevel@tonic-gate "%s... end of deliver(%s)", 36197c478bd9Sstevel@tonic-gate e->e_to == NULL ? "NO-TO-LIST" 36207c478bd9Sstevel@tonic-gate : shortenstring(e->e_to, 36217c478bd9Sstevel@tonic-gate MAXSHORTSTR), 36227c478bd9Sstevel@tonic-gate m->m_name); 36237c478bd9Sstevel@tonic-gate checkfd012(wbuf); 36247c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate errno = 0; 36277c478bd9Sstevel@tonic-gate 36287c478bd9Sstevel@tonic-gate /* 36297c478bd9Sstevel@tonic-gate ** It was originally necessary to set macro 'g' to NULL 36307c478bd9Sstevel@tonic-gate ** because it previously pointed to an auto buffer. 36317c478bd9Sstevel@tonic-gate ** We don't do this any more, so this may be unnecessary. 36327c478bd9Sstevel@tonic-gate */ 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 36357c478bd9Sstevel@tonic-gate e->e_to = NULL; 36367c478bd9Sstevel@tonic-gate } 36377c478bd9Sstevel@tonic-gate SM_END_TRY 36387c478bd9Sstevel@tonic-gate return rcode; 36397c478bd9Sstevel@tonic-gate } 36407c478bd9Sstevel@tonic-gate 36417c478bd9Sstevel@tonic-gate /* 36427c478bd9Sstevel@tonic-gate ** MARKFAILURE -- mark a failure on a specific address. 36437c478bd9Sstevel@tonic-gate ** 36447c478bd9Sstevel@tonic-gate ** Parameters: 36457c478bd9Sstevel@tonic-gate ** e -- the envelope we are sending. 36467c478bd9Sstevel@tonic-gate ** q -- the address to mark. 36477c478bd9Sstevel@tonic-gate ** mci -- mailer connection information. 36487c478bd9Sstevel@tonic-gate ** rcode -- the code signifying the particular failure. 36497c478bd9Sstevel@tonic-gate ** ovr -- override an existing code? 36507c478bd9Sstevel@tonic-gate ** 36517c478bd9Sstevel@tonic-gate ** Returns: 36527c478bd9Sstevel@tonic-gate ** none. 36537c478bd9Sstevel@tonic-gate ** 36547c478bd9Sstevel@tonic-gate ** Side Effects: 36557c478bd9Sstevel@tonic-gate ** marks the address (and possibly the envelope) with the 36567c478bd9Sstevel@tonic-gate ** failure so that an error will be returned or 36577c478bd9Sstevel@tonic-gate ** the message will be queued, as appropriate. 36587c478bd9Sstevel@tonic-gate */ 36597c478bd9Sstevel@tonic-gate 36607c478bd9Sstevel@tonic-gate void 36617c478bd9Sstevel@tonic-gate markfailure(e, q, mci, rcode, ovr) 36627c478bd9Sstevel@tonic-gate register ENVELOPE *e; 36637c478bd9Sstevel@tonic-gate register ADDRESS *q; 36647c478bd9Sstevel@tonic-gate register MCI *mci; 36657c478bd9Sstevel@tonic-gate int rcode; 36667c478bd9Sstevel@tonic-gate bool ovr; 36677c478bd9Sstevel@tonic-gate { 36687c478bd9Sstevel@tonic-gate int save_errno = errno; 36697c478bd9Sstevel@tonic-gate char *status = NULL; 36707c478bd9Sstevel@tonic-gate char *rstatus = NULL; 36717c478bd9Sstevel@tonic-gate 36727c478bd9Sstevel@tonic-gate switch (rcode) 36737c478bd9Sstevel@tonic-gate { 36747c478bd9Sstevel@tonic-gate case EX_OK: 36757c478bd9Sstevel@tonic-gate break; 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 36787c478bd9Sstevel@tonic-gate case EX_IOERR: 36797c478bd9Sstevel@tonic-gate case EX_OSERR: 36807c478bd9Sstevel@tonic-gate q->q_state = QS_QUEUEUP; 36817c478bd9Sstevel@tonic-gate break; 36827c478bd9Sstevel@tonic-gate 36837c478bd9Sstevel@tonic-gate default: 36847c478bd9Sstevel@tonic-gate q->q_state = QS_BADADDR; 36857c478bd9Sstevel@tonic-gate break; 36867c478bd9Sstevel@tonic-gate } 36877c478bd9Sstevel@tonic-gate 36887c478bd9Sstevel@tonic-gate /* find most specific error code possible */ 36897c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_status != NULL) 36907c478bd9Sstevel@tonic-gate { 36917c478bd9Sstevel@tonic-gate status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 36927c478bd9Sstevel@tonic-gate if (mci->mci_rstatus != NULL) 36937c478bd9Sstevel@tonic-gate rstatus = sm_rpool_strdup_x(e->e_rpool, 36947c478bd9Sstevel@tonic-gate mci->mci_rstatus); 36957c478bd9Sstevel@tonic-gate else 36967c478bd9Sstevel@tonic-gate rstatus = NULL; 36977c478bd9Sstevel@tonic-gate } 36987c478bd9Sstevel@tonic-gate else if (e->e_status != NULL) 36997c478bd9Sstevel@tonic-gate { 37007c478bd9Sstevel@tonic-gate status = e->e_status; 37017c478bd9Sstevel@tonic-gate rstatus = NULL; 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate else 37047c478bd9Sstevel@tonic-gate { 37057c478bd9Sstevel@tonic-gate switch (rcode) 37067c478bd9Sstevel@tonic-gate { 37077c478bd9Sstevel@tonic-gate case EX_USAGE: 37087c478bd9Sstevel@tonic-gate status = "5.5.4"; 37097c478bd9Sstevel@tonic-gate break; 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate case EX_DATAERR: 37127c478bd9Sstevel@tonic-gate status = "5.5.2"; 37137c478bd9Sstevel@tonic-gate break; 37147c478bd9Sstevel@tonic-gate 37157c478bd9Sstevel@tonic-gate case EX_NOUSER: 37167c478bd9Sstevel@tonic-gate status = "5.1.1"; 37177c478bd9Sstevel@tonic-gate break; 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate case EX_NOHOST: 37207c478bd9Sstevel@tonic-gate status = "5.1.2"; 37217c478bd9Sstevel@tonic-gate break; 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate case EX_NOINPUT: 37247c478bd9Sstevel@tonic-gate case EX_CANTCREAT: 37257c478bd9Sstevel@tonic-gate case EX_NOPERM: 37267c478bd9Sstevel@tonic-gate status = "5.3.0"; 37277c478bd9Sstevel@tonic-gate break; 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate case EX_UNAVAILABLE: 37307c478bd9Sstevel@tonic-gate case EX_SOFTWARE: 37317c478bd9Sstevel@tonic-gate case EX_OSFILE: 37327c478bd9Sstevel@tonic-gate case EX_PROTOCOL: 37337c478bd9Sstevel@tonic-gate case EX_CONFIG: 37347c478bd9Sstevel@tonic-gate status = "5.5.0"; 37357c478bd9Sstevel@tonic-gate break; 37367c478bd9Sstevel@tonic-gate 37377c478bd9Sstevel@tonic-gate case EX_OSERR: 37387c478bd9Sstevel@tonic-gate case EX_IOERR: 37397c478bd9Sstevel@tonic-gate status = "4.5.0"; 37407c478bd9Sstevel@tonic-gate break; 37417c478bd9Sstevel@tonic-gate 37427c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 37437c478bd9Sstevel@tonic-gate status = "4.2.0"; 37447c478bd9Sstevel@tonic-gate break; 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate /* new status? */ 37497c478bd9Sstevel@tonic-gate if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 37507c478bd9Sstevel@tonic-gate *q->q_status == '\0' || *q->q_status < *status)) 37517c478bd9Sstevel@tonic-gate { 37527c478bd9Sstevel@tonic-gate q->q_status = status; 37537c478bd9Sstevel@tonic-gate q->q_rstatus = rstatus; 37547c478bd9Sstevel@tonic-gate } 37557c478bd9Sstevel@tonic-gate if (rcode != EX_OK && q->q_rstatus == NULL && 37567c478bd9Sstevel@tonic-gate q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 37577c478bd9Sstevel@tonic-gate sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 37587c478bd9Sstevel@tonic-gate { 37597c478bd9Sstevel@tonic-gate char buf[16]; 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%d", rcode); 37627c478bd9Sstevel@tonic-gate q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 37637c478bd9Sstevel@tonic-gate } 37647c478bd9Sstevel@tonic-gate 37657c478bd9Sstevel@tonic-gate q->q_statdate = curtime(); 37667c478bd9Sstevel@tonic-gate if (CurHostName != NULL && CurHostName[0] != '\0' && 37677c478bd9Sstevel@tonic-gate mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 37687c478bd9Sstevel@tonic-gate q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 37697c478bd9Sstevel@tonic-gate 37707c478bd9Sstevel@tonic-gate /* restore errno */ 37717c478bd9Sstevel@tonic-gate errno = save_errno; 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate /* 37747c478bd9Sstevel@tonic-gate ** ENDMAILER -- Wait for mailer to terminate. 37757c478bd9Sstevel@tonic-gate ** 37767c478bd9Sstevel@tonic-gate ** We should never get fatal errors (e.g., segmentation 37777c478bd9Sstevel@tonic-gate ** violation), so we report those specially. For other 37787c478bd9Sstevel@tonic-gate ** errors, we choose a status message (into statmsg), 37797c478bd9Sstevel@tonic-gate ** and if it represents an error, we print it. 37807c478bd9Sstevel@tonic-gate ** 37817c478bd9Sstevel@tonic-gate ** Parameters: 37827c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 37837c478bd9Sstevel@tonic-gate ** e -- the current envelope. 37847c478bd9Sstevel@tonic-gate ** pv -- the parameter vector that invoked the mailer 37857c478bd9Sstevel@tonic-gate ** (for error messages). 37867c478bd9Sstevel@tonic-gate ** 37877c478bd9Sstevel@tonic-gate ** Returns: 37887c478bd9Sstevel@tonic-gate ** exit code of mailer. 37897c478bd9Sstevel@tonic-gate ** 37907c478bd9Sstevel@tonic-gate ** Side Effects: 37917c478bd9Sstevel@tonic-gate ** none. 37927c478bd9Sstevel@tonic-gate */ 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate static jmp_buf EndWaitTimeout; 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate static void 37977c478bd9Sstevel@tonic-gate endwaittimeout(ignore) 37987c478bd9Sstevel@tonic-gate int ignore; 37997c478bd9Sstevel@tonic-gate { 38007c478bd9Sstevel@tonic-gate /* 38017c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 38027c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 38037c478bd9Sstevel@tonic-gate ** DOING. 38047c478bd9Sstevel@tonic-gate */ 38057c478bd9Sstevel@tonic-gate 38067c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 38077c478bd9Sstevel@tonic-gate longjmp(EndWaitTimeout, 1); 38087c478bd9Sstevel@tonic-gate } 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate int 38117c478bd9Sstevel@tonic-gate endmailer(mci, e, pv) 38127c478bd9Sstevel@tonic-gate register MCI *mci; 38137c478bd9Sstevel@tonic-gate register ENVELOPE *e; 38147c478bd9Sstevel@tonic-gate char **pv; 38157c478bd9Sstevel@tonic-gate { 38167c478bd9Sstevel@tonic-gate int st; 38177c478bd9Sstevel@tonic-gate int save_errno = errno; 38187c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 38197c478bd9Sstevel@tonic-gate SM_EVENT *ev = NULL; 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate mci_unlock_host(mci); 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate /* close output to mailer */ 38257c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL) 38267c478bd9Sstevel@tonic-gate { 38277c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 38287c478bd9Sstevel@tonic-gate mci->mci_out = NULL; 38297c478bd9Sstevel@tonic-gate } 38307c478bd9Sstevel@tonic-gate 38317c478bd9Sstevel@tonic-gate /* copy any remaining input to transcript */ 38327c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 38337c478bd9Sstevel@tonic-gate e->e_xfp != NULL) 38347c478bd9Sstevel@tonic-gate { 38357c478bd9Sstevel@tonic-gate while (sfgets(buf, sizeof buf, mci->mci_in, 38367c478bd9Sstevel@tonic-gate TimeOuts.to_quit, "Draining Input") != NULL) 38377c478bd9Sstevel@tonic-gate (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 38387c478bd9Sstevel@tonic-gate } 38397c478bd9Sstevel@tonic-gate 38407c478bd9Sstevel@tonic-gate #if SASL 38417c478bd9Sstevel@tonic-gate /* close SASL connection */ 38427c478bd9Sstevel@tonic-gate if (bitset(MCIF_AUTHACT, mci->mci_flags)) 38437c478bd9Sstevel@tonic-gate { 38447c478bd9Sstevel@tonic-gate sasl_dispose(&mci->mci_conn); 38457c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_AUTHACT; 38467c478bd9Sstevel@tonic-gate } 38477c478bd9Sstevel@tonic-gate #endif /* SASL */ 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate #if STARTTLS 38507c478bd9Sstevel@tonic-gate /* shutdown TLS */ 38517c478bd9Sstevel@tonic-gate (void) endtlsclt(mci); 38527c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate /* now close the input */ 38557c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL) 38567c478bd9Sstevel@tonic-gate { 38577c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 38587c478bd9Sstevel@tonic-gate mci->mci_in = NULL; 38597c478bd9Sstevel@tonic-gate } 38607c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED; 38617c478bd9Sstevel@tonic-gate 38627c478bd9Sstevel@tonic-gate errno = save_errno; 38637c478bd9Sstevel@tonic-gate 38647c478bd9Sstevel@tonic-gate /* in the IPC case there is nothing to wait for */ 38657c478bd9Sstevel@tonic-gate if (mci->mci_pid == 0) 38667c478bd9Sstevel@tonic-gate return EX_OK; 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate /* put a timeout around the wait */ 38697c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_wait > 0) 38707c478bd9Sstevel@tonic-gate { 38717c478bd9Sstevel@tonic-gate if (setjmp(EndWaitTimeout) == 0) 38727c478bd9Sstevel@tonic-gate ev = sm_setevent(mci->mci_mailer->m_wait, 38737c478bd9Sstevel@tonic-gate endwaittimeout, 0); 38747c478bd9Sstevel@tonic-gate else 38757c478bd9Sstevel@tonic-gate { 38767c478bd9Sstevel@tonic-gate syserr("endmailer %s: wait timeout (%ld)", 38777c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name, 38787c478bd9Sstevel@tonic-gate (long) mci->mci_mailer->m_wait); 38797c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 38807c478bd9Sstevel@tonic-gate } 38817c478bd9Sstevel@tonic-gate } 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate /* wait for the mailer process, collect status */ 38847c478bd9Sstevel@tonic-gate st = waitfor(mci->mci_pid); 38857c478bd9Sstevel@tonic-gate save_errno = errno; 38867c478bd9Sstevel@tonic-gate if (ev != NULL) 38877c478bd9Sstevel@tonic-gate sm_clrevent(ev); 38887c478bd9Sstevel@tonic-gate errno = save_errno; 38897c478bd9Sstevel@tonic-gate 38907c478bd9Sstevel@tonic-gate if (st == -1) 38917c478bd9Sstevel@tonic-gate { 38927c478bd9Sstevel@tonic-gate syserr("endmailer %s: wait", mci->mci_mailer->m_name); 38937c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 38947c478bd9Sstevel@tonic-gate } 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate if (WIFEXITED(st)) 38977c478bd9Sstevel@tonic-gate { 38987c478bd9Sstevel@tonic-gate /* normal death -- return status */ 38997c478bd9Sstevel@tonic-gate return (WEXITSTATUS(st)); 39007c478bd9Sstevel@tonic-gate } 39017c478bd9Sstevel@tonic-gate 39027c478bd9Sstevel@tonic-gate /* it died a horrid death */ 39037c478bd9Sstevel@tonic-gate syserr("451 4.3.0 mailer %s died with signal %d%s", 39047c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name, WTERMSIG(st), 39057c478bd9Sstevel@tonic-gate WCOREDUMP(st) ? " (core dumped)" : 39067c478bd9Sstevel@tonic-gate (WIFSTOPPED(st) ? " (stopped)" : "")); 39077c478bd9Sstevel@tonic-gate 39087c478bd9Sstevel@tonic-gate /* log the arguments */ 39097c478bd9Sstevel@tonic-gate if (pv != NULL && e->e_xfp != NULL) 39107c478bd9Sstevel@tonic-gate { 39117c478bd9Sstevel@tonic-gate register char **av; 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 39147c478bd9Sstevel@tonic-gate for (av = pv; *av != NULL; av++) 39157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 39167c478bd9Sstevel@tonic-gate *av); 39177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 39187c478bd9Sstevel@tonic-gate } 39197c478bd9Sstevel@tonic-gate 39207c478bd9Sstevel@tonic-gate ExitStat = EX_TEMPFAIL; 39217c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 39227c478bd9Sstevel@tonic-gate } 39237c478bd9Sstevel@tonic-gate /* 39247c478bd9Sstevel@tonic-gate ** GIVERESPONSE -- Interpret an error response from a mailer 39257c478bd9Sstevel@tonic-gate ** 39267c478bd9Sstevel@tonic-gate ** Parameters: 39277c478bd9Sstevel@tonic-gate ** status -- the status code from the mailer (high byte 39287c478bd9Sstevel@tonic-gate ** only; core dumps must have been taken care of 39297c478bd9Sstevel@tonic-gate ** already). 39307c478bd9Sstevel@tonic-gate ** dsn -- the DSN associated with the address, if any. 39317c478bd9Sstevel@tonic-gate ** m -- the mailer info for this mailer. 39327c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info -- can be NULL if the 39337c478bd9Sstevel@tonic-gate ** response is given before the connection is made. 39347c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address for the recipient 39357c478bd9Sstevel@tonic-gate ** address(es). 39367c478bd9Sstevel@tonic-gate ** xstart -- the transaction start time, for computing 39377c478bd9Sstevel@tonic-gate ** transaction delays. 39387c478bd9Sstevel@tonic-gate ** e -- the current envelope. 39397c478bd9Sstevel@tonic-gate ** to -- the current recipient (NULL if none). 39407c478bd9Sstevel@tonic-gate ** 39417c478bd9Sstevel@tonic-gate ** Returns: 39427c478bd9Sstevel@tonic-gate ** none. 39437c478bd9Sstevel@tonic-gate ** 39447c478bd9Sstevel@tonic-gate ** Side Effects: 39457c478bd9Sstevel@tonic-gate ** Errors may be incremented. 39467c478bd9Sstevel@tonic-gate ** ExitStat may be set. 39477c478bd9Sstevel@tonic-gate */ 39487c478bd9Sstevel@tonic-gate 39497c478bd9Sstevel@tonic-gate void 39507c478bd9Sstevel@tonic-gate giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 39517c478bd9Sstevel@tonic-gate int status; 39527c478bd9Sstevel@tonic-gate char *dsn; 39537c478bd9Sstevel@tonic-gate register MAILER *m; 39547c478bd9Sstevel@tonic-gate register MCI *mci; 39557c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 39567c478bd9Sstevel@tonic-gate time_t xstart; 39577c478bd9Sstevel@tonic-gate ENVELOPE *e; 39587c478bd9Sstevel@tonic-gate ADDRESS *to; 39597c478bd9Sstevel@tonic-gate { 39607c478bd9Sstevel@tonic-gate register const char *statmsg; 39617c478bd9Sstevel@tonic-gate int errnum = errno; 39627c478bd9Sstevel@tonic-gate int off = 4; 39637c478bd9Sstevel@tonic-gate bool usestat = false; 39647c478bd9Sstevel@tonic-gate char dsnbuf[ENHSCLEN]; 39657c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 39667c478bd9Sstevel@tonic-gate char *exmsg; 39677c478bd9Sstevel@tonic-gate 39687c478bd9Sstevel@tonic-gate if (e == NULL) 3969*3ee0e492Sjbeck { 39707c478bd9Sstevel@tonic-gate syserr("giveresponse: null envelope"); 3971*3ee0e492Sjbeck /* NOTREACHED */ 3972*3ee0e492Sjbeck SM_ASSERT(0); 3973*3ee0e492Sjbeck } 39747c478bd9Sstevel@tonic-gate 39757c478bd9Sstevel@tonic-gate /* 39767c478bd9Sstevel@tonic-gate ** Compute status message from code. 39777c478bd9Sstevel@tonic-gate */ 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate exmsg = sm_sysexmsg(status); 39807c478bd9Sstevel@tonic-gate if (status == 0) 39817c478bd9Sstevel@tonic-gate { 39827c478bd9Sstevel@tonic-gate statmsg = "250 2.0.0 Sent"; 39837c478bd9Sstevel@tonic-gate if (e->e_statmsg != NULL) 39847c478bd9Sstevel@tonic-gate { 39857c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", 39867c478bd9Sstevel@tonic-gate statmsg, 39877c478bd9Sstevel@tonic-gate shortenstring(e->e_statmsg, 403)); 39887c478bd9Sstevel@tonic-gate statmsg = buf; 39897c478bd9Sstevel@tonic-gate } 39907c478bd9Sstevel@tonic-gate } 39917c478bd9Sstevel@tonic-gate else if (exmsg == NULL) 39927c478bd9Sstevel@tonic-gate { 39937c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 39947c478bd9Sstevel@tonic-gate "554 5.3.0 unknown mailer error %d", 39957c478bd9Sstevel@tonic-gate status); 39967c478bd9Sstevel@tonic-gate status = EX_UNAVAILABLE; 39977c478bd9Sstevel@tonic-gate statmsg = buf; 39987c478bd9Sstevel@tonic-gate usestat = true; 39997c478bd9Sstevel@tonic-gate } 40007c478bd9Sstevel@tonic-gate else if (status == EX_TEMPFAIL) 40017c478bd9Sstevel@tonic-gate { 40027c478bd9Sstevel@tonic-gate char *bp = buf; 40037c478bd9Sstevel@tonic-gate 40047c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 40057c478bd9Sstevel@tonic-gate bp += strlen(bp); 40067c478bd9Sstevel@tonic-gate #if NAMED_BIND 40077c478bd9Sstevel@tonic-gate if (h_errno == TRY_AGAIN) 40087c478bd9Sstevel@tonic-gate statmsg = sm_errstring(h_errno + E_DNSBASE); 40097c478bd9Sstevel@tonic-gate else 40107c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 40117c478bd9Sstevel@tonic-gate { 40127c478bd9Sstevel@tonic-gate if (errnum != 0) 40137c478bd9Sstevel@tonic-gate statmsg = sm_errstring(errnum); 40147c478bd9Sstevel@tonic-gate else 40157c478bd9Sstevel@tonic-gate statmsg = SmtpError; 40167c478bd9Sstevel@tonic-gate } 40177c478bd9Sstevel@tonic-gate if (statmsg != NULL && statmsg[0] != '\0') 40187c478bd9Sstevel@tonic-gate { 40197c478bd9Sstevel@tonic-gate switch (errnum) 40207c478bd9Sstevel@tonic-gate { 40217c478bd9Sstevel@tonic-gate #ifdef ENETDOWN 40227c478bd9Sstevel@tonic-gate case ENETDOWN: /* Network is down */ 40237c478bd9Sstevel@tonic-gate #endif /* ENETDOWN */ 40247c478bd9Sstevel@tonic-gate #ifdef ENETUNREACH 40257c478bd9Sstevel@tonic-gate case ENETUNREACH: /* Network is unreachable */ 40267c478bd9Sstevel@tonic-gate #endif /* ENETUNREACH */ 40277c478bd9Sstevel@tonic-gate #ifdef ENETRESET 40287c478bd9Sstevel@tonic-gate case ENETRESET: /* Network dropped connection on reset */ 40297c478bd9Sstevel@tonic-gate #endif /* ENETRESET */ 40307c478bd9Sstevel@tonic-gate #ifdef ECONNABORTED 40317c478bd9Sstevel@tonic-gate case ECONNABORTED: /* Software caused connection abort */ 40327c478bd9Sstevel@tonic-gate #endif /* ECONNABORTED */ 40337c478bd9Sstevel@tonic-gate #ifdef EHOSTDOWN 40347c478bd9Sstevel@tonic-gate case EHOSTDOWN: /* Host is down */ 40357c478bd9Sstevel@tonic-gate #endif /* EHOSTDOWN */ 40367c478bd9Sstevel@tonic-gate #ifdef EHOSTUNREACH 40377c478bd9Sstevel@tonic-gate case EHOSTUNREACH: /* No route to host */ 40387c478bd9Sstevel@tonic-gate #endif /* EHOSTUNREACH */ 40397c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 40407c478bd9Sstevel@tonic-gate { 40417c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, 40427c478bd9Sstevel@tonic-gate SPACELEFT(buf, bp), 40437c478bd9Sstevel@tonic-gate 2, ": ", 40447c478bd9Sstevel@tonic-gate mci->mci_host); 40457c478bd9Sstevel@tonic-gate bp += strlen(bp); 40467c478bd9Sstevel@tonic-gate } 40477c478bd9Sstevel@tonic-gate break; 40487c478bd9Sstevel@tonic-gate } 40497c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 40507c478bd9Sstevel@tonic-gate statmsg); 40517c478bd9Sstevel@tonic-gate usestat = true; 40527c478bd9Sstevel@tonic-gate } 40537c478bd9Sstevel@tonic-gate statmsg = buf; 40547c478bd9Sstevel@tonic-gate } 40557c478bd9Sstevel@tonic-gate #if NAMED_BIND 40567c478bd9Sstevel@tonic-gate else if (status == EX_NOHOST && h_errno != 0) 40577c478bd9Sstevel@tonic-gate { 40587c478bd9Sstevel@tonic-gate statmsg = sm_errstring(h_errno + E_DNSBASE); 40597c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1, 40607c478bd9Sstevel@tonic-gate statmsg); 40617c478bd9Sstevel@tonic-gate statmsg = buf; 40627c478bd9Sstevel@tonic-gate usestat = true; 40637c478bd9Sstevel@tonic-gate } 40647c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 40657c478bd9Sstevel@tonic-gate else 40667c478bd9Sstevel@tonic-gate { 40677c478bd9Sstevel@tonic-gate statmsg = exmsg; 40687c478bd9Sstevel@tonic-gate if (*statmsg++ == ':' && errnum != 0) 40697c478bd9Sstevel@tonic-gate { 40707c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg, 40717c478bd9Sstevel@tonic-gate sm_errstring(errnum)); 40727c478bd9Sstevel@tonic-gate statmsg = buf; 40737c478bd9Sstevel@tonic-gate usestat = true; 40747c478bd9Sstevel@tonic-gate } 40757c478bd9Sstevel@tonic-gate else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL) 40767c478bd9Sstevel@tonic-gate { 40777c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", statmsg, 40787c478bd9Sstevel@tonic-gate shortenstring(e->e_statmsg, 403)); 40797c478bd9Sstevel@tonic-gate statmsg = buf; 40807c478bd9Sstevel@tonic-gate usestat = true; 40817c478bd9Sstevel@tonic-gate } 40827c478bd9Sstevel@tonic-gate } 40837c478bd9Sstevel@tonic-gate 40847c478bd9Sstevel@tonic-gate /* 40857c478bd9Sstevel@tonic-gate ** Print the message as appropriate 40867c478bd9Sstevel@tonic-gate */ 40877c478bd9Sstevel@tonic-gate 40887c478bd9Sstevel@tonic-gate if (status == EX_OK || status == EX_TEMPFAIL) 40897c478bd9Sstevel@tonic-gate { 40907c478bd9Sstevel@tonic-gate extern char MsgBuf[]; 40917c478bd9Sstevel@tonic-gate 40927c478bd9Sstevel@tonic-gate if ((off = isenhsc(statmsg + 4, ' ')) > 0) 40937c478bd9Sstevel@tonic-gate { 40947c478bd9Sstevel@tonic-gate if (dsn == NULL) 40957c478bd9Sstevel@tonic-gate { 40967c478bd9Sstevel@tonic-gate (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 40977c478bd9Sstevel@tonic-gate "%.*s", off, statmsg + 4); 40987c478bd9Sstevel@tonic-gate dsn = dsnbuf; 40997c478bd9Sstevel@tonic-gate } 41007c478bd9Sstevel@tonic-gate off += 5; 41017c478bd9Sstevel@tonic-gate } 41027c478bd9Sstevel@tonic-gate else 41037c478bd9Sstevel@tonic-gate { 41047c478bd9Sstevel@tonic-gate off = 4; 41057c478bd9Sstevel@tonic-gate } 41067c478bd9Sstevel@tonic-gate message("%s", statmsg + off); 41077c478bd9Sstevel@tonic-gate if (status == EX_TEMPFAIL && e->e_xfp != NULL) 41087c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 41097c478bd9Sstevel@tonic-gate &MsgBuf[4]); 41107c478bd9Sstevel@tonic-gate } 41117c478bd9Sstevel@tonic-gate else 41127c478bd9Sstevel@tonic-gate { 41137c478bd9Sstevel@tonic-gate char mbuf[ENHSCLEN + 4]; 41147c478bd9Sstevel@tonic-gate 41157c478bd9Sstevel@tonic-gate Errors++; 41167c478bd9Sstevel@tonic-gate if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 41177c478bd9Sstevel@tonic-gate off < sizeof mbuf - 4) 41187c478bd9Sstevel@tonic-gate { 41197c478bd9Sstevel@tonic-gate if (dsn == NULL) 41207c478bd9Sstevel@tonic-gate { 41217c478bd9Sstevel@tonic-gate (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 41227c478bd9Sstevel@tonic-gate "%.*s", off, statmsg + 4); 41237c478bd9Sstevel@tonic-gate dsn = dsnbuf; 41247c478bd9Sstevel@tonic-gate } 41257c478bd9Sstevel@tonic-gate off += 5; 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate /* copy only part of statmsg to mbuf */ 41287c478bd9Sstevel@tonic-gate (void) sm_strlcpy(mbuf, statmsg, off); 41297c478bd9Sstevel@tonic-gate (void) sm_strlcat(mbuf, " %s", sizeof mbuf); 41307c478bd9Sstevel@tonic-gate } 41317c478bd9Sstevel@tonic-gate else 41327c478bd9Sstevel@tonic-gate { 41337c478bd9Sstevel@tonic-gate dsnbuf[0] = '\0'; 41347c478bd9Sstevel@tonic-gate (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s", 41357c478bd9Sstevel@tonic-gate statmsg); 41367c478bd9Sstevel@tonic-gate off = 4; 41377c478bd9Sstevel@tonic-gate } 41387c478bd9Sstevel@tonic-gate usrerr(mbuf, &statmsg[off]); 41397c478bd9Sstevel@tonic-gate } 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate /* 41427c478bd9Sstevel@tonic-gate ** Final cleanup. 41437c478bd9Sstevel@tonic-gate ** Log a record of the transaction. Compute the new 41447c478bd9Sstevel@tonic-gate ** ExitStat -- if we already had an error, stick with 41457c478bd9Sstevel@tonic-gate ** that. 41467c478bd9Sstevel@tonic-gate */ 41477c478bd9Sstevel@tonic-gate 41487c478bd9Sstevel@tonic-gate if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 41497c478bd9Sstevel@tonic-gate LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 41507c478bd9Sstevel@tonic-gate logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 41517c478bd9Sstevel@tonic-gate 41527c478bd9Sstevel@tonic-gate if (tTd(11, 2)) 41537c478bd9Sstevel@tonic-gate sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 41547c478bd9Sstevel@tonic-gate status, 41557c478bd9Sstevel@tonic-gate dsn == NULL ? "<NULL>" : dsn, 41567c478bd9Sstevel@tonic-gate e->e_message == NULL ? "<NULL>" : e->e_message, 41577c478bd9Sstevel@tonic-gate errnum); 41587c478bd9Sstevel@tonic-gate 41597c478bd9Sstevel@tonic-gate if (status != EX_TEMPFAIL) 41607c478bd9Sstevel@tonic-gate setstat(status); 41617c478bd9Sstevel@tonic-gate if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 41627c478bd9Sstevel@tonic-gate e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 41637c478bd9Sstevel@tonic-gate if (status != EX_OK && to != NULL && to->q_message == NULL) 41647c478bd9Sstevel@tonic-gate { 41657c478bd9Sstevel@tonic-gate if (!usestat && e->e_message != NULL) 41667c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 41677c478bd9Sstevel@tonic-gate e->e_message); 41687c478bd9Sstevel@tonic-gate else 41697c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 41707c478bd9Sstevel@tonic-gate statmsg + off); 41717c478bd9Sstevel@tonic-gate } 41727c478bd9Sstevel@tonic-gate errno = 0; 41737c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 41747c478bd9Sstevel@tonic-gate } 41757c478bd9Sstevel@tonic-gate /* 41767c478bd9Sstevel@tonic-gate ** LOGDELIVERY -- log the delivery in the system log 41777c478bd9Sstevel@tonic-gate ** 41787c478bd9Sstevel@tonic-gate ** Care is taken to avoid logging lines that are too long, because 41797c478bd9Sstevel@tonic-gate ** some versions of syslog have an unfortunate proclivity for core 41807c478bd9Sstevel@tonic-gate ** dumping. This is a hack, to be sure, that is at best empirical. 41817c478bd9Sstevel@tonic-gate ** 41827c478bd9Sstevel@tonic-gate ** Parameters: 41837c478bd9Sstevel@tonic-gate ** m -- the mailer info. Can be NULL for initial queue. 41847c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info -- can be NULL if the 41857c478bd9Sstevel@tonic-gate ** log is occurring when no connection is active. 41867c478bd9Sstevel@tonic-gate ** dsn -- the DSN attached to the status. 41877c478bd9Sstevel@tonic-gate ** status -- the message to print for the status. 41887c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address for the to list. 41897c478bd9Sstevel@tonic-gate ** xstart -- the transaction start time, used for 41907c478bd9Sstevel@tonic-gate ** computing transaction delay. 41917c478bd9Sstevel@tonic-gate ** e -- the current envelope. 41927c478bd9Sstevel@tonic-gate ** 41937c478bd9Sstevel@tonic-gate ** Returns: 41947c478bd9Sstevel@tonic-gate ** none 41957c478bd9Sstevel@tonic-gate ** 41967c478bd9Sstevel@tonic-gate ** Side Effects: 41977c478bd9Sstevel@tonic-gate ** none 41987c478bd9Sstevel@tonic-gate */ 41997c478bd9Sstevel@tonic-gate 42007c478bd9Sstevel@tonic-gate void 42017c478bd9Sstevel@tonic-gate logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 42027c478bd9Sstevel@tonic-gate MAILER *m; 42037c478bd9Sstevel@tonic-gate register MCI *mci; 42047c478bd9Sstevel@tonic-gate char *dsn; 42057c478bd9Sstevel@tonic-gate const char *status; 42067c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 42077c478bd9Sstevel@tonic-gate time_t xstart; 42087c478bd9Sstevel@tonic-gate register ENVELOPE *e; 42097c478bd9Sstevel@tonic-gate { 42107c478bd9Sstevel@tonic-gate register char *bp; 42117c478bd9Sstevel@tonic-gate register char *p; 42127c478bd9Sstevel@tonic-gate int l; 42137c478bd9Sstevel@tonic-gate time_t now = curtime(); 42147c478bd9Sstevel@tonic-gate char buf[1024]; 42157c478bd9Sstevel@tonic-gate 42167c478bd9Sstevel@tonic-gate #if (SYSLOG_BUFSIZE) >= 256 42177c478bd9Sstevel@tonic-gate /* ctladdr: max 106 bytes */ 42187c478bd9Sstevel@tonic-gate bp = buf; 42197c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 42207c478bd9Sstevel@tonic-gate { 42217c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 42227c478bd9Sstevel@tonic-gate shortenstring(ctladdr->q_paddr, 83)); 42237c478bd9Sstevel@tonic-gate bp += strlen(bp); 42247c478bd9Sstevel@tonic-gate if (bitset(QGOODUID, ctladdr->q_flags)) 42257c478bd9Sstevel@tonic-gate { 42267c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 42277c478bd9Sstevel@tonic-gate (int) ctladdr->q_uid, 42287c478bd9Sstevel@tonic-gate (int) ctladdr->q_gid); 42297c478bd9Sstevel@tonic-gate bp += strlen(bp); 42307c478bd9Sstevel@tonic-gate } 42317c478bd9Sstevel@tonic-gate } 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate /* delay & xdelay: max 41 bytes */ 42347c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 42357c478bd9Sstevel@tonic-gate pintvl(now - e->e_ctime, true)); 42367c478bd9Sstevel@tonic-gate bp += strlen(bp); 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate if (xstart != (time_t) 0) 42397c478bd9Sstevel@tonic-gate { 42407c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 42417c478bd9Sstevel@tonic-gate pintvl(now - xstart, true)); 42427c478bd9Sstevel@tonic-gate bp += strlen(bp); 42437c478bd9Sstevel@tonic-gate } 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 42467c478bd9Sstevel@tonic-gate if (m != NULL) 42477c478bd9Sstevel@tonic-gate { 42487c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 42497c478bd9Sstevel@tonic-gate m->m_name); 42507c478bd9Sstevel@tonic-gate bp += strlen(bp); 42517c478bd9Sstevel@tonic-gate } 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate /* pri: changes with each delivery attempt */ 42547c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 42557c478bd9Sstevel@tonic-gate e->e_msgpriority); 42567c478bd9Sstevel@tonic-gate bp += strlen(bp); 42577c478bd9Sstevel@tonic-gate 42587c478bd9Sstevel@tonic-gate /* relay: max 66 bytes for IPv4 addresses */ 42597c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 42607c478bd9Sstevel@tonic-gate { 42617c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr; 42627c478bd9Sstevel@tonic-gate 42637c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 42647c478bd9Sstevel@tonic-gate shortenstring(mci->mci_host, 40)); 42657c478bd9Sstevel@tonic-gate bp += strlen(bp); 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate if (CurHostAddr.sa.sa_family != 0) 42687c478bd9Sstevel@tonic-gate { 42697c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 42707c478bd9Sstevel@tonic-gate anynet_ntoa(&CurHostAddr)); 42717c478bd9Sstevel@tonic-gate } 42727c478bd9Sstevel@tonic-gate } 42737c478bd9Sstevel@tonic-gate else if (strcmp(status, "quarantined") == 0) 42747c478bd9Sstevel@tonic-gate { 42757c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 42767c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 42777c478bd9Sstevel@tonic-gate ", quarantine=%s", 42787c478bd9Sstevel@tonic-gate shortenstring(e->e_quarmsg, 40)); 42797c478bd9Sstevel@tonic-gate } 42807c478bd9Sstevel@tonic-gate else if (strcmp(status, "queued") != 0) 42817c478bd9Sstevel@tonic-gate { 42827c478bd9Sstevel@tonic-gate p = macvalue('h', e); 42837c478bd9Sstevel@tonic-gate if (p != NULL && p[0] != '\0') 42847c478bd9Sstevel@tonic-gate { 42857c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 42867c478bd9Sstevel@tonic-gate ", relay=%s", shortenstring(p, 40)); 42877c478bd9Sstevel@tonic-gate } 42887c478bd9Sstevel@tonic-gate } 42897c478bd9Sstevel@tonic-gate bp += strlen(bp); 42907c478bd9Sstevel@tonic-gate 42917c478bd9Sstevel@tonic-gate /* dsn */ 42927c478bd9Sstevel@tonic-gate if (dsn != NULL && *dsn != '\0') 42937c478bd9Sstevel@tonic-gate { 42947c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 42957c478bd9Sstevel@tonic-gate shortenstring(dsn, ENHSCLEN)); 42967c478bd9Sstevel@tonic-gate bp += strlen(bp); 42977c478bd9Sstevel@tonic-gate } 42987c478bd9Sstevel@tonic-gate 42997c478bd9Sstevel@tonic-gate #if _FFR_LOG_NTRIES 43007c478bd9Sstevel@tonic-gate /* ntries */ 43017c478bd9Sstevel@tonic-gate if (e->e_ntries >= 0) 43027c478bd9Sstevel@tonic-gate { 43037c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 43047c478bd9Sstevel@tonic-gate ", ntries=%d", e->e_ntries + 1); 43057c478bd9Sstevel@tonic-gate bp += strlen(bp); 43067c478bd9Sstevel@tonic-gate } 43077c478bd9Sstevel@tonic-gate #endif /* _FFR_LOG_NTRIES */ 43087c478bd9Sstevel@tonic-gate 43097c478bd9Sstevel@tonic-gate # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 43107c478bd9Sstevel@tonic-gate # if (STATLEN) < 63 43117c478bd9Sstevel@tonic-gate # undef STATLEN 43127c478bd9Sstevel@tonic-gate # define STATLEN 63 43137c478bd9Sstevel@tonic-gate # endif /* (STATLEN) < 63 */ 43147c478bd9Sstevel@tonic-gate # if (STATLEN) > 203 43157c478bd9Sstevel@tonic-gate # undef STATLEN 43167c478bd9Sstevel@tonic-gate # define STATLEN 203 43177c478bd9Sstevel@tonic-gate # endif /* (STATLEN) > 203 */ 43187c478bd9Sstevel@tonic-gate 43197c478bd9Sstevel@tonic-gate /* stat: max 210 bytes */ 43207c478bd9Sstevel@tonic-gate if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 43217c478bd9Sstevel@tonic-gate { 43227c478bd9Sstevel@tonic-gate /* desperation move -- truncate data */ 43237c478bd9Sstevel@tonic-gate bp = buf + sizeof buf - ((STATLEN) + 17); 43247c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 43257c478bd9Sstevel@tonic-gate bp += 3; 43267c478bd9Sstevel@tonic-gate } 43277c478bd9Sstevel@tonic-gate 43287c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 43297c478bd9Sstevel@tonic-gate bp += strlen(bp); 43307c478bd9Sstevel@tonic-gate 43317c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 43327c478bd9Sstevel@tonic-gate SPACELEFT(buf, bp)); 43337c478bd9Sstevel@tonic-gate 43347c478bd9Sstevel@tonic-gate /* id, to: max 13 + TOBUFSIZE bytes */ 43357c478bd9Sstevel@tonic-gate l = SYSLOG_BUFSIZE - 100 - strlen(buf); 43367c478bd9Sstevel@tonic-gate if (l < 0) 43377c478bd9Sstevel@tonic-gate l = 0; 43387c478bd9Sstevel@tonic-gate p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 43397c478bd9Sstevel@tonic-gate while (strlen(p) >= l) 43407c478bd9Sstevel@tonic-gate { 43417c478bd9Sstevel@tonic-gate register char *q; 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate for (q = p + l; q > p; q--) 43447c478bd9Sstevel@tonic-gate { 43457c478bd9Sstevel@tonic-gate if (*q == ',') 43467c478bd9Sstevel@tonic-gate break; 43477c478bd9Sstevel@tonic-gate } 43487c478bd9Sstevel@tonic-gate if (p == q) 43497c478bd9Sstevel@tonic-gate break; 43507c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 43517c478bd9Sstevel@tonic-gate (int) (++q - p), p, buf); 43527c478bd9Sstevel@tonic-gate p = q; 43537c478bd9Sstevel@tonic-gate } 43547c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate #else /* (SYSLOG_BUFSIZE) >= 256 */ 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate l = SYSLOG_BUFSIZE - 85; 43597c478bd9Sstevel@tonic-gate if (l < 0) 43607c478bd9Sstevel@tonic-gate l = 0; 43617c478bd9Sstevel@tonic-gate p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 43627c478bd9Sstevel@tonic-gate while (strlen(p) >= l) 43637c478bd9Sstevel@tonic-gate { 43647c478bd9Sstevel@tonic-gate register char *q; 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate for (q = p + l; q > p; q--) 43677c478bd9Sstevel@tonic-gate { 43687c478bd9Sstevel@tonic-gate if (*q == ',') 43697c478bd9Sstevel@tonic-gate break; 43707c478bd9Sstevel@tonic-gate } 43717c478bd9Sstevel@tonic-gate if (p == q) 43727c478bd9Sstevel@tonic-gate break; 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 43757c478bd9Sstevel@tonic-gate (int) (++q - p), p); 43767c478bd9Sstevel@tonic-gate p = q; 43777c478bd9Sstevel@tonic-gate } 43787c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 43817c478bd9Sstevel@tonic-gate { 43827c478bd9Sstevel@tonic-gate bp = buf; 43837c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 43847c478bd9Sstevel@tonic-gate shortenstring(ctladdr->q_paddr, 83)); 43857c478bd9Sstevel@tonic-gate bp += strlen(bp); 43867c478bd9Sstevel@tonic-gate if (bitset(QGOODUID, ctladdr->q_flags)) 43877c478bd9Sstevel@tonic-gate { 43887c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 43897c478bd9Sstevel@tonic-gate ctladdr->q_uid, ctladdr->q_gid); 43907c478bd9Sstevel@tonic-gate bp += strlen(bp); 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%s", buf); 43937c478bd9Sstevel@tonic-gate } 43947c478bd9Sstevel@tonic-gate bp = buf; 43957c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 43967c478bd9Sstevel@tonic-gate pintvl(now - e->e_ctime, true)); 43977c478bd9Sstevel@tonic-gate bp += strlen(bp); 43987c478bd9Sstevel@tonic-gate if (xstart != (time_t) 0) 43997c478bd9Sstevel@tonic-gate { 44007c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 44017c478bd9Sstevel@tonic-gate pintvl(now - xstart, true)); 44027c478bd9Sstevel@tonic-gate bp += strlen(bp); 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate 44057c478bd9Sstevel@tonic-gate if (m != NULL) 44067c478bd9Sstevel@tonic-gate { 44077c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 44087c478bd9Sstevel@tonic-gate m->m_name); 44097c478bd9Sstevel@tonic-gate bp += strlen(bp); 44107c478bd9Sstevel@tonic-gate } 44117c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 44127c478bd9Sstevel@tonic-gate 44137c478bd9Sstevel@tonic-gate buf[0] = '\0'; 44147c478bd9Sstevel@tonic-gate bp = buf; 44157c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 44167c478bd9Sstevel@tonic-gate { 44177c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr; 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 44207c478bd9Sstevel@tonic-gate mci->mci_host); 44217c478bd9Sstevel@tonic-gate bp += strlen(bp); 44227c478bd9Sstevel@tonic-gate 44237c478bd9Sstevel@tonic-gate if (CurHostAddr.sa.sa_family != 0) 44247c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 44257c478bd9Sstevel@tonic-gate " [%.100s]", 44267c478bd9Sstevel@tonic-gate anynet_ntoa(&CurHostAddr)); 44277c478bd9Sstevel@tonic-gate } 44287c478bd9Sstevel@tonic-gate else if (strcmp(status, "quarantined") == 0) 44297c478bd9Sstevel@tonic-gate { 44307c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 44317c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 44327c478bd9Sstevel@tonic-gate ", quarantine=%.100s", 44337c478bd9Sstevel@tonic-gate e->e_quarmsg); 44347c478bd9Sstevel@tonic-gate } 44357c478bd9Sstevel@tonic-gate else if (strcmp(status, "queued") != 0) 44367c478bd9Sstevel@tonic-gate { 44377c478bd9Sstevel@tonic-gate p = macvalue('h', e); 44387c478bd9Sstevel@tonic-gate if (p != NULL && p[0] != '\0') 44397c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p); 44407c478bd9Sstevel@tonic-gate } 44417c478bd9Sstevel@tonic-gate if (buf[0] != '\0') 44427c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 44457c478bd9Sstevel@tonic-gate #endif /* (SYSLOG_BUFSIZE) >= 256 */ 44467c478bd9Sstevel@tonic-gate } 44477c478bd9Sstevel@tonic-gate /* 44487c478bd9Sstevel@tonic-gate ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 44497c478bd9Sstevel@tonic-gate ** 44507c478bd9Sstevel@tonic-gate ** This can be made an arbitrary message separator by changing $l 44517c478bd9Sstevel@tonic-gate ** 44527c478bd9Sstevel@tonic-gate ** One of the ugliest hacks seen by human eyes is contained herein: 44537c478bd9Sstevel@tonic-gate ** UUCP wants those stupid "remote from <host>" lines. Why oh why 44547c478bd9Sstevel@tonic-gate ** does a well-meaning programmer such as myself have to deal with 44557c478bd9Sstevel@tonic-gate ** this kind of antique garbage???? 44567c478bd9Sstevel@tonic-gate ** 44577c478bd9Sstevel@tonic-gate ** Parameters: 44587c478bd9Sstevel@tonic-gate ** mci -- the connection information. 44597c478bd9Sstevel@tonic-gate ** e -- the envelope. 44607c478bd9Sstevel@tonic-gate ** 44617c478bd9Sstevel@tonic-gate ** Returns: 4462445f2479Sjbeck ** true iff line was written successfully 44637c478bd9Sstevel@tonic-gate ** 44647c478bd9Sstevel@tonic-gate ** Side Effects: 44657c478bd9Sstevel@tonic-gate ** outputs some text to fp. 44667c478bd9Sstevel@tonic-gate */ 44677c478bd9Sstevel@tonic-gate 4468445f2479Sjbeck bool 44697c478bd9Sstevel@tonic-gate putfromline(mci, e) 44707c478bd9Sstevel@tonic-gate register MCI *mci; 44717c478bd9Sstevel@tonic-gate ENVELOPE *e; 44727c478bd9Sstevel@tonic-gate { 44737c478bd9Sstevel@tonic-gate char *template = UnixFromLine; 44747c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 44757c478bd9Sstevel@tonic-gate char xbuf[MAXLINE]; 44767c478bd9Sstevel@tonic-gate 44777c478bd9Sstevel@tonic-gate if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 4478445f2479Sjbeck return true; 44797c478bd9Sstevel@tonic-gate 44807c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 44837c478bd9Sstevel@tonic-gate { 44847c478bd9Sstevel@tonic-gate char *bang; 44857c478bd9Sstevel@tonic-gate 44867c478bd9Sstevel@tonic-gate expand("\201g", buf, sizeof buf, e); 44877c478bd9Sstevel@tonic-gate bang = strchr(buf, '!'); 44887c478bd9Sstevel@tonic-gate if (bang == NULL) 44897c478bd9Sstevel@tonic-gate { 44907c478bd9Sstevel@tonic-gate char *at; 44917c478bd9Sstevel@tonic-gate char hname[MAXNAME]; 44927c478bd9Sstevel@tonic-gate 44937c478bd9Sstevel@tonic-gate /* 44947c478bd9Sstevel@tonic-gate ** If we can construct a UUCP path, do so 44957c478bd9Sstevel@tonic-gate */ 44967c478bd9Sstevel@tonic-gate 44977c478bd9Sstevel@tonic-gate at = strrchr(buf, '@'); 44987c478bd9Sstevel@tonic-gate if (at == NULL) 44997c478bd9Sstevel@tonic-gate { 45007c478bd9Sstevel@tonic-gate expand("\201k", hname, sizeof hname, e); 45017c478bd9Sstevel@tonic-gate at = hname; 45027c478bd9Sstevel@tonic-gate } 45037c478bd9Sstevel@tonic-gate else 45047c478bd9Sstevel@tonic-gate *at++ = '\0'; 45057c478bd9Sstevel@tonic-gate (void) sm_snprintf(xbuf, sizeof xbuf, 45067c478bd9Sstevel@tonic-gate "From %.800s \201d remote from %.100s\n", 45077c478bd9Sstevel@tonic-gate buf, at); 45087c478bd9Sstevel@tonic-gate } 45097c478bd9Sstevel@tonic-gate else 45107c478bd9Sstevel@tonic-gate { 45117c478bd9Sstevel@tonic-gate *bang++ = '\0'; 45127c478bd9Sstevel@tonic-gate (void) sm_snprintf(xbuf, sizeof xbuf, 45137c478bd9Sstevel@tonic-gate "From %.800s \201d remote from %.100s\n", 45147c478bd9Sstevel@tonic-gate bang, buf); 45157c478bd9Sstevel@tonic-gate template = xbuf; 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate } 45187c478bd9Sstevel@tonic-gate expand(template, buf, sizeof buf, e); 4519445f2479Sjbeck return putxline(buf, strlen(buf), mci, PXLF_HEADER); 45207c478bd9Sstevel@tonic-gate } 4521445f2479Sjbeck 45227c478bd9Sstevel@tonic-gate /* 45237c478bd9Sstevel@tonic-gate ** PUTBODY -- put the body of a message. 45247c478bd9Sstevel@tonic-gate ** 45257c478bd9Sstevel@tonic-gate ** Parameters: 45267c478bd9Sstevel@tonic-gate ** mci -- the connection information. 45277c478bd9Sstevel@tonic-gate ** e -- the envelope to put out. 45287c478bd9Sstevel@tonic-gate ** separator -- if non-NULL, a message separator that must 45297c478bd9Sstevel@tonic-gate ** not be permitted in the resulting message. 45307c478bd9Sstevel@tonic-gate ** 45317c478bd9Sstevel@tonic-gate ** Returns: 4532445f2479Sjbeck ** true iff message was written successfully 45337c478bd9Sstevel@tonic-gate ** 45347c478bd9Sstevel@tonic-gate ** Side Effects: 45357c478bd9Sstevel@tonic-gate ** The message is written onto fp. 45367c478bd9Sstevel@tonic-gate */ 45377c478bd9Sstevel@tonic-gate 45387c478bd9Sstevel@tonic-gate /* values for output state variable */ 453949218d4fSjbeck #define OSTATE_HEAD 0 /* at beginning of line */ 454049218d4fSjbeck #define OSTATE_CR 1 /* read a carriage return */ 454149218d4fSjbeck #define OSTATE_INLINE 2 /* putting rest of line */ 45427c478bd9Sstevel@tonic-gate 4543445f2479Sjbeck bool 45447c478bd9Sstevel@tonic-gate putbody(mci, e, separator) 45457c478bd9Sstevel@tonic-gate register MCI *mci; 45467c478bd9Sstevel@tonic-gate register ENVELOPE *e; 45477c478bd9Sstevel@tonic-gate char *separator; 45487c478bd9Sstevel@tonic-gate { 45497c478bd9Sstevel@tonic-gate bool dead = false; 4550445f2479Sjbeck bool ioerr = false; 4551445f2479Sjbeck int save_errno; 45527c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 45537c478bd9Sstevel@tonic-gate #if MIME8TO7 45547c478bd9Sstevel@tonic-gate char *boundaries[MAXMIMENESTING + 1]; 45557c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 45567c478bd9Sstevel@tonic-gate 45577c478bd9Sstevel@tonic-gate /* 45587c478bd9Sstevel@tonic-gate ** Output the body of the message 45597c478bd9Sstevel@tonic-gate */ 45607c478bd9Sstevel@tonic-gate 45617c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 45627c478bd9Sstevel@tonic-gate { 45637c478bd9Sstevel@tonic-gate char *df = queuename(e, DATAFL_LETTER); 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 45667c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL); 45677c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45687c478bd9Sstevel@tonic-gate { 45697c478bd9Sstevel@tonic-gate char *msg = "!putbody: Cannot open %s for %s from %s"; 45707c478bd9Sstevel@tonic-gate 45717c478bd9Sstevel@tonic-gate if (errno == ENOENT) 45727c478bd9Sstevel@tonic-gate msg++; 45737c478bd9Sstevel@tonic-gate syserr(msg, df, e->e_to, e->e_from.q_paddr); 45747c478bd9Sstevel@tonic-gate } 45757c478bd9Sstevel@tonic-gate 45767c478bd9Sstevel@tonic-gate } 45777c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45787c478bd9Sstevel@tonic-gate { 45797c478bd9Sstevel@tonic-gate if (bitset(MCIF_INHEADER, mci->mci_flags)) 45807c478bd9Sstevel@tonic-gate { 4581445f2479Sjbeck if (!putline("", mci)) 4582445f2479Sjbeck goto writeerr; 45837c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 45847c478bd9Sstevel@tonic-gate } 4585445f2479Sjbeck if (!putline("<<< No Message Collected >>>", mci)) 4586445f2479Sjbeck goto writeerr; 45877c478bd9Sstevel@tonic-gate goto endofmessage; 45887c478bd9Sstevel@tonic-gate } 45897c478bd9Sstevel@tonic-gate 45907c478bd9Sstevel@tonic-gate if (e->e_dfino == (ino_t) 0) 45917c478bd9Sstevel@tonic-gate { 45927c478bd9Sstevel@tonic-gate struct stat stbuf; 45937c478bd9Sstevel@tonic-gate 45947c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 45957c478bd9Sstevel@tonic-gate < 0) 45967c478bd9Sstevel@tonic-gate e->e_dfino = -1; 45977c478bd9Sstevel@tonic-gate else 45987c478bd9Sstevel@tonic-gate { 45997c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 46007c478bd9Sstevel@tonic-gate e->e_dfino = stbuf.st_ino; 46017c478bd9Sstevel@tonic-gate } 46027c478bd9Sstevel@tonic-gate } 46037c478bd9Sstevel@tonic-gate 46047c478bd9Sstevel@tonic-gate /* paranoia: the data file should always be in a rewound state */ 46057c478bd9Sstevel@tonic-gate (void) bfrewind(e->e_dfp); 46067c478bd9Sstevel@tonic-gate 4607445f2479Sjbeck /* simulate an I/O timeout when used as source */ 4608445f2479Sjbeck if (tTd(84, 101)) 4609445f2479Sjbeck sleep(319); 4610445f2479Sjbeck 46117c478bd9Sstevel@tonic-gate #if MIME8TO7 46127c478bd9Sstevel@tonic-gate if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 46137c478bd9Sstevel@tonic-gate { 46147c478bd9Sstevel@tonic-gate /* 46157c478bd9Sstevel@tonic-gate ** Do 8 to 7 bit MIME conversion. 46167c478bd9Sstevel@tonic-gate */ 46177c478bd9Sstevel@tonic-gate 46187c478bd9Sstevel@tonic-gate /* make sure it looks like a MIME message */ 4619445f2479Sjbeck if (hvalue("MIME-Version", e->e_header) == NULL && 4620445f2479Sjbeck !putline("MIME-Version: 1.0", mci)) 4621445f2479Sjbeck goto writeerr; 46227c478bd9Sstevel@tonic-gate 46237c478bd9Sstevel@tonic-gate if (hvalue("Content-Type", e->e_header) == NULL) 46247c478bd9Sstevel@tonic-gate { 46257c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 46267c478bd9Sstevel@tonic-gate "Content-Type: text/plain; charset=%s", 46277c478bd9Sstevel@tonic-gate defcharset(e)); 4628445f2479Sjbeck if (!putline(buf, mci)) 4629445f2479Sjbeck goto writeerr; 46307c478bd9Sstevel@tonic-gate } 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate /* now do the hard work */ 46337c478bd9Sstevel@tonic-gate boundaries[0] = NULL; 46347c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 4635*3ee0e492Sjbeck if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER, 0) == 4636445f2479Sjbeck SM_IO_EOF) 4637445f2479Sjbeck goto writeerr; 46387c478bd9Sstevel@tonic-gate } 46397c478bd9Sstevel@tonic-gate # if MIME7TO8 46407c478bd9Sstevel@tonic-gate else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 46417c478bd9Sstevel@tonic-gate { 4642445f2479Sjbeck if (!mime7to8(mci, e->e_header, e)) 4643445f2479Sjbeck goto writeerr; 46447c478bd9Sstevel@tonic-gate } 46457c478bd9Sstevel@tonic-gate # endif /* MIME7TO8 */ 46467c478bd9Sstevel@tonic-gate else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 46477c478bd9Sstevel@tonic-gate { 46487c478bd9Sstevel@tonic-gate bool oldsuprerrs = SuprErrs; 46497c478bd9Sstevel@tonic-gate 46507c478bd9Sstevel@tonic-gate /* Use mime8to7 to check multipart for MIME header overflows */ 46517c478bd9Sstevel@tonic-gate boundaries[0] = NULL; 46527c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 46537c478bd9Sstevel@tonic-gate 46547c478bd9Sstevel@tonic-gate /* 46557c478bd9Sstevel@tonic-gate ** If EF_DONT_MIME is set, we have a broken MIME message 46567c478bd9Sstevel@tonic-gate ** and don't want to generate a new bounce message whose 46577c478bd9Sstevel@tonic-gate ** body propagates the broken MIME. We can't just not call 46587c478bd9Sstevel@tonic-gate ** mime8to7() as is done above since we need the security 46597c478bd9Sstevel@tonic-gate ** checks. The best we can do is suppress the errors. 46607c478bd9Sstevel@tonic-gate */ 46617c478bd9Sstevel@tonic-gate 46627c478bd9Sstevel@tonic-gate if (bitset(EF_DONT_MIME, e->e_flags)) 46637c478bd9Sstevel@tonic-gate SuprErrs = true; 46647c478bd9Sstevel@tonic-gate 4665445f2479Sjbeck if (mime8to7(mci, e->e_header, e, boundaries, 4666*3ee0e492Sjbeck M87F_OUTER|M87F_NO8TO7, 0) == SM_IO_EOF) 4667445f2479Sjbeck goto writeerr; 46687c478bd9Sstevel@tonic-gate 46697c478bd9Sstevel@tonic-gate /* restore SuprErrs */ 46707c478bd9Sstevel@tonic-gate SuprErrs = oldsuprerrs; 46717c478bd9Sstevel@tonic-gate } 46727c478bd9Sstevel@tonic-gate else 46737c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 46747c478bd9Sstevel@tonic-gate { 46757c478bd9Sstevel@tonic-gate int ostate; 46767c478bd9Sstevel@tonic-gate register char *bp; 46777c478bd9Sstevel@tonic-gate register char *pbp; 46787c478bd9Sstevel@tonic-gate register int c; 46797c478bd9Sstevel@tonic-gate register char *xp; 46807c478bd9Sstevel@tonic-gate int padc; 46817c478bd9Sstevel@tonic-gate char *buflim; 46827c478bd9Sstevel@tonic-gate int pos = 0; 46837c478bd9Sstevel@tonic-gate char peekbuf[12]; 46847c478bd9Sstevel@tonic-gate 46857c478bd9Sstevel@tonic-gate if (bitset(MCIF_INHEADER, mci->mci_flags)) 46867c478bd9Sstevel@tonic-gate { 4687445f2479Sjbeck if (!putline("", mci)) 4688445f2479Sjbeck goto writeerr; 46897c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 46907c478bd9Sstevel@tonic-gate } 46917c478bd9Sstevel@tonic-gate 46927c478bd9Sstevel@tonic-gate /* determine end of buffer; allow for short mailer lines */ 46937c478bd9Sstevel@tonic-gate buflim = &buf[sizeof buf - 1]; 46947c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_linelimit > 0 && 46957c478bd9Sstevel@tonic-gate mci->mci_mailer->m_linelimit < sizeof buf - 1) 46967c478bd9Sstevel@tonic-gate buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 46977c478bd9Sstevel@tonic-gate 46987c478bd9Sstevel@tonic-gate /* copy temp file to output with mapping */ 469949218d4fSjbeck ostate = OSTATE_HEAD; 47007c478bd9Sstevel@tonic-gate bp = buf; 47017c478bd9Sstevel@tonic-gate pbp = peekbuf; 47027c478bd9Sstevel@tonic-gate while (!sm_io_error(mci->mci_out) && !dead) 47037c478bd9Sstevel@tonic-gate { 47047c478bd9Sstevel@tonic-gate if (pbp > peekbuf) 47057c478bd9Sstevel@tonic-gate c = *--pbp; 47067c478bd9Sstevel@tonic-gate else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 47077c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47087c478bd9Sstevel@tonic-gate break; 47097c478bd9Sstevel@tonic-gate if (bitset(MCIF_7BIT, mci->mci_flags)) 47107c478bd9Sstevel@tonic-gate c &= 0x7f; 47117c478bd9Sstevel@tonic-gate switch (ostate) 47127c478bd9Sstevel@tonic-gate { 471349218d4fSjbeck case OSTATE_HEAD: 47147c478bd9Sstevel@tonic-gate if (c == '\0' && 47157c478bd9Sstevel@tonic-gate bitnset(M_NONULLS, 47167c478bd9Sstevel@tonic-gate mci->mci_mailer->m_flags)) 47177c478bd9Sstevel@tonic-gate break; 47187c478bd9Sstevel@tonic-gate if (c != '\r' && c != '\n' && bp < buflim) 47197c478bd9Sstevel@tonic-gate { 47207c478bd9Sstevel@tonic-gate *bp++ = c; 47217c478bd9Sstevel@tonic-gate break; 47227c478bd9Sstevel@tonic-gate } 47237c478bd9Sstevel@tonic-gate 47247c478bd9Sstevel@tonic-gate /* check beginning of line for special cases */ 47257c478bd9Sstevel@tonic-gate *bp = '\0'; 47267c478bd9Sstevel@tonic-gate pos = 0; 47277c478bd9Sstevel@tonic-gate padc = SM_IO_EOF; 47287c478bd9Sstevel@tonic-gate if (buf[0] == 'F' && 47297c478bd9Sstevel@tonic-gate bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 47307c478bd9Sstevel@tonic-gate && strncmp(buf, "From ", 5) == 0) 47317c478bd9Sstevel@tonic-gate { 47327c478bd9Sstevel@tonic-gate padc = '>'; 47337c478bd9Sstevel@tonic-gate } 47347c478bd9Sstevel@tonic-gate if (buf[0] == '-' && buf[1] == '-' && 47357c478bd9Sstevel@tonic-gate separator != NULL) 47367c478bd9Sstevel@tonic-gate { 47377c478bd9Sstevel@tonic-gate /* possible separator */ 47387c478bd9Sstevel@tonic-gate int sl = strlen(separator); 47397c478bd9Sstevel@tonic-gate 47407c478bd9Sstevel@tonic-gate if (strncmp(&buf[2], separator, sl) 47417c478bd9Sstevel@tonic-gate == 0) 47427c478bd9Sstevel@tonic-gate padc = ' '; 47437c478bd9Sstevel@tonic-gate } 47447c478bd9Sstevel@tonic-gate if (buf[0] == '.' && 47457c478bd9Sstevel@tonic-gate bitnset(M_XDOT, mci->mci_mailer->m_flags)) 47467c478bd9Sstevel@tonic-gate { 47477c478bd9Sstevel@tonic-gate padc = '.'; 47487c478bd9Sstevel@tonic-gate } 47497c478bd9Sstevel@tonic-gate 47507c478bd9Sstevel@tonic-gate /* now copy out saved line */ 47517c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 47527c478bd9Sstevel@tonic-gate { 47537c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 47547c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47557c478bd9Sstevel@tonic-gate "%05d >>> ", 47567c478bd9Sstevel@tonic-gate (int) CurrentPid); 47577c478bd9Sstevel@tonic-gate if (padc != SM_IO_EOF) 47587c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 47597c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47607c478bd9Sstevel@tonic-gate padc); 47617c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 47627c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 47637c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47647c478bd9Sstevel@tonic-gate (unsigned char) *xp); 47657c478bd9Sstevel@tonic-gate if (c == '\n') 47667c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 47677c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47687c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 47697c478bd9Sstevel@tonic-gate } 47707c478bd9Sstevel@tonic-gate if (padc != SM_IO_EOF) 47717c478bd9Sstevel@tonic-gate { 47727c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 47737c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, padc) 47747c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47757c478bd9Sstevel@tonic-gate { 47767c478bd9Sstevel@tonic-gate dead = true; 47777c478bd9Sstevel@tonic-gate continue; 47787c478bd9Sstevel@tonic-gate } 47797c478bd9Sstevel@tonic-gate pos++; 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 47827c478bd9Sstevel@tonic-gate { 47837c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 47847c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47857c478bd9Sstevel@tonic-gate (unsigned char) *xp) 47867c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47877c478bd9Sstevel@tonic-gate { 47887c478bd9Sstevel@tonic-gate dead = true; 47897c478bd9Sstevel@tonic-gate break; 47907c478bd9Sstevel@tonic-gate } 47917c478bd9Sstevel@tonic-gate } 47927c478bd9Sstevel@tonic-gate if (dead) 47937c478bd9Sstevel@tonic-gate continue; 47947c478bd9Sstevel@tonic-gate if (c == '\n') 47957c478bd9Sstevel@tonic-gate { 47967c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 47977c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47987c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 47997c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48007c478bd9Sstevel@tonic-gate break; 48017c478bd9Sstevel@tonic-gate pos = 0; 48027c478bd9Sstevel@tonic-gate } 48037c478bd9Sstevel@tonic-gate else 48047c478bd9Sstevel@tonic-gate { 48057c478bd9Sstevel@tonic-gate pos += bp - buf; 48067c478bd9Sstevel@tonic-gate if (c != '\r') 48077c478bd9Sstevel@tonic-gate { 48087c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 48097c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 48107c478bd9Sstevel@tonic-gate *pbp++ = c; 48117c478bd9Sstevel@tonic-gate } 48127c478bd9Sstevel@tonic-gate } 48137c478bd9Sstevel@tonic-gate 48147c478bd9Sstevel@tonic-gate bp = buf; 48157c478bd9Sstevel@tonic-gate 48167c478bd9Sstevel@tonic-gate /* determine next state */ 48177c478bd9Sstevel@tonic-gate if (c == '\n') 481849218d4fSjbeck ostate = OSTATE_HEAD; 48197c478bd9Sstevel@tonic-gate else if (c == '\r') 482049218d4fSjbeck ostate = OSTATE_CR; 48217c478bd9Sstevel@tonic-gate else 482249218d4fSjbeck ostate = OSTATE_INLINE; 48237c478bd9Sstevel@tonic-gate continue; 48247c478bd9Sstevel@tonic-gate 482549218d4fSjbeck case OSTATE_CR: 48267c478bd9Sstevel@tonic-gate if (c == '\n') 48277c478bd9Sstevel@tonic-gate { 48287c478bd9Sstevel@tonic-gate /* got CRLF */ 48297c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 48307c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48317c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 48327c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48337c478bd9Sstevel@tonic-gate continue; 48347c478bd9Sstevel@tonic-gate 48357c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 48367c478bd9Sstevel@tonic-gate { 48377c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 48387c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48397c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 48407c478bd9Sstevel@tonic-gate } 484149218d4fSjbeck ostate = OSTATE_HEAD; 48427c478bd9Sstevel@tonic-gate continue; 48437c478bd9Sstevel@tonic-gate } 48447c478bd9Sstevel@tonic-gate 48457c478bd9Sstevel@tonic-gate /* had a naked carriage return */ 48467c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 48477c478bd9Sstevel@tonic-gate *pbp++ = c; 48487c478bd9Sstevel@tonic-gate c = '\r'; 484949218d4fSjbeck ostate = OSTATE_INLINE; 48507c478bd9Sstevel@tonic-gate goto putch; 48517c478bd9Sstevel@tonic-gate 485249218d4fSjbeck case OSTATE_INLINE: 48537c478bd9Sstevel@tonic-gate if (c == '\r') 48547c478bd9Sstevel@tonic-gate { 485549218d4fSjbeck ostate = OSTATE_CR; 48567c478bd9Sstevel@tonic-gate continue; 48577c478bd9Sstevel@tonic-gate } 48587c478bd9Sstevel@tonic-gate if (c == '\0' && 48597c478bd9Sstevel@tonic-gate bitnset(M_NONULLS, 48607c478bd9Sstevel@tonic-gate mci->mci_mailer->m_flags)) 48617c478bd9Sstevel@tonic-gate break; 48627c478bd9Sstevel@tonic-gate putch: 48637c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_linelimit > 0 && 48647c478bd9Sstevel@tonic-gate pos >= mci->mci_mailer->m_linelimit - 1 && 48657c478bd9Sstevel@tonic-gate c != '\n') 48667c478bd9Sstevel@tonic-gate { 48677c478bd9Sstevel@tonic-gate int d; 48687c478bd9Sstevel@tonic-gate 48697c478bd9Sstevel@tonic-gate /* check next character for EOL */ 48707c478bd9Sstevel@tonic-gate if (pbp > peekbuf) 48717c478bd9Sstevel@tonic-gate d = *(pbp - 1); 48727c478bd9Sstevel@tonic-gate else if ((d = sm_io_getc(e->e_dfp, 48737c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT)) 48747c478bd9Sstevel@tonic-gate != SM_IO_EOF) 48757c478bd9Sstevel@tonic-gate { 48767c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 48777c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 48787c478bd9Sstevel@tonic-gate *pbp++ = d; 48797c478bd9Sstevel@tonic-gate } 48807c478bd9Sstevel@tonic-gate 48817c478bd9Sstevel@tonic-gate if (d == '\n' || d == SM_IO_EOF) 48827c478bd9Sstevel@tonic-gate { 48837c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 48847c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 48857c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48867c478bd9Sstevel@tonic-gate (unsigned char) c); 48877c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 48887c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48897c478bd9Sstevel@tonic-gate (unsigned char) c) 48907c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48917c478bd9Sstevel@tonic-gate { 48927c478bd9Sstevel@tonic-gate dead = true; 48937c478bd9Sstevel@tonic-gate continue; 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate pos++; 48967c478bd9Sstevel@tonic-gate continue; 48977c478bd9Sstevel@tonic-gate } 48987c478bd9Sstevel@tonic-gate 48997c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 49007c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, '!') 49017c478bd9Sstevel@tonic-gate == SM_IO_EOF || 49027c478bd9Sstevel@tonic-gate sm_io_fputs(mci->mci_out, 49037c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49047c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 49057c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49067c478bd9Sstevel@tonic-gate { 49077c478bd9Sstevel@tonic-gate dead = true; 49087c478bd9Sstevel@tonic-gate continue; 49097c478bd9Sstevel@tonic-gate } 49107c478bd9Sstevel@tonic-gate 49117c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49127c478bd9Sstevel@tonic-gate { 49137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 49147c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49157c478bd9Sstevel@tonic-gate "!%s", 49167c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 49177c478bd9Sstevel@tonic-gate } 491849218d4fSjbeck ostate = OSTATE_HEAD; 49197c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 49207c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 49217c478bd9Sstevel@tonic-gate *pbp++ = c; 49227c478bd9Sstevel@tonic-gate continue; 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate if (c == '\n') 49257c478bd9Sstevel@tonic-gate { 49267c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49277c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 49287c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49297c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 49307c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 49317c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49327c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 49337c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49347c478bd9Sstevel@tonic-gate continue; 49357c478bd9Sstevel@tonic-gate pos = 0; 493649218d4fSjbeck ostate = OSTATE_HEAD; 49377c478bd9Sstevel@tonic-gate } 49387c478bd9Sstevel@tonic-gate else 49397c478bd9Sstevel@tonic-gate { 49407c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49417c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 49427c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49437c478bd9Sstevel@tonic-gate (unsigned char) c); 49447c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 49457c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49467c478bd9Sstevel@tonic-gate (unsigned char) c) 49477c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49487c478bd9Sstevel@tonic-gate { 49497c478bd9Sstevel@tonic-gate dead = true; 49507c478bd9Sstevel@tonic-gate continue; 49517c478bd9Sstevel@tonic-gate } 49527c478bd9Sstevel@tonic-gate pos++; 495349218d4fSjbeck ostate = OSTATE_INLINE; 49547c478bd9Sstevel@tonic-gate } 49557c478bd9Sstevel@tonic-gate break; 49567c478bd9Sstevel@tonic-gate } 49577c478bd9Sstevel@tonic-gate } 49587c478bd9Sstevel@tonic-gate 49597c478bd9Sstevel@tonic-gate /* make sure we are at the beginning of a line */ 49607c478bd9Sstevel@tonic-gate if (bp > buf) 49617c478bd9Sstevel@tonic-gate { 49627c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49637c478bd9Sstevel@tonic-gate { 49647c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 49657c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 49667c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49677c478bd9Sstevel@tonic-gate (unsigned char) *xp); 49687c478bd9Sstevel@tonic-gate } 49697c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 49707c478bd9Sstevel@tonic-gate { 49717c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 49727c478bd9Sstevel@tonic-gate (unsigned char) *xp) 49737c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49747c478bd9Sstevel@tonic-gate { 49757c478bd9Sstevel@tonic-gate dead = true; 49767c478bd9Sstevel@tonic-gate break; 49777c478bd9Sstevel@tonic-gate } 49787c478bd9Sstevel@tonic-gate } 49797c478bd9Sstevel@tonic-gate pos += bp - buf; 49807c478bd9Sstevel@tonic-gate } 49817c478bd9Sstevel@tonic-gate if (!dead && pos > 0) 49827c478bd9Sstevel@tonic-gate { 49837c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49847c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 49857c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49867c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 4987445f2479Sjbeck if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 4988445f2479Sjbeck mci->mci_mailer->m_eol) == SM_IO_EOF) 4989445f2479Sjbeck goto writeerr; 49907c478bd9Sstevel@tonic-gate } 49917c478bd9Sstevel@tonic-gate } 49927c478bd9Sstevel@tonic-gate 49937c478bd9Sstevel@tonic-gate if (sm_io_error(e->e_dfp)) 49947c478bd9Sstevel@tonic-gate { 49957c478bd9Sstevel@tonic-gate syserr("putbody: %s/%cf%s: read error", 49967c478bd9Sstevel@tonic-gate qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 49977c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 49987c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 4999445f2479Sjbeck ioerr = true; 50007c478bd9Sstevel@tonic-gate } 50017c478bd9Sstevel@tonic-gate 50027c478bd9Sstevel@tonic-gate endofmessage: 50037c478bd9Sstevel@tonic-gate /* 50047c478bd9Sstevel@tonic-gate ** Since mailfile() uses e_dfp in a child process, 50057c478bd9Sstevel@tonic-gate ** the file offset in the stdio library for the 50067c478bd9Sstevel@tonic-gate ** parent process will not agree with the in-kernel 50077c478bd9Sstevel@tonic-gate ** file offset since the file descriptor is shared 50087c478bd9Sstevel@tonic-gate ** between the processes. Therefore, it is vital 50097c478bd9Sstevel@tonic-gate ** that the file always be rewound. This forces the 50107c478bd9Sstevel@tonic-gate ** kernel offset (lseek) and stdio library (ftell) 50117c478bd9Sstevel@tonic-gate ** offset to match. 50127c478bd9Sstevel@tonic-gate */ 50137c478bd9Sstevel@tonic-gate 5014445f2479Sjbeck save_errno = errno; 50157c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 50167c478bd9Sstevel@tonic-gate (void) bfrewind(e->e_dfp); 50177c478bd9Sstevel@tonic-gate 50187c478bd9Sstevel@tonic-gate /* some mailers want extra blank line at end of message */ 50197c478bd9Sstevel@tonic-gate if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 50207c478bd9Sstevel@tonic-gate buf[0] != '\0' && buf[0] != '\n') 50217c478bd9Sstevel@tonic-gate { 5022445f2479Sjbeck if (!putline("", mci)) 5023445f2479Sjbeck goto writeerr; 5024445f2479Sjbeck } 5025445f2479Sjbeck 5026445f2479Sjbeck if (!dead && 5027445f2479Sjbeck (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF || 5028445f2479Sjbeck (sm_io_error(mci->mci_out) && errno != EPIPE))) 5029445f2479Sjbeck { 5030445f2479Sjbeck save_errno = errno; 50317c478bd9Sstevel@tonic-gate syserr("putbody: write error"); 50327c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 5033445f2479Sjbeck ioerr = true; 50347c478bd9Sstevel@tonic-gate } 50357c478bd9Sstevel@tonic-gate 5036445f2479Sjbeck errno = save_errno; 5037445f2479Sjbeck return !dead && !ioerr; 5038445f2479Sjbeck 5039445f2479Sjbeck writeerr: 5040445f2479Sjbeck return false; 50417c478bd9Sstevel@tonic-gate } 5042445f2479Sjbeck 50437c478bd9Sstevel@tonic-gate /* 50447c478bd9Sstevel@tonic-gate ** MAILFILE -- Send a message to a file. 50457c478bd9Sstevel@tonic-gate ** 50467c478bd9Sstevel@tonic-gate ** If the file has the set-user-ID/set-group-ID bits set, but NO 50477c478bd9Sstevel@tonic-gate ** execute bits, sendmail will try to become the owner of that file 50487c478bd9Sstevel@tonic-gate ** rather than the real user. Obviously, this only works if 50497c478bd9Sstevel@tonic-gate ** sendmail runs as root. 50507c478bd9Sstevel@tonic-gate ** 50517c478bd9Sstevel@tonic-gate ** This could be done as a subordinate mailer, except that it 50527c478bd9Sstevel@tonic-gate ** is used implicitly to save messages in ~/dead.letter. We 50537c478bd9Sstevel@tonic-gate ** view this as being sufficiently important as to include it 50547c478bd9Sstevel@tonic-gate ** here. For example, if the system is dying, we shouldn't have 50557c478bd9Sstevel@tonic-gate ** to create another process plus some pipes to save the message. 50567c478bd9Sstevel@tonic-gate ** 50577c478bd9Sstevel@tonic-gate ** Parameters: 50587c478bd9Sstevel@tonic-gate ** filename -- the name of the file to send to. 50597c478bd9Sstevel@tonic-gate ** mailer -- mailer definition for recipient -- if NULL, 50607c478bd9Sstevel@tonic-gate ** use FileMailer. 50617c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address header -- includes 50627c478bd9Sstevel@tonic-gate ** the userid/groupid to be when sending. 50637c478bd9Sstevel@tonic-gate ** sfflags -- flags for opening. 50647c478bd9Sstevel@tonic-gate ** e -- the current envelope. 50657c478bd9Sstevel@tonic-gate ** 50667c478bd9Sstevel@tonic-gate ** Returns: 50677c478bd9Sstevel@tonic-gate ** The exit code associated with the operation. 50687c478bd9Sstevel@tonic-gate ** 50697c478bd9Sstevel@tonic-gate ** Side Effects: 50707c478bd9Sstevel@tonic-gate ** none. 50717c478bd9Sstevel@tonic-gate */ 50727c478bd9Sstevel@tonic-gate 50737c478bd9Sstevel@tonic-gate # define RETURN(st) exit(st); 50747c478bd9Sstevel@tonic-gate 50757c478bd9Sstevel@tonic-gate static jmp_buf CtxMailfileTimeout; 50767c478bd9Sstevel@tonic-gate 50777c478bd9Sstevel@tonic-gate int 50787c478bd9Sstevel@tonic-gate mailfile(filename, mailer, ctladdr, sfflags, e) 50797c478bd9Sstevel@tonic-gate char *volatile filename; 50807c478bd9Sstevel@tonic-gate MAILER *volatile mailer; 50817c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 50827c478bd9Sstevel@tonic-gate volatile long sfflags; 50837c478bd9Sstevel@tonic-gate register ENVELOPE *e; 50847c478bd9Sstevel@tonic-gate { 50857c478bd9Sstevel@tonic-gate register SM_FILE_T *f; 50867c478bd9Sstevel@tonic-gate register pid_t pid = -1; 50877c478bd9Sstevel@tonic-gate volatile int mode; 50887c478bd9Sstevel@tonic-gate int len; 50897c478bd9Sstevel@tonic-gate off_t curoff; 50907c478bd9Sstevel@tonic-gate bool suidwarn = geteuid() == 0; 50917c478bd9Sstevel@tonic-gate char *p; 50927c478bd9Sstevel@tonic-gate char *volatile realfile; 50937c478bd9Sstevel@tonic-gate SM_EVENT *ev; 50947c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 50957c478bd9Sstevel@tonic-gate char targetfile[MAXPATHLEN]; 50967c478bd9Sstevel@tonic-gate 50977c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 50987c478bd9Sstevel@tonic-gate { 50997c478bd9Sstevel@tonic-gate sm_dprintf("mailfile %s\n ctladdr=", filename); 51007c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 51017c478bd9Sstevel@tonic-gate } 51027c478bd9Sstevel@tonic-gate 51037c478bd9Sstevel@tonic-gate if (mailer == NULL) 51047c478bd9Sstevel@tonic-gate mailer = FileMailer; 51057c478bd9Sstevel@tonic-gate 51067c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 51077c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 51087c478bd9Sstevel@tonic-gate 51097c478bd9Sstevel@tonic-gate /* 51107c478bd9Sstevel@tonic-gate ** Special case /dev/null. This allows us to restrict file 51117c478bd9Sstevel@tonic-gate ** delivery to regular files only. 51127c478bd9Sstevel@tonic-gate */ 51137c478bd9Sstevel@tonic-gate 51147c478bd9Sstevel@tonic-gate if (sm_path_isdevnull(filename)) 51157c478bd9Sstevel@tonic-gate return EX_OK; 51167c478bd9Sstevel@tonic-gate 51177c478bd9Sstevel@tonic-gate /* check for 8-bit available */ 51187c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 51197c478bd9Sstevel@tonic-gate bitnset(M_7BITS, mailer->m_flags) && 51207c478bd9Sstevel@tonic-gate (bitset(EF_DONT_MIME, e->e_flags) || 51217c478bd9Sstevel@tonic-gate !(bitset(MM_MIME8BIT, MimeMode) || 51227c478bd9Sstevel@tonic-gate (bitset(EF_IS_MIME, e->e_flags) && 51237c478bd9Sstevel@tonic-gate bitset(MM_CVTMIME, MimeMode))))) 51247c478bd9Sstevel@tonic-gate { 51257c478bd9Sstevel@tonic-gate e->e_status = "5.6.3"; 51267c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 51277c478bd9Sstevel@tonic-gate "554 Cannot send 8-bit data to 7-bit destination"); 51287c478bd9Sstevel@tonic-gate errno = 0; 51297c478bd9Sstevel@tonic-gate return EX_DATAERR; 51307c478bd9Sstevel@tonic-gate } 51317c478bd9Sstevel@tonic-gate 51327c478bd9Sstevel@tonic-gate /* Find the actual file */ 51337c478bd9Sstevel@tonic-gate if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 51347c478bd9Sstevel@tonic-gate { 51357c478bd9Sstevel@tonic-gate len = strlen(SafeFileEnv); 51367c478bd9Sstevel@tonic-gate 51377c478bd9Sstevel@tonic-gate if (strncmp(SafeFileEnv, filename, len) == 0) 51387c478bd9Sstevel@tonic-gate filename += len; 51397c478bd9Sstevel@tonic-gate 51407c478bd9Sstevel@tonic-gate if (len + strlen(filename) + 1 >= sizeof targetfile) 51417c478bd9Sstevel@tonic-gate { 51427c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s/%s)", 51437c478bd9Sstevel@tonic-gate SafeFileEnv, filename); 51447c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51457c478bd9Sstevel@tonic-gate } 51467c478bd9Sstevel@tonic-gate (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile); 51477c478bd9Sstevel@tonic-gate realfile = targetfile + len; 51487c478bd9Sstevel@tonic-gate if (*filename == '/') 51497c478bd9Sstevel@tonic-gate filename++; 51507c478bd9Sstevel@tonic-gate if (*filename != '\0') 51517c478bd9Sstevel@tonic-gate { 51527c478bd9Sstevel@tonic-gate /* paranoia: trailing / should be removed in readcf */ 51537c478bd9Sstevel@tonic-gate if (targetfile[len - 1] != '/') 51547c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, 51557c478bd9Sstevel@tonic-gate "/", sizeof targetfile); 51567c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename, 51577c478bd9Sstevel@tonic-gate sizeof targetfile); 51587c478bd9Sstevel@tonic-gate } 51597c478bd9Sstevel@tonic-gate } 51607c478bd9Sstevel@tonic-gate else if (mailer->m_rootdir != NULL) 51617c478bd9Sstevel@tonic-gate { 51627c478bd9Sstevel@tonic-gate expand(mailer->m_rootdir, targetfile, sizeof targetfile, e); 51637c478bd9Sstevel@tonic-gate len = strlen(targetfile); 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate if (strncmp(targetfile, filename, len) == 0) 51667c478bd9Sstevel@tonic-gate filename += len; 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate if (len + strlen(filename) + 1 >= sizeof targetfile) 51697c478bd9Sstevel@tonic-gate { 51707c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s/%s)", 51717c478bd9Sstevel@tonic-gate targetfile, filename); 51727c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51737c478bd9Sstevel@tonic-gate } 51747c478bd9Sstevel@tonic-gate realfile = targetfile + len; 51757c478bd9Sstevel@tonic-gate if (targetfile[len - 1] != '/') 51767c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, "/", sizeof targetfile); 51777c478bd9Sstevel@tonic-gate if (*filename == '/') 51787c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename + 1, 51797c478bd9Sstevel@tonic-gate sizeof targetfile); 51807c478bd9Sstevel@tonic-gate else 51817c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename, 51827c478bd9Sstevel@tonic-gate sizeof targetfile); 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate else 51857c478bd9Sstevel@tonic-gate { 51867c478bd9Sstevel@tonic-gate if (sm_strlcpy(targetfile, filename, sizeof targetfile) >= 51877c478bd9Sstevel@tonic-gate sizeof targetfile) 51887c478bd9Sstevel@tonic-gate { 51897c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s)", filename); 51907c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51917c478bd9Sstevel@tonic-gate } 51927c478bd9Sstevel@tonic-gate realfile = targetfile; 51937c478bd9Sstevel@tonic-gate } 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate /* 51967c478bd9Sstevel@tonic-gate ** Fork so we can change permissions here. 51977c478bd9Sstevel@tonic-gate ** Note that we MUST use fork, not vfork, because of 51987c478bd9Sstevel@tonic-gate ** the complications of calling subroutines, etc. 51997c478bd9Sstevel@tonic-gate */ 52007c478bd9Sstevel@tonic-gate 52017c478bd9Sstevel@tonic-gate 52027c478bd9Sstevel@tonic-gate /* 52037c478bd9Sstevel@tonic-gate ** Dispose of SIGCHLD signal catchers that may be laying 52047c478bd9Sstevel@tonic-gate ** around so that the waitfor() below will get it. 52057c478bd9Sstevel@tonic-gate */ 52067c478bd9Sstevel@tonic-gate 52077c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 52087c478bd9Sstevel@tonic-gate 52097c478bd9Sstevel@tonic-gate DOFORK(fork); 52107c478bd9Sstevel@tonic-gate 52117c478bd9Sstevel@tonic-gate if (pid < 0) 52127c478bd9Sstevel@tonic-gate return EX_OSERR; 52137c478bd9Sstevel@tonic-gate else if (pid == 0) 52147c478bd9Sstevel@tonic-gate { 52157c478bd9Sstevel@tonic-gate /* child -- actually write to file */ 52167c478bd9Sstevel@tonic-gate struct stat stb; 52177c478bd9Sstevel@tonic-gate MCI mcibuf; 52187c478bd9Sstevel@tonic-gate int err; 52197c478bd9Sstevel@tonic-gate volatile int oflags = O_WRONLY|O_APPEND; 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate /* Reset global flags */ 52227c478bd9Sstevel@tonic-gate RestartRequest = NULL; 52237c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 52247c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 52257c478bd9Sstevel@tonic-gate PendingSignal = 0; 52267c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 52277c478bd9Sstevel@tonic-gate 52287c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 5229*3ee0e492Sjbeck { 5230*3ee0e492Sjbeck int fd; 5231*3ee0e492Sjbeck 5232*3ee0e492Sjbeck fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL); 5233*3ee0e492Sjbeck /* SM_ASSERT(fd >= 0); */ 5234*3ee0e492Sjbeck if (fd >= 0) 5235*3ee0e492Sjbeck (void) close(fd); 5236*3ee0e492Sjbeck } 52377c478bd9Sstevel@tonic-gate 52387c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, SIG_DFL); 52397c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_DFL); 52407c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, SIG_DFL); 52417c478bd9Sstevel@tonic-gate (void) umask(OldUmask); 52427c478bd9Sstevel@tonic-gate e->e_to = filename; 52437c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 52447c478bd9Sstevel@tonic-gate 52457c478bd9Sstevel@tonic-gate if (setjmp(CtxMailfileTimeout) != 0) 52467c478bd9Sstevel@tonic-gate { 52477c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 52487c478bd9Sstevel@tonic-gate } 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate if (TimeOuts.to_fileopen > 0) 52517c478bd9Sstevel@tonic-gate ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 52527c478bd9Sstevel@tonic-gate 0); 52537c478bd9Sstevel@tonic-gate else 52547c478bd9Sstevel@tonic-gate ev = NULL; 52557c478bd9Sstevel@tonic-gate 52567c478bd9Sstevel@tonic-gate /* check file mode to see if set-user-ID */ 52577c478bd9Sstevel@tonic-gate if (stat(targetfile, &stb) < 0) 52587c478bd9Sstevel@tonic-gate mode = FileMode; 52597c478bd9Sstevel@tonic-gate else 52607c478bd9Sstevel@tonic-gate mode = stb.st_mode; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate /* limit the errors to those actually caused in the child */ 52637c478bd9Sstevel@tonic-gate errno = 0; 52647c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 52657c478bd9Sstevel@tonic-gate 52667c478bd9Sstevel@tonic-gate /* Allow alias expansions to use the S_IS{U,G}ID bits */ 52677c478bd9Sstevel@tonic-gate if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 52687c478bd9Sstevel@tonic-gate bitset(SFF_RUNASREALUID, sfflags)) 52697c478bd9Sstevel@tonic-gate { 52707c478bd9Sstevel@tonic-gate /* ignore set-user-ID and set-group-ID bits */ 52717c478bd9Sstevel@tonic-gate mode &= ~(S_ISGID|S_ISUID); 52727c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 52737c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 52747c478bd9Sstevel@tonic-gate } 52757c478bd9Sstevel@tonic-gate 52767c478bd9Sstevel@tonic-gate /* we have to open the data file BEFORE setuid() */ 52777c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 52787c478bd9Sstevel@tonic-gate { 52797c478bd9Sstevel@tonic-gate char *df = queuename(e, DATAFL_LETTER); 52807c478bd9Sstevel@tonic-gate 52817c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 52827c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL); 52837c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 52847c478bd9Sstevel@tonic-gate { 52857c478bd9Sstevel@tonic-gate syserr("mailfile: Cannot open %s for %s from %s", 52867c478bd9Sstevel@tonic-gate df, e->e_to, e->e_from.q_paddr); 52877c478bd9Sstevel@tonic-gate } 52887c478bd9Sstevel@tonic-gate } 52897c478bd9Sstevel@tonic-gate 52907c478bd9Sstevel@tonic-gate /* select a new user to run as */ 52917c478bd9Sstevel@tonic-gate if (!bitset(SFF_RUNASREALUID, sfflags)) 52927c478bd9Sstevel@tonic-gate { 52937c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 52947c478bd9Sstevel@tonic-gate { 52957c478bd9Sstevel@tonic-gate RealUserName = NULL; 52967c478bd9Sstevel@tonic-gate if (mailer->m_uid == NO_UID) 52977c478bd9Sstevel@tonic-gate RealUid = RunAsUid; 52987c478bd9Sstevel@tonic-gate else 52997c478bd9Sstevel@tonic-gate RealUid = mailer->m_uid; 53007c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && RealUid != RunAsUid) 53017c478bd9Sstevel@tonic-gate { 53027c478bd9Sstevel@tonic-gate /* Only root can change the uid */ 53037c478bd9Sstevel@tonic-gate syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", 53047c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) RealUid); 53057c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53067c478bd9Sstevel@tonic-gate } 53077c478bd9Sstevel@tonic-gate } 53087c478bd9Sstevel@tonic-gate else if (bitset(S_ISUID, mode)) 53097c478bd9Sstevel@tonic-gate { 53107c478bd9Sstevel@tonic-gate RealUserName = NULL; 53117c478bd9Sstevel@tonic-gate RealUid = stb.st_uid; 53127c478bd9Sstevel@tonic-gate } 53137c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_uid != 0) 53147c478bd9Sstevel@tonic-gate { 53157c478bd9Sstevel@tonic-gate if (ctladdr->q_ruser != NULL) 53167c478bd9Sstevel@tonic-gate RealUserName = ctladdr->q_ruser; 53177c478bd9Sstevel@tonic-gate else 53187c478bd9Sstevel@tonic-gate RealUserName = ctladdr->q_user; 53197c478bd9Sstevel@tonic-gate RealUid = ctladdr->q_uid; 53207c478bd9Sstevel@tonic-gate } 53217c478bd9Sstevel@tonic-gate else if (mailer != NULL && mailer->m_uid != NO_UID) 53227c478bd9Sstevel@tonic-gate { 53237c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53247c478bd9Sstevel@tonic-gate RealUid = mailer->m_uid; 53257c478bd9Sstevel@tonic-gate } 53267c478bd9Sstevel@tonic-gate else 53277c478bd9Sstevel@tonic-gate { 53287c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53297c478bd9Sstevel@tonic-gate RealUid = DefUid; 53307c478bd9Sstevel@tonic-gate } 53317c478bd9Sstevel@tonic-gate 53327c478bd9Sstevel@tonic-gate /* select a new group to run as */ 53337c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 53347c478bd9Sstevel@tonic-gate { 53357c478bd9Sstevel@tonic-gate if (mailer->m_gid == NO_GID) 53367c478bd9Sstevel@tonic-gate RealGid = RunAsGid; 53377c478bd9Sstevel@tonic-gate else 53387c478bd9Sstevel@tonic-gate RealGid = mailer->m_gid; 53397c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && 53407c478bd9Sstevel@tonic-gate (RealGid != getgid() || 53417c478bd9Sstevel@tonic-gate RealGid != getegid())) 53427c478bd9Sstevel@tonic-gate { 53437c478bd9Sstevel@tonic-gate /* Only root can change the gid */ 53447c478bd9Sstevel@tonic-gate syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", 53457c478bd9Sstevel@tonic-gate (int) RealGid, (int) RunAsUid, 53467c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 53477c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53487c478bd9Sstevel@tonic-gate } 53497c478bd9Sstevel@tonic-gate } 53507c478bd9Sstevel@tonic-gate else if (bitset(S_ISGID, mode)) 53517c478bd9Sstevel@tonic-gate RealGid = stb.st_gid; 53527c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && 53537c478bd9Sstevel@tonic-gate ctladdr->q_uid == DefUid && 53547c478bd9Sstevel@tonic-gate ctladdr->q_gid == 0) 53557c478bd9Sstevel@tonic-gate { 53567c478bd9Sstevel@tonic-gate /* 53577c478bd9Sstevel@tonic-gate ** Special case: This means it is an 53587c478bd9Sstevel@tonic-gate ** alias and we should act as DefaultUser. 53597c478bd9Sstevel@tonic-gate ** See alias()'s comments. 53607c478bd9Sstevel@tonic-gate */ 53617c478bd9Sstevel@tonic-gate 53627c478bd9Sstevel@tonic-gate RealGid = DefGid; 53637c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53647c478bd9Sstevel@tonic-gate } 53657c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_uid != 0) 53667c478bd9Sstevel@tonic-gate RealGid = ctladdr->q_gid; 53677c478bd9Sstevel@tonic-gate else if (mailer != NULL && mailer->m_gid != NO_GID) 53687c478bd9Sstevel@tonic-gate RealGid = mailer->m_gid; 53697c478bd9Sstevel@tonic-gate else 53707c478bd9Sstevel@tonic-gate RealGid = DefGid; 53717c478bd9Sstevel@tonic-gate } 53727c478bd9Sstevel@tonic-gate 53737c478bd9Sstevel@tonic-gate /* last ditch */ 53747c478bd9Sstevel@tonic-gate if (!bitset(SFF_ROOTOK, sfflags)) 53757c478bd9Sstevel@tonic-gate { 53767c478bd9Sstevel@tonic-gate if (RealUid == 0) 53777c478bd9Sstevel@tonic-gate RealUid = DefUid; 53787c478bd9Sstevel@tonic-gate if (RealGid == 0) 53797c478bd9Sstevel@tonic-gate RealGid = DefGid; 53807c478bd9Sstevel@tonic-gate } 53817c478bd9Sstevel@tonic-gate 53827c478bd9Sstevel@tonic-gate /* set group id list (needs /etc/group access) */ 53837c478bd9Sstevel@tonic-gate if (RealUserName != NULL && !DontInitGroups) 53847c478bd9Sstevel@tonic-gate { 53857c478bd9Sstevel@tonic-gate if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 53867c478bd9Sstevel@tonic-gate { 53877c478bd9Sstevel@tonic-gate syserr("mailfile: initgroups(%s, %d) failed", 53887c478bd9Sstevel@tonic-gate RealUserName, RealGid); 53897c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53907c478bd9Sstevel@tonic-gate } 53917c478bd9Sstevel@tonic-gate } 53927c478bd9Sstevel@tonic-gate else 53937c478bd9Sstevel@tonic-gate { 53947c478bd9Sstevel@tonic-gate GIDSET_T gidset[1]; 53957c478bd9Sstevel@tonic-gate 53967c478bd9Sstevel@tonic-gate gidset[0] = RealGid; 53977c478bd9Sstevel@tonic-gate if (setgroups(1, gidset) == -1 && suidwarn) 53987c478bd9Sstevel@tonic-gate { 53997c478bd9Sstevel@tonic-gate syserr("mailfile: setgroups() failed"); 54007c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 54017c478bd9Sstevel@tonic-gate } 54027c478bd9Sstevel@tonic-gate } 54037c478bd9Sstevel@tonic-gate 54047c478bd9Sstevel@tonic-gate /* 54057c478bd9Sstevel@tonic-gate ** If you have a safe environment, go into it. 54067c478bd9Sstevel@tonic-gate */ 54077c478bd9Sstevel@tonic-gate 54087c478bd9Sstevel@tonic-gate if (realfile != targetfile) 54097c478bd9Sstevel@tonic-gate { 54107c478bd9Sstevel@tonic-gate char save; 54117c478bd9Sstevel@tonic-gate 54127c478bd9Sstevel@tonic-gate save = *realfile; 54137c478bd9Sstevel@tonic-gate *realfile = '\0'; 54147c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 54157c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: chroot %s\n", targetfile); 54167c478bd9Sstevel@tonic-gate if (chroot(targetfile) < 0) 54177c478bd9Sstevel@tonic-gate { 54187c478bd9Sstevel@tonic-gate syserr("mailfile: Cannot chroot(%s)", 54197c478bd9Sstevel@tonic-gate targetfile); 54207c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 54217c478bd9Sstevel@tonic-gate } 54227c478bd9Sstevel@tonic-gate *realfile = save; 54237c478bd9Sstevel@tonic-gate } 54247c478bd9Sstevel@tonic-gate 54257c478bd9Sstevel@tonic-gate if (tTd(11, 40)) 54267c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: deliver to %s\n", realfile); 54277c478bd9Sstevel@tonic-gate 54287c478bd9Sstevel@tonic-gate if (chdir("/") < 0) 54297c478bd9Sstevel@tonic-gate { 54307c478bd9Sstevel@tonic-gate syserr("mailfile: cannot chdir(/)"); 54317c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 54327c478bd9Sstevel@tonic-gate } 54337c478bd9Sstevel@tonic-gate 54347c478bd9Sstevel@tonic-gate /* now reset the group and user ids */ 54357c478bd9Sstevel@tonic-gate endpwent(); 54367c478bd9Sstevel@tonic-gate sm_mbdb_terminate(); 54377c478bd9Sstevel@tonic-gate if (setgid(RealGid) < 0 && suidwarn) 54387c478bd9Sstevel@tonic-gate { 54397c478bd9Sstevel@tonic-gate syserr("mailfile: setgid(%ld) failed", (long) RealGid); 54407c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 54417c478bd9Sstevel@tonic-gate } 54427c478bd9Sstevel@tonic-gate vendor_set_uid(RealUid); 54437c478bd9Sstevel@tonic-gate if (setuid(RealUid) < 0 && suidwarn) 54447c478bd9Sstevel@tonic-gate { 54457c478bd9Sstevel@tonic-gate syserr("mailfile: setuid(%ld) failed", (long) RealUid); 54467c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 54477c478bd9Sstevel@tonic-gate } 54487c478bd9Sstevel@tonic-gate 54497c478bd9Sstevel@tonic-gate if (tTd(11, 2)) 54507c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 54517c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid(), 54527c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 54537c478bd9Sstevel@tonic-gate 54547c478bd9Sstevel@tonic-gate 54557c478bd9Sstevel@tonic-gate /* move into some "safe" directory */ 54567c478bd9Sstevel@tonic-gate if (mailer->m_execdir != NULL) 54577c478bd9Sstevel@tonic-gate { 54587c478bd9Sstevel@tonic-gate char *q; 54597c478bd9Sstevel@tonic-gate 54607c478bd9Sstevel@tonic-gate for (p = mailer->m_execdir; p != NULL; p = q) 54617c478bd9Sstevel@tonic-gate { 54627c478bd9Sstevel@tonic-gate q = strchr(p, ':'); 54637c478bd9Sstevel@tonic-gate if (q != NULL) 54647c478bd9Sstevel@tonic-gate *q = '\0'; 54657c478bd9Sstevel@tonic-gate expand(p, buf, sizeof buf, e); 54667c478bd9Sstevel@tonic-gate if (q != NULL) 54677c478bd9Sstevel@tonic-gate *q++ = ':'; 54687c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 54697c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: trydir %s\n", 54707c478bd9Sstevel@tonic-gate buf); 54717c478bd9Sstevel@tonic-gate if (buf[0] != '\0' && chdir(buf) >= 0) 54727c478bd9Sstevel@tonic-gate break; 54737c478bd9Sstevel@tonic-gate } 54747c478bd9Sstevel@tonic-gate } 54757c478bd9Sstevel@tonic-gate 54767c478bd9Sstevel@tonic-gate /* 54777c478bd9Sstevel@tonic-gate ** Recheck the file after we have assumed the ID of the 54787c478bd9Sstevel@tonic-gate ** delivery user to make sure we can deliver to it as 54797c478bd9Sstevel@tonic-gate ** that user. This is necessary if sendmail is running 54807c478bd9Sstevel@tonic-gate ** as root and the file is on an NFS mount which treats 54817c478bd9Sstevel@tonic-gate ** root as nobody. 54827c478bd9Sstevel@tonic-gate */ 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate #if HASLSTAT 54857c478bd9Sstevel@tonic-gate if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 54867c478bd9Sstevel@tonic-gate err = stat(realfile, &stb); 54877c478bd9Sstevel@tonic-gate else 54887c478bd9Sstevel@tonic-gate err = lstat(realfile, &stb); 54897c478bd9Sstevel@tonic-gate #else /* HASLSTAT */ 54907c478bd9Sstevel@tonic-gate err = stat(realfile, &stb); 54917c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 54927c478bd9Sstevel@tonic-gate 54937c478bd9Sstevel@tonic-gate if (err < 0) 54947c478bd9Sstevel@tonic-gate { 54957c478bd9Sstevel@tonic-gate stb.st_mode = ST_MODE_NOFILE; 54967c478bd9Sstevel@tonic-gate mode = FileMode; 54977c478bd9Sstevel@tonic-gate oflags |= O_CREAT|O_EXCL; 54987c478bd9Sstevel@tonic-gate } 54997c478bd9Sstevel@tonic-gate else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 55007c478bd9Sstevel@tonic-gate (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 55017c478bd9Sstevel@tonic-gate DontBlameSendmail) && 55027c478bd9Sstevel@tonic-gate stb.st_nlink != 1) || 55037c478bd9Sstevel@tonic-gate (realfile != targetfile && !S_ISREG(mode))) 55047c478bd9Sstevel@tonic-gate exit(EX_CANTCREAT); 55057c478bd9Sstevel@tonic-gate else 55067c478bd9Sstevel@tonic-gate mode = stb.st_mode; 55077c478bd9Sstevel@tonic-gate 55087c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 55097c478bd9Sstevel@tonic-gate sfflags |= SFF_NOSLINK; 55107c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 55117c478bd9Sstevel@tonic-gate sfflags |= SFF_NOHLINK; 55127c478bd9Sstevel@tonic-gate sfflags &= ~SFF_OPENASROOT; 55137c478bd9Sstevel@tonic-gate f = safefopen(realfile, oflags, mode, sfflags); 55147c478bd9Sstevel@tonic-gate if (f == NULL) 55157c478bd9Sstevel@tonic-gate { 55167c478bd9Sstevel@tonic-gate if (transienterror(errno)) 55177c478bd9Sstevel@tonic-gate { 55187c478bd9Sstevel@tonic-gate usrerr("454 4.3.0 cannot open %s: %s", 55197c478bd9Sstevel@tonic-gate shortenstring(realfile, MAXSHORTSTR), 55207c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55217c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 55227c478bd9Sstevel@tonic-gate } 55237c478bd9Sstevel@tonic-gate else 55247c478bd9Sstevel@tonic-gate { 55257c478bd9Sstevel@tonic-gate usrerr("554 5.3.0 cannot open %s: %s", 55267c478bd9Sstevel@tonic-gate shortenstring(realfile, MAXSHORTSTR), 55277c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55287c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55297c478bd9Sstevel@tonic-gate } 55307c478bd9Sstevel@tonic-gate } 55317c478bd9Sstevel@tonic-gate if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55327c478bd9Sstevel@tonic-gate &stb)) 55337c478bd9Sstevel@tonic-gate { 55347c478bd9Sstevel@tonic-gate syserr("554 5.3.0 file changed after open"); 55357c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55367c478bd9Sstevel@tonic-gate } 55377c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 55387c478bd9Sstevel@tonic-gate { 55397c478bd9Sstevel@tonic-gate syserr("554 5.3.0 cannot fstat %s", 55407c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55417c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55427c478bd9Sstevel@tonic-gate } 55437c478bd9Sstevel@tonic-gate 55447c478bd9Sstevel@tonic-gate curoff = stb.st_size; 55457c478bd9Sstevel@tonic-gate 55467c478bd9Sstevel@tonic-gate if (ev != NULL) 55477c478bd9Sstevel@tonic-gate sm_clrevent(ev); 55487c478bd9Sstevel@tonic-gate 55497c478bd9Sstevel@tonic-gate memset(&mcibuf, '\0', sizeof mcibuf); 55507c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = mailer; 55517c478bd9Sstevel@tonic-gate mcibuf.mci_out = f; 55527c478bd9Sstevel@tonic-gate if (bitnset(M_7BITS, mailer->m_flags)) 55537c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_7BIT; 55547c478bd9Sstevel@tonic-gate 55557c478bd9Sstevel@tonic-gate /* clear out per-message flags from connection structure */ 55567c478bd9Sstevel@tonic-gate mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 55577c478bd9Sstevel@tonic-gate 55587c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 55597c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) && 55607c478bd9Sstevel@tonic-gate bitnset(M_7BITS, mailer->m_flags)) 55617c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_CVT8TO7; 55627c478bd9Sstevel@tonic-gate 55637c478bd9Sstevel@tonic-gate #if MIME7TO8 55647c478bd9Sstevel@tonic-gate if (bitnset(M_MAKE8BIT, mailer->m_flags) && 55657c478bd9Sstevel@tonic-gate !bitset(MCIF_7BIT, mcibuf.mci_flags) && 55667c478bd9Sstevel@tonic-gate (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 55677c478bd9Sstevel@tonic-gate (sm_strcasecmp(p, "quoted-printable") == 0 || 55687c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "base64") == 0) && 55697c478bd9Sstevel@tonic-gate (p = hvalue("Content-Type", e->e_header)) != NULL) 55707c478bd9Sstevel@tonic-gate { 55717c478bd9Sstevel@tonic-gate /* may want to convert 7 -> 8 */ 55727c478bd9Sstevel@tonic-gate /* XXX should really parse it here -- and use a class XXX */ 55737c478bd9Sstevel@tonic-gate if (sm_strncasecmp(p, "text/plain", 10) == 0 && 55747c478bd9Sstevel@tonic-gate (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 55757c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_CVT7TO8; 55767c478bd9Sstevel@tonic-gate } 55777c478bd9Sstevel@tonic-gate #endif /* MIME7TO8 */ 55787c478bd9Sstevel@tonic-gate 5579445f2479Sjbeck if (!putfromline(&mcibuf, e) || 5580445f2479Sjbeck !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) || 5581445f2479Sjbeck !(*e->e_putbody)(&mcibuf, e, NULL) || 5582445f2479Sjbeck !putline("\n", &mcibuf) || 5583445f2479Sjbeck (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 55847c478bd9Sstevel@tonic-gate (SuperSafe != SAFE_NO && 55857c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 5586445f2479Sjbeck sm_io_error(f))) 55877c478bd9Sstevel@tonic-gate { 55887c478bd9Sstevel@tonic-gate setstat(EX_IOERR); 55897c478bd9Sstevel@tonic-gate #if !NOFTRUNCATE 55907c478bd9Sstevel@tonic-gate (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55917c478bd9Sstevel@tonic-gate curoff); 55927c478bd9Sstevel@tonic-gate #endif /* !NOFTRUNCATE */ 55937c478bd9Sstevel@tonic-gate } 55947c478bd9Sstevel@tonic-gate 55957c478bd9Sstevel@tonic-gate /* reset ISUID & ISGID bits for paranoid systems */ 55967c478bd9Sstevel@tonic-gate #if HASFCHMOD 55977c478bd9Sstevel@tonic-gate (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55987c478bd9Sstevel@tonic-gate (MODE_T) mode); 55997c478bd9Sstevel@tonic-gate #else /* HASFCHMOD */ 56007c478bd9Sstevel@tonic-gate (void) chmod(filename, (MODE_T) mode); 56017c478bd9Sstevel@tonic-gate #endif /* HASFCHMOD */ 56027c478bd9Sstevel@tonic-gate if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 56037c478bd9Sstevel@tonic-gate setstat(EX_IOERR); 56047c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 56057c478bd9Sstevel@tonic-gate (void) setuid(RealUid); 56067c478bd9Sstevel@tonic-gate exit(ExitStat); 56077c478bd9Sstevel@tonic-gate /* NOTREACHED */ 56087c478bd9Sstevel@tonic-gate } 56097c478bd9Sstevel@tonic-gate else 56107c478bd9Sstevel@tonic-gate { 56117c478bd9Sstevel@tonic-gate /* parent -- wait for exit status */ 56127c478bd9Sstevel@tonic-gate int st; 56137c478bd9Sstevel@tonic-gate 56147c478bd9Sstevel@tonic-gate st = waitfor(pid); 56157c478bd9Sstevel@tonic-gate if (st == -1) 56167c478bd9Sstevel@tonic-gate { 56177c478bd9Sstevel@tonic-gate syserr("mailfile: %s: wait", mailer->m_name); 56187c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 56197c478bd9Sstevel@tonic-gate } 56207c478bd9Sstevel@tonic-gate if (WIFEXITED(st)) 56217c478bd9Sstevel@tonic-gate { 56227c478bd9Sstevel@tonic-gate errno = 0; 56237c478bd9Sstevel@tonic-gate return (WEXITSTATUS(st)); 56247c478bd9Sstevel@tonic-gate } 56257c478bd9Sstevel@tonic-gate else 56267c478bd9Sstevel@tonic-gate { 56277c478bd9Sstevel@tonic-gate syserr("mailfile: %s: child died on signal %d", 56287c478bd9Sstevel@tonic-gate mailer->m_name, st); 56297c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE; 56307c478bd9Sstevel@tonic-gate } 56317c478bd9Sstevel@tonic-gate /* NOTREACHED */ 56327c478bd9Sstevel@tonic-gate } 56337c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 56347c478bd9Sstevel@tonic-gate } 56357c478bd9Sstevel@tonic-gate 56367c478bd9Sstevel@tonic-gate static void 56377c478bd9Sstevel@tonic-gate mailfiletimeout(ignore) 56387c478bd9Sstevel@tonic-gate int ignore; 56397c478bd9Sstevel@tonic-gate { 56407c478bd9Sstevel@tonic-gate /* 56417c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 56427c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 56437c478bd9Sstevel@tonic-gate ** DOING. 56447c478bd9Sstevel@tonic-gate */ 56457c478bd9Sstevel@tonic-gate 56467c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 56477c478bd9Sstevel@tonic-gate longjmp(CtxMailfileTimeout, 1); 56487c478bd9Sstevel@tonic-gate } 56497c478bd9Sstevel@tonic-gate /* 56507c478bd9Sstevel@tonic-gate ** HOSTSIGNATURE -- return the "signature" for a host. 56517c478bd9Sstevel@tonic-gate ** 56527c478bd9Sstevel@tonic-gate ** The signature describes how we are going to send this -- it 56537c478bd9Sstevel@tonic-gate ** can be just the hostname (for non-Internet hosts) or can be 56547c478bd9Sstevel@tonic-gate ** an ordered list of MX hosts. 56557c478bd9Sstevel@tonic-gate ** 56567c478bd9Sstevel@tonic-gate ** Parameters: 56577c478bd9Sstevel@tonic-gate ** m -- the mailer describing this host. 56587c478bd9Sstevel@tonic-gate ** host -- the host name. 56597c478bd9Sstevel@tonic-gate ** 56607c478bd9Sstevel@tonic-gate ** Returns: 56617c478bd9Sstevel@tonic-gate ** The signature for this host. 56627c478bd9Sstevel@tonic-gate ** 56637c478bd9Sstevel@tonic-gate ** Side Effects: 56647c478bd9Sstevel@tonic-gate ** Can tweak the symbol table. 56657c478bd9Sstevel@tonic-gate */ 56667c478bd9Sstevel@tonic-gate 56677c478bd9Sstevel@tonic-gate #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 56687c478bd9Sstevel@tonic-gate 56697c478bd9Sstevel@tonic-gate char * 56707c478bd9Sstevel@tonic-gate hostsignature(m, host) 56717c478bd9Sstevel@tonic-gate register MAILER *m; 56727c478bd9Sstevel@tonic-gate char *host; 56737c478bd9Sstevel@tonic-gate { 56747c478bd9Sstevel@tonic-gate register char *p; 56757c478bd9Sstevel@tonic-gate register STAB *s; 56767c478bd9Sstevel@tonic-gate time_t now; 56777c478bd9Sstevel@tonic-gate #if NAMED_BIND 56787c478bd9Sstevel@tonic-gate char sep = ':'; 56797c478bd9Sstevel@tonic-gate char prevsep = ':'; 56807c478bd9Sstevel@tonic-gate int i; 56817c478bd9Sstevel@tonic-gate int len; 56827c478bd9Sstevel@tonic-gate int nmx; 56837c478bd9Sstevel@tonic-gate int hl; 56847c478bd9Sstevel@tonic-gate char *hp; 56857c478bd9Sstevel@tonic-gate char *endp; 56867c478bd9Sstevel@tonic-gate int oldoptions = _res.options; 56877c478bd9Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 56887c478bd9Sstevel@tonic-gate unsigned short mxprefs[MAXMXHOSTS + 1]; 56897c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 56907c478bd9Sstevel@tonic-gate 56917c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 56927c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(%s)\n", host); 56937c478bd9Sstevel@tonic-gate 56947c478bd9Sstevel@tonic-gate /* 56957c478bd9Sstevel@tonic-gate ** If local delivery (and not remote), just return a constant. 56967c478bd9Sstevel@tonic-gate */ 56977c478bd9Sstevel@tonic-gate 56987c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) && 56997c478bd9Sstevel@tonic-gate strcmp(m->m_mailer, "[IPC]") != 0 && 57007c478bd9Sstevel@tonic-gate !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 57017c478bd9Sstevel@tonic-gate return "localhost"; 57027c478bd9Sstevel@tonic-gate 57037c478bd9Sstevel@tonic-gate /* an empty host does not have MX records */ 57047c478bd9Sstevel@tonic-gate if (*host == '\0') 57057c478bd9Sstevel@tonic-gate return "_empty_"; 57067c478bd9Sstevel@tonic-gate 57077c478bd9Sstevel@tonic-gate /* 57087c478bd9Sstevel@tonic-gate ** Check to see if this uses IPC -- if not, it can't have MX records. 57097c478bd9Sstevel@tonic-gate */ 57107c478bd9Sstevel@tonic-gate 57117c478bd9Sstevel@tonic-gate if (strcmp(m->m_mailer, "[IPC]") != 0 || 57127c478bd9Sstevel@tonic-gate CurEnv->e_sendmode == SM_DEFER) 57137c478bd9Sstevel@tonic-gate { 57147c478bd9Sstevel@tonic-gate /* just an ordinary mailer or deferred mode */ 57157c478bd9Sstevel@tonic-gate return host; 57167c478bd9Sstevel@tonic-gate } 57177c478bd9Sstevel@tonic-gate #if NETUNIX 57187c478bd9Sstevel@tonic-gate else if (m->m_argv[0] != NULL && 57197c478bd9Sstevel@tonic-gate strcmp(m->m_argv[0], "FILE") == 0) 57207c478bd9Sstevel@tonic-gate { 57217c478bd9Sstevel@tonic-gate /* rendezvous in the file system, no MX records */ 57227c478bd9Sstevel@tonic-gate return host; 57237c478bd9Sstevel@tonic-gate } 57247c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 57257c478bd9Sstevel@tonic-gate 57267c478bd9Sstevel@tonic-gate /* 57277c478bd9Sstevel@tonic-gate ** Look it up in the symbol table. 57287c478bd9Sstevel@tonic-gate */ 57297c478bd9Sstevel@tonic-gate 57307c478bd9Sstevel@tonic-gate now = curtime(); 57317c478bd9Sstevel@tonic-gate s = stab(host, ST_HOSTSIG, ST_ENTER); 57327c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 57337c478bd9Sstevel@tonic-gate { 57347c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_exp >= now) 57357c478bd9Sstevel@tonic-gate { 57367c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 57377c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 57387c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig); 57397c478bd9Sstevel@tonic-gate return s->s_hostsig.hs_sig; 57407c478bd9Sstevel@tonic-gate } 57417c478bd9Sstevel@tonic-gate 57427c478bd9Sstevel@tonic-gate /* signature is expired: clear it */ 57437c478bd9Sstevel@tonic-gate sm_free(s->s_hostsig.hs_sig); 57447c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = NULL; 57457c478bd9Sstevel@tonic-gate } 57467c478bd9Sstevel@tonic-gate 57477c478bd9Sstevel@tonic-gate /* set default TTL */ 57487c478bd9Sstevel@tonic-gate s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 57497c478bd9Sstevel@tonic-gate 57507c478bd9Sstevel@tonic-gate /* 57517c478bd9Sstevel@tonic-gate ** Not already there or expired -- create a signature. 57527c478bd9Sstevel@tonic-gate */ 57537c478bd9Sstevel@tonic-gate 57547c478bd9Sstevel@tonic-gate #if NAMED_BIND 57557c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 57567c478bd9Sstevel@tonic-gate _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 57577c478bd9Sstevel@tonic-gate 57587c478bd9Sstevel@tonic-gate for (hp = host; hp != NULL; hp = endp) 57597c478bd9Sstevel@tonic-gate { 57607c478bd9Sstevel@tonic-gate #if NETINET6 57617c478bd9Sstevel@tonic-gate if (*hp == '[') 57627c478bd9Sstevel@tonic-gate { 57637c478bd9Sstevel@tonic-gate endp = strchr(hp + 1, ']'); 57647c478bd9Sstevel@tonic-gate if (endp != NULL) 57657c478bd9Sstevel@tonic-gate endp = strpbrk(endp + 1, ":,"); 57667c478bd9Sstevel@tonic-gate } 57677c478bd9Sstevel@tonic-gate else 57687c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 57697c478bd9Sstevel@tonic-gate #else /* NETINET6 */ 57707c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 57717c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 57727c478bd9Sstevel@tonic-gate if (endp != NULL) 57737c478bd9Sstevel@tonic-gate { 57747c478bd9Sstevel@tonic-gate sep = *endp; 57757c478bd9Sstevel@tonic-gate *endp = '\0'; 57767c478bd9Sstevel@tonic-gate } 57777c478bd9Sstevel@tonic-gate 57787c478bd9Sstevel@tonic-gate if (bitnset(M_NOMX, m->m_flags)) 57797c478bd9Sstevel@tonic-gate { 57807c478bd9Sstevel@tonic-gate /* skip MX lookups */ 57817c478bd9Sstevel@tonic-gate nmx = 1; 57827c478bd9Sstevel@tonic-gate mxhosts[0] = hp; 57837c478bd9Sstevel@tonic-gate } 57847c478bd9Sstevel@tonic-gate else 57857c478bd9Sstevel@tonic-gate { 57867c478bd9Sstevel@tonic-gate auto int rcode; 57877c478bd9Sstevel@tonic-gate int ttl; 57887c478bd9Sstevel@tonic-gate 57897c478bd9Sstevel@tonic-gate nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true, 57907c478bd9Sstevel@tonic-gate &ttl); 57917c478bd9Sstevel@tonic-gate if (nmx <= 0) 57927c478bd9Sstevel@tonic-gate { 57937c478bd9Sstevel@tonic-gate int save_errno; 57947c478bd9Sstevel@tonic-gate register MCI *mci; 57957c478bd9Sstevel@tonic-gate 57967c478bd9Sstevel@tonic-gate /* update the connection info for this host */ 57977c478bd9Sstevel@tonic-gate save_errno = errno; 57987c478bd9Sstevel@tonic-gate mci = mci_get(hp, m); 57997c478bd9Sstevel@tonic-gate mci->mci_errno = save_errno; 58007c478bd9Sstevel@tonic-gate mci->mci_herrno = h_errno; 58017c478bd9Sstevel@tonic-gate mci->mci_lastuse = now; 58027c478bd9Sstevel@tonic-gate if (rcode == EX_NOHOST) 58037c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, "5.1.2", 58047c478bd9Sstevel@tonic-gate "550 Host unknown"); 58057c478bd9Sstevel@tonic-gate else 58067c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, NULL, NULL); 58077c478bd9Sstevel@tonic-gate 58087c478bd9Sstevel@tonic-gate /* use the original host name as signature */ 58097c478bd9Sstevel@tonic-gate nmx = 1; 58107c478bd9Sstevel@tonic-gate mxhosts[0] = hp; 58117c478bd9Sstevel@tonic-gate } 58127c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 58137c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 58147c478bd9Sstevel@tonic-gate nmx, mxhosts[0]); 58157c478bd9Sstevel@tonic-gate 58167c478bd9Sstevel@tonic-gate /* 58177c478bd9Sstevel@tonic-gate ** Set new TTL: we use only one! 58187c478bd9Sstevel@tonic-gate ** We could try to use the minimum instead. 58197c478bd9Sstevel@tonic-gate */ 58207c478bd9Sstevel@tonic-gate 58217c478bd9Sstevel@tonic-gate s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 58227c478bd9Sstevel@tonic-gate } 58237c478bd9Sstevel@tonic-gate 58247c478bd9Sstevel@tonic-gate len = 0; 58257c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 58267c478bd9Sstevel@tonic-gate len += strlen(mxhosts[i]) + 1; 58277c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 58287c478bd9Sstevel@tonic-gate len += strlen(s->s_hostsig.hs_sig) + 1; 58297c478bd9Sstevel@tonic-gate if (len < 0 || len >= MAXHOSTSIGNATURE) 58307c478bd9Sstevel@tonic-gate { 58317c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 58327c478bd9Sstevel@tonic-gate host, MAXHOSTSIGNATURE, len); 58337c478bd9Sstevel@tonic-gate len = MAXHOSTSIGNATURE; 58347c478bd9Sstevel@tonic-gate } 58357c478bd9Sstevel@tonic-gate p = sm_pmalloc_x(len); 58367c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 58377c478bd9Sstevel@tonic-gate { 58387c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 58397c478bd9Sstevel@tonic-gate sm_free(s->s_hostsig.hs_sig); /* XXX */ 58407c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = p; 58417c478bd9Sstevel@tonic-gate hl = strlen(p); 58427c478bd9Sstevel@tonic-gate p += hl; 58437c478bd9Sstevel@tonic-gate *p++ = prevsep; 58447c478bd9Sstevel@tonic-gate len -= hl + 1; 58457c478bd9Sstevel@tonic-gate } 58467c478bd9Sstevel@tonic-gate else 58477c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = p; 58487c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 58497c478bd9Sstevel@tonic-gate { 58507c478bd9Sstevel@tonic-gate hl = strlen(mxhosts[i]); 58517c478bd9Sstevel@tonic-gate if (len - 1 < hl || len <= 1) 58527c478bd9Sstevel@tonic-gate { 58537c478bd9Sstevel@tonic-gate /* force to drop out of outer loop */ 58547c478bd9Sstevel@tonic-gate len = -1; 58557c478bd9Sstevel@tonic-gate break; 58567c478bd9Sstevel@tonic-gate } 58577c478bd9Sstevel@tonic-gate if (i != 0) 58587c478bd9Sstevel@tonic-gate { 58597c478bd9Sstevel@tonic-gate if (mxprefs[i] == mxprefs[i - 1]) 58607c478bd9Sstevel@tonic-gate *p++ = ','; 58617c478bd9Sstevel@tonic-gate else 58627c478bd9Sstevel@tonic-gate *p++ = ':'; 58637c478bd9Sstevel@tonic-gate len--; 58647c478bd9Sstevel@tonic-gate } 58657c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, mxhosts[i], len); 58667c478bd9Sstevel@tonic-gate p += hl; 58677c478bd9Sstevel@tonic-gate len -= hl; 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate 58707c478bd9Sstevel@tonic-gate /* 58717c478bd9Sstevel@tonic-gate ** break out of loop if len exceeded MAXHOSTSIGNATURE 58727c478bd9Sstevel@tonic-gate ** because we won't have more space for further hosts 58737c478bd9Sstevel@tonic-gate ** anyway (separated by : in the .cf file). 58747c478bd9Sstevel@tonic-gate */ 58757c478bd9Sstevel@tonic-gate 58767c478bd9Sstevel@tonic-gate if (len < 0) 58777c478bd9Sstevel@tonic-gate break; 58787c478bd9Sstevel@tonic-gate if (endp != NULL) 58797c478bd9Sstevel@tonic-gate *endp++ = sep; 58807c478bd9Sstevel@tonic-gate prevsep = sep; 58817c478bd9Sstevel@tonic-gate } 58827c478bd9Sstevel@tonic-gate makelower(s->s_hostsig.hs_sig); 58837c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 58847c478bd9Sstevel@tonic-gate _res.options = oldoptions; 58857c478bd9Sstevel@tonic-gate #else /* NAMED_BIND */ 58867c478bd9Sstevel@tonic-gate /* not using BIND -- the signature is just the host name */ 58877c478bd9Sstevel@tonic-gate /* 58887c478bd9Sstevel@tonic-gate ** 'host' points to storage that will be freed after we are 58897c478bd9Sstevel@tonic-gate ** done processing the current envelope, so we copy it. 58907c478bd9Sstevel@tonic-gate */ 58917c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = sm_pstrdup_x(host); 58927c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 58937c478bd9Sstevel@tonic-gate if (tTd(17, 1)) 58947c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 58957c478bd9Sstevel@tonic-gate return s->s_hostsig.hs_sig; 58967c478bd9Sstevel@tonic-gate } 58977c478bd9Sstevel@tonic-gate /* 58987c478bd9Sstevel@tonic-gate ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 58997c478bd9Sstevel@tonic-gate ** 59007c478bd9Sstevel@tonic-gate ** The signature describes how we are going to send this -- it 59017c478bd9Sstevel@tonic-gate ** can be just the hostname (for non-Internet hosts) or can be 59027c478bd9Sstevel@tonic-gate ** an ordered list of MX hosts which must be randomized for equal 59037c478bd9Sstevel@tonic-gate ** MX preference values. 59047c478bd9Sstevel@tonic-gate ** 59057c478bd9Sstevel@tonic-gate ** Parameters: 59067c478bd9Sstevel@tonic-gate ** sig -- the host signature. 59077c478bd9Sstevel@tonic-gate ** mxhosts -- array to populate. 59087c478bd9Sstevel@tonic-gate ** mailer -- mailer. 59097c478bd9Sstevel@tonic-gate ** 59107c478bd9Sstevel@tonic-gate ** Returns: 59117c478bd9Sstevel@tonic-gate ** The number of hosts inserted into mxhosts array. 59127c478bd9Sstevel@tonic-gate ** 59137c478bd9Sstevel@tonic-gate ** Side Effects: 59147c478bd9Sstevel@tonic-gate ** Randomizes equal MX preference hosts in mxhosts. 59157c478bd9Sstevel@tonic-gate */ 59167c478bd9Sstevel@tonic-gate 59177c478bd9Sstevel@tonic-gate static int 59187c478bd9Sstevel@tonic-gate parse_hostsignature(sig, mxhosts, mailer) 59197c478bd9Sstevel@tonic-gate char *sig; 59207c478bd9Sstevel@tonic-gate char **mxhosts; 59217c478bd9Sstevel@tonic-gate MAILER *mailer; 59227c478bd9Sstevel@tonic-gate { 59237c478bd9Sstevel@tonic-gate unsigned short curpref = 0; 59247c478bd9Sstevel@tonic-gate int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 59257c478bd9Sstevel@tonic-gate char *hp, *endp; 59267c478bd9Sstevel@tonic-gate unsigned short prefer[MAXMXHOSTS]; 59277c478bd9Sstevel@tonic-gate long rndm[MAXMXHOSTS]; 59287c478bd9Sstevel@tonic-gate 59297c478bd9Sstevel@tonic-gate for (hp = sig; hp != NULL; hp = endp) 59307c478bd9Sstevel@tonic-gate { 59317c478bd9Sstevel@tonic-gate char sep = ':'; 59327c478bd9Sstevel@tonic-gate 59337c478bd9Sstevel@tonic-gate #if NETINET6 59347c478bd9Sstevel@tonic-gate if (*hp == '[') 59357c478bd9Sstevel@tonic-gate { 59367c478bd9Sstevel@tonic-gate endp = strchr(hp + 1, ']'); 59377c478bd9Sstevel@tonic-gate if (endp != NULL) 59387c478bd9Sstevel@tonic-gate endp = strpbrk(endp + 1, ":,"); 59397c478bd9Sstevel@tonic-gate } 59407c478bd9Sstevel@tonic-gate else 59417c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 59427c478bd9Sstevel@tonic-gate #else /* NETINET6 */ 59437c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 59447c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 59457c478bd9Sstevel@tonic-gate if (endp != NULL) 59467c478bd9Sstevel@tonic-gate { 59477c478bd9Sstevel@tonic-gate sep = *endp; 59487c478bd9Sstevel@tonic-gate *endp = '\0'; 59497c478bd9Sstevel@tonic-gate } 59507c478bd9Sstevel@tonic-gate 59517c478bd9Sstevel@tonic-gate mxhosts[nmx] = hp; 59527c478bd9Sstevel@tonic-gate prefer[nmx] = curpref; 59537c478bd9Sstevel@tonic-gate if (mci_match(hp, mailer)) 59547c478bd9Sstevel@tonic-gate rndm[nmx] = 0; 59557c478bd9Sstevel@tonic-gate else 59567c478bd9Sstevel@tonic-gate rndm[nmx] = get_random(); 59577c478bd9Sstevel@tonic-gate 59587c478bd9Sstevel@tonic-gate if (endp != NULL) 59597c478bd9Sstevel@tonic-gate { 59607c478bd9Sstevel@tonic-gate /* 59617c478bd9Sstevel@tonic-gate ** Since we don't have the original MX prefs, 59627c478bd9Sstevel@tonic-gate ** make our own. If the separator is a ':', that 59637c478bd9Sstevel@tonic-gate ** means the preference for the next host will be 59647c478bd9Sstevel@tonic-gate ** higher than this one, so simply increment curpref. 59657c478bd9Sstevel@tonic-gate */ 59667c478bd9Sstevel@tonic-gate 59677c478bd9Sstevel@tonic-gate if (sep == ':') 59687c478bd9Sstevel@tonic-gate curpref++; 59697c478bd9Sstevel@tonic-gate 59707c478bd9Sstevel@tonic-gate *endp++ = sep; 59717c478bd9Sstevel@tonic-gate } 59727c478bd9Sstevel@tonic-gate if (++nmx >= MAXMXHOSTS) 59737c478bd9Sstevel@tonic-gate break; 59747c478bd9Sstevel@tonic-gate } 59757c478bd9Sstevel@tonic-gate 59767c478bd9Sstevel@tonic-gate /* sort the records using the random factor for equal preferences */ 59777c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 59787c478bd9Sstevel@tonic-gate { 59797c478bd9Sstevel@tonic-gate for (j = i + 1; j < nmx; j++) 59807c478bd9Sstevel@tonic-gate { 59817c478bd9Sstevel@tonic-gate /* 59827c478bd9Sstevel@tonic-gate ** List is already sorted by MX preference, only 59837c478bd9Sstevel@tonic-gate ** need to look for equal preference MX records 59847c478bd9Sstevel@tonic-gate */ 59857c478bd9Sstevel@tonic-gate 59867c478bd9Sstevel@tonic-gate if (prefer[i] < prefer[j]) 59877c478bd9Sstevel@tonic-gate break; 59887c478bd9Sstevel@tonic-gate 59897c478bd9Sstevel@tonic-gate if (prefer[i] > prefer[j] || 59907c478bd9Sstevel@tonic-gate (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 59917c478bd9Sstevel@tonic-gate { 59927c478bd9Sstevel@tonic-gate register unsigned short tempp; 59937c478bd9Sstevel@tonic-gate register long tempr; 59947c478bd9Sstevel@tonic-gate register char *temp1; 59957c478bd9Sstevel@tonic-gate 59967c478bd9Sstevel@tonic-gate tempp = prefer[i]; 59977c478bd9Sstevel@tonic-gate prefer[i] = prefer[j]; 59987c478bd9Sstevel@tonic-gate prefer[j] = tempp; 59997c478bd9Sstevel@tonic-gate temp1 = mxhosts[i]; 60007c478bd9Sstevel@tonic-gate mxhosts[i] = mxhosts[j]; 60017c478bd9Sstevel@tonic-gate mxhosts[j] = temp1; 60027c478bd9Sstevel@tonic-gate tempr = rndm[i]; 60037c478bd9Sstevel@tonic-gate rndm[i] = rndm[j]; 60047c478bd9Sstevel@tonic-gate rndm[j] = tempr; 60057c478bd9Sstevel@tonic-gate } 60067c478bd9Sstevel@tonic-gate } 60077c478bd9Sstevel@tonic-gate } 60087c478bd9Sstevel@tonic-gate return nmx; 60097c478bd9Sstevel@tonic-gate } 60107c478bd9Sstevel@tonic-gate 60117c478bd9Sstevel@tonic-gate # if STARTTLS 60127c478bd9Sstevel@tonic-gate static SSL_CTX *clt_ctx = NULL; 60137c478bd9Sstevel@tonic-gate static bool tls_ok_clt = true; 60147c478bd9Sstevel@tonic-gate 60157c478bd9Sstevel@tonic-gate /* 60167c478bd9Sstevel@tonic-gate ** SETCLTTLS -- client side TLS: allow/disallow. 60177c478bd9Sstevel@tonic-gate ** 60187c478bd9Sstevel@tonic-gate ** Parameters: 60197c478bd9Sstevel@tonic-gate ** tls_ok -- should tls be done? 60207c478bd9Sstevel@tonic-gate ** 60217c478bd9Sstevel@tonic-gate ** Returns: 60227c478bd9Sstevel@tonic-gate ** none. 60237c478bd9Sstevel@tonic-gate ** 60247c478bd9Sstevel@tonic-gate ** Side Effects: 60257c478bd9Sstevel@tonic-gate ** sets tls_ok_clt (static variable in this module) 60267c478bd9Sstevel@tonic-gate */ 60277c478bd9Sstevel@tonic-gate 60287c478bd9Sstevel@tonic-gate void 60297c478bd9Sstevel@tonic-gate setclttls(tls_ok) 60307c478bd9Sstevel@tonic-gate bool tls_ok; 60317c478bd9Sstevel@tonic-gate { 60327c478bd9Sstevel@tonic-gate tls_ok_clt = tls_ok; 60337c478bd9Sstevel@tonic-gate return; 60347c478bd9Sstevel@tonic-gate } 60357c478bd9Sstevel@tonic-gate /* 60367c478bd9Sstevel@tonic-gate ** INITCLTTLS -- initialize client side TLS 60377c478bd9Sstevel@tonic-gate ** 60387c478bd9Sstevel@tonic-gate ** Parameters: 60397c478bd9Sstevel@tonic-gate ** tls_ok -- should tls initialization be done? 60407c478bd9Sstevel@tonic-gate ** 60417c478bd9Sstevel@tonic-gate ** Returns: 60427c478bd9Sstevel@tonic-gate ** succeeded? 60437c478bd9Sstevel@tonic-gate ** 60447c478bd9Sstevel@tonic-gate ** Side Effects: 60457c478bd9Sstevel@tonic-gate ** sets tls_ok_clt (static variable in this module) 60467c478bd9Sstevel@tonic-gate */ 60477c478bd9Sstevel@tonic-gate 60487c478bd9Sstevel@tonic-gate bool 60497c478bd9Sstevel@tonic-gate initclttls(tls_ok) 60507c478bd9Sstevel@tonic-gate bool tls_ok; 60517c478bd9Sstevel@tonic-gate { 60527c478bd9Sstevel@tonic-gate if (!tls_ok_clt) 60537c478bd9Sstevel@tonic-gate return false; 60547c478bd9Sstevel@tonic-gate tls_ok_clt = tls_ok; 60557c478bd9Sstevel@tonic-gate if (!tls_ok_clt) 60567c478bd9Sstevel@tonic-gate return false; 60577c478bd9Sstevel@tonic-gate if (clt_ctx != NULL) 60587c478bd9Sstevel@tonic-gate return true; /* already done */ 60597c478bd9Sstevel@tonic-gate tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCertFile, 60607c478bd9Sstevel@tonic-gate CltKeyFile, CACertPath, CACertFile, DHParams); 60617c478bd9Sstevel@tonic-gate return tls_ok_clt; 60627c478bd9Sstevel@tonic-gate } 60637c478bd9Sstevel@tonic-gate 60647c478bd9Sstevel@tonic-gate /* 60657c478bd9Sstevel@tonic-gate ** STARTTLS -- try to start secure connection (client side) 60667c478bd9Sstevel@tonic-gate ** 60677c478bd9Sstevel@tonic-gate ** Parameters: 60687c478bd9Sstevel@tonic-gate ** m -- the mailer. 60697c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 60707c478bd9Sstevel@tonic-gate ** e -- the envelope. 60717c478bd9Sstevel@tonic-gate ** 60727c478bd9Sstevel@tonic-gate ** Returns: 60737c478bd9Sstevel@tonic-gate ** success? 60747c478bd9Sstevel@tonic-gate ** (maybe this should be some other code than EX_ 60757c478bd9Sstevel@tonic-gate ** that denotes which stage failed.) 60767c478bd9Sstevel@tonic-gate */ 60777c478bd9Sstevel@tonic-gate 60787c478bd9Sstevel@tonic-gate static int 60797c478bd9Sstevel@tonic-gate starttls(m, mci, e) 60807c478bd9Sstevel@tonic-gate MAILER *m; 60817c478bd9Sstevel@tonic-gate MCI *mci; 60827c478bd9Sstevel@tonic-gate ENVELOPE *e; 60837c478bd9Sstevel@tonic-gate { 60847c478bd9Sstevel@tonic-gate int smtpresult; 60857c478bd9Sstevel@tonic-gate int result = 0; 60867c478bd9Sstevel@tonic-gate int rfd, wfd; 60877c478bd9Sstevel@tonic-gate SSL *clt_ssl = NULL; 60887c478bd9Sstevel@tonic-gate time_t tlsstart; 60897c478bd9Sstevel@tonic-gate 60907c478bd9Sstevel@tonic-gate if (clt_ctx == NULL && !initclttls(true)) 60917c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 60927c478bd9Sstevel@tonic-gate smtpmessage("STARTTLS", m, mci); 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate /* get the reply */ 60957c478bd9Sstevel@tonic-gate smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL, 60967c478bd9Sstevel@tonic-gate XS_STARTTLS); 60977c478bd9Sstevel@tonic-gate 60987c478bd9Sstevel@tonic-gate /* check return code from server */ 6099445f2479Sjbeck if (REPLYTYPE(smtpresult) == 4) 61007c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 61017c478bd9Sstevel@tonic-gate if (smtpresult == 501) 61027c478bd9Sstevel@tonic-gate return EX_USAGE; 61037c478bd9Sstevel@tonic-gate if (smtpresult == -1) 61047c478bd9Sstevel@tonic-gate return smtpresult; 6105445f2479Sjbeck 6106445f2479Sjbeck /* not an expected reply but we have to deal with it */ 6107445f2479Sjbeck if (REPLYTYPE(smtpresult) == 5) 6108445f2479Sjbeck return EX_UNAVAILABLE; 61097c478bd9Sstevel@tonic-gate if (smtpresult != 220) 61107c478bd9Sstevel@tonic-gate return EX_PROTOCOL; 61117c478bd9Sstevel@tonic-gate 61127c478bd9Sstevel@tonic-gate if (LogLevel > 13) 61137c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 61147c478bd9Sstevel@tonic-gate 61157c478bd9Sstevel@tonic-gate /* start connection */ 61167c478bd9Sstevel@tonic-gate if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 61177c478bd9Sstevel@tonic-gate { 61187c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61197c478bd9Sstevel@tonic-gate { 61207c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 61217c478bd9Sstevel@tonic-gate "STARTTLS=client, error: SSL_new failed"); 61227c478bd9Sstevel@tonic-gate if (LogLevel > 9) 61237c478bd9Sstevel@tonic-gate tlslogerr("client"); 61247c478bd9Sstevel@tonic-gate } 61257c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61267c478bd9Sstevel@tonic-gate } 61277c478bd9Sstevel@tonic-gate 61287c478bd9Sstevel@tonic-gate rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 61297c478bd9Sstevel@tonic-gate wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 61307c478bd9Sstevel@tonic-gate 61317c478bd9Sstevel@tonic-gate /* SSL_clear(clt_ssl); ? */ 61327c478bd9Sstevel@tonic-gate if (rfd < 0 || wfd < 0 || 61337c478bd9Sstevel@tonic-gate (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 61347c478bd9Sstevel@tonic-gate (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 61357c478bd9Sstevel@tonic-gate { 61367c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61377c478bd9Sstevel@tonic-gate { 61387c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 61397c478bd9Sstevel@tonic-gate "STARTTLS=client, error: SSL_set_xfd failed=%d", 61407c478bd9Sstevel@tonic-gate result); 61417c478bd9Sstevel@tonic-gate if (LogLevel > 9) 61427c478bd9Sstevel@tonic-gate tlslogerr("client"); 61437c478bd9Sstevel@tonic-gate } 61447c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61457c478bd9Sstevel@tonic-gate } 61467c478bd9Sstevel@tonic-gate SSL_set_connect_state(clt_ssl); 61477c478bd9Sstevel@tonic-gate tlsstart = curtime(); 61487c478bd9Sstevel@tonic-gate 61497c478bd9Sstevel@tonic-gate ssl_retry: 61507c478bd9Sstevel@tonic-gate if ((result = SSL_connect(clt_ssl)) <= 0) 61517c478bd9Sstevel@tonic-gate { 6152445f2479Sjbeck int i, ssl_err; 61537c478bd9Sstevel@tonic-gate 6154445f2479Sjbeck ssl_err = SSL_get_error(clt_ssl, result); 6155445f2479Sjbeck i = tls_retry(clt_ssl, rfd, wfd, tlsstart, 6156445f2479Sjbeck TimeOuts.to_starttls, ssl_err, "client"); 6157445f2479Sjbeck if (i > 0) 6158445f2479Sjbeck goto ssl_retry; 61597c478bd9Sstevel@tonic-gate 61607c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61617c478bd9Sstevel@tonic-gate { 6162445f2479Sjbeck sm_syslog(LOG_WARNING, NOQID, 6163445f2479Sjbeck "STARTTLS=client, error: connect failed=%d, SSL_error=%d, errno=%d, retry=%d", 6164445f2479Sjbeck result, ssl_err, errno, i); 61657c478bd9Sstevel@tonic-gate if (LogLevel > 8) 61667c478bd9Sstevel@tonic-gate tlslogerr("client"); 61677c478bd9Sstevel@tonic-gate } 61687c478bd9Sstevel@tonic-gate 61697c478bd9Sstevel@tonic-gate SSL_free(clt_ssl); 61707c478bd9Sstevel@tonic-gate clt_ssl = NULL; 61717c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61727c478bd9Sstevel@tonic-gate } 61737c478bd9Sstevel@tonic-gate mci->mci_ssl = clt_ssl; 61747c478bd9Sstevel@tonic-gate result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 61757c478bd9Sstevel@tonic-gate &mci->mci_macro, true); 61767c478bd9Sstevel@tonic-gate 61777c478bd9Sstevel@tonic-gate /* switch to use TLS... */ 61787c478bd9Sstevel@tonic-gate if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 61797c478bd9Sstevel@tonic-gate return EX_OK; 61807c478bd9Sstevel@tonic-gate 61817c478bd9Sstevel@tonic-gate /* failure */ 61827c478bd9Sstevel@tonic-gate SSL_free(clt_ssl); 61837c478bd9Sstevel@tonic-gate clt_ssl = NULL; 61847c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61857c478bd9Sstevel@tonic-gate } 61867c478bd9Sstevel@tonic-gate /* 61877c478bd9Sstevel@tonic-gate ** ENDTLSCLT -- shutdown secure connection (client side) 61887c478bd9Sstevel@tonic-gate ** 61897c478bd9Sstevel@tonic-gate ** Parameters: 61907c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 61917c478bd9Sstevel@tonic-gate ** 61927c478bd9Sstevel@tonic-gate ** Returns: 61937c478bd9Sstevel@tonic-gate ** success? 61947c478bd9Sstevel@tonic-gate */ 61957c478bd9Sstevel@tonic-gate 61967c478bd9Sstevel@tonic-gate static int 61977c478bd9Sstevel@tonic-gate endtlsclt(mci) 61987c478bd9Sstevel@tonic-gate MCI *mci; 61997c478bd9Sstevel@tonic-gate { 62007c478bd9Sstevel@tonic-gate int r; 62017c478bd9Sstevel@tonic-gate 62027c478bd9Sstevel@tonic-gate if (!bitset(MCIF_TLSACT, mci->mci_flags)) 62037c478bd9Sstevel@tonic-gate return EX_OK; 62047c478bd9Sstevel@tonic-gate r = endtls(mci->mci_ssl, "client"); 62057c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_TLSACT; 62067c478bd9Sstevel@tonic-gate return r; 62077c478bd9Sstevel@tonic-gate } 62087c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 62097c478bd9Sstevel@tonic-gate # if STARTTLS || SASL 62107c478bd9Sstevel@tonic-gate /* 62117c478bd9Sstevel@tonic-gate ** ISCLTFLGSET -- check whether client flag is set. 62127c478bd9Sstevel@tonic-gate ** 62137c478bd9Sstevel@tonic-gate ** Parameters: 62147c478bd9Sstevel@tonic-gate ** e -- envelope. 62157c478bd9Sstevel@tonic-gate ** flag -- flag to check in {client_flags} 62167c478bd9Sstevel@tonic-gate ** 62177c478bd9Sstevel@tonic-gate ** Returns: 62187c478bd9Sstevel@tonic-gate ** true iff flag is set. 62197c478bd9Sstevel@tonic-gate */ 62207c478bd9Sstevel@tonic-gate 62217c478bd9Sstevel@tonic-gate static bool 62227c478bd9Sstevel@tonic-gate iscltflgset(e, flag) 62237c478bd9Sstevel@tonic-gate ENVELOPE *e; 62247c478bd9Sstevel@tonic-gate int flag; 62257c478bd9Sstevel@tonic-gate { 62267c478bd9Sstevel@tonic-gate char *p; 62277c478bd9Sstevel@tonic-gate 62287c478bd9Sstevel@tonic-gate p = macvalue(macid("{client_flags}"), e); 62297c478bd9Sstevel@tonic-gate if (p == NULL) 62307c478bd9Sstevel@tonic-gate return false; 62317c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 62327c478bd9Sstevel@tonic-gate { 62337c478bd9Sstevel@tonic-gate /* look for just this one flag */ 62347c478bd9Sstevel@tonic-gate if (*p == (char) flag) 62357c478bd9Sstevel@tonic-gate return true; 62367c478bd9Sstevel@tonic-gate } 62377c478bd9Sstevel@tonic-gate return false; 62387c478bd9Sstevel@tonic-gate } 62397c478bd9Sstevel@tonic-gate # endif /* STARTTLS || SASL */ 6240