17c478bd9Sstevel@tonic-gate /* 2*445f2479Sjbeck * 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*445f2479Sjbeck SM_RCSID("@(#)$Id: deliver.c,v 8.1000 2006/03/02 01:37:39 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; 2997*445f2479Sjbeck case EX_UNAVAILABLE: 2998*445f2479Sjbeck s = "NONE"; 2999*445f2479Sjbeck 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 { 31327c478bd9Sstevel@tonic-gate /* 31337c478bd9Sstevel@tonic-gate ** Convert I/O layer to use SASL. 31347c478bd9Sstevel@tonic-gate ** If the call fails, the connection 31357c478bd9Sstevel@tonic-gate ** is aborted. 31367c478bd9Sstevel@tonic-gate */ 31377c478bd9Sstevel@tonic-gate 31387c478bd9Sstevel@tonic-gate if (sfdcsasl(&mci->mci_in, 31397c478bd9Sstevel@tonic-gate &mci->mci_out, 31407c478bd9Sstevel@tonic-gate mci->mci_conn) == 0) 31417c478bd9Sstevel@tonic-gate { 31427c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_EXTENS; 31437c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTHACT| 31447c478bd9Sstevel@tonic-gate MCIF_ONLY_EHLO; 31457c478bd9Sstevel@tonic-gate goto reconnect; 31467c478bd9Sstevel@tonic-gate } 31477c478bd9Sstevel@tonic-gate syserr("AUTH TLS switch failed in client"); 31487c478bd9Sstevel@tonic-gate } 31497c478bd9Sstevel@tonic-gate /* else? XXX */ 31507c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTHACT; 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate } 31537c478bd9Sstevel@tonic-gate else if (ret == EX_TEMPFAIL) 31547c478bd9Sstevel@tonic-gate { 31557c478bd9Sstevel@tonic-gate if (LogLevel > 8) 31567c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 31577c478bd9Sstevel@tonic-gate "AUTH=client, relay=%.100s, temporary failure, connection abort", 31587c478bd9Sstevel@tonic-gate mci->mci_host); 31597c478bd9Sstevel@tonic-gate smtpquit(m, mci, e); 31607c478bd9Sstevel@tonic-gate 31617c478bd9Sstevel@tonic-gate /* avoid bogus error msg */ 31627c478bd9Sstevel@tonic-gate mci->mci_errno = 0; 31637c478bd9Sstevel@tonic-gate rcode = EX_TEMPFAIL; 31647c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, "4.3.0", p); 31657c478bd9Sstevel@tonic-gate 31667c478bd9Sstevel@tonic-gate /* 31677c478bd9Sstevel@tonic-gate ** hack to get the error message into 31687c478bd9Sstevel@tonic-gate ** the envelope (done in giveresponse()) 31697c478bd9Sstevel@tonic-gate */ 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate (void) sm_strlcpy(SmtpError, 31727c478bd9Sstevel@tonic-gate "Temporary AUTH failure", 31737c478bd9Sstevel@tonic-gate sizeof SmtpError); 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate } 31767c478bd9Sstevel@tonic-gate # endif /* SASL */ 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate do_transfer: 31817c478bd9Sstevel@tonic-gate /* clear out per-message flags from connection structure */ 31827c478bd9Sstevel@tonic-gate mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 31837c478bd9Sstevel@tonic-gate 31847c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 31857c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) && 31867c478bd9Sstevel@tonic-gate bitnset(M_7BITS, m->m_flags)) 31877c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CVT8TO7; 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate #if MIME7TO8 31907c478bd9Sstevel@tonic-gate if (bitnset(M_MAKE8BIT, m->m_flags) && 31917c478bd9Sstevel@tonic-gate !bitset(MCIF_7BIT, mci->mci_flags) && 31927c478bd9Sstevel@tonic-gate (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 31937c478bd9Sstevel@tonic-gate (sm_strcasecmp(p, "quoted-printable") == 0 || 31947c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "base64") == 0) && 31957c478bd9Sstevel@tonic-gate (p = hvalue("Content-Type", e->e_header)) != NULL) 31967c478bd9Sstevel@tonic-gate { 31977c478bd9Sstevel@tonic-gate /* may want to convert 7 -> 8 */ 31987c478bd9Sstevel@tonic-gate /* XXX should really parse it here -- and use a class XXX */ 31997c478bd9Sstevel@tonic-gate if (sm_strncasecmp(p, "text/plain", 10) == 0 && 32007c478bd9Sstevel@tonic-gate (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 32017c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CVT7TO8; 32027c478bd9Sstevel@tonic-gate } 32037c478bd9Sstevel@tonic-gate #endif /* MIME7TO8 */ 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 32067c478bd9Sstevel@tonic-gate { 32077c478bd9Sstevel@tonic-gate sm_dprintf("openmailer: "); 32087c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false); 32097c478bd9Sstevel@tonic-gate } 32107c478bd9Sstevel@tonic-gate 32117c478bd9Sstevel@tonic-gate #if _FFR_CLIENT_SIZE 32127c478bd9Sstevel@tonic-gate /* 32137c478bd9Sstevel@tonic-gate ** See if we know the maximum size and 32147c478bd9Sstevel@tonic-gate ** abort if the message is too big. 32157c478bd9Sstevel@tonic-gate ** 32167c478bd9Sstevel@tonic-gate ** NOTE: _FFR_CLIENT_SIZE is untested. 32177c478bd9Sstevel@tonic-gate */ 32187c478bd9Sstevel@tonic-gate 32197c478bd9Sstevel@tonic-gate if (bitset(MCIF_SIZE, mci->mci_flags) && 32207c478bd9Sstevel@tonic-gate mci->mci_maxsize > 0 && 32217c478bd9Sstevel@tonic-gate e->e_msgsize > mci->mci_maxsize) 32227c478bd9Sstevel@tonic-gate { 32237c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 32247c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags)) 32257c478bd9Sstevel@tonic-gate e->e_status = "5.2.3"; 32267c478bd9Sstevel@tonic-gate else 32277c478bd9Sstevel@tonic-gate e->e_status = "5.3.4"; 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 32307c478bd9Sstevel@tonic-gate "552 Message is too large; %ld bytes max", 32317c478bd9Sstevel@tonic-gate mci->mci_maxsize); 32327c478bd9Sstevel@tonic-gate rcode = EX_DATAERR; 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate /* Need an e_message for error */ 32357c478bd9Sstevel@tonic-gate (void) sm_snprintf(SmtpError, sizeof SmtpError, 32367c478bd9Sstevel@tonic-gate "Message is too large; %ld bytes max", 32377c478bd9Sstevel@tonic-gate mci->mci_maxsize); 32387c478bd9Sstevel@tonic-gate goto give_up; 32397c478bd9Sstevel@tonic-gate } 32407c478bd9Sstevel@tonic-gate #endif /* _FFR_CLIENT_SIZE */ 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_OPEN) 32437c478bd9Sstevel@tonic-gate { 32447c478bd9Sstevel@tonic-gate /* couldn't open the mailer */ 32457c478bd9Sstevel@tonic-gate rcode = mci->mci_exitstat; 32467c478bd9Sstevel@tonic-gate errno = mci->mci_errno; 32477c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(mci->mci_herrno); 32487c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 32497c478bd9Sstevel@tonic-gate { 32507c478bd9Sstevel@tonic-gate /* shouldn't happen */ 32517c478bd9Sstevel@tonic-gate syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", 32527c478bd9Sstevel@tonic-gate (unsigned long) mci, rcode, errno, 32537c478bd9Sstevel@tonic-gate mci->mci_state, firstsig); 32547c478bd9Sstevel@tonic-gate mci_dump_all(smioout, true); 32557c478bd9Sstevel@tonic-gate rcode = EX_SOFTWARE; 32567c478bd9Sstevel@tonic-gate } 32577c478bd9Sstevel@tonic-gate else if (nummxhosts > hostnum) 32587c478bd9Sstevel@tonic-gate { 32597c478bd9Sstevel@tonic-gate /* try next MX site */ 32607c478bd9Sstevel@tonic-gate goto tryhost; 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate } 32637c478bd9Sstevel@tonic-gate else if (!clever) 32647c478bd9Sstevel@tonic-gate { 3265*445f2479Sjbeck bool ok; 3266*445f2479Sjbeck 32677c478bd9Sstevel@tonic-gate /* 32687c478bd9Sstevel@tonic-gate ** Format and send message. 32697c478bd9Sstevel@tonic-gate */ 32707c478bd9Sstevel@tonic-gate 3271*445f2479Sjbeck rcode = EX_OK; 3272*445f2479Sjbeck errno = 0; 3273*445f2479Sjbeck ok = putfromline(mci, e); 3274*445f2479Sjbeck if (ok) 3275*445f2479Sjbeck ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 3276*445f2479Sjbeck if (ok) 3277*445f2479Sjbeck ok = (*e->e_putbody)(mci, e, NULL); 32787c478bd9Sstevel@tonic-gate 3279*445f2479Sjbeck /* 3280*445f2479Sjbeck ** Ignore an I/O error that was caused by EPIPE. 3281*445f2479Sjbeck ** Some broken mailers don't read the entire body 3282*445f2479Sjbeck ** but just exit() thus causing an I/O error. 3283*445f2479Sjbeck */ 3284*445f2479Sjbeck 3285*445f2479Sjbeck if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE)) 3286*445f2479Sjbeck ok = true; 3287*445f2479Sjbeck 3288*445f2479Sjbeck /* (always) get the exit status */ 32897c478bd9Sstevel@tonic-gate rcode = endmailer(mci, e, pv); 3290*445f2479Sjbeck if (!ok) 3291*445f2479Sjbeck rcode = EX_TEMPFAIL; 32927c478bd9Sstevel@tonic-gate if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0') 32937c478bd9Sstevel@tonic-gate { 32947c478bd9Sstevel@tonic-gate /* 32957c478bd9Sstevel@tonic-gate ** Need an e_message for mailq display. 32967c478bd9Sstevel@tonic-gate ** We set SmtpError as 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate (void) sm_snprintf(SmtpError, sizeof SmtpError, 33007c478bd9Sstevel@tonic-gate "%s mailer (%s) exited with EX_TEMPFAIL", 33017c478bd9Sstevel@tonic-gate m->m_name, m->m_mailer); 33027c478bd9Sstevel@tonic-gate } 33037c478bd9Sstevel@tonic-gate } 33047c478bd9Sstevel@tonic-gate else 33057c478bd9Sstevel@tonic-gate { 33067c478bd9Sstevel@tonic-gate /* 33077c478bd9Sstevel@tonic-gate ** Send the MAIL FROM: protocol 33087c478bd9Sstevel@tonic-gate */ 33097c478bd9Sstevel@tonic-gate 33107c478bd9Sstevel@tonic-gate /* XXX this isn't pipelined... */ 33117c478bd9Sstevel@tonic-gate rcode = smtpmailfrom(m, mci, e); 33127c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 33137c478bd9Sstevel@tonic-gate { 33147c478bd9Sstevel@tonic-gate register int i; 33157c478bd9Sstevel@tonic-gate # if PIPELINING 33167c478bd9Sstevel@tonic-gate ADDRESS *volatile pchain; 33177c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33187c478bd9Sstevel@tonic-gate 33197c478bd9Sstevel@tonic-gate /* send the recipient list */ 33207c478bd9Sstevel@tonic-gate tobuf[0] = '\0'; 33217c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = false; 33227c478bd9Sstevel@tonic-gate mci->mci_tolist = tobuf; 33237c478bd9Sstevel@tonic-gate # if PIPELINING 33247c478bd9Sstevel@tonic-gate pchain = NULL; 33257c478bd9Sstevel@tonic-gate mci->mci_nextaddr = NULL; 33267c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33277c478bd9Sstevel@tonic-gate 33287c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 33297c478bd9Sstevel@tonic-gate { 33307c478bd9Sstevel@tonic-gate if (!QS_IS_UNMARKED(to->q_state)) 33317c478bd9Sstevel@tonic-gate continue; 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate /* mark recipient state as "ok so far" */ 33347c478bd9Sstevel@tonic-gate to->q_state = QS_OK; 33357c478bd9Sstevel@tonic-gate e->e_to = to->q_paddr; 33367c478bd9Sstevel@tonic-gate # if STARTTLS 33377c478bd9Sstevel@tonic-gate i = rscheck("tls_rcpt", to->q_user, NULL, e, 33387c478bd9Sstevel@tonic-gate RSF_RMCOMM|RSF_COUNT, 3, 33397c478bd9Sstevel@tonic-gate mci->mci_host, e->e_id); 33407c478bd9Sstevel@tonic-gate if (i != EX_OK) 33417c478bd9Sstevel@tonic-gate { 33427c478bd9Sstevel@tonic-gate markfailure(e, to, mci, i, false); 33437c478bd9Sstevel@tonic-gate giveresponse(i, to->q_status, m, mci, 33447c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 33457c478bd9Sstevel@tonic-gate if (i == EX_TEMPFAIL) 33467c478bd9Sstevel@tonic-gate { 33477c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = true; 33487c478bd9Sstevel@tonic-gate to->q_state = QS_RETRY; 33497c478bd9Sstevel@tonic-gate } 33507c478bd9Sstevel@tonic-gate continue; 33517c478bd9Sstevel@tonic-gate } 33527c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate i = smtprcpt(to, m, mci, e, ctladdr, xstart); 33557c478bd9Sstevel@tonic-gate # if PIPELINING 33567c478bd9Sstevel@tonic-gate if (i == EX_OK && 33577c478bd9Sstevel@tonic-gate bitset(MCIF_PIPELINED, mci->mci_flags)) 33587c478bd9Sstevel@tonic-gate { 33597c478bd9Sstevel@tonic-gate /* 33607c478bd9Sstevel@tonic-gate ** Add new element to list of 33617c478bd9Sstevel@tonic-gate ** recipients for pipelining. 33627c478bd9Sstevel@tonic-gate */ 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate to->q_pchain = NULL; 33657c478bd9Sstevel@tonic-gate if (mci->mci_nextaddr == NULL) 33667c478bd9Sstevel@tonic-gate mci->mci_nextaddr = to; 33677c478bd9Sstevel@tonic-gate if (pchain == NULL) 33687c478bd9Sstevel@tonic-gate pchain = to; 33697c478bd9Sstevel@tonic-gate else 33707c478bd9Sstevel@tonic-gate { 33717c478bd9Sstevel@tonic-gate pchain->q_pchain = to; 33727c478bd9Sstevel@tonic-gate pchain = pchain->q_pchain; 33737c478bd9Sstevel@tonic-gate } 33747c478bd9Sstevel@tonic-gate } 33757c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33767c478bd9Sstevel@tonic-gate if (i != EX_OK) 33777c478bd9Sstevel@tonic-gate { 33787c478bd9Sstevel@tonic-gate markfailure(e, to, mci, i, false); 33797c478bd9Sstevel@tonic-gate giveresponse(i, to->q_status, m, mci, 33807c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 33817c478bd9Sstevel@tonic-gate if (i == EX_TEMPFAIL) 33827c478bd9Sstevel@tonic-gate to->q_state = QS_RETRY; 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate } 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate /* No recipients in list and no missing responses? */ 33877c478bd9Sstevel@tonic-gate if (tobuf[0] == '\0' 33887c478bd9Sstevel@tonic-gate # if PIPELINING 33897c478bd9Sstevel@tonic-gate && mci->mci_nextaddr == NULL 33907c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 33917c478bd9Sstevel@tonic-gate ) 33927c478bd9Sstevel@tonic-gate { 33937c478bd9Sstevel@tonic-gate rcode = EX_OK; 33947c478bd9Sstevel@tonic-gate e->e_to = NULL; 33957c478bd9Sstevel@tonic-gate if (bitset(MCIF_CACHED, mci->mci_flags)) 33967c478bd9Sstevel@tonic-gate smtprset(m, mci, e); 33977c478bd9Sstevel@tonic-gate } 33987c478bd9Sstevel@tonic-gate else 33997c478bd9Sstevel@tonic-gate { 34007c478bd9Sstevel@tonic-gate e->e_to = tobuf + 1; 34017c478bd9Sstevel@tonic-gate rcode = smtpdata(m, mci, e, ctladdr, xstart); 34027c478bd9Sstevel@tonic-gate } 34037c478bd9Sstevel@tonic-gate } 34047c478bd9Sstevel@tonic-gate if (rcode == EX_TEMPFAIL && nummxhosts > hostnum) 34057c478bd9Sstevel@tonic-gate { 34067c478bd9Sstevel@tonic-gate /* try next MX site */ 34077c478bd9Sstevel@tonic-gate goto tryhost; 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate #if NAMED_BIND 34117c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 34127c478bd9Sstevel@tonic-gate _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 34137c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 34147c478bd9Sstevel@tonic-gate 34157c478bd9Sstevel@tonic-gate if (tTd(62, 1)) 34167c478bd9Sstevel@tonic-gate checkfds("after delivery"); 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate ** Do final status disposal. 34207c478bd9Sstevel@tonic-gate ** We check for something in tobuf for the SMTP case. 34217c478bd9Sstevel@tonic-gate ** If we got a temporary failure, arrange to queue the 34227c478bd9Sstevel@tonic-gate ** addressees. 34237c478bd9Sstevel@tonic-gate */ 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate give_up: 34267c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 34277c478bd9Sstevel@tonic-gate { 34287c478bd9Sstevel@tonic-gate lmtp_rcode = rcode; 34297c478bd9Sstevel@tonic-gate tobuf[0] = '\0'; 34307c478bd9Sstevel@tonic-gate anyok = false; 34317c478bd9Sstevel@tonic-gate strsize = 0; 34327c478bd9Sstevel@tonic-gate } 34337c478bd9Sstevel@tonic-gate else 34347c478bd9Sstevel@tonic-gate anyok = rcode == EX_OK; 34357c478bd9Sstevel@tonic-gate 34367c478bd9Sstevel@tonic-gate for (to = tochain; to != NULL; to = to->q_tchain) 34377c478bd9Sstevel@tonic-gate { 34387c478bd9Sstevel@tonic-gate /* see if address already marked */ 34397c478bd9Sstevel@tonic-gate if (!QS_IS_OK(to->q_state)) 34407c478bd9Sstevel@tonic-gate continue; 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate /* if running LMTP, get the status for each address */ 34437c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 34447c478bd9Sstevel@tonic-gate { 34457c478bd9Sstevel@tonic-gate if (lmtp_rcode == EX_OK) 34467c478bd9Sstevel@tonic-gate rcode = smtpgetstat(m, mci, e); 34477c478bd9Sstevel@tonic-gate if (rcode == EX_OK) 34487c478bd9Sstevel@tonic-gate { 34497c478bd9Sstevel@tonic-gate strsize += sm_strlcat2(tobuf + strsize, ",", 34507c478bd9Sstevel@tonic-gate to->q_paddr, 34517c478bd9Sstevel@tonic-gate tobufsize - strsize); 34527c478bd9Sstevel@tonic-gate SM_ASSERT(strsize < tobufsize); 34537c478bd9Sstevel@tonic-gate anyok = true; 34547c478bd9Sstevel@tonic-gate } 34557c478bd9Sstevel@tonic-gate else 34567c478bd9Sstevel@tonic-gate { 34577c478bd9Sstevel@tonic-gate e->e_to = to->q_paddr; 34587c478bd9Sstevel@tonic-gate markfailure(e, to, mci, rcode, true); 34597c478bd9Sstevel@tonic-gate giveresponse(rcode, to->q_status, m, mci, 34607c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to); 34617c478bd9Sstevel@tonic-gate e->e_to = tobuf + 1; 34627c478bd9Sstevel@tonic-gate continue; 34637c478bd9Sstevel@tonic-gate } 34647c478bd9Sstevel@tonic-gate } 34657c478bd9Sstevel@tonic-gate else 34667c478bd9Sstevel@tonic-gate { 34677c478bd9Sstevel@tonic-gate /* mark bad addresses */ 34687c478bd9Sstevel@tonic-gate if (rcode != EX_OK) 34697c478bd9Sstevel@tonic-gate { 34707c478bd9Sstevel@tonic-gate if (goodmxfound && rcode == EX_NOHOST) 34717c478bd9Sstevel@tonic-gate rcode = EX_TEMPFAIL; 34727c478bd9Sstevel@tonic-gate markfailure(e, to, mci, rcode, true); 34737c478bd9Sstevel@tonic-gate continue; 34747c478bd9Sstevel@tonic-gate } 34757c478bd9Sstevel@tonic-gate } 34767c478bd9Sstevel@tonic-gate 34777c478bd9Sstevel@tonic-gate /* successful delivery */ 34787c478bd9Sstevel@tonic-gate to->q_state = QS_SENT; 34797c478bd9Sstevel@tonic-gate to->q_statdate = curtime(); 34807c478bd9Sstevel@tonic-gate e->e_nsent++; 34817c478bd9Sstevel@tonic-gate 34827c478bd9Sstevel@tonic-gate /* 34837c478bd9Sstevel@tonic-gate ** Checkpoint the send list every few addresses 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate 34867c478bd9Sstevel@tonic-gate if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) 34877c478bd9Sstevel@tonic-gate { 34887c478bd9Sstevel@tonic-gate queueup(e, false, false); 34897c478bd9Sstevel@tonic-gate e->e_nsent = 0; 34907c478bd9Sstevel@tonic-gate } 34917c478bd9Sstevel@tonic-gate 34927c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) && 34937c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags)) 34947c478bd9Sstevel@tonic-gate { 34957c478bd9Sstevel@tonic-gate to->q_flags |= QDELIVERED; 34967c478bd9Sstevel@tonic-gate to->q_status = "2.1.5"; 34977c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 34987c478bd9Sstevel@tonic-gate "%s... Successfully delivered\n", 34997c478bd9Sstevel@tonic-gate to->q_paddr); 35007c478bd9Sstevel@tonic-gate } 35017c478bd9Sstevel@tonic-gate else if (bitset(QPINGONSUCCESS, to->q_flags) && 35027c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags) && 35037c478bd9Sstevel@tonic-gate !bitset(MCIF_DSN, mci->mci_flags)) 35047c478bd9Sstevel@tonic-gate { 35057c478bd9Sstevel@tonic-gate to->q_flags |= QRELAYED; 35067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35077c478bd9Sstevel@tonic-gate "%s... relayed; expect no further notifications\n", 35087c478bd9Sstevel@tonic-gate to->q_paddr); 35097c478bd9Sstevel@tonic-gate } 35107c478bd9Sstevel@tonic-gate else if (IS_DLVR_NOTIFY(e) && 35117c478bd9Sstevel@tonic-gate !bitset(MCIF_DLVR_BY, mci->mci_flags) && 35127c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags) && 35137c478bd9Sstevel@tonic-gate (!bitset(QHASNOTIFY, to->q_flags) || 35147c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags) || 35157c478bd9Sstevel@tonic-gate bitset(QPINGONFAILURE, to->q_flags) || 35167c478bd9Sstevel@tonic-gate bitset(QPINGONDELAY, to->q_flags))) 35177c478bd9Sstevel@tonic-gate { 35187c478bd9Sstevel@tonic-gate /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */ 35197c478bd9Sstevel@tonic-gate to->q_flags |= QBYNRELAY; 35207c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35217c478bd9Sstevel@tonic-gate "%s... Deliver-by notify: relayed\n", 35227c478bd9Sstevel@tonic-gate to->q_paddr); 35237c478bd9Sstevel@tonic-gate } 35247c478bd9Sstevel@tonic-gate else if (IS_DLVR_TRACE(e) && 35257c478bd9Sstevel@tonic-gate (!bitset(QHASNOTIFY, to->q_flags) || 35267c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, to->q_flags) || 35277c478bd9Sstevel@tonic-gate bitset(QPINGONFAILURE, to->q_flags) || 35287c478bd9Sstevel@tonic-gate bitset(QPINGONDELAY, to->q_flags)) && 35297c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags)) 35307c478bd9Sstevel@tonic-gate { 35317c478bd9Sstevel@tonic-gate /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */ 35327c478bd9Sstevel@tonic-gate to->q_flags |= QBYTRACE; 35337c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 35347c478bd9Sstevel@tonic-gate "%s... Deliver-By trace: relayed\n", 35357c478bd9Sstevel@tonic-gate to->q_paddr); 35367c478bd9Sstevel@tonic-gate } 35377c478bd9Sstevel@tonic-gate } 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags)) 35407c478bd9Sstevel@tonic-gate { 35417c478bd9Sstevel@tonic-gate /* 35427c478bd9Sstevel@tonic-gate ** Global information applies to the last recipient only; 35437c478bd9Sstevel@tonic-gate ** clear it out to avoid bogus errors. 35447c478bd9Sstevel@tonic-gate */ 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate rcode = EX_OK; 35477c478bd9Sstevel@tonic-gate e->e_statmsg = NULL; 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate /* reset the mci state for the next transaction */ 35507c478bd9Sstevel@tonic-gate if (mci != NULL && 35517c478bd9Sstevel@tonic-gate (mci->mci_state == MCIS_MAIL || 35527c478bd9Sstevel@tonic-gate mci->mci_state == MCIS_RCPT || 35537c478bd9Sstevel@tonic-gate mci->mci_state == MCIS_DATA)) 35547c478bd9Sstevel@tonic-gate { 35557c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN; 35567c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "idle"; 35577c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s: %s", CurHostName, 35587c478bd9Sstevel@tonic-gate mci->mci_phase); 35597c478bd9Sstevel@tonic-gate } 35607c478bd9Sstevel@tonic-gate } 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate if (tobuf[0] != '\0') 35637c478bd9Sstevel@tonic-gate { 35647c478bd9Sstevel@tonic-gate giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); 35657c478bd9Sstevel@tonic-gate #if 0 35667c478bd9Sstevel@tonic-gate /* 35677c478bd9Sstevel@tonic-gate ** This code is disabled for now because I am not 35687c478bd9Sstevel@tonic-gate ** sure that copying status from the first recipient 35697c478bd9Sstevel@tonic-gate ** to all non-status'ed recipients is a good idea. 35707c478bd9Sstevel@tonic-gate */ 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate if (tochain->q_message != NULL && 35737c478bd9Sstevel@tonic-gate !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK) 35747c478bd9Sstevel@tonic-gate { 35757c478bd9Sstevel@tonic-gate for (to = tochain->q_tchain; to != NULL; 35767c478bd9Sstevel@tonic-gate to = to->q_tchain) 35777c478bd9Sstevel@tonic-gate { 35787c478bd9Sstevel@tonic-gate /* see if address already marked */ 35797c478bd9Sstevel@tonic-gate if (QS_IS_QUEUEUP(to->q_state) && 35807c478bd9Sstevel@tonic-gate to->q_message == NULL) 35817c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 35827c478bd9Sstevel@tonic-gate tochain->q_message); 35837c478bd9Sstevel@tonic-gate } 35847c478bd9Sstevel@tonic-gate } 35857c478bd9Sstevel@tonic-gate #endif /* 0 */ 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate if (anyok) 35887c478bd9Sstevel@tonic-gate markstats(e, tochain, STATS_NORMAL); 35897c478bd9Sstevel@tonic-gate mci_store_persistent(mci); 35907c478bd9Sstevel@tonic-gate 35917c478bd9Sstevel@tonic-gate /* Some recipients were tempfailed, try them on the next host */ 35927c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum) 35937c478bd9Sstevel@tonic-gate { 35947c478bd9Sstevel@tonic-gate /* try next MX site */ 35957c478bd9Sstevel@tonic-gate goto tryhost; 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate /* now close the connection */ 35997c478bd9Sstevel@tonic-gate if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED && 36007c478bd9Sstevel@tonic-gate !bitset(MCIF_CACHED, mci->mci_flags)) 36017c478bd9Sstevel@tonic-gate smtpquit(m, mci, e); 36027c478bd9Sstevel@tonic-gate 36037c478bd9Sstevel@tonic-gate cleanup: ; 36047c478bd9Sstevel@tonic-gate } 36057c478bd9Sstevel@tonic-gate SM_FINALLY 36067c478bd9Sstevel@tonic-gate { 36077c478bd9Sstevel@tonic-gate /* 36087c478bd9Sstevel@tonic-gate ** Restore state and return. 36097c478bd9Sstevel@tonic-gate */ 36107c478bd9Sstevel@tonic-gate #if XDEBUG 36117c478bd9Sstevel@tonic-gate char wbuf[MAXLINE]; 36127c478bd9Sstevel@tonic-gate 36137c478bd9Sstevel@tonic-gate /* make absolutely certain 0, 1, and 2 are in use */ 36147c478bd9Sstevel@tonic-gate (void) sm_snprintf(wbuf, sizeof wbuf, 36157c478bd9Sstevel@tonic-gate "%s... end of deliver(%s)", 36167c478bd9Sstevel@tonic-gate e->e_to == NULL ? "NO-TO-LIST" 36177c478bd9Sstevel@tonic-gate : shortenstring(e->e_to, 36187c478bd9Sstevel@tonic-gate MAXSHORTSTR), 36197c478bd9Sstevel@tonic-gate m->m_name); 36207c478bd9Sstevel@tonic-gate checkfd012(wbuf); 36217c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate errno = 0; 36247c478bd9Sstevel@tonic-gate 36257c478bd9Sstevel@tonic-gate /* 36267c478bd9Sstevel@tonic-gate ** It was originally necessary to set macro 'g' to NULL 36277c478bd9Sstevel@tonic-gate ** because it previously pointed to an auto buffer. 36287c478bd9Sstevel@tonic-gate ** We don't do this any more, so this may be unnecessary. 36297c478bd9Sstevel@tonic-gate */ 36307c478bd9Sstevel@tonic-gate 36317c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL); 36327c478bd9Sstevel@tonic-gate e->e_to = NULL; 36337c478bd9Sstevel@tonic-gate } 36347c478bd9Sstevel@tonic-gate SM_END_TRY 36357c478bd9Sstevel@tonic-gate return rcode; 36367c478bd9Sstevel@tonic-gate } 36377c478bd9Sstevel@tonic-gate 36387c478bd9Sstevel@tonic-gate /* 36397c478bd9Sstevel@tonic-gate ** MARKFAILURE -- mark a failure on a specific address. 36407c478bd9Sstevel@tonic-gate ** 36417c478bd9Sstevel@tonic-gate ** Parameters: 36427c478bd9Sstevel@tonic-gate ** e -- the envelope we are sending. 36437c478bd9Sstevel@tonic-gate ** q -- the address to mark. 36447c478bd9Sstevel@tonic-gate ** mci -- mailer connection information. 36457c478bd9Sstevel@tonic-gate ** rcode -- the code signifying the particular failure. 36467c478bd9Sstevel@tonic-gate ** ovr -- override an existing code? 36477c478bd9Sstevel@tonic-gate ** 36487c478bd9Sstevel@tonic-gate ** Returns: 36497c478bd9Sstevel@tonic-gate ** none. 36507c478bd9Sstevel@tonic-gate ** 36517c478bd9Sstevel@tonic-gate ** Side Effects: 36527c478bd9Sstevel@tonic-gate ** marks the address (and possibly the envelope) with the 36537c478bd9Sstevel@tonic-gate ** failure so that an error will be returned or 36547c478bd9Sstevel@tonic-gate ** the message will be queued, as appropriate. 36557c478bd9Sstevel@tonic-gate */ 36567c478bd9Sstevel@tonic-gate 36577c478bd9Sstevel@tonic-gate void 36587c478bd9Sstevel@tonic-gate markfailure(e, q, mci, rcode, ovr) 36597c478bd9Sstevel@tonic-gate register ENVELOPE *e; 36607c478bd9Sstevel@tonic-gate register ADDRESS *q; 36617c478bd9Sstevel@tonic-gate register MCI *mci; 36627c478bd9Sstevel@tonic-gate int rcode; 36637c478bd9Sstevel@tonic-gate bool ovr; 36647c478bd9Sstevel@tonic-gate { 36657c478bd9Sstevel@tonic-gate int save_errno = errno; 36667c478bd9Sstevel@tonic-gate char *status = NULL; 36677c478bd9Sstevel@tonic-gate char *rstatus = NULL; 36687c478bd9Sstevel@tonic-gate 36697c478bd9Sstevel@tonic-gate switch (rcode) 36707c478bd9Sstevel@tonic-gate { 36717c478bd9Sstevel@tonic-gate case EX_OK: 36727c478bd9Sstevel@tonic-gate break; 36737c478bd9Sstevel@tonic-gate 36747c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 36757c478bd9Sstevel@tonic-gate case EX_IOERR: 36767c478bd9Sstevel@tonic-gate case EX_OSERR: 36777c478bd9Sstevel@tonic-gate q->q_state = QS_QUEUEUP; 36787c478bd9Sstevel@tonic-gate break; 36797c478bd9Sstevel@tonic-gate 36807c478bd9Sstevel@tonic-gate default: 36817c478bd9Sstevel@tonic-gate q->q_state = QS_BADADDR; 36827c478bd9Sstevel@tonic-gate break; 36837c478bd9Sstevel@tonic-gate } 36847c478bd9Sstevel@tonic-gate 36857c478bd9Sstevel@tonic-gate /* find most specific error code possible */ 36867c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_status != NULL) 36877c478bd9Sstevel@tonic-gate { 36887c478bd9Sstevel@tonic-gate status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status); 36897c478bd9Sstevel@tonic-gate if (mci->mci_rstatus != NULL) 36907c478bd9Sstevel@tonic-gate rstatus = sm_rpool_strdup_x(e->e_rpool, 36917c478bd9Sstevel@tonic-gate mci->mci_rstatus); 36927c478bd9Sstevel@tonic-gate else 36937c478bd9Sstevel@tonic-gate rstatus = NULL; 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate else if (e->e_status != NULL) 36967c478bd9Sstevel@tonic-gate { 36977c478bd9Sstevel@tonic-gate status = e->e_status; 36987c478bd9Sstevel@tonic-gate rstatus = NULL; 36997c478bd9Sstevel@tonic-gate } 37007c478bd9Sstevel@tonic-gate else 37017c478bd9Sstevel@tonic-gate { 37027c478bd9Sstevel@tonic-gate switch (rcode) 37037c478bd9Sstevel@tonic-gate { 37047c478bd9Sstevel@tonic-gate case EX_USAGE: 37057c478bd9Sstevel@tonic-gate status = "5.5.4"; 37067c478bd9Sstevel@tonic-gate break; 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate case EX_DATAERR: 37097c478bd9Sstevel@tonic-gate status = "5.5.2"; 37107c478bd9Sstevel@tonic-gate break; 37117c478bd9Sstevel@tonic-gate 37127c478bd9Sstevel@tonic-gate case EX_NOUSER: 37137c478bd9Sstevel@tonic-gate status = "5.1.1"; 37147c478bd9Sstevel@tonic-gate break; 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate case EX_NOHOST: 37177c478bd9Sstevel@tonic-gate status = "5.1.2"; 37187c478bd9Sstevel@tonic-gate break; 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate case EX_NOINPUT: 37217c478bd9Sstevel@tonic-gate case EX_CANTCREAT: 37227c478bd9Sstevel@tonic-gate case EX_NOPERM: 37237c478bd9Sstevel@tonic-gate status = "5.3.0"; 37247c478bd9Sstevel@tonic-gate break; 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate case EX_UNAVAILABLE: 37277c478bd9Sstevel@tonic-gate case EX_SOFTWARE: 37287c478bd9Sstevel@tonic-gate case EX_OSFILE: 37297c478bd9Sstevel@tonic-gate case EX_PROTOCOL: 37307c478bd9Sstevel@tonic-gate case EX_CONFIG: 37317c478bd9Sstevel@tonic-gate status = "5.5.0"; 37327c478bd9Sstevel@tonic-gate break; 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate case EX_OSERR: 37357c478bd9Sstevel@tonic-gate case EX_IOERR: 37367c478bd9Sstevel@tonic-gate status = "4.5.0"; 37377c478bd9Sstevel@tonic-gate break; 37387c478bd9Sstevel@tonic-gate 37397c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 37407c478bd9Sstevel@tonic-gate status = "4.2.0"; 37417c478bd9Sstevel@tonic-gate break; 37427c478bd9Sstevel@tonic-gate } 37437c478bd9Sstevel@tonic-gate } 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate /* new status? */ 37467c478bd9Sstevel@tonic-gate if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL || 37477c478bd9Sstevel@tonic-gate *q->q_status == '\0' || *q->q_status < *status)) 37487c478bd9Sstevel@tonic-gate { 37497c478bd9Sstevel@tonic-gate q->q_status = status; 37507c478bd9Sstevel@tonic-gate q->q_rstatus = rstatus; 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate if (rcode != EX_OK && q->q_rstatus == NULL && 37537c478bd9Sstevel@tonic-gate q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL && 37547c478bd9Sstevel@tonic-gate sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0) 37557c478bd9Sstevel@tonic-gate { 37567c478bd9Sstevel@tonic-gate char buf[16]; 37577c478bd9Sstevel@tonic-gate 37587c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%d", rcode); 37597c478bd9Sstevel@tonic-gate q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf); 37607c478bd9Sstevel@tonic-gate } 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate q->q_statdate = curtime(); 37637c478bd9Sstevel@tonic-gate if (CurHostName != NULL && CurHostName[0] != '\0' && 37647c478bd9Sstevel@tonic-gate mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags)) 37657c478bd9Sstevel@tonic-gate q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName); 37667c478bd9Sstevel@tonic-gate 37677c478bd9Sstevel@tonic-gate /* restore errno */ 37687c478bd9Sstevel@tonic-gate errno = save_errno; 37697c478bd9Sstevel@tonic-gate } 37707c478bd9Sstevel@tonic-gate /* 37717c478bd9Sstevel@tonic-gate ** ENDMAILER -- Wait for mailer to terminate. 37727c478bd9Sstevel@tonic-gate ** 37737c478bd9Sstevel@tonic-gate ** We should never get fatal errors (e.g., segmentation 37747c478bd9Sstevel@tonic-gate ** violation), so we report those specially. For other 37757c478bd9Sstevel@tonic-gate ** errors, we choose a status message (into statmsg), 37767c478bd9Sstevel@tonic-gate ** and if it represents an error, we print it. 37777c478bd9Sstevel@tonic-gate ** 37787c478bd9Sstevel@tonic-gate ** Parameters: 37797c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 37807c478bd9Sstevel@tonic-gate ** e -- the current envelope. 37817c478bd9Sstevel@tonic-gate ** pv -- the parameter vector that invoked the mailer 37827c478bd9Sstevel@tonic-gate ** (for error messages). 37837c478bd9Sstevel@tonic-gate ** 37847c478bd9Sstevel@tonic-gate ** Returns: 37857c478bd9Sstevel@tonic-gate ** exit code of mailer. 37867c478bd9Sstevel@tonic-gate ** 37877c478bd9Sstevel@tonic-gate ** Side Effects: 37887c478bd9Sstevel@tonic-gate ** none. 37897c478bd9Sstevel@tonic-gate */ 37907c478bd9Sstevel@tonic-gate 37917c478bd9Sstevel@tonic-gate static jmp_buf EndWaitTimeout; 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate static void 37947c478bd9Sstevel@tonic-gate endwaittimeout(ignore) 37957c478bd9Sstevel@tonic-gate int ignore; 37967c478bd9Sstevel@tonic-gate { 37977c478bd9Sstevel@tonic-gate /* 37987c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 37997c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 38007c478bd9Sstevel@tonic-gate ** DOING. 38017c478bd9Sstevel@tonic-gate */ 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 38047c478bd9Sstevel@tonic-gate longjmp(EndWaitTimeout, 1); 38057c478bd9Sstevel@tonic-gate } 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate int 38087c478bd9Sstevel@tonic-gate endmailer(mci, e, pv) 38097c478bd9Sstevel@tonic-gate register MCI *mci; 38107c478bd9Sstevel@tonic-gate register ENVELOPE *e; 38117c478bd9Sstevel@tonic-gate char **pv; 38127c478bd9Sstevel@tonic-gate { 38137c478bd9Sstevel@tonic-gate int st; 38147c478bd9Sstevel@tonic-gate int save_errno = errno; 38157c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 38167c478bd9Sstevel@tonic-gate SM_EVENT *ev = NULL; 38177c478bd9Sstevel@tonic-gate 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate mci_unlock_host(mci); 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate /* close output to mailer */ 38227c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL) 38237c478bd9Sstevel@tonic-gate { 38247c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 38257c478bd9Sstevel@tonic-gate mci->mci_out = NULL; 38267c478bd9Sstevel@tonic-gate } 38277c478bd9Sstevel@tonic-gate 38287c478bd9Sstevel@tonic-gate /* copy any remaining input to transcript */ 38297c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && 38307c478bd9Sstevel@tonic-gate e->e_xfp != NULL) 38317c478bd9Sstevel@tonic-gate { 38327c478bd9Sstevel@tonic-gate while (sfgets(buf, sizeof buf, mci->mci_in, 38337c478bd9Sstevel@tonic-gate TimeOuts.to_quit, "Draining Input") != NULL) 38347c478bd9Sstevel@tonic-gate (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf); 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate 38377c478bd9Sstevel@tonic-gate #if SASL 38387c478bd9Sstevel@tonic-gate /* close SASL connection */ 38397c478bd9Sstevel@tonic-gate if (bitset(MCIF_AUTHACT, mci->mci_flags)) 38407c478bd9Sstevel@tonic-gate { 38417c478bd9Sstevel@tonic-gate sasl_dispose(&mci->mci_conn); 38427c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_AUTHACT; 38437c478bd9Sstevel@tonic-gate } 38447c478bd9Sstevel@tonic-gate #endif /* SASL */ 38457c478bd9Sstevel@tonic-gate 38467c478bd9Sstevel@tonic-gate #if STARTTLS 38477c478bd9Sstevel@tonic-gate /* shutdown TLS */ 38487c478bd9Sstevel@tonic-gate (void) endtlsclt(mci); 38497c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate /* now close the input */ 38527c478bd9Sstevel@tonic-gate if (mci->mci_in != NULL) 38537c478bd9Sstevel@tonic-gate { 38547c478bd9Sstevel@tonic-gate (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT); 38557c478bd9Sstevel@tonic-gate mci->mci_in = NULL; 38567c478bd9Sstevel@tonic-gate } 38577c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_CLOSED; 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate errno = save_errno; 38607c478bd9Sstevel@tonic-gate 38617c478bd9Sstevel@tonic-gate /* in the IPC case there is nothing to wait for */ 38627c478bd9Sstevel@tonic-gate if (mci->mci_pid == 0) 38637c478bd9Sstevel@tonic-gate return EX_OK; 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate /* put a timeout around the wait */ 38667c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_wait > 0) 38677c478bd9Sstevel@tonic-gate { 38687c478bd9Sstevel@tonic-gate if (setjmp(EndWaitTimeout) == 0) 38697c478bd9Sstevel@tonic-gate ev = sm_setevent(mci->mci_mailer->m_wait, 38707c478bd9Sstevel@tonic-gate endwaittimeout, 0); 38717c478bd9Sstevel@tonic-gate else 38727c478bd9Sstevel@tonic-gate { 38737c478bd9Sstevel@tonic-gate syserr("endmailer %s: wait timeout (%ld)", 38747c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name, 38757c478bd9Sstevel@tonic-gate (long) mci->mci_mailer->m_wait); 38767c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 38777c478bd9Sstevel@tonic-gate } 38787c478bd9Sstevel@tonic-gate } 38797c478bd9Sstevel@tonic-gate 38807c478bd9Sstevel@tonic-gate /* wait for the mailer process, collect status */ 38817c478bd9Sstevel@tonic-gate st = waitfor(mci->mci_pid); 38827c478bd9Sstevel@tonic-gate save_errno = errno; 38837c478bd9Sstevel@tonic-gate if (ev != NULL) 38847c478bd9Sstevel@tonic-gate sm_clrevent(ev); 38857c478bd9Sstevel@tonic-gate errno = save_errno; 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate if (st == -1) 38887c478bd9Sstevel@tonic-gate { 38897c478bd9Sstevel@tonic-gate syserr("endmailer %s: wait", mci->mci_mailer->m_name); 38907c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 38917c478bd9Sstevel@tonic-gate } 38927c478bd9Sstevel@tonic-gate 38937c478bd9Sstevel@tonic-gate if (WIFEXITED(st)) 38947c478bd9Sstevel@tonic-gate { 38957c478bd9Sstevel@tonic-gate /* normal death -- return status */ 38967c478bd9Sstevel@tonic-gate return (WEXITSTATUS(st)); 38977c478bd9Sstevel@tonic-gate } 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate /* it died a horrid death */ 39007c478bd9Sstevel@tonic-gate syserr("451 4.3.0 mailer %s died with signal %d%s", 39017c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name, WTERMSIG(st), 39027c478bd9Sstevel@tonic-gate WCOREDUMP(st) ? " (core dumped)" : 39037c478bd9Sstevel@tonic-gate (WIFSTOPPED(st) ? " (stopped)" : "")); 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate /* log the arguments */ 39067c478bd9Sstevel@tonic-gate if (pv != NULL && e->e_xfp != NULL) 39077c478bd9Sstevel@tonic-gate { 39087c478bd9Sstevel@tonic-gate register char **av; 39097c478bd9Sstevel@tonic-gate 39107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:"); 39117c478bd9Sstevel@tonic-gate for (av = pv; *av != NULL; av++) 39127c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s", 39137c478bd9Sstevel@tonic-gate *av); 39147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n"); 39157c478bd9Sstevel@tonic-gate } 39167c478bd9Sstevel@tonic-gate 39177c478bd9Sstevel@tonic-gate ExitStat = EX_TEMPFAIL; 39187c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 39197c478bd9Sstevel@tonic-gate } 39207c478bd9Sstevel@tonic-gate /* 39217c478bd9Sstevel@tonic-gate ** GIVERESPONSE -- Interpret an error response from a mailer 39227c478bd9Sstevel@tonic-gate ** 39237c478bd9Sstevel@tonic-gate ** Parameters: 39247c478bd9Sstevel@tonic-gate ** status -- the status code from the mailer (high byte 39257c478bd9Sstevel@tonic-gate ** only; core dumps must have been taken care of 39267c478bd9Sstevel@tonic-gate ** already). 39277c478bd9Sstevel@tonic-gate ** dsn -- the DSN associated with the address, if any. 39287c478bd9Sstevel@tonic-gate ** m -- the mailer info for this mailer. 39297c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info -- can be NULL if the 39307c478bd9Sstevel@tonic-gate ** response is given before the connection is made. 39317c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address for the recipient 39327c478bd9Sstevel@tonic-gate ** address(es). 39337c478bd9Sstevel@tonic-gate ** xstart -- the transaction start time, for computing 39347c478bd9Sstevel@tonic-gate ** transaction delays. 39357c478bd9Sstevel@tonic-gate ** e -- the current envelope. 39367c478bd9Sstevel@tonic-gate ** to -- the current recipient (NULL if none). 39377c478bd9Sstevel@tonic-gate ** 39387c478bd9Sstevel@tonic-gate ** Returns: 39397c478bd9Sstevel@tonic-gate ** none. 39407c478bd9Sstevel@tonic-gate ** 39417c478bd9Sstevel@tonic-gate ** Side Effects: 39427c478bd9Sstevel@tonic-gate ** Errors may be incremented. 39437c478bd9Sstevel@tonic-gate ** ExitStat may be set. 39447c478bd9Sstevel@tonic-gate */ 39457c478bd9Sstevel@tonic-gate 39467c478bd9Sstevel@tonic-gate void 39477c478bd9Sstevel@tonic-gate giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) 39487c478bd9Sstevel@tonic-gate int status; 39497c478bd9Sstevel@tonic-gate char *dsn; 39507c478bd9Sstevel@tonic-gate register MAILER *m; 39517c478bd9Sstevel@tonic-gate register MCI *mci; 39527c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 39537c478bd9Sstevel@tonic-gate time_t xstart; 39547c478bd9Sstevel@tonic-gate ENVELOPE *e; 39557c478bd9Sstevel@tonic-gate ADDRESS *to; 39567c478bd9Sstevel@tonic-gate { 39577c478bd9Sstevel@tonic-gate register const char *statmsg; 39587c478bd9Sstevel@tonic-gate int errnum = errno; 39597c478bd9Sstevel@tonic-gate int off = 4; 39607c478bd9Sstevel@tonic-gate bool usestat = false; 39617c478bd9Sstevel@tonic-gate char dsnbuf[ENHSCLEN]; 39627c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 39637c478bd9Sstevel@tonic-gate char *exmsg; 39647c478bd9Sstevel@tonic-gate 39657c478bd9Sstevel@tonic-gate if (e == NULL) 39667c478bd9Sstevel@tonic-gate syserr("giveresponse: null envelope"); 39677c478bd9Sstevel@tonic-gate 39687c478bd9Sstevel@tonic-gate /* 39697c478bd9Sstevel@tonic-gate ** Compute status message from code. 39707c478bd9Sstevel@tonic-gate */ 39717c478bd9Sstevel@tonic-gate 39727c478bd9Sstevel@tonic-gate exmsg = sm_sysexmsg(status); 39737c478bd9Sstevel@tonic-gate if (status == 0) 39747c478bd9Sstevel@tonic-gate { 39757c478bd9Sstevel@tonic-gate statmsg = "250 2.0.0 Sent"; 39767c478bd9Sstevel@tonic-gate if (e->e_statmsg != NULL) 39777c478bd9Sstevel@tonic-gate { 39787c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", 39797c478bd9Sstevel@tonic-gate statmsg, 39807c478bd9Sstevel@tonic-gate shortenstring(e->e_statmsg, 403)); 39817c478bd9Sstevel@tonic-gate statmsg = buf; 39827c478bd9Sstevel@tonic-gate } 39837c478bd9Sstevel@tonic-gate } 39847c478bd9Sstevel@tonic-gate else if (exmsg == NULL) 39857c478bd9Sstevel@tonic-gate { 39867c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 39877c478bd9Sstevel@tonic-gate "554 5.3.0 unknown mailer error %d", 39887c478bd9Sstevel@tonic-gate status); 39897c478bd9Sstevel@tonic-gate status = EX_UNAVAILABLE; 39907c478bd9Sstevel@tonic-gate statmsg = buf; 39917c478bd9Sstevel@tonic-gate usestat = true; 39927c478bd9Sstevel@tonic-gate } 39937c478bd9Sstevel@tonic-gate else if (status == EX_TEMPFAIL) 39947c478bd9Sstevel@tonic-gate { 39957c478bd9Sstevel@tonic-gate char *bp = buf; 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp)); 39987c478bd9Sstevel@tonic-gate bp += strlen(bp); 39997c478bd9Sstevel@tonic-gate #if NAMED_BIND 40007c478bd9Sstevel@tonic-gate if (h_errno == TRY_AGAIN) 40017c478bd9Sstevel@tonic-gate statmsg = sm_errstring(h_errno + E_DNSBASE); 40027c478bd9Sstevel@tonic-gate else 40037c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 40047c478bd9Sstevel@tonic-gate { 40057c478bd9Sstevel@tonic-gate if (errnum != 0) 40067c478bd9Sstevel@tonic-gate statmsg = sm_errstring(errnum); 40077c478bd9Sstevel@tonic-gate else 40087c478bd9Sstevel@tonic-gate statmsg = SmtpError; 40097c478bd9Sstevel@tonic-gate } 40107c478bd9Sstevel@tonic-gate if (statmsg != NULL && statmsg[0] != '\0') 40117c478bd9Sstevel@tonic-gate { 40127c478bd9Sstevel@tonic-gate switch (errnum) 40137c478bd9Sstevel@tonic-gate { 40147c478bd9Sstevel@tonic-gate #ifdef ENETDOWN 40157c478bd9Sstevel@tonic-gate case ENETDOWN: /* Network is down */ 40167c478bd9Sstevel@tonic-gate #endif /* ENETDOWN */ 40177c478bd9Sstevel@tonic-gate #ifdef ENETUNREACH 40187c478bd9Sstevel@tonic-gate case ENETUNREACH: /* Network is unreachable */ 40197c478bd9Sstevel@tonic-gate #endif /* ENETUNREACH */ 40207c478bd9Sstevel@tonic-gate #ifdef ENETRESET 40217c478bd9Sstevel@tonic-gate case ENETRESET: /* Network dropped connection on reset */ 40227c478bd9Sstevel@tonic-gate #endif /* ENETRESET */ 40237c478bd9Sstevel@tonic-gate #ifdef ECONNABORTED 40247c478bd9Sstevel@tonic-gate case ECONNABORTED: /* Software caused connection abort */ 40257c478bd9Sstevel@tonic-gate #endif /* ECONNABORTED */ 40267c478bd9Sstevel@tonic-gate #ifdef EHOSTDOWN 40277c478bd9Sstevel@tonic-gate case EHOSTDOWN: /* Host is down */ 40287c478bd9Sstevel@tonic-gate #endif /* EHOSTDOWN */ 40297c478bd9Sstevel@tonic-gate #ifdef EHOSTUNREACH 40307c478bd9Sstevel@tonic-gate case EHOSTUNREACH: /* No route to host */ 40317c478bd9Sstevel@tonic-gate #endif /* EHOSTUNREACH */ 40327c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 40337c478bd9Sstevel@tonic-gate { 40347c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, 40357c478bd9Sstevel@tonic-gate SPACELEFT(buf, bp), 40367c478bd9Sstevel@tonic-gate 2, ": ", 40377c478bd9Sstevel@tonic-gate mci->mci_host); 40387c478bd9Sstevel@tonic-gate bp += strlen(bp); 40397c478bd9Sstevel@tonic-gate } 40407c478bd9Sstevel@tonic-gate break; 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ", 40437c478bd9Sstevel@tonic-gate statmsg); 40447c478bd9Sstevel@tonic-gate usestat = true; 40457c478bd9Sstevel@tonic-gate } 40467c478bd9Sstevel@tonic-gate statmsg = buf; 40477c478bd9Sstevel@tonic-gate } 40487c478bd9Sstevel@tonic-gate #if NAMED_BIND 40497c478bd9Sstevel@tonic-gate else if (status == EX_NOHOST && h_errno != 0) 40507c478bd9Sstevel@tonic-gate { 40517c478bd9Sstevel@tonic-gate statmsg = sm_errstring(h_errno + E_DNSBASE); 40527c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1, 40537c478bd9Sstevel@tonic-gate statmsg); 40547c478bd9Sstevel@tonic-gate statmsg = buf; 40557c478bd9Sstevel@tonic-gate usestat = true; 40567c478bd9Sstevel@tonic-gate } 40577c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 40587c478bd9Sstevel@tonic-gate else 40597c478bd9Sstevel@tonic-gate { 40607c478bd9Sstevel@tonic-gate statmsg = exmsg; 40617c478bd9Sstevel@tonic-gate if (*statmsg++ == ':' && errnum != 0) 40627c478bd9Sstevel@tonic-gate { 40637c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg, 40647c478bd9Sstevel@tonic-gate sm_errstring(errnum)); 40657c478bd9Sstevel@tonic-gate statmsg = buf; 40667c478bd9Sstevel@tonic-gate usestat = true; 40677c478bd9Sstevel@tonic-gate } 40687c478bd9Sstevel@tonic-gate else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL) 40697c478bd9Sstevel@tonic-gate { 40707c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%s (%s)", statmsg, 40717c478bd9Sstevel@tonic-gate shortenstring(e->e_statmsg, 403)); 40727c478bd9Sstevel@tonic-gate statmsg = buf; 40737c478bd9Sstevel@tonic-gate usestat = true; 40747c478bd9Sstevel@tonic-gate } 40757c478bd9Sstevel@tonic-gate } 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate ** Print the message as appropriate 40797c478bd9Sstevel@tonic-gate */ 40807c478bd9Sstevel@tonic-gate 40817c478bd9Sstevel@tonic-gate if (status == EX_OK || status == EX_TEMPFAIL) 40827c478bd9Sstevel@tonic-gate { 40837c478bd9Sstevel@tonic-gate extern char MsgBuf[]; 40847c478bd9Sstevel@tonic-gate 40857c478bd9Sstevel@tonic-gate if ((off = isenhsc(statmsg + 4, ' ')) > 0) 40867c478bd9Sstevel@tonic-gate { 40877c478bd9Sstevel@tonic-gate if (dsn == NULL) 40887c478bd9Sstevel@tonic-gate { 40897c478bd9Sstevel@tonic-gate (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 40907c478bd9Sstevel@tonic-gate "%.*s", off, statmsg + 4); 40917c478bd9Sstevel@tonic-gate dsn = dsnbuf; 40927c478bd9Sstevel@tonic-gate } 40937c478bd9Sstevel@tonic-gate off += 5; 40947c478bd9Sstevel@tonic-gate } 40957c478bd9Sstevel@tonic-gate else 40967c478bd9Sstevel@tonic-gate { 40977c478bd9Sstevel@tonic-gate off = 4; 40987c478bd9Sstevel@tonic-gate } 40997c478bd9Sstevel@tonic-gate message("%s", statmsg + off); 41007c478bd9Sstevel@tonic-gate if (status == EX_TEMPFAIL && e->e_xfp != NULL) 41017c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n", 41027c478bd9Sstevel@tonic-gate &MsgBuf[4]); 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate else 41057c478bd9Sstevel@tonic-gate { 41067c478bd9Sstevel@tonic-gate char mbuf[ENHSCLEN + 4]; 41077c478bd9Sstevel@tonic-gate 41087c478bd9Sstevel@tonic-gate Errors++; 41097c478bd9Sstevel@tonic-gate if ((off = isenhsc(statmsg + 4, ' ')) > 0 && 41107c478bd9Sstevel@tonic-gate off < sizeof mbuf - 4) 41117c478bd9Sstevel@tonic-gate { 41127c478bd9Sstevel@tonic-gate if (dsn == NULL) 41137c478bd9Sstevel@tonic-gate { 41147c478bd9Sstevel@tonic-gate (void) sm_snprintf(dsnbuf, sizeof dsnbuf, 41157c478bd9Sstevel@tonic-gate "%.*s", off, statmsg + 4); 41167c478bd9Sstevel@tonic-gate dsn = dsnbuf; 41177c478bd9Sstevel@tonic-gate } 41187c478bd9Sstevel@tonic-gate off += 5; 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate /* copy only part of statmsg to mbuf */ 41217c478bd9Sstevel@tonic-gate (void) sm_strlcpy(mbuf, statmsg, off); 41227c478bd9Sstevel@tonic-gate (void) sm_strlcat(mbuf, " %s", sizeof mbuf); 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate else 41257c478bd9Sstevel@tonic-gate { 41267c478bd9Sstevel@tonic-gate dsnbuf[0] = '\0'; 41277c478bd9Sstevel@tonic-gate (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s", 41287c478bd9Sstevel@tonic-gate statmsg); 41297c478bd9Sstevel@tonic-gate off = 4; 41307c478bd9Sstevel@tonic-gate } 41317c478bd9Sstevel@tonic-gate usrerr(mbuf, &statmsg[off]); 41327c478bd9Sstevel@tonic-gate } 41337c478bd9Sstevel@tonic-gate 41347c478bd9Sstevel@tonic-gate /* 41357c478bd9Sstevel@tonic-gate ** Final cleanup. 41367c478bd9Sstevel@tonic-gate ** Log a record of the transaction. Compute the new 41377c478bd9Sstevel@tonic-gate ** ExitStat -- if we already had an error, stick with 41387c478bd9Sstevel@tonic-gate ** that. 41397c478bd9Sstevel@tonic-gate */ 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && 41427c478bd9Sstevel@tonic-gate LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) 41437c478bd9Sstevel@tonic-gate logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); 41447c478bd9Sstevel@tonic-gate 41457c478bd9Sstevel@tonic-gate if (tTd(11, 2)) 41467c478bd9Sstevel@tonic-gate sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", 41477c478bd9Sstevel@tonic-gate status, 41487c478bd9Sstevel@tonic-gate dsn == NULL ? "<NULL>" : dsn, 41497c478bd9Sstevel@tonic-gate e->e_message == NULL ? "<NULL>" : e->e_message, 41507c478bd9Sstevel@tonic-gate errnum); 41517c478bd9Sstevel@tonic-gate 41527c478bd9Sstevel@tonic-gate if (status != EX_TEMPFAIL) 41537c478bd9Sstevel@tonic-gate setstat(status); 41547c478bd9Sstevel@tonic-gate if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) 41557c478bd9Sstevel@tonic-gate e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off); 41567c478bd9Sstevel@tonic-gate if (status != EX_OK && to != NULL && to->q_message == NULL) 41577c478bd9Sstevel@tonic-gate { 41587c478bd9Sstevel@tonic-gate if (!usestat && e->e_message != NULL) 41597c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 41607c478bd9Sstevel@tonic-gate e->e_message); 41617c478bd9Sstevel@tonic-gate else 41627c478bd9Sstevel@tonic-gate to->q_message = sm_rpool_strdup_x(e->e_rpool, 41637c478bd9Sstevel@tonic-gate statmsg + off); 41647c478bd9Sstevel@tonic-gate } 41657c478bd9Sstevel@tonic-gate errno = 0; 41667c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 41677c478bd9Sstevel@tonic-gate } 41687c478bd9Sstevel@tonic-gate /* 41697c478bd9Sstevel@tonic-gate ** LOGDELIVERY -- log the delivery in the system log 41707c478bd9Sstevel@tonic-gate ** 41717c478bd9Sstevel@tonic-gate ** Care is taken to avoid logging lines that are too long, because 41727c478bd9Sstevel@tonic-gate ** some versions of syslog have an unfortunate proclivity for core 41737c478bd9Sstevel@tonic-gate ** dumping. This is a hack, to be sure, that is at best empirical. 41747c478bd9Sstevel@tonic-gate ** 41757c478bd9Sstevel@tonic-gate ** Parameters: 41767c478bd9Sstevel@tonic-gate ** m -- the mailer info. Can be NULL for initial queue. 41777c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info -- can be NULL if the 41787c478bd9Sstevel@tonic-gate ** log is occurring when no connection is active. 41797c478bd9Sstevel@tonic-gate ** dsn -- the DSN attached to the status. 41807c478bd9Sstevel@tonic-gate ** status -- the message to print for the status. 41817c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address for the to list. 41827c478bd9Sstevel@tonic-gate ** xstart -- the transaction start time, used for 41837c478bd9Sstevel@tonic-gate ** computing transaction delay. 41847c478bd9Sstevel@tonic-gate ** e -- the current envelope. 41857c478bd9Sstevel@tonic-gate ** 41867c478bd9Sstevel@tonic-gate ** Returns: 41877c478bd9Sstevel@tonic-gate ** none 41887c478bd9Sstevel@tonic-gate ** 41897c478bd9Sstevel@tonic-gate ** Side Effects: 41907c478bd9Sstevel@tonic-gate ** none 41917c478bd9Sstevel@tonic-gate */ 41927c478bd9Sstevel@tonic-gate 41937c478bd9Sstevel@tonic-gate void 41947c478bd9Sstevel@tonic-gate logdelivery(m, mci, dsn, status, ctladdr, xstart, e) 41957c478bd9Sstevel@tonic-gate MAILER *m; 41967c478bd9Sstevel@tonic-gate register MCI *mci; 41977c478bd9Sstevel@tonic-gate char *dsn; 41987c478bd9Sstevel@tonic-gate const char *status; 41997c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 42007c478bd9Sstevel@tonic-gate time_t xstart; 42017c478bd9Sstevel@tonic-gate register ENVELOPE *e; 42027c478bd9Sstevel@tonic-gate { 42037c478bd9Sstevel@tonic-gate register char *bp; 42047c478bd9Sstevel@tonic-gate register char *p; 42057c478bd9Sstevel@tonic-gate int l; 42067c478bd9Sstevel@tonic-gate time_t now = curtime(); 42077c478bd9Sstevel@tonic-gate char buf[1024]; 42087c478bd9Sstevel@tonic-gate 42097c478bd9Sstevel@tonic-gate #if (SYSLOG_BUFSIZE) >= 256 42107c478bd9Sstevel@tonic-gate /* ctladdr: max 106 bytes */ 42117c478bd9Sstevel@tonic-gate bp = buf; 42127c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 42137c478bd9Sstevel@tonic-gate { 42147c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=", 42157c478bd9Sstevel@tonic-gate shortenstring(ctladdr->q_paddr, 83)); 42167c478bd9Sstevel@tonic-gate bp += strlen(bp); 42177c478bd9Sstevel@tonic-gate if (bitset(QGOODUID, ctladdr->q_flags)) 42187c478bd9Sstevel@tonic-gate { 42197c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 42207c478bd9Sstevel@tonic-gate (int) ctladdr->q_uid, 42217c478bd9Sstevel@tonic-gate (int) ctladdr->q_gid); 42227c478bd9Sstevel@tonic-gate bp += strlen(bp); 42237c478bd9Sstevel@tonic-gate } 42247c478bd9Sstevel@tonic-gate } 42257c478bd9Sstevel@tonic-gate 42267c478bd9Sstevel@tonic-gate /* delay & xdelay: max 41 bytes */ 42277c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=", 42287c478bd9Sstevel@tonic-gate pintvl(now - e->e_ctime, true)); 42297c478bd9Sstevel@tonic-gate bp += strlen(bp); 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate if (xstart != (time_t) 0) 42327c478bd9Sstevel@tonic-gate { 42337c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 42347c478bd9Sstevel@tonic-gate pintvl(now - xstart, true)); 42357c478bd9Sstevel@tonic-gate bp += strlen(bp); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate /* mailer: assume about 19 bytes (max 10 byte mailer name) */ 42397c478bd9Sstevel@tonic-gate if (m != NULL) 42407c478bd9Sstevel@tonic-gate { 42417c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 42427c478bd9Sstevel@tonic-gate m->m_name); 42437c478bd9Sstevel@tonic-gate bp += strlen(bp); 42447c478bd9Sstevel@tonic-gate } 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate /* pri: changes with each delivery attempt */ 42477c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", 42487c478bd9Sstevel@tonic-gate e->e_msgpriority); 42497c478bd9Sstevel@tonic-gate bp += strlen(bp); 42507c478bd9Sstevel@tonic-gate 42517c478bd9Sstevel@tonic-gate /* relay: max 66 bytes for IPv4 addresses */ 42527c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 42537c478bd9Sstevel@tonic-gate { 42547c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr; 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=", 42577c478bd9Sstevel@tonic-gate shortenstring(mci->mci_host, 40)); 42587c478bd9Sstevel@tonic-gate bp += strlen(bp); 42597c478bd9Sstevel@tonic-gate 42607c478bd9Sstevel@tonic-gate if (CurHostAddr.sa.sa_family != 0) 42617c478bd9Sstevel@tonic-gate { 42627c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]", 42637c478bd9Sstevel@tonic-gate anynet_ntoa(&CurHostAddr)); 42647c478bd9Sstevel@tonic-gate } 42657c478bd9Sstevel@tonic-gate } 42667c478bd9Sstevel@tonic-gate else if (strcmp(status, "quarantined") == 0) 42677c478bd9Sstevel@tonic-gate { 42687c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 42697c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 42707c478bd9Sstevel@tonic-gate ", quarantine=%s", 42717c478bd9Sstevel@tonic-gate shortenstring(e->e_quarmsg, 40)); 42727c478bd9Sstevel@tonic-gate } 42737c478bd9Sstevel@tonic-gate else if (strcmp(status, "queued") != 0) 42747c478bd9Sstevel@tonic-gate { 42757c478bd9Sstevel@tonic-gate p = macvalue('h', e); 42767c478bd9Sstevel@tonic-gate if (p != NULL && p[0] != '\0') 42777c478bd9Sstevel@tonic-gate { 42787c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 42797c478bd9Sstevel@tonic-gate ", relay=%s", shortenstring(p, 40)); 42807c478bd9Sstevel@tonic-gate } 42817c478bd9Sstevel@tonic-gate } 42827c478bd9Sstevel@tonic-gate bp += strlen(bp); 42837c478bd9Sstevel@tonic-gate 42847c478bd9Sstevel@tonic-gate /* dsn */ 42857c478bd9Sstevel@tonic-gate if (dsn != NULL && *dsn != '\0') 42867c478bd9Sstevel@tonic-gate { 42877c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=", 42887c478bd9Sstevel@tonic-gate shortenstring(dsn, ENHSCLEN)); 42897c478bd9Sstevel@tonic-gate bp += strlen(bp); 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate #if _FFR_LOG_NTRIES 42937c478bd9Sstevel@tonic-gate /* ntries */ 42947c478bd9Sstevel@tonic-gate if (e->e_ntries >= 0) 42957c478bd9Sstevel@tonic-gate { 42967c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 42977c478bd9Sstevel@tonic-gate ", ntries=%d", e->e_ntries + 1); 42987c478bd9Sstevel@tonic-gate bp += strlen(bp); 42997c478bd9Sstevel@tonic-gate } 43007c478bd9Sstevel@tonic-gate #endif /* _FFR_LOG_NTRIES */ 43017c478bd9Sstevel@tonic-gate 43027c478bd9Sstevel@tonic-gate # define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 43037c478bd9Sstevel@tonic-gate # if (STATLEN) < 63 43047c478bd9Sstevel@tonic-gate # undef STATLEN 43057c478bd9Sstevel@tonic-gate # define STATLEN 63 43067c478bd9Sstevel@tonic-gate # endif /* (STATLEN) < 63 */ 43077c478bd9Sstevel@tonic-gate # if (STATLEN) > 203 43087c478bd9Sstevel@tonic-gate # undef STATLEN 43097c478bd9Sstevel@tonic-gate # define STATLEN 203 43107c478bd9Sstevel@tonic-gate # endif /* (STATLEN) > 203 */ 43117c478bd9Sstevel@tonic-gate 43127c478bd9Sstevel@tonic-gate /* stat: max 210 bytes */ 43137c478bd9Sstevel@tonic-gate if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 43147c478bd9Sstevel@tonic-gate { 43157c478bd9Sstevel@tonic-gate /* desperation move -- truncate data */ 43167c478bd9Sstevel@tonic-gate bp = buf + sizeof buf - ((STATLEN) + 17); 43177c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp)); 43187c478bd9Sstevel@tonic-gate bp += 3; 43197c478bd9Sstevel@tonic-gate } 43207c478bd9Sstevel@tonic-gate 43217c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp)); 43227c478bd9Sstevel@tonic-gate bp += strlen(bp); 43237c478bd9Sstevel@tonic-gate 43247c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, shortenstring(status, STATLEN), 43257c478bd9Sstevel@tonic-gate SPACELEFT(buf, bp)); 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate /* id, to: max 13 + TOBUFSIZE bytes */ 43287c478bd9Sstevel@tonic-gate l = SYSLOG_BUFSIZE - 100 - strlen(buf); 43297c478bd9Sstevel@tonic-gate if (l < 0) 43307c478bd9Sstevel@tonic-gate l = 0; 43317c478bd9Sstevel@tonic-gate p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 43327c478bd9Sstevel@tonic-gate while (strlen(p) >= l) 43337c478bd9Sstevel@tonic-gate { 43347c478bd9Sstevel@tonic-gate register char *q; 43357c478bd9Sstevel@tonic-gate 43367c478bd9Sstevel@tonic-gate for (q = p + l; q > p; q--) 43377c478bd9Sstevel@tonic-gate { 43387c478bd9Sstevel@tonic-gate if (*q == ',') 43397c478bd9Sstevel@tonic-gate break; 43407c478bd9Sstevel@tonic-gate } 43417c478bd9Sstevel@tonic-gate if (p == q) 43427c478bd9Sstevel@tonic-gate break; 43437c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", 43447c478bd9Sstevel@tonic-gate (int) (++q - p), p, buf); 43457c478bd9Sstevel@tonic-gate p = q; 43467c478bd9Sstevel@tonic-gate } 43477c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); 43487c478bd9Sstevel@tonic-gate 43497c478bd9Sstevel@tonic-gate #else /* (SYSLOG_BUFSIZE) >= 256 */ 43507c478bd9Sstevel@tonic-gate 43517c478bd9Sstevel@tonic-gate l = SYSLOG_BUFSIZE - 85; 43527c478bd9Sstevel@tonic-gate if (l < 0) 43537c478bd9Sstevel@tonic-gate l = 0; 43547c478bd9Sstevel@tonic-gate p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; 43557c478bd9Sstevel@tonic-gate while (strlen(p) >= l) 43567c478bd9Sstevel@tonic-gate { 43577c478bd9Sstevel@tonic-gate register char *q; 43587c478bd9Sstevel@tonic-gate 43597c478bd9Sstevel@tonic-gate for (q = p + l; q > p; q--) 43607c478bd9Sstevel@tonic-gate { 43617c478bd9Sstevel@tonic-gate if (*q == ',') 43627c478bd9Sstevel@tonic-gate break; 43637c478bd9Sstevel@tonic-gate } 43647c478bd9Sstevel@tonic-gate if (p == q) 43657c478bd9Sstevel@tonic-gate break; 43667c478bd9Sstevel@tonic-gate 43677c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", 43687c478bd9Sstevel@tonic-gate (int) (++q - p), p); 43697c478bd9Sstevel@tonic-gate p = q; 43707c478bd9Sstevel@tonic-gate } 43717c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); 43727c478bd9Sstevel@tonic-gate 43737c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 43747c478bd9Sstevel@tonic-gate { 43757c478bd9Sstevel@tonic-gate bp = buf; 43767c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=", 43777c478bd9Sstevel@tonic-gate shortenstring(ctladdr->q_paddr, 83)); 43787c478bd9Sstevel@tonic-gate bp += strlen(bp); 43797c478bd9Sstevel@tonic-gate if (bitset(QGOODUID, ctladdr->q_flags)) 43807c478bd9Sstevel@tonic-gate { 43817c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)", 43827c478bd9Sstevel@tonic-gate ctladdr->q_uid, ctladdr->q_gid); 43837c478bd9Sstevel@tonic-gate bp += strlen(bp); 43847c478bd9Sstevel@tonic-gate } 43857c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%s", buf); 43867c478bd9Sstevel@tonic-gate } 43877c478bd9Sstevel@tonic-gate bp = buf; 43887c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=", 43897c478bd9Sstevel@tonic-gate pintvl(now - e->e_ctime, true)); 43907c478bd9Sstevel@tonic-gate bp += strlen(bp); 43917c478bd9Sstevel@tonic-gate if (xstart != (time_t) 0) 43927c478bd9Sstevel@tonic-gate { 43937c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=", 43947c478bd9Sstevel@tonic-gate pintvl(now - xstart, true)); 43957c478bd9Sstevel@tonic-gate bp += strlen(bp); 43967c478bd9Sstevel@tonic-gate } 43977c478bd9Sstevel@tonic-gate 43987c478bd9Sstevel@tonic-gate if (m != NULL) 43997c478bd9Sstevel@tonic-gate { 44007c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=", 44017c478bd9Sstevel@tonic-gate m->m_name); 44027c478bd9Sstevel@tonic-gate bp += strlen(bp); 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 44057c478bd9Sstevel@tonic-gate 44067c478bd9Sstevel@tonic-gate buf[0] = '\0'; 44077c478bd9Sstevel@tonic-gate bp = buf; 44087c478bd9Sstevel@tonic-gate if (mci != NULL && mci->mci_host != NULL) 44097c478bd9Sstevel@tonic-gate { 44107c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr; 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", 44137c478bd9Sstevel@tonic-gate mci->mci_host); 44147c478bd9Sstevel@tonic-gate bp += strlen(bp); 44157c478bd9Sstevel@tonic-gate 44167c478bd9Sstevel@tonic-gate if (CurHostAddr.sa.sa_family != 0) 44177c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 44187c478bd9Sstevel@tonic-gate " [%.100s]", 44197c478bd9Sstevel@tonic-gate anynet_ntoa(&CurHostAddr)); 44207c478bd9Sstevel@tonic-gate } 44217c478bd9Sstevel@tonic-gate else if (strcmp(status, "quarantined") == 0) 44227c478bd9Sstevel@tonic-gate { 44237c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 44247c478bd9Sstevel@tonic-gate (void) sm_snprintf(bp, SPACELEFT(buf, bp), 44257c478bd9Sstevel@tonic-gate ", quarantine=%.100s", 44267c478bd9Sstevel@tonic-gate e->e_quarmsg); 44277c478bd9Sstevel@tonic-gate } 44287c478bd9Sstevel@tonic-gate else if (strcmp(status, "queued") != 0) 44297c478bd9Sstevel@tonic-gate { 44307c478bd9Sstevel@tonic-gate p = macvalue('h', e); 44317c478bd9Sstevel@tonic-gate if (p != NULL && p[0] != '\0') 44327c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p); 44337c478bd9Sstevel@tonic-gate } 44347c478bd9Sstevel@tonic-gate if (buf[0] != '\0') 44357c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf); 44367c478bd9Sstevel@tonic-gate 44377c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63)); 44387c478bd9Sstevel@tonic-gate #endif /* (SYSLOG_BUFSIZE) >= 256 */ 44397c478bd9Sstevel@tonic-gate } 44407c478bd9Sstevel@tonic-gate /* 44417c478bd9Sstevel@tonic-gate ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 44427c478bd9Sstevel@tonic-gate ** 44437c478bd9Sstevel@tonic-gate ** This can be made an arbitrary message separator by changing $l 44447c478bd9Sstevel@tonic-gate ** 44457c478bd9Sstevel@tonic-gate ** One of the ugliest hacks seen by human eyes is contained herein: 44467c478bd9Sstevel@tonic-gate ** UUCP wants those stupid "remote from <host>" lines. Why oh why 44477c478bd9Sstevel@tonic-gate ** does a well-meaning programmer such as myself have to deal with 44487c478bd9Sstevel@tonic-gate ** this kind of antique garbage???? 44497c478bd9Sstevel@tonic-gate ** 44507c478bd9Sstevel@tonic-gate ** Parameters: 44517c478bd9Sstevel@tonic-gate ** mci -- the connection information. 44527c478bd9Sstevel@tonic-gate ** e -- the envelope. 44537c478bd9Sstevel@tonic-gate ** 44547c478bd9Sstevel@tonic-gate ** Returns: 4455*445f2479Sjbeck ** true iff line was written successfully 44567c478bd9Sstevel@tonic-gate ** 44577c478bd9Sstevel@tonic-gate ** Side Effects: 44587c478bd9Sstevel@tonic-gate ** outputs some text to fp. 44597c478bd9Sstevel@tonic-gate */ 44607c478bd9Sstevel@tonic-gate 4461*445f2479Sjbeck bool 44627c478bd9Sstevel@tonic-gate putfromline(mci, e) 44637c478bd9Sstevel@tonic-gate register MCI *mci; 44647c478bd9Sstevel@tonic-gate ENVELOPE *e; 44657c478bd9Sstevel@tonic-gate { 44667c478bd9Sstevel@tonic-gate char *template = UnixFromLine; 44677c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 44687c478bd9Sstevel@tonic-gate char xbuf[MAXLINE]; 44697c478bd9Sstevel@tonic-gate 44707c478bd9Sstevel@tonic-gate if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 4471*445f2479Sjbeck return true; 44727c478bd9Sstevel@tonic-gate 44737c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 44747c478bd9Sstevel@tonic-gate 44757c478bd9Sstevel@tonic-gate if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 44767c478bd9Sstevel@tonic-gate { 44777c478bd9Sstevel@tonic-gate char *bang; 44787c478bd9Sstevel@tonic-gate 44797c478bd9Sstevel@tonic-gate expand("\201g", buf, sizeof buf, e); 44807c478bd9Sstevel@tonic-gate bang = strchr(buf, '!'); 44817c478bd9Sstevel@tonic-gate if (bang == NULL) 44827c478bd9Sstevel@tonic-gate { 44837c478bd9Sstevel@tonic-gate char *at; 44847c478bd9Sstevel@tonic-gate char hname[MAXNAME]; 44857c478bd9Sstevel@tonic-gate 44867c478bd9Sstevel@tonic-gate /* 44877c478bd9Sstevel@tonic-gate ** If we can construct a UUCP path, do so 44887c478bd9Sstevel@tonic-gate */ 44897c478bd9Sstevel@tonic-gate 44907c478bd9Sstevel@tonic-gate at = strrchr(buf, '@'); 44917c478bd9Sstevel@tonic-gate if (at == NULL) 44927c478bd9Sstevel@tonic-gate { 44937c478bd9Sstevel@tonic-gate expand("\201k", hname, sizeof hname, e); 44947c478bd9Sstevel@tonic-gate at = hname; 44957c478bd9Sstevel@tonic-gate } 44967c478bd9Sstevel@tonic-gate else 44977c478bd9Sstevel@tonic-gate *at++ = '\0'; 44987c478bd9Sstevel@tonic-gate (void) sm_snprintf(xbuf, sizeof xbuf, 44997c478bd9Sstevel@tonic-gate "From %.800s \201d remote from %.100s\n", 45007c478bd9Sstevel@tonic-gate buf, at); 45017c478bd9Sstevel@tonic-gate } 45027c478bd9Sstevel@tonic-gate else 45037c478bd9Sstevel@tonic-gate { 45047c478bd9Sstevel@tonic-gate *bang++ = '\0'; 45057c478bd9Sstevel@tonic-gate (void) sm_snprintf(xbuf, sizeof xbuf, 45067c478bd9Sstevel@tonic-gate "From %.800s \201d remote from %.100s\n", 45077c478bd9Sstevel@tonic-gate bang, buf); 45087c478bd9Sstevel@tonic-gate template = xbuf; 45097c478bd9Sstevel@tonic-gate } 45107c478bd9Sstevel@tonic-gate } 45117c478bd9Sstevel@tonic-gate expand(template, buf, sizeof buf, e); 4512*445f2479Sjbeck return putxline(buf, strlen(buf), mci, PXLF_HEADER); 45137c478bd9Sstevel@tonic-gate } 4514*445f2479Sjbeck 45157c478bd9Sstevel@tonic-gate /* 45167c478bd9Sstevel@tonic-gate ** PUTBODY -- put the body of a message. 45177c478bd9Sstevel@tonic-gate ** 45187c478bd9Sstevel@tonic-gate ** Parameters: 45197c478bd9Sstevel@tonic-gate ** mci -- the connection information. 45207c478bd9Sstevel@tonic-gate ** e -- the envelope to put out. 45217c478bd9Sstevel@tonic-gate ** separator -- if non-NULL, a message separator that must 45227c478bd9Sstevel@tonic-gate ** not be permitted in the resulting message. 45237c478bd9Sstevel@tonic-gate ** 45247c478bd9Sstevel@tonic-gate ** Returns: 4525*445f2479Sjbeck ** true iff message was written successfully 45267c478bd9Sstevel@tonic-gate ** 45277c478bd9Sstevel@tonic-gate ** Side Effects: 45287c478bd9Sstevel@tonic-gate ** The message is written onto fp. 45297c478bd9Sstevel@tonic-gate */ 45307c478bd9Sstevel@tonic-gate 45317c478bd9Sstevel@tonic-gate /* values for output state variable */ 453249218d4fSjbeck #define OSTATE_HEAD 0 /* at beginning of line */ 453349218d4fSjbeck #define OSTATE_CR 1 /* read a carriage return */ 453449218d4fSjbeck #define OSTATE_INLINE 2 /* putting rest of line */ 45357c478bd9Sstevel@tonic-gate 4536*445f2479Sjbeck bool 45377c478bd9Sstevel@tonic-gate putbody(mci, e, separator) 45387c478bd9Sstevel@tonic-gate register MCI *mci; 45397c478bd9Sstevel@tonic-gate register ENVELOPE *e; 45407c478bd9Sstevel@tonic-gate char *separator; 45417c478bd9Sstevel@tonic-gate { 45427c478bd9Sstevel@tonic-gate bool dead = false; 4543*445f2479Sjbeck bool ioerr = false; 4544*445f2479Sjbeck int save_errno; 45457c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 45467c478bd9Sstevel@tonic-gate #if MIME8TO7 45477c478bd9Sstevel@tonic-gate char *boundaries[MAXMIMENESTING + 1]; 45487c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 45497c478bd9Sstevel@tonic-gate 45507c478bd9Sstevel@tonic-gate /* 45517c478bd9Sstevel@tonic-gate ** Output the body of the message 45527c478bd9Sstevel@tonic-gate */ 45537c478bd9Sstevel@tonic-gate 45547c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 45557c478bd9Sstevel@tonic-gate { 45567c478bd9Sstevel@tonic-gate char *df = queuename(e, DATAFL_LETTER); 45577c478bd9Sstevel@tonic-gate 45587c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 45597c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL); 45607c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45617c478bd9Sstevel@tonic-gate { 45627c478bd9Sstevel@tonic-gate char *msg = "!putbody: Cannot open %s for %s from %s"; 45637c478bd9Sstevel@tonic-gate 45647c478bd9Sstevel@tonic-gate if (errno == ENOENT) 45657c478bd9Sstevel@tonic-gate msg++; 45667c478bd9Sstevel@tonic-gate syserr(msg, df, e->e_to, e->e_from.q_paddr); 45677c478bd9Sstevel@tonic-gate } 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate } 45707c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 45717c478bd9Sstevel@tonic-gate { 45727c478bd9Sstevel@tonic-gate if (bitset(MCIF_INHEADER, mci->mci_flags)) 45737c478bd9Sstevel@tonic-gate { 4574*445f2479Sjbeck if (!putline("", mci)) 4575*445f2479Sjbeck goto writeerr; 45767c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 45777c478bd9Sstevel@tonic-gate } 4578*445f2479Sjbeck if (!putline("<<< No Message Collected >>>", mci)) 4579*445f2479Sjbeck goto writeerr; 45807c478bd9Sstevel@tonic-gate goto endofmessage; 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate if (e->e_dfino == (ino_t) 0) 45847c478bd9Sstevel@tonic-gate { 45857c478bd9Sstevel@tonic-gate struct stat stbuf; 45867c478bd9Sstevel@tonic-gate 45877c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf) 45887c478bd9Sstevel@tonic-gate < 0) 45897c478bd9Sstevel@tonic-gate e->e_dfino = -1; 45907c478bd9Sstevel@tonic-gate else 45917c478bd9Sstevel@tonic-gate { 45927c478bd9Sstevel@tonic-gate e->e_dfdev = stbuf.st_dev; 45937c478bd9Sstevel@tonic-gate e->e_dfino = stbuf.st_ino; 45947c478bd9Sstevel@tonic-gate } 45957c478bd9Sstevel@tonic-gate } 45967c478bd9Sstevel@tonic-gate 45977c478bd9Sstevel@tonic-gate /* paranoia: the data file should always be in a rewound state */ 45987c478bd9Sstevel@tonic-gate (void) bfrewind(e->e_dfp); 45997c478bd9Sstevel@tonic-gate 4600*445f2479Sjbeck /* simulate an I/O timeout when used as source */ 4601*445f2479Sjbeck if (tTd(84, 101)) 4602*445f2479Sjbeck sleep(319); 4603*445f2479Sjbeck 46047c478bd9Sstevel@tonic-gate #if MIME8TO7 46057c478bd9Sstevel@tonic-gate if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 46067c478bd9Sstevel@tonic-gate { 46077c478bd9Sstevel@tonic-gate /* 46087c478bd9Sstevel@tonic-gate ** Do 8 to 7 bit MIME conversion. 46097c478bd9Sstevel@tonic-gate */ 46107c478bd9Sstevel@tonic-gate 46117c478bd9Sstevel@tonic-gate /* make sure it looks like a MIME message */ 4612*445f2479Sjbeck if (hvalue("MIME-Version", e->e_header) == NULL && 4613*445f2479Sjbeck !putline("MIME-Version: 1.0", mci)) 4614*445f2479Sjbeck goto writeerr; 46157c478bd9Sstevel@tonic-gate 46167c478bd9Sstevel@tonic-gate if (hvalue("Content-Type", e->e_header) == NULL) 46177c478bd9Sstevel@tonic-gate { 46187c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 46197c478bd9Sstevel@tonic-gate "Content-Type: text/plain; charset=%s", 46207c478bd9Sstevel@tonic-gate defcharset(e)); 4621*445f2479Sjbeck if (!putline(buf, mci)) 4622*445f2479Sjbeck goto writeerr; 46237c478bd9Sstevel@tonic-gate } 46247c478bd9Sstevel@tonic-gate 46257c478bd9Sstevel@tonic-gate /* now do the hard work */ 46267c478bd9Sstevel@tonic-gate boundaries[0] = NULL; 46277c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 4628*445f2479Sjbeck if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER) == 4629*445f2479Sjbeck SM_IO_EOF) 4630*445f2479Sjbeck goto writeerr; 46317c478bd9Sstevel@tonic-gate } 46327c478bd9Sstevel@tonic-gate # if MIME7TO8 46337c478bd9Sstevel@tonic-gate else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) 46347c478bd9Sstevel@tonic-gate { 4635*445f2479Sjbeck if (!mime7to8(mci, e->e_header, e)) 4636*445f2479Sjbeck goto writeerr; 46377c478bd9Sstevel@tonic-gate } 46387c478bd9Sstevel@tonic-gate # endif /* MIME7TO8 */ 46397c478bd9Sstevel@tonic-gate else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0) 46407c478bd9Sstevel@tonic-gate { 46417c478bd9Sstevel@tonic-gate bool oldsuprerrs = SuprErrs; 46427c478bd9Sstevel@tonic-gate 46437c478bd9Sstevel@tonic-gate /* Use mime8to7 to check multipart for MIME header overflows */ 46447c478bd9Sstevel@tonic-gate boundaries[0] = NULL; 46457c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 46467c478bd9Sstevel@tonic-gate 46477c478bd9Sstevel@tonic-gate /* 46487c478bd9Sstevel@tonic-gate ** If EF_DONT_MIME is set, we have a broken MIME message 46497c478bd9Sstevel@tonic-gate ** and don't want to generate a new bounce message whose 46507c478bd9Sstevel@tonic-gate ** body propagates the broken MIME. We can't just not call 46517c478bd9Sstevel@tonic-gate ** mime8to7() as is done above since we need the security 46527c478bd9Sstevel@tonic-gate ** checks. The best we can do is suppress the errors. 46537c478bd9Sstevel@tonic-gate */ 46547c478bd9Sstevel@tonic-gate 46557c478bd9Sstevel@tonic-gate if (bitset(EF_DONT_MIME, e->e_flags)) 46567c478bd9Sstevel@tonic-gate SuprErrs = true; 46577c478bd9Sstevel@tonic-gate 4658*445f2479Sjbeck if (mime8to7(mci, e->e_header, e, boundaries, 4659*445f2479Sjbeck M87F_OUTER|M87F_NO8TO7) == SM_IO_EOF) 4660*445f2479Sjbeck goto writeerr; 46617c478bd9Sstevel@tonic-gate 46627c478bd9Sstevel@tonic-gate /* restore SuprErrs */ 46637c478bd9Sstevel@tonic-gate SuprErrs = oldsuprerrs; 46647c478bd9Sstevel@tonic-gate } 46657c478bd9Sstevel@tonic-gate else 46667c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 46677c478bd9Sstevel@tonic-gate { 46687c478bd9Sstevel@tonic-gate int ostate; 46697c478bd9Sstevel@tonic-gate register char *bp; 46707c478bd9Sstevel@tonic-gate register char *pbp; 46717c478bd9Sstevel@tonic-gate register int c; 46727c478bd9Sstevel@tonic-gate register char *xp; 46737c478bd9Sstevel@tonic-gate int padc; 46747c478bd9Sstevel@tonic-gate char *buflim; 46757c478bd9Sstevel@tonic-gate int pos = 0; 46767c478bd9Sstevel@tonic-gate char peekbuf[12]; 46777c478bd9Sstevel@tonic-gate 46787c478bd9Sstevel@tonic-gate if (bitset(MCIF_INHEADER, mci->mci_flags)) 46797c478bd9Sstevel@tonic-gate { 4680*445f2479Sjbeck if (!putline("", mci)) 4681*445f2479Sjbeck goto writeerr; 46827c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 46837c478bd9Sstevel@tonic-gate } 46847c478bd9Sstevel@tonic-gate 46857c478bd9Sstevel@tonic-gate /* determine end of buffer; allow for short mailer lines */ 46867c478bd9Sstevel@tonic-gate buflim = &buf[sizeof buf - 1]; 46877c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_linelimit > 0 && 46887c478bd9Sstevel@tonic-gate mci->mci_mailer->m_linelimit < sizeof buf - 1) 46897c478bd9Sstevel@tonic-gate buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 46907c478bd9Sstevel@tonic-gate 46917c478bd9Sstevel@tonic-gate /* copy temp file to output with mapping */ 469249218d4fSjbeck ostate = OSTATE_HEAD; 46937c478bd9Sstevel@tonic-gate bp = buf; 46947c478bd9Sstevel@tonic-gate pbp = peekbuf; 46957c478bd9Sstevel@tonic-gate while (!sm_io_error(mci->mci_out) && !dead) 46967c478bd9Sstevel@tonic-gate { 46977c478bd9Sstevel@tonic-gate if (pbp > peekbuf) 46987c478bd9Sstevel@tonic-gate c = *--pbp; 46997c478bd9Sstevel@tonic-gate else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) 47007c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47017c478bd9Sstevel@tonic-gate break; 47027c478bd9Sstevel@tonic-gate if (bitset(MCIF_7BIT, mci->mci_flags)) 47037c478bd9Sstevel@tonic-gate c &= 0x7f; 47047c478bd9Sstevel@tonic-gate switch (ostate) 47057c478bd9Sstevel@tonic-gate { 470649218d4fSjbeck case OSTATE_HEAD: 47077c478bd9Sstevel@tonic-gate if (c == '\0' && 47087c478bd9Sstevel@tonic-gate bitnset(M_NONULLS, 47097c478bd9Sstevel@tonic-gate mci->mci_mailer->m_flags)) 47107c478bd9Sstevel@tonic-gate break; 47117c478bd9Sstevel@tonic-gate if (c != '\r' && c != '\n' && bp < buflim) 47127c478bd9Sstevel@tonic-gate { 47137c478bd9Sstevel@tonic-gate *bp++ = c; 47147c478bd9Sstevel@tonic-gate break; 47157c478bd9Sstevel@tonic-gate } 47167c478bd9Sstevel@tonic-gate 47177c478bd9Sstevel@tonic-gate /* check beginning of line for special cases */ 47187c478bd9Sstevel@tonic-gate *bp = '\0'; 47197c478bd9Sstevel@tonic-gate pos = 0; 47207c478bd9Sstevel@tonic-gate padc = SM_IO_EOF; 47217c478bd9Sstevel@tonic-gate if (buf[0] == 'F' && 47227c478bd9Sstevel@tonic-gate bitnset(M_ESCFROM, mci->mci_mailer->m_flags) 47237c478bd9Sstevel@tonic-gate && strncmp(buf, "From ", 5) == 0) 47247c478bd9Sstevel@tonic-gate { 47257c478bd9Sstevel@tonic-gate padc = '>'; 47267c478bd9Sstevel@tonic-gate } 47277c478bd9Sstevel@tonic-gate if (buf[0] == '-' && buf[1] == '-' && 47287c478bd9Sstevel@tonic-gate separator != NULL) 47297c478bd9Sstevel@tonic-gate { 47307c478bd9Sstevel@tonic-gate /* possible separator */ 47317c478bd9Sstevel@tonic-gate int sl = strlen(separator); 47327c478bd9Sstevel@tonic-gate 47337c478bd9Sstevel@tonic-gate if (strncmp(&buf[2], separator, sl) 47347c478bd9Sstevel@tonic-gate == 0) 47357c478bd9Sstevel@tonic-gate padc = ' '; 47367c478bd9Sstevel@tonic-gate } 47377c478bd9Sstevel@tonic-gate if (buf[0] == '.' && 47387c478bd9Sstevel@tonic-gate bitnset(M_XDOT, mci->mci_mailer->m_flags)) 47397c478bd9Sstevel@tonic-gate { 47407c478bd9Sstevel@tonic-gate padc = '.'; 47417c478bd9Sstevel@tonic-gate } 47427c478bd9Sstevel@tonic-gate 47437c478bd9Sstevel@tonic-gate /* now copy out saved line */ 47447c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 47457c478bd9Sstevel@tonic-gate { 47467c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 47477c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47487c478bd9Sstevel@tonic-gate "%05d >>> ", 47497c478bd9Sstevel@tonic-gate (int) CurrentPid); 47507c478bd9Sstevel@tonic-gate if (padc != SM_IO_EOF) 47517c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 47527c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47537c478bd9Sstevel@tonic-gate padc); 47547c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 47557c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 47567c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47577c478bd9Sstevel@tonic-gate (unsigned char) *xp); 47587c478bd9Sstevel@tonic-gate if (c == '\n') 47597c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 47607c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47617c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate if (padc != SM_IO_EOF) 47647c478bd9Sstevel@tonic-gate { 47657c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 47667c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, padc) 47677c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47687c478bd9Sstevel@tonic-gate { 47697c478bd9Sstevel@tonic-gate dead = true; 47707c478bd9Sstevel@tonic-gate continue; 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate pos++; 47737c478bd9Sstevel@tonic-gate } 47747c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 47757c478bd9Sstevel@tonic-gate { 47767c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 47777c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47787c478bd9Sstevel@tonic-gate (unsigned char) *xp) 47797c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47807c478bd9Sstevel@tonic-gate { 47817c478bd9Sstevel@tonic-gate dead = true; 47827c478bd9Sstevel@tonic-gate break; 47837c478bd9Sstevel@tonic-gate } 47847c478bd9Sstevel@tonic-gate } 47857c478bd9Sstevel@tonic-gate if (dead) 47867c478bd9Sstevel@tonic-gate continue; 47877c478bd9Sstevel@tonic-gate if (c == '\n') 47887c478bd9Sstevel@tonic-gate { 47897c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 47907c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 47917c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 47927c478bd9Sstevel@tonic-gate == SM_IO_EOF) 47937c478bd9Sstevel@tonic-gate break; 47947c478bd9Sstevel@tonic-gate pos = 0; 47957c478bd9Sstevel@tonic-gate } 47967c478bd9Sstevel@tonic-gate else 47977c478bd9Sstevel@tonic-gate { 47987c478bd9Sstevel@tonic-gate pos += bp - buf; 47997c478bd9Sstevel@tonic-gate if (c != '\r') 48007c478bd9Sstevel@tonic-gate { 48017c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 48027c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 48037c478bd9Sstevel@tonic-gate *pbp++ = c; 48047c478bd9Sstevel@tonic-gate } 48057c478bd9Sstevel@tonic-gate } 48067c478bd9Sstevel@tonic-gate 48077c478bd9Sstevel@tonic-gate bp = buf; 48087c478bd9Sstevel@tonic-gate 48097c478bd9Sstevel@tonic-gate /* determine next state */ 48107c478bd9Sstevel@tonic-gate if (c == '\n') 481149218d4fSjbeck ostate = OSTATE_HEAD; 48127c478bd9Sstevel@tonic-gate else if (c == '\r') 481349218d4fSjbeck ostate = OSTATE_CR; 48147c478bd9Sstevel@tonic-gate else 481549218d4fSjbeck ostate = OSTATE_INLINE; 48167c478bd9Sstevel@tonic-gate continue; 48177c478bd9Sstevel@tonic-gate 481849218d4fSjbeck case OSTATE_CR: 48197c478bd9Sstevel@tonic-gate if (c == '\n') 48207c478bd9Sstevel@tonic-gate { 48217c478bd9Sstevel@tonic-gate /* got CRLF */ 48227c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 48237c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48247c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 48257c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48267c478bd9Sstevel@tonic-gate continue; 48277c478bd9Sstevel@tonic-gate 48287c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 48297c478bd9Sstevel@tonic-gate { 48307c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 48317c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48327c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 48337c478bd9Sstevel@tonic-gate } 483449218d4fSjbeck ostate = OSTATE_HEAD; 48357c478bd9Sstevel@tonic-gate continue; 48367c478bd9Sstevel@tonic-gate } 48377c478bd9Sstevel@tonic-gate 48387c478bd9Sstevel@tonic-gate /* had a naked carriage return */ 48397c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + sizeof(peekbuf)); 48407c478bd9Sstevel@tonic-gate *pbp++ = c; 48417c478bd9Sstevel@tonic-gate c = '\r'; 484249218d4fSjbeck ostate = OSTATE_INLINE; 48437c478bd9Sstevel@tonic-gate goto putch; 48447c478bd9Sstevel@tonic-gate 484549218d4fSjbeck case OSTATE_INLINE: 48467c478bd9Sstevel@tonic-gate if (c == '\r') 48477c478bd9Sstevel@tonic-gate { 484849218d4fSjbeck ostate = OSTATE_CR; 48497c478bd9Sstevel@tonic-gate continue; 48507c478bd9Sstevel@tonic-gate } 48517c478bd9Sstevel@tonic-gate if (c == '\0' && 48527c478bd9Sstevel@tonic-gate bitnset(M_NONULLS, 48537c478bd9Sstevel@tonic-gate mci->mci_mailer->m_flags)) 48547c478bd9Sstevel@tonic-gate break; 48557c478bd9Sstevel@tonic-gate putch: 48567c478bd9Sstevel@tonic-gate if (mci->mci_mailer->m_linelimit > 0 && 48577c478bd9Sstevel@tonic-gate pos >= mci->mci_mailer->m_linelimit - 1 && 48587c478bd9Sstevel@tonic-gate c != '\n') 48597c478bd9Sstevel@tonic-gate { 48607c478bd9Sstevel@tonic-gate int d; 48617c478bd9Sstevel@tonic-gate 48627c478bd9Sstevel@tonic-gate /* check next character for EOL */ 48637c478bd9Sstevel@tonic-gate if (pbp > peekbuf) 48647c478bd9Sstevel@tonic-gate d = *(pbp - 1); 48657c478bd9Sstevel@tonic-gate else if ((d = sm_io_getc(e->e_dfp, 48667c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT)) 48677c478bd9Sstevel@tonic-gate != SM_IO_EOF) 48687c478bd9Sstevel@tonic-gate { 48697c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 48707c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 48717c478bd9Sstevel@tonic-gate *pbp++ = d; 48727c478bd9Sstevel@tonic-gate } 48737c478bd9Sstevel@tonic-gate 48747c478bd9Sstevel@tonic-gate if (d == '\n' || d == SM_IO_EOF) 48757c478bd9Sstevel@tonic-gate { 48767c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 48777c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 48787c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48797c478bd9Sstevel@tonic-gate (unsigned char) c); 48807c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 48817c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48827c478bd9Sstevel@tonic-gate (unsigned char) c) 48837c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48847c478bd9Sstevel@tonic-gate { 48857c478bd9Sstevel@tonic-gate dead = true; 48867c478bd9Sstevel@tonic-gate continue; 48877c478bd9Sstevel@tonic-gate } 48887c478bd9Sstevel@tonic-gate pos++; 48897c478bd9Sstevel@tonic-gate continue; 48907c478bd9Sstevel@tonic-gate } 48917c478bd9Sstevel@tonic-gate 48927c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 48937c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, '!') 48947c478bd9Sstevel@tonic-gate == SM_IO_EOF || 48957c478bd9Sstevel@tonic-gate sm_io_fputs(mci->mci_out, 48967c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 48977c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 48987c478bd9Sstevel@tonic-gate == SM_IO_EOF) 48997c478bd9Sstevel@tonic-gate { 49007c478bd9Sstevel@tonic-gate dead = true; 49017c478bd9Sstevel@tonic-gate continue; 49027c478bd9Sstevel@tonic-gate } 49037c478bd9Sstevel@tonic-gate 49047c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49057c478bd9Sstevel@tonic-gate { 49067c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, 49077c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49087c478bd9Sstevel@tonic-gate "!%s", 49097c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 49107c478bd9Sstevel@tonic-gate } 491149218d4fSjbeck ostate = OSTATE_HEAD; 49127c478bd9Sstevel@tonic-gate SM_ASSERT(pbp < peekbuf + 49137c478bd9Sstevel@tonic-gate sizeof(peekbuf)); 49147c478bd9Sstevel@tonic-gate *pbp++ = c; 49157c478bd9Sstevel@tonic-gate continue; 49167c478bd9Sstevel@tonic-gate } 49177c478bd9Sstevel@tonic-gate if (c == '\n') 49187c478bd9Sstevel@tonic-gate { 49197c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49207c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 49217c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49227c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 49237c478bd9Sstevel@tonic-gate if (sm_io_fputs(mci->mci_out, 49247c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49257c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol) 49267c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49277c478bd9Sstevel@tonic-gate continue; 49287c478bd9Sstevel@tonic-gate pos = 0; 492949218d4fSjbeck ostate = OSTATE_HEAD; 49307c478bd9Sstevel@tonic-gate } 49317c478bd9Sstevel@tonic-gate else 49327c478bd9Sstevel@tonic-gate { 49337c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49347c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 49357c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49367c478bd9Sstevel@tonic-gate (unsigned char) c); 49377c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, 49387c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49397c478bd9Sstevel@tonic-gate (unsigned char) c) 49407c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49417c478bd9Sstevel@tonic-gate { 49427c478bd9Sstevel@tonic-gate dead = true; 49437c478bd9Sstevel@tonic-gate continue; 49447c478bd9Sstevel@tonic-gate } 49457c478bd9Sstevel@tonic-gate pos++; 494649218d4fSjbeck ostate = OSTATE_INLINE; 49477c478bd9Sstevel@tonic-gate } 49487c478bd9Sstevel@tonic-gate break; 49497c478bd9Sstevel@tonic-gate } 49507c478bd9Sstevel@tonic-gate } 49517c478bd9Sstevel@tonic-gate 49527c478bd9Sstevel@tonic-gate /* make sure we are at the beginning of a line */ 49537c478bd9Sstevel@tonic-gate if (bp > buf) 49547c478bd9Sstevel@tonic-gate { 49557c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49567c478bd9Sstevel@tonic-gate { 49577c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 49587c478bd9Sstevel@tonic-gate (void) sm_io_putc(TrafficLogFile, 49597c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49607c478bd9Sstevel@tonic-gate (unsigned char) *xp); 49617c478bd9Sstevel@tonic-gate } 49627c478bd9Sstevel@tonic-gate for (xp = buf; xp < bp; xp++) 49637c478bd9Sstevel@tonic-gate { 49647c478bd9Sstevel@tonic-gate if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 49657c478bd9Sstevel@tonic-gate (unsigned char) *xp) 49667c478bd9Sstevel@tonic-gate == SM_IO_EOF) 49677c478bd9Sstevel@tonic-gate { 49687c478bd9Sstevel@tonic-gate dead = true; 49697c478bd9Sstevel@tonic-gate break; 49707c478bd9Sstevel@tonic-gate } 49717c478bd9Sstevel@tonic-gate } 49727c478bd9Sstevel@tonic-gate pos += bp - buf; 49737c478bd9Sstevel@tonic-gate } 49747c478bd9Sstevel@tonic-gate if (!dead && pos > 0) 49757c478bd9Sstevel@tonic-gate { 49767c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL) 49777c478bd9Sstevel@tonic-gate (void) sm_io_fputs(TrafficLogFile, 49787c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 49797c478bd9Sstevel@tonic-gate mci->mci_mailer->m_eol); 4980*445f2479Sjbeck if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 4981*445f2479Sjbeck mci->mci_mailer->m_eol) == SM_IO_EOF) 4982*445f2479Sjbeck goto writeerr; 49837c478bd9Sstevel@tonic-gate } 49847c478bd9Sstevel@tonic-gate } 49857c478bd9Sstevel@tonic-gate 49867c478bd9Sstevel@tonic-gate if (sm_io_error(e->e_dfp)) 49877c478bd9Sstevel@tonic-gate { 49887c478bd9Sstevel@tonic-gate syserr("putbody: %s/%cf%s: read error", 49897c478bd9Sstevel@tonic-gate qid_printqueue(e->e_dfqgrp, e->e_dfqdir), 49907c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 49917c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 4992*445f2479Sjbeck ioerr = true; 49937c478bd9Sstevel@tonic-gate } 49947c478bd9Sstevel@tonic-gate 49957c478bd9Sstevel@tonic-gate endofmessage: 49967c478bd9Sstevel@tonic-gate /* 49977c478bd9Sstevel@tonic-gate ** Since mailfile() uses e_dfp in a child process, 49987c478bd9Sstevel@tonic-gate ** the file offset in the stdio library for the 49997c478bd9Sstevel@tonic-gate ** parent process will not agree with the in-kernel 50007c478bd9Sstevel@tonic-gate ** file offset since the file descriptor is shared 50017c478bd9Sstevel@tonic-gate ** between the processes. Therefore, it is vital 50027c478bd9Sstevel@tonic-gate ** that the file always be rewound. This forces the 50037c478bd9Sstevel@tonic-gate ** kernel offset (lseek) and stdio library (ftell) 50047c478bd9Sstevel@tonic-gate ** offset to match. 50057c478bd9Sstevel@tonic-gate */ 50067c478bd9Sstevel@tonic-gate 5007*445f2479Sjbeck save_errno = errno; 50087c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) 50097c478bd9Sstevel@tonic-gate (void) bfrewind(e->e_dfp); 50107c478bd9Sstevel@tonic-gate 50117c478bd9Sstevel@tonic-gate /* some mailers want extra blank line at end of message */ 50127c478bd9Sstevel@tonic-gate if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 50137c478bd9Sstevel@tonic-gate buf[0] != '\0' && buf[0] != '\n') 50147c478bd9Sstevel@tonic-gate { 5015*445f2479Sjbeck if (!putline("", mci)) 5016*445f2479Sjbeck goto writeerr; 5017*445f2479Sjbeck } 5018*445f2479Sjbeck 5019*445f2479Sjbeck if (!dead && 5020*445f2479Sjbeck (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF || 5021*445f2479Sjbeck (sm_io_error(mci->mci_out) && errno != EPIPE))) 5022*445f2479Sjbeck { 5023*445f2479Sjbeck save_errno = errno; 50247c478bd9Sstevel@tonic-gate syserr("putbody: write error"); 50257c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 5026*445f2479Sjbeck ioerr = true; 50277c478bd9Sstevel@tonic-gate } 50287c478bd9Sstevel@tonic-gate 5029*445f2479Sjbeck errno = save_errno; 5030*445f2479Sjbeck return !dead && !ioerr; 5031*445f2479Sjbeck 5032*445f2479Sjbeck writeerr: 5033*445f2479Sjbeck return false; 50347c478bd9Sstevel@tonic-gate } 5035*445f2479Sjbeck 50367c478bd9Sstevel@tonic-gate /* 50377c478bd9Sstevel@tonic-gate ** MAILFILE -- Send a message to a file. 50387c478bd9Sstevel@tonic-gate ** 50397c478bd9Sstevel@tonic-gate ** If the file has the set-user-ID/set-group-ID bits set, but NO 50407c478bd9Sstevel@tonic-gate ** execute bits, sendmail will try to become the owner of that file 50417c478bd9Sstevel@tonic-gate ** rather than the real user. Obviously, this only works if 50427c478bd9Sstevel@tonic-gate ** sendmail runs as root. 50437c478bd9Sstevel@tonic-gate ** 50447c478bd9Sstevel@tonic-gate ** This could be done as a subordinate mailer, except that it 50457c478bd9Sstevel@tonic-gate ** is used implicitly to save messages in ~/dead.letter. We 50467c478bd9Sstevel@tonic-gate ** view this as being sufficiently important as to include it 50477c478bd9Sstevel@tonic-gate ** here. For example, if the system is dying, we shouldn't have 50487c478bd9Sstevel@tonic-gate ** to create another process plus some pipes to save the message. 50497c478bd9Sstevel@tonic-gate ** 50507c478bd9Sstevel@tonic-gate ** Parameters: 50517c478bd9Sstevel@tonic-gate ** filename -- the name of the file to send to. 50527c478bd9Sstevel@tonic-gate ** mailer -- mailer definition for recipient -- if NULL, 50537c478bd9Sstevel@tonic-gate ** use FileMailer. 50547c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address header -- includes 50557c478bd9Sstevel@tonic-gate ** the userid/groupid to be when sending. 50567c478bd9Sstevel@tonic-gate ** sfflags -- flags for opening. 50577c478bd9Sstevel@tonic-gate ** e -- the current envelope. 50587c478bd9Sstevel@tonic-gate ** 50597c478bd9Sstevel@tonic-gate ** Returns: 50607c478bd9Sstevel@tonic-gate ** The exit code associated with the operation. 50617c478bd9Sstevel@tonic-gate ** 50627c478bd9Sstevel@tonic-gate ** Side Effects: 50637c478bd9Sstevel@tonic-gate ** none. 50647c478bd9Sstevel@tonic-gate */ 50657c478bd9Sstevel@tonic-gate 50667c478bd9Sstevel@tonic-gate # define RETURN(st) exit(st); 50677c478bd9Sstevel@tonic-gate 50687c478bd9Sstevel@tonic-gate static jmp_buf CtxMailfileTimeout; 50697c478bd9Sstevel@tonic-gate 50707c478bd9Sstevel@tonic-gate int 50717c478bd9Sstevel@tonic-gate mailfile(filename, mailer, ctladdr, sfflags, e) 50727c478bd9Sstevel@tonic-gate char *volatile filename; 50737c478bd9Sstevel@tonic-gate MAILER *volatile mailer; 50747c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 50757c478bd9Sstevel@tonic-gate volatile long sfflags; 50767c478bd9Sstevel@tonic-gate register ENVELOPE *e; 50777c478bd9Sstevel@tonic-gate { 50787c478bd9Sstevel@tonic-gate register SM_FILE_T *f; 50797c478bd9Sstevel@tonic-gate register pid_t pid = -1; 50807c478bd9Sstevel@tonic-gate volatile int mode; 50817c478bd9Sstevel@tonic-gate int len; 50827c478bd9Sstevel@tonic-gate off_t curoff; 50837c478bd9Sstevel@tonic-gate bool suidwarn = geteuid() == 0; 50847c478bd9Sstevel@tonic-gate char *p; 50857c478bd9Sstevel@tonic-gate char *volatile realfile; 50867c478bd9Sstevel@tonic-gate SM_EVENT *ev; 50877c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 50887c478bd9Sstevel@tonic-gate char targetfile[MAXPATHLEN]; 50897c478bd9Sstevel@tonic-gate 50907c478bd9Sstevel@tonic-gate if (tTd(11, 1)) 50917c478bd9Sstevel@tonic-gate { 50927c478bd9Sstevel@tonic-gate sm_dprintf("mailfile %s\n ctladdr=", filename); 50937c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 50947c478bd9Sstevel@tonic-gate } 50957c478bd9Sstevel@tonic-gate 50967c478bd9Sstevel@tonic-gate if (mailer == NULL) 50977c478bd9Sstevel@tonic-gate mailer = FileMailer; 50987c478bd9Sstevel@tonic-gate 50997c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 51007c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate /* 51037c478bd9Sstevel@tonic-gate ** Special case /dev/null. This allows us to restrict file 51047c478bd9Sstevel@tonic-gate ** delivery to regular files only. 51057c478bd9Sstevel@tonic-gate */ 51067c478bd9Sstevel@tonic-gate 51077c478bd9Sstevel@tonic-gate if (sm_path_isdevnull(filename)) 51087c478bd9Sstevel@tonic-gate return EX_OK; 51097c478bd9Sstevel@tonic-gate 51107c478bd9Sstevel@tonic-gate /* check for 8-bit available */ 51117c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 51127c478bd9Sstevel@tonic-gate bitnset(M_7BITS, mailer->m_flags) && 51137c478bd9Sstevel@tonic-gate (bitset(EF_DONT_MIME, e->e_flags) || 51147c478bd9Sstevel@tonic-gate !(bitset(MM_MIME8BIT, MimeMode) || 51157c478bd9Sstevel@tonic-gate (bitset(EF_IS_MIME, e->e_flags) && 51167c478bd9Sstevel@tonic-gate bitset(MM_CVTMIME, MimeMode))))) 51177c478bd9Sstevel@tonic-gate { 51187c478bd9Sstevel@tonic-gate e->e_status = "5.6.3"; 51197c478bd9Sstevel@tonic-gate usrerrenh(e->e_status, 51207c478bd9Sstevel@tonic-gate "554 Cannot send 8-bit data to 7-bit destination"); 51217c478bd9Sstevel@tonic-gate errno = 0; 51227c478bd9Sstevel@tonic-gate return EX_DATAERR; 51237c478bd9Sstevel@tonic-gate } 51247c478bd9Sstevel@tonic-gate 51257c478bd9Sstevel@tonic-gate /* Find the actual file */ 51267c478bd9Sstevel@tonic-gate if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 51277c478bd9Sstevel@tonic-gate { 51287c478bd9Sstevel@tonic-gate len = strlen(SafeFileEnv); 51297c478bd9Sstevel@tonic-gate 51307c478bd9Sstevel@tonic-gate if (strncmp(SafeFileEnv, filename, len) == 0) 51317c478bd9Sstevel@tonic-gate filename += len; 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate if (len + strlen(filename) + 1 >= sizeof targetfile) 51347c478bd9Sstevel@tonic-gate { 51357c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s/%s)", 51367c478bd9Sstevel@tonic-gate SafeFileEnv, filename); 51377c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51387c478bd9Sstevel@tonic-gate } 51397c478bd9Sstevel@tonic-gate (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile); 51407c478bd9Sstevel@tonic-gate realfile = targetfile + len; 51417c478bd9Sstevel@tonic-gate if (*filename == '/') 51427c478bd9Sstevel@tonic-gate filename++; 51437c478bd9Sstevel@tonic-gate if (*filename != '\0') 51447c478bd9Sstevel@tonic-gate { 51457c478bd9Sstevel@tonic-gate /* paranoia: trailing / should be removed in readcf */ 51467c478bd9Sstevel@tonic-gate if (targetfile[len - 1] != '/') 51477c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, 51487c478bd9Sstevel@tonic-gate "/", sizeof targetfile); 51497c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename, 51507c478bd9Sstevel@tonic-gate sizeof targetfile); 51517c478bd9Sstevel@tonic-gate } 51527c478bd9Sstevel@tonic-gate } 51537c478bd9Sstevel@tonic-gate else if (mailer->m_rootdir != NULL) 51547c478bd9Sstevel@tonic-gate { 51557c478bd9Sstevel@tonic-gate expand(mailer->m_rootdir, targetfile, sizeof targetfile, e); 51567c478bd9Sstevel@tonic-gate len = strlen(targetfile); 51577c478bd9Sstevel@tonic-gate 51587c478bd9Sstevel@tonic-gate if (strncmp(targetfile, filename, len) == 0) 51597c478bd9Sstevel@tonic-gate filename += len; 51607c478bd9Sstevel@tonic-gate 51617c478bd9Sstevel@tonic-gate if (len + strlen(filename) + 1 >= sizeof targetfile) 51627c478bd9Sstevel@tonic-gate { 51637c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s/%s)", 51647c478bd9Sstevel@tonic-gate targetfile, filename); 51657c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51667c478bd9Sstevel@tonic-gate } 51677c478bd9Sstevel@tonic-gate realfile = targetfile + len; 51687c478bd9Sstevel@tonic-gate if (targetfile[len - 1] != '/') 51697c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, "/", sizeof targetfile); 51707c478bd9Sstevel@tonic-gate if (*filename == '/') 51717c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename + 1, 51727c478bd9Sstevel@tonic-gate sizeof targetfile); 51737c478bd9Sstevel@tonic-gate else 51747c478bd9Sstevel@tonic-gate (void) sm_strlcat(targetfile, filename, 51757c478bd9Sstevel@tonic-gate sizeof targetfile); 51767c478bd9Sstevel@tonic-gate } 51777c478bd9Sstevel@tonic-gate else 51787c478bd9Sstevel@tonic-gate { 51797c478bd9Sstevel@tonic-gate if (sm_strlcpy(targetfile, filename, sizeof targetfile) >= 51807c478bd9Sstevel@tonic-gate sizeof targetfile) 51817c478bd9Sstevel@tonic-gate { 51827c478bd9Sstevel@tonic-gate syserr("mailfile: filename too long (%s)", filename); 51837c478bd9Sstevel@tonic-gate return EX_CANTCREAT; 51847c478bd9Sstevel@tonic-gate } 51857c478bd9Sstevel@tonic-gate realfile = targetfile; 51867c478bd9Sstevel@tonic-gate } 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate /* 51897c478bd9Sstevel@tonic-gate ** Fork so we can change permissions here. 51907c478bd9Sstevel@tonic-gate ** Note that we MUST use fork, not vfork, because of 51917c478bd9Sstevel@tonic-gate ** the complications of calling subroutines, etc. 51927c478bd9Sstevel@tonic-gate */ 51937c478bd9Sstevel@tonic-gate 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate /* 51967c478bd9Sstevel@tonic-gate ** Dispose of SIGCHLD signal catchers that may be laying 51977c478bd9Sstevel@tonic-gate ** around so that the waitfor() below will get it. 51987c478bd9Sstevel@tonic-gate */ 51997c478bd9Sstevel@tonic-gate 52007c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 52017c478bd9Sstevel@tonic-gate 52027c478bd9Sstevel@tonic-gate DOFORK(fork); 52037c478bd9Sstevel@tonic-gate 52047c478bd9Sstevel@tonic-gate if (pid < 0) 52057c478bd9Sstevel@tonic-gate return EX_OSERR; 52067c478bd9Sstevel@tonic-gate else if (pid == 0) 52077c478bd9Sstevel@tonic-gate { 52087c478bd9Sstevel@tonic-gate /* child -- actually write to file */ 52097c478bd9Sstevel@tonic-gate struct stat stb; 52107c478bd9Sstevel@tonic-gate MCI mcibuf; 52117c478bd9Sstevel@tonic-gate int err; 52127c478bd9Sstevel@tonic-gate volatile int oflags = O_WRONLY|O_APPEND; 52137c478bd9Sstevel@tonic-gate 52147c478bd9Sstevel@tonic-gate /* Reset global flags */ 52157c478bd9Sstevel@tonic-gate RestartRequest = NULL; 52167c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 52177c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 52187c478bd9Sstevel@tonic-gate PendingSignal = 0; 52197c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate if (e->e_lockfp != NULL) 52227c478bd9Sstevel@tonic-gate (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, 52237c478bd9Sstevel@tonic-gate NULL)); 52247c478bd9Sstevel@tonic-gate 52257c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, SIG_DFL); 52267c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, SIG_DFL); 52277c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, SIG_DFL); 52287c478bd9Sstevel@tonic-gate (void) umask(OldUmask); 52297c478bd9Sstevel@tonic-gate e->e_to = filename; 52307c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 52317c478bd9Sstevel@tonic-gate 52327c478bd9Sstevel@tonic-gate if (setjmp(CtxMailfileTimeout) != 0) 52337c478bd9Sstevel@tonic-gate { 52347c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 52357c478bd9Sstevel@tonic-gate } 52367c478bd9Sstevel@tonic-gate 52377c478bd9Sstevel@tonic-gate if (TimeOuts.to_fileopen > 0) 52387c478bd9Sstevel@tonic-gate ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout, 52397c478bd9Sstevel@tonic-gate 0); 52407c478bd9Sstevel@tonic-gate else 52417c478bd9Sstevel@tonic-gate ev = NULL; 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate /* check file mode to see if set-user-ID */ 52447c478bd9Sstevel@tonic-gate if (stat(targetfile, &stb) < 0) 52457c478bd9Sstevel@tonic-gate mode = FileMode; 52467c478bd9Sstevel@tonic-gate else 52477c478bd9Sstevel@tonic-gate mode = stb.st_mode; 52487c478bd9Sstevel@tonic-gate 52497c478bd9Sstevel@tonic-gate /* limit the errors to those actually caused in the child */ 52507c478bd9Sstevel@tonic-gate errno = 0; 52517c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 52527c478bd9Sstevel@tonic-gate 52537c478bd9Sstevel@tonic-gate /* Allow alias expansions to use the S_IS{U,G}ID bits */ 52547c478bd9Sstevel@tonic-gate if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) || 52557c478bd9Sstevel@tonic-gate bitset(SFF_RUNASREALUID, sfflags)) 52567c478bd9Sstevel@tonic-gate { 52577c478bd9Sstevel@tonic-gate /* ignore set-user-ID and set-group-ID bits */ 52587c478bd9Sstevel@tonic-gate mode &= ~(S_ISGID|S_ISUID); 52597c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 52607c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n"); 52617c478bd9Sstevel@tonic-gate } 52627c478bd9Sstevel@tonic-gate 52637c478bd9Sstevel@tonic-gate /* we have to open the data file BEFORE setuid() */ 52647c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 52657c478bd9Sstevel@tonic-gate { 52667c478bd9Sstevel@tonic-gate char *df = queuename(e, DATAFL_LETTER); 52677c478bd9Sstevel@tonic-gate 52687c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df, 52697c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL); 52707c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 52717c478bd9Sstevel@tonic-gate { 52727c478bd9Sstevel@tonic-gate syserr("mailfile: Cannot open %s for %s from %s", 52737c478bd9Sstevel@tonic-gate df, e->e_to, e->e_from.q_paddr); 52747c478bd9Sstevel@tonic-gate } 52757c478bd9Sstevel@tonic-gate } 52767c478bd9Sstevel@tonic-gate 52777c478bd9Sstevel@tonic-gate /* select a new user to run as */ 52787c478bd9Sstevel@tonic-gate if (!bitset(SFF_RUNASREALUID, sfflags)) 52797c478bd9Sstevel@tonic-gate { 52807c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 52817c478bd9Sstevel@tonic-gate { 52827c478bd9Sstevel@tonic-gate RealUserName = NULL; 52837c478bd9Sstevel@tonic-gate if (mailer->m_uid == NO_UID) 52847c478bd9Sstevel@tonic-gate RealUid = RunAsUid; 52857c478bd9Sstevel@tonic-gate else 52867c478bd9Sstevel@tonic-gate RealUid = mailer->m_uid; 52877c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && RealUid != RunAsUid) 52887c478bd9Sstevel@tonic-gate { 52897c478bd9Sstevel@tonic-gate /* Only root can change the uid */ 52907c478bd9Sstevel@tonic-gate syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", 52917c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) RealUid); 52927c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 52937c478bd9Sstevel@tonic-gate } 52947c478bd9Sstevel@tonic-gate } 52957c478bd9Sstevel@tonic-gate else if (bitset(S_ISUID, mode)) 52967c478bd9Sstevel@tonic-gate { 52977c478bd9Sstevel@tonic-gate RealUserName = NULL; 52987c478bd9Sstevel@tonic-gate RealUid = stb.st_uid; 52997c478bd9Sstevel@tonic-gate } 53007c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_uid != 0) 53017c478bd9Sstevel@tonic-gate { 53027c478bd9Sstevel@tonic-gate if (ctladdr->q_ruser != NULL) 53037c478bd9Sstevel@tonic-gate RealUserName = ctladdr->q_ruser; 53047c478bd9Sstevel@tonic-gate else 53057c478bd9Sstevel@tonic-gate RealUserName = ctladdr->q_user; 53067c478bd9Sstevel@tonic-gate RealUid = ctladdr->q_uid; 53077c478bd9Sstevel@tonic-gate } 53087c478bd9Sstevel@tonic-gate else if (mailer != NULL && mailer->m_uid != NO_UID) 53097c478bd9Sstevel@tonic-gate { 53107c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53117c478bd9Sstevel@tonic-gate RealUid = mailer->m_uid; 53127c478bd9Sstevel@tonic-gate } 53137c478bd9Sstevel@tonic-gate else 53147c478bd9Sstevel@tonic-gate { 53157c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53167c478bd9Sstevel@tonic-gate RealUid = DefUid; 53177c478bd9Sstevel@tonic-gate } 53187c478bd9Sstevel@tonic-gate 53197c478bd9Sstevel@tonic-gate /* select a new group to run as */ 53207c478bd9Sstevel@tonic-gate if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) 53217c478bd9Sstevel@tonic-gate { 53227c478bd9Sstevel@tonic-gate if (mailer->m_gid == NO_GID) 53237c478bd9Sstevel@tonic-gate RealGid = RunAsGid; 53247c478bd9Sstevel@tonic-gate else 53257c478bd9Sstevel@tonic-gate RealGid = mailer->m_gid; 53267c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && 53277c478bd9Sstevel@tonic-gate (RealGid != getgid() || 53287c478bd9Sstevel@tonic-gate RealGid != getegid())) 53297c478bd9Sstevel@tonic-gate { 53307c478bd9Sstevel@tonic-gate /* Only root can change the gid */ 53317c478bd9Sstevel@tonic-gate syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", 53327c478bd9Sstevel@tonic-gate (int) RealGid, (int) RunAsUid, 53337c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 53347c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53357c478bd9Sstevel@tonic-gate } 53367c478bd9Sstevel@tonic-gate } 53377c478bd9Sstevel@tonic-gate else if (bitset(S_ISGID, mode)) 53387c478bd9Sstevel@tonic-gate RealGid = stb.st_gid; 53397c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && 53407c478bd9Sstevel@tonic-gate ctladdr->q_uid == DefUid && 53417c478bd9Sstevel@tonic-gate ctladdr->q_gid == 0) 53427c478bd9Sstevel@tonic-gate { 53437c478bd9Sstevel@tonic-gate /* 53447c478bd9Sstevel@tonic-gate ** Special case: This means it is an 53457c478bd9Sstevel@tonic-gate ** alias and we should act as DefaultUser. 53467c478bd9Sstevel@tonic-gate ** See alias()'s comments. 53477c478bd9Sstevel@tonic-gate */ 53487c478bd9Sstevel@tonic-gate 53497c478bd9Sstevel@tonic-gate RealGid = DefGid; 53507c478bd9Sstevel@tonic-gate RealUserName = DefUser; 53517c478bd9Sstevel@tonic-gate } 53527c478bd9Sstevel@tonic-gate else if (ctladdr != NULL && ctladdr->q_uid != 0) 53537c478bd9Sstevel@tonic-gate RealGid = ctladdr->q_gid; 53547c478bd9Sstevel@tonic-gate else if (mailer != NULL && mailer->m_gid != NO_GID) 53557c478bd9Sstevel@tonic-gate RealGid = mailer->m_gid; 53567c478bd9Sstevel@tonic-gate else 53577c478bd9Sstevel@tonic-gate RealGid = DefGid; 53587c478bd9Sstevel@tonic-gate } 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate /* last ditch */ 53617c478bd9Sstevel@tonic-gate if (!bitset(SFF_ROOTOK, sfflags)) 53627c478bd9Sstevel@tonic-gate { 53637c478bd9Sstevel@tonic-gate if (RealUid == 0) 53647c478bd9Sstevel@tonic-gate RealUid = DefUid; 53657c478bd9Sstevel@tonic-gate if (RealGid == 0) 53667c478bd9Sstevel@tonic-gate RealGid = DefGid; 53677c478bd9Sstevel@tonic-gate } 53687c478bd9Sstevel@tonic-gate 53697c478bd9Sstevel@tonic-gate /* set group id list (needs /etc/group access) */ 53707c478bd9Sstevel@tonic-gate if (RealUserName != NULL && !DontInitGroups) 53717c478bd9Sstevel@tonic-gate { 53727c478bd9Sstevel@tonic-gate if (initgroups(RealUserName, RealGid) == -1 && suidwarn) 53737c478bd9Sstevel@tonic-gate { 53747c478bd9Sstevel@tonic-gate syserr("mailfile: initgroups(%s, %d) failed", 53757c478bd9Sstevel@tonic-gate RealUserName, RealGid); 53767c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53777c478bd9Sstevel@tonic-gate } 53787c478bd9Sstevel@tonic-gate } 53797c478bd9Sstevel@tonic-gate else 53807c478bd9Sstevel@tonic-gate { 53817c478bd9Sstevel@tonic-gate GIDSET_T gidset[1]; 53827c478bd9Sstevel@tonic-gate 53837c478bd9Sstevel@tonic-gate gidset[0] = RealGid; 53847c478bd9Sstevel@tonic-gate if (setgroups(1, gidset) == -1 && suidwarn) 53857c478bd9Sstevel@tonic-gate { 53867c478bd9Sstevel@tonic-gate syserr("mailfile: setgroups() failed"); 53877c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 53887c478bd9Sstevel@tonic-gate } 53897c478bd9Sstevel@tonic-gate } 53907c478bd9Sstevel@tonic-gate 53917c478bd9Sstevel@tonic-gate /* 53927c478bd9Sstevel@tonic-gate ** If you have a safe environment, go into it. 53937c478bd9Sstevel@tonic-gate */ 53947c478bd9Sstevel@tonic-gate 53957c478bd9Sstevel@tonic-gate if (realfile != targetfile) 53967c478bd9Sstevel@tonic-gate { 53977c478bd9Sstevel@tonic-gate char save; 53987c478bd9Sstevel@tonic-gate 53997c478bd9Sstevel@tonic-gate save = *realfile; 54007c478bd9Sstevel@tonic-gate *realfile = '\0'; 54017c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 54027c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: chroot %s\n", targetfile); 54037c478bd9Sstevel@tonic-gate if (chroot(targetfile) < 0) 54047c478bd9Sstevel@tonic-gate { 54057c478bd9Sstevel@tonic-gate syserr("mailfile: Cannot chroot(%s)", 54067c478bd9Sstevel@tonic-gate targetfile); 54077c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 54087c478bd9Sstevel@tonic-gate } 54097c478bd9Sstevel@tonic-gate *realfile = save; 54107c478bd9Sstevel@tonic-gate } 54117c478bd9Sstevel@tonic-gate 54127c478bd9Sstevel@tonic-gate if (tTd(11, 40)) 54137c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: deliver to %s\n", realfile); 54147c478bd9Sstevel@tonic-gate 54157c478bd9Sstevel@tonic-gate if (chdir("/") < 0) 54167c478bd9Sstevel@tonic-gate { 54177c478bd9Sstevel@tonic-gate syserr("mailfile: cannot chdir(/)"); 54187c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 54197c478bd9Sstevel@tonic-gate } 54207c478bd9Sstevel@tonic-gate 54217c478bd9Sstevel@tonic-gate /* now reset the group and user ids */ 54227c478bd9Sstevel@tonic-gate endpwent(); 54237c478bd9Sstevel@tonic-gate sm_mbdb_terminate(); 54247c478bd9Sstevel@tonic-gate if (setgid(RealGid) < 0 && suidwarn) 54257c478bd9Sstevel@tonic-gate { 54267c478bd9Sstevel@tonic-gate syserr("mailfile: setgid(%ld) failed", (long) RealGid); 54277c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 54287c478bd9Sstevel@tonic-gate } 54297c478bd9Sstevel@tonic-gate vendor_set_uid(RealUid); 54307c478bd9Sstevel@tonic-gate if (setuid(RealUid) < 0 && suidwarn) 54317c478bd9Sstevel@tonic-gate { 54327c478bd9Sstevel@tonic-gate syserr("mailfile: setuid(%ld) failed", (long) RealUid); 54337c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 54347c478bd9Sstevel@tonic-gate } 54357c478bd9Sstevel@tonic-gate 54367c478bd9Sstevel@tonic-gate if (tTd(11, 2)) 54377c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", 54387c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid(), 54397c478bd9Sstevel@tonic-gate (int) getgid(), (int) getegid()); 54407c478bd9Sstevel@tonic-gate 54417c478bd9Sstevel@tonic-gate 54427c478bd9Sstevel@tonic-gate /* move into some "safe" directory */ 54437c478bd9Sstevel@tonic-gate if (mailer->m_execdir != NULL) 54447c478bd9Sstevel@tonic-gate { 54457c478bd9Sstevel@tonic-gate char *q; 54467c478bd9Sstevel@tonic-gate 54477c478bd9Sstevel@tonic-gate for (p = mailer->m_execdir; p != NULL; p = q) 54487c478bd9Sstevel@tonic-gate { 54497c478bd9Sstevel@tonic-gate q = strchr(p, ':'); 54507c478bd9Sstevel@tonic-gate if (q != NULL) 54517c478bd9Sstevel@tonic-gate *q = '\0'; 54527c478bd9Sstevel@tonic-gate expand(p, buf, sizeof buf, e); 54537c478bd9Sstevel@tonic-gate if (q != NULL) 54547c478bd9Sstevel@tonic-gate *q++ = ':'; 54557c478bd9Sstevel@tonic-gate if (tTd(11, 20)) 54567c478bd9Sstevel@tonic-gate sm_dprintf("mailfile: trydir %s\n", 54577c478bd9Sstevel@tonic-gate buf); 54587c478bd9Sstevel@tonic-gate if (buf[0] != '\0' && chdir(buf) >= 0) 54597c478bd9Sstevel@tonic-gate break; 54607c478bd9Sstevel@tonic-gate } 54617c478bd9Sstevel@tonic-gate } 54627c478bd9Sstevel@tonic-gate 54637c478bd9Sstevel@tonic-gate /* 54647c478bd9Sstevel@tonic-gate ** Recheck the file after we have assumed the ID of the 54657c478bd9Sstevel@tonic-gate ** delivery user to make sure we can deliver to it as 54667c478bd9Sstevel@tonic-gate ** that user. This is necessary if sendmail is running 54677c478bd9Sstevel@tonic-gate ** as root and the file is on an NFS mount which treats 54687c478bd9Sstevel@tonic-gate ** root as nobody. 54697c478bd9Sstevel@tonic-gate */ 54707c478bd9Sstevel@tonic-gate 54717c478bd9Sstevel@tonic-gate #if HASLSTAT 54727c478bd9Sstevel@tonic-gate if (bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 54737c478bd9Sstevel@tonic-gate err = stat(realfile, &stb); 54747c478bd9Sstevel@tonic-gate else 54757c478bd9Sstevel@tonic-gate err = lstat(realfile, &stb); 54767c478bd9Sstevel@tonic-gate #else /* HASLSTAT */ 54777c478bd9Sstevel@tonic-gate err = stat(realfile, &stb); 54787c478bd9Sstevel@tonic-gate #endif /* HASLSTAT */ 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate if (err < 0) 54817c478bd9Sstevel@tonic-gate { 54827c478bd9Sstevel@tonic-gate stb.st_mode = ST_MODE_NOFILE; 54837c478bd9Sstevel@tonic-gate mode = FileMode; 54847c478bd9Sstevel@tonic-gate oflags |= O_CREAT|O_EXCL; 54857c478bd9Sstevel@tonic-gate } 54867c478bd9Sstevel@tonic-gate else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, mode) || 54877c478bd9Sstevel@tonic-gate (!bitnset(DBS_FILEDELIVERYTOHARDLINK, 54887c478bd9Sstevel@tonic-gate DontBlameSendmail) && 54897c478bd9Sstevel@tonic-gate stb.st_nlink != 1) || 54907c478bd9Sstevel@tonic-gate (realfile != targetfile && !S_ISREG(mode))) 54917c478bd9Sstevel@tonic-gate exit(EX_CANTCREAT); 54927c478bd9Sstevel@tonic-gate else 54937c478bd9Sstevel@tonic-gate mode = stb.st_mode; 54947c478bd9Sstevel@tonic-gate 54957c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 54967c478bd9Sstevel@tonic-gate sfflags |= SFF_NOSLINK; 54977c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 54987c478bd9Sstevel@tonic-gate sfflags |= SFF_NOHLINK; 54997c478bd9Sstevel@tonic-gate sfflags &= ~SFF_OPENASROOT; 55007c478bd9Sstevel@tonic-gate f = safefopen(realfile, oflags, mode, sfflags); 55017c478bd9Sstevel@tonic-gate if (f == NULL) 55027c478bd9Sstevel@tonic-gate { 55037c478bd9Sstevel@tonic-gate if (transienterror(errno)) 55047c478bd9Sstevel@tonic-gate { 55057c478bd9Sstevel@tonic-gate usrerr("454 4.3.0 cannot open %s: %s", 55067c478bd9Sstevel@tonic-gate shortenstring(realfile, MAXSHORTSTR), 55077c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55087c478bd9Sstevel@tonic-gate RETURN(EX_TEMPFAIL); 55097c478bd9Sstevel@tonic-gate } 55107c478bd9Sstevel@tonic-gate else 55117c478bd9Sstevel@tonic-gate { 55127c478bd9Sstevel@tonic-gate usrerr("554 5.3.0 cannot open %s: %s", 55137c478bd9Sstevel@tonic-gate shortenstring(realfile, MAXSHORTSTR), 55147c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55157c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55167c478bd9Sstevel@tonic-gate } 55177c478bd9Sstevel@tonic-gate } 55187c478bd9Sstevel@tonic-gate if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55197c478bd9Sstevel@tonic-gate &stb)) 55207c478bd9Sstevel@tonic-gate { 55217c478bd9Sstevel@tonic-gate syserr("554 5.3.0 file changed after open"); 55227c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55237c478bd9Sstevel@tonic-gate } 55247c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0) 55257c478bd9Sstevel@tonic-gate { 55267c478bd9Sstevel@tonic-gate syserr("554 5.3.0 cannot fstat %s", 55277c478bd9Sstevel@tonic-gate sm_errstring(errno)); 55287c478bd9Sstevel@tonic-gate RETURN(EX_CANTCREAT); 55297c478bd9Sstevel@tonic-gate } 55307c478bd9Sstevel@tonic-gate 55317c478bd9Sstevel@tonic-gate curoff = stb.st_size; 55327c478bd9Sstevel@tonic-gate 55337c478bd9Sstevel@tonic-gate if (ev != NULL) 55347c478bd9Sstevel@tonic-gate sm_clrevent(ev); 55357c478bd9Sstevel@tonic-gate 55367c478bd9Sstevel@tonic-gate memset(&mcibuf, '\0', sizeof mcibuf); 55377c478bd9Sstevel@tonic-gate mcibuf.mci_mailer = mailer; 55387c478bd9Sstevel@tonic-gate mcibuf.mci_out = f; 55397c478bd9Sstevel@tonic-gate if (bitnset(M_7BITS, mailer->m_flags)) 55407c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_7BIT; 55417c478bd9Sstevel@tonic-gate 55427c478bd9Sstevel@tonic-gate /* clear out per-message flags from connection structure */ 55437c478bd9Sstevel@tonic-gate mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7); 55447c478bd9Sstevel@tonic-gate 55457c478bd9Sstevel@tonic-gate if (bitset(EF_HAS8BIT, e->e_flags) && 55467c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) && 55477c478bd9Sstevel@tonic-gate bitnset(M_7BITS, mailer->m_flags)) 55487c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_CVT8TO7; 55497c478bd9Sstevel@tonic-gate 55507c478bd9Sstevel@tonic-gate #if MIME7TO8 55517c478bd9Sstevel@tonic-gate if (bitnset(M_MAKE8BIT, mailer->m_flags) && 55527c478bd9Sstevel@tonic-gate !bitset(MCIF_7BIT, mcibuf.mci_flags) && 55537c478bd9Sstevel@tonic-gate (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && 55547c478bd9Sstevel@tonic-gate (sm_strcasecmp(p, "quoted-printable") == 0 || 55557c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "base64") == 0) && 55567c478bd9Sstevel@tonic-gate (p = hvalue("Content-Type", e->e_header)) != NULL) 55577c478bd9Sstevel@tonic-gate { 55587c478bd9Sstevel@tonic-gate /* may want to convert 7 -> 8 */ 55597c478bd9Sstevel@tonic-gate /* XXX should really parse it here -- and use a class XXX */ 55607c478bd9Sstevel@tonic-gate if (sm_strncasecmp(p, "text/plain", 10) == 0 && 55617c478bd9Sstevel@tonic-gate (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) 55627c478bd9Sstevel@tonic-gate mcibuf.mci_flags |= MCIF_CVT7TO8; 55637c478bd9Sstevel@tonic-gate } 55647c478bd9Sstevel@tonic-gate #endif /* MIME7TO8 */ 55657c478bd9Sstevel@tonic-gate 5566*445f2479Sjbeck if (!putfromline(&mcibuf, e) || 5567*445f2479Sjbeck !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) || 5568*445f2479Sjbeck !(*e->e_putbody)(&mcibuf, e, NULL) || 5569*445f2479Sjbeck !putline("\n", &mcibuf) || 5570*445f2479Sjbeck (sm_io_flush(f, SM_TIME_DEFAULT) != 0 || 55717c478bd9Sstevel@tonic-gate (SuperSafe != SAFE_NO && 55727c478bd9Sstevel@tonic-gate fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) || 5573*445f2479Sjbeck sm_io_error(f))) 55747c478bd9Sstevel@tonic-gate { 55757c478bd9Sstevel@tonic-gate setstat(EX_IOERR); 55767c478bd9Sstevel@tonic-gate #if !NOFTRUNCATE 55777c478bd9Sstevel@tonic-gate (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55787c478bd9Sstevel@tonic-gate curoff); 55797c478bd9Sstevel@tonic-gate #endif /* !NOFTRUNCATE */ 55807c478bd9Sstevel@tonic-gate } 55817c478bd9Sstevel@tonic-gate 55827c478bd9Sstevel@tonic-gate /* reset ISUID & ISGID bits for paranoid systems */ 55837c478bd9Sstevel@tonic-gate #if HASFCHMOD 55847c478bd9Sstevel@tonic-gate (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), 55857c478bd9Sstevel@tonic-gate (MODE_T) mode); 55867c478bd9Sstevel@tonic-gate #else /* HASFCHMOD */ 55877c478bd9Sstevel@tonic-gate (void) chmod(filename, (MODE_T) mode); 55887c478bd9Sstevel@tonic-gate #endif /* HASFCHMOD */ 55897c478bd9Sstevel@tonic-gate if (sm_io_close(f, SM_TIME_DEFAULT) < 0) 55907c478bd9Sstevel@tonic-gate setstat(EX_IOERR); 55917c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 55927c478bd9Sstevel@tonic-gate (void) setuid(RealUid); 55937c478bd9Sstevel@tonic-gate exit(ExitStat); 55947c478bd9Sstevel@tonic-gate /* NOTREACHED */ 55957c478bd9Sstevel@tonic-gate } 55967c478bd9Sstevel@tonic-gate else 55977c478bd9Sstevel@tonic-gate { 55987c478bd9Sstevel@tonic-gate /* parent -- wait for exit status */ 55997c478bd9Sstevel@tonic-gate int st; 56007c478bd9Sstevel@tonic-gate 56017c478bd9Sstevel@tonic-gate st = waitfor(pid); 56027c478bd9Sstevel@tonic-gate if (st == -1) 56037c478bd9Sstevel@tonic-gate { 56047c478bd9Sstevel@tonic-gate syserr("mailfile: %s: wait", mailer->m_name); 56057c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 56067c478bd9Sstevel@tonic-gate } 56077c478bd9Sstevel@tonic-gate if (WIFEXITED(st)) 56087c478bd9Sstevel@tonic-gate { 56097c478bd9Sstevel@tonic-gate errno = 0; 56107c478bd9Sstevel@tonic-gate return (WEXITSTATUS(st)); 56117c478bd9Sstevel@tonic-gate } 56127c478bd9Sstevel@tonic-gate else 56137c478bd9Sstevel@tonic-gate { 56147c478bd9Sstevel@tonic-gate syserr("mailfile: %s: child died on signal %d", 56157c478bd9Sstevel@tonic-gate mailer->m_name, st); 56167c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE; 56177c478bd9Sstevel@tonic-gate } 56187c478bd9Sstevel@tonic-gate /* NOTREACHED */ 56197c478bd9Sstevel@tonic-gate } 56207c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ 56217c478bd9Sstevel@tonic-gate } 56227c478bd9Sstevel@tonic-gate 56237c478bd9Sstevel@tonic-gate static void 56247c478bd9Sstevel@tonic-gate mailfiletimeout(ignore) 56257c478bd9Sstevel@tonic-gate int ignore; 56267c478bd9Sstevel@tonic-gate { 56277c478bd9Sstevel@tonic-gate /* 56287c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 56297c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 56307c478bd9Sstevel@tonic-gate ** DOING. 56317c478bd9Sstevel@tonic-gate */ 56327c478bd9Sstevel@tonic-gate 56337c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 56347c478bd9Sstevel@tonic-gate longjmp(CtxMailfileTimeout, 1); 56357c478bd9Sstevel@tonic-gate } 56367c478bd9Sstevel@tonic-gate /* 56377c478bd9Sstevel@tonic-gate ** HOSTSIGNATURE -- return the "signature" for a host. 56387c478bd9Sstevel@tonic-gate ** 56397c478bd9Sstevel@tonic-gate ** The signature describes how we are going to send this -- it 56407c478bd9Sstevel@tonic-gate ** can be just the hostname (for non-Internet hosts) or can be 56417c478bd9Sstevel@tonic-gate ** an ordered list of MX hosts. 56427c478bd9Sstevel@tonic-gate ** 56437c478bd9Sstevel@tonic-gate ** Parameters: 56447c478bd9Sstevel@tonic-gate ** m -- the mailer describing this host. 56457c478bd9Sstevel@tonic-gate ** host -- the host name. 56467c478bd9Sstevel@tonic-gate ** 56477c478bd9Sstevel@tonic-gate ** Returns: 56487c478bd9Sstevel@tonic-gate ** The signature for this host. 56497c478bd9Sstevel@tonic-gate ** 56507c478bd9Sstevel@tonic-gate ** Side Effects: 56517c478bd9Sstevel@tonic-gate ** Can tweak the symbol table. 56527c478bd9Sstevel@tonic-gate */ 56537c478bd9Sstevel@tonic-gate 56547c478bd9Sstevel@tonic-gate #define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */ 56557c478bd9Sstevel@tonic-gate 56567c478bd9Sstevel@tonic-gate char * 56577c478bd9Sstevel@tonic-gate hostsignature(m, host) 56587c478bd9Sstevel@tonic-gate register MAILER *m; 56597c478bd9Sstevel@tonic-gate char *host; 56607c478bd9Sstevel@tonic-gate { 56617c478bd9Sstevel@tonic-gate register char *p; 56627c478bd9Sstevel@tonic-gate register STAB *s; 56637c478bd9Sstevel@tonic-gate time_t now; 56647c478bd9Sstevel@tonic-gate #if NAMED_BIND 56657c478bd9Sstevel@tonic-gate char sep = ':'; 56667c478bd9Sstevel@tonic-gate char prevsep = ':'; 56677c478bd9Sstevel@tonic-gate int i; 56687c478bd9Sstevel@tonic-gate int len; 56697c478bd9Sstevel@tonic-gate int nmx; 56707c478bd9Sstevel@tonic-gate int hl; 56717c478bd9Sstevel@tonic-gate char *hp; 56727c478bd9Sstevel@tonic-gate char *endp; 56737c478bd9Sstevel@tonic-gate int oldoptions = _res.options; 56747c478bd9Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 56757c478bd9Sstevel@tonic-gate unsigned short mxprefs[MAXMXHOSTS + 1]; 56767c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 56777c478bd9Sstevel@tonic-gate 56787c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 56797c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(%s)\n", host); 56807c478bd9Sstevel@tonic-gate 56817c478bd9Sstevel@tonic-gate /* 56827c478bd9Sstevel@tonic-gate ** If local delivery (and not remote), just return a constant. 56837c478bd9Sstevel@tonic-gate */ 56847c478bd9Sstevel@tonic-gate 56857c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, m->m_flags) && 56867c478bd9Sstevel@tonic-gate strcmp(m->m_mailer, "[IPC]") != 0 && 56877c478bd9Sstevel@tonic-gate !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0)) 56887c478bd9Sstevel@tonic-gate return "localhost"; 56897c478bd9Sstevel@tonic-gate 56907c478bd9Sstevel@tonic-gate /* an empty host does not have MX records */ 56917c478bd9Sstevel@tonic-gate if (*host == '\0') 56927c478bd9Sstevel@tonic-gate return "_empty_"; 56937c478bd9Sstevel@tonic-gate 56947c478bd9Sstevel@tonic-gate /* 56957c478bd9Sstevel@tonic-gate ** Check to see if this uses IPC -- if not, it can't have MX records. 56967c478bd9Sstevel@tonic-gate */ 56977c478bd9Sstevel@tonic-gate 56987c478bd9Sstevel@tonic-gate if (strcmp(m->m_mailer, "[IPC]") != 0 || 56997c478bd9Sstevel@tonic-gate CurEnv->e_sendmode == SM_DEFER) 57007c478bd9Sstevel@tonic-gate { 57017c478bd9Sstevel@tonic-gate /* just an ordinary mailer or deferred mode */ 57027c478bd9Sstevel@tonic-gate return host; 57037c478bd9Sstevel@tonic-gate } 57047c478bd9Sstevel@tonic-gate #if NETUNIX 57057c478bd9Sstevel@tonic-gate else if (m->m_argv[0] != NULL && 57067c478bd9Sstevel@tonic-gate strcmp(m->m_argv[0], "FILE") == 0) 57077c478bd9Sstevel@tonic-gate { 57087c478bd9Sstevel@tonic-gate /* rendezvous in the file system, no MX records */ 57097c478bd9Sstevel@tonic-gate return host; 57107c478bd9Sstevel@tonic-gate } 57117c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 57127c478bd9Sstevel@tonic-gate 57137c478bd9Sstevel@tonic-gate /* 57147c478bd9Sstevel@tonic-gate ** Look it up in the symbol table. 57157c478bd9Sstevel@tonic-gate */ 57167c478bd9Sstevel@tonic-gate 57177c478bd9Sstevel@tonic-gate now = curtime(); 57187c478bd9Sstevel@tonic-gate s = stab(host, ST_HOSTSIG, ST_ENTER); 57197c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 57207c478bd9Sstevel@tonic-gate { 57217c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_exp >= now) 57227c478bd9Sstevel@tonic-gate { 57237c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 57247c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(): stab(%s) found %s\n", host, 57257c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig); 57267c478bd9Sstevel@tonic-gate return s->s_hostsig.hs_sig; 57277c478bd9Sstevel@tonic-gate } 57287c478bd9Sstevel@tonic-gate 57297c478bd9Sstevel@tonic-gate /* signature is expired: clear it */ 57307c478bd9Sstevel@tonic-gate sm_free(s->s_hostsig.hs_sig); 57317c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = NULL; 57327c478bd9Sstevel@tonic-gate } 57337c478bd9Sstevel@tonic-gate 57347c478bd9Sstevel@tonic-gate /* set default TTL */ 57357c478bd9Sstevel@tonic-gate s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL; 57367c478bd9Sstevel@tonic-gate 57377c478bd9Sstevel@tonic-gate /* 57387c478bd9Sstevel@tonic-gate ** Not already there or expired -- create a signature. 57397c478bd9Sstevel@tonic-gate */ 57407c478bd9Sstevel@tonic-gate 57417c478bd9Sstevel@tonic-gate #if NAMED_BIND 57427c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 57437c478bd9Sstevel@tonic-gate _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 57447c478bd9Sstevel@tonic-gate 57457c478bd9Sstevel@tonic-gate for (hp = host; hp != NULL; hp = endp) 57467c478bd9Sstevel@tonic-gate { 57477c478bd9Sstevel@tonic-gate #if NETINET6 57487c478bd9Sstevel@tonic-gate if (*hp == '[') 57497c478bd9Sstevel@tonic-gate { 57507c478bd9Sstevel@tonic-gate endp = strchr(hp + 1, ']'); 57517c478bd9Sstevel@tonic-gate if (endp != NULL) 57527c478bd9Sstevel@tonic-gate endp = strpbrk(endp + 1, ":,"); 57537c478bd9Sstevel@tonic-gate } 57547c478bd9Sstevel@tonic-gate else 57557c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 57567c478bd9Sstevel@tonic-gate #else /* NETINET6 */ 57577c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 57587c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 57597c478bd9Sstevel@tonic-gate if (endp != NULL) 57607c478bd9Sstevel@tonic-gate { 57617c478bd9Sstevel@tonic-gate sep = *endp; 57627c478bd9Sstevel@tonic-gate *endp = '\0'; 57637c478bd9Sstevel@tonic-gate } 57647c478bd9Sstevel@tonic-gate 57657c478bd9Sstevel@tonic-gate if (bitnset(M_NOMX, m->m_flags)) 57667c478bd9Sstevel@tonic-gate { 57677c478bd9Sstevel@tonic-gate /* skip MX lookups */ 57687c478bd9Sstevel@tonic-gate nmx = 1; 57697c478bd9Sstevel@tonic-gate mxhosts[0] = hp; 57707c478bd9Sstevel@tonic-gate } 57717c478bd9Sstevel@tonic-gate else 57727c478bd9Sstevel@tonic-gate { 57737c478bd9Sstevel@tonic-gate auto int rcode; 57747c478bd9Sstevel@tonic-gate int ttl; 57757c478bd9Sstevel@tonic-gate 57767c478bd9Sstevel@tonic-gate nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true, 57777c478bd9Sstevel@tonic-gate &ttl); 57787c478bd9Sstevel@tonic-gate if (nmx <= 0) 57797c478bd9Sstevel@tonic-gate { 57807c478bd9Sstevel@tonic-gate int save_errno; 57817c478bd9Sstevel@tonic-gate register MCI *mci; 57827c478bd9Sstevel@tonic-gate 57837c478bd9Sstevel@tonic-gate /* update the connection info for this host */ 57847c478bd9Sstevel@tonic-gate save_errno = errno; 57857c478bd9Sstevel@tonic-gate mci = mci_get(hp, m); 57867c478bd9Sstevel@tonic-gate mci->mci_errno = save_errno; 57877c478bd9Sstevel@tonic-gate mci->mci_herrno = h_errno; 57887c478bd9Sstevel@tonic-gate mci->mci_lastuse = now; 57897c478bd9Sstevel@tonic-gate if (rcode == EX_NOHOST) 57907c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, "5.1.2", 57917c478bd9Sstevel@tonic-gate "550 Host unknown"); 57927c478bd9Sstevel@tonic-gate else 57937c478bd9Sstevel@tonic-gate mci_setstat(mci, rcode, NULL, NULL); 57947c478bd9Sstevel@tonic-gate 57957c478bd9Sstevel@tonic-gate /* use the original host name as signature */ 57967c478bd9Sstevel@tonic-gate nmx = 1; 57977c478bd9Sstevel@tonic-gate mxhosts[0] = hp; 57987c478bd9Sstevel@tonic-gate } 57997c478bd9Sstevel@tonic-gate if (tTd(17, 3)) 58007c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n", 58017c478bd9Sstevel@tonic-gate nmx, mxhosts[0]); 58027c478bd9Sstevel@tonic-gate 58037c478bd9Sstevel@tonic-gate /* 58047c478bd9Sstevel@tonic-gate ** Set new TTL: we use only one! 58057c478bd9Sstevel@tonic-gate ** We could try to use the minimum instead. 58067c478bd9Sstevel@tonic-gate */ 58077c478bd9Sstevel@tonic-gate 58087c478bd9Sstevel@tonic-gate s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); 58097c478bd9Sstevel@tonic-gate } 58107c478bd9Sstevel@tonic-gate 58117c478bd9Sstevel@tonic-gate len = 0; 58127c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 58137c478bd9Sstevel@tonic-gate len += strlen(mxhosts[i]) + 1; 58147c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 58157c478bd9Sstevel@tonic-gate len += strlen(s->s_hostsig.hs_sig) + 1; 58167c478bd9Sstevel@tonic-gate if (len < 0 || len >= MAXHOSTSIGNATURE) 58177c478bd9Sstevel@tonic-gate { 58187c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d", 58197c478bd9Sstevel@tonic-gate host, MAXHOSTSIGNATURE, len); 58207c478bd9Sstevel@tonic-gate len = MAXHOSTSIGNATURE; 58217c478bd9Sstevel@tonic-gate } 58227c478bd9Sstevel@tonic-gate p = sm_pmalloc_x(len); 58237c478bd9Sstevel@tonic-gate if (s->s_hostsig.hs_sig != NULL) 58247c478bd9Sstevel@tonic-gate { 58257c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len); 58267c478bd9Sstevel@tonic-gate sm_free(s->s_hostsig.hs_sig); /* XXX */ 58277c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = p; 58287c478bd9Sstevel@tonic-gate hl = strlen(p); 58297c478bd9Sstevel@tonic-gate p += hl; 58307c478bd9Sstevel@tonic-gate *p++ = prevsep; 58317c478bd9Sstevel@tonic-gate len -= hl + 1; 58327c478bd9Sstevel@tonic-gate } 58337c478bd9Sstevel@tonic-gate else 58347c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = p; 58357c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 58367c478bd9Sstevel@tonic-gate { 58377c478bd9Sstevel@tonic-gate hl = strlen(mxhosts[i]); 58387c478bd9Sstevel@tonic-gate if (len - 1 < hl || len <= 1) 58397c478bd9Sstevel@tonic-gate { 58407c478bd9Sstevel@tonic-gate /* force to drop out of outer loop */ 58417c478bd9Sstevel@tonic-gate len = -1; 58427c478bd9Sstevel@tonic-gate break; 58437c478bd9Sstevel@tonic-gate } 58447c478bd9Sstevel@tonic-gate if (i != 0) 58457c478bd9Sstevel@tonic-gate { 58467c478bd9Sstevel@tonic-gate if (mxprefs[i] == mxprefs[i - 1]) 58477c478bd9Sstevel@tonic-gate *p++ = ','; 58487c478bd9Sstevel@tonic-gate else 58497c478bd9Sstevel@tonic-gate *p++ = ':'; 58507c478bd9Sstevel@tonic-gate len--; 58517c478bd9Sstevel@tonic-gate } 58527c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, mxhosts[i], len); 58537c478bd9Sstevel@tonic-gate p += hl; 58547c478bd9Sstevel@tonic-gate len -= hl; 58557c478bd9Sstevel@tonic-gate } 58567c478bd9Sstevel@tonic-gate 58577c478bd9Sstevel@tonic-gate /* 58587c478bd9Sstevel@tonic-gate ** break out of loop if len exceeded MAXHOSTSIGNATURE 58597c478bd9Sstevel@tonic-gate ** because we won't have more space for further hosts 58607c478bd9Sstevel@tonic-gate ** anyway (separated by : in the .cf file). 58617c478bd9Sstevel@tonic-gate */ 58627c478bd9Sstevel@tonic-gate 58637c478bd9Sstevel@tonic-gate if (len < 0) 58647c478bd9Sstevel@tonic-gate break; 58657c478bd9Sstevel@tonic-gate if (endp != NULL) 58667c478bd9Sstevel@tonic-gate *endp++ = sep; 58677c478bd9Sstevel@tonic-gate prevsep = sep; 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate makelower(s->s_hostsig.hs_sig); 58707c478bd9Sstevel@tonic-gate if (ConfigLevel < 2) 58717c478bd9Sstevel@tonic-gate _res.options = oldoptions; 58727c478bd9Sstevel@tonic-gate #else /* NAMED_BIND */ 58737c478bd9Sstevel@tonic-gate /* not using BIND -- the signature is just the host name */ 58747c478bd9Sstevel@tonic-gate /* 58757c478bd9Sstevel@tonic-gate ** 'host' points to storage that will be freed after we are 58767c478bd9Sstevel@tonic-gate ** done processing the current envelope, so we copy it. 58777c478bd9Sstevel@tonic-gate */ 58787c478bd9Sstevel@tonic-gate s->s_hostsig.hs_sig = sm_pstrdup_x(host); 58797c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 58807c478bd9Sstevel@tonic-gate if (tTd(17, 1)) 58817c478bd9Sstevel@tonic-gate sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig); 58827c478bd9Sstevel@tonic-gate return s->s_hostsig.hs_sig; 58837c478bd9Sstevel@tonic-gate } 58847c478bd9Sstevel@tonic-gate /* 58857c478bd9Sstevel@tonic-gate ** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array. 58867c478bd9Sstevel@tonic-gate ** 58877c478bd9Sstevel@tonic-gate ** The signature describes how we are going to send this -- it 58887c478bd9Sstevel@tonic-gate ** can be just the hostname (for non-Internet hosts) or can be 58897c478bd9Sstevel@tonic-gate ** an ordered list of MX hosts which must be randomized for equal 58907c478bd9Sstevel@tonic-gate ** MX preference values. 58917c478bd9Sstevel@tonic-gate ** 58927c478bd9Sstevel@tonic-gate ** Parameters: 58937c478bd9Sstevel@tonic-gate ** sig -- the host signature. 58947c478bd9Sstevel@tonic-gate ** mxhosts -- array to populate. 58957c478bd9Sstevel@tonic-gate ** mailer -- mailer. 58967c478bd9Sstevel@tonic-gate ** 58977c478bd9Sstevel@tonic-gate ** Returns: 58987c478bd9Sstevel@tonic-gate ** The number of hosts inserted into mxhosts array. 58997c478bd9Sstevel@tonic-gate ** 59007c478bd9Sstevel@tonic-gate ** Side Effects: 59017c478bd9Sstevel@tonic-gate ** Randomizes equal MX preference hosts in mxhosts. 59027c478bd9Sstevel@tonic-gate */ 59037c478bd9Sstevel@tonic-gate 59047c478bd9Sstevel@tonic-gate static int 59057c478bd9Sstevel@tonic-gate parse_hostsignature(sig, mxhosts, mailer) 59067c478bd9Sstevel@tonic-gate char *sig; 59077c478bd9Sstevel@tonic-gate char **mxhosts; 59087c478bd9Sstevel@tonic-gate MAILER *mailer; 59097c478bd9Sstevel@tonic-gate { 59107c478bd9Sstevel@tonic-gate unsigned short curpref = 0; 59117c478bd9Sstevel@tonic-gate int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */ 59127c478bd9Sstevel@tonic-gate char *hp, *endp; 59137c478bd9Sstevel@tonic-gate unsigned short prefer[MAXMXHOSTS]; 59147c478bd9Sstevel@tonic-gate long rndm[MAXMXHOSTS]; 59157c478bd9Sstevel@tonic-gate 59167c478bd9Sstevel@tonic-gate for (hp = sig; hp != NULL; hp = endp) 59177c478bd9Sstevel@tonic-gate { 59187c478bd9Sstevel@tonic-gate char sep = ':'; 59197c478bd9Sstevel@tonic-gate 59207c478bd9Sstevel@tonic-gate #if NETINET6 59217c478bd9Sstevel@tonic-gate if (*hp == '[') 59227c478bd9Sstevel@tonic-gate { 59237c478bd9Sstevel@tonic-gate endp = strchr(hp + 1, ']'); 59247c478bd9Sstevel@tonic-gate if (endp != NULL) 59257c478bd9Sstevel@tonic-gate endp = strpbrk(endp + 1, ":,"); 59267c478bd9Sstevel@tonic-gate } 59277c478bd9Sstevel@tonic-gate else 59287c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 59297c478bd9Sstevel@tonic-gate #else /* NETINET6 */ 59307c478bd9Sstevel@tonic-gate endp = strpbrk(hp, ":,"); 59317c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 59327c478bd9Sstevel@tonic-gate if (endp != NULL) 59337c478bd9Sstevel@tonic-gate { 59347c478bd9Sstevel@tonic-gate sep = *endp; 59357c478bd9Sstevel@tonic-gate *endp = '\0'; 59367c478bd9Sstevel@tonic-gate } 59377c478bd9Sstevel@tonic-gate 59387c478bd9Sstevel@tonic-gate mxhosts[nmx] = hp; 59397c478bd9Sstevel@tonic-gate prefer[nmx] = curpref; 59407c478bd9Sstevel@tonic-gate if (mci_match(hp, mailer)) 59417c478bd9Sstevel@tonic-gate rndm[nmx] = 0; 59427c478bd9Sstevel@tonic-gate else 59437c478bd9Sstevel@tonic-gate rndm[nmx] = get_random(); 59447c478bd9Sstevel@tonic-gate 59457c478bd9Sstevel@tonic-gate if (endp != NULL) 59467c478bd9Sstevel@tonic-gate { 59477c478bd9Sstevel@tonic-gate /* 59487c478bd9Sstevel@tonic-gate ** Since we don't have the original MX prefs, 59497c478bd9Sstevel@tonic-gate ** make our own. If the separator is a ':', that 59507c478bd9Sstevel@tonic-gate ** means the preference for the next host will be 59517c478bd9Sstevel@tonic-gate ** higher than this one, so simply increment curpref. 59527c478bd9Sstevel@tonic-gate */ 59537c478bd9Sstevel@tonic-gate 59547c478bd9Sstevel@tonic-gate if (sep == ':') 59557c478bd9Sstevel@tonic-gate curpref++; 59567c478bd9Sstevel@tonic-gate 59577c478bd9Sstevel@tonic-gate *endp++ = sep; 59587c478bd9Sstevel@tonic-gate } 59597c478bd9Sstevel@tonic-gate if (++nmx >= MAXMXHOSTS) 59607c478bd9Sstevel@tonic-gate break; 59617c478bd9Sstevel@tonic-gate } 59627c478bd9Sstevel@tonic-gate 59637c478bd9Sstevel@tonic-gate /* sort the records using the random factor for equal preferences */ 59647c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 59657c478bd9Sstevel@tonic-gate { 59667c478bd9Sstevel@tonic-gate for (j = i + 1; j < nmx; j++) 59677c478bd9Sstevel@tonic-gate { 59687c478bd9Sstevel@tonic-gate /* 59697c478bd9Sstevel@tonic-gate ** List is already sorted by MX preference, only 59707c478bd9Sstevel@tonic-gate ** need to look for equal preference MX records 59717c478bd9Sstevel@tonic-gate */ 59727c478bd9Sstevel@tonic-gate 59737c478bd9Sstevel@tonic-gate if (prefer[i] < prefer[j]) 59747c478bd9Sstevel@tonic-gate break; 59757c478bd9Sstevel@tonic-gate 59767c478bd9Sstevel@tonic-gate if (prefer[i] > prefer[j] || 59777c478bd9Sstevel@tonic-gate (prefer[i] == prefer[j] && rndm[i] > rndm[j])) 59787c478bd9Sstevel@tonic-gate { 59797c478bd9Sstevel@tonic-gate register unsigned short tempp; 59807c478bd9Sstevel@tonic-gate register long tempr; 59817c478bd9Sstevel@tonic-gate register char *temp1; 59827c478bd9Sstevel@tonic-gate 59837c478bd9Sstevel@tonic-gate tempp = prefer[i]; 59847c478bd9Sstevel@tonic-gate prefer[i] = prefer[j]; 59857c478bd9Sstevel@tonic-gate prefer[j] = tempp; 59867c478bd9Sstevel@tonic-gate temp1 = mxhosts[i]; 59877c478bd9Sstevel@tonic-gate mxhosts[i] = mxhosts[j]; 59887c478bd9Sstevel@tonic-gate mxhosts[j] = temp1; 59897c478bd9Sstevel@tonic-gate tempr = rndm[i]; 59907c478bd9Sstevel@tonic-gate rndm[i] = rndm[j]; 59917c478bd9Sstevel@tonic-gate rndm[j] = tempr; 59927c478bd9Sstevel@tonic-gate } 59937c478bd9Sstevel@tonic-gate } 59947c478bd9Sstevel@tonic-gate } 59957c478bd9Sstevel@tonic-gate return nmx; 59967c478bd9Sstevel@tonic-gate } 59977c478bd9Sstevel@tonic-gate 59987c478bd9Sstevel@tonic-gate # if STARTTLS 59997c478bd9Sstevel@tonic-gate static SSL_CTX *clt_ctx = NULL; 60007c478bd9Sstevel@tonic-gate static bool tls_ok_clt = true; 60017c478bd9Sstevel@tonic-gate 60027c478bd9Sstevel@tonic-gate /* 60037c478bd9Sstevel@tonic-gate ** SETCLTTLS -- client side TLS: allow/disallow. 60047c478bd9Sstevel@tonic-gate ** 60057c478bd9Sstevel@tonic-gate ** Parameters: 60067c478bd9Sstevel@tonic-gate ** tls_ok -- should tls be done? 60077c478bd9Sstevel@tonic-gate ** 60087c478bd9Sstevel@tonic-gate ** Returns: 60097c478bd9Sstevel@tonic-gate ** none. 60107c478bd9Sstevel@tonic-gate ** 60117c478bd9Sstevel@tonic-gate ** Side Effects: 60127c478bd9Sstevel@tonic-gate ** sets tls_ok_clt (static variable in this module) 60137c478bd9Sstevel@tonic-gate */ 60147c478bd9Sstevel@tonic-gate 60157c478bd9Sstevel@tonic-gate void 60167c478bd9Sstevel@tonic-gate setclttls(tls_ok) 60177c478bd9Sstevel@tonic-gate bool tls_ok; 60187c478bd9Sstevel@tonic-gate { 60197c478bd9Sstevel@tonic-gate tls_ok_clt = tls_ok; 60207c478bd9Sstevel@tonic-gate return; 60217c478bd9Sstevel@tonic-gate } 60227c478bd9Sstevel@tonic-gate /* 60237c478bd9Sstevel@tonic-gate ** INITCLTTLS -- initialize client side TLS 60247c478bd9Sstevel@tonic-gate ** 60257c478bd9Sstevel@tonic-gate ** Parameters: 60267c478bd9Sstevel@tonic-gate ** tls_ok -- should tls initialization be done? 60277c478bd9Sstevel@tonic-gate ** 60287c478bd9Sstevel@tonic-gate ** Returns: 60297c478bd9Sstevel@tonic-gate ** succeeded? 60307c478bd9Sstevel@tonic-gate ** 60317c478bd9Sstevel@tonic-gate ** Side Effects: 60327c478bd9Sstevel@tonic-gate ** sets tls_ok_clt (static variable in this module) 60337c478bd9Sstevel@tonic-gate */ 60347c478bd9Sstevel@tonic-gate 60357c478bd9Sstevel@tonic-gate bool 60367c478bd9Sstevel@tonic-gate initclttls(tls_ok) 60377c478bd9Sstevel@tonic-gate bool tls_ok; 60387c478bd9Sstevel@tonic-gate { 60397c478bd9Sstevel@tonic-gate if (!tls_ok_clt) 60407c478bd9Sstevel@tonic-gate return false; 60417c478bd9Sstevel@tonic-gate tls_ok_clt = tls_ok; 60427c478bd9Sstevel@tonic-gate if (!tls_ok_clt) 60437c478bd9Sstevel@tonic-gate return false; 60447c478bd9Sstevel@tonic-gate if (clt_ctx != NULL) 60457c478bd9Sstevel@tonic-gate return true; /* already done */ 60467c478bd9Sstevel@tonic-gate tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCertFile, 60477c478bd9Sstevel@tonic-gate CltKeyFile, CACertPath, CACertFile, DHParams); 60487c478bd9Sstevel@tonic-gate return tls_ok_clt; 60497c478bd9Sstevel@tonic-gate } 60507c478bd9Sstevel@tonic-gate 60517c478bd9Sstevel@tonic-gate /* 60527c478bd9Sstevel@tonic-gate ** STARTTLS -- try to start secure connection (client side) 60537c478bd9Sstevel@tonic-gate ** 60547c478bd9Sstevel@tonic-gate ** Parameters: 60557c478bd9Sstevel@tonic-gate ** m -- the mailer. 60567c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 60577c478bd9Sstevel@tonic-gate ** e -- the envelope. 60587c478bd9Sstevel@tonic-gate ** 60597c478bd9Sstevel@tonic-gate ** Returns: 60607c478bd9Sstevel@tonic-gate ** success? 60617c478bd9Sstevel@tonic-gate ** (maybe this should be some other code than EX_ 60627c478bd9Sstevel@tonic-gate ** that denotes which stage failed.) 60637c478bd9Sstevel@tonic-gate */ 60647c478bd9Sstevel@tonic-gate 60657c478bd9Sstevel@tonic-gate static int 60667c478bd9Sstevel@tonic-gate starttls(m, mci, e) 60677c478bd9Sstevel@tonic-gate MAILER *m; 60687c478bd9Sstevel@tonic-gate MCI *mci; 60697c478bd9Sstevel@tonic-gate ENVELOPE *e; 60707c478bd9Sstevel@tonic-gate { 60717c478bd9Sstevel@tonic-gate int smtpresult; 60727c478bd9Sstevel@tonic-gate int result = 0; 60737c478bd9Sstevel@tonic-gate int rfd, wfd; 60747c478bd9Sstevel@tonic-gate SSL *clt_ssl = NULL; 60757c478bd9Sstevel@tonic-gate time_t tlsstart; 60767c478bd9Sstevel@tonic-gate 60777c478bd9Sstevel@tonic-gate if (clt_ctx == NULL && !initclttls(true)) 60787c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 60797c478bd9Sstevel@tonic-gate smtpmessage("STARTTLS", m, mci); 60807c478bd9Sstevel@tonic-gate 60817c478bd9Sstevel@tonic-gate /* get the reply */ 60827c478bd9Sstevel@tonic-gate smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL, 60837c478bd9Sstevel@tonic-gate XS_STARTTLS); 60847c478bd9Sstevel@tonic-gate 60857c478bd9Sstevel@tonic-gate /* check return code from server */ 6086*445f2479Sjbeck if (REPLYTYPE(smtpresult) == 4) 60877c478bd9Sstevel@tonic-gate return EX_TEMPFAIL; 60887c478bd9Sstevel@tonic-gate if (smtpresult == 501) 60897c478bd9Sstevel@tonic-gate return EX_USAGE; 60907c478bd9Sstevel@tonic-gate if (smtpresult == -1) 60917c478bd9Sstevel@tonic-gate return smtpresult; 6092*445f2479Sjbeck 6093*445f2479Sjbeck /* not an expected reply but we have to deal with it */ 6094*445f2479Sjbeck if (REPLYTYPE(smtpresult) == 5) 6095*445f2479Sjbeck return EX_UNAVAILABLE; 60967c478bd9Sstevel@tonic-gate if (smtpresult != 220) 60977c478bd9Sstevel@tonic-gate return EX_PROTOCOL; 60987c478bd9Sstevel@tonic-gate 60997c478bd9Sstevel@tonic-gate if (LogLevel > 13) 61007c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate /* start connection */ 61037c478bd9Sstevel@tonic-gate if ((clt_ssl = SSL_new(clt_ctx)) == NULL) 61047c478bd9Sstevel@tonic-gate { 61057c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61067c478bd9Sstevel@tonic-gate { 61077c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 61087c478bd9Sstevel@tonic-gate "STARTTLS=client, error: SSL_new failed"); 61097c478bd9Sstevel@tonic-gate if (LogLevel > 9) 61107c478bd9Sstevel@tonic-gate tlslogerr("client"); 61117c478bd9Sstevel@tonic-gate } 61127c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61137c478bd9Sstevel@tonic-gate } 61147c478bd9Sstevel@tonic-gate 61157c478bd9Sstevel@tonic-gate rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); 61167c478bd9Sstevel@tonic-gate wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); 61177c478bd9Sstevel@tonic-gate 61187c478bd9Sstevel@tonic-gate /* SSL_clear(clt_ssl); ? */ 61197c478bd9Sstevel@tonic-gate if (rfd < 0 || wfd < 0 || 61207c478bd9Sstevel@tonic-gate (result = SSL_set_rfd(clt_ssl, rfd)) != 1 || 61217c478bd9Sstevel@tonic-gate (result = SSL_set_wfd(clt_ssl, wfd)) != 1) 61227c478bd9Sstevel@tonic-gate { 61237c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61247c478bd9Sstevel@tonic-gate { 61257c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 61267c478bd9Sstevel@tonic-gate "STARTTLS=client, error: SSL_set_xfd failed=%d", 61277c478bd9Sstevel@tonic-gate result); 61287c478bd9Sstevel@tonic-gate if (LogLevel > 9) 61297c478bd9Sstevel@tonic-gate tlslogerr("client"); 61307c478bd9Sstevel@tonic-gate } 61317c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61327c478bd9Sstevel@tonic-gate } 61337c478bd9Sstevel@tonic-gate SSL_set_connect_state(clt_ssl); 61347c478bd9Sstevel@tonic-gate tlsstart = curtime(); 61357c478bd9Sstevel@tonic-gate 61367c478bd9Sstevel@tonic-gate ssl_retry: 61377c478bd9Sstevel@tonic-gate if ((result = SSL_connect(clt_ssl)) <= 0) 61387c478bd9Sstevel@tonic-gate { 6139*445f2479Sjbeck int i, ssl_err; 61407c478bd9Sstevel@tonic-gate 6141*445f2479Sjbeck ssl_err = SSL_get_error(clt_ssl, result); 6142*445f2479Sjbeck i = tls_retry(clt_ssl, rfd, wfd, tlsstart, 6143*445f2479Sjbeck TimeOuts.to_starttls, ssl_err, "client"); 6144*445f2479Sjbeck if (i > 0) 6145*445f2479Sjbeck goto ssl_retry; 61467c478bd9Sstevel@tonic-gate 61477c478bd9Sstevel@tonic-gate if (LogLevel > 5) 61487c478bd9Sstevel@tonic-gate { 6149*445f2479Sjbeck sm_syslog(LOG_WARNING, NOQID, 6150*445f2479Sjbeck "STARTTLS=client, error: connect failed=%d, SSL_error=%d, errno=%d, retry=%d", 6151*445f2479Sjbeck result, ssl_err, errno, i); 61527c478bd9Sstevel@tonic-gate if (LogLevel > 8) 61537c478bd9Sstevel@tonic-gate tlslogerr("client"); 61547c478bd9Sstevel@tonic-gate } 61557c478bd9Sstevel@tonic-gate 61567c478bd9Sstevel@tonic-gate SSL_free(clt_ssl); 61577c478bd9Sstevel@tonic-gate clt_ssl = NULL; 61587c478bd9Sstevel@tonic-gate return EX_SOFTWARE; 61597c478bd9Sstevel@tonic-gate } 61607c478bd9Sstevel@tonic-gate mci->mci_ssl = clt_ssl; 61617c478bd9Sstevel@tonic-gate result = tls_get_info(mci->mci_ssl, false, mci->mci_host, 61627c478bd9Sstevel@tonic-gate &mci->mci_macro, true); 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate /* switch to use TLS... */ 61657c478bd9Sstevel@tonic-gate if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) 61667c478bd9Sstevel@tonic-gate return EX_OK; 61677c478bd9Sstevel@tonic-gate 61687c478bd9Sstevel@tonic-gate /* failure */ 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 /* 61747c478bd9Sstevel@tonic-gate ** ENDTLSCLT -- shutdown secure connection (client side) 61757c478bd9Sstevel@tonic-gate ** 61767c478bd9Sstevel@tonic-gate ** Parameters: 61777c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info. 61787c478bd9Sstevel@tonic-gate ** 61797c478bd9Sstevel@tonic-gate ** Returns: 61807c478bd9Sstevel@tonic-gate ** success? 61817c478bd9Sstevel@tonic-gate */ 61827c478bd9Sstevel@tonic-gate 61837c478bd9Sstevel@tonic-gate static int 61847c478bd9Sstevel@tonic-gate endtlsclt(mci) 61857c478bd9Sstevel@tonic-gate MCI *mci; 61867c478bd9Sstevel@tonic-gate { 61877c478bd9Sstevel@tonic-gate int r; 61887c478bd9Sstevel@tonic-gate 61897c478bd9Sstevel@tonic-gate if (!bitset(MCIF_TLSACT, mci->mci_flags)) 61907c478bd9Sstevel@tonic-gate return EX_OK; 61917c478bd9Sstevel@tonic-gate r = endtls(mci->mci_ssl, "client"); 61927c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_TLSACT; 61937c478bd9Sstevel@tonic-gate return r; 61947c478bd9Sstevel@tonic-gate } 61957c478bd9Sstevel@tonic-gate # endif /* STARTTLS */ 61967c478bd9Sstevel@tonic-gate # if STARTTLS || SASL 61977c478bd9Sstevel@tonic-gate /* 61987c478bd9Sstevel@tonic-gate ** ISCLTFLGSET -- check whether client flag is set. 61997c478bd9Sstevel@tonic-gate ** 62007c478bd9Sstevel@tonic-gate ** Parameters: 62017c478bd9Sstevel@tonic-gate ** e -- envelope. 62027c478bd9Sstevel@tonic-gate ** flag -- flag to check in {client_flags} 62037c478bd9Sstevel@tonic-gate ** 62047c478bd9Sstevel@tonic-gate ** Returns: 62057c478bd9Sstevel@tonic-gate ** true iff flag is set. 62067c478bd9Sstevel@tonic-gate */ 62077c478bd9Sstevel@tonic-gate 62087c478bd9Sstevel@tonic-gate static bool 62097c478bd9Sstevel@tonic-gate iscltflgset(e, flag) 62107c478bd9Sstevel@tonic-gate ENVELOPE *e; 62117c478bd9Sstevel@tonic-gate int flag; 62127c478bd9Sstevel@tonic-gate { 62137c478bd9Sstevel@tonic-gate char *p; 62147c478bd9Sstevel@tonic-gate 62157c478bd9Sstevel@tonic-gate p = macvalue(macid("{client_flags}"), e); 62167c478bd9Sstevel@tonic-gate if (p == NULL) 62177c478bd9Sstevel@tonic-gate return false; 62187c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 62197c478bd9Sstevel@tonic-gate { 62207c478bd9Sstevel@tonic-gate /* look for just this one flag */ 62217c478bd9Sstevel@tonic-gate if (*p == (char) flag) 62227c478bd9Sstevel@tonic-gate return true; 62237c478bd9Sstevel@tonic-gate } 62247c478bd9Sstevel@tonic-gate return false; 62257c478bd9Sstevel@tonic-gate } 62267c478bd9Sstevel@tonic-gate # endif /* STARTTLS || SASL */ 6227