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