17c478bd9Sstevel@tonic-gate /*
2*e9af4bc0SJohn Beck * Copyright (c) 1998-2006, 2008, 2009 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>
157c478bd9Sstevel@tonic-gate
16*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: usersmtp.c,v 8.473 2009/06/17 17:26:51 ca Exp $")
177c478bd9Sstevel@tonic-gate
187c478bd9Sstevel@tonic-gate #include <sysexits.h>
197c478bd9Sstevel@tonic-gate
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
227c478bd9Sstevel@tonic-gate static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
237c478bd9Sstevel@tonic-gate static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate #if SASL
267c478bd9Sstevel@tonic-gate extern void *sm_sasl_malloc __P((unsigned long));
277c478bd9Sstevel@tonic-gate extern void sm_sasl_free __P((void *));
287c478bd9Sstevel@tonic-gate #endif /* SASL */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate ** USERSMTP -- run SMTP protocol from the user end.
327c478bd9Sstevel@tonic-gate **
337c478bd9Sstevel@tonic-gate ** This protocol is described in RFC821.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
377c478bd9Sstevel@tonic-gate #define SMTPCLOSING 421 /* "Service Shutting Down" */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #define ENHSCN(e, d) ((e) == NULL ? (d) : (e))
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #define ENHSCN_RPOOL(e, d, rpool) \
427c478bd9Sstevel@tonic-gate ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
457c478bd9Sstevel@tonic-gate static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
467c478bd9Sstevel@tonic-gate static bool SmtpNeedIntro; /* need "while talking" in transcript */
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate ** SMTPINIT -- initialize SMTP.
497c478bd9Sstevel@tonic-gate **
507c478bd9Sstevel@tonic-gate ** Opens the connection and sends the initial protocol.
517c478bd9Sstevel@tonic-gate **
527c478bd9Sstevel@tonic-gate ** Parameters:
537c478bd9Sstevel@tonic-gate ** m -- mailer to create connection to.
547c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info.
557c478bd9Sstevel@tonic-gate ** e -- the envelope.
567c478bd9Sstevel@tonic-gate ** onlyhelo -- send only helo command?
577c478bd9Sstevel@tonic-gate **
587c478bd9Sstevel@tonic-gate ** Returns:
597c478bd9Sstevel@tonic-gate ** none.
607c478bd9Sstevel@tonic-gate **
617c478bd9Sstevel@tonic-gate ** Side Effects:
627c478bd9Sstevel@tonic-gate ** creates connection and sends initial protocol.
637c478bd9Sstevel@tonic-gate */
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate void
smtpinit(m,mci,e,onlyhelo)667c478bd9Sstevel@tonic-gate smtpinit(m, mci, e, onlyhelo)
677c478bd9Sstevel@tonic-gate MAILER *m;
687c478bd9Sstevel@tonic-gate register MCI *mci;
697c478bd9Sstevel@tonic-gate ENVELOPE *e;
707c478bd9Sstevel@tonic-gate bool onlyhelo;
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate register int r;
737c478bd9Sstevel@tonic-gate int state;
747c478bd9Sstevel@tonic-gate register char *p;
757c478bd9Sstevel@tonic-gate register char *hn;
767c478bd9Sstevel@tonic-gate char *enhsc;
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate enhsc = NULL;
797c478bd9Sstevel@tonic-gate if (tTd(18, 1))
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate sm_dprintf("smtpinit ");
827c478bd9Sstevel@tonic-gate mci_dump(sm_debug_file(), mci, false);
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate ** Open the connection to the mailer.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate SmtpError[0] = '\0';
907c478bd9Sstevel@tonic-gate SmtpMsgBuffer[0] = '\0';
917c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; /* XXX UGLY XXX */
927c478bd9Sstevel@tonic-gate if (CurHostName == NULL)
937c478bd9Sstevel@tonic-gate CurHostName = MyHostName;
947c478bd9Sstevel@tonic-gate SmtpNeedIntro = true;
957c478bd9Sstevel@tonic-gate state = mci->mci_state;
967c478bd9Sstevel@tonic-gate switch (state)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate case MCIS_MAIL:
997c478bd9Sstevel@tonic-gate case MCIS_RCPT:
1007c478bd9Sstevel@tonic-gate case MCIS_DATA:
1017c478bd9Sstevel@tonic-gate /* need to clear old information */
1027c478bd9Sstevel@tonic-gate smtprset(m, mci, e);
1037c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate case MCIS_OPEN:
1067c478bd9Sstevel@tonic-gate if (!onlyhelo)
1077c478bd9Sstevel@tonic-gate return;
1087c478bd9Sstevel@tonic-gate break;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate case MCIS_ERROR:
1117c478bd9Sstevel@tonic-gate case MCIS_QUITING:
1127c478bd9Sstevel@tonic-gate case MCIS_SSD:
1137c478bd9Sstevel@tonic-gate /* shouldn't happen */
1147c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
1157c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate case MCIS_CLOSED:
1187c478bd9Sstevel@tonic-gate syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
1197c478bd9Sstevel@tonic-gate return;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate case MCIS_OPENING:
1227c478bd9Sstevel@tonic-gate break;
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate if (onlyhelo)
1257c478bd9Sstevel@tonic-gate goto helo;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPENING;
1287c478bd9Sstevel@tonic-gate clrsessenvelope(e);
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate ** Get the greeting message.
1327c478bd9Sstevel@tonic-gate ** This should appear spontaneously. Give it five minutes to
1337c478bd9Sstevel@tonic-gate ** happen.
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client greeting";
1377c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s",
1387c478bd9Sstevel@tonic-gate qid_printname(e), CurHostName, mci->mci_phase);
1397c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL,
1407c478bd9Sstevel@tonic-gate XS_DEFAULT);
1417c478bd9Sstevel@tonic-gate if (r < 0)
1427c478bd9Sstevel@tonic-gate goto tempfail1;
1437c478bd9Sstevel@tonic-gate if (REPLYTYPE(r) == 4)
1447c478bd9Sstevel@tonic-gate goto tempfail2;
1457c478bd9Sstevel@tonic-gate if (REPLYTYPE(r) != 2)
1467c478bd9Sstevel@tonic-gate goto unavailable;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate ** Send the HELO command.
1507c478bd9Sstevel@tonic-gate ** My mother taught me to always introduce myself.
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate helo:
1547c478bd9Sstevel@tonic-gate if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
1557c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_ESMTP;
1567c478bd9Sstevel@tonic-gate hn = mci->mci_heloname ? mci->mci_heloname : MyHostName;
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate tryhelo:
1597c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_EXT_ON_HELO
1607c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_HELO;
1617c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_EXT_ON_HELO */
1627c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags))
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate smtpmessage("LHLO %s", m, mci, hn);
1657c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client LHLO";
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
1687c478bd9Sstevel@tonic-gate !bitnset(M_FSMTP, m->m_flags))
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate smtpmessage("EHLO %s", m, mci, hn);
1717c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client EHLO";
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate else
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate smtpmessage("HELO %s", m, mci, hn);
1767c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client HELO";
1777c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_EXT_ON_HELO
1787c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_HELO;
1797c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_EXT_ON_HELO */
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
1827c478bd9Sstevel@tonic-gate CurHostName, mci->mci_phase);
1837c478bd9Sstevel@tonic-gate r = reply(m, mci, e,
1847c478bd9Sstevel@tonic-gate bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
1857c478bd9Sstevel@tonic-gate : TimeOuts.to_helo,
1867c478bd9Sstevel@tonic-gate helo_options, NULL, XS_DEFAULT);
1877c478bd9Sstevel@tonic-gate if (r < 0)
1887c478bd9Sstevel@tonic-gate goto tempfail1;
1897c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate if (bitset(MCIF_ESMTP, mci->mci_flags) &&
1927c478bd9Sstevel@tonic-gate !bitnset(M_LMTP, m->m_flags))
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate /* try old SMTP instead */
1957c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_ESMTP;
1967c478bd9Sstevel@tonic-gate goto tryhelo;
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate goto unavailable;
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) != 2)
2017c478bd9Sstevel@tonic-gate goto tempfail2;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate ** Check to see if we actually ended up talking to ourself.
2057c478bd9Sstevel@tonic-gate ** This means we didn't know about an alias or MX, or we managed
2067c478bd9Sstevel@tonic-gate ** to connect to an echo server.
2077c478bd9Sstevel@tonic-gate */
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate p = strchr(&SmtpReplyBuffer[4], ' ');
2107c478bd9Sstevel@tonic-gate if (p != NULL)
2117c478bd9Sstevel@tonic-gate *p = '\0';
2127c478bd9Sstevel@tonic-gate if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
2137c478bd9Sstevel@tonic-gate !bitnset(M_LMTP, m->m_flags) &&
2147c478bd9Sstevel@tonic-gate sm_strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
2177c478bd9Sstevel@tonic-gate CurHostName);
2187c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_CONFIG, "5.3.5",
2197c478bd9Sstevel@tonic-gate "553 5.3.5 system config error");
2207c478bd9Sstevel@tonic-gate mci->mci_errno = 0;
2217c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
2227c478bd9Sstevel@tonic-gate return;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate ** If this is expected to be another sendmail, send some internal
2277c478bd9Sstevel@tonic-gate ** commands.
2287c478bd9Sstevel@tonic-gate ** If we're running as MSP, "propagate" -v flag if possible.
2297c478bd9Sstevel@tonic-gate */
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags))
2327c478bd9Sstevel@tonic-gate # if !_FFR_DEPRECATE_MAILER_FLAG_I
2337c478bd9Sstevel@tonic-gate || bitnset(M_INTERNAL, m->m_flags)
2347c478bd9Sstevel@tonic-gate # endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */
2357c478bd9Sstevel@tonic-gate )
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate /* tell it to be verbose */
2387c478bd9Sstevel@tonic-gate smtpmessage("VERB", m, mci);
2397c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
2407c478bd9Sstevel@tonic-gate XS_DEFAULT);
2417c478bd9Sstevel@tonic-gate if (r < 0)
2427c478bd9Sstevel@tonic-gate goto tempfail1;
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN;
2487c478bd9Sstevel@tonic-gate return;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /* got a 421 error code during startup */
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate tempfail1:
2547c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
2557c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED)
2567c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
2577c478bd9Sstevel@tonic-gate return;
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate tempfail2:
2607c478bd9Sstevel@tonic-gate /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
2617c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
2627c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
2637c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_CLOSED)
2647c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
2657c478bd9Sstevel@tonic-gate return;
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate unavailable:
2687c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
2697c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
2707c478bd9Sstevel@tonic-gate return;
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
2747c478bd9Sstevel@tonic-gate **
2757c478bd9Sstevel@tonic-gate ** Parameters:
2767c478bd9Sstevel@tonic-gate ** line -- the response line.
2777c478bd9Sstevel@tonic-gate ** firstline -- set if this is the first line of the reply.
2787c478bd9Sstevel@tonic-gate ** m -- the mailer.
2797c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info.
2807c478bd9Sstevel@tonic-gate ** e -- the envelope.
2817c478bd9Sstevel@tonic-gate **
2827c478bd9Sstevel@tonic-gate ** Returns:
2837c478bd9Sstevel@tonic-gate ** none.
2847c478bd9Sstevel@tonic-gate */
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate static void
esmtp_check(line,firstline,m,mci,e)2877c478bd9Sstevel@tonic-gate esmtp_check(line, firstline, m, mci, e)
2887c478bd9Sstevel@tonic-gate char *line;
2897c478bd9Sstevel@tonic-gate bool firstline;
2907c478bd9Sstevel@tonic-gate MAILER *m;
2917c478bd9Sstevel@tonic-gate register MCI *mci;
2927c478bd9Sstevel@tonic-gate ENVELOPE *e;
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate if (strstr(line, "ESMTP") != NULL)
2957c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_ESMTP;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate ** Dirty hack below. Quoting the author:
2997c478bd9Sstevel@tonic-gate ** This was a response to people who wanted SMTP transmission to be
3007c478bd9Sstevel@tonic-gate ** just-send-8 by default. Essentially, you could put this tag into
3017c478bd9Sstevel@tonic-gate ** your greeting message to behave as though the F=8 flag was set on
3027c478bd9Sstevel@tonic-gate ** the mailer.
3037c478bd9Sstevel@tonic-gate */
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate if (strstr(line, "8BIT-OK") != NULL)
3067c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_8BITOK;
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate #if SASL
3107c478bd9Sstevel@tonic-gate /* specify prototype so compiler can check calls */
3117c478bd9Sstevel@tonic-gate static char *str_union __P((char *, char *, SM_RPOOL_T *));
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate ** STR_UNION -- create the union of two lists
3157c478bd9Sstevel@tonic-gate **
3167c478bd9Sstevel@tonic-gate ** Parameters:
3177c478bd9Sstevel@tonic-gate ** s1, s2 -- lists of items (separated by single blanks).
3187c478bd9Sstevel@tonic-gate ** rpool -- resource pool from which result is allocated.
3197c478bd9Sstevel@tonic-gate **
3207c478bd9Sstevel@tonic-gate ** Returns:
3217c478bd9Sstevel@tonic-gate ** the union of both lists.
3227c478bd9Sstevel@tonic-gate */
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate static char *
str_union(s1,s2,rpool)3257c478bd9Sstevel@tonic-gate str_union(s1, s2, rpool)
3267c478bd9Sstevel@tonic-gate char *s1, *s2;
3277c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate char *hr, *h1, *h, *res;
3307c478bd9Sstevel@tonic-gate int l1, l2, rl;
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate if (s1 == NULL || *s1 == '\0')
3337c478bd9Sstevel@tonic-gate return s2;
3347c478bd9Sstevel@tonic-gate if (s2 == NULL || *s2 == '\0')
3357c478bd9Sstevel@tonic-gate return s1;
3367c478bd9Sstevel@tonic-gate l1 = strlen(s1);
3377c478bd9Sstevel@tonic-gate l2 = strlen(s2);
3387c478bd9Sstevel@tonic-gate rl = l1 + l2;
3397c478bd9Sstevel@tonic-gate res = (char *) sm_rpool_malloc(rpool, rl + 2);
3407c478bd9Sstevel@tonic-gate if (res == NULL)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate if (l1 > l2)
3437c478bd9Sstevel@tonic-gate return s1;
3447c478bd9Sstevel@tonic-gate return s2;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate (void) sm_strlcpy(res, s1, rl);
3477c478bd9Sstevel@tonic-gate hr = res + l1;
3487c478bd9Sstevel@tonic-gate h1 = s2;
3497c478bd9Sstevel@tonic-gate h = s2;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate /* walk through s2 */
3527c478bd9Sstevel@tonic-gate while (h != NULL && *h1 != '\0')
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate /* is there something after the current word? */
3557c478bd9Sstevel@tonic-gate if ((h = strchr(h1, ' ')) != NULL)
3567c478bd9Sstevel@tonic-gate *h = '\0';
3577c478bd9Sstevel@tonic-gate l1 = strlen(h1);
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /* does the current word appear in s1 ? */
3607c478bd9Sstevel@tonic-gate if (iteminlist(h1, s1, " ") == NULL)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate /* add space as delimiter */
3637c478bd9Sstevel@tonic-gate *hr++ = ' ';
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate /* copy the item */
3667c478bd9Sstevel@tonic-gate memcpy(hr, h1, l1);
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate /* advance pointer in result list */
3697c478bd9Sstevel@tonic-gate hr += l1;
3707c478bd9Sstevel@tonic-gate *hr = '\0';
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate if (h != NULL)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate /* there are more items */
3757c478bd9Sstevel@tonic-gate *h = ' ';
3767c478bd9Sstevel@tonic-gate h1 = h + 1;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate return res;
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate #endif /* SASL */
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate ** HELO_OPTIONS -- process the options on a HELO line.
3857c478bd9Sstevel@tonic-gate **
3867c478bd9Sstevel@tonic-gate ** Parameters:
3877c478bd9Sstevel@tonic-gate ** line -- the response line.
3887c478bd9Sstevel@tonic-gate ** firstline -- set if this is the first line of the reply.
3897c478bd9Sstevel@tonic-gate ** m -- the mailer.
3907c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info.
3917c478bd9Sstevel@tonic-gate ** e -- the envelope (unused).
3927c478bd9Sstevel@tonic-gate **
3937c478bd9Sstevel@tonic-gate ** Returns:
3947c478bd9Sstevel@tonic-gate ** none.
3957c478bd9Sstevel@tonic-gate */
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate static void
helo_options(line,firstline,m,mci,e)3987c478bd9Sstevel@tonic-gate helo_options(line, firstline, m, mci, e)
3997c478bd9Sstevel@tonic-gate char *line;
4007c478bd9Sstevel@tonic-gate bool firstline;
4017c478bd9Sstevel@tonic-gate MAILER *m;
4027c478bd9Sstevel@tonic-gate register MCI *mci;
4037c478bd9Sstevel@tonic-gate ENVELOPE *e;
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate register char *p;
4067c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_EXT_ON_HELO
4077c478bd9Sstevel@tonic-gate static bool logged = false;
4087c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_EXT_ON_HELO */
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate if (firstline)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate #if SASL
4137c478bd9Sstevel@tonic-gate mci->mci_saslcap = NULL;
4147c478bd9Sstevel@tonic-gate #endif /* SASL */
4157c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_EXT_ON_HELO
4167c478bd9Sstevel@tonic-gate logged = false;
4177c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_EXT_ON_HELO */
4187c478bd9Sstevel@tonic-gate return;
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_EXT_ON_HELO
4217c478bd9Sstevel@tonic-gate else if (bitset(MCIF_HELO, mci->mci_flags))
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate if (LogLevel > 8 && !logged)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
4267c478bd9Sstevel@tonic-gate "server=%s [%s] returned extensions despite HELO command",
4277c478bd9Sstevel@tonic-gate macvalue(macid("{server_name}"), e),
4287c478bd9Sstevel@tonic-gate macvalue(macid("{server_addr}"), e));
4297c478bd9Sstevel@tonic-gate logged = true;
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate return;
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_EXT_ON_HELO */
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate if (strlen(line) < 5)
4367c478bd9Sstevel@tonic-gate return;
4377c478bd9Sstevel@tonic-gate line += 4;
4387c478bd9Sstevel@tonic-gate p = strpbrk(line, " =");
4397c478bd9Sstevel@tonic-gate if (p != NULL)
4407c478bd9Sstevel@tonic-gate *p++ = '\0';
4417c478bd9Sstevel@tonic-gate if (sm_strcasecmp(line, "size") == 0)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_SIZE;
4447c478bd9Sstevel@tonic-gate if (p != NULL)
4457c478bd9Sstevel@tonic-gate mci->mci_maxsize = atol(p);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "8bitmime") == 0)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_8BITMIME;
4507c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_7BIT;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "expn") == 0)
4537c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_EXPN;
4547c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "dsn") == 0)
4557c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_DSN;
4567c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "enhancedstatuscodes") == 0)
4577c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_ENHSTAT;
4587c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "pipelining") == 0)
4597c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_PIPELINED;
4607c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "verb") == 0)
4617c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_VERB;
4627c478bd9Sstevel@tonic-gate #if STARTTLS
4637c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "starttls") == 0)
4647c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_TLS;
4657c478bd9Sstevel@tonic-gate #endif /* STARTTLS */
4667c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "deliverby") == 0)
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_DLVR_BY;
4697c478bd9Sstevel@tonic-gate if (p != NULL)
4707c478bd9Sstevel@tonic-gate mci->mci_min_by = atol(p);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate #if SASL
4737c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(line, "auth") == 0)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate if (p != NULL && *p != '\0')
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate if (mci->mci_saslcap != NULL)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate ** Create the union with previous auth
4817c478bd9Sstevel@tonic-gate ** offerings because we recognize "auth "
4827c478bd9Sstevel@tonic-gate ** and "auth=" (old format).
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate mci->mci_saslcap = str_union(mci->mci_saslcap,
4867c478bd9Sstevel@tonic-gate p, mci->mci_rpool);
4877c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTH;
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate else
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate int l;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate l = strlen(p) + 1;
4947c478bd9Sstevel@tonic-gate mci->mci_saslcap = (char *)
4957c478bd9Sstevel@tonic-gate sm_rpool_malloc(mci->mci_rpool, l);
4967c478bd9Sstevel@tonic-gate if (mci->mci_saslcap != NULL)
4977c478bd9Sstevel@tonic-gate {
4987c478bd9Sstevel@tonic-gate (void) sm_strlcpy(mci->mci_saslcap, p,
4997c478bd9Sstevel@tonic-gate l);
5007c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_AUTH;
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate #endif /* SASL */
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate #if SASL
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate static int getsimple __P((void *, int, const char **, unsigned *));
5107c478bd9Sstevel@tonic-gate static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
5117c478bd9Sstevel@tonic-gate static int saslgetrealm __P((void *, int, const char **, const char **));
5127c478bd9Sstevel@tonic-gate static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
5137c478bd9Sstevel@tonic-gate static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *));
5147c478bd9Sstevel@tonic-gate static char *removemech __P((char *, char *, SM_RPOOL_T *));
5157c478bd9Sstevel@tonic-gate static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate static sasl_callback_t callbacks[] =
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate { SASL_CB_GETREALM, &saslgetrealm, NULL },
5207c478bd9Sstevel@tonic-gate #define CB_GETREALM_IDX 0
5217c478bd9Sstevel@tonic-gate { SASL_CB_PASS, &getsecret, NULL },
5227c478bd9Sstevel@tonic-gate #define CB_PASS_IDX 1
5237c478bd9Sstevel@tonic-gate { SASL_CB_USER, &getsimple, NULL },
5247c478bd9Sstevel@tonic-gate #define CB_USER_IDX 2
5257c478bd9Sstevel@tonic-gate { SASL_CB_AUTHNAME, &getsimple, NULL },
5267c478bd9Sstevel@tonic-gate #define CB_AUTHNAME_IDX 3
5277c478bd9Sstevel@tonic-gate { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
5287c478bd9Sstevel@tonic-gate #define CB_SAFESASL_IDX 4
5297c478bd9Sstevel@tonic-gate { SASL_CB_LIST_END, NULL, NULL }
5307c478bd9Sstevel@tonic-gate };
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate ** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
5347c478bd9Sstevel@tonic-gate **
5357c478bd9Sstevel@tonic-gate ** Parameters:
5367c478bd9Sstevel@tonic-gate ** none.
5377c478bd9Sstevel@tonic-gate **
5387c478bd9Sstevel@tonic-gate ** Returns:
5397c478bd9Sstevel@tonic-gate ** SASL_OK -- if successful.
5407c478bd9Sstevel@tonic-gate ** SASL error code -- otherwise.
5417c478bd9Sstevel@tonic-gate **
5427c478bd9Sstevel@tonic-gate ** Side Effects:
5437c478bd9Sstevel@tonic-gate ** checks/sets sasl_clt_init.
544058561cbSjbeck **
545058561cbSjbeck ** Note:
546058561cbSjbeck ** Callbacks are ignored if sasl_client_init() has
547058561cbSjbeck ** been called before (by a library such as libnss_ldap)
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate static bool sasl_clt_init = false;
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate static int
init_sasl_client()5537c478bd9Sstevel@tonic-gate init_sasl_client()
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate int result;
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate if (sasl_clt_init)
5587c478bd9Sstevel@tonic-gate return SASL_OK;
5597c478bd9Sstevel@tonic-gate result = sasl_client_init(callbacks);
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate /* should we retry later again or just remember that it failed? */
5627c478bd9Sstevel@tonic-gate if (result == SASL_OK)
5637c478bd9Sstevel@tonic-gate sasl_clt_init = true;
5647c478bd9Sstevel@tonic-gate return result;
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate ** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
5687c478bd9Sstevel@tonic-gate **
5697c478bd9Sstevel@tonic-gate ** Parameters:
5707c478bd9Sstevel@tonic-gate ** none.
5717c478bd9Sstevel@tonic-gate **
5727c478bd9Sstevel@tonic-gate ** Returns:
5737c478bd9Sstevel@tonic-gate ** none.
5747c478bd9Sstevel@tonic-gate **
5757c478bd9Sstevel@tonic-gate ** Side Effects:
5767c478bd9Sstevel@tonic-gate ** checks/sets sasl_clt_init.
5777c478bd9Sstevel@tonic-gate */
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate void
stop_sasl_client()5807c478bd9Sstevel@tonic-gate stop_sasl_client()
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate if (!sasl_clt_init)
5837c478bd9Sstevel@tonic-gate return;
5847c478bd9Sstevel@tonic-gate sasl_clt_init = false;
5857c478bd9Sstevel@tonic-gate sasl_done();
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate ** GETSASLDATA -- process the challenges from the SASL protocol
5897c478bd9Sstevel@tonic-gate **
5907c478bd9Sstevel@tonic-gate ** This gets the relevant sasl response data out of the reply
5917c478bd9Sstevel@tonic-gate ** from the server.
5927c478bd9Sstevel@tonic-gate **
5937c478bd9Sstevel@tonic-gate ** Parameters:
5947c478bd9Sstevel@tonic-gate ** line -- the response line.
5957c478bd9Sstevel@tonic-gate ** firstline -- set if this is the first line of the reply.
5967c478bd9Sstevel@tonic-gate ** m -- the mailer.
5977c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info.
5987c478bd9Sstevel@tonic-gate ** e -- the envelope (unused).
5997c478bd9Sstevel@tonic-gate **
6007c478bd9Sstevel@tonic-gate ** Returns:
6017c478bd9Sstevel@tonic-gate ** none.
6027c478bd9Sstevel@tonic-gate */
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate static void
getsasldata(line,firstline,m,mci,e)6077c478bd9Sstevel@tonic-gate getsasldata(line, firstline, m, mci, e)
6087c478bd9Sstevel@tonic-gate char *line;
6097c478bd9Sstevel@tonic-gate bool firstline;
6107c478bd9Sstevel@tonic-gate MAILER *m;
6117c478bd9Sstevel@tonic-gate register MCI *mci;
6127c478bd9Sstevel@tonic-gate ENVELOPE *e;
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate int len;
6157c478bd9Sstevel@tonic-gate int result;
6167c478bd9Sstevel@tonic-gate # if SASL < 20000
6177c478bd9Sstevel@tonic-gate char *out;
6187c478bd9Sstevel@tonic-gate # endif /* SASL < 20000 */
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate /* if not a continue we don't care about it */
6217c478bd9Sstevel@tonic-gate len = strlen(line);
6227c478bd9Sstevel@tonic-gate if ((len <= 4) ||
6237c478bd9Sstevel@tonic-gate (line[0] != '3') ||
6247c478bd9Sstevel@tonic-gate !isascii(line[1]) || !isdigit(line[1]) ||
6257c478bd9Sstevel@tonic-gate !isascii(line[2]) || !isdigit(line[2]))
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate SM_FREE_CLR(mci->mci_sasl_string);
6287c478bd9Sstevel@tonic-gate return;
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate /* forget about "334 " */
6327c478bd9Sstevel@tonic-gate line += 4;
6337c478bd9Sstevel@tonic-gate len -= 4;
6347c478bd9Sstevel@tonic-gate # if SASL >= 20000
6357c478bd9Sstevel@tonic-gate /* XXX put this into a macro/function? It's duplicated below */
6367c478bd9Sstevel@tonic-gate if (mci->mci_sasl_string != NULL)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate if (mci->mci_sasl_string_len <= len)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate sm_free(mci->mci_sasl_string); /* XXX */
6417c478bd9Sstevel@tonic-gate mci->mci_sasl_string = xalloc(len + 1);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate else
6457c478bd9Sstevel@tonic-gate mci->mci_sasl_string = xalloc(len + 1);
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
6487c478bd9Sstevel@tonic-gate (unsigned int *) &mci->mci_sasl_string_len);
6497c478bd9Sstevel@tonic-gate if (result != SASL_OK)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate mci->mci_sasl_string_len = 0;
6527c478bd9Sstevel@tonic-gate *mci->mci_sasl_string = '\0';
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
6557c478bd9Sstevel@tonic-gate out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
6567c478bd9Sstevel@tonic-gate result = sasl_decode64(line, len, out, (unsigned int *) &len);
6577c478bd9Sstevel@tonic-gate if (result != SASL_OK)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate len = 0;
6607c478bd9Sstevel@tonic-gate *out = '\0';
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate ** mci_sasl_string is "shared" with Cyrus-SASL library; hence
6657c478bd9Sstevel@tonic-gate ** it can't be in an rpool unless we use the same memory
6667c478bd9Sstevel@tonic-gate ** management mechanism (with same rpool!) for Cyrus SASL.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate if (mci->mci_sasl_string != NULL)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate if (mci->mci_sasl_string_len <= len)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate sm_free(mci->mci_sasl_string); /* XXX */
6747c478bd9Sstevel@tonic-gate mci->mci_sasl_string = xalloc(len + 1);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate else
6787c478bd9Sstevel@tonic-gate mci->mci_sasl_string = xalloc(len + 1);
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate memcpy(mci->mci_sasl_string, out, len);
6817c478bd9Sstevel@tonic-gate mci->mci_sasl_string[len] = '\0';
6827c478bd9Sstevel@tonic-gate mci->mci_sasl_string_len = len;
6837c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
6847c478bd9Sstevel@tonic-gate return;
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate /*
6877c478bd9Sstevel@tonic-gate ** READAUTH -- read auth values from a file
6887c478bd9Sstevel@tonic-gate **
6897c478bd9Sstevel@tonic-gate ** Parameters:
6907c478bd9Sstevel@tonic-gate ** filename -- name of file to read.
6917c478bd9Sstevel@tonic-gate ** safe -- if set, this is a safe read.
6927c478bd9Sstevel@tonic-gate ** sai -- where to store auth_info.
6937c478bd9Sstevel@tonic-gate ** rpool -- resource pool for sai.
6947c478bd9Sstevel@tonic-gate **
6957c478bd9Sstevel@tonic-gate ** Returns:
6967c478bd9Sstevel@tonic-gate ** EX_OK -- data succesfully read.
6977c478bd9Sstevel@tonic-gate ** EX_UNAVAILABLE -- no valid filename.
6987c478bd9Sstevel@tonic-gate ** EX_TEMPFAIL -- temporary failure.
6997c478bd9Sstevel@tonic-gate */
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate static char *sasl_info_name[] =
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate "user id",
7047c478bd9Sstevel@tonic-gate "authentication id",
7057c478bd9Sstevel@tonic-gate "password",
7067c478bd9Sstevel@tonic-gate "realm",
7077c478bd9Sstevel@tonic-gate "mechlist"
7087c478bd9Sstevel@tonic-gate };
7097c478bd9Sstevel@tonic-gate static int
readauth(filename,safe,sai,rpool)7107c478bd9Sstevel@tonic-gate readauth(filename, safe, sai, rpool)
7117c478bd9Sstevel@tonic-gate char *filename;
7127c478bd9Sstevel@tonic-gate bool safe;
7137c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
7147c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate SM_FILE_T *f;
7177c478bd9Sstevel@tonic-gate long sff;
7187c478bd9Sstevel@tonic-gate pid_t pid;
7197c478bd9Sstevel@tonic-gate int lc;
7207c478bd9Sstevel@tonic-gate char *s;
7217c478bd9Sstevel@tonic-gate char buf[MAXLINE];
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate if (filename == NULL || filename[0] == '\0')
7247c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate #if !_FFR_ALLOW_SASLINFO
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate ** make sure we don't use a program that is not
7297c478bd9Sstevel@tonic-gate ** accesible to the user who specified a different authinfo file.
7307c478bd9Sstevel@tonic-gate ** However, currently we don't pass this info (authinfo file
7317c478bd9Sstevel@tonic-gate ** specified by user) around, so we just turn off program access.
7327c478bd9Sstevel@tonic-gate */
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate if (filename[0] == '|')
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate auto int fd;
7377c478bd9Sstevel@tonic-gate int i;
7387c478bd9Sstevel@tonic-gate char *p;
7397c478bd9Sstevel@tonic-gate char *argv[MAXPV + 1];
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate i = 0;
7427c478bd9Sstevel@tonic-gate for (p = strtok(&filename[1], " \t"); p != NULL;
7437c478bd9Sstevel@tonic-gate p = strtok(NULL, " \t"))
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate if (i >= MAXPV)
7467c478bd9Sstevel@tonic-gate break;
7477c478bd9Sstevel@tonic-gate argv[i++] = p;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate argv[i] = NULL;
7507c478bd9Sstevel@tonic-gate pid = prog_open(argv, &fd, CurEnv);
7517c478bd9Sstevel@tonic-gate if (pid < 0)
7527c478bd9Sstevel@tonic-gate f = NULL;
7537c478bd9Sstevel@tonic-gate else
7547c478bd9Sstevel@tonic-gate f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
7557c478bd9Sstevel@tonic-gate (void *) &fd, SM_IO_RDONLY, NULL);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate else
7587c478bd9Sstevel@tonic-gate #endif /* !_FFR_ALLOW_SASLINFO */
7597c478bd9Sstevel@tonic-gate {
7607c478bd9Sstevel@tonic-gate pid = -1;
7617c478bd9Sstevel@tonic-gate sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
7627c478bd9Sstevel@tonic-gate |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
7637c478bd9Sstevel@tonic-gate # if _FFR_GROUPREADABLEAUTHINFOFILE
7647c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
7657c478bd9Sstevel@tonic-gate # endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
7667c478bd9Sstevel@tonic-gate sff |= SFF_NOGRFILES;
7677c478bd9Sstevel@tonic-gate if (DontLockReadFiles)
7687c478bd9Sstevel@tonic-gate sff |= SFF_NOLOCK;
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate #if _FFR_ALLOW_SASLINFO
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate ** XXX: make sure we don't read or open files that are not
7737c478bd9Sstevel@tonic-gate ** accesible to the user who specified a different authinfo
7747c478bd9Sstevel@tonic-gate ** file.
7757c478bd9Sstevel@tonic-gate */
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate sff |= SFF_MUSTOWN;
7787c478bd9Sstevel@tonic-gate #else /* _FFR_ALLOW_SASLINFO */
7797c478bd9Sstevel@tonic-gate if (safe)
7807c478bd9Sstevel@tonic-gate sff |= SFF_OPENASROOT;
7817c478bd9Sstevel@tonic-gate #endif /* _FFR_ALLOW_SASLINFO */
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate f = safefopen(filename, O_RDONLY, 0, sff);
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate if (f == NULL)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate if (LogLevel > 5)
7887c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
7897c478bd9Sstevel@tonic-gate "AUTH=client, error: can't open %s: %s",
7907c478bd9Sstevel@tonic-gate filename, sm_errstring(errno));
7917c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate lc = 0;
7957c478bd9Sstevel@tonic-gate while (lc <= SASL_MECHLIST &&
796058561cbSjbeck sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate if (buf[0] != '#')
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate (*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
8017c478bd9Sstevel@tonic-gate if ((s = strchr((*sai)[lc], '\n')) != NULL)
8027c478bd9Sstevel@tonic-gate *s = '\0';
8037c478bd9Sstevel@tonic-gate lc++;
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate (void) sm_io_close(f, SM_TIME_DEFAULT);
8087c478bd9Sstevel@tonic-gate if (pid > 0)
8097c478bd9Sstevel@tonic-gate (void) waitfor(pid);
8107c478bd9Sstevel@tonic-gate if (lc < SASL_PASSWORD)
8117c478bd9Sstevel@tonic-gate {
8127c478bd9Sstevel@tonic-gate if (LogLevel > 8)
8137c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
8147c478bd9Sstevel@tonic-gate "AUTH=client, error: can't read %s from %s",
8157c478bd9Sstevel@tonic-gate sasl_info_name[lc + 1], filename);
8167c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate return EX_OK;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate ** GETAUTH -- get authinfo from ruleset call
8237c478bd9Sstevel@tonic-gate **
8247c478bd9Sstevel@tonic-gate ** {server_name}, {server_addr} must be set
8257c478bd9Sstevel@tonic-gate **
8267c478bd9Sstevel@tonic-gate ** Parameters:
8277c478bd9Sstevel@tonic-gate ** mci -- the mailer connection structure.
8287c478bd9Sstevel@tonic-gate ** e -- the envelope (including the sender to specify).
8297c478bd9Sstevel@tonic-gate ** sai -- pointer to authinfo (result).
8307c478bd9Sstevel@tonic-gate **
8317c478bd9Sstevel@tonic-gate ** Returns:
8327c478bd9Sstevel@tonic-gate ** EX_OK -- ruleset was succesfully called, data may not
8337c478bd9Sstevel@tonic-gate ** be available, sai must be checked.
8347c478bd9Sstevel@tonic-gate ** EX_UNAVAILABLE -- ruleset unavailable (or failed).
8357c478bd9Sstevel@tonic-gate ** EX_TEMPFAIL -- temporary failure (from ruleset).
8367c478bd9Sstevel@tonic-gate **
8377c478bd9Sstevel@tonic-gate ** Side Effects:
8387c478bd9Sstevel@tonic-gate ** Fills in sai if successful.
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate static int
getauth(mci,e,sai)8427c478bd9Sstevel@tonic-gate getauth(mci, e, sai)
8437c478bd9Sstevel@tonic-gate MCI *mci;
8447c478bd9Sstevel@tonic-gate ENVELOPE *e;
8457c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate int i, r, l, got, ret;
8487c478bd9Sstevel@tonic-gate char **pvp;
8497c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate r = rscap("authinfo", macvalue(macid("{server_name}"), e),
8527c478bd9Sstevel@tonic-gate macvalue(macid("{server_addr}"), e), e,
8537c478bd9Sstevel@tonic-gate &pvp, pvpbuf, sizeof(pvpbuf));
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate if (r != EX_OK)
8567c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate /* other than expected return value: ok (i.e., no auth) */
8597c478bd9Sstevel@tonic-gate if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
8607c478bd9Sstevel@tonic-gate return EX_OK;
8617c478bd9Sstevel@tonic-gate if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
8627c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate ** parse the data, put it into sai
8667c478bd9Sstevel@tonic-gate ** format: "TDstring" (including the '"' !)
8677c478bd9Sstevel@tonic-gate ** where T is a tag: 'U', ...
8687c478bd9Sstevel@tonic-gate ** D is a delimiter: ':' or '='
8697c478bd9Sstevel@tonic-gate */
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate ret = EX_OK; /* default return value */
8727c478bd9Sstevel@tonic-gate i = 0;
8737c478bd9Sstevel@tonic-gate got = 0;
8747c478bd9Sstevel@tonic-gate while (i < SASL_ENTRIES)
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate if (pvp[i + 1] == NULL)
8777c478bd9Sstevel@tonic-gate break;
8787c478bd9Sstevel@tonic-gate if (pvp[i + 1][0] != '"')
8797c478bd9Sstevel@tonic-gate break;
8807c478bd9Sstevel@tonic-gate switch (pvp[i + 1][1])
8817c478bd9Sstevel@tonic-gate {
8827c478bd9Sstevel@tonic-gate case 'U':
8837c478bd9Sstevel@tonic-gate case 'u':
8847c478bd9Sstevel@tonic-gate r = SASL_USER;
8857c478bd9Sstevel@tonic-gate break;
8867c478bd9Sstevel@tonic-gate case 'I':
8877c478bd9Sstevel@tonic-gate case 'i':
8887c478bd9Sstevel@tonic-gate r = SASL_AUTHID;
8897c478bd9Sstevel@tonic-gate break;
8907c478bd9Sstevel@tonic-gate case 'P':
8917c478bd9Sstevel@tonic-gate case 'p':
8927c478bd9Sstevel@tonic-gate r = SASL_PASSWORD;
8937c478bd9Sstevel@tonic-gate break;
8947c478bd9Sstevel@tonic-gate case 'R':
8957c478bd9Sstevel@tonic-gate case 'r':
8967c478bd9Sstevel@tonic-gate r = SASL_DEFREALM;
8977c478bd9Sstevel@tonic-gate break;
8987c478bd9Sstevel@tonic-gate case 'M':
8997c478bd9Sstevel@tonic-gate case 'm':
9007c478bd9Sstevel@tonic-gate r = SASL_MECHLIST;
9017c478bd9Sstevel@tonic-gate break;
9027c478bd9Sstevel@tonic-gate default:
9037c478bd9Sstevel@tonic-gate goto fail;
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate l = strlen(pvp[i + 1]);
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate /* check syntax */
9087c478bd9Sstevel@tonic-gate if (l <= 3 || pvp[i + 1][l - 1] != '"')
9097c478bd9Sstevel@tonic-gate goto fail;
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /* remove closing quote */
9127c478bd9Sstevel@tonic-gate pvp[i + 1][l - 1] = '\0';
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate /* remove "TD and " */
9157c478bd9Sstevel@tonic-gate l -= 4;
9167c478bd9Sstevel@tonic-gate (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
9177c478bd9Sstevel@tonic-gate if ((*sai)[r] == NULL)
9187c478bd9Sstevel@tonic-gate goto tempfail;
9197c478bd9Sstevel@tonic-gate if (pvp[i + 1][2] == ':')
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate /* ':text' (just copy) */
9227c478bd9Sstevel@tonic-gate (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
9237c478bd9Sstevel@tonic-gate got |= 1 << r;
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate else if (pvp[i + 1][2] == '=')
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate unsigned int len;
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate /* '=base64' (decode) */
9307c478bd9Sstevel@tonic-gate # if SASL >= 20000
9317c478bd9Sstevel@tonic-gate ret = sasl_decode64(pvp[i + 1] + 3,
9327c478bd9Sstevel@tonic-gate (unsigned int) l, (*sai)[r],
9337c478bd9Sstevel@tonic-gate (unsigned int) l + 1, &len);
9347c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
9357c478bd9Sstevel@tonic-gate ret = sasl_decode64(pvp[i + 1] + 3,
9367c478bd9Sstevel@tonic-gate (unsigned int) l, (*sai)[r], &len);
9377c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
9387c478bd9Sstevel@tonic-gate if (ret != SASL_OK)
9397c478bd9Sstevel@tonic-gate goto fail;
9407c478bd9Sstevel@tonic-gate got |= 1 << r;
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate else
9437c478bd9Sstevel@tonic-gate goto fail;
9447c478bd9Sstevel@tonic-gate if (tTd(95, 5))
9457c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
9467c478bd9Sstevel@tonic-gate sasl_info_name[r], (*sai)[r]);
9477c478bd9Sstevel@tonic-gate ++i;
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate /* did we get the expected data? */
9517c478bd9Sstevel@tonic-gate /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */
9527c478bd9Sstevel@tonic-gate if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
9537c478bd9Sstevel@tonic-gate bitset(SASL_PASSWORD_BIT, got)))
9547c478bd9Sstevel@tonic-gate goto fail;
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate /* no authid? copy uid */
9577c478bd9Sstevel@tonic-gate if (!bitset(SASL_AUTHID_BIT, got))
9587c478bd9Sstevel@tonic-gate {
9597c478bd9Sstevel@tonic-gate l = strlen((*sai)[SASL_USER]) + 1;
9607c478bd9Sstevel@tonic-gate (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
9617c478bd9Sstevel@tonic-gate l + 1);
9627c478bd9Sstevel@tonic-gate if ((*sai)[SASL_AUTHID] == NULL)
9637c478bd9Sstevel@tonic-gate goto tempfail;
9647c478bd9Sstevel@tonic-gate (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate /* no uid? copy authid */
9687c478bd9Sstevel@tonic-gate if (!bitset(SASL_USER_BIT, got))
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate l = strlen((*sai)[SASL_AUTHID]) + 1;
9717c478bd9Sstevel@tonic-gate (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
9727c478bd9Sstevel@tonic-gate l + 1);
9737c478bd9Sstevel@tonic-gate if ((*sai)[SASL_USER] == NULL)
9747c478bd9Sstevel@tonic-gate goto tempfail;
9757c478bd9Sstevel@tonic-gate (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate return EX_OK;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate tempfail:
9807c478bd9Sstevel@tonic-gate ret = EX_TEMPFAIL;
9817c478bd9Sstevel@tonic-gate fail:
9827c478bd9Sstevel@tonic-gate if (LogLevel > 8)
9837c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
9847c478bd9Sstevel@tonic-gate "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
9857c478bd9Sstevel@tonic-gate macvalue(macid("{server_name}"), e),
9867c478bd9Sstevel@tonic-gate macvalue(macid("{server_addr}"), e),
9877c478bd9Sstevel@tonic-gate ret == EX_TEMPFAIL ? "temp" : "");
9887c478bd9Sstevel@tonic-gate for (i = 0; i <= SASL_MECHLIST; i++)
9897c478bd9Sstevel@tonic-gate (*sai)[i] = NULL; /* just clear; rpool */
9907c478bd9Sstevel@tonic-gate return ret;
9917c478bd9Sstevel@tonic-gate }
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate # if SASL >= 20000
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate ** GETSIMPLE -- callback to get userid or authid
9967c478bd9Sstevel@tonic-gate **
9977c478bd9Sstevel@tonic-gate ** Parameters:
9987c478bd9Sstevel@tonic-gate ** context -- sai
9997c478bd9Sstevel@tonic-gate ** id -- what to do
10007c478bd9Sstevel@tonic-gate ** result -- (pointer to) result
10017c478bd9Sstevel@tonic-gate ** len -- (pointer to) length of result
10027c478bd9Sstevel@tonic-gate **
10037c478bd9Sstevel@tonic-gate ** Returns:
10047c478bd9Sstevel@tonic-gate ** OK/failure values
10057c478bd9Sstevel@tonic-gate */
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate static int
getsimple(context,id,result,len)10087c478bd9Sstevel@tonic-gate getsimple(context, id, result, len)
10097c478bd9Sstevel@tonic-gate void *context;
10107c478bd9Sstevel@tonic-gate int id;
10117c478bd9Sstevel@tonic-gate const char **result;
10127c478bd9Sstevel@tonic-gate unsigned *len;
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gate if (result == NULL || context == NULL)
10177c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
10187c478bd9Sstevel@tonic-gate sai = (SASL_AI_T *) context;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate switch (id)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate case SASL_CB_USER:
10237c478bd9Sstevel@tonic-gate *result = (*sai)[SASL_USER];
10247c478bd9Sstevel@tonic-gate if (tTd(95, 5))
10257c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
10267c478bd9Sstevel@tonic-gate *result);
10277c478bd9Sstevel@tonic-gate if (len != NULL)
10287c478bd9Sstevel@tonic-gate *len = *result != NULL ? strlen(*result) : 0;
10297c478bd9Sstevel@tonic-gate break;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate case SASL_CB_AUTHNAME:
10327c478bd9Sstevel@tonic-gate *result = (*sai)[SASL_AUTHID];
10337c478bd9Sstevel@tonic-gate if (tTd(95, 5))
10347c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
10357c478bd9Sstevel@tonic-gate *result);
10367c478bd9Sstevel@tonic-gate if (len != NULL)
10377c478bd9Sstevel@tonic-gate *len = *result != NULL ? strlen(*result) : 0;
10387c478bd9Sstevel@tonic-gate break;
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate case SASL_CB_LANGUAGE:
10417c478bd9Sstevel@tonic-gate *result = NULL;
10427c478bd9Sstevel@tonic-gate if (len != NULL)
10437c478bd9Sstevel@tonic-gate *len = 0;
10447c478bd9Sstevel@tonic-gate break;
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate default:
10477c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate return SASL_OK;
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate ** GETSECRET -- callback to get password
10537c478bd9Sstevel@tonic-gate **
10547c478bd9Sstevel@tonic-gate ** Parameters:
10557c478bd9Sstevel@tonic-gate ** conn -- connection information
10567c478bd9Sstevel@tonic-gate ** context -- sai
10577c478bd9Sstevel@tonic-gate ** id -- what to do
10587c478bd9Sstevel@tonic-gate ** psecret -- (pointer to) result
10597c478bd9Sstevel@tonic-gate **
10607c478bd9Sstevel@tonic-gate ** Returns:
10617c478bd9Sstevel@tonic-gate ** OK/failure values
10627c478bd9Sstevel@tonic-gate */
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate static int
getsecret(conn,context,id,psecret)10657c478bd9Sstevel@tonic-gate getsecret(conn, context, id, psecret)
10667c478bd9Sstevel@tonic-gate sasl_conn_t *conn;
10677c478bd9Sstevel@tonic-gate SM_UNUSED(void *context);
10687c478bd9Sstevel@tonic-gate int id;
10697c478bd9Sstevel@tonic-gate sasl_secret_t **psecret;
10707c478bd9Sstevel@tonic-gate {
10717c478bd9Sstevel@tonic-gate int len;
10727c478bd9Sstevel@tonic-gate char *authpass;
10737c478bd9Sstevel@tonic-gate MCI *mci;
10747c478bd9Sstevel@tonic-gate
10757c478bd9Sstevel@tonic-gate if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
10767c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate mci = (MCI *) context;
10797c478bd9Sstevel@tonic-gate authpass = mci->mci_sai[SASL_PASSWORD];
10807c478bd9Sstevel@tonic-gate len = strlen(authpass);
10817c478bd9Sstevel@tonic-gate
10827c478bd9Sstevel@tonic-gate /*
10837c478bd9Sstevel@tonic-gate ** use an rpool because we are responsible for free()ing the secret,
10847c478bd9Sstevel@tonic-gate ** but we can't free() it until after the auth completes
10857c478bd9Sstevel@tonic-gate */
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
10887c478bd9Sstevel@tonic-gate sizeof(sasl_secret_t) +
10897c478bd9Sstevel@tonic-gate len + 1);
10907c478bd9Sstevel@tonic-gate if (*psecret == NULL)
10917c478bd9Sstevel@tonic-gate return SASL_FAIL;
10927c478bd9Sstevel@tonic-gate (void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1);
10937c478bd9Sstevel@tonic-gate (*psecret)->len = (unsigned long) len;
10947c478bd9Sstevel@tonic-gate return SASL_OK;
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
10977c478bd9Sstevel@tonic-gate /*
10987c478bd9Sstevel@tonic-gate ** GETSIMPLE -- callback to get userid or authid
10997c478bd9Sstevel@tonic-gate **
11007c478bd9Sstevel@tonic-gate ** Parameters:
11017c478bd9Sstevel@tonic-gate ** context -- sai
11027c478bd9Sstevel@tonic-gate ** id -- what to do
11037c478bd9Sstevel@tonic-gate ** result -- (pointer to) result
11047c478bd9Sstevel@tonic-gate ** len -- (pointer to) length of result
11057c478bd9Sstevel@tonic-gate **
11067c478bd9Sstevel@tonic-gate ** Returns:
11077c478bd9Sstevel@tonic-gate ** OK/failure values
11087c478bd9Sstevel@tonic-gate */
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate static int
getsimple(context,id,result,len)11117c478bd9Sstevel@tonic-gate getsimple(context, id, result, len)
11127c478bd9Sstevel@tonic-gate void *context;
11137c478bd9Sstevel@tonic-gate int id;
11147c478bd9Sstevel@tonic-gate const char **result;
11157c478bd9Sstevel@tonic-gate unsigned *len;
11167c478bd9Sstevel@tonic-gate {
11177c478bd9Sstevel@tonic-gate char *h, *s;
11187c478bd9Sstevel@tonic-gate # if SASL > 10509
11197c478bd9Sstevel@tonic-gate bool addrealm;
11207c478bd9Sstevel@tonic-gate # endif /* SASL > 10509 */
11217c478bd9Sstevel@tonic-gate size_t l;
11227c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
11237c478bd9Sstevel@tonic-gate char *authid = NULL;
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate if (result == NULL || context == NULL)
11267c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
11277c478bd9Sstevel@tonic-gate sai = (SASL_AI_T *) context;
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate ** Unfortunately it is not clear whether this routine should
11317c478bd9Sstevel@tonic-gate ** return a copy of a string or just a pointer to a string.
11327c478bd9Sstevel@tonic-gate ** The Cyrus-SASL plugins treat these return values differently, e.g.,
11337c478bd9Sstevel@tonic-gate ** plugins/cram.c free()s authid, plugings/digestmd5.c does not.
11347c478bd9Sstevel@tonic-gate ** The best solution to this problem is to fix Cyrus-SASL, but it
11357c478bd9Sstevel@tonic-gate ** seems there is nobody who creates patches... Hello CMU!?
11367c478bd9Sstevel@tonic-gate ** The second best solution is to have flags that tell this routine
11377c478bd9Sstevel@tonic-gate ** whether to return an malloc()ed copy.
11387c478bd9Sstevel@tonic-gate ** The next best solution is to always return an malloc()ed copy,
11397c478bd9Sstevel@tonic-gate ** and suffer from some memory leak, which is ugly for persistent
11407c478bd9Sstevel@tonic-gate ** queue runners.
11417c478bd9Sstevel@tonic-gate ** For now we go with the last solution...
11427c478bd9Sstevel@tonic-gate ** We can't use rpools (which would avoid this particular problem)
11437c478bd9Sstevel@tonic-gate ** as explained in sasl.c.
11447c478bd9Sstevel@tonic-gate */
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate switch (id)
11477c478bd9Sstevel@tonic-gate {
11487c478bd9Sstevel@tonic-gate case SASL_CB_USER:
11497c478bd9Sstevel@tonic-gate l = strlen((*sai)[SASL_USER]) + 1;
11507c478bd9Sstevel@tonic-gate s = sm_sasl_malloc(l);
11517c478bd9Sstevel@tonic-gate if (s == NULL)
11527c478bd9Sstevel@tonic-gate {
11537c478bd9Sstevel@tonic-gate if (len != NULL)
11547c478bd9Sstevel@tonic-gate *len = 0;
11557c478bd9Sstevel@tonic-gate *result = NULL;
11567c478bd9Sstevel@tonic-gate return SASL_NOMEM;
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate (void) sm_strlcpy(s, (*sai)[SASL_USER], l);
11597c478bd9Sstevel@tonic-gate *result = s;
11607c478bd9Sstevel@tonic-gate if (tTd(95, 5))
11617c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
11627c478bd9Sstevel@tonic-gate *result);
11637c478bd9Sstevel@tonic-gate if (len != NULL)
11647c478bd9Sstevel@tonic-gate *len = *result != NULL ? strlen(*result) : 0;
11657c478bd9Sstevel@tonic-gate break;
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate case SASL_CB_AUTHNAME:
11687c478bd9Sstevel@tonic-gate h = (*sai)[SASL_AUTHID];
11697c478bd9Sstevel@tonic-gate # if SASL > 10509
11707c478bd9Sstevel@tonic-gate /* XXX maybe other mechanisms too?! */
11717c478bd9Sstevel@tonic-gate addrealm = (*sai)[SASL_MECH] != NULL &&
11727c478bd9Sstevel@tonic-gate sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0;
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate /*
11757c478bd9Sstevel@tonic-gate ** Add realm to authentication id unless authid contains
11767c478bd9Sstevel@tonic-gate ** '@' (i.e., a realm) or the default realm is empty.
11777c478bd9Sstevel@tonic-gate */
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate if (addrealm && h != NULL && strchr(h, '@') == NULL)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate /* has this been done before? */
11827c478bd9Sstevel@tonic-gate if ((*sai)[SASL_ID_REALM] == NULL)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate char *realm;
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate realm = (*sai)[SASL_DEFREALM];
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate /* do not add an empty realm */
11897c478bd9Sstevel@tonic-gate if (*realm == '\0')
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate authid = h;
11927c478bd9Sstevel@tonic-gate (*sai)[SASL_ID_REALM] = NULL;
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate else
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate l = strlen(h) + strlen(realm) + 2;
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate /* should use rpool, but from where? */
11997c478bd9Sstevel@tonic-gate authid = sm_sasl_malloc(l);
12007c478bd9Sstevel@tonic-gate if (authid != NULL)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate (void) sm_snprintf(authid, l,
12037c478bd9Sstevel@tonic-gate "%s@%s",
12047c478bd9Sstevel@tonic-gate h, realm);
12057c478bd9Sstevel@tonic-gate (*sai)[SASL_ID_REALM] = authid;
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate else
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate authid = h;
12107c478bd9Sstevel@tonic-gate (*sai)[SASL_ID_REALM] = NULL;
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate else
12157c478bd9Sstevel@tonic-gate authid = (*sai)[SASL_ID_REALM];
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate else
12187c478bd9Sstevel@tonic-gate # endif /* SASL > 10509 */
12197c478bd9Sstevel@tonic-gate authid = h;
12207c478bd9Sstevel@tonic-gate l = strlen(authid) + 1;
12217c478bd9Sstevel@tonic-gate s = sm_sasl_malloc(l);
12227c478bd9Sstevel@tonic-gate if (s == NULL)
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate if (len != NULL)
12257c478bd9Sstevel@tonic-gate *len = 0;
12267c478bd9Sstevel@tonic-gate *result = NULL;
12277c478bd9Sstevel@tonic-gate return SASL_NOMEM;
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate (void) sm_strlcpy(s, authid, l);
12307c478bd9Sstevel@tonic-gate *result = s;
12317c478bd9Sstevel@tonic-gate if (tTd(95, 5))
12327c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
12337c478bd9Sstevel@tonic-gate *result);
12347c478bd9Sstevel@tonic-gate if (len != NULL)
12357c478bd9Sstevel@tonic-gate *len = authid ? strlen(authid) : 0;
12367c478bd9Sstevel@tonic-gate break;
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate case SASL_CB_LANGUAGE:
12397c478bd9Sstevel@tonic-gate *result = NULL;
12407c478bd9Sstevel@tonic-gate if (len != NULL)
12417c478bd9Sstevel@tonic-gate *len = 0;
12427c478bd9Sstevel@tonic-gate break;
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate default:
12457c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate return SASL_OK;
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate /*
12507c478bd9Sstevel@tonic-gate ** GETSECRET -- callback to get password
12517c478bd9Sstevel@tonic-gate **
12527c478bd9Sstevel@tonic-gate ** Parameters:
12537c478bd9Sstevel@tonic-gate ** conn -- connection information
12547c478bd9Sstevel@tonic-gate ** context -- sai
12557c478bd9Sstevel@tonic-gate ** id -- what to do
12567c478bd9Sstevel@tonic-gate ** psecret -- (pointer to) result
12577c478bd9Sstevel@tonic-gate **
12587c478bd9Sstevel@tonic-gate ** Returns:
12597c478bd9Sstevel@tonic-gate ** OK/failure values
12607c478bd9Sstevel@tonic-gate */
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate static int
getsecret(conn,context,id,psecret)12637c478bd9Sstevel@tonic-gate getsecret(conn, context, id, psecret)
12647c478bd9Sstevel@tonic-gate sasl_conn_t *conn;
12657c478bd9Sstevel@tonic-gate SM_UNUSED(void *context);
12667c478bd9Sstevel@tonic-gate int id;
12677c478bd9Sstevel@tonic-gate sasl_secret_t **psecret;
12687c478bd9Sstevel@tonic-gate {
12697c478bd9Sstevel@tonic-gate int len;
12707c478bd9Sstevel@tonic-gate char *authpass;
12717c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
12747c478bd9Sstevel@tonic-gate return SASL_BADPARAM;
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate sai = (SASL_AI_T *) context;
12777c478bd9Sstevel@tonic-gate authpass = (*sai)[SASL_PASSWORD];
12787c478bd9Sstevel@tonic-gate len = strlen(authpass);
12797c478bd9Sstevel@tonic-gate *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
12807c478bd9Sstevel@tonic-gate len + 1);
12817c478bd9Sstevel@tonic-gate if (*psecret == NULL)
12827c478bd9Sstevel@tonic-gate return SASL_FAIL;
12837c478bd9Sstevel@tonic-gate (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
12847c478bd9Sstevel@tonic-gate (*psecret)->len = (unsigned long) len;
12857c478bd9Sstevel@tonic-gate return SASL_OK;
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate /*
12907c478bd9Sstevel@tonic-gate ** SAFESASLFILE -- callback for sasl: is file safe?
12917c478bd9Sstevel@tonic-gate **
12927c478bd9Sstevel@tonic-gate ** Parameters:
12937c478bd9Sstevel@tonic-gate ** context -- pointer to context between invocations (unused)
12947c478bd9Sstevel@tonic-gate ** file -- name of file to check
12957c478bd9Sstevel@tonic-gate ** type -- type of file to check
12967c478bd9Sstevel@tonic-gate **
12977c478bd9Sstevel@tonic-gate ** Returns:
12987c478bd9Sstevel@tonic-gate ** SASL_OK -- file can be used
12997c478bd9Sstevel@tonic-gate ** SASL_CONTINUE -- don't use file
13007c478bd9Sstevel@tonic-gate ** SASL_FAIL -- failure (not used here)
13017c478bd9Sstevel@tonic-gate **
13027c478bd9Sstevel@tonic-gate */
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate int
13057c478bd9Sstevel@tonic-gate #if SASL > 10515
safesaslfile(context,file,type)13067c478bd9Sstevel@tonic-gate safesaslfile(context, file, type)
13077c478bd9Sstevel@tonic-gate #else /* SASL > 10515 */
13087c478bd9Sstevel@tonic-gate safesaslfile(context, file)
13097c478bd9Sstevel@tonic-gate #endif /* SASL > 10515 */
13107c478bd9Sstevel@tonic-gate void *context;
13117c478bd9Sstevel@tonic-gate # if SASL >= 20000
13127c478bd9Sstevel@tonic-gate const char *file;
13137c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
13147c478bd9Sstevel@tonic-gate char *file;
13157c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
13167c478bd9Sstevel@tonic-gate #if SASL > 10515
13177c478bd9Sstevel@tonic-gate # if SASL >= 20000
13187c478bd9Sstevel@tonic-gate sasl_verify_type_t type;
13197c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
13207c478bd9Sstevel@tonic-gate int type;
13217c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
13227c478bd9Sstevel@tonic-gate #endif /* SASL > 10515 */
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate long sff;
13257c478bd9Sstevel@tonic-gate int r;
13267c478bd9Sstevel@tonic-gate #if SASL <= 10515
13277c478bd9Sstevel@tonic-gate size_t len;
13287c478bd9Sstevel@tonic-gate #endif /* SASL <= 10515 */
13297c478bd9Sstevel@tonic-gate char *p;
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate if (file == NULL || *file == '\0')
13327c478bd9Sstevel@tonic-gate return SASL_OK;
13337c478bd9Sstevel@tonic-gate sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
13347c478bd9Sstevel@tonic-gate #if SASL <= 10515
13357c478bd9Sstevel@tonic-gate if ((p = strrchr(file, '/')) == NULL)
13367c478bd9Sstevel@tonic-gate p = file;
13377c478bd9Sstevel@tonic-gate else
13387c478bd9Sstevel@tonic-gate ++p;
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate /* everything beside libs and .conf files must not be readable */
13417c478bd9Sstevel@tonic-gate len = strlen(p);
13427c478bd9Sstevel@tonic-gate if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
13437c478bd9Sstevel@tonic-gate (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
13447c478bd9Sstevel@tonic-gate {
13457c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
13467c478bd9Sstevel@tonic-gate sff |= SFF_NORFILES;
13477c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
13487c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES;
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate #else /* SASL <= 10515 */
13517c478bd9Sstevel@tonic-gate /* files containing passwords should be not readable */
13527c478bd9Sstevel@tonic-gate if (type == SASL_VRFY_PASSWD)
13537c478bd9Sstevel@tonic-gate {
13547c478bd9Sstevel@tonic-gate if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
13557c478bd9Sstevel@tonic-gate sff |= SFF_NOWRFILES;
13567c478bd9Sstevel@tonic-gate else
13577c478bd9Sstevel@tonic-gate sff |= SFF_NORFILES;
13587c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
13597c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES;
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate #endif /* SASL <= 10515 */
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate p = (char *) file;
13647c478bd9Sstevel@tonic-gate if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
13657c478bd9Sstevel@tonic-gate S_IRUSR, NULL)) == 0)
13667c478bd9Sstevel@tonic-gate return SASL_OK;
13677c478bd9Sstevel@tonic-gate if (LogLevel > (r != ENOENT ? 8 : 10))
13687c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
13697c478bd9Sstevel@tonic-gate p, sm_errstring(r));
13707c478bd9Sstevel@tonic-gate return SASL_CONTINUE;
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate /*
13747c478bd9Sstevel@tonic-gate ** SASLGETREALM -- return the realm for SASL
13757c478bd9Sstevel@tonic-gate **
13767c478bd9Sstevel@tonic-gate ** return the realm for the client
13777c478bd9Sstevel@tonic-gate **
13787c478bd9Sstevel@tonic-gate ** Parameters:
13797c478bd9Sstevel@tonic-gate ** context -- context shared between invocations
13807c478bd9Sstevel@tonic-gate ** availrealms -- list of available realms
13817c478bd9Sstevel@tonic-gate ** {realm, realm, ...}
13827c478bd9Sstevel@tonic-gate ** result -- pointer to result
13837c478bd9Sstevel@tonic-gate **
13847c478bd9Sstevel@tonic-gate ** Returns:
13857c478bd9Sstevel@tonic-gate ** failure/success
13867c478bd9Sstevel@tonic-gate */
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate static int
saslgetrealm(context,id,availrealms,result)13897c478bd9Sstevel@tonic-gate saslgetrealm(context, id, availrealms, result)
13907c478bd9Sstevel@tonic-gate void *context;
13917c478bd9Sstevel@tonic-gate int id;
13927c478bd9Sstevel@tonic-gate const char **availrealms;
13937c478bd9Sstevel@tonic-gate const char **result;
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate char *r;
13967c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate sai = (SASL_AI_T *) context;
13997c478bd9Sstevel@tonic-gate if (sai == NULL)
14007c478bd9Sstevel@tonic-gate return SASL_FAIL;
14017c478bd9Sstevel@tonic-gate r = (*sai)[SASL_DEFREALM];
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate if (LogLevel > 12)
14047c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
14057c478bd9Sstevel@tonic-gate "AUTH=client, realm=%s, available realms=%s",
14067c478bd9Sstevel@tonic-gate r == NULL ? "<No Realm>" : r,
14077c478bd9Sstevel@tonic-gate (availrealms == NULL || *availrealms == NULL)
14087c478bd9Sstevel@tonic-gate ? "<No Realms>" : *availrealms);
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate /* check whether context is in list */
14117c478bd9Sstevel@tonic-gate if (availrealms != NULL && *availrealms != NULL)
14127c478bd9Sstevel@tonic-gate {
14137c478bd9Sstevel@tonic-gate if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
14147c478bd9Sstevel@tonic-gate NULL)
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate if (LogLevel > 8)
14177c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID,
14187c478bd9Sstevel@tonic-gate "AUTH=client, realm=%s not in list=%s",
14197c478bd9Sstevel@tonic-gate r, *availrealms);
14207c478bd9Sstevel@tonic-gate return SASL_FAIL;
14217c478bd9Sstevel@tonic-gate }
14227c478bd9Sstevel@tonic-gate }
14237c478bd9Sstevel@tonic-gate *result = r;
14247c478bd9Sstevel@tonic-gate return SASL_OK;
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate /*
14277c478bd9Sstevel@tonic-gate ** ITEMINLIST -- does item appear in list?
14287c478bd9Sstevel@tonic-gate **
14297c478bd9Sstevel@tonic-gate ** Check whether item appears in list (which must be separated by a
14307c478bd9Sstevel@tonic-gate ** character in delim) as a "word", i.e. it must appear at the begin
14317c478bd9Sstevel@tonic-gate ** of the list or after a space, and it must end with a space or the
14327c478bd9Sstevel@tonic-gate ** end of the list.
14337c478bd9Sstevel@tonic-gate **
14347c478bd9Sstevel@tonic-gate ** Parameters:
14357c478bd9Sstevel@tonic-gate ** item -- item to search.
14367c478bd9Sstevel@tonic-gate ** list -- list of items.
14377c478bd9Sstevel@tonic-gate ** delim -- list of delimiters.
14387c478bd9Sstevel@tonic-gate **
14397c478bd9Sstevel@tonic-gate ** Returns:
14407c478bd9Sstevel@tonic-gate ** pointer to occurrence (NULL if not found).
14417c478bd9Sstevel@tonic-gate */
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate char *
iteminlist(item,list,delim)14447c478bd9Sstevel@tonic-gate iteminlist(item, list, delim)
14457c478bd9Sstevel@tonic-gate char *item;
14467c478bd9Sstevel@tonic-gate char *list;
14477c478bd9Sstevel@tonic-gate char *delim;
14487c478bd9Sstevel@tonic-gate {
14497c478bd9Sstevel@tonic-gate char *s;
14507c478bd9Sstevel@tonic-gate int len;
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate if (list == NULL || *list == '\0')
14537c478bd9Sstevel@tonic-gate return NULL;
14547c478bd9Sstevel@tonic-gate if (item == NULL || *item == '\0')
14557c478bd9Sstevel@tonic-gate return NULL;
14567c478bd9Sstevel@tonic-gate s = list;
14577c478bd9Sstevel@tonic-gate len = strlen(item);
14587c478bd9Sstevel@tonic-gate while (s != NULL && *s != '\0')
14597c478bd9Sstevel@tonic-gate {
14607c478bd9Sstevel@tonic-gate if (sm_strncasecmp(s, item, len) == 0 &&
14617c478bd9Sstevel@tonic-gate (s[len] == '\0' || strchr(delim, s[len]) != NULL))
14627c478bd9Sstevel@tonic-gate return s;
14637c478bd9Sstevel@tonic-gate s = strpbrk(s, delim);
14647c478bd9Sstevel@tonic-gate if (s != NULL)
14657c478bd9Sstevel@tonic-gate while (*++s == ' ')
14667c478bd9Sstevel@tonic-gate continue;
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate return NULL;
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate ** REMOVEMECH -- remove item [rem] from list [list]
14727c478bd9Sstevel@tonic-gate **
14737c478bd9Sstevel@tonic-gate ** Parameters:
14747c478bd9Sstevel@tonic-gate ** rem -- item to remove
14757c478bd9Sstevel@tonic-gate ** list -- list of items
14767c478bd9Sstevel@tonic-gate ** rpool -- resource pool from which result is allocated.
14777c478bd9Sstevel@tonic-gate **
14787c478bd9Sstevel@tonic-gate ** Returns:
14797c478bd9Sstevel@tonic-gate ** pointer to new list (NULL in case of error).
14807c478bd9Sstevel@tonic-gate */
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate static char *
removemech(rem,list,rpool)14837c478bd9Sstevel@tonic-gate removemech(rem, list, rpool)
14847c478bd9Sstevel@tonic-gate char *rem;
14857c478bd9Sstevel@tonic-gate char *list;
14867c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate char *ret;
14897c478bd9Sstevel@tonic-gate char *needle;
14907c478bd9Sstevel@tonic-gate int len;
14917c478bd9Sstevel@tonic-gate
14927c478bd9Sstevel@tonic-gate if (list == NULL)
14937c478bd9Sstevel@tonic-gate return NULL;
14947c478bd9Sstevel@tonic-gate if (rem == NULL || *rem == '\0')
14957c478bd9Sstevel@tonic-gate {
14967c478bd9Sstevel@tonic-gate /* take out what? */
14977c478bd9Sstevel@tonic-gate return NULL;
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate
15007c478bd9Sstevel@tonic-gate /* find the item in the list */
15017c478bd9Sstevel@tonic-gate if ((needle = iteminlist(rem, list, " ")) == NULL)
15027c478bd9Sstevel@tonic-gate {
15037c478bd9Sstevel@tonic-gate /* not in there: return original */
15047c478bd9Sstevel@tonic-gate return list;
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate /* length of string without rem */
15087c478bd9Sstevel@tonic-gate len = strlen(list) - strlen(rem);
15097c478bd9Sstevel@tonic-gate if (len <= 0)
15107c478bd9Sstevel@tonic-gate {
15117c478bd9Sstevel@tonic-gate ret = (char *) sm_rpool_malloc_x(rpool, 1);
15127c478bd9Sstevel@tonic-gate *ret = '\0';
15137c478bd9Sstevel@tonic-gate return ret;
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate ret = (char *) sm_rpool_malloc_x(rpool, len);
15167c478bd9Sstevel@tonic-gate memset(ret, '\0', len);
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate /* copy from start to removed item */
15197c478bd9Sstevel@tonic-gate memcpy(ret, list, needle - list);
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate /* length of rest of string past removed item */
15227c478bd9Sstevel@tonic-gate len = strlen(needle) - strlen(rem) - 1;
15237c478bd9Sstevel@tonic-gate if (len > 0)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate /* not last item -- copy into string */
15267c478bd9Sstevel@tonic-gate memcpy(ret + (needle - list),
15277c478bd9Sstevel@tonic-gate list + (needle - list) + strlen(rem) + 1,
15287c478bd9Sstevel@tonic-gate len);
15297c478bd9Sstevel@tonic-gate }
15307c478bd9Sstevel@tonic-gate else
15317c478bd9Sstevel@tonic-gate ret[(needle - list) - 1] = '\0';
15327c478bd9Sstevel@tonic-gate return ret;
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate /*
15357c478bd9Sstevel@tonic-gate ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism
15367c478bd9Sstevel@tonic-gate **
15377c478bd9Sstevel@tonic-gate ** Parameters:
15387c478bd9Sstevel@tonic-gate ** m -- the mailer.
15397c478bd9Sstevel@tonic-gate ** mci -- the mailer connection structure.
15407c478bd9Sstevel@tonic-gate ** e -- the envelope (including the sender to specify).
15417c478bd9Sstevel@tonic-gate ** sai - sasl authinfo
15427c478bd9Sstevel@tonic-gate **
15437c478bd9Sstevel@tonic-gate ** Returns:
15447c478bd9Sstevel@tonic-gate ** EX_OK -- authentication was successful.
15457c478bd9Sstevel@tonic-gate ** EX_NOPERM -- authentication failed.
15467c478bd9Sstevel@tonic-gate ** EX_IOERR -- authentication dialogue failed (I/O problem?).
15477c478bd9Sstevel@tonic-gate ** EX_TEMPFAIL -- temporary failure.
15487c478bd9Sstevel@tonic-gate **
15497c478bd9Sstevel@tonic-gate */
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate static int
attemptauth(m,mci,e,sai)15527c478bd9Sstevel@tonic-gate attemptauth(m, mci, e, sai)
15537c478bd9Sstevel@tonic-gate MAILER *m;
15547c478bd9Sstevel@tonic-gate MCI *mci;
15557c478bd9Sstevel@tonic-gate ENVELOPE *e;
15567c478bd9Sstevel@tonic-gate SASL_AI_T *sai;
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate int saslresult, smtpresult;
15597c478bd9Sstevel@tonic-gate # if SASL >= 20000
15607c478bd9Sstevel@tonic-gate sasl_ssf_t ssf;
15617c478bd9Sstevel@tonic-gate const char *auth_id;
15627c478bd9Sstevel@tonic-gate const char *out;
15637c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
15647c478bd9Sstevel@tonic-gate sasl_external_properties_t ssf;
15657c478bd9Sstevel@tonic-gate char *out;
15667c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
15677c478bd9Sstevel@tonic-gate unsigned int outlen;
15687c478bd9Sstevel@tonic-gate sasl_interact_t *client_interact = NULL;
15697c478bd9Sstevel@tonic-gate char *mechusing;
15707c478bd9Sstevel@tonic-gate sasl_security_properties_t ssp;
1571*e9af4bc0SJohn Beck
1572*e9af4bc0SJohn Beck /* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */
1573*e9af4bc0SJohn Beck char in64[MAXOUTLEN + 1];
15747c478bd9Sstevel@tonic-gate #if NETINET || (NETINET6 && SASL >= 20000)
15757c478bd9Sstevel@tonic-gate extern SOCKADDR CurHostAddr;
15767c478bd9Sstevel@tonic-gate #endif /* NETINET || (NETINET6 && SASL >= 20000) */
15777c478bd9Sstevel@tonic-gate
15787c478bd9Sstevel@tonic-gate /* no mechanism selected (yet) */
15797c478bd9Sstevel@tonic-gate (*sai)[SASL_MECH] = NULL;
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate /* dispose old connection */
15827c478bd9Sstevel@tonic-gate if (mci->mci_conn != NULL)
15837c478bd9Sstevel@tonic-gate sasl_dispose(&(mci->mci_conn));
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate /* make a new client sasl connection */
15867c478bd9Sstevel@tonic-gate # if SASL >= 20000
1587058561cbSjbeck /*
1588058561cbSjbeck ** We provide the callbacks again because global callbacks in
1589058561cbSjbeck ** sasl_client_init() are ignored if SASL has been initialized
1590058561cbSjbeck ** before, for example, by a library such as libnss-ldap.
1591058561cbSjbeck */
1592058561cbSjbeck
15937c478bd9Sstevel@tonic-gate saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
15947c478bd9Sstevel@tonic-gate : "smtp",
1595058561cbSjbeck CurHostName, NULL, NULL, callbacks, 0,
15967c478bd9Sstevel@tonic-gate &mci->mci_conn);
15977c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
15987c478bd9Sstevel@tonic-gate saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
15997c478bd9Sstevel@tonic-gate : "smtp",
16007c478bd9Sstevel@tonic-gate CurHostName, NULL, 0, &mci->mci_conn);
16017c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
16027c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
16037c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate /* set properties */
1606058561cbSjbeck (void) memset(&ssp, '\0', sizeof(ssp));
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate /* XXX should these be options settable via .cf ? */
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate ssp.max_ssf = MaxSLBits;
16117c478bd9Sstevel@tonic-gate ssp.maxbufsize = MAXOUTLEN;
16127c478bd9Sstevel@tonic-gate # if 0
16137c478bd9Sstevel@tonic-gate ssp.security_flags = SASL_SEC_NOPLAINTEXT;
16147c478bd9Sstevel@tonic-gate # endif /* 0 */
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
16177c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
16187c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate # if SASL >= 20000
16217c478bd9Sstevel@tonic-gate /* external security strength factor, authentication id */
16227c478bd9Sstevel@tonic-gate ssf = 0;
16237c478bd9Sstevel@tonic-gate auth_id = NULL;
16247c478bd9Sstevel@tonic-gate # if STARTTLS
16257c478bd9Sstevel@tonic-gate out = macvalue(macid("{cert_subject}"), e);
16267c478bd9Sstevel@tonic-gate if (out != NULL && *out != '\0')
16277c478bd9Sstevel@tonic-gate auth_id = out;
16287c478bd9Sstevel@tonic-gate out = macvalue(macid("{cipher_bits}"), e);
16297c478bd9Sstevel@tonic-gate if (out != NULL && *out != '\0')
16307c478bd9Sstevel@tonic-gate ssf = atoi(out);
16317c478bd9Sstevel@tonic-gate # endif /* STARTTLS */
16327c478bd9Sstevel@tonic-gate saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
16337c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
16347c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16357c478bd9Sstevel@tonic-gate saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
16367c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
16377c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
16407c478bd9Sstevel@tonic-gate /* set local/remote ipv4 addresses */
16417c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL && (
16427c478bd9Sstevel@tonic-gate # if NETINET6
16437c478bd9Sstevel@tonic-gate CurHostAddr.sa.sa_family == AF_INET6 ||
16447c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
16457c478bd9Sstevel@tonic-gate CurHostAddr.sa.sa_family == AF_INET))
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrsize;
16487c478bd9Sstevel@tonic-gate SOCKADDR saddr_l;
16497c478bd9Sstevel@tonic-gate char localip[60], remoteip[60];
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate switch (CurHostAddr.sa.sa_family)
16527c478bd9Sstevel@tonic-gate {
16537c478bd9Sstevel@tonic-gate case AF_INET:
16547c478bd9Sstevel@tonic-gate addrsize = sizeof(struct sockaddr_in);
16557c478bd9Sstevel@tonic-gate break;
16567c478bd9Sstevel@tonic-gate # if NETINET6
16577c478bd9Sstevel@tonic-gate case AF_INET6:
16587c478bd9Sstevel@tonic-gate addrsize = sizeof(struct sockaddr_in6);
16597c478bd9Sstevel@tonic-gate break;
16607c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
16617c478bd9Sstevel@tonic-gate default:
16627c478bd9Sstevel@tonic-gate break;
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate if (iptostring(&CurHostAddr, addrsize,
1665058561cbSjbeck remoteip, sizeof(remoteip)))
16667c478bd9Sstevel@tonic-gate {
16677c478bd9Sstevel@tonic-gate if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
16687c478bd9Sstevel@tonic-gate remoteip) != SASL_OK)
16697c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate addrsize = sizeof(saddr_l);
16727c478bd9Sstevel@tonic-gate if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
16737c478bd9Sstevel@tonic-gate NULL),
16747c478bd9Sstevel@tonic-gate (struct sockaddr *) &saddr_l, &addrsize) == 0)
16757c478bd9Sstevel@tonic-gate {
16767c478bd9Sstevel@tonic-gate if (iptostring(&saddr_l, addrsize,
1677058561cbSjbeck localip, sizeof(localip)))
16787c478bd9Sstevel@tonic-gate {
16797c478bd9Sstevel@tonic-gate if (sasl_setprop(mci->mci_conn,
16807c478bd9Sstevel@tonic-gate SASL_IPLOCALPORT,
16817c478bd9Sstevel@tonic-gate localip) != SASL_OK)
16827c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate }
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate /* start client side of sasl */
16897c478bd9Sstevel@tonic-gate saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
16907c478bd9Sstevel@tonic-gate &client_interact,
16917c478bd9Sstevel@tonic-gate &out, &outlen,
16927c478bd9Sstevel@tonic-gate (const char **) &mechusing);
16937c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
16947c478bd9Sstevel@tonic-gate /* external security strength factor, authentication id */
16957c478bd9Sstevel@tonic-gate ssf.ssf = 0;
16967c478bd9Sstevel@tonic-gate ssf.auth_id = NULL;
16977c478bd9Sstevel@tonic-gate # if STARTTLS
16987c478bd9Sstevel@tonic-gate out = macvalue(macid("{cert_subject}"), e);
16997c478bd9Sstevel@tonic-gate if (out != NULL && *out != '\0')
17007c478bd9Sstevel@tonic-gate ssf.auth_id = out;
17017c478bd9Sstevel@tonic-gate out = macvalue(macid("{cipher_bits}"), e);
17027c478bd9Sstevel@tonic-gate if (out != NULL && *out != '\0')
17037c478bd9Sstevel@tonic-gate ssf.ssf = atoi(out);
17047c478bd9Sstevel@tonic-gate # endif /* STARTTLS */
17057c478bd9Sstevel@tonic-gate saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
17067c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
17077c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate # if NETINET
17107c478bd9Sstevel@tonic-gate /* set local/remote ipv4 addresses */
17117c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
17127c478bd9Sstevel@tonic-gate {
17137c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrsize;
17147c478bd9Sstevel@tonic-gate struct sockaddr_in saddr_l;
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
17177c478bd9Sstevel@tonic-gate (struct sockaddr_in *) &CurHostAddr)
17187c478bd9Sstevel@tonic-gate != SASL_OK)
17197c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
17207c478bd9Sstevel@tonic-gate addrsize = sizeof(struct sockaddr_in);
17217c478bd9Sstevel@tonic-gate if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
17227c478bd9Sstevel@tonic-gate NULL),
17237c478bd9Sstevel@tonic-gate (struct sockaddr *) &saddr_l, &addrsize) == 0)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
17267c478bd9Sstevel@tonic-gate &saddr_l) != SASL_OK)
17277c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate # endif /* NETINET */
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate /* start client side of sasl */
17337c478bd9Sstevel@tonic-gate saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
17347c478bd9Sstevel@tonic-gate NULL, &client_interact,
17357c478bd9Sstevel@tonic-gate &out, &outlen,
17367c478bd9Sstevel@tonic-gate (const char **) &mechusing);
17377c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
17407c478bd9Sstevel@tonic-gate {
17417c478bd9Sstevel@tonic-gate if (saslresult == SASL_NOMECH && LogLevel > 8)
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id,
17447c478bd9Sstevel@tonic-gate "AUTH=client, available mechanisms do not fulfill requirements");
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate /* just point current mechanism to the data in the sasl library */
17507c478bd9Sstevel@tonic-gate (*sai)[SASL_MECH] = mechusing;
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate /* send the info across the wire */
17537c478bd9Sstevel@tonic-gate if (out == NULL
17547c478bd9Sstevel@tonic-gate /* login and digest-md5 up to 1.5.28 set out="" */
17557c478bd9Sstevel@tonic-gate || (outlen == 0 &&
17567c478bd9Sstevel@tonic-gate (sm_strcasecmp(mechusing, "LOGIN") == 0 ||
17577c478bd9Sstevel@tonic-gate sm_strcasecmp(mechusing, "DIGEST-MD5") == 0))
17587c478bd9Sstevel@tonic-gate )
17597c478bd9Sstevel@tonic-gate {
17607c478bd9Sstevel@tonic-gate /* no initial response */
17617c478bd9Sstevel@tonic-gate smtpmessage("AUTH %s", m, mci, mechusing);
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate else if (outlen == 0)
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate /*
17667c478bd9Sstevel@tonic-gate ** zero-length initial response, per RFC 2554 4.:
17677c478bd9Sstevel@tonic-gate ** "Unlike a zero-length client answer to a 334 reply, a zero-
17687c478bd9Sstevel@tonic-gate ** length initial response is sent as a single equals sign"
17697c478bd9Sstevel@tonic-gate */
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate smtpmessage("AUTH %s =", m, mci, mechusing);
17727c478bd9Sstevel@tonic-gate }
17737c478bd9Sstevel@tonic-gate else
17747c478bd9Sstevel@tonic-gate {
1775*e9af4bc0SJohn Beck saslresult = sasl_encode64(out, outlen, in64, sizeof(in64),
1776*e9af4bc0SJohn Beck NULL);
17777c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK) /* internal error */
17787c478bd9Sstevel@tonic-gate {
17797c478bd9Sstevel@tonic-gate if (LogLevel > 8)
17807c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
17817c478bd9Sstevel@tonic-gate "encode64 for AUTH failed");
17827c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
17837c478bd9Sstevel@tonic-gate }
17847c478bd9Sstevel@tonic-gate smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate # if SASL < 20000
17877c478bd9Sstevel@tonic-gate sm_sasl_free(out); /* XXX only if no rpool is used */
17887c478bd9Sstevel@tonic-gate # endif /* SASL < 20000 */
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate /* get the reply */
17917c478bd9Sstevel@tonic-gate smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
17927c478bd9Sstevel@tonic-gate XS_AUTH);
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate for (;;)
17957c478bd9Sstevel@tonic-gate {
17967c478bd9Sstevel@tonic-gate /* check return code from server */
17977c478bd9Sstevel@tonic-gate if (smtpresult == 235)
17987c478bd9Sstevel@tonic-gate {
17997c478bd9Sstevel@tonic-gate macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
18007c478bd9Sstevel@tonic-gate mechusing);
18017c478bd9Sstevel@tonic-gate return EX_OK;
18027c478bd9Sstevel@tonic-gate }
18037c478bd9Sstevel@tonic-gate if (smtpresult == -1)
18047c478bd9Sstevel@tonic-gate return EX_IOERR;
18057c478bd9Sstevel@tonic-gate if (REPLYTYPE(smtpresult) == 5)
18067c478bd9Sstevel@tonic-gate return EX_NOPERM; /* ugly, but ... */
18077c478bd9Sstevel@tonic-gate if (REPLYTYPE(smtpresult) != 3)
18087c478bd9Sstevel@tonic-gate {
18097c478bd9Sstevel@tonic-gate /* should we fail deliberately, see RFC 2554 4. ? */
18107c478bd9Sstevel@tonic-gate /* smtpmessage("*", m, mci); */
18117c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate saslresult = sasl_client_step(mci->mci_conn,
18157c478bd9Sstevel@tonic-gate mci->mci_sasl_string,
18167c478bd9Sstevel@tonic-gate mci->mci_sasl_string_len,
18177c478bd9Sstevel@tonic-gate &client_interact,
18187c478bd9Sstevel@tonic-gate &out, &outlen);
18197c478bd9Sstevel@tonic-gate
18207c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
18217c478bd9Sstevel@tonic-gate {
18227c478bd9Sstevel@tonic-gate if (tTd(95, 5))
18237c478bd9Sstevel@tonic-gate sm_dprintf("AUTH FAIL=%s (%d)\n",
18247c478bd9Sstevel@tonic-gate sasl_errstring(saslresult, NULL, NULL),
18257c478bd9Sstevel@tonic-gate saslresult);
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate /* fail deliberately, see RFC 2554 4. */
18287c478bd9Sstevel@tonic-gate smtpmessage("*", m, mci);
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate ** but we should only fail for this authentication
18327c478bd9Sstevel@tonic-gate ** mechanism; how to do that?
18337c478bd9Sstevel@tonic-gate */
18347c478bd9Sstevel@tonic-gate
18357c478bd9Sstevel@tonic-gate smtpresult = reply(m, mci, e, TimeOuts.to_auth,
18367c478bd9Sstevel@tonic-gate getsasldata, NULL, XS_AUTH);
18377c478bd9Sstevel@tonic-gate return EX_NOPERM;
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate
18407c478bd9Sstevel@tonic-gate if (outlen > 0)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate saslresult = sasl_encode64(out, outlen, in64,
1843*e9af4bc0SJohn Beck sizeof(in64), NULL);
18447c478bd9Sstevel@tonic-gate if (saslresult != SASL_OK)
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate /* give an error reply to the other side! */
18477c478bd9Sstevel@tonic-gate smtpmessage("*", m, mci);
18487c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate }
18517c478bd9Sstevel@tonic-gate else
18527c478bd9Sstevel@tonic-gate in64[0] = '\0';
18537c478bd9Sstevel@tonic-gate # if SASL < 20000
18547c478bd9Sstevel@tonic-gate sm_sasl_free(out); /* XXX only if no rpool is used */
18557c478bd9Sstevel@tonic-gate # endif /* SASL < 20000 */
18567c478bd9Sstevel@tonic-gate smtpmessage("%s", m, mci, in64);
18577c478bd9Sstevel@tonic-gate smtpresult = reply(m, mci, e, TimeOuts.to_auth,
18587c478bd9Sstevel@tonic-gate getsasldata, NULL, XS_AUTH);
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate /* NOTREACHED */
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate /*
18637c478bd9Sstevel@tonic-gate ** SMTPAUTH -- try to AUTHenticate
18647c478bd9Sstevel@tonic-gate **
18657c478bd9Sstevel@tonic-gate ** This will try mechanisms in the order the sasl library decided until:
18667c478bd9Sstevel@tonic-gate ** - there are no more mechanisms
18677c478bd9Sstevel@tonic-gate ** - a mechanism succeeds
18687c478bd9Sstevel@tonic-gate ** - the sasl library fails initializing
18697c478bd9Sstevel@tonic-gate **
18707c478bd9Sstevel@tonic-gate ** Parameters:
18717c478bd9Sstevel@tonic-gate ** m -- the mailer.
18727c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info.
18737c478bd9Sstevel@tonic-gate ** e -- the envelope.
18747c478bd9Sstevel@tonic-gate **
18757c478bd9Sstevel@tonic-gate ** Returns:
18767c478bd9Sstevel@tonic-gate ** EX_OK -- authentication was successful
18777c478bd9Sstevel@tonic-gate ** EX_UNAVAILABLE -- authentication not possible, e.g.,
18787c478bd9Sstevel@tonic-gate ** no data available.
18797c478bd9Sstevel@tonic-gate ** EX_NOPERM -- authentication failed.
18807c478bd9Sstevel@tonic-gate ** EX_TEMPFAIL -- temporary failure.
18817c478bd9Sstevel@tonic-gate **
18827c478bd9Sstevel@tonic-gate ** Notice: AuthInfo is used for all connections, hence we must
18837c478bd9Sstevel@tonic-gate ** return EX_TEMPFAIL only if we really want to retry, i.e.,
18847c478bd9Sstevel@tonic-gate ** iff getauth() tempfailed or getauth() was used and
18857c478bd9Sstevel@tonic-gate ** authentication tempfailed.
18867c478bd9Sstevel@tonic-gate */
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate int
smtpauth(m,mci,e)18897c478bd9Sstevel@tonic-gate smtpauth(m, mci, e)
18907c478bd9Sstevel@tonic-gate MAILER *m;
18917c478bd9Sstevel@tonic-gate MCI *mci;
18927c478bd9Sstevel@tonic-gate ENVELOPE *e;
18937c478bd9Sstevel@tonic-gate {
18947c478bd9Sstevel@tonic-gate int result;
18957c478bd9Sstevel@tonic-gate int i;
18967c478bd9Sstevel@tonic-gate bool usedgetauth;
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate mci->mci_sasl_auth = false;
18997c478bd9Sstevel@tonic-gate for (i = 0; i < SASL_MECH ; i++)
19007c478bd9Sstevel@tonic-gate mci->mci_sai[i] = NULL;
19017c478bd9Sstevel@tonic-gate
19027c478bd9Sstevel@tonic-gate result = getauth(mci, e, &(mci->mci_sai));
19037c478bd9Sstevel@tonic-gate if (result == EX_TEMPFAIL)
19047c478bd9Sstevel@tonic-gate return result;
19057c478bd9Sstevel@tonic-gate usedgetauth = true;
19067c478bd9Sstevel@tonic-gate
19077c478bd9Sstevel@tonic-gate /* no data available: don't try to authenticate */
19087c478bd9Sstevel@tonic-gate if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
19097c478bd9Sstevel@tonic-gate return result;
19107c478bd9Sstevel@tonic-gate if (result != EX_OK)
19117c478bd9Sstevel@tonic-gate {
19127c478bd9Sstevel@tonic-gate if (SASLInfo == NULL)
19137c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate /* read authinfo from file */
19167c478bd9Sstevel@tonic-gate result = readauth(SASLInfo, true, &(mci->mci_sai),
19177c478bd9Sstevel@tonic-gate mci->mci_rpool);
19187c478bd9Sstevel@tonic-gate if (result != EX_OK)
19197c478bd9Sstevel@tonic-gate return result;
19207c478bd9Sstevel@tonic-gate usedgetauth = false;
19217c478bd9Sstevel@tonic-gate }
19227c478bd9Sstevel@tonic-gate
19237c478bd9Sstevel@tonic-gate /* check whether sufficient data is available */
19247c478bd9Sstevel@tonic-gate if (mci->mci_sai[SASL_PASSWORD] == NULL ||
19257c478bd9Sstevel@tonic-gate *(mci->mci_sai)[SASL_PASSWORD] == '\0')
19267c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
19277c478bd9Sstevel@tonic-gate if ((mci->mci_sai[SASL_AUTHID] == NULL ||
19287c478bd9Sstevel@tonic-gate *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
19297c478bd9Sstevel@tonic-gate (mci->mci_sai[SASL_USER] == NULL ||
19307c478bd9Sstevel@tonic-gate *(mci->mci_sai)[SASL_USER] == '\0'))
19317c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
19327c478bd9Sstevel@tonic-gate
19337c478bd9Sstevel@tonic-gate /* set the context for the callback function to sai */
19347c478bd9Sstevel@tonic-gate # if SASL >= 20000
19357c478bd9Sstevel@tonic-gate callbacks[CB_PASS_IDX].context = (void *) mci;
19367c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */
19377c478bd9Sstevel@tonic-gate callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
19387c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */
19397c478bd9Sstevel@tonic-gate callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
19407c478bd9Sstevel@tonic-gate callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
19417c478bd9Sstevel@tonic-gate callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
19427c478bd9Sstevel@tonic-gate #if 0
19437c478bd9Sstevel@tonic-gate callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
19447c478bd9Sstevel@tonic-gate #endif /* 0 */
19457c478bd9Sstevel@tonic-gate
19467c478bd9Sstevel@tonic-gate /* set default value for realm */
19477c478bd9Sstevel@tonic-gate if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
19487c478bd9Sstevel@tonic-gate (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
19497c478bd9Sstevel@tonic-gate macvalue('j', CurEnv));
19507c478bd9Sstevel@tonic-gate
19517c478bd9Sstevel@tonic-gate /* set default value for list of mechanism to use */
19527c478bd9Sstevel@tonic-gate if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
19537c478bd9Sstevel@tonic-gate *(mci->mci_sai)[SASL_MECHLIST] == '\0')
19547c478bd9Sstevel@tonic-gate (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate /* create list of mechanisms to try */
19577c478bd9Sstevel@tonic-gate mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
19587c478bd9Sstevel@tonic-gate mci->mci_saslcap, mci->mci_rpool);
19597c478bd9Sstevel@tonic-gate
19607c478bd9Sstevel@tonic-gate /* initialize sasl client library */
19617c478bd9Sstevel@tonic-gate result = init_sasl_client();
19627c478bd9Sstevel@tonic-gate if (result != SASL_OK)
19637c478bd9Sstevel@tonic-gate return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
19647c478bd9Sstevel@tonic-gate do
19657c478bd9Sstevel@tonic-gate {
19667c478bd9Sstevel@tonic-gate result = attemptauth(m, mci, e, &(mci->mci_sai));
19677c478bd9Sstevel@tonic-gate if (result == EX_OK)
19687c478bd9Sstevel@tonic-gate mci->mci_sasl_auth = true;
19697c478bd9Sstevel@tonic-gate else if (result == EX_TEMPFAIL || result == EX_NOPERM)
19707c478bd9Sstevel@tonic-gate {
19717c478bd9Sstevel@tonic-gate mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
19727c478bd9Sstevel@tonic-gate mci->mci_saslcap,
19737c478bd9Sstevel@tonic-gate mci->mci_rpool);
19747c478bd9Sstevel@tonic-gate if (mci->mci_saslcap == NULL ||
19757c478bd9Sstevel@tonic-gate *(mci->mci_saslcap) == '\0')
19767c478bd9Sstevel@tonic-gate return usedgetauth ? result
19777c478bd9Sstevel@tonic-gate : EX_UNAVAILABLE;
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate else
19807c478bd9Sstevel@tonic-gate return result;
19817c478bd9Sstevel@tonic-gate } while (result != EX_OK);
19827c478bd9Sstevel@tonic-gate return result;
19837c478bd9Sstevel@tonic-gate }
19847c478bd9Sstevel@tonic-gate #endif /* SASL */
19857c478bd9Sstevel@tonic-gate
19867c478bd9Sstevel@tonic-gate /*
19877c478bd9Sstevel@tonic-gate ** SMTPMAILFROM -- send MAIL command
19887c478bd9Sstevel@tonic-gate **
19897c478bd9Sstevel@tonic-gate ** Parameters:
19907c478bd9Sstevel@tonic-gate ** m -- the mailer.
19917c478bd9Sstevel@tonic-gate ** mci -- the mailer connection structure.
19927c478bd9Sstevel@tonic-gate ** e -- the envelope (including the sender to specify).
19937c478bd9Sstevel@tonic-gate */
19947c478bd9Sstevel@tonic-gate
19957c478bd9Sstevel@tonic-gate int
smtpmailfrom(m,mci,e)19967c478bd9Sstevel@tonic-gate smtpmailfrom(m, mci, e)
19977c478bd9Sstevel@tonic-gate MAILER *m;
19987c478bd9Sstevel@tonic-gate MCI *mci;
19997c478bd9Sstevel@tonic-gate ENVELOPE *e;
20007c478bd9Sstevel@tonic-gate {
20017c478bd9Sstevel@tonic-gate int r;
20027c478bd9Sstevel@tonic-gate char *bufp;
20037c478bd9Sstevel@tonic-gate char *bodytype;
20047c478bd9Sstevel@tonic-gate char *enhsc;
20057c478bd9Sstevel@tonic-gate char buf[MAXNAME + 1];
20067c478bd9Sstevel@tonic-gate char optbuf[MAXLINE];
20077c478bd9Sstevel@tonic-gate
20087c478bd9Sstevel@tonic-gate if (tTd(18, 2))
20097c478bd9Sstevel@tonic-gate sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
20107c478bd9Sstevel@tonic-gate enhsc = NULL;
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /*
20137c478bd9Sstevel@tonic-gate ** Check if connection is gone, if so
20147c478bd9Sstevel@tonic-gate ** it's a tempfail and we use mci_errno
20157c478bd9Sstevel@tonic-gate ** for the reason.
20167c478bd9Sstevel@tonic-gate */
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
20197c478bd9Sstevel@tonic-gate {
20207c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
20217c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate /* set up appropriate options to include */
20257c478bd9Sstevel@tonic-gate if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
20267c478bd9Sstevel@tonic-gate {
2027058561cbSjbeck (void) sm_snprintf(optbuf, sizeof(optbuf), " SIZE=%ld",
20287c478bd9Sstevel@tonic-gate e->e_msgsize);
20297c478bd9Sstevel@tonic-gate bufp = &optbuf[strlen(optbuf)];
20307c478bd9Sstevel@tonic-gate }
20317c478bd9Sstevel@tonic-gate else
20327c478bd9Sstevel@tonic-gate {
20337c478bd9Sstevel@tonic-gate optbuf[0] = '\0';
20347c478bd9Sstevel@tonic-gate bufp = optbuf;
20357c478bd9Sstevel@tonic-gate }
20367c478bd9Sstevel@tonic-gate
20377c478bd9Sstevel@tonic-gate bodytype = e->e_bodytype;
20387c478bd9Sstevel@tonic-gate if (bitset(MCIF_8BITMIME, mci->mci_flags))
20397c478bd9Sstevel@tonic-gate {
20407c478bd9Sstevel@tonic-gate if (bodytype == NULL &&
20417c478bd9Sstevel@tonic-gate bitset(MM_MIME8BIT, MimeMode) &&
20427c478bd9Sstevel@tonic-gate bitset(EF_HAS8BIT, e->e_flags) &&
20437c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) &&
20447c478bd9Sstevel@tonic-gate !bitnset(M_8BITS, m->m_flags))
20457c478bd9Sstevel@tonic-gate bodytype = "8BITMIME";
20467c478bd9Sstevel@tonic-gate if (bodytype != NULL &&
20477c478bd9Sstevel@tonic-gate SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
20487c478bd9Sstevel@tonic-gate {
20497c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
20507c478bd9Sstevel@tonic-gate " BODY=%s", bodytype);
20517c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate }
20547c478bd9Sstevel@tonic-gate else if (bitnset(M_8BITS, m->m_flags) ||
20557c478bd9Sstevel@tonic-gate !bitset(EF_HAS8BIT, e->e_flags) ||
20567c478bd9Sstevel@tonic-gate bitset(MCIF_8BITOK, mci->mci_flags))
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate /* EMPTY */
20597c478bd9Sstevel@tonic-gate /* just pass it through */
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate #if MIME8TO7
20627c478bd9Sstevel@tonic-gate else if (bitset(MM_CVTMIME, MimeMode) &&
20637c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) &&
20647c478bd9Sstevel@tonic-gate (!bitset(MM_PASS8BIT, MimeMode) ||
20657c478bd9Sstevel@tonic-gate bitset(EF_IS_MIME, e->e_flags)))
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate /* must convert from 8bit MIME format to 7bit encoded */
20687c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_CVT8TO7;
20697c478bd9Sstevel@tonic-gate }
20707c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */
20717c478bd9Sstevel@tonic-gate else if (!bitset(MM_PASS8BIT, MimeMode))
20727c478bd9Sstevel@tonic-gate {
20737c478bd9Sstevel@tonic-gate /* cannot just send a 8-bit version */
20747c478bd9Sstevel@tonic-gate extern char MsgBuf[];
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
20777c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
20787c478bd9Sstevel@tonic-gate return EX_DATAERR;
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate if (bitset(MCIF_DSN, mci->mci_flags))
20827c478bd9Sstevel@tonic-gate {
20837c478bd9Sstevel@tonic-gate if (e->e_envid != NULL &&
20847c478bd9Sstevel@tonic-gate SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
20857c478bd9Sstevel@tonic-gate {
20867c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
20877c478bd9Sstevel@tonic-gate " ENVID=%s", e->e_envid);
20887c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
20897c478bd9Sstevel@tonic-gate }
20907c478bd9Sstevel@tonic-gate
20917c478bd9Sstevel@tonic-gate /* RET= parameter */
20927c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags) &&
20937c478bd9Sstevel@tonic-gate SPACELEFT(optbuf, bufp) > 9)
20947c478bd9Sstevel@tonic-gate {
20957c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
20967c478bd9Sstevel@tonic-gate " RET=%s",
20977c478bd9Sstevel@tonic-gate bitset(EF_NO_BODY_RETN, e->e_flags) ?
20987c478bd9Sstevel@tonic-gate "HDRS" : "FULL");
20997c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate }
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
21047c478bd9Sstevel@tonic-gate SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
21057c478bd9Sstevel@tonic-gate #if SASL
21067c478bd9Sstevel@tonic-gate && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
21077c478bd9Sstevel@tonic-gate #endif /* SASL */
21087c478bd9Sstevel@tonic-gate )
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
21117c478bd9Sstevel@tonic-gate " AUTH=%s", e->e_auth_param);
21127c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate /*
21167c478bd9Sstevel@tonic-gate ** 17 is the max length required, we could use log() to compute
21177c478bd9Sstevel@tonic-gate ** the exact length (and check IS_DLVR_TRACE())
21187c478bd9Sstevel@tonic-gate */
21197c478bd9Sstevel@tonic-gate
21207c478bd9Sstevel@tonic-gate if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
21217c478bd9Sstevel@tonic-gate IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
21227c478bd9Sstevel@tonic-gate {
21237c478bd9Sstevel@tonic-gate long dby;
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate /*
21267c478bd9Sstevel@tonic-gate ** Avoid problems with delays (for R) since the check
21277c478bd9Sstevel@tonic-gate ** in deliver() whether min-deliver-time is sufficient.
21287c478bd9Sstevel@tonic-gate ** Alternatively we could pass the computed time to this
21297c478bd9Sstevel@tonic-gate ** function.
21307c478bd9Sstevel@tonic-gate */
21317c478bd9Sstevel@tonic-gate
21327c478bd9Sstevel@tonic-gate dby = e->e_deliver_by - (curtime() - e->e_ctime);
21337c478bd9Sstevel@tonic-gate if (dby <= 0 && IS_DLVR_RETURN(e))
21347c478bd9Sstevel@tonic-gate dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
21357c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
21367c478bd9Sstevel@tonic-gate " BY=%ld;%c%s",
21377c478bd9Sstevel@tonic-gate dby,
21387c478bd9Sstevel@tonic-gate IS_DLVR_RETURN(e) ? 'R' : 'N',
21397c478bd9Sstevel@tonic-gate IS_DLVR_TRACE(e) ? "T" : "");
21407c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate /*
21447c478bd9Sstevel@tonic-gate ** Send the MAIL command.
21457c478bd9Sstevel@tonic-gate ** Designates the sender.
21467c478bd9Sstevel@tonic-gate */
21477c478bd9Sstevel@tonic-gate
21487c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_MAIL;
21497c478bd9Sstevel@tonic-gate
21507c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags) &&
21517c478bd9Sstevel@tonic-gate !bitnset(M_NO_NULL_FROM, m->m_flags))
21527c478bd9Sstevel@tonic-gate buf[0] = '\0';
21537c478bd9Sstevel@tonic-gate else
2154058561cbSjbeck expand("\201g", buf, sizeof(buf), e);
21557c478bd9Sstevel@tonic-gate if (buf[0] == '<')
21567c478bd9Sstevel@tonic-gate {
21577c478bd9Sstevel@tonic-gate /* strip off <angle brackets> (put back on below) */
21587c478bd9Sstevel@tonic-gate bufp = &buf[strlen(buf) - 1];
21597c478bd9Sstevel@tonic-gate if (*bufp == '>')
21607c478bd9Sstevel@tonic-gate *bufp = '\0';
21617c478bd9Sstevel@tonic-gate bufp = &buf[1];
21627c478bd9Sstevel@tonic-gate }
21637c478bd9Sstevel@tonic-gate else
21647c478bd9Sstevel@tonic-gate bufp = buf;
21657c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
21667c478bd9Sstevel@tonic-gate !bitnset(M_FROMPATH, m->m_flags))
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
21697c478bd9Sstevel@tonic-gate }
21707c478bd9Sstevel@tonic-gate else
21717c478bd9Sstevel@tonic-gate {
21727c478bd9Sstevel@tonic-gate smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
21737c478bd9Sstevel@tonic-gate *bufp == '@' ? ',' : ':', bufp, optbuf);
21747c478bd9Sstevel@tonic-gate }
21757c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client MAIL";
21767c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
21777c478bd9Sstevel@tonic-gate CurHostName, mci->mci_phase);
21787c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_DEFAULT);
21797c478bd9Sstevel@tonic-gate if (r < 0)
21807c478bd9Sstevel@tonic-gate {
21817c478bd9Sstevel@tonic-gate /* communications failure */
21827c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
21837c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
21847c478bd9Sstevel@tonic-gate }
21857c478bd9Sstevel@tonic-gate else if (r == SMTPCLOSING)
21867c478bd9Sstevel@tonic-gate {
21877c478bd9Sstevel@tonic-gate /* service shutting down: handled by reply() */
21887c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 4)
21917c478bd9Sstevel@tonic-gate {
21927c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
21937c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
21947c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
21957c478bd9Sstevel@tonic-gate }
21967c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 2)
21977c478bd9Sstevel@tonic-gate {
21987c478bd9Sstevel@tonic-gate return EX_OK;
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate else if (r == 501)
22017c478bd9Sstevel@tonic-gate {
22027c478bd9Sstevel@tonic-gate /* syntax error in arguments */
22037c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
22047c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
22057c478bd9Sstevel@tonic-gate return EX_DATAERR;
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate else if (r == 553)
22087c478bd9Sstevel@tonic-gate {
22097c478bd9Sstevel@tonic-gate /* mailbox name not allowed */
22107c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
22117c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
22127c478bd9Sstevel@tonic-gate return EX_DATAERR;
22137c478bd9Sstevel@tonic-gate }
22147c478bd9Sstevel@tonic-gate else if (r == 552)
22157c478bd9Sstevel@tonic-gate {
22167c478bd9Sstevel@tonic-gate /* exceeded storage allocation */
22177c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
22187c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
22197c478bd9Sstevel@tonic-gate if (bitset(MCIF_SIZE, mci->mci_flags))
22207c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN;
22217c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
22247c478bd9Sstevel@tonic-gate {
22257c478bd9Sstevel@tonic-gate /* unknown error */
22267c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
22277c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
22287c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate
22317c478bd9Sstevel@tonic-gate if (LogLevel > 1)
22327c478bd9Sstevel@tonic-gate {
22337c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
22347c478bd9Sstevel@tonic-gate "%.100s: SMTP MAIL protocol error: %s",
22357c478bd9Sstevel@tonic-gate CurHostName,
22367c478bd9Sstevel@tonic-gate shortenstring(SmtpReplyBuffer, 403));
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate
22397c478bd9Sstevel@tonic-gate /* protocol error -- close up */
22407c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
22417c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
22427c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
22437c478bd9Sstevel@tonic-gate return EX_PROTOCOL;
22447c478bd9Sstevel@tonic-gate }
22457c478bd9Sstevel@tonic-gate /*
22467c478bd9Sstevel@tonic-gate ** SMTPRCPT -- designate recipient.
22477c478bd9Sstevel@tonic-gate **
22487c478bd9Sstevel@tonic-gate ** Parameters:
22497c478bd9Sstevel@tonic-gate ** to -- address of recipient.
22507c478bd9Sstevel@tonic-gate ** m -- the mailer we are sending to.
22517c478bd9Sstevel@tonic-gate ** mci -- the connection info for this transaction.
22527c478bd9Sstevel@tonic-gate ** e -- the envelope for this transaction.
22537c478bd9Sstevel@tonic-gate **
22547c478bd9Sstevel@tonic-gate ** Returns:
22557c478bd9Sstevel@tonic-gate ** exit status corresponding to recipient status.
22567c478bd9Sstevel@tonic-gate **
22577c478bd9Sstevel@tonic-gate ** Side Effects:
22587c478bd9Sstevel@tonic-gate ** Sends the mail via SMTP.
22597c478bd9Sstevel@tonic-gate */
22607c478bd9Sstevel@tonic-gate
22617c478bd9Sstevel@tonic-gate int
smtprcpt(to,m,mci,e,ctladdr,xstart)22627c478bd9Sstevel@tonic-gate smtprcpt(to, m, mci, e, ctladdr, xstart)
22637c478bd9Sstevel@tonic-gate ADDRESS *to;
22647c478bd9Sstevel@tonic-gate register MAILER *m;
22657c478bd9Sstevel@tonic-gate MCI *mci;
22667c478bd9Sstevel@tonic-gate ENVELOPE *e;
22677c478bd9Sstevel@tonic-gate ADDRESS *ctladdr;
22687c478bd9Sstevel@tonic-gate time_t xstart;
22697c478bd9Sstevel@tonic-gate {
22707c478bd9Sstevel@tonic-gate char *bufp;
22717c478bd9Sstevel@tonic-gate char optbuf[MAXLINE];
22727c478bd9Sstevel@tonic-gate
22737c478bd9Sstevel@tonic-gate #if PIPELINING
22747c478bd9Sstevel@tonic-gate /*
22757c478bd9Sstevel@tonic-gate ** If there is status waiting from the other end, read it.
22767c478bd9Sstevel@tonic-gate ** This should normally happen because of SMTP pipelining.
22777c478bd9Sstevel@tonic-gate */
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate while (mci->mci_nextaddr != NULL &&
22807c478bd9Sstevel@tonic-gate sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
22817c478bd9Sstevel@tonic-gate {
22827c478bd9Sstevel@tonic-gate int r;
22837c478bd9Sstevel@tonic-gate
22847c478bd9Sstevel@tonic-gate r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
22857c478bd9Sstevel@tonic-gate if (r != EX_OK)
22867c478bd9Sstevel@tonic-gate {
22877c478bd9Sstevel@tonic-gate markfailure(e, mci->mci_nextaddr, mci, r, false);
22887c478bd9Sstevel@tonic-gate giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
22897c478bd9Sstevel@tonic-gate ctladdr, xstart, e, to);
22907c478bd9Sstevel@tonic-gate }
22917c478bd9Sstevel@tonic-gate mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
22927c478bd9Sstevel@tonic-gate }
22937c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
22947c478bd9Sstevel@tonic-gate
22957c478bd9Sstevel@tonic-gate /*
22967c478bd9Sstevel@tonic-gate ** Check if connection is gone, if so
22977c478bd9Sstevel@tonic-gate ** it's a tempfail and we use mci_errno
22987c478bd9Sstevel@tonic-gate ** for the reason.
22997c478bd9Sstevel@tonic-gate */
23007c478bd9Sstevel@tonic-gate
23017c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
23027c478bd9Sstevel@tonic-gate {
23037c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
23047c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
23057c478bd9Sstevel@tonic-gate }
23067c478bd9Sstevel@tonic-gate
23077c478bd9Sstevel@tonic-gate optbuf[0] = '\0';
23087c478bd9Sstevel@tonic-gate bufp = optbuf;
23097c478bd9Sstevel@tonic-gate
23107c478bd9Sstevel@tonic-gate /*
23117c478bd9Sstevel@tonic-gate ** Warning: in the following it is assumed that the free space
2312058561cbSjbeck ** in bufp is sizeof(optbuf)
23137c478bd9Sstevel@tonic-gate */
23147c478bd9Sstevel@tonic-gate
23157c478bd9Sstevel@tonic-gate if (bitset(MCIF_DSN, mci->mci_flags))
23167c478bd9Sstevel@tonic-gate {
23177c478bd9Sstevel@tonic-gate if (IS_DLVR_NOTIFY(e) &&
23187c478bd9Sstevel@tonic-gate !bitset(MCIF_DLVR_BY, mci->mci_flags))
23197c478bd9Sstevel@tonic-gate {
23207c478bd9Sstevel@tonic-gate /* RFC 2852: 4.1.4.2 */
23217c478bd9Sstevel@tonic-gate if (!bitset(QHASNOTIFY, to->q_flags))
23227c478bd9Sstevel@tonic-gate to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
23237c478bd9Sstevel@tonic-gate else if (bitset(QPINGONSUCCESS, to->q_flags) ||
23247c478bd9Sstevel@tonic-gate bitset(QPINGONFAILURE, to->q_flags) ||
23257c478bd9Sstevel@tonic-gate bitset(QPINGONDELAY, to->q_flags))
23267c478bd9Sstevel@tonic-gate to->q_flags |= QPINGONDELAY;
23277c478bd9Sstevel@tonic-gate }
23287c478bd9Sstevel@tonic-gate
23297c478bd9Sstevel@tonic-gate /* NOTIFY= parameter */
23307c478bd9Sstevel@tonic-gate if (bitset(QHASNOTIFY, to->q_flags) &&
23317c478bd9Sstevel@tonic-gate bitset(QPRIMARY, to->q_flags) &&
23327c478bd9Sstevel@tonic-gate !bitnset(M_LOCALMAILER, m->m_flags))
23337c478bd9Sstevel@tonic-gate {
23347c478bd9Sstevel@tonic-gate bool firstone = true;
23357c478bd9Sstevel@tonic-gate
2336058561cbSjbeck (void) sm_strlcat(bufp, " NOTIFY=", sizeof(optbuf));
23377c478bd9Sstevel@tonic-gate if (bitset(QPINGONSUCCESS, to->q_flags))
23387c478bd9Sstevel@tonic-gate {
2339058561cbSjbeck (void) sm_strlcat(bufp, "SUCCESS", sizeof(optbuf));
23407c478bd9Sstevel@tonic-gate firstone = false;
23417c478bd9Sstevel@tonic-gate }
23427c478bd9Sstevel@tonic-gate if (bitset(QPINGONFAILURE, to->q_flags))
23437c478bd9Sstevel@tonic-gate {
23447c478bd9Sstevel@tonic-gate if (!firstone)
23457c478bd9Sstevel@tonic-gate (void) sm_strlcat(bufp, ",",
2346058561cbSjbeck sizeof(optbuf));
2347058561cbSjbeck (void) sm_strlcat(bufp, "FAILURE", sizeof(optbuf));
23487c478bd9Sstevel@tonic-gate firstone = false;
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate if (bitset(QPINGONDELAY, to->q_flags))
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate if (!firstone)
23537c478bd9Sstevel@tonic-gate (void) sm_strlcat(bufp, ",",
2354058561cbSjbeck sizeof(optbuf));
2355058561cbSjbeck (void) sm_strlcat(bufp, "DELAY", sizeof(optbuf));
23567c478bd9Sstevel@tonic-gate firstone = false;
23577c478bd9Sstevel@tonic-gate }
23587c478bd9Sstevel@tonic-gate if (firstone)
2359058561cbSjbeck (void) sm_strlcat(bufp, "NEVER", sizeof(optbuf));
23607c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
23617c478bd9Sstevel@tonic-gate }
23627c478bd9Sstevel@tonic-gate
23637c478bd9Sstevel@tonic-gate /* ORCPT= parameter */
23647c478bd9Sstevel@tonic-gate if (to->q_orcpt != NULL &&
23657c478bd9Sstevel@tonic-gate SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
23667c478bd9Sstevel@tonic-gate {
23677c478bd9Sstevel@tonic-gate (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
23687c478bd9Sstevel@tonic-gate " ORCPT=%s", to->q_orcpt);
23697c478bd9Sstevel@tonic-gate bufp += strlen(bufp);
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate
23737c478bd9Sstevel@tonic-gate smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
23747c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_RCPT;
23757c478bd9Sstevel@tonic-gate
23767c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client RCPT";
23777c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
23787c478bd9Sstevel@tonic-gate CurHostName, mci->mci_phase);
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate #if PIPELINING
23817c478bd9Sstevel@tonic-gate /*
23827c478bd9Sstevel@tonic-gate ** If running SMTP pipelining, we will pick up status later
23837c478bd9Sstevel@tonic-gate */
23847c478bd9Sstevel@tonic-gate
23857c478bd9Sstevel@tonic-gate if (bitset(MCIF_PIPELINED, mci->mci_flags))
23867c478bd9Sstevel@tonic-gate return EX_OK;
23877c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
23887c478bd9Sstevel@tonic-gate
23897c478bd9Sstevel@tonic-gate return smtprcptstat(to, m, mci, e);
23907c478bd9Sstevel@tonic-gate }
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate ** SMTPRCPTSTAT -- get recipient status
23937c478bd9Sstevel@tonic-gate **
23947c478bd9Sstevel@tonic-gate ** This is only called during SMTP pipelining
23957c478bd9Sstevel@tonic-gate **
23967c478bd9Sstevel@tonic-gate ** Parameters:
23977c478bd9Sstevel@tonic-gate ** to -- address of recipient.
23987c478bd9Sstevel@tonic-gate ** m -- mailer being sent to.
23997c478bd9Sstevel@tonic-gate ** mci -- the mailer connection information.
24007c478bd9Sstevel@tonic-gate ** e -- the envelope for this message.
24017c478bd9Sstevel@tonic-gate **
24027c478bd9Sstevel@tonic-gate ** Returns:
24037c478bd9Sstevel@tonic-gate ** EX_* -- protocol status
24047c478bd9Sstevel@tonic-gate */
24057c478bd9Sstevel@tonic-gate
24067c478bd9Sstevel@tonic-gate static int
smtprcptstat(to,m,mci,e)24077c478bd9Sstevel@tonic-gate smtprcptstat(to, m, mci, e)
24087c478bd9Sstevel@tonic-gate ADDRESS *to;
24097c478bd9Sstevel@tonic-gate MAILER *m;
24107c478bd9Sstevel@tonic-gate register MCI *mci;
24117c478bd9Sstevel@tonic-gate register ENVELOPE *e;
24127c478bd9Sstevel@tonic-gate {
24137c478bd9Sstevel@tonic-gate int r;
24147c478bd9Sstevel@tonic-gate int save_errno;
24157c478bd9Sstevel@tonic-gate char *enhsc;
24167c478bd9Sstevel@tonic-gate
24177c478bd9Sstevel@tonic-gate /*
24187c478bd9Sstevel@tonic-gate ** Check if connection is gone, if so
24197c478bd9Sstevel@tonic-gate ** it's a tempfail and we use mci_errno
24207c478bd9Sstevel@tonic-gate ** for the reason.
24217c478bd9Sstevel@tonic-gate */
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
24247c478bd9Sstevel@tonic-gate {
24257c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
24267c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
24277c478bd9Sstevel@tonic-gate }
24287c478bd9Sstevel@tonic-gate
24297c478bd9Sstevel@tonic-gate enhsc = NULL;
24307c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_DEFAULT);
24317c478bd9Sstevel@tonic-gate save_errno = errno;
24327c478bd9Sstevel@tonic-gate to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
24337c478bd9Sstevel@tonic-gate to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
24347c478bd9Sstevel@tonic-gate if (!bitnset(M_LMTP, m->m_flags))
24357c478bd9Sstevel@tonic-gate to->q_statmta = mci->mci_host;
24367c478bd9Sstevel@tonic-gate if (r < 0 || REPLYTYPE(r) == 4)
24377c478bd9Sstevel@tonic-gate {
24387c478bd9Sstevel@tonic-gate mci->mci_retryrcpt = true;
24397c478bd9Sstevel@tonic-gate errno = save_errno;
24407c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
24417c478bd9Sstevel@tonic-gate }
24427c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 2)
24437c478bd9Sstevel@tonic-gate {
24447c478bd9Sstevel@tonic-gate char *t;
24457c478bd9Sstevel@tonic-gate
24467c478bd9Sstevel@tonic-gate if ((t = mci->mci_tolist) != NULL)
24477c478bd9Sstevel@tonic-gate {
24487c478bd9Sstevel@tonic-gate char *p;
24497c478bd9Sstevel@tonic-gate
24507c478bd9Sstevel@tonic-gate *t++ = ',';
24517c478bd9Sstevel@tonic-gate for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
24527c478bd9Sstevel@tonic-gate continue;
24537c478bd9Sstevel@tonic-gate *t = '\0';
24547c478bd9Sstevel@tonic-gate mci->mci_tolist = t;
24557c478bd9Sstevel@tonic-gate }
24567c478bd9Sstevel@tonic-gate #if PIPELINING
24577c478bd9Sstevel@tonic-gate mci->mci_okrcpts++;
24587c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
24597c478bd9Sstevel@tonic-gate return EX_OK;
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate else if (r == 550)
24627c478bd9Sstevel@tonic-gate {
24637c478bd9Sstevel@tonic-gate to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
24647c478bd9Sstevel@tonic-gate return EX_NOUSER;
24657c478bd9Sstevel@tonic-gate }
24667c478bd9Sstevel@tonic-gate else if (r == 551)
24677c478bd9Sstevel@tonic-gate {
24687c478bd9Sstevel@tonic-gate to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
24697c478bd9Sstevel@tonic-gate return EX_NOUSER;
24707c478bd9Sstevel@tonic-gate }
24717c478bd9Sstevel@tonic-gate else if (r == 553)
24727c478bd9Sstevel@tonic-gate {
24737c478bd9Sstevel@tonic-gate to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
24747c478bd9Sstevel@tonic-gate return EX_NOUSER;
24757c478bd9Sstevel@tonic-gate }
24767c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
24777c478bd9Sstevel@tonic-gate {
24787c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
24797c478bd9Sstevel@tonic-gate }
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate if (LogLevel > 1)
24827c478bd9Sstevel@tonic-gate {
24837c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
24847c478bd9Sstevel@tonic-gate "%.100s: SMTP RCPT protocol error: %s",
24857c478bd9Sstevel@tonic-gate CurHostName,
24867c478bd9Sstevel@tonic-gate shortenstring(SmtpReplyBuffer, 403));
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate
24897c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
24907c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
24917c478bd9Sstevel@tonic-gate return EX_PROTOCOL;
24927c478bd9Sstevel@tonic-gate }
24937c478bd9Sstevel@tonic-gate /*
24947c478bd9Sstevel@tonic-gate ** SMTPDATA -- send the data and clean up the transaction.
24957c478bd9Sstevel@tonic-gate **
24967c478bd9Sstevel@tonic-gate ** Parameters:
24977c478bd9Sstevel@tonic-gate ** m -- mailer being sent to.
24987c478bd9Sstevel@tonic-gate ** mci -- the mailer connection information.
24997c478bd9Sstevel@tonic-gate ** e -- the envelope for this message.
25007c478bd9Sstevel@tonic-gate **
25017c478bd9Sstevel@tonic-gate ** Returns:
25027c478bd9Sstevel@tonic-gate ** exit status corresponding to DATA command.
25037c478bd9Sstevel@tonic-gate */
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate int
smtpdata(m,mci,e,ctladdr,xstart)25067c478bd9Sstevel@tonic-gate smtpdata(m, mci, e, ctladdr, xstart)
25077c478bd9Sstevel@tonic-gate MAILER *m;
25087c478bd9Sstevel@tonic-gate register MCI *mci;
25097c478bd9Sstevel@tonic-gate register ENVELOPE *e;
25107c478bd9Sstevel@tonic-gate ADDRESS *ctladdr;
25117c478bd9Sstevel@tonic-gate time_t xstart;
25127c478bd9Sstevel@tonic-gate {
25137c478bd9Sstevel@tonic-gate register int r;
25147c478bd9Sstevel@tonic-gate int rstat;
25157c478bd9Sstevel@tonic-gate int xstat;
2516445f2479Sjbeck int timeout;
25177c478bd9Sstevel@tonic-gate char *enhsc;
25187c478bd9Sstevel@tonic-gate
25197c478bd9Sstevel@tonic-gate /*
25207c478bd9Sstevel@tonic-gate ** Check if connection is gone, if so
25217c478bd9Sstevel@tonic-gate ** it's a tempfail and we use mci_errno
25227c478bd9Sstevel@tonic-gate ** for the reason.
25237c478bd9Sstevel@tonic-gate */
25247c478bd9Sstevel@tonic-gate
25257c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
25267c478bd9Sstevel@tonic-gate {
25277c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
25287c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
25297c478bd9Sstevel@tonic-gate }
25307c478bd9Sstevel@tonic-gate
25317c478bd9Sstevel@tonic-gate enhsc = NULL;
25327c478bd9Sstevel@tonic-gate
25337c478bd9Sstevel@tonic-gate /*
25347c478bd9Sstevel@tonic-gate ** Send the data.
25357c478bd9Sstevel@tonic-gate ** First send the command and check that it is ok.
25367c478bd9Sstevel@tonic-gate ** Then send the data (if there are valid recipients).
25377c478bd9Sstevel@tonic-gate ** Follow it up with a dot to terminate.
25387c478bd9Sstevel@tonic-gate ** Finally get the results of the transaction.
25397c478bd9Sstevel@tonic-gate */
25407c478bd9Sstevel@tonic-gate
25417c478bd9Sstevel@tonic-gate /* send the command and check ok to proceed */
25427c478bd9Sstevel@tonic-gate smtpmessage("DATA", m, mci);
25437c478bd9Sstevel@tonic-gate
25447c478bd9Sstevel@tonic-gate #if PIPELINING
25457c478bd9Sstevel@tonic-gate if (mci->mci_nextaddr != NULL)
25467c478bd9Sstevel@tonic-gate {
25477c478bd9Sstevel@tonic-gate char *oldto = e->e_to;
25487c478bd9Sstevel@tonic-gate
25497c478bd9Sstevel@tonic-gate /* pick up any pending RCPT responses for SMTP pipelining */
25507c478bd9Sstevel@tonic-gate while (mci->mci_nextaddr != NULL)
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate int r;
25537c478bd9Sstevel@tonic-gate
25547c478bd9Sstevel@tonic-gate e->e_to = mci->mci_nextaddr->q_paddr;
25557c478bd9Sstevel@tonic-gate r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
25567c478bd9Sstevel@tonic-gate if (r != EX_OK)
25577c478bd9Sstevel@tonic-gate {
25587c478bd9Sstevel@tonic-gate markfailure(e, mci->mci_nextaddr, mci, r,
25597c478bd9Sstevel@tonic-gate false);
25607c478bd9Sstevel@tonic-gate giveresponse(r, mci->mci_nextaddr->q_status, m,
25617c478bd9Sstevel@tonic-gate mci, ctladdr, xstart, e,
25627c478bd9Sstevel@tonic-gate mci->mci_nextaddr);
25637c478bd9Sstevel@tonic-gate if (r == EX_TEMPFAIL)
25647c478bd9Sstevel@tonic-gate mci->mci_nextaddr->q_state = QS_RETRY;
25657c478bd9Sstevel@tonic-gate }
25667c478bd9Sstevel@tonic-gate mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
25677c478bd9Sstevel@tonic-gate }
25687c478bd9Sstevel@tonic-gate e->e_to = oldto;
25697c478bd9Sstevel@tonic-gate
25707c478bd9Sstevel@tonic-gate /*
25717c478bd9Sstevel@tonic-gate ** Connection might be closed in response to a RCPT command,
25727c478bd9Sstevel@tonic-gate ** i.e., the server responded with 421. In that case (at
25737c478bd9Sstevel@tonic-gate ** least) one RCPT has a temporary failure, hence we don't
25747c478bd9Sstevel@tonic-gate ** need to check mci_okrcpts (as it is done below) to figure
25757c478bd9Sstevel@tonic-gate ** out which error to return.
25767c478bd9Sstevel@tonic-gate */
25777c478bd9Sstevel@tonic-gate
25787c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
25797c478bd9Sstevel@tonic-gate {
25807c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
25817c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
25827c478bd9Sstevel@tonic-gate }
25837c478bd9Sstevel@tonic-gate }
25847c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
25857c478bd9Sstevel@tonic-gate
25867c478bd9Sstevel@tonic-gate /* now proceed with DATA phase */
25877c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client DATA 354";
25887c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_DATA;
25897c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s",
25907c478bd9Sstevel@tonic-gate qid_printname(e), CurHostName, mci->mci_phase);
25917c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DEFAULT);
25927c478bd9Sstevel@tonic-gate if (r < 0 || REPLYTYPE(r) == 4)
25937c478bd9Sstevel@tonic-gate {
25947c478bd9Sstevel@tonic-gate if (r >= 0)
25957c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
25967c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
25977c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
25987c478bd9Sstevel@tonic-gate }
25997c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
26007c478bd9Sstevel@tonic-gate {
26017c478bd9Sstevel@tonic-gate smtprset(m, mci, e);
26027c478bd9Sstevel@tonic-gate #if PIPELINING
26037c478bd9Sstevel@tonic-gate if (mci->mci_okrcpts <= 0)
26047c478bd9Sstevel@tonic-gate return mci->mci_retryrcpt ? EX_TEMPFAIL
26057c478bd9Sstevel@tonic-gate : EX_UNAVAILABLE;
26067c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
26077c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
26087c478bd9Sstevel@tonic-gate }
26097c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) != 3)
26107c478bd9Sstevel@tonic-gate {
26117c478bd9Sstevel@tonic-gate if (LogLevel > 1)
26127c478bd9Sstevel@tonic-gate {
26137c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
26147c478bd9Sstevel@tonic-gate "%.100s: SMTP DATA-1 protocol error: %s",
26157c478bd9Sstevel@tonic-gate CurHostName,
26167c478bd9Sstevel@tonic-gate shortenstring(SmtpReplyBuffer, 403));
26177c478bd9Sstevel@tonic-gate }
26187c478bd9Sstevel@tonic-gate smtprset(m, mci, e);
26197c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
26207c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
26217c478bd9Sstevel@tonic-gate #if PIPELINING
26227c478bd9Sstevel@tonic-gate if (mci->mci_okrcpts <= 0)
26237c478bd9Sstevel@tonic-gate return mci->mci_retryrcpt ? EX_TEMPFAIL
26247c478bd9Sstevel@tonic-gate : EX_PROTOCOL;
26257c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
26267c478bd9Sstevel@tonic-gate return EX_PROTOCOL;
26277c478bd9Sstevel@tonic-gate }
26287c478bd9Sstevel@tonic-gate
26297c478bd9Sstevel@tonic-gate #if PIPELINING
26307c478bd9Sstevel@tonic-gate if (mci->mci_okrcpts > 0)
26317c478bd9Sstevel@tonic-gate {
26327c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
26337c478bd9Sstevel@tonic-gate
26347c478bd9Sstevel@tonic-gate /*
26357c478bd9Sstevel@tonic-gate ** Set timeout around data writes. Make it at least large
26367c478bd9Sstevel@tonic-gate ** enough for DNS timeouts on all recipients plus some fudge
26377c478bd9Sstevel@tonic-gate ** factor. The main thing is that it should not be infinite.
26387c478bd9Sstevel@tonic-gate */
26397c478bd9Sstevel@tonic-gate
26407c478bd9Sstevel@tonic-gate if (tTd(18, 101))
26417c478bd9Sstevel@tonic-gate {
26427c478bd9Sstevel@tonic-gate /* simulate a DATA timeout */
2643445f2479Sjbeck timeout = 10;
26447c478bd9Sstevel@tonic-gate }
26457c478bd9Sstevel@tonic-gate else
2646445f2479Sjbeck timeout = DATA_PROGRESS_TIMEOUT * 1000;
2647445f2479Sjbeck sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
26487c478bd9Sstevel@tonic-gate
26497c478bd9Sstevel@tonic-gate
26507c478bd9Sstevel@tonic-gate /*
26517c478bd9Sstevel@tonic-gate ** Output the actual message.
26527c478bd9Sstevel@tonic-gate */
26537c478bd9Sstevel@tonic-gate
2654445f2479Sjbeck if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
2655445f2479Sjbeck goto writeerr;
26567c478bd9Sstevel@tonic-gate
26577c478bd9Sstevel@tonic-gate if (tTd(18, 101))
26587c478bd9Sstevel@tonic-gate {
26597c478bd9Sstevel@tonic-gate /* simulate a DATA timeout */
26607c478bd9Sstevel@tonic-gate (void) sleep(2);
26617c478bd9Sstevel@tonic-gate }
26627c478bd9Sstevel@tonic-gate
2663445f2479Sjbeck if (!(*e->e_putbody)(mci, e, NULL))
2664445f2479Sjbeck goto writeerr;
26657c478bd9Sstevel@tonic-gate
26667c478bd9Sstevel@tonic-gate /*
26677c478bd9Sstevel@tonic-gate ** Cleanup after sending message.
26687c478bd9Sstevel@tonic-gate */
26697c478bd9Sstevel@tonic-gate
26707c478bd9Sstevel@tonic-gate
26717c478bd9Sstevel@tonic-gate #if PIPELINING
26727c478bd9Sstevel@tonic-gate }
26737c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
26747c478bd9Sstevel@tonic-gate
26757c478bd9Sstevel@tonic-gate #if _FFR_CATCH_BROKEN_MTAS
26767c478bd9Sstevel@tonic-gate if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
26777c478bd9Sstevel@tonic-gate {
26787c478bd9Sstevel@tonic-gate /* terminate the message */
26797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
26807c478bd9Sstevel@tonic-gate m->m_eol);
26817c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL)
26827c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
26837c478bd9Sstevel@tonic-gate "%05d >>> .\n", (int) CurrentPid);
26847c478bd9Sstevel@tonic-gate if (Verbose)
26857c478bd9Sstevel@tonic-gate nmessage(">>> .");
26867c478bd9Sstevel@tonic-gate
26877c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
26887c478bd9Sstevel@tonic-gate "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
26897c478bd9Sstevel@tonic-gate CurHostName);
26907c478bd9Sstevel@tonic-gate mci->mci_errno = EIO;
26917c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_ERROR;
26927c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
26937c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
26947c478bd9Sstevel@tonic-gate return EX_PROTOCOL;
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate #endif /* _FFR_CATCH_BROKEN_MTAS */
26977c478bd9Sstevel@tonic-gate
26987c478bd9Sstevel@tonic-gate if (sm_io_error(mci->mci_out))
26997c478bd9Sstevel@tonic-gate {
27007c478bd9Sstevel@tonic-gate /* error during processing -- don't send the dot */
27017c478bd9Sstevel@tonic-gate mci->mci_errno = EIO;
27027c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_ERROR;
27037c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
27047c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
27057c478bd9Sstevel@tonic-gate return EX_IOERR;
27067c478bd9Sstevel@tonic-gate }
27077c478bd9Sstevel@tonic-gate
27087c478bd9Sstevel@tonic-gate /* terminate the message */
27097800901eSjbeck if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s.%s",
27107800901eSjbeck bitset(MCIF_INLONGLINE, mci->mci_flags) ? m->m_eol : "",
27117800901eSjbeck m->m_eol) == SM_IO_EOF)
2712445f2479Sjbeck goto writeerr;
27137c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL)
27147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
27157c478bd9Sstevel@tonic-gate "%05d >>> .\n", (int) CurrentPid);
27167c478bd9Sstevel@tonic-gate if (Verbose)
27177c478bd9Sstevel@tonic-gate nmessage(">>> .");
27187c478bd9Sstevel@tonic-gate
27197c478bd9Sstevel@tonic-gate /* check for the results of the transaction */
27207c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "client DATA status";
27217c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
27227c478bd9Sstevel@tonic-gate CurHostName, mci->mci_phase);
27237c478bd9Sstevel@tonic-gate if (bitnset(M_LMTP, m->m_flags))
27247c478bd9Sstevel@tonic-gate return EX_OK;
27257c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT);
27267c478bd9Sstevel@tonic-gate if (r < 0)
27277c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
27287c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_DATA)
27297c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN;
27307c478bd9Sstevel@tonic-gate xstat = EX_NOTSTICKY;
27317c478bd9Sstevel@tonic-gate if (r == 452)
27327c478bd9Sstevel@tonic-gate rstat = EX_TEMPFAIL;
27337c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 4)
27347c478bd9Sstevel@tonic-gate rstat = xstat = EX_TEMPFAIL;
27357c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 2)
27367c478bd9Sstevel@tonic-gate rstat = xstat = EX_OK;
27377c478bd9Sstevel@tonic-gate else if (REPLYCLASS(r) != 5)
27387c478bd9Sstevel@tonic-gate rstat = xstat = EX_PROTOCOL;
27397c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
27407c478bd9Sstevel@tonic-gate rstat = EX_UNAVAILABLE;
27417c478bd9Sstevel@tonic-gate else
27427c478bd9Sstevel@tonic-gate rstat = EX_PROTOCOL;
27437c478bd9Sstevel@tonic-gate mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
27447c478bd9Sstevel@tonic-gate SmtpReplyBuffer);
27457c478bd9Sstevel@tonic-gate if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
27467c478bd9Sstevel@tonic-gate (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
27477c478bd9Sstevel@tonic-gate r += 5;
27487c478bd9Sstevel@tonic-gate else
27497c478bd9Sstevel@tonic-gate r = 4;
27507c478bd9Sstevel@tonic-gate e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
27517c478bd9Sstevel@tonic-gate SmtpPhase = mci->mci_phase = "idle";
27527c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
27537c478bd9Sstevel@tonic-gate if (rstat != EX_PROTOCOL)
27547c478bd9Sstevel@tonic-gate return rstat;
27557c478bd9Sstevel@tonic-gate if (LogLevel > 1)
27567c478bd9Sstevel@tonic-gate {
27577c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
27587c478bd9Sstevel@tonic-gate "%.100s: SMTP DATA-2 protocol error: %s",
27597c478bd9Sstevel@tonic-gate CurHostName,
27607c478bd9Sstevel@tonic-gate shortenstring(SmtpReplyBuffer, 403));
27617c478bd9Sstevel@tonic-gate }
27627c478bd9Sstevel@tonic-gate return rstat;
27637c478bd9Sstevel@tonic-gate
2764445f2479Sjbeck writeerr:
2765445f2479Sjbeck mci->mci_errno = errno;
2766445f2479Sjbeck mci->mci_state = MCIS_ERROR;
2767445f2479Sjbeck mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
27687c478bd9Sstevel@tonic-gate
27697c478bd9Sstevel@tonic-gate /*
2770445f2479Sjbeck ** If putbody() couldn't finish due to a timeout,
2771445f2479Sjbeck ** rewind it here in the timeout handler. See
2772445f2479Sjbeck ** comments at the end of putbody() for reasoning.
27737c478bd9Sstevel@tonic-gate */
27747c478bd9Sstevel@tonic-gate
2775445f2479Sjbeck if (e->e_dfp != NULL)
2776445f2479Sjbeck (void) bfrewind(e->e_dfp);
27777c478bd9Sstevel@tonic-gate
2778445f2479Sjbeck errno = mci->mci_errno;
2779445f2479Sjbeck syserr("451 4.4.1 timeout writing message to %s", CurHostName);
2780445f2479Sjbeck smtpquit(m, mci, e);
2781445f2479Sjbeck return EX_TEMPFAIL;
27827c478bd9Sstevel@tonic-gate }
2783445f2479Sjbeck
27847c478bd9Sstevel@tonic-gate /*
27857c478bd9Sstevel@tonic-gate ** SMTPGETSTAT -- get status code from DATA in LMTP
27867c478bd9Sstevel@tonic-gate **
27877c478bd9Sstevel@tonic-gate ** Parameters:
27887c478bd9Sstevel@tonic-gate ** m -- the mailer to which we are sending the message.
27897c478bd9Sstevel@tonic-gate ** mci -- the mailer connection structure.
27907c478bd9Sstevel@tonic-gate ** e -- the current envelope.
27917c478bd9Sstevel@tonic-gate **
27927c478bd9Sstevel@tonic-gate ** Returns:
27937c478bd9Sstevel@tonic-gate ** The exit status corresponding to the reply code.
27947c478bd9Sstevel@tonic-gate */
27957c478bd9Sstevel@tonic-gate
27967c478bd9Sstevel@tonic-gate int
smtpgetstat(m,mci,e)27977c478bd9Sstevel@tonic-gate smtpgetstat(m, mci, e)
27987c478bd9Sstevel@tonic-gate MAILER *m;
27997c478bd9Sstevel@tonic-gate MCI *mci;
28007c478bd9Sstevel@tonic-gate ENVELOPE *e;
28017c478bd9Sstevel@tonic-gate {
28027c478bd9Sstevel@tonic-gate int r;
28037c478bd9Sstevel@tonic-gate int off;
28047c478bd9Sstevel@tonic-gate int status, xstat;
28057c478bd9Sstevel@tonic-gate char *enhsc;
28067c478bd9Sstevel@tonic-gate
28077c478bd9Sstevel@tonic-gate enhsc = NULL;
28087c478bd9Sstevel@tonic-gate
28097c478bd9Sstevel@tonic-gate /* check for the results of the transaction */
28107c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT);
28117c478bd9Sstevel@tonic-gate if (r < 0)
28127c478bd9Sstevel@tonic-gate return EX_TEMPFAIL;
28137c478bd9Sstevel@tonic-gate xstat = EX_NOTSTICKY;
28147c478bd9Sstevel@tonic-gate if (REPLYTYPE(r) == 4)
28157c478bd9Sstevel@tonic-gate status = EX_TEMPFAIL;
28167c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 2)
28177c478bd9Sstevel@tonic-gate status = xstat = EX_OK;
28187c478bd9Sstevel@tonic-gate else if (REPLYCLASS(r) != 5)
28197c478bd9Sstevel@tonic-gate status = xstat = EX_PROTOCOL;
28207c478bd9Sstevel@tonic-gate else if (REPLYTYPE(r) == 5)
28217c478bd9Sstevel@tonic-gate status = EX_UNAVAILABLE;
28227c478bd9Sstevel@tonic-gate else
28237c478bd9Sstevel@tonic-gate status = EX_PROTOCOL;
28247c478bd9Sstevel@tonic-gate if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
28257c478bd9Sstevel@tonic-gate (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
28267c478bd9Sstevel@tonic-gate off += 5;
28277c478bd9Sstevel@tonic-gate else
28287c478bd9Sstevel@tonic-gate off = 4;
28297c478bd9Sstevel@tonic-gate e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]);
28307c478bd9Sstevel@tonic-gate mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer);
28317c478bd9Sstevel@tonic-gate if (LogLevel > 1 && status == EX_PROTOCOL)
28327c478bd9Sstevel@tonic-gate {
28337c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id,
28347c478bd9Sstevel@tonic-gate "%.100s: SMTP DATA-3 protocol error: %s",
28357c478bd9Sstevel@tonic-gate CurHostName,
28367c478bd9Sstevel@tonic-gate shortenstring(SmtpReplyBuffer, 403));
28377c478bd9Sstevel@tonic-gate }
28387c478bd9Sstevel@tonic-gate return status;
28397c478bd9Sstevel@tonic-gate }
28407c478bd9Sstevel@tonic-gate /*
28417c478bd9Sstevel@tonic-gate ** SMTPQUIT -- close the SMTP connection.
28427c478bd9Sstevel@tonic-gate **
28437c478bd9Sstevel@tonic-gate ** Parameters:
28447c478bd9Sstevel@tonic-gate ** m -- a pointer to the mailer.
28457c478bd9Sstevel@tonic-gate ** mci -- the mailer connection information.
28467c478bd9Sstevel@tonic-gate ** e -- the current envelope.
28477c478bd9Sstevel@tonic-gate **
28487c478bd9Sstevel@tonic-gate ** Returns:
28497c478bd9Sstevel@tonic-gate ** none.
28507c478bd9Sstevel@tonic-gate **
28517c478bd9Sstevel@tonic-gate ** Side Effects:
28527c478bd9Sstevel@tonic-gate ** sends the final protocol and closes the connection.
28537c478bd9Sstevel@tonic-gate */
28547c478bd9Sstevel@tonic-gate
28557c478bd9Sstevel@tonic-gate void
smtpquit(m,mci,e)28567c478bd9Sstevel@tonic-gate smtpquit(m, mci, e)
28577c478bd9Sstevel@tonic-gate register MAILER *m;
28587c478bd9Sstevel@tonic-gate register MCI *mci;
28597c478bd9Sstevel@tonic-gate ENVELOPE *e;
28607c478bd9Sstevel@tonic-gate {
28617c478bd9Sstevel@tonic-gate bool oldSuprErrs = SuprErrs;
28627c478bd9Sstevel@tonic-gate int rcode;
28637c478bd9Sstevel@tonic-gate char *oldcurhost;
28647c478bd9Sstevel@tonic-gate
28657c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
28667c478bd9Sstevel@tonic-gate {
28677c478bd9Sstevel@tonic-gate mci_close(mci, "smtpquit:1");
28687c478bd9Sstevel@tonic-gate return;
28697c478bd9Sstevel@tonic-gate }
28707c478bd9Sstevel@tonic-gate
28717c478bd9Sstevel@tonic-gate oldcurhost = CurHostName;
28727c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; /* XXX UGLY XXX */
28737c478bd9Sstevel@tonic-gate if (CurHostName == NULL)
28747c478bd9Sstevel@tonic-gate CurHostName = MyHostName;
28757c478bd9Sstevel@tonic-gate
28767c478bd9Sstevel@tonic-gate #if PIPELINING
28777c478bd9Sstevel@tonic-gate mci->mci_okrcpts = 0;
28787c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
28797c478bd9Sstevel@tonic-gate
28807c478bd9Sstevel@tonic-gate /*
28817c478bd9Sstevel@tonic-gate ** Suppress errors here -- we may be processing a different
28827c478bd9Sstevel@tonic-gate ** job when we do the quit connection, and we don't want the
28837c478bd9Sstevel@tonic-gate ** new job to be penalized for something that isn't it's
28847c478bd9Sstevel@tonic-gate ** problem.
28857c478bd9Sstevel@tonic-gate */
28867c478bd9Sstevel@tonic-gate
28877c478bd9Sstevel@tonic-gate SuprErrs = true;
28887c478bd9Sstevel@tonic-gate
28897c478bd9Sstevel@tonic-gate /* send the quit message if we haven't gotten I/O error */
28907c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_ERROR &&
28917c478bd9Sstevel@tonic-gate mci->mci_state != MCIS_QUITING)
28927c478bd9Sstevel@tonic-gate {
28937c478bd9Sstevel@tonic-gate SmtpPhase = "client QUIT";
28947c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_QUITING;
28957c478bd9Sstevel@tonic-gate smtpmessage("QUIT", m, mci);
28967c478bd9Sstevel@tonic-gate (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL,
28977c478bd9Sstevel@tonic-gate XS_DEFAULT);
28987c478bd9Sstevel@tonic-gate SuprErrs = oldSuprErrs;
28997c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
29007c478bd9Sstevel@tonic-gate goto end;
29017c478bd9Sstevel@tonic-gate }
29027c478bd9Sstevel@tonic-gate
29037c478bd9Sstevel@tonic-gate /* now actually close the connection and pick up the zombie */
29047c478bd9Sstevel@tonic-gate rcode = endmailer(mci, e, NULL);
29057c478bd9Sstevel@tonic-gate if (rcode != EX_OK)
29067c478bd9Sstevel@tonic-gate {
29077c478bd9Sstevel@tonic-gate char *mailer = NULL;
29087c478bd9Sstevel@tonic-gate
29097c478bd9Sstevel@tonic-gate if (mci->mci_mailer != NULL &&
29107c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name != NULL)
29117c478bd9Sstevel@tonic-gate mailer = mci->mci_mailer->m_name;
29127c478bd9Sstevel@tonic-gate
29137c478bd9Sstevel@tonic-gate /* look for naughty mailers */
29147c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
29157c478bd9Sstevel@tonic-gate "smtpquit: mailer%s%s exited with exit value %d",
29167c478bd9Sstevel@tonic-gate mailer == NULL ? "" : " ",
29177c478bd9Sstevel@tonic-gate mailer == NULL ? "" : mailer,
29187c478bd9Sstevel@tonic-gate rcode);
29197c478bd9Sstevel@tonic-gate }
29207c478bd9Sstevel@tonic-gate
29217c478bd9Sstevel@tonic-gate SuprErrs = oldSuprErrs;
29227c478bd9Sstevel@tonic-gate
29237c478bd9Sstevel@tonic-gate end:
29247c478bd9Sstevel@tonic-gate CurHostName = oldcurhost;
29257c478bd9Sstevel@tonic-gate return;
29267c478bd9Sstevel@tonic-gate }
29277c478bd9Sstevel@tonic-gate /*
29287c478bd9Sstevel@tonic-gate ** SMTPRSET -- send a RSET (reset) command
29297c478bd9Sstevel@tonic-gate **
29307c478bd9Sstevel@tonic-gate ** Parameters:
29317c478bd9Sstevel@tonic-gate ** m -- a pointer to the mailer.
29327c478bd9Sstevel@tonic-gate ** mci -- the mailer connection information.
29337c478bd9Sstevel@tonic-gate ** e -- the current envelope.
29347c478bd9Sstevel@tonic-gate **
29357c478bd9Sstevel@tonic-gate ** Returns:
29367c478bd9Sstevel@tonic-gate ** none.
29377c478bd9Sstevel@tonic-gate **
29387c478bd9Sstevel@tonic-gate ** Side Effects:
29397c478bd9Sstevel@tonic-gate ** closes the connection if there is no reply to RSET.
29407c478bd9Sstevel@tonic-gate */
29417c478bd9Sstevel@tonic-gate
29427c478bd9Sstevel@tonic-gate void
smtprset(m,mci,e)29437c478bd9Sstevel@tonic-gate smtprset(m, mci, e)
29447c478bd9Sstevel@tonic-gate register MAILER *m;
29457c478bd9Sstevel@tonic-gate register MCI *mci;
29467c478bd9Sstevel@tonic-gate ENVELOPE *e;
29477c478bd9Sstevel@tonic-gate {
29487c478bd9Sstevel@tonic-gate int r;
29497c478bd9Sstevel@tonic-gate
29507c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; /* XXX UGLY XXX */
29517c478bd9Sstevel@tonic-gate if (CurHostName == NULL)
29527c478bd9Sstevel@tonic-gate CurHostName = MyHostName;
29537c478bd9Sstevel@tonic-gate
29547c478bd9Sstevel@tonic-gate #if PIPELINING
29557c478bd9Sstevel@tonic-gate mci->mci_okrcpts = 0;
29567c478bd9Sstevel@tonic-gate #endif /* PIPELINING */
29577c478bd9Sstevel@tonic-gate
29587c478bd9Sstevel@tonic-gate /*
29597c478bd9Sstevel@tonic-gate ** Check if connection is gone, if so
29607c478bd9Sstevel@tonic-gate ** it's a tempfail and we use mci_errno
29617c478bd9Sstevel@tonic-gate ** for the reason.
29627c478bd9Sstevel@tonic-gate */
29637c478bd9Sstevel@tonic-gate
29647c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
29657c478bd9Sstevel@tonic-gate {
29667c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
29677c478bd9Sstevel@tonic-gate return;
29687c478bd9Sstevel@tonic-gate }
29697c478bd9Sstevel@tonic-gate
29707c478bd9Sstevel@tonic-gate SmtpPhase = "client RSET";
29717c478bd9Sstevel@tonic-gate smtpmessage("RSET", m, mci);
29727c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT);
29737c478bd9Sstevel@tonic-gate if (r < 0)
29747c478bd9Sstevel@tonic-gate return;
29757c478bd9Sstevel@tonic-gate
29767c478bd9Sstevel@tonic-gate /*
29777c478bd9Sstevel@tonic-gate ** Any response is deemed to be acceptable.
29787c478bd9Sstevel@tonic-gate ** The standard does not state the proper action
29797c478bd9Sstevel@tonic-gate ** to take when a value other than 250 is received.
29807c478bd9Sstevel@tonic-gate **
29817c478bd9Sstevel@tonic-gate ** However, if 421 is returned for the RSET, leave
29827c478bd9Sstevel@tonic-gate ** mci_state alone (MCIS_SSD can be set in reply()
29837c478bd9Sstevel@tonic-gate ** and MCIS_CLOSED can be set in smtpquit() if
29847c478bd9Sstevel@tonic-gate ** reply() gets a 421 and calls smtpquit()).
29857c478bd9Sstevel@tonic-gate */
29867c478bd9Sstevel@tonic-gate
29877c478bd9Sstevel@tonic-gate if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED)
29887c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_OPEN;
2989445f2479Sjbeck else if (mci->mci_exitstat == EX_OK)
2990445f2479Sjbeck mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL);
29917c478bd9Sstevel@tonic-gate }
29927c478bd9Sstevel@tonic-gate /*
29937c478bd9Sstevel@tonic-gate ** SMTPPROBE -- check the connection state
29947c478bd9Sstevel@tonic-gate **
29957c478bd9Sstevel@tonic-gate ** Parameters:
29967c478bd9Sstevel@tonic-gate ** mci -- the mailer connection information.
29977c478bd9Sstevel@tonic-gate **
29987c478bd9Sstevel@tonic-gate ** Returns:
29997c478bd9Sstevel@tonic-gate ** none.
30007c478bd9Sstevel@tonic-gate **
30017c478bd9Sstevel@tonic-gate ** Side Effects:
30027c478bd9Sstevel@tonic-gate ** closes the connection if there is no reply to RSET.
30037c478bd9Sstevel@tonic-gate */
30047c478bd9Sstevel@tonic-gate
30057c478bd9Sstevel@tonic-gate int
smtpprobe(mci)30067c478bd9Sstevel@tonic-gate smtpprobe(mci)
30077c478bd9Sstevel@tonic-gate register MCI *mci;
30087c478bd9Sstevel@tonic-gate {
30097c478bd9Sstevel@tonic-gate int r;
30107c478bd9Sstevel@tonic-gate MAILER *m = mci->mci_mailer;
30117c478bd9Sstevel@tonic-gate ENVELOPE *e;
30127c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope;
30137c478bd9Sstevel@tonic-gate
30147c478bd9Sstevel@tonic-gate CurHostName = mci->mci_host; /* XXX UGLY XXX */
30157c478bd9Sstevel@tonic-gate if (CurHostName == NULL)
30167c478bd9Sstevel@tonic-gate CurHostName = MyHostName;
30177c478bd9Sstevel@tonic-gate
30187c478bd9Sstevel@tonic-gate e = &BlankEnvelope;
30197c478bd9Sstevel@tonic-gate SmtpPhase = "client probe";
30207c478bd9Sstevel@tonic-gate smtpmessage("RSET", m, mci);
30217c478bd9Sstevel@tonic-gate r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT);
30227c478bd9Sstevel@tonic-gate if (REPLYTYPE(r) != 2)
30237c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
30247c478bd9Sstevel@tonic-gate return r;
30257c478bd9Sstevel@tonic-gate }
30267c478bd9Sstevel@tonic-gate /*
30277c478bd9Sstevel@tonic-gate ** REPLY -- read arpanet reply
30287c478bd9Sstevel@tonic-gate **
30297c478bd9Sstevel@tonic-gate ** Parameters:
30307c478bd9Sstevel@tonic-gate ** m -- the mailer we are reading the reply from.
30317c478bd9Sstevel@tonic-gate ** mci -- the mailer connection info structure.
30327c478bd9Sstevel@tonic-gate ** e -- the current envelope.
30337c478bd9Sstevel@tonic-gate ** timeout -- the timeout for reads.
30347c478bd9Sstevel@tonic-gate ** pfunc -- processing function called on each line of response.
30357c478bd9Sstevel@tonic-gate ** If null, no special processing is done.
30367c478bd9Sstevel@tonic-gate ** enhstat -- optional, returns enhanced error code string (if set)
30377c478bd9Sstevel@tonic-gate ** rtype -- type of SmtpMsgBuffer: does it contains secret data?
30387c478bd9Sstevel@tonic-gate **
30397c478bd9Sstevel@tonic-gate ** Returns:
30407c478bd9Sstevel@tonic-gate ** reply code it reads.
30417c478bd9Sstevel@tonic-gate **
30427c478bd9Sstevel@tonic-gate ** Side Effects:
30437c478bd9Sstevel@tonic-gate ** flushes the mail file.
30447c478bd9Sstevel@tonic-gate */
30457c478bd9Sstevel@tonic-gate
30467c478bd9Sstevel@tonic-gate int
reply(m,mci,e,timeout,pfunc,enhstat,rtype)30477c478bd9Sstevel@tonic-gate reply(m, mci, e, timeout, pfunc, enhstat, rtype)
30487c478bd9Sstevel@tonic-gate MAILER *m;
30497c478bd9Sstevel@tonic-gate MCI *mci;
30507c478bd9Sstevel@tonic-gate ENVELOPE *e;
30517c478bd9Sstevel@tonic-gate time_t timeout;
30527c478bd9Sstevel@tonic-gate void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
30537c478bd9Sstevel@tonic-gate char **enhstat;
30547c478bd9Sstevel@tonic-gate int rtype;
30557c478bd9Sstevel@tonic-gate {
30567c478bd9Sstevel@tonic-gate register char *bufp;
30577c478bd9Sstevel@tonic-gate register int r;
30587c478bd9Sstevel@tonic-gate bool firstline = true;
30597c478bd9Sstevel@tonic-gate char junkbuf[MAXLINE];
30607c478bd9Sstevel@tonic-gate static char enhstatcode[ENHSCLEN];
30617c478bd9Sstevel@tonic-gate int save_errno;
30627c478bd9Sstevel@tonic-gate
30637c478bd9Sstevel@tonic-gate /*
30647c478bd9Sstevel@tonic-gate ** Flush the output before reading response.
30657c478bd9Sstevel@tonic-gate **
30667c478bd9Sstevel@tonic-gate ** For SMTP pipelining, it would be better if we didn't do
30677c478bd9Sstevel@tonic-gate ** this if there was already data waiting to be read. But
30687c478bd9Sstevel@tonic-gate ** to do it properly means pushing it to the I/O library,
30697c478bd9Sstevel@tonic-gate ** since it really needs to be done below the buffer layer.
30707c478bd9Sstevel@tonic-gate */
30717c478bd9Sstevel@tonic-gate
30727c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL)
30737c478bd9Sstevel@tonic-gate (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
30747c478bd9Sstevel@tonic-gate
30757c478bd9Sstevel@tonic-gate if (tTd(18, 1))
30767c478bd9Sstevel@tonic-gate sm_dprintf("reply\n");
30777c478bd9Sstevel@tonic-gate
30787c478bd9Sstevel@tonic-gate /*
30797c478bd9Sstevel@tonic-gate ** Read the input line, being careful not to hang.
30807c478bd9Sstevel@tonic-gate */
30817c478bd9Sstevel@tonic-gate
30827c478bd9Sstevel@tonic-gate bufp = SmtpReplyBuffer;
3083d4660949Sjbeck set_tls_rd_tmo(timeout);
30847c478bd9Sstevel@tonic-gate for (;;)
30857c478bd9Sstevel@tonic-gate {
30867c478bd9Sstevel@tonic-gate register char *p;
30877c478bd9Sstevel@tonic-gate
30887c478bd9Sstevel@tonic-gate /* actually do the read */
30897c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) /* for debugging */
30907c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
30917c478bd9Sstevel@tonic-gate
30927c478bd9Sstevel@tonic-gate /* if we are in the process of closing just give the code */
30937c478bd9Sstevel@tonic-gate if (mci->mci_state == MCIS_CLOSED)
30947c478bd9Sstevel@tonic-gate return SMTPCLOSING;
30957c478bd9Sstevel@tonic-gate
30967c478bd9Sstevel@tonic-gate /* don't try to read from a non-existent fd */
30977c478bd9Sstevel@tonic-gate if (mci->mci_in == NULL)
30987c478bd9Sstevel@tonic-gate {
30997c478bd9Sstevel@tonic-gate if (mci->mci_errno == 0)
31007c478bd9Sstevel@tonic-gate mci->mci_errno = EBADF;
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate /* errors on QUIT should be ignored */
31037c478bd9Sstevel@tonic-gate if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
31047c478bd9Sstevel@tonic-gate {
31057c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
31067c478bd9Sstevel@tonic-gate mci_close(mci, "reply:1");
31077c478bd9Sstevel@tonic-gate return -1;
31087c478bd9Sstevel@tonic-gate }
31097c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_ERROR;
31107c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
31117c478bd9Sstevel@tonic-gate errno = mci->mci_errno;
31127c478bd9Sstevel@tonic-gate return -1;
31137c478bd9Sstevel@tonic-gate }
31147c478bd9Sstevel@tonic-gate
31157c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL)
31167c478bd9Sstevel@tonic-gate (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
31177c478bd9Sstevel@tonic-gate
31187c478bd9Sstevel@tonic-gate /* get the line from the other side */
31197c478bd9Sstevel@tonic-gate p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
31207c478bd9Sstevel@tonic-gate save_errno = errno;
31217c478bd9Sstevel@tonic-gate mci->mci_lastuse = curtime();
31227c478bd9Sstevel@tonic-gate
31237c478bd9Sstevel@tonic-gate if (p == NULL)
31247c478bd9Sstevel@tonic-gate {
31257c478bd9Sstevel@tonic-gate bool oldholderrs;
31267c478bd9Sstevel@tonic-gate extern char MsgBuf[];
31277c478bd9Sstevel@tonic-gate
31287c478bd9Sstevel@tonic-gate /* errors on QUIT should be ignored */
31297c478bd9Sstevel@tonic-gate if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
31307c478bd9Sstevel@tonic-gate {
31317c478bd9Sstevel@tonic-gate mci_close(mci, "reply:2");
31327c478bd9Sstevel@tonic-gate return -1;
31337c478bd9Sstevel@tonic-gate }
31347c478bd9Sstevel@tonic-gate
31357c478bd9Sstevel@tonic-gate /* if the remote end closed early, fake an error */
31367c478bd9Sstevel@tonic-gate errno = save_errno;
31377c478bd9Sstevel@tonic-gate if (errno == 0)
31387c478bd9Sstevel@tonic-gate {
31397c478bd9Sstevel@tonic-gate (void) sm_snprintf(SmtpReplyBuffer,
3140058561cbSjbeck sizeof(SmtpReplyBuffer),
31417c478bd9Sstevel@tonic-gate "421 4.4.1 Connection reset by %s",
31427c478bd9Sstevel@tonic-gate CURHOSTNAME);
31437c478bd9Sstevel@tonic-gate #ifdef ECONNRESET
31447c478bd9Sstevel@tonic-gate errno = ECONNRESET;
31457c478bd9Sstevel@tonic-gate #else /* ECONNRESET */
31467c478bd9Sstevel@tonic-gate errno = EPIPE;
31477c478bd9Sstevel@tonic-gate #endif /* ECONNRESET */
31487c478bd9Sstevel@tonic-gate }
31497c478bd9Sstevel@tonic-gate
31507c478bd9Sstevel@tonic-gate mci->mci_errno = errno;
31517c478bd9Sstevel@tonic-gate oldholderrs = HoldErrs;
31527c478bd9Sstevel@tonic-gate HoldErrs = true;
31537c478bd9Sstevel@tonic-gate usrerr("451 4.4.1 reply: read error from %s",
31547c478bd9Sstevel@tonic-gate CURHOSTNAME);
31557c478bd9Sstevel@tonic-gate mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
31567c478bd9Sstevel@tonic-gate
31577c478bd9Sstevel@tonic-gate /* if debugging, pause so we can see state */
31587c478bd9Sstevel@tonic-gate if (tTd(18, 100))
31597c478bd9Sstevel@tonic-gate (void) pause();
31607c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_ERROR;
31617c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
31627c478bd9Sstevel@tonic-gate #if XDEBUG
31637c478bd9Sstevel@tonic-gate {
31647c478bd9Sstevel@tonic-gate char wbuf[MAXLINE];
31657c478bd9Sstevel@tonic-gate
31667c478bd9Sstevel@tonic-gate p = wbuf;
31677c478bd9Sstevel@tonic-gate if (e->e_to != NULL)
31687c478bd9Sstevel@tonic-gate {
31697c478bd9Sstevel@tonic-gate (void) sm_snprintf(p,
31707c478bd9Sstevel@tonic-gate SPACELEFT(wbuf, p),
31717c478bd9Sstevel@tonic-gate "%s... ",
31727c478bd9Sstevel@tonic-gate shortenstring(e->e_to, MAXSHORTSTR));
31737c478bd9Sstevel@tonic-gate p += strlen(p);
31747c478bd9Sstevel@tonic-gate }
31757c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(wbuf, p),
31767c478bd9Sstevel@tonic-gate "reply(%.100s) during %s",
31777c478bd9Sstevel@tonic-gate CURHOSTNAME, SmtpPhase);
31787c478bd9Sstevel@tonic-gate checkfd012(wbuf);
31797c478bd9Sstevel@tonic-gate }
31807c478bd9Sstevel@tonic-gate #endif /* XDEBUG */
31817c478bd9Sstevel@tonic-gate HoldErrs = oldholderrs;
31827c478bd9Sstevel@tonic-gate errno = save_errno;
31837c478bd9Sstevel@tonic-gate return -1;
31847c478bd9Sstevel@tonic-gate }
31857c478bd9Sstevel@tonic-gate fixcrlf(bufp, true);
31867c478bd9Sstevel@tonic-gate
31877c478bd9Sstevel@tonic-gate /* EHLO failure is not a real error */
31887c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL && (bufp[0] == '4' ||
31897c478bd9Sstevel@tonic-gate (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
31907c478bd9Sstevel@tonic-gate {
31917c478bd9Sstevel@tonic-gate /* serious error -- log the previous command */
31927c478bd9Sstevel@tonic-gate if (SmtpNeedIntro)
31937c478bd9Sstevel@tonic-gate {
31947c478bd9Sstevel@tonic-gate /* inform user who we are chatting with */
31957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(CurEnv->e_xfp,
31967c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
31977c478bd9Sstevel@tonic-gate "... while talking to %s:\n",
31987c478bd9Sstevel@tonic-gate CURHOSTNAME);
31997c478bd9Sstevel@tonic-gate SmtpNeedIntro = false;
32007c478bd9Sstevel@tonic-gate }
32017c478bd9Sstevel@tonic-gate if (SmtpMsgBuffer[0] != '\0')
32027c478bd9Sstevel@tonic-gate {
32037c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp,
32047c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT,
32057c478bd9Sstevel@tonic-gate ">>> %s\n",
32067c478bd9Sstevel@tonic-gate (rtype == XS_STARTTLS)
32077c478bd9Sstevel@tonic-gate ? "STARTTLS dialogue"
32087c478bd9Sstevel@tonic-gate : ((rtype == XS_AUTH)
32097c478bd9Sstevel@tonic-gate ? "AUTH dialogue"
32107c478bd9Sstevel@tonic-gate : SmtpMsgBuffer));
32117c478bd9Sstevel@tonic-gate SmtpMsgBuffer[0] = '\0';
32127c478bd9Sstevel@tonic-gate }
32137c478bd9Sstevel@tonic-gate
32147c478bd9Sstevel@tonic-gate /* now log the message as from the other side */
32157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
32167c478bd9Sstevel@tonic-gate "<<< %s\n", bufp);
32177c478bd9Sstevel@tonic-gate }
32187c478bd9Sstevel@tonic-gate
32197c478bd9Sstevel@tonic-gate /* display the input for verbose mode */
32207c478bd9Sstevel@tonic-gate if (Verbose)
32217c478bd9Sstevel@tonic-gate nmessage("050 %s", bufp);
32227c478bd9Sstevel@tonic-gate
32237c478bd9Sstevel@tonic-gate /* ignore improperly formatted input */
32247c478bd9Sstevel@tonic-gate if (!ISSMTPREPLY(bufp))
32257c478bd9Sstevel@tonic-gate continue;
32267c478bd9Sstevel@tonic-gate
32277c478bd9Sstevel@tonic-gate if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
32287c478bd9Sstevel@tonic-gate enhstat != NULL &&
32297c478bd9Sstevel@tonic-gate extenhsc(bufp + 4, ' ', enhstatcode) > 0)
32307c478bd9Sstevel@tonic-gate *enhstat = enhstatcode;
32317c478bd9Sstevel@tonic-gate
32327c478bd9Sstevel@tonic-gate /* process the line */
32337c478bd9Sstevel@tonic-gate if (pfunc != NULL)
32347c478bd9Sstevel@tonic-gate (*pfunc)(bufp, firstline, m, mci, e);
32357c478bd9Sstevel@tonic-gate
32367c478bd9Sstevel@tonic-gate firstline = false;
32377c478bd9Sstevel@tonic-gate
32387c478bd9Sstevel@tonic-gate /* decode the reply code */
32397c478bd9Sstevel@tonic-gate r = atoi(bufp);
32407c478bd9Sstevel@tonic-gate
32417c478bd9Sstevel@tonic-gate /* extra semantics: 0xx codes are "informational" */
32427c478bd9Sstevel@tonic-gate if (r < 100)
32437c478bd9Sstevel@tonic-gate continue;
32447c478bd9Sstevel@tonic-gate
32457c478bd9Sstevel@tonic-gate /* if no continuation lines, return this line */
32467c478bd9Sstevel@tonic-gate if (bufp[3] != '-')
32477c478bd9Sstevel@tonic-gate break;
32487c478bd9Sstevel@tonic-gate
32497c478bd9Sstevel@tonic-gate /* first line of real reply -- ignore rest */
32507c478bd9Sstevel@tonic-gate bufp = junkbuf;
32517c478bd9Sstevel@tonic-gate }
32527c478bd9Sstevel@tonic-gate
32537c478bd9Sstevel@tonic-gate /*
32547c478bd9Sstevel@tonic-gate ** Now look at SmtpReplyBuffer -- only care about the first
32557c478bd9Sstevel@tonic-gate ** line of the response from here on out.
32567c478bd9Sstevel@tonic-gate */
32577c478bd9Sstevel@tonic-gate
32587c478bd9Sstevel@tonic-gate /* save temporary failure messages for posterity */
32597c478bd9Sstevel@tonic-gate if (SmtpReplyBuffer[0] == '4')
3260058561cbSjbeck (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof(SmtpError));
32617c478bd9Sstevel@tonic-gate
32627c478bd9Sstevel@tonic-gate /* reply code 421 is "Service Shutting Down" */
32637c478bd9Sstevel@tonic-gate if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
32647c478bd9Sstevel@tonic-gate mci->mci_state != MCIS_QUITING)
32657c478bd9Sstevel@tonic-gate {
32667c478bd9Sstevel@tonic-gate /* send the quit protocol */
32677c478bd9Sstevel@tonic-gate mci->mci_state = MCIS_SSD;
32687c478bd9Sstevel@tonic-gate smtpquit(m, mci, e);
32697c478bd9Sstevel@tonic-gate }
32707c478bd9Sstevel@tonic-gate
32717c478bd9Sstevel@tonic-gate return r;
32727c478bd9Sstevel@tonic-gate }
32737c478bd9Sstevel@tonic-gate /*
32747c478bd9Sstevel@tonic-gate ** SMTPMESSAGE -- send message to server
32757c478bd9Sstevel@tonic-gate **
32767c478bd9Sstevel@tonic-gate ** Parameters:
32777c478bd9Sstevel@tonic-gate ** f -- format
32787c478bd9Sstevel@tonic-gate ** m -- the mailer to control formatting.
32797c478bd9Sstevel@tonic-gate ** a, b, c -- parameters
32807c478bd9Sstevel@tonic-gate **
32817c478bd9Sstevel@tonic-gate ** Returns:
32827c478bd9Sstevel@tonic-gate ** none.
32837c478bd9Sstevel@tonic-gate **
32847c478bd9Sstevel@tonic-gate ** Side Effects:
32857c478bd9Sstevel@tonic-gate ** writes message to mci->mci_out.
32867c478bd9Sstevel@tonic-gate */
32877c478bd9Sstevel@tonic-gate
32887c478bd9Sstevel@tonic-gate /*VARARGS1*/
32897c478bd9Sstevel@tonic-gate void
32907c478bd9Sstevel@tonic-gate #ifdef __STDC__
smtpmessage(char * f,MAILER * m,MCI * mci,...)32917c478bd9Sstevel@tonic-gate smtpmessage(char *f, MAILER *m, MCI *mci, ...)
32927c478bd9Sstevel@tonic-gate #else /* __STDC__ */
32937c478bd9Sstevel@tonic-gate smtpmessage(f, m, mci, va_alist)
32947c478bd9Sstevel@tonic-gate char *f;
32957c478bd9Sstevel@tonic-gate MAILER *m;
32967c478bd9Sstevel@tonic-gate MCI *mci;
32977c478bd9Sstevel@tonic-gate va_dcl
32987c478bd9Sstevel@tonic-gate #endif /* __STDC__ */
32997c478bd9Sstevel@tonic-gate {
33007c478bd9Sstevel@tonic-gate SM_VA_LOCAL_DECL
33017c478bd9Sstevel@tonic-gate
33027c478bd9Sstevel@tonic-gate SM_VA_START(ap, mci);
3303058561cbSjbeck (void) sm_vsnprintf(SmtpMsgBuffer, sizeof(SmtpMsgBuffer), f, ap);
33047c478bd9Sstevel@tonic-gate SM_VA_END(ap);
33057c478bd9Sstevel@tonic-gate
33067c478bd9Sstevel@tonic-gate if (tTd(18, 1) || Verbose)
33077c478bd9Sstevel@tonic-gate nmessage(">>> %s", SmtpMsgBuffer);
33087c478bd9Sstevel@tonic-gate if (TrafficLogFile != NULL)
33097c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
33107c478bd9Sstevel@tonic-gate "%05d >>> %s\n", (int) CurrentPid,
33117c478bd9Sstevel@tonic-gate SmtpMsgBuffer);
33127c478bd9Sstevel@tonic-gate if (mci->mci_out != NULL)
33137c478bd9Sstevel@tonic-gate {
33147c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
33157c478bd9Sstevel@tonic-gate SmtpMsgBuffer, m == NULL ? "\r\n"
33167c478bd9Sstevel@tonic-gate : m->m_eol);
33177c478bd9Sstevel@tonic-gate }
33187c478bd9Sstevel@tonic-gate else if (tTd(18, 1))
33197c478bd9Sstevel@tonic-gate {
33207c478bd9Sstevel@tonic-gate sm_dprintf("smtpmessage: NULL mci_out\n");
33217c478bd9Sstevel@tonic-gate }
33227c478bd9Sstevel@tonic-gate }
3323