2 * Copyright (c) 1998-2006, 2008-2010, 2014 Proofpoint, Inc. and its suppliers.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
16 SM_RCSID("@(#)$Id: usersmtp.c,v 8.488 2013-11-22 20:51:57 ca Exp $")
21 static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
22 static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
23 static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
26 extern void *sm_sasl_malloc __P((unsigned long));
27 extern void sm_sasl_free __P((void *));
31 ** USERSMTP -- run SMTP protocol from the user end.
33 ** This protocol is described in RFC821.
36 #define SMTPCLOSING 421 /* "Service Shutting Down" */
38 #define ENHSCN(e, d) ((e) == NULL ? (d) : (e))
40 #define ENHSCN_RPOOL(e, d, rpool) \
41 ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
43 static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
44 static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
45 static bool SmtpNeedIntro; /* need "while talking" in transcript */
47 ** SMTPINIT -- initialize SMTP.
49 ** Opens the connection and sends the initial protocol.
52 ** m -- mailer to create connection to.
53 ** mci -- the mailer connection info.
55 ** onlyhelo -- send only helo command?
61 ** creates connection and sends initial protocol.
65 smtpinit(m, mci, e, onlyhelo)
75 #if _FFR_EXPAND_HELONAME
76 char hnbuf[MAXNAME + 1];
83 sm_dprintf("smtpinit ");
84 mci_dump(sm_debug_file(), mci, false);
88 ** Open the connection to the mailer.
92 SmtpMsgBuffer[0] = '\0';
93 CurHostName = mci->mci_host; /* XXX UGLY XXX */
94 if (CurHostName == NULL)
95 CurHostName = MyHostName;
97 state = mci->mci_state;
99 e->e_renhsc[0] = '\0';
106 /* need to clear old information */
118 /* shouldn't happen */
123 syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
132 mci->mci_state = MCIS_OPENING;
136 ** Get the greeting message.
137 ** This should appear spontaneously. Give it five minutes to
141 SmtpPhase = mci->mci_phase = "client greeting";
142 sm_setproctitle(true, e, "%s %s: %s",
143 qid_printname(e), CurHostName, mci->mci_phase);
144 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET);
147 if (REPLYTYPE(r) == 4)
149 if (REPLYTYPE(r) != 2)
153 ** Send the HELO command.
154 ** My mother taught me to always introduce myself.
158 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
159 mci->mci_flags |= MCIF_ESMTP;
160 if (mci->mci_heloname != NULL)
162 #if _FFR_EXPAND_HELONAME
163 expand(mci->mci_heloname, hnbuf, sizeof(hnbuf), e);
166 hn = mci->mci_heloname;
173 #if _FFR_IGNORE_EXT_ON_HELO
174 mci->mci_flags &= ~MCIF_HELO;
176 if (bitnset(M_LMTP, m->m_flags))
178 smtpmessage("LHLO %s", m, mci, hn);
179 SmtpPhase = mci->mci_phase = "client LHLO";
181 else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
182 !bitnset(M_FSMTP, m->m_flags))
184 smtpmessage("EHLO %s", m, mci, hn);
185 SmtpPhase = mci->mci_phase = "client EHLO";
189 smtpmessage("HELO %s", m, mci, hn);
190 SmtpPhase = mci->mci_phase = "client HELO";
191 #if _FFR_IGNORE_EXT_ON_HELO
192 mci->mci_flags |= MCIF_HELO;
195 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
196 CurHostName, mci->mci_phase);
198 bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
200 helo_options, NULL, XS_EHLO);
203 else if (REPLYTYPE(r) == 5)
205 if (bitset(MCIF_ESMTP, mci->mci_flags) &&
206 !bitnset(M_LMTP, m->m_flags))
208 /* try old SMTP instead */
209 mci->mci_flags &= ~MCIF_ESMTP;
214 else if (REPLYTYPE(r) != 2)
218 ** Check to see if we actually ended up talking to ourself.
219 ** This means we didn't know about an alias or MX, or we managed
220 ** to connect to an echo server.
223 p = strchr(&SmtpReplyBuffer[4], ' ');
226 if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
227 !bitnset(M_LMTP, m->m_flags) &&
228 sm_strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
230 syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
232 mci_setstat(mci, EX_CONFIG, "5.3.5",
233 "553 5.3.5 system config error");
240 ** If this is expected to be another sendmail, send some internal
242 ** If we're running as MSP, "propagate" -v flag if possible.
245 if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags))
246 || bitnset(M_INTERNAL, m->m_flags))
248 /* tell it to be verbose */
249 smtpmessage("VERB", m, mci);
250 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
256 if (mci->mci_state != MCIS_CLOSED)
258 mci->mci_state = MCIS_OPEN;
262 /* got a 421 error code during startup */
265 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
266 if (mci->mci_state != MCIS_CLOSED)
271 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
272 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
274 if (mci->mci_state != MCIS_CLOSED)
279 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
284 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
287 ** line -- the response line.
288 ** firstline -- set if this is the first line of the reply.
290 ** mci -- the mailer connection info.
291 ** e -- the envelope.
298 esmtp_check(line, firstline, m, mci, e)
305 if (strstr(line, "ESMTP") != NULL)
306 mci->mci_flags |= MCIF_ESMTP;
309 ** Dirty hack below. Quoting the author:
310 ** This was a response to people who wanted SMTP transmission to be
311 ** just-send-8 by default. Essentially, you could put this tag into
312 ** your greeting message to behave as though the F=8 flag was set on
316 if (strstr(line, "8BIT-OK") != NULL)
317 mci->mci_flags |= MCIF_8BITOK;
321 /* specify prototype so compiler can check calls */
322 static char *str_union __P((char *, char *, SM_RPOOL_T *));
325 ** STR_UNION -- create the union of two lists
328 ** s1, s2 -- lists of items (separated by single blanks).
329 ** rpool -- resource pool from which result is allocated.
332 ** the union of both lists.
336 str_union(s1, s2, rpool)
340 char *hr, *h1, *h, *res;
343 if (s1 == NULL || *s1 == '\0')
345 if (s2 == NULL || *s2 == '\0')
352 sm_syslog(LOG_WARNING, NOQID,
353 "str_union: stringlen1=%d, stringlen2=%d, sum=%d, status=overflow",
358 res = (char *) sm_rpool_malloc(rpool, rl + 2);
365 (void) sm_strlcpy(res, s1, rl);
370 /* walk through s2 */
371 while (h != NULL && *h1 != '\0')
373 /* is there something after the current word? */
374 if ((h = strchr(h1, ' ')) != NULL)
378 /* does the current word appear in s1 ? */
379 if (iteminlist(h1, s1, " ") == NULL)
381 /* add space as delimiter */
387 /* advance pointer in result list */
393 /* there are more items */
403 ** HELO_OPTIONS -- process the options on a HELO line.
406 ** line -- the response line.
407 ** firstline -- set if this is the first line of the reply.
409 ** mci -- the mailer connection info.
410 ** e -- the envelope (unused).
417 helo_options(line, firstline, m, mci, e)
425 #if _FFR_IGNORE_EXT_ON_HELO
426 static bool logged = false;
431 mci_clr_extensions(mci);
432 #if _FFR_IGNORE_EXT_ON_HELO
437 #if _FFR_IGNORE_EXT_ON_HELO
438 else if (bitset(MCIF_HELO, mci->mci_flags))
440 if (LogLevel > 8 && !logged)
442 sm_syslog(LOG_WARNING, NOQID,
443 "server=%s [%s] returned extensions despite HELO command",
444 macvalue(macid("{server_name}"), e),
445 macvalue(macid("{server_addr}"), e));
450 #endif /* _FFR_IGNORE_EXT_ON_HELO */
452 if (strlen(line) < 5)
455 p = strpbrk(line, " =");
458 if (sm_strcasecmp(line, "size") == 0)
460 mci->mci_flags |= MCIF_SIZE;
462 mci->mci_maxsize = atol(p);
464 else if (sm_strcasecmp(line, "8bitmime") == 0)
466 mci->mci_flags |= MCIF_8BITMIME;
467 mci->mci_flags &= ~MCIF_7BIT;
469 else if (sm_strcasecmp(line, "expn") == 0)
470 mci->mci_flags |= MCIF_EXPN;
471 else if (sm_strcasecmp(line, "dsn") == 0)
472 mci->mci_flags |= MCIF_DSN;
473 else if (sm_strcasecmp(line, "enhancedstatuscodes") == 0)
474 mci->mci_flags |= MCIF_ENHSTAT;
475 else if (sm_strcasecmp(line, "pipelining") == 0)
476 mci->mci_flags |= MCIF_PIPELINED;
477 else if (sm_strcasecmp(line, "verb") == 0)
478 mci->mci_flags |= MCIF_VERB;
480 else if (sm_strcasecmp(line, "smtputf8") == 0)
481 mci->mci_flags |= MCIF_EAI;
482 #endif /* _FFR_EAI */
484 else if (sm_strcasecmp(line, "starttls") == 0)
485 mci->mci_flags |= MCIF_TLS;
487 else if (sm_strcasecmp(line, "deliverby") == 0)
489 mci->mci_flags |= MCIF_DLVR_BY;
491 mci->mci_min_by = atol(p);
494 else if (sm_strcasecmp(line, "auth") == 0)
496 if (p != NULL && *p != '\0' &&
497 !bitset(MCIF_AUTH2, mci->mci_flags))
499 if (mci->mci_saslcap != NULL)
502 ** Create the union with previous auth
503 ** offerings because we recognize "auth "
504 ** and "auth=" (old format).
507 mci->mci_saslcap = str_union(mci->mci_saslcap,
509 mci->mci_flags |= MCIF_AUTH2;
516 mci->mci_saslcap = (char *)
517 sm_rpool_malloc(mci->mci_rpool, l);
518 if (mci->mci_saslcap != NULL)
520 (void) sm_strlcpy(mci->mci_saslcap, p,
522 mci->mci_flags |= MCIF_AUTH;
527 sm_syslog(LOG_DEBUG, NOQID, "AUTH flags=%lx, mechs=%s",
528 mci->mci_flags, mci->mci_saslcap);
534 static int getsimple __P((void *, int, const char **, unsigned *));
535 static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
536 static int saslgetrealm __P((void *, int, const char **, const char **));
537 static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
538 static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *));
539 static char *removemech __P((char *, char *, SM_RPOOL_T *));
540 static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
542 static sasl_callback_t callbacks[] =
544 { SASL_CB_GETREALM, (sasl_callback_ft)&saslgetrealm, NULL },
545 #define CB_GETREALM_IDX 0
546 { SASL_CB_PASS, (sasl_callback_ft)&getsecret, NULL },
547 #define CB_PASS_IDX 1
548 { SASL_CB_USER, (sasl_callback_ft)&getsimple, NULL },
549 #define CB_USER_IDX 2
550 { SASL_CB_AUTHNAME, (sasl_callback_ft)&getsimple, NULL },
551 #define CB_AUTHNAME_IDX 3
552 { SASL_CB_VERIFYFILE, (sasl_callback_ft)&safesaslfile, NULL },
553 #define CB_SAFESASL_IDX 4
554 { SASL_CB_LIST_END, NULL, NULL }
558 ** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
564 ** SASL_OK -- if successful.
565 ** SASL error code -- otherwise.
568 ** checks/sets sasl_clt_init.
571 ** Callbacks are ignored if sasl_client_init() has
572 ** been called before (by a library such as libnss_ldap)
575 static bool sasl_clt_init = false;
584 result = sasl_client_init(callbacks);
586 /* should we retry later again or just remember that it failed? */
587 if (result == SASL_OK)
588 sasl_clt_init = true;
592 ** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
601 ** checks/sets sasl_clt_init.
609 sasl_clt_init = false;
613 ** GETSASLDATA -- process the challenges from the SASL protocol
615 ** This gets the relevant sasl response data out of the reply
619 ** line -- the response line.
620 ** firstline -- set if this is the first line of the reply.
622 ** mci -- the mailer connection info.
623 ** e -- the envelope (unused).
629 static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
632 getsasldata(line, firstline, m, mci, e)
645 /* if not a continue we don't care about it */
649 !isascii(line[1]) || !isdigit(line[1]) ||
650 !isascii(line[2]) || !isdigit(line[2]))
652 SM_FREE(mci->mci_sasl_string);
656 /* forget about "334 " */
660 /* XXX put this into a macro/function? It's duplicated below */
661 if (mci->mci_sasl_string != NULL)
663 if (mci->mci_sasl_string_len <= len)
665 sm_free(mci->mci_sasl_string); /* XXX */
666 mci->mci_sasl_string = xalloc(len + 1);
670 mci->mci_sasl_string = xalloc(len + 1);
672 result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
673 (unsigned int *) &mci->mci_sasl_string_len);
674 if (result != SASL_OK)
676 mci->mci_sasl_string_len = 0;
677 *mci->mci_sasl_string = '\0';
679 # else /* SASL >= 20000 */
680 out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
681 result = sasl_decode64(line, len, out, (unsigned int *) &len);
682 if (result != SASL_OK)
689 ** mci_sasl_string is "shared" with Cyrus-SASL library; hence
690 ** it can't be in an rpool unless we use the same memory
691 ** management mechanism (with same rpool!) for Cyrus SASL.
694 if (mci->mci_sasl_string != NULL)
696 if (mci->mci_sasl_string_len <= len)
698 sm_free(mci->mci_sasl_string); /* XXX */
699 mci->mci_sasl_string = xalloc(len + 1);
703 mci->mci_sasl_string = xalloc(len + 1);
705 memcpy(mci->mci_sasl_string, out, len);
706 mci->mci_sasl_string[len] = '\0';
707 mci->mci_sasl_string_len = len;
708 # endif /* SASL >= 20000 */
712 ** READAUTH -- read auth values from a file
715 ** filename -- name of file to read.
716 ** safe -- if set, this is a safe read.
717 ** sai -- where to store auth_info.
718 ** rpool -- resource pool for sai.
721 ** EX_OK -- data successfully read.
722 ** EX_UNAVAILABLE -- no valid filename.
723 ** EX_TEMPFAIL -- temporary failure.
726 static char *sasl_info_name[] =
735 readauth(filename, safe, sai, rpool)
748 if (filename == NULL || filename[0] == '\0')
749 return EX_UNAVAILABLE;
751 #if !_FFR_ALLOW_SASLINFO
753 ** make sure we don't use a program that is not
754 ** accessible to the user who specified a different authinfo file.
755 ** However, currently we don't pass this info (authinfo file
756 ** specified by user) around, so we just turn off program access.
759 if (filename[0] == '|')
764 char *argv[MAXPV + 1];
767 for (p = strtok(&filename[1], " \t"); p != NULL;
768 p = strtok(NULL, " \t"))
775 pid = prog_open(argv, &fd, CurEnv);
779 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
780 (void *) &fd, SM_IO_RDONLY, NULL);
783 #endif /* !_FFR_ALLOW_SASLINFO */
786 sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
787 |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
788 if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
789 sff |= SFF_NOGRFILES;
790 if (DontLockReadFiles)
793 #if _FFR_ALLOW_SASLINFO
795 ** XXX: make sure we don't read or open files that are not
796 ** accessible to the user who specified a different authinfo
801 #else /* _FFR_ALLOW_SASLINFO */
803 sff |= SFF_OPENASROOT;
804 #endif /* _FFR_ALLOW_SASLINFO */
806 f = safefopen(filename, O_RDONLY, 0, sff);
811 sm_syslog(LOG_ERR, NOQID,
812 "AUTH=client, error: can't open %s: %s",
813 filename, sm_errstring(errno));
818 while (lc <= SASL_MECHLIST &&
819 sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
823 (*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
824 if ((s = strchr((*sai)[lc], '\n')) != NULL)
830 (void) sm_io_close(f, SM_TIME_DEFAULT);
833 if (lc < SASL_PASSWORD)
836 sm_syslog(LOG_ERR, NOQID,
837 "AUTH=client, error: can't read %s from %s",
838 sasl_info_name[lc + 1], filename);
845 ** GETAUTH -- get authinfo from ruleset call
847 ** {server_name}, {server_addr} must be set
850 ** mci -- the mailer connection structure.
851 ** e -- the envelope (including the sender to specify).
852 ** sai -- pointer to authinfo (result).
855 ** EX_OK -- ruleset was successfully called, data may not
856 ** be available, sai must be checked.
857 ** EX_UNAVAILABLE -- ruleset unavailable (or failed).
858 ** EX_TEMPFAIL -- temporary failure (from ruleset).
861 ** Fills in sai if successful.
870 int i, r, l, got, ret;
872 char pvpbuf[PSBUFSIZE];
874 r = rscap("authinfo", macvalue(macid("{server_name}"), e),
875 macvalue(macid("{server_addr}"), e), e,
876 &pvp, pvpbuf, sizeof(pvpbuf));
879 return EX_UNAVAILABLE;
881 /* other than expected return value: ok (i.e., no auth) */
882 if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
884 if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
888 ** parse the data, put it into sai
889 ** format: "TDstring" (including the '"' !)
890 ** where T is a tag: 'U', ...
891 ** D is a delimiter: ':' or '='
894 ret = EX_OK; /* default return value */
897 while (i < SASL_ENTRIES)
899 if (pvp[i + 1] == NULL)
901 if (pvp[i + 1][0] != '"')
903 switch (pvp[i + 1][1])
928 l = strlen(pvp[i + 1]);
931 if (l <= 3 || pvp[i + 1][l - 1] != '"')
934 /* remove closing quote */
935 pvp[i + 1][l - 1] = '\0';
937 /* remove "TD and " */
939 (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
940 if ((*sai)[r] == NULL)
942 if (pvp[i + 1][2] == ':')
944 /* ':text' (just copy) */
945 (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
948 else if (pvp[i + 1][2] == '=')
952 /* '=base64' (decode) */
954 ret = sasl_decode64(pvp[i + 1] + 3,
955 (unsigned int) l, (*sai)[r],
956 (unsigned int) l + 1, &len);
957 # else /* SASL >= 20000 */
958 ret = sasl_decode64(pvp[i + 1] + 3,
959 (unsigned int) l, (*sai)[r], &len);
960 # endif /* SASL >= 20000 */
968 sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
969 sasl_info_name[r], (*sai)[r]);
973 /* did we get the expected data? */
974 /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */
975 if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
976 bitset(SASL_PASSWORD_BIT, got)))
979 /* no authid? copy uid */
980 if (!bitset(SASL_AUTHID_BIT, got))
982 l = strlen((*sai)[SASL_USER]) + 1;
983 (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
985 if ((*sai)[SASL_AUTHID] == NULL)
987 (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
990 /* no uid? copy authid */
991 if (!bitset(SASL_USER_BIT, got))
993 l = strlen((*sai)[SASL_AUTHID]) + 1;
994 (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
996 if ((*sai)[SASL_USER] == NULL)
998 (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
1006 sm_syslog(LOG_WARNING, NOQID,
1007 "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
1008 macvalue(macid("{server_name}"), e),
1009 macvalue(macid("{server_addr}"), e),
1010 ret == EX_TEMPFAIL ? "temp" : "");
1011 for (i = 0; i <= SASL_MECHLIST; i++)
1012 (*sai)[i] = NULL; /* just clear; rpool */
1018 ** GETSIMPLE -- callback to get userid or authid
1023 ** result -- (pointer to) result
1024 ** len -- (pointer to) length of result
1027 ** OK/failure values
1031 getsimple(context, id, result, len)
1034 const char **result;
1039 if (result == NULL || context == NULL)
1040 return SASL_BADPARAM;
1041 sai = (SASL_AI_T *) context;
1046 *result = (*sai)[SASL_USER];
1048 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1051 *len = *result != NULL ? strlen(*result) : 0;
1054 case SASL_CB_AUTHNAME:
1055 *result = (*sai)[SASL_AUTHID];
1057 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1060 *len = *result != NULL ? strlen(*result) : 0;
1063 case SASL_CB_LANGUAGE:
1070 return SASL_BADPARAM;
1075 ** GETSECRET -- callback to get password
1078 ** conn -- connection information
1081 ** psecret -- (pointer to) result
1084 ** OK/failure values
1088 getsecret(conn, context, id, psecret)
1090 SM_UNUSED(void *context);
1092 sasl_secret_t **psecret;
1098 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1099 return SASL_BADPARAM;
1101 mci = (MCI *) context;
1102 authpass = mci->mci_sai[SASL_PASSWORD];
1103 len = strlen(authpass);
1106 ** use an rpool because we are responsible for free()ing the secret,
1107 ** but we can't free() it until after the auth completes
1110 *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
1111 sizeof(sasl_secret_t) +
1113 if (*psecret == NULL)
1115 (void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1);
1116 (*psecret)->len = (unsigned long) len;
1119 # else /* SASL >= 20000 */
1121 ** GETSIMPLE -- callback to get userid or authid
1126 ** result -- (pointer to) result
1127 ** len -- (pointer to) length of result
1130 ** OK/failure values
1134 getsimple(context, id, result, len)
1137 const char **result;
1146 char *authid = NULL;
1148 if (result == NULL || context == NULL)
1149 return SASL_BADPARAM;
1150 sai = (SASL_AI_T *) context;
1153 ** Unfortunately it is not clear whether this routine should
1154 ** return a copy of a string or just a pointer to a string.
1155 ** The Cyrus-SASL plugins treat these return values differently, e.g.,
1156 ** plugins/cram.c free()s authid, plugings/digestmd5.c does not.
1157 ** The best solution to this problem is to fix Cyrus-SASL, but it
1158 ** seems there is nobody who creates patches... Hello CMU!?
1159 ** The second best solution is to have flags that tell this routine
1160 ** whether to return an malloc()ed copy.
1161 ** The next best solution is to always return an malloc()ed copy,
1162 ** and suffer from some memory leak, which is ugly for persistent
1164 ** For now we go with the last solution...
1165 ** We can't use rpools (which would avoid this particular problem)
1166 ** as explained in sasl.c.
1172 l = strlen((*sai)[SASL_USER]) + 1;
1173 s = sm_sasl_malloc(l);
1181 (void) sm_strlcpy(s, (*sai)[SASL_USER], l);
1184 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1187 *len = *result != NULL ? strlen(*result) : 0;
1190 case SASL_CB_AUTHNAME:
1191 h = (*sai)[SASL_AUTHID];
1193 /* XXX maybe other mechanisms too?! */
1194 addrealm = (*sai)[SASL_MECH] != NULL &&
1195 sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0;
1198 ** Add realm to authentication id unless authid contains
1199 ** '@' (i.e., a realm) or the default realm is empty.
1202 if (addrealm && h != NULL && strchr(h, '@') == NULL)
1204 /* has this been done before? */
1205 if ((*sai)[SASL_ID_REALM] == NULL)
1209 realm = (*sai)[SASL_DEFREALM];
1211 /* do not add an empty realm */
1215 (*sai)[SASL_ID_REALM] = NULL;
1219 l = strlen(h) + strlen(realm) + 2;
1221 /* should use rpool, but from where? */
1222 authid = sm_sasl_malloc(l);
1225 (void) sm_snprintf(authid, l,
1228 (*sai)[SASL_ID_REALM] = authid;
1233 (*sai)[SASL_ID_REALM] = NULL;
1238 authid = (*sai)[SASL_ID_REALM];
1241 # endif /* SASL > 10509 */
1243 l = strlen(authid) + 1;
1244 s = sm_sasl_malloc(l);
1252 (void) sm_strlcpy(s, authid, l);
1255 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1258 *len = authid ? strlen(authid) : 0;
1261 case SASL_CB_LANGUAGE:
1268 return SASL_BADPARAM;
1273 ** GETSECRET -- callback to get password
1276 ** conn -- connection information
1279 ** psecret -- (pointer to) result
1282 ** OK/failure values
1286 getsecret(conn, context, id, psecret)
1288 SM_UNUSED(void *context);
1290 sasl_secret_t **psecret;
1296 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1297 return SASL_BADPARAM;
1299 sai = (SASL_AI_T *) context;
1300 authpass = (*sai)[SASL_PASSWORD];
1301 len = strlen(authpass);
1302 *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
1304 if (*psecret == NULL)
1306 (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
1307 (*psecret)->len = (unsigned long) len;
1310 # endif /* SASL >= 20000 */
1313 ** SAFESASLFILE -- callback for sasl: is file safe?
1316 ** context -- pointer to context between invocations (unused)
1317 ** file -- name of file to check
1318 ** type -- type of file to check
1321 ** SASL_OK -- file can be used
1322 ** SASL_CONTINUE -- don't use file
1323 ** SASL_FAIL -- failure (not used here)
1329 safesaslfile(context, file, type)
1331 safesaslfile(context, file)
1341 sasl_verify_type_t type;
1354 if (file == NULL || *file == '\0')
1357 sm_dprintf("safesaslfile=%s\n", file);
1358 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
1360 if ((p = strrchr(file, '/')) == NULL)
1365 /* everything beside libs and .conf files must not be readable */
1367 if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
1368 (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
1370 if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1371 sff |= SFF_NORFILES;
1372 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1373 sff |= SFF_NOGWFILES;
1375 #else /* SASL <= 10515 */
1376 /* files containing passwords should be not readable */
1377 if (type == SASL_VRFY_PASSWD)
1379 if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1380 sff |= SFF_NOWRFILES;
1382 sff |= SFF_NORFILES;
1383 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1384 sff |= SFF_NOGWFILES;
1386 #endif /* SASL <= 10515 */
1389 if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
1390 S_IRUSR, NULL)) == 0)
1392 if (LogLevel > (r != ENOENT ? 8 : 10))
1393 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
1394 p, sm_errstring(r));
1395 return SASL_CONTINUE;
1399 ** SASLGETREALM -- return the realm for SASL
1401 ** return the realm for the client
1404 ** context -- context shared between invocations
1405 ** availrealms -- list of available realms
1406 ** {realm, realm, ...}
1407 ** result -- pointer to result
1414 saslgetrealm(context, id, availrealms, result)
1417 const char **availrealms;
1418 const char **result;
1423 sai = (SASL_AI_T *) context;
1426 r = (*sai)[SASL_DEFREALM];
1429 sm_syslog(LOG_INFO, NOQID,
1430 "AUTH=client, realm=%s, available realms=%s",
1431 r == NULL ? "<No Realm>" : r,
1432 (availrealms == NULL || *availrealms == NULL)
1433 ? "<No Realms>" : *availrealms);
1435 /* check whether context is in list */
1436 if (availrealms != NULL && *availrealms != NULL)
1438 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
1442 sm_syslog(LOG_ERR, NOQID,
1443 "AUTH=client, realm=%s not in list=%s",
1452 ** ITEMINLIST -- does item appear in list?
1454 ** Check whether item appears in list (which must be separated by a
1455 ** character in delim) as a "word", i.e. it must appear at the begin
1456 ** of the list or after a space, and it must end with a space or the
1460 ** item -- item to search.
1461 ** list -- list of items.
1462 ** delim -- list of delimiters.
1465 ** pointer to occurrence (NULL if not found).
1469 iteminlist(item, list, delim)
1477 if (list == NULL || *list == '\0')
1479 if (item == NULL || *item == '\0')
1483 while (s != NULL && *s != '\0')
1485 if (sm_strncasecmp(s, item, len) == 0 &&
1486 (s[len] == '\0' || strchr(delim, s[len]) != NULL))
1488 s = strpbrk(s, delim);
1496 ** REMOVEMECH -- remove item [rem] from list [list]
1499 ** rem -- item to remove
1500 ** list -- list of items
1501 ** rpool -- resource pool from which result is allocated.
1504 ** pointer to new list (NULL in case of error).
1508 removemech(rem, list, rpool)
1519 if (rem == NULL || *rem == '\0')
1521 /* take out what? */
1525 /* find the item in the list */
1526 if ((needle = iteminlist(rem, list, " ")) == NULL)
1528 /* not in there: return original */
1532 /* length of string without rem */
1533 len = strlen(list) - strlen(rem);
1536 ret = (char *) sm_rpool_malloc_x(rpool, 1);
1540 ret = (char *) sm_rpool_malloc_x(rpool, len);
1541 memset(ret, '\0', len);
1543 /* copy from start to removed item */
1544 memcpy(ret, list, needle - list);
1546 /* length of rest of string past removed item */
1547 len = strlen(needle) - strlen(rem) - 1;
1550 /* not last item -- copy into string */
1551 memcpy(ret + (needle - list),
1552 list + (needle - list) + strlen(rem) + 1,
1556 ret[(needle - list) - 1] = '\0';
1560 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism
1564 ** mci -- the mailer connection structure.
1565 ** e -- the envelope (including the sender to specify).
1566 ** sai - sasl authinfo
1569 ** EX_OK -- authentication was successful.
1570 ** EX_NOPERM -- authentication failed.
1571 ** EX_IOERR -- authentication dialogue failed (I/O problem?).
1572 ** EX_TEMPFAIL -- temporary failure.
1577 attemptauth(m, mci, e, sai)
1583 int saslresult, smtpresult;
1586 const char *auth_id;
1588 # else /* SASL >= 20000 */
1589 sasl_external_properties_t ssf;
1591 # endif /* SASL >= 20000 */
1592 unsigned int outlen;
1593 sasl_interact_t *client_interact = NULL;
1595 sasl_security_properties_t ssp;
1597 /* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */
1598 char in64[MAXOUTLEN + 1];
1599 #if NETINET || (NETINET6 && SASL >= 20000)
1600 extern SOCKADDR CurHostAddr;
1603 /* no mechanism selected (yet) */
1604 (*sai)[SASL_MECH] = NULL;
1606 /* dispose old connection */
1607 if (mci->mci_conn != NULL)
1608 sasl_dispose(&(mci->mci_conn));
1610 /* make a new client sasl connection */
1613 ** We provide the callbacks again because global callbacks in
1614 ** sasl_client_init() are ignored if SASL has been initialized
1615 ** before, for example, by a library such as libnss-ldap.
1618 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1620 CurHostName, NULL, NULL, callbacks, 0,
1622 # else /* SASL >= 20000 */
1623 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1625 CurHostName, NULL, 0, &mci->mci_conn);
1626 # endif /* SASL >= 20000 */
1627 if (saslresult != SASL_OK)
1630 /* set properties */
1631 (void) memset(&ssp, '\0', sizeof(ssp));
1633 /* XXX should these be options settable via .cf ? */
1634 ssp.max_ssf = MaxSLBits;
1635 ssp.maxbufsize = MAXOUTLEN;
1637 ssp.security_flags = SASL_SEC_NOPLAINTEXT;
1639 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
1640 if (saslresult != SASL_OK)
1644 /* external security strength factor, authentication id */
1648 out = macvalue(macid("{cert_subject}"), e);
1649 if (out != NULL && *out != '\0')
1651 out = macvalue(macid("{cipher_bits}"), e);
1652 if (out != NULL && *out != '\0')
1654 # endif /* STARTTLS */
1655 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1656 if (saslresult != SASL_OK)
1658 saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
1659 if (saslresult != SASL_OK)
1662 # if NETINET || NETINET6
1663 /* set local/remote ipv4 addresses */
1664 if (mci->mci_out != NULL && (
1666 CurHostAddr.sa.sa_family == AF_INET6 ||
1668 CurHostAddr.sa.sa_family == AF_INET))
1670 SOCKADDR_LEN_T addrsize;
1672 char localip[60], remoteip[60];
1674 switch (CurHostAddr.sa.sa_family)
1677 addrsize = sizeof(struct sockaddr_in);
1681 addrsize = sizeof(struct sockaddr_in6);
1687 if (iptostring(&CurHostAddr, addrsize,
1688 remoteip, sizeof(remoteip)))
1690 if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
1691 remoteip) != SASL_OK)
1694 addrsize = sizeof(saddr_l);
1695 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1697 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1699 if (iptostring(&saddr_l, addrsize,
1700 localip, sizeof(localip)))
1702 if (sasl_setprop(mci->mci_conn,
1704 localip) != SASL_OK)
1709 # endif /* NETINET || NETINET6 */
1711 /* start client side of sasl */
1712 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1715 (const char **) &mechusing);
1716 # else /* SASL >= 20000 */
1717 /* external security strength factor, authentication id */
1721 out = macvalue(macid("{cert_subject}"), e);
1722 if (out != NULL && *out != '\0')
1724 out = macvalue(macid("{cipher_bits}"), e);
1725 if (out != NULL && *out != '\0')
1726 ssf.ssf = atoi(out);
1727 # endif /* STARTTLS */
1728 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1729 if (saslresult != SASL_OK)
1733 /* set local/remote ipv4 addresses */
1734 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
1736 SOCKADDR_LEN_T addrsize;
1737 struct sockaddr_in saddr_l;
1739 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
1740 (struct sockaddr_in *) &CurHostAddr)
1743 addrsize = sizeof(struct sockaddr_in);
1744 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1746 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1748 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
1749 &saddr_l) != SASL_OK)
1753 # endif /* NETINET */
1755 /* start client side of sasl */
1756 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1757 NULL, &client_interact,
1759 (const char **) &mechusing);
1760 # endif /* SASL >= 20000 */
1762 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1764 if (saslresult == SASL_NOMECH && LogLevel > 8)
1766 sm_syslog(LOG_NOTICE, e->e_id,
1767 "AUTH=client, available mechanisms=%s do not fulfill requirements", mci->mci_saslcap);
1772 /* just point current mechanism to the data in the sasl library */
1773 (*sai)[SASL_MECH] = mechusing;
1775 /* send the info across the wire */
1777 /* login and digest-md5 up to 1.5.28 set out="" */
1779 (sm_strcasecmp(mechusing, "LOGIN") == 0 ||
1780 sm_strcasecmp(mechusing, "DIGEST-MD5") == 0))
1783 /* no initial response */
1784 smtpmessage("AUTH %s", m, mci, mechusing);
1786 else if (outlen == 0)
1789 ** zero-length initial response, per RFC 2554 4.:
1790 ** "Unlike a zero-length client answer to a 334 reply, a zero-
1791 ** length initial response is sent as a single equals sign"
1794 smtpmessage("AUTH %s =", m, mci, mechusing);
1798 saslresult = sasl_encode64(out, outlen, in64, sizeof(in64),
1800 if (saslresult != SASL_OK) /* internal error */
1803 sm_syslog(LOG_ERR, e->e_id,
1804 "encode64 for AUTH failed");
1807 smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
1810 sm_sasl_free(out); /* XXX only if no rpool is used */
1814 smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
1819 /* check return code from server */
1820 if (smtpresult == 235)
1822 macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
1826 if (smtpresult == -1)
1828 if (REPLYTYPE(smtpresult) == 5)
1829 return EX_NOPERM; /* ugly, but ... */
1830 if (REPLYTYPE(smtpresult) != 3)
1832 /* should we fail deliberately, see RFC 2554 4. ? */
1833 /* smtpmessage("*", m, mci); */
1837 saslresult = sasl_client_step(mci->mci_conn,
1838 mci->mci_sasl_string,
1839 mci->mci_sasl_string_len,
1843 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1846 sm_dprintf("AUTH FAIL=%s (%d)\n",
1847 sasl_errstring(saslresult, NULL, NULL),
1850 /* fail deliberately, see RFC 2554 4. */
1851 smtpmessage("*", m, mci);
1854 ** but we should only fail for this authentication
1855 ** mechanism; how to do that?
1858 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1859 getsasldata, NULL, XS_AUTH);
1865 saslresult = sasl_encode64(out, outlen, in64,
1866 sizeof(in64), NULL);
1867 if (saslresult != SASL_OK)
1869 /* give an error reply to the other side! */
1870 smtpmessage("*", m, mci);
1877 sm_sasl_free(out); /* XXX only if no rpool is used */
1879 smtpmessage("%s", m, mci, in64);
1880 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1881 getsasldata, NULL, XS_AUTH);
1886 ** SMTPAUTH -- try to AUTHenticate
1888 ** This will try mechanisms in the order the sasl library decided until:
1889 ** - there are no more mechanisms
1890 ** - a mechanism succeeds
1891 ** - the sasl library fails initializing
1895 ** mci -- the mailer connection info.
1896 ** e -- the envelope.
1899 ** EX_OK -- authentication was successful
1900 ** EX_UNAVAILABLE -- authentication not possible, e.g.,
1901 ** no data available.
1902 ** EX_NOPERM -- authentication failed.
1903 ** EX_TEMPFAIL -- temporary failure.
1905 ** Notice: AuthInfo is used for all connections, hence we must
1906 ** return EX_TEMPFAIL only if we really want to retry, i.e.,
1907 ** iff getauth() tempfailed or getauth() was used and
1908 ** authentication tempfailed.
1921 mci->mci_sasl_auth = false;
1922 for (i = 0; i < SASL_MECH ; i++)
1923 mci->mci_sai[i] = NULL;
1925 result = getauth(mci, e, &(mci->mci_sai));
1926 if (result == EX_TEMPFAIL)
1930 /* no data available: don't try to authenticate */
1931 if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
1933 if (result != EX_OK)
1935 if (SASLInfo == NULL)
1936 return EX_UNAVAILABLE;
1938 /* read authinfo from file */
1939 result = readauth(SASLInfo, true, &(mci->mci_sai),
1941 if (result != EX_OK)
1943 usedgetauth = false;
1946 /* check whether sufficient data is available */
1947 if (mci->mci_sai[SASL_PASSWORD] == NULL ||
1948 *(mci->mci_sai)[SASL_PASSWORD] == '\0')
1949 return EX_UNAVAILABLE;
1950 if ((mci->mci_sai[SASL_AUTHID] == NULL ||
1951 *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
1952 (mci->mci_sai[SASL_USER] == NULL ||
1953 *(mci->mci_sai)[SASL_USER] == '\0'))
1954 return EX_UNAVAILABLE;
1956 /* set the context for the callback function to sai */
1958 callbacks[CB_PASS_IDX].context = (void *) mci;
1960 callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
1962 callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
1963 callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
1964 callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
1966 callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
1969 /* set default value for realm */
1970 if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
1971 (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
1972 macvalue('j', CurEnv));
1974 /* set default value for list of mechanism to use */
1975 if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
1976 *(mci->mci_sai)[SASL_MECHLIST] == '\0')
1977 (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
1979 /* create list of mechanisms to try */
1980 mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
1981 mci->mci_saslcap, mci->mci_rpool);
1983 /* initialize sasl client library */
1984 result = init_sasl_client();
1985 if (result != SASL_OK)
1986 return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
1989 result = attemptauth(m, mci, e, &(mci->mci_sai));
1990 if (result == EX_OK)
1991 mci->mci_sasl_auth = true;
1992 else if (result == EX_TEMPFAIL || result == EX_NOPERM)
1994 mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
1997 if (mci->mci_saslcap == NULL ||
1998 *(mci->mci_saslcap) == '\0')
1999 return usedgetauth ? result
2004 } while (result != EX_OK);
2010 ** SMTPMAILFROM -- send MAIL command
2014 ** mci -- the mailer connection structure.
2015 ** e -- the envelope (including the sender to specify).
2019 smtpmailfrom(m, mci, e)
2028 char buf[MAXNAME + 1];
2029 char optbuf[MAXLINE];
2032 sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
2036 ** Check if connection is gone, if so
2037 ** it's a tempfail and we use mci_errno
2041 if (mci->mci_state == MCIS_CLOSED)
2043 errno = mci->mci_errno;
2049 ** Abort right away if the message needs SMTPUTF8 and the
2050 ** server does not advertise SMTPUTF8.
2053 if (e->e_smtputf8 && !bitset(MCIF_EAI, mci->mci_flags)) {
2054 usrerrenh("5.6.7", "%s does not support SMTPUTF8", CurHostName);
2055 mci_setstat(mci, EX_NOTSTICKY, "5.6.7", NULL);
2058 #endif /* _FFR_EAI */
2060 /* set up appropriate options to include */
2061 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
2063 (void) sm_snprintf(optbuf, sizeof(optbuf), " SIZE=%ld",
2065 bufp = &optbuf[strlen(optbuf)];
2074 if (e->e_smtputf8) {
2075 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2077 bufp += strlen(bufp);
2079 #endif /* _FFR_EAI */
2081 bodytype = e->e_bodytype;
2082 if (bitset(MCIF_8BITMIME, mci->mci_flags))
2084 if (bodytype == NULL &&
2085 bitset(MM_MIME8BIT, MimeMode) &&
2086 bitset(EF_HAS8BIT, e->e_flags) &&
2087 !bitset(EF_DONT_MIME, e->e_flags) &&
2088 !bitnset(M_8BITS, m->m_flags))
2089 bodytype = "8BITMIME";
2090 if (bodytype != NULL &&
2091 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
2093 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2094 " BODY=%s", bodytype);
2095 bufp += strlen(bufp);
2098 else if (bitnset(M_8BITS, m->m_flags) ||
2099 !bitset(EF_HAS8BIT, e->e_flags) ||
2100 bitset(MCIF_8BITOK, mci->mci_flags))
2103 /* just pass it through */
2106 else if (bitset(MM_CVTMIME, MimeMode) &&
2107 !bitset(EF_DONT_MIME, e->e_flags) &&
2108 (!bitset(MM_PASS8BIT, MimeMode) ||
2109 bitset(EF_IS_MIME, e->e_flags)))
2111 /* must convert from 8bit MIME format to 7bit encoded */
2112 mci->mci_flags |= MCIF_CVT8TO7;
2114 #endif /* MIME8TO7 */
2115 else if (!bitset(MM_PASS8BIT, MimeMode))
2117 /* cannot just send a 8-bit version */
2118 extern char MsgBuf[];
2120 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
2121 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
2125 if (bitset(MCIF_DSN, mci->mci_flags))
2127 if (e->e_envid != NULL &&
2128 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
2130 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2131 " ENVID=%s", e->e_envid);
2132 bufp += strlen(bufp);
2135 /* RET= parameter */
2136 if (bitset(EF_RET_PARAM, e->e_flags) &&
2137 SPACELEFT(optbuf, bufp) > 9)
2139 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2141 bitset(EF_NO_BODY_RETN, e->e_flags) ?
2143 bufp += strlen(bufp);
2147 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
2148 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
2150 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
2154 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2155 " AUTH=%s", e->e_auth_param);
2156 bufp += strlen(bufp);
2160 ** 17 is the max length required, we could use log() to compute
2161 ** the exact length (and check IS_DLVR_TRACE())
2164 if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
2165 IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
2170 ** Avoid problems with delays (for R) since the check
2171 ** in deliver() whether min-deliver-time is sufficient.
2172 ** Alternatively we could pass the computed time to this
2176 dby = e->e_deliver_by - (curtime() - e->e_ctime);
2177 if (dby <= 0 && IS_DLVR_RETURN(e))
2178 dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
2179 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2182 IS_DLVR_RETURN(e) ? 'R' : 'N',
2183 IS_DLVR_TRACE(e) ? "T" : "");
2184 bufp += strlen(bufp);
2188 ** Send the MAIL command.
2189 ** Designates the sender.
2192 mci->mci_state = MCIS_MAIL;
2194 if (bitset(EF_RESPONSE, e->e_flags) &&
2195 !bitnset(M_NO_NULL_FROM, m->m_flags))
2198 expand("\201g", buf, sizeof(buf), e);
2201 /* strip off <angle brackets> (put back on below) */
2202 bufp = &buf[strlen(buf) - 1];
2209 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
2210 !bitnset(M_FROMPATH, m->m_flags))
2212 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
2216 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
2217 *bufp == '@' ? ',' : ':', bufp, optbuf);
2219 SmtpPhase = mci->mci_phase = "client MAIL";
2220 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2221 CurHostName, mci->mci_phase);
2222 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL);
2225 /* communications failure */
2226 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
2229 else if (r == SMTPCLOSING)
2231 /* service shutting down: handled by reply() */
2234 else if (REPLYTYPE(r) == 4)
2236 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
2240 else if (REPLYTYPE(r) == 2)
2246 /* syntax error in arguments */
2247 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
2253 /* mailbox name not allowed */
2254 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
2260 /* exceeded storage allocation */
2261 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
2263 if (bitset(MCIF_SIZE, mci->mci_flags))
2264 e->e_flags |= EF_NO_BODY_RETN;
2265 return EX_UNAVAILABLE;
2267 else if (REPLYTYPE(r) == 5)
2270 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
2272 return EX_UNAVAILABLE;
2277 sm_syslog(LOG_CRIT, e->e_id,
2278 "%.100s: SMTP MAIL protocol error: %s",
2280 shortenstring(SmtpReplyBuffer, 403));
2283 /* protocol error -- close up */
2284 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2286 smtpquit(m, mci, e);
2290 ** SMTPRCPT -- designate recipient.
2293 ** to -- address of recipient.
2294 ** m -- the mailer we are sending to.
2295 ** mci -- the connection info for this transaction.
2296 ** e -- the envelope for this transaction.
2299 ** exit status corresponding to recipient status.
2302 ** Sends the mail via SMTP.
2306 smtprcpt(to, m, mci, e, ctladdr, xstart)
2315 char optbuf[MAXLINE];
2319 ** If there is status waiting from the other end, read it.
2320 ** This should normally happen because of SMTP pipelining.
2323 while (mci->mci_nextaddr != NULL &&
2324 sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2328 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2331 markfailure(e, mci->mci_nextaddr, mci, r, false);
2332 giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
2333 ctladdr, xstart, e, to);
2335 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2337 #endif /* PIPELINING */
2340 ** Check if connection is gone, if so
2341 ** it's a tempfail and we use mci_errno
2345 if (mci->mci_state == MCIS_CLOSED)
2347 errno = mci->mci_errno;
2355 ** Warning: in the following it is assumed that the free space
2356 ** in bufp is sizeof(optbuf)
2359 if (bitset(MCIF_DSN, mci->mci_flags))
2361 if (IS_DLVR_NOTIFY(e) &&
2362 !bitset(MCIF_DLVR_BY, mci->mci_flags))
2364 /* RFC 2852: 4.1.4.2 */
2365 if (!bitset(QHASNOTIFY, to->q_flags))
2366 to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
2367 else if (bitset(QPINGONSUCCESS, to->q_flags) ||
2368 bitset(QPINGONFAILURE, to->q_flags) ||
2369 bitset(QPINGONDELAY, to->q_flags))
2370 to->q_flags |= QPINGONDELAY;
2373 /* NOTIFY= parameter */
2374 if (bitset(QHASNOTIFY, to->q_flags) &&
2375 bitset(QPRIMARY, to->q_flags) &&
2376 !bitnset(M_LOCALMAILER, m->m_flags))
2378 bool firstone = true;
2380 (void) sm_strlcat(bufp, " NOTIFY=", sizeof(optbuf));
2381 if (bitset(QPINGONSUCCESS, to->q_flags))
2383 (void) sm_strlcat(bufp, "SUCCESS", sizeof(optbuf));
2386 if (bitset(QPINGONFAILURE, to->q_flags))
2389 (void) sm_strlcat(bufp, ",",
2391 (void) sm_strlcat(bufp, "FAILURE", sizeof(optbuf));
2394 if (bitset(QPINGONDELAY, to->q_flags))
2397 (void) sm_strlcat(bufp, ",",
2399 (void) sm_strlcat(bufp, "DELAY", sizeof(optbuf));
2403 (void) sm_strlcat(bufp, "NEVER", sizeof(optbuf));
2404 bufp += strlen(bufp);
2407 /* ORCPT= parameter */
2408 if (to->q_orcpt != NULL &&
2409 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
2411 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2412 " ORCPT=%s", to->q_orcpt);
2413 bufp += strlen(bufp);
2417 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
2418 mci->mci_state = MCIS_RCPT;
2420 SmtpPhase = mci->mci_phase = "client RCPT";
2421 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2422 CurHostName, mci->mci_phase);
2426 ** If running SMTP pipelining, we will pick up status later
2429 if (bitset(MCIF_PIPELINED, mci->mci_flags))
2431 #endif /* PIPELINING */
2433 return smtprcptstat(to, m, mci, e);
2436 ** SMTPRCPTSTAT -- get recipient status
2438 ** This is only called during SMTP pipelining
2441 ** to -- address of recipient.
2442 ** m -- mailer being sent to.
2443 ** mci -- the mailer connection information.
2444 ** e -- the envelope for this message.
2447 ** EX_* -- protocol status
2451 smtprcptstat(to, m, mci, e)
2455 register ENVELOPE *e;
2462 ** Check if connection is gone, if so
2463 ** it's a tempfail and we use mci_errno
2467 if (mci->mci_state == MCIS_CLOSED)
2469 errno = mci->mci_errno;
2474 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT);
2476 to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
2477 to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
2478 if (!bitnset(M_LMTP, m->m_flags))
2479 to->q_statmta = mci->mci_host;
2480 if (r < 0 || REPLYTYPE(r) == 4)
2482 mci->mci_retryrcpt = true;
2486 else if (REPLYTYPE(r) == 2)
2490 if ((t = mci->mci_tolist) != NULL)
2495 for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
2498 mci->mci_tolist = t;
2507 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
2512 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
2517 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
2520 else if (REPLYTYPE(r) == 5)
2522 return EX_UNAVAILABLE;
2527 sm_syslog(LOG_CRIT, e->e_id,
2528 "%.100s: SMTP RCPT protocol error: %s",
2530 shortenstring(SmtpReplyBuffer, 403));
2533 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2538 ** SMTPDATA -- send the data and clean up the transaction.
2541 ** m -- mailer being sent to.
2542 ** mci -- the mailer connection information.
2543 ** e -- the envelope for this message.
2546 ** exit status corresponding to DATA command.
2550 smtpdata(m, mci, e, ctladdr, xstart)
2553 register ENVELOPE *e;
2564 ** Check if connection is gone, if so
2565 ** it's a tempfail and we use mci_errno
2569 if (mci->mci_state == MCIS_CLOSED)
2571 errno = mci->mci_errno;
2579 ** First send the command and check that it is ok.
2580 ** Then send the data (if there are valid recipients).
2581 ** Follow it up with a dot to terminate.
2582 ** Finally get the results of the transaction.
2585 /* send the command and check ok to proceed */
2586 smtpmessage("DATA", m, mci);
2589 if (mci->mci_nextaddr != NULL)
2591 char *oldto = e->e_to;
2593 /* pick up any pending RCPT responses for SMTP pipelining */
2594 while (mci->mci_nextaddr != NULL)
2596 e->e_to = mci->mci_nextaddr->q_paddr;
2597 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2600 markfailure(e, mci->mci_nextaddr, mci, r,
2602 giveresponse(r, mci->mci_nextaddr->q_status, m,
2603 mci, ctladdr, xstart, e,
2605 if (r == EX_TEMPFAIL)
2606 mci->mci_nextaddr->q_state = QS_RETRY;
2608 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2613 ** Connection might be closed in response to a RCPT command,
2614 ** i.e., the server responded with 421. In that case (at
2615 ** least) one RCPT has a temporary failure, hence we don't
2616 ** need to check mci_okrcpts (as it is done below) to figure
2617 ** out which error to return.
2620 if (mci->mci_state == MCIS_CLOSED)
2622 errno = mci->mci_errno;
2626 #endif /* PIPELINING */
2628 /* now proceed with DATA phase */
2629 SmtpPhase = mci->mci_phase = "client DATA 354";
2630 mci->mci_state = MCIS_DATA;
2631 sm_setproctitle(true, e, "%s %s: %s",
2632 qid_printname(e), CurHostName, mci->mci_phase);
2633 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA);
2634 if (r < 0 || REPLYTYPE(r) == 4)
2637 smtpquit(m, mci, e);
2638 errno = mci->mci_errno;
2641 else if (REPLYTYPE(r) == 5)
2643 smtprset(m, mci, e);
2645 if (mci->mci_okrcpts <= 0)
2646 return mci->mci_retryrcpt ? EX_TEMPFAIL
2649 return EX_UNAVAILABLE;
2651 else if (REPLYTYPE(r) != 3)
2655 sm_syslog(LOG_CRIT, e->e_id,
2656 "%.100s: SMTP DATA-1 protocol error: %s",
2658 shortenstring(SmtpReplyBuffer, 403));
2660 smtprset(m, mci, e);
2661 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2664 if (mci->mci_okrcpts <= 0)
2665 return mci->mci_retryrcpt ? EX_TEMPFAIL
2672 if (mci->mci_okrcpts > 0)
2677 ** Set timeout around data writes. Make it at least large
2678 ** enough for DNS timeouts on all recipients plus some fudge
2679 ** factor. The main thing is that it should not be infinite.
2684 /* simulate a DATA timeout */
2688 timeout = DATA_PROGRESS_TIMEOUT * 1000;
2689 sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
2693 ** Output the actual message.
2696 if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
2701 /* simulate a DATA timeout */
2705 if (!(*e->e_putbody)(mci, e, NULL))
2709 ** Cleanup after sending message.
2717 #if _FFR_CATCH_BROKEN_MTAS
2718 if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2720 /* terminate the message */
2721 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
2723 if (TrafficLogFile != NULL)
2724 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2725 "%05d >>> .\n", (int) CurrentPid);
2729 sm_syslog(LOG_CRIT, e->e_id,
2730 "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
2732 mci->mci_errno = EIO;
2733 mci->mci_state = MCIS_ERROR;
2734 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
2735 smtpquit(m, mci, e);
2738 #endif /* _FFR_CATCH_BROKEN_MTAS */
2740 if (sm_io_error(mci->mci_out))
2742 /* error during processing -- don't send the dot */
2743 mci->mci_errno = EIO;
2744 mci->mci_state = MCIS_ERROR;
2745 mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
2746 smtpquit(m, mci, e);
2750 /* terminate the message */
2751 if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s.%s",
2752 bitset(MCIF_INLONGLINE, mci->mci_flags) ? m->m_eol : "",
2753 m->m_eol) == SM_IO_EOF)
2755 if (TrafficLogFile != NULL)
2756 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2757 "%05d >>> .\n", (int) CurrentPid);
2761 /* check for the results of the transaction */
2762 SmtpPhase = mci->mci_phase = "client DATA status";
2763 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2764 CurHostName, mci->mci_phase);
2765 if (bitnset(M_LMTP, m->m_flags))
2767 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM);
2770 if (mci->mci_state == MCIS_DATA)
2771 mci->mci_state = MCIS_OPEN;
2772 xstat = EX_NOTSTICKY;
2774 rstat = EX_TEMPFAIL;
2775 else if (REPLYTYPE(r) == 4)
2776 rstat = xstat = EX_TEMPFAIL;
2777 else if (REPLYTYPE(r) == 2)
2778 rstat = xstat = EX_OK;
2779 else if (REPLYCLASS(r) != 5)
2780 rstat = xstat = EX_PROTOCOL;
2781 else if (REPLYTYPE(r) == 5)
2782 rstat = EX_UNAVAILABLE;
2784 rstat = EX_PROTOCOL;
2785 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
2787 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2788 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2792 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
2793 SmtpPhase = mci->mci_phase = "idle";
2794 sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
2795 if (rstat != EX_PROTOCOL)
2799 sm_syslog(LOG_CRIT, e->e_id,
2800 "%.100s: SMTP DATA-2 protocol error: %s",
2802 shortenstring(SmtpReplyBuffer, 403));
2807 mci->mci_errno = errno;
2808 mci->mci_state = MCIS_ERROR;
2809 mci_setstat(mci, bitset(MCIF_NOTSTICKY, mci->mci_flags)
2810 ? EX_NOTSTICKY: EX_TEMPFAIL,
2812 mci->mci_flags &= ~MCIF_NOTSTICKY;
2815 ** If putbody() couldn't finish due to a timeout,
2816 ** rewind it here in the timeout handler. See
2817 ** comments at the end of putbody() for reasoning.
2820 if (e->e_dfp != NULL)
2821 (void) bfrewind(e->e_dfp);
2823 errno = mci->mci_errno;
2824 syserr("+451 4.4.1 timeout writing message to %s", CurHostName);
2825 smtpquit(m, mci, e);
2830 ** SMTPGETSTAT -- get status code from DATA in LMTP
2833 ** m -- the mailer to which we are sending the message.
2834 ** mci -- the mailer connection structure.
2835 ** e -- the current envelope.
2838 ** The exit status corresponding to the reply code.
2842 smtpgetstat(m, mci, e)
2854 /* check for the results of the transaction */
2855 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2);
2858 xstat = EX_NOTSTICKY;
2859 if (REPLYTYPE(r) == 4)
2860 status = EX_TEMPFAIL;
2861 else if (REPLYTYPE(r) == 2)
2862 status = xstat = EX_OK;
2863 else if (REPLYCLASS(r) != 5)
2864 status = xstat = EX_PROTOCOL;
2865 else if (REPLYTYPE(r) == 5)
2866 status = EX_UNAVAILABLE;
2868 status = EX_PROTOCOL;
2869 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2870 (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2874 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]);
2875 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer);
2876 if (LogLevel > 1 && status == EX_PROTOCOL)
2878 sm_syslog(LOG_CRIT, e->e_id,
2879 "%.100s: SMTP DATA-3 protocol error: %s",
2881 shortenstring(SmtpReplyBuffer, 403));
2886 ** SMTPQUIT -- close the SMTP connection.
2889 ** m -- a pointer to the mailer.
2890 ** mci -- the mailer connection information.
2891 ** e -- the current envelope.
2897 ** sends the final protocol and closes the connection.
2906 bool oldSuprErrs = SuprErrs;
2910 if (mci->mci_state == MCIS_CLOSED)
2912 mci_close(mci, "smtpquit:1");
2916 oldcurhost = CurHostName;
2917 CurHostName = mci->mci_host; /* XXX UGLY XXX */
2918 if (CurHostName == NULL)
2919 CurHostName = MyHostName;
2922 mci->mci_okrcpts = 0;
2926 ** Suppress errors here -- we may be processing a different
2927 ** job when we do the quit connection, and we don't want the
2928 ** new job to be penalized for something that isn't it's
2934 /* send the quit message if we haven't gotten I/O error */
2935 if (mci->mci_state != MCIS_ERROR &&
2936 mci->mci_state != MCIS_QUITING)
2938 SmtpPhase = "client QUIT";
2939 mci->mci_state = MCIS_QUITING;
2940 smtpmessage("QUIT", m, mci);
2941 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT);
2942 SuprErrs = oldSuprErrs;
2943 if (mci->mci_state == MCIS_CLOSED)
2947 /* now actually close the connection and pick up the zombie */
2948 rcode = endmailer(mci, e, NULL);
2951 char *mailer = NULL;
2953 if (mci->mci_mailer != NULL &&
2954 mci->mci_mailer->m_name != NULL)
2955 mailer = mci->mci_mailer->m_name;
2957 /* look for naughty mailers */
2958 sm_syslog(LOG_ERR, e->e_id,
2959 "smtpquit: mailer%s%s exited with exit value %d",
2960 mailer == NULL ? "" : " ",
2961 mailer == NULL ? "" : mailer,
2965 SuprErrs = oldSuprErrs;
2968 CurHostName = oldcurhost;
2972 ** SMTPRSET -- send a RSET (reset) command
2975 ** m -- a pointer to the mailer.
2976 ** mci -- the mailer connection information.
2977 ** e -- the current envelope.
2983 ** closes the connection if there is no reply to RSET.
2994 CurHostName = mci->mci_host; /* XXX UGLY XXX */
2995 if (CurHostName == NULL)
2996 CurHostName = MyHostName;
2999 mci->mci_okrcpts = 0;
3003 ** Check if connection is gone, if so
3004 ** it's a tempfail and we use mci_errno
3008 if (mci->mci_state == MCIS_CLOSED)
3010 errno = mci->mci_errno;
3014 SmtpPhase = "client RSET";
3015 smtpmessage("RSET", m, mci);
3016 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT);
3021 ** Any response is deemed to be acceptable.
3022 ** The standard does not state the proper action
3023 ** to take when a value other than 250 is received.
3025 ** However, if 421 is returned for the RSET, leave
3026 ** mci_state alone (MCIS_SSD can be set in reply()
3027 ** and MCIS_CLOSED can be set in smtpquit() if
3028 ** reply() gets a 421 and calls smtpquit()).
3031 if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED)
3032 mci->mci_state = MCIS_OPEN;
3033 else if (mci->mci_exitstat == EX_OK)
3034 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL);
3037 ** SMTPPROBE -- check the connection state
3040 ** mci -- the mailer connection information.
3046 ** closes the connection if there is no reply to RSET.
3054 MAILER *m = mci->mci_mailer;
3056 extern ENVELOPE BlankEnvelope;
3058 CurHostName = mci->mci_host; /* XXX UGLY XXX */
3059 if (CurHostName == NULL)
3060 CurHostName = MyHostName;
3063 SmtpPhase = "client probe";
3064 smtpmessage("RSET", m, mci);
3065 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT);
3066 if (REPLYTYPE(r) != 2)
3067 smtpquit(m, mci, e);
3071 ** REPLY -- read arpanet reply
3074 ** m -- the mailer we are reading the reply from.
3075 ** mci -- the mailer connection info structure.
3076 ** e -- the current envelope.
3077 ** timeout -- the timeout for reads.
3078 ** pfunc -- processing function called on each line of response.
3079 ** If null, no special processing is done.
3080 ** enhstat -- optional, returns enhanced error code string (if set)
3081 ** rtype -- type of SmtpMsgBuffer: does it contains secret data?
3084 ** reply code it reads.
3087 ** flushes the mail file.
3091 reply(m, mci, e, timeout, pfunc, enhstat, rtype)
3096 void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
3100 register char *bufp;
3102 bool firstline = true;
3103 char junkbuf[MAXLINE];
3104 static char enhstatcode[ENHSCLEN];
3108 ** Flush the output before reading response.
3110 ** For SMTP pipelining, it would be better if we didn't do
3111 ** this if there was already data waiting to be read. But
3112 ** to do it properly means pushing it to the I/O library,
3113 ** since it really needs to be done below the buffer layer.
3116 if (mci->mci_out != NULL)
3117 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3123 if (SmtpMsgBuffer[0] != '\0')
3124 what = SmtpMsgBuffer;
3125 else if (SmtpPhase != NULL && SmtpPhase[0] != '\0')
3127 else if (XS_GREET == rtype)
3131 sm_dprintf("reply to %s\n", what);
3135 ** Read the input line, being careful not to hang.
3138 bufp = SmtpReplyBuffer;
3139 (void) set_tls_rd_tmo(timeout);
3144 /* actually do the read */
3145 if (e->e_xfp != NULL) /* for debugging */
3146 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
3148 /* if we are in the process of closing just give the code */
3149 if (mci->mci_state == MCIS_CLOSED)
3152 /* don't try to read from a non-existent fd */
3153 if (mci->mci_in == NULL)
3155 if (mci->mci_errno == 0)
3156 mci->mci_errno = EBADF;
3158 /* errors on QUIT should be ignored */
3159 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3161 errno = mci->mci_errno;
3162 mci_close(mci, "reply:1");
3165 mci->mci_state = MCIS_ERROR;
3166 smtpquit(m, mci, e);
3167 errno = mci->mci_errno;
3171 if (mci->mci_out != NULL)
3172 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3174 /* get the line from the other side */
3175 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
3177 mci->mci_lastuse = curtime();
3182 extern char MsgBuf[];
3184 /* errors on QUIT should be ignored */
3185 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3187 mci_close(mci, "reply:2");
3191 /* if the remote end closed early, fake an error */
3195 (void) sm_snprintf(SmtpReplyBuffer,
3196 sizeof(SmtpReplyBuffer),
3197 "421 4.4.1 Connection reset by %s",
3206 mci->mci_errno = errno;
3207 oldholderrs = HoldErrs;
3209 usrerr("451 4.4.1 reply: read error from %s",
3211 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
3213 /* if debugging, pause so we can see state */
3216 mci->mci_state = MCIS_ERROR;
3217 smtpquit(m, mci, e);
3223 if (e->e_to != NULL)
3225 (void) sm_snprintf(p,
3228 shortenstring(e->e_to, MAXSHORTSTR));
3231 (void) sm_snprintf(p, SPACELEFT(wbuf, p),
3232 "reply(%.100s) during %s",
3233 CURHOSTNAME, SmtpPhase);
3237 HoldErrs = oldholderrs;
3241 fixcrlf(bufp, true);
3243 /* EHLO failure is not a real error */
3244 if (e->e_xfp != NULL && (bufp[0] == '4' ||
3245 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
3247 /* serious error -- log the previous command */
3250 /* inform user who we are chatting with */
3251 (void) sm_io_fprintf(CurEnv->e_xfp,
3253 "... while talking to %s:\n",
3255 SmtpNeedIntro = false;
3257 if (SmtpMsgBuffer[0] != '\0')
3259 (void) sm_io_fprintf(e->e_xfp,
3262 (rtype == XS_STARTTLS)
3263 ? "STARTTLS dialogue"
3264 : ((rtype == XS_AUTH)
3267 SmtpMsgBuffer[0] = '\0';
3270 /* now log the message as from the other side */
3271 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
3275 /* display the input for verbose mode */
3277 nmessage("050 %s", bufp);
3279 /* ignore improperly formatted input */
3280 if (!ISSMTPREPLY(bufp))
3283 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
3285 extenhsc(bufp + 4, ' ', enhstatcode) > 0)
3286 *enhstat = enhstatcode;
3288 /* process the line */
3290 (*pfunc)(bufp, firstline, m, mci, e);
3292 /* decode the reply code */
3295 /* extra semantics: 0xx codes are "informational" */
3301 if (REPLYTYPE(r) > 3 && firstline
3304 (e->e_sendmode != SM_PROXY
3305 || (e->e_sendmode == SM_PROXY
3306 && (e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5))
3314 ** ignore error iff: DATA, 5xy error, but we had
3315 ** "retryable" recipients. XREF: smtpdata()
3318 if (!(rtype == XS_DATA && REPLYTYPE(r) == 5 &&
3319 mci->mci_okrcpts <= 0 && mci->mci_retryrcpt))
3320 # endif /* PIPELINING */
3322 o = extenhsc(bufp + 4, ' ', enhstatcode);
3325 sm_strlcpy(e->e_renhsc, enhstatcode,
3326 sizeof(e->e_renhsc));
3328 /* skip SMTP reply code, delimiters */
3335 ** Don't use this for reply= logging
3336 ** if it was for QUIT.
3337 ** (Note: use the debug option to
3338 ** reproduce the original error.)
3341 if (rtype != XS_QUIT || tTd(87, 101))
3344 e->e_text = sm_rpool_strdup_x(
3345 e->e_rpool, bufp + o);
3350 sm_dprintf("user: e=%p, offset=%d, bufp=%s, rcode=%d, enhstat=%s, rtype=%d, text=%s\n"
3351 , (void *)e, o, bufp, r, e->e_renhsc
3352 , rtype, e->e_text);
3358 /* if no continuation lines, return this line */
3362 /* first line of real reply -- ignore rest */
3367 ** Now look at SmtpReplyBuffer -- only care about the first
3368 ** line of the response from here on out.
3371 /* save temporary failure messages for posterity */
3372 if (SmtpReplyBuffer[0] == '4')
3373 (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof(SmtpError));
3375 /* reply code 421 is "Service Shutting Down" */
3376 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
3377 mci->mci_state != MCIS_QUITING)
3379 /* send the quit protocol */
3380 mci->mci_state = MCIS_SSD;
3381 smtpquit(m, mci, e);
3387 ** SMTPMESSAGE -- send message to server
3391 ** m -- the mailer to control formatting.
3392 ** a, b, c -- parameters
3398 ** writes message to mci->mci_out.
3404 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
3405 #else /* __STDC__ */
3406 smtpmessage(f, m, mci, va_alist)
3411 #endif /* __STDC__ */
3415 SM_VA_START(ap, mci);
3416 (void) sm_vsnprintf(SmtpMsgBuffer, sizeof(SmtpMsgBuffer), f, ap);
3419 if (tTd(18, 1) || Verbose)
3420 nmessage(">>> %s", SmtpMsgBuffer);
3421 if (TrafficLogFile != NULL)
3422 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
3423 "%05d >>> %s\n", (int) CurrentPid,
3425 if (mci->mci_out != NULL)
3427 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
3428 SmtpMsgBuffer, m == NULL ? "\r\n"
3431 else if (tTd(18, 1))
3433 sm_dprintf("smtpmessage: NULL mci_out\n");