2 * Copyright (c) 1998-2006 Sendmail, 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.467 2006/03/19 06:07:56 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 REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
37 #define SMTPCLOSING 421 /* "Service Shutting Down" */
39 #define ENHSCN(e, d) ((e) == NULL ? (d) : (e))
41 #define ENHSCN_RPOOL(e, d, rpool) \
42 ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
44 static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
45 static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
46 static bool SmtpNeedIntro; /* need "while talking" in transcript */
48 ** SMTPINIT -- initialize SMTP.
50 ** Opens the connection and sends the initial protocol.
53 ** m -- mailer to create connection to.
54 ** mci -- the mailer connection info.
56 ** onlyhelo -- send only helo command?
62 ** creates connection and sends initial protocol.
66 smtpinit(m, mci, e, onlyhelo)
81 sm_dprintf("smtpinit ");
82 mci_dump(sm_debug_file(), mci, false);
86 ** Open the connection to the mailer.
90 SmtpMsgBuffer[0] = '\0';
91 CurHostName = mci->mci_host; /* XXX UGLY XXX */
92 if (CurHostName == NULL)
93 CurHostName = MyHostName;
95 state = mci->mci_state;
101 /* need to clear old information */
113 /* shouldn't happen */
118 syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
127 mci->mci_state = MCIS_OPENING;
131 ** Get the greeting message.
132 ** This should appear spontaneously. Give it five minutes to
136 SmtpPhase = mci->mci_phase = "client greeting";
137 sm_setproctitle(true, e, "%s %s: %s",
138 qid_printname(e), CurHostName, mci->mci_phase);
139 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL,
143 if (REPLYTYPE(r) == 4)
145 if (REPLYTYPE(r) != 2)
149 ** Send the HELO command.
150 ** My mother taught me to always introduce myself.
154 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
155 mci->mci_flags |= MCIF_ESMTP;
156 hn = mci->mci_heloname ? mci->mci_heloname : MyHostName;
159 #if _FFR_IGNORE_EXT_ON_HELO
160 mci->mci_flags &= ~MCIF_HELO;
161 #endif /* _FFR_IGNORE_EXT_ON_HELO */
162 if (bitnset(M_LMTP, m->m_flags))
164 smtpmessage("LHLO %s", m, mci, hn);
165 SmtpPhase = mci->mci_phase = "client LHLO";
167 else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
168 !bitnset(M_FSMTP, m->m_flags))
170 smtpmessage("EHLO %s", m, mci, hn);
171 SmtpPhase = mci->mci_phase = "client EHLO";
175 smtpmessage("HELO %s", m, mci, hn);
176 SmtpPhase = mci->mci_phase = "client HELO";
177 #if _FFR_IGNORE_EXT_ON_HELO
178 mci->mci_flags |= MCIF_HELO;
179 #endif /* _FFR_IGNORE_EXT_ON_HELO */
181 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
182 CurHostName, mci->mci_phase);
184 bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
186 helo_options, NULL, XS_DEFAULT);
189 else if (REPLYTYPE(r) == 5)
191 if (bitset(MCIF_ESMTP, mci->mci_flags) &&
192 !bitnset(M_LMTP, m->m_flags))
194 /* try old SMTP instead */
195 mci->mci_flags &= ~MCIF_ESMTP;
200 else if (REPLYTYPE(r) != 2)
204 ** Check to see if we actually ended up talking to ourself.
205 ** This means we didn't know about an alias or MX, or we managed
206 ** to connect to an echo server.
209 p = strchr(&SmtpReplyBuffer[4], ' ');
212 if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
213 !bitnset(M_LMTP, m->m_flags) &&
214 sm_strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
216 syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
218 mci_setstat(mci, EX_CONFIG, "5.3.5",
219 "553 5.3.5 system config error");
226 ** If this is expected to be another sendmail, send some internal
228 ** If we're running as MSP, "propagate" -v flag if possible.
231 if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags))
232 # if !_FFR_DEPRECATE_MAILER_FLAG_I
233 || bitnset(M_INTERNAL, m->m_flags)
234 # endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */
237 /* tell it to be verbose */
238 smtpmessage("VERB", m, mci);
239 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
245 if (mci->mci_state != MCIS_CLOSED)
247 mci->mci_state = MCIS_OPEN;
251 /* got a 421 error code during startup */
254 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
255 if (mci->mci_state != MCIS_CLOSED)
260 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
261 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
263 if (mci->mci_state != MCIS_CLOSED)
268 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
273 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
276 ** line -- the response line.
277 ** firstline -- set if this is the first line of the reply.
279 ** mci -- the mailer connection info.
280 ** e -- the envelope.
287 esmtp_check(line, firstline, m, mci, e)
294 if (strstr(line, "ESMTP") != NULL)
295 mci->mci_flags |= MCIF_ESMTP;
298 ** Dirty hack below. Quoting the author:
299 ** This was a response to people who wanted SMTP transmission to be
300 ** just-send-8 by default. Essentially, you could put this tag into
301 ** your greeting message to behave as though the F=8 flag was set on
305 if (strstr(line, "8BIT-OK") != NULL)
306 mci->mci_flags |= MCIF_8BITOK;
310 /* specify prototype so compiler can check calls */
311 static char *str_union __P((char *, char *, SM_RPOOL_T *));
314 ** STR_UNION -- create the union of two lists
317 ** s1, s2 -- lists of items (separated by single blanks).
318 ** rpool -- resource pool from which result is allocated.
321 ** the union of both lists.
325 str_union(s1, s2, rpool)
329 char *hr, *h1, *h, *res;
332 if (s1 == NULL || *s1 == '\0')
334 if (s2 == NULL || *s2 == '\0')
339 res = (char *) sm_rpool_malloc(rpool, rl + 2);
346 (void) sm_strlcpy(res, s1, rl);
351 /* walk through s2 */
352 while (h != NULL && *h1 != '\0')
354 /* is there something after the current word? */
355 if ((h = strchr(h1, ' ')) != NULL)
359 /* does the current word appear in s1 ? */
360 if (iteminlist(h1, s1, " ") == NULL)
362 /* add space as delimiter */
368 /* advance pointer in result list */
374 /* there are more items */
384 ** HELO_OPTIONS -- process the options on a HELO line.
387 ** line -- the response line.
388 ** firstline -- set if this is the first line of the reply.
390 ** mci -- the mailer connection info.
391 ** e -- the envelope (unused).
398 helo_options(line, firstline, m, mci, e)
406 #if _FFR_IGNORE_EXT_ON_HELO
407 static bool logged = false;
408 #endif /* _FFR_IGNORE_EXT_ON_HELO */
413 mci->mci_saslcap = NULL;
415 #if _FFR_IGNORE_EXT_ON_HELO
417 #endif /* _FFR_IGNORE_EXT_ON_HELO */
420 #if _FFR_IGNORE_EXT_ON_HELO
421 else if (bitset(MCIF_HELO, mci->mci_flags))
423 if (LogLevel > 8 && !logged)
425 sm_syslog(LOG_WARNING, NOQID,
426 "server=%s [%s] returned extensions despite HELO command",
427 macvalue(macid("{server_name}"), e),
428 macvalue(macid("{server_addr}"), e));
433 #endif /* _FFR_IGNORE_EXT_ON_HELO */
435 if (strlen(line) < 5)
438 p = strpbrk(line, " =");
441 if (sm_strcasecmp(line, "size") == 0)
443 mci->mci_flags |= MCIF_SIZE;
445 mci->mci_maxsize = atol(p);
447 else if (sm_strcasecmp(line, "8bitmime") == 0)
449 mci->mci_flags |= MCIF_8BITMIME;
450 mci->mci_flags &= ~MCIF_7BIT;
452 else if (sm_strcasecmp(line, "expn") == 0)
453 mci->mci_flags |= MCIF_EXPN;
454 else if (sm_strcasecmp(line, "dsn") == 0)
455 mci->mci_flags |= MCIF_DSN;
456 else if (sm_strcasecmp(line, "enhancedstatuscodes") == 0)
457 mci->mci_flags |= MCIF_ENHSTAT;
458 else if (sm_strcasecmp(line, "pipelining") == 0)
459 mci->mci_flags |= MCIF_PIPELINED;
460 else if (sm_strcasecmp(line, "verb") == 0)
461 mci->mci_flags |= MCIF_VERB;
463 else if (sm_strcasecmp(line, "starttls") == 0)
464 mci->mci_flags |= MCIF_TLS;
465 #endif /* STARTTLS */
466 else if (sm_strcasecmp(line, "deliverby") == 0)
468 mci->mci_flags |= MCIF_DLVR_BY;
470 mci->mci_min_by = atol(p);
473 else if (sm_strcasecmp(line, "auth") == 0)
475 if (p != NULL && *p != '\0')
477 if (mci->mci_saslcap != NULL)
480 ** Create the union with previous auth
481 ** offerings because we recognize "auth "
482 ** and "auth=" (old format).
485 mci->mci_saslcap = str_union(mci->mci_saslcap,
487 mci->mci_flags |= MCIF_AUTH;
494 mci->mci_saslcap = (char *)
495 sm_rpool_malloc(mci->mci_rpool, l);
496 if (mci->mci_saslcap != NULL)
498 (void) sm_strlcpy(mci->mci_saslcap, p,
500 mci->mci_flags |= MCIF_AUTH;
509 static int getsimple __P((void *, int, const char **, unsigned *));
510 static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
511 static int saslgetrealm __P((void *, int, const char **, const char **));
512 static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
513 static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *));
514 static char *removemech __P((char *, char *, SM_RPOOL_T *));
515 static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
517 static sasl_callback_t callbacks[] =
519 { SASL_CB_GETREALM, &saslgetrealm, NULL },
520 #define CB_GETREALM_IDX 0
521 { SASL_CB_PASS, &getsecret, NULL },
522 #define CB_PASS_IDX 1
523 { SASL_CB_USER, &getsimple, NULL },
524 #define CB_USER_IDX 2
525 { SASL_CB_AUTHNAME, &getsimple, NULL },
526 #define CB_AUTHNAME_IDX 3
527 { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
528 #define CB_SAFESASL_IDX 4
529 { SASL_CB_LIST_END, NULL, NULL }
533 ** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
539 ** SASL_OK -- if successful.
540 ** SASL error code -- otherwise.
543 ** checks/sets sasl_clt_init.
546 static bool sasl_clt_init = false;
555 result = sasl_client_init(callbacks);
557 /* should we retry later again or just remember that it failed? */
558 if (result == SASL_OK)
559 sasl_clt_init = true;
563 ** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
572 ** checks/sets sasl_clt_init.
580 sasl_clt_init = false;
584 ** GETSASLDATA -- process the challenges from the SASL protocol
586 ** This gets the relevant sasl response data out of the reply
590 ** line -- the response line.
591 ** firstline -- set if this is the first line of the reply.
593 ** mci -- the mailer connection info.
594 ** e -- the envelope (unused).
600 static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
603 getsasldata(line, firstline, m, mci, e)
614 # endif /* SASL < 20000 */
616 /* if not a continue we don't care about it */
620 !isascii(line[1]) || !isdigit(line[1]) ||
621 !isascii(line[2]) || !isdigit(line[2]))
623 SM_FREE_CLR(mci->mci_sasl_string);
627 /* forget about "334 " */
631 /* XXX put this into a macro/function? It's duplicated below */
632 if (mci->mci_sasl_string != NULL)
634 if (mci->mci_sasl_string_len <= len)
636 sm_free(mci->mci_sasl_string); /* XXX */
637 mci->mci_sasl_string = xalloc(len + 1);
641 mci->mci_sasl_string = xalloc(len + 1);
643 result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
644 (unsigned int *) &mci->mci_sasl_string_len);
645 if (result != SASL_OK)
647 mci->mci_sasl_string_len = 0;
648 *mci->mci_sasl_string = '\0';
650 # else /* SASL >= 20000 */
651 out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
652 result = sasl_decode64(line, len, out, (unsigned int *) &len);
653 if (result != SASL_OK)
660 ** mci_sasl_string is "shared" with Cyrus-SASL library; hence
661 ** it can't be in an rpool unless we use the same memory
662 ** management mechanism (with same rpool!) for Cyrus SASL.
665 if (mci->mci_sasl_string != NULL)
667 if (mci->mci_sasl_string_len <= len)
669 sm_free(mci->mci_sasl_string); /* XXX */
670 mci->mci_sasl_string = xalloc(len + 1);
674 mci->mci_sasl_string = xalloc(len + 1);
676 memcpy(mci->mci_sasl_string, out, len);
677 mci->mci_sasl_string[len] = '\0';
678 mci->mci_sasl_string_len = len;
679 # endif /* SASL >= 20000 */
683 ** READAUTH -- read auth values from a file
686 ** filename -- name of file to read.
687 ** safe -- if set, this is a safe read.
688 ** sai -- where to store auth_info.
689 ** rpool -- resource pool for sai.
692 ** EX_OK -- data succesfully read.
693 ** EX_UNAVAILABLE -- no valid filename.
694 ** EX_TEMPFAIL -- temporary failure.
697 static char *sasl_info_name[] =
706 readauth(filename, safe, sai, rpool)
719 if (filename == NULL || filename[0] == '\0')
720 return EX_UNAVAILABLE;
722 #if !_FFR_ALLOW_SASLINFO
724 ** make sure we don't use a program that is not
725 ** accesible to the user who specified a different authinfo file.
726 ** However, currently we don't pass this info (authinfo file
727 ** specified by user) around, so we just turn off program access.
730 if (filename[0] == '|')
735 char *argv[MAXPV + 1];
738 for (p = strtok(&filename[1], " \t"); p != NULL;
739 p = strtok(NULL, " \t"))
746 pid = prog_open(argv, &fd, CurEnv);
750 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
751 (void *) &fd, SM_IO_RDONLY, NULL);
754 #endif /* !_FFR_ALLOW_SASLINFO */
757 sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
758 |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
759 # if _FFR_GROUPREADABLEAUTHINFOFILE
760 if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
761 # endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
762 sff |= SFF_NOGRFILES;
763 if (DontLockReadFiles)
766 #if _FFR_ALLOW_SASLINFO
768 ** XXX: make sure we don't read or open files that are not
769 ** accesible to the user who specified a different authinfo
774 #else /* _FFR_ALLOW_SASLINFO */
776 sff |= SFF_OPENASROOT;
777 #endif /* _FFR_ALLOW_SASLINFO */
779 f = safefopen(filename, O_RDONLY, 0, sff);
784 sm_syslog(LOG_ERR, NOQID,
785 "AUTH=client, error: can't open %s: %s",
786 filename, sm_errstring(errno));
791 while (lc <= SASL_MECHLIST &&
792 sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
796 (*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
797 if ((s = strchr((*sai)[lc], '\n')) != NULL)
803 (void) sm_io_close(f, SM_TIME_DEFAULT);
806 if (lc < SASL_PASSWORD)
809 sm_syslog(LOG_ERR, NOQID,
810 "AUTH=client, error: can't read %s from %s",
811 sasl_info_name[lc + 1], filename);
818 ** GETAUTH -- get authinfo from ruleset call
820 ** {server_name}, {server_addr} must be set
823 ** mci -- the mailer connection structure.
824 ** e -- the envelope (including the sender to specify).
825 ** sai -- pointer to authinfo (result).
828 ** EX_OK -- ruleset was succesfully called, data may not
829 ** be available, sai must be checked.
830 ** EX_UNAVAILABLE -- ruleset unavailable (or failed).
831 ** EX_TEMPFAIL -- temporary failure (from ruleset).
834 ** Fills in sai if successful.
843 int i, r, l, got, ret;
845 char pvpbuf[PSBUFSIZE];
847 r = rscap("authinfo", macvalue(macid("{server_name}"), e),
848 macvalue(macid("{server_addr}"), e), e,
849 &pvp, pvpbuf, sizeof(pvpbuf));
852 return EX_UNAVAILABLE;
854 /* other than expected return value: ok (i.e., no auth) */
855 if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
857 if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
861 ** parse the data, put it into sai
862 ** format: "TDstring" (including the '"' !)
863 ** where T is a tag: 'U', ...
864 ** D is a delimiter: ':' or '='
867 ret = EX_OK; /* default return value */
870 while (i < SASL_ENTRIES)
872 if (pvp[i + 1] == NULL)
874 if (pvp[i + 1][0] != '"')
876 switch (pvp[i + 1][1])
901 l = strlen(pvp[i + 1]);
904 if (l <= 3 || pvp[i + 1][l - 1] != '"')
907 /* remove closing quote */
908 pvp[i + 1][l - 1] = '\0';
910 /* remove "TD and " */
912 (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
913 if ((*sai)[r] == NULL)
915 if (pvp[i + 1][2] == ':')
917 /* ':text' (just copy) */
918 (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
921 else if (pvp[i + 1][2] == '=')
925 /* '=base64' (decode) */
927 ret = sasl_decode64(pvp[i + 1] + 3,
928 (unsigned int) l, (*sai)[r],
929 (unsigned int) l + 1, &len);
930 # else /* SASL >= 20000 */
931 ret = sasl_decode64(pvp[i + 1] + 3,
932 (unsigned int) l, (*sai)[r], &len);
933 # endif /* SASL >= 20000 */
941 sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
942 sasl_info_name[r], (*sai)[r]);
946 /* did we get the expected data? */
947 /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */
948 if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
949 bitset(SASL_PASSWORD_BIT, got)))
952 /* no authid? copy uid */
953 if (!bitset(SASL_AUTHID_BIT, got))
955 l = strlen((*sai)[SASL_USER]) + 1;
956 (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
958 if ((*sai)[SASL_AUTHID] == NULL)
960 (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
963 /* no uid? copy authid */
964 if (!bitset(SASL_USER_BIT, got))
966 l = strlen((*sai)[SASL_AUTHID]) + 1;
967 (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
969 if ((*sai)[SASL_USER] == NULL)
971 (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
979 sm_syslog(LOG_WARNING, NOQID,
980 "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
981 macvalue(macid("{server_name}"), e),
982 macvalue(macid("{server_addr}"), e),
983 ret == EX_TEMPFAIL ? "temp" : "");
984 for (i = 0; i <= SASL_MECHLIST; i++)
985 (*sai)[i] = NULL; /* just clear; rpool */
991 ** GETSIMPLE -- callback to get userid or authid
996 ** result -- (pointer to) result
997 ** len -- (pointer to) length of result
1000 ** OK/failure values
1004 getsimple(context, id, result, len)
1007 const char **result;
1012 if (result == NULL || context == NULL)
1013 return SASL_BADPARAM;
1014 sai = (SASL_AI_T *) context;
1019 *result = (*sai)[SASL_USER];
1021 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1024 *len = *result != NULL ? strlen(*result) : 0;
1027 case SASL_CB_AUTHNAME:
1028 *result = (*sai)[SASL_AUTHID];
1030 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1033 *len = *result != NULL ? strlen(*result) : 0;
1036 case SASL_CB_LANGUAGE:
1043 return SASL_BADPARAM;
1048 ** GETSECRET -- callback to get password
1051 ** conn -- connection information
1054 ** psecret -- (pointer to) result
1057 ** OK/failure values
1061 getsecret(conn, context, id, psecret)
1063 SM_UNUSED(void *context);
1065 sasl_secret_t **psecret;
1071 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1072 return SASL_BADPARAM;
1074 mci = (MCI *) context;
1075 authpass = mci->mci_sai[SASL_PASSWORD];
1076 len = strlen(authpass);
1079 ** use an rpool because we are responsible for free()ing the secret,
1080 ** but we can't free() it until after the auth completes
1083 *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
1084 sizeof(sasl_secret_t) +
1086 if (*psecret == NULL)
1088 (void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1);
1089 (*psecret)->len = (unsigned long) len;
1092 # else /* SASL >= 20000 */
1094 ** GETSIMPLE -- callback to get userid or authid
1099 ** result -- (pointer to) result
1100 ** len -- (pointer to) length of result
1103 ** OK/failure values
1107 getsimple(context, id, result, len)
1110 const char **result;
1116 # endif /* SASL > 10509 */
1119 char *authid = NULL;
1121 if (result == NULL || context == NULL)
1122 return SASL_BADPARAM;
1123 sai = (SASL_AI_T *) context;
1126 ** Unfortunately it is not clear whether this routine should
1127 ** return a copy of a string or just a pointer to a string.
1128 ** The Cyrus-SASL plugins treat these return values differently, e.g.,
1129 ** plugins/cram.c free()s authid, plugings/digestmd5.c does not.
1130 ** The best solution to this problem is to fix Cyrus-SASL, but it
1131 ** seems there is nobody who creates patches... Hello CMU!?
1132 ** The second best solution is to have flags that tell this routine
1133 ** whether to return an malloc()ed copy.
1134 ** The next best solution is to always return an malloc()ed copy,
1135 ** and suffer from some memory leak, which is ugly for persistent
1137 ** For now we go with the last solution...
1138 ** We can't use rpools (which would avoid this particular problem)
1139 ** as explained in sasl.c.
1145 l = strlen((*sai)[SASL_USER]) + 1;
1146 s = sm_sasl_malloc(l);
1154 (void) sm_strlcpy(s, (*sai)[SASL_USER], l);
1157 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1160 *len = *result != NULL ? strlen(*result) : 0;
1163 case SASL_CB_AUTHNAME:
1164 h = (*sai)[SASL_AUTHID];
1166 /* XXX maybe other mechanisms too?! */
1167 addrealm = (*sai)[SASL_MECH] != NULL &&
1168 sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0;
1171 ** Add realm to authentication id unless authid contains
1172 ** '@' (i.e., a realm) or the default realm is empty.
1175 if (addrealm && h != NULL && strchr(h, '@') == NULL)
1177 /* has this been done before? */
1178 if ((*sai)[SASL_ID_REALM] == NULL)
1182 realm = (*sai)[SASL_DEFREALM];
1184 /* do not add an empty realm */
1188 (*sai)[SASL_ID_REALM] = NULL;
1192 l = strlen(h) + strlen(realm) + 2;
1194 /* should use rpool, but from where? */
1195 authid = sm_sasl_malloc(l);
1198 (void) sm_snprintf(authid, l,
1201 (*sai)[SASL_ID_REALM] = authid;
1206 (*sai)[SASL_ID_REALM] = NULL;
1211 authid = (*sai)[SASL_ID_REALM];
1214 # endif /* SASL > 10509 */
1216 l = strlen(authid) + 1;
1217 s = sm_sasl_malloc(l);
1225 (void) sm_strlcpy(s, authid, l);
1228 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1231 *len = authid ? strlen(authid) : 0;
1234 case SASL_CB_LANGUAGE:
1241 return SASL_BADPARAM;
1246 ** GETSECRET -- callback to get password
1249 ** conn -- connection information
1252 ** psecret -- (pointer to) result
1255 ** OK/failure values
1259 getsecret(conn, context, id, psecret)
1261 SM_UNUSED(void *context);
1263 sasl_secret_t **psecret;
1269 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1270 return SASL_BADPARAM;
1272 sai = (SASL_AI_T *) context;
1273 authpass = (*sai)[SASL_PASSWORD];
1274 len = strlen(authpass);
1275 *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
1277 if (*psecret == NULL)
1279 (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
1280 (*psecret)->len = (unsigned long) len;
1283 # endif /* SASL >= 20000 */
1286 ** SAFESASLFILE -- callback for sasl: is file safe?
1289 ** context -- pointer to context between invocations (unused)
1290 ** file -- name of file to check
1291 ** type -- type of file to check
1294 ** SASL_OK -- file can be used
1295 ** SASL_CONTINUE -- don't use file
1296 ** SASL_FAIL -- failure (not used here)
1302 safesaslfile(context, file, type)
1303 #else /* SASL > 10515 */
1304 safesaslfile(context, file)
1305 #endif /* SASL > 10515 */
1309 # else /* SASL >= 20000 */
1311 # endif /* SASL >= 20000 */
1314 sasl_verify_type_t type;
1315 # else /* SASL >= 20000 */
1317 # endif /* SASL >= 20000 */
1318 #endif /* SASL > 10515 */
1324 #endif /* SASL <= 10515 */
1327 if (file == NULL || *file == '\0')
1329 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
1331 if ((p = strrchr(file, '/')) == NULL)
1336 /* everything beside libs and .conf files must not be readable */
1338 if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
1339 (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
1341 if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1342 sff |= SFF_NORFILES;
1343 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1344 sff |= SFF_NOGWFILES;
1346 #else /* SASL <= 10515 */
1347 /* files containing passwords should be not readable */
1348 if (type == SASL_VRFY_PASSWD)
1350 if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1351 sff |= SFF_NOWRFILES;
1353 sff |= SFF_NORFILES;
1354 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1355 sff |= SFF_NOGWFILES;
1357 #endif /* SASL <= 10515 */
1360 if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
1361 S_IRUSR, NULL)) == 0)
1363 if (LogLevel > (r != ENOENT ? 8 : 10))
1364 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
1365 p, sm_errstring(r));
1366 return SASL_CONTINUE;
1370 ** SASLGETREALM -- return the realm for SASL
1372 ** return the realm for the client
1375 ** context -- context shared between invocations
1376 ** availrealms -- list of available realms
1377 ** {realm, realm, ...}
1378 ** result -- pointer to result
1385 saslgetrealm(context, id, availrealms, result)
1388 const char **availrealms;
1389 const char **result;
1394 sai = (SASL_AI_T *) context;
1397 r = (*sai)[SASL_DEFREALM];
1400 sm_syslog(LOG_INFO, NOQID,
1401 "AUTH=client, realm=%s, available realms=%s",
1402 r == NULL ? "<No Realm>" : r,
1403 (availrealms == NULL || *availrealms == NULL)
1404 ? "<No Realms>" : *availrealms);
1406 /* check whether context is in list */
1407 if (availrealms != NULL && *availrealms != NULL)
1409 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
1413 sm_syslog(LOG_ERR, NOQID,
1414 "AUTH=client, realm=%s not in list=%s",
1423 ** ITEMINLIST -- does item appear in list?
1425 ** Check whether item appears in list (which must be separated by a
1426 ** character in delim) as a "word", i.e. it must appear at the begin
1427 ** of the list or after a space, and it must end with a space or the
1431 ** item -- item to search.
1432 ** list -- list of items.
1433 ** delim -- list of delimiters.
1436 ** pointer to occurrence (NULL if not found).
1440 iteminlist(item, list, delim)
1448 if (list == NULL || *list == '\0')
1450 if (item == NULL || *item == '\0')
1454 while (s != NULL && *s != '\0')
1456 if (sm_strncasecmp(s, item, len) == 0 &&
1457 (s[len] == '\0' || strchr(delim, s[len]) != NULL))
1459 s = strpbrk(s, delim);
1467 ** REMOVEMECH -- remove item [rem] from list [list]
1470 ** rem -- item to remove
1471 ** list -- list of items
1472 ** rpool -- resource pool from which result is allocated.
1475 ** pointer to new list (NULL in case of error).
1479 removemech(rem, list, rpool)
1490 if (rem == NULL || *rem == '\0')
1492 /* take out what? */
1496 /* find the item in the list */
1497 if ((needle = iteminlist(rem, list, " ")) == NULL)
1499 /* not in there: return original */
1503 /* length of string without rem */
1504 len = strlen(list) - strlen(rem);
1507 ret = (char *) sm_rpool_malloc_x(rpool, 1);
1511 ret = (char *) sm_rpool_malloc_x(rpool, len);
1512 memset(ret, '\0', len);
1514 /* copy from start to removed item */
1515 memcpy(ret, list, needle - list);
1517 /* length of rest of string past removed item */
1518 len = strlen(needle) - strlen(rem) - 1;
1521 /* not last item -- copy into string */
1522 memcpy(ret + (needle - list),
1523 list + (needle - list) + strlen(rem) + 1,
1527 ret[(needle - list) - 1] = '\0';
1531 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism
1535 ** mci -- the mailer connection structure.
1536 ** e -- the envelope (including the sender to specify).
1537 ** sai - sasl authinfo
1540 ** EX_OK -- authentication was successful.
1541 ** EX_NOPERM -- authentication failed.
1542 ** EX_IOERR -- authentication dialogue failed (I/O problem?).
1543 ** EX_TEMPFAIL -- temporary failure.
1548 attemptauth(m, mci, e, sai)
1554 int saslresult, smtpresult;
1557 const char *auth_id;
1559 # else /* SASL >= 20000 */
1560 sasl_external_properties_t ssf;
1562 # endif /* SASL >= 20000 */
1563 unsigned int outlen;
1564 sasl_interact_t *client_interact = NULL;
1566 sasl_security_properties_t ssp;
1567 char in64[MAXOUTLEN];
1568 #if NETINET || (NETINET6 && SASL >= 20000)
1569 extern SOCKADDR CurHostAddr;
1570 #endif /* NETINET || (NETINET6 && SASL >= 20000) */
1572 /* no mechanism selected (yet) */
1573 (*sai)[SASL_MECH] = NULL;
1575 /* dispose old connection */
1576 if (mci->mci_conn != NULL)
1577 sasl_dispose(&(mci->mci_conn));
1579 /* make a new client sasl connection */
1581 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1583 CurHostName, NULL, NULL, NULL, 0,
1585 # else /* SASL >= 20000 */
1586 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1588 CurHostName, NULL, 0, &mci->mci_conn);
1589 # endif /* SASL >= 20000 */
1590 if (saslresult != SASL_OK)
1593 /* set properties */
1594 (void) memset(&ssp, '\0', sizeof ssp);
1596 /* XXX should these be options settable via .cf ? */
1598 ssp.max_ssf = MaxSLBits;
1599 ssp.maxbufsize = MAXOUTLEN;
1601 ssp.security_flags = SASL_SEC_NOPLAINTEXT;
1604 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
1605 if (saslresult != SASL_OK)
1609 /* external security strength factor, authentication id */
1613 out = macvalue(macid("{cert_subject}"), e);
1614 if (out != NULL && *out != '\0')
1616 out = macvalue(macid("{cipher_bits}"), e);
1617 if (out != NULL && *out != '\0')
1619 # endif /* STARTTLS */
1620 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1621 if (saslresult != SASL_OK)
1623 saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
1624 if (saslresult != SASL_OK)
1627 # if NETINET || NETINET6
1628 /* set local/remote ipv4 addresses */
1629 if (mci->mci_out != NULL && (
1631 CurHostAddr.sa.sa_family == AF_INET6 ||
1632 # endif /* NETINET6 */
1633 CurHostAddr.sa.sa_family == AF_INET))
1635 SOCKADDR_LEN_T addrsize;
1637 char localip[60], remoteip[60];
1639 switch (CurHostAddr.sa.sa_family)
1642 addrsize = sizeof(struct sockaddr_in);
1646 addrsize = sizeof(struct sockaddr_in6);
1648 # endif /* NETINET6 */
1652 if (iptostring(&CurHostAddr, addrsize,
1653 remoteip, sizeof remoteip))
1655 if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
1656 remoteip) != SASL_OK)
1659 addrsize = sizeof(saddr_l);
1660 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1662 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1664 if (iptostring(&saddr_l, addrsize,
1665 localip, sizeof localip))
1667 if (sasl_setprop(mci->mci_conn,
1669 localip) != SASL_OK)
1674 # endif /* NETINET || NETINET6 */
1676 /* start client side of sasl */
1677 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1680 (const char **) &mechusing);
1681 # else /* SASL >= 20000 */
1682 /* external security strength factor, authentication id */
1686 out = macvalue(macid("{cert_subject}"), e);
1687 if (out != NULL && *out != '\0')
1689 out = macvalue(macid("{cipher_bits}"), e);
1690 if (out != NULL && *out != '\0')
1691 ssf.ssf = atoi(out);
1692 # endif /* STARTTLS */
1693 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1694 if (saslresult != SASL_OK)
1698 /* set local/remote ipv4 addresses */
1699 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
1701 SOCKADDR_LEN_T addrsize;
1702 struct sockaddr_in saddr_l;
1704 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
1705 (struct sockaddr_in *) &CurHostAddr)
1708 addrsize = sizeof(struct sockaddr_in);
1709 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1711 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1713 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
1714 &saddr_l) != SASL_OK)
1718 # endif /* NETINET */
1720 /* start client side of sasl */
1721 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1722 NULL, &client_interact,
1724 (const char **) &mechusing);
1725 # endif /* SASL >= 20000 */
1727 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1729 if (saslresult == SASL_NOMECH && LogLevel > 8)
1731 sm_syslog(LOG_NOTICE, e->e_id,
1732 "AUTH=client, available mechanisms do not fulfill requirements");
1737 /* just point current mechanism to the data in the sasl library */
1738 (*sai)[SASL_MECH] = mechusing;
1740 /* send the info across the wire */
1742 /* login and digest-md5 up to 1.5.28 set out="" */
1744 (sm_strcasecmp(mechusing, "LOGIN") == 0 ||
1745 sm_strcasecmp(mechusing, "DIGEST-MD5") == 0))
1748 /* no initial response */
1749 smtpmessage("AUTH %s", m, mci, mechusing);
1751 else if (outlen == 0)
1754 ** zero-length initial response, per RFC 2554 4.:
1755 ** "Unlike a zero-length client answer to a 334 reply, a zero-
1756 ** length initial response is sent as a single equals sign"
1759 smtpmessage("AUTH %s =", m, mci, mechusing);
1763 saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL);
1764 if (saslresult != SASL_OK) /* internal error */
1767 sm_syslog(LOG_ERR, e->e_id,
1768 "encode64 for AUTH failed");
1771 smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
1774 sm_sasl_free(out); /* XXX only if no rpool is used */
1775 # endif /* SASL < 20000 */
1778 smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
1783 /* check return code from server */
1784 if (smtpresult == 235)
1786 macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
1790 if (smtpresult == -1)
1792 if (REPLYTYPE(smtpresult) == 5)
1793 return EX_NOPERM; /* ugly, but ... */
1794 if (REPLYTYPE(smtpresult) != 3)
1796 /* should we fail deliberately, see RFC 2554 4. ? */
1797 /* smtpmessage("*", m, mci); */
1801 saslresult = sasl_client_step(mci->mci_conn,
1802 mci->mci_sasl_string,
1803 mci->mci_sasl_string_len,
1807 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1810 sm_dprintf("AUTH FAIL=%s (%d)\n",
1811 sasl_errstring(saslresult, NULL, NULL),
1814 /* fail deliberately, see RFC 2554 4. */
1815 smtpmessage("*", m, mci);
1818 ** but we should only fail for this authentication
1819 ** mechanism; how to do that?
1822 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1823 getsasldata, NULL, XS_AUTH);
1829 saslresult = sasl_encode64(out, outlen, in64,
1831 if (saslresult != SASL_OK)
1833 /* give an error reply to the other side! */
1834 smtpmessage("*", m, mci);
1841 sm_sasl_free(out); /* XXX only if no rpool is used */
1842 # endif /* SASL < 20000 */
1843 smtpmessage("%s", m, mci, in64);
1844 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1845 getsasldata, NULL, XS_AUTH);
1850 ** SMTPAUTH -- try to AUTHenticate
1852 ** This will try mechanisms in the order the sasl library decided until:
1853 ** - there are no more mechanisms
1854 ** - a mechanism succeeds
1855 ** - the sasl library fails initializing
1859 ** mci -- the mailer connection info.
1860 ** e -- the envelope.
1863 ** EX_OK -- authentication was successful
1864 ** EX_UNAVAILABLE -- authentication not possible, e.g.,
1865 ** no data available.
1866 ** EX_NOPERM -- authentication failed.
1867 ** EX_TEMPFAIL -- temporary failure.
1869 ** Notice: AuthInfo is used for all connections, hence we must
1870 ** return EX_TEMPFAIL only if we really want to retry, i.e.,
1871 ** iff getauth() tempfailed or getauth() was used and
1872 ** authentication tempfailed.
1885 mci->mci_sasl_auth = false;
1886 for (i = 0; i < SASL_MECH ; i++)
1887 mci->mci_sai[i] = NULL;
1889 result = getauth(mci, e, &(mci->mci_sai));
1890 if (result == EX_TEMPFAIL)
1894 /* no data available: don't try to authenticate */
1895 if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
1897 if (result != EX_OK)
1899 if (SASLInfo == NULL)
1900 return EX_UNAVAILABLE;
1902 /* read authinfo from file */
1903 result = readauth(SASLInfo, true, &(mci->mci_sai),
1905 if (result != EX_OK)
1907 usedgetauth = false;
1910 /* check whether sufficient data is available */
1911 if (mci->mci_sai[SASL_PASSWORD] == NULL ||
1912 *(mci->mci_sai)[SASL_PASSWORD] == '\0')
1913 return EX_UNAVAILABLE;
1914 if ((mci->mci_sai[SASL_AUTHID] == NULL ||
1915 *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
1916 (mci->mci_sai[SASL_USER] == NULL ||
1917 *(mci->mci_sai)[SASL_USER] == '\0'))
1918 return EX_UNAVAILABLE;
1920 /* set the context for the callback function to sai */
1922 callbacks[CB_PASS_IDX].context = (void *) mci;
1923 # else /* SASL >= 20000 */
1924 callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
1925 # endif /* SASL >= 20000 */
1926 callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
1927 callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
1928 callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
1930 callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
1933 /* set default value for realm */
1934 if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
1935 (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
1936 macvalue('j', CurEnv));
1938 /* set default value for list of mechanism to use */
1939 if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
1940 *(mci->mci_sai)[SASL_MECHLIST] == '\0')
1941 (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
1943 /* create list of mechanisms to try */
1944 mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
1945 mci->mci_saslcap, mci->mci_rpool);
1947 /* initialize sasl client library */
1948 result = init_sasl_client();
1949 if (result != SASL_OK)
1950 return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
1953 result = attemptauth(m, mci, e, &(mci->mci_sai));
1954 if (result == EX_OK)
1955 mci->mci_sasl_auth = true;
1956 else if (result == EX_TEMPFAIL || result == EX_NOPERM)
1958 mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
1961 if (mci->mci_saslcap == NULL ||
1962 *(mci->mci_saslcap) == '\0')
1963 return usedgetauth ? result
1968 } while (result != EX_OK);
1974 ** SMTPMAILFROM -- send MAIL command
1978 ** mci -- the mailer connection structure.
1979 ** e -- the envelope (including the sender to specify).
1983 smtpmailfrom(m, mci, e)
1992 char buf[MAXNAME + 1];
1993 char optbuf[MAXLINE];
1996 sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
2000 ** Check if connection is gone, if so
2001 ** it's a tempfail and we use mci_errno
2005 if (mci->mci_state == MCIS_CLOSED)
2007 errno = mci->mci_errno;
2011 /* set up appropriate options to include */
2012 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
2014 (void) sm_snprintf(optbuf, sizeof optbuf, " SIZE=%ld",
2016 bufp = &optbuf[strlen(optbuf)];
2024 bodytype = e->e_bodytype;
2025 if (bitset(MCIF_8BITMIME, mci->mci_flags))
2027 if (bodytype == NULL &&
2028 bitset(MM_MIME8BIT, MimeMode) &&
2029 bitset(EF_HAS8BIT, e->e_flags) &&
2030 !bitset(EF_DONT_MIME, e->e_flags) &&
2031 !bitnset(M_8BITS, m->m_flags))
2032 bodytype = "8BITMIME";
2033 if (bodytype != NULL &&
2034 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
2036 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2037 " BODY=%s", bodytype);
2038 bufp += strlen(bufp);
2041 else if (bitnset(M_8BITS, m->m_flags) ||
2042 !bitset(EF_HAS8BIT, e->e_flags) ||
2043 bitset(MCIF_8BITOK, mci->mci_flags))
2046 /* just pass it through */
2049 else if (bitset(MM_CVTMIME, MimeMode) &&
2050 !bitset(EF_DONT_MIME, e->e_flags) &&
2051 (!bitset(MM_PASS8BIT, MimeMode) ||
2052 bitset(EF_IS_MIME, e->e_flags)))
2054 /* must convert from 8bit MIME format to 7bit encoded */
2055 mci->mci_flags |= MCIF_CVT8TO7;
2057 #endif /* MIME8TO7 */
2058 else if (!bitset(MM_PASS8BIT, MimeMode))
2060 /* cannot just send a 8-bit version */
2061 extern char MsgBuf[];
2063 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
2064 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
2068 if (bitset(MCIF_DSN, mci->mci_flags))
2070 if (e->e_envid != NULL &&
2071 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
2073 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2074 " ENVID=%s", e->e_envid);
2075 bufp += strlen(bufp);
2078 /* RET= parameter */
2079 if (bitset(EF_RET_PARAM, e->e_flags) &&
2080 SPACELEFT(optbuf, bufp) > 9)
2082 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2084 bitset(EF_NO_BODY_RETN, e->e_flags) ?
2086 bufp += strlen(bufp);
2090 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
2091 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
2093 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
2097 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2098 " AUTH=%s", e->e_auth_param);
2099 bufp += strlen(bufp);
2103 ** 17 is the max length required, we could use log() to compute
2104 ** the exact length (and check IS_DLVR_TRACE())
2107 if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
2108 IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
2113 ** Avoid problems with delays (for R) since the check
2114 ** in deliver() whether min-deliver-time is sufficient.
2115 ** Alternatively we could pass the computed time to this
2119 dby = e->e_deliver_by - (curtime() - e->e_ctime);
2120 if (dby <= 0 && IS_DLVR_RETURN(e))
2121 dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
2122 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2125 IS_DLVR_RETURN(e) ? 'R' : 'N',
2126 IS_DLVR_TRACE(e) ? "T" : "");
2127 bufp += strlen(bufp);
2131 ** Send the MAIL command.
2132 ** Designates the sender.
2135 mci->mci_state = MCIS_MAIL;
2137 if (bitset(EF_RESPONSE, e->e_flags) &&
2138 !bitnset(M_NO_NULL_FROM, m->m_flags))
2141 expand("\201g", buf, sizeof buf, e);
2144 /* strip off <angle brackets> (put back on below) */
2145 bufp = &buf[strlen(buf) - 1];
2152 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
2153 !bitnset(M_FROMPATH, m->m_flags))
2155 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
2159 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
2160 *bufp == '@' ? ',' : ':', bufp, optbuf);
2162 SmtpPhase = mci->mci_phase = "client MAIL";
2163 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2164 CurHostName, mci->mci_phase);
2165 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_DEFAULT);
2168 /* communications failure */
2169 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
2172 else if (r == SMTPCLOSING)
2174 /* service shutting down: handled by reply() */
2177 else if (REPLYTYPE(r) == 4)
2179 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
2183 else if (REPLYTYPE(r) == 2)
2189 /* syntax error in arguments */
2190 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
2196 /* mailbox name not allowed */
2197 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
2203 /* exceeded storage allocation */
2204 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
2206 if (bitset(MCIF_SIZE, mci->mci_flags))
2207 e->e_flags |= EF_NO_BODY_RETN;
2208 return EX_UNAVAILABLE;
2210 else if (REPLYTYPE(r) == 5)
2213 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
2215 return EX_UNAVAILABLE;
2220 sm_syslog(LOG_CRIT, e->e_id,
2221 "%.100s: SMTP MAIL protocol error: %s",
2223 shortenstring(SmtpReplyBuffer, 403));
2226 /* protocol error -- close up */
2227 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2229 smtpquit(m, mci, e);
2233 ** SMTPRCPT -- designate recipient.
2236 ** to -- address of recipient.
2237 ** m -- the mailer we are sending to.
2238 ** mci -- the connection info for this transaction.
2239 ** e -- the envelope for this transaction.
2242 ** exit status corresponding to recipient status.
2245 ** Sends the mail via SMTP.
2249 smtprcpt(to, m, mci, e, ctladdr, xstart)
2258 char optbuf[MAXLINE];
2262 ** If there is status waiting from the other end, read it.
2263 ** This should normally happen because of SMTP pipelining.
2266 while (mci->mci_nextaddr != NULL &&
2267 sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2271 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2274 markfailure(e, mci->mci_nextaddr, mci, r, false);
2275 giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
2276 ctladdr, xstart, e, to);
2278 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2280 #endif /* PIPELINING */
2283 ** Check if connection is gone, if so
2284 ** it's a tempfail and we use mci_errno
2288 if (mci->mci_state == MCIS_CLOSED)
2290 errno = mci->mci_errno;
2298 ** Warning: in the following it is assumed that the free space
2299 ** in bufp is sizeof optbuf
2302 if (bitset(MCIF_DSN, mci->mci_flags))
2304 if (IS_DLVR_NOTIFY(e) &&
2305 !bitset(MCIF_DLVR_BY, mci->mci_flags))
2307 /* RFC 2852: 4.1.4.2 */
2308 if (!bitset(QHASNOTIFY, to->q_flags))
2309 to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
2310 else if (bitset(QPINGONSUCCESS, to->q_flags) ||
2311 bitset(QPINGONFAILURE, to->q_flags) ||
2312 bitset(QPINGONDELAY, to->q_flags))
2313 to->q_flags |= QPINGONDELAY;
2316 /* NOTIFY= parameter */
2317 if (bitset(QHASNOTIFY, to->q_flags) &&
2318 bitset(QPRIMARY, to->q_flags) &&
2319 !bitnset(M_LOCALMAILER, m->m_flags))
2321 bool firstone = true;
2323 (void) sm_strlcat(bufp, " NOTIFY=", sizeof optbuf);
2324 if (bitset(QPINGONSUCCESS, to->q_flags))
2326 (void) sm_strlcat(bufp, "SUCCESS", sizeof optbuf);
2329 if (bitset(QPINGONFAILURE, to->q_flags))
2332 (void) sm_strlcat(bufp, ",",
2334 (void) sm_strlcat(bufp, "FAILURE", sizeof optbuf);
2337 if (bitset(QPINGONDELAY, to->q_flags))
2340 (void) sm_strlcat(bufp, ",",
2342 (void) sm_strlcat(bufp, "DELAY", sizeof optbuf);
2346 (void) sm_strlcat(bufp, "NEVER", sizeof optbuf);
2347 bufp += strlen(bufp);
2350 /* ORCPT= parameter */
2351 if (to->q_orcpt != NULL &&
2352 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
2354 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2355 " ORCPT=%s", to->q_orcpt);
2356 bufp += strlen(bufp);
2360 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
2361 mci->mci_state = MCIS_RCPT;
2363 SmtpPhase = mci->mci_phase = "client RCPT";
2364 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2365 CurHostName, mci->mci_phase);
2369 ** If running SMTP pipelining, we will pick up status later
2372 if (bitset(MCIF_PIPELINED, mci->mci_flags))
2374 #endif /* PIPELINING */
2376 return smtprcptstat(to, m, mci, e);
2379 ** SMTPRCPTSTAT -- get recipient status
2381 ** This is only called during SMTP pipelining
2384 ** to -- address of recipient.
2385 ** m -- mailer being sent to.
2386 ** mci -- the mailer connection information.
2387 ** e -- the envelope for this message.
2390 ** EX_* -- protocol status
2394 smtprcptstat(to, m, mci, e)
2398 register ENVELOPE *e;
2405 ** Check if connection is gone, if so
2406 ** it's a tempfail and we use mci_errno
2410 if (mci->mci_state == MCIS_CLOSED)
2412 errno = mci->mci_errno;
2417 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_DEFAULT);
2419 to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
2420 to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
2421 if (!bitnset(M_LMTP, m->m_flags))
2422 to->q_statmta = mci->mci_host;
2423 if (r < 0 || REPLYTYPE(r) == 4)
2425 mci->mci_retryrcpt = true;
2429 else if (REPLYTYPE(r) == 2)
2433 if ((t = mci->mci_tolist) != NULL)
2438 for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
2441 mci->mci_tolist = t;
2445 #endif /* PIPELINING */
2450 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
2455 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
2460 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
2463 else if (REPLYTYPE(r) == 5)
2465 return EX_UNAVAILABLE;
2470 sm_syslog(LOG_CRIT, e->e_id,
2471 "%.100s: SMTP RCPT protocol error: %s",
2473 shortenstring(SmtpReplyBuffer, 403));
2476 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2481 ** SMTPDATA -- send the data and clean up the transaction.
2484 ** m -- mailer being sent to.
2485 ** mci -- the mailer connection information.
2486 ** e -- the envelope for this message.
2489 ** exit status corresponding to DATA command.
2493 smtpdata(m, mci, e, ctladdr, xstart)
2496 register ENVELOPE *e;
2507 ** Check if connection is gone, if so
2508 ** it's a tempfail and we use mci_errno
2512 if (mci->mci_state == MCIS_CLOSED)
2514 errno = mci->mci_errno;
2522 ** First send the command and check that it is ok.
2523 ** Then send the data (if there are valid recipients).
2524 ** Follow it up with a dot to terminate.
2525 ** Finally get the results of the transaction.
2528 /* send the command and check ok to proceed */
2529 smtpmessage("DATA", m, mci);
2532 if (mci->mci_nextaddr != NULL)
2534 char *oldto = e->e_to;
2536 /* pick up any pending RCPT responses for SMTP pipelining */
2537 while (mci->mci_nextaddr != NULL)
2541 e->e_to = mci->mci_nextaddr->q_paddr;
2542 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2545 markfailure(e, mci->mci_nextaddr, mci, r,
2547 giveresponse(r, mci->mci_nextaddr->q_status, m,
2548 mci, ctladdr, xstart, e,
2550 if (r == EX_TEMPFAIL)
2551 mci->mci_nextaddr->q_state = QS_RETRY;
2553 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2558 ** Connection might be closed in response to a RCPT command,
2559 ** i.e., the server responded with 421. In that case (at
2560 ** least) one RCPT has a temporary failure, hence we don't
2561 ** need to check mci_okrcpts (as it is done below) to figure
2562 ** out which error to return.
2565 if (mci->mci_state == MCIS_CLOSED)
2567 errno = mci->mci_errno;
2571 #endif /* PIPELINING */
2573 /* now proceed with DATA phase */
2574 SmtpPhase = mci->mci_phase = "client DATA 354";
2575 mci->mci_state = MCIS_DATA;
2576 sm_setproctitle(true, e, "%s %s: %s",
2577 qid_printname(e), CurHostName, mci->mci_phase);
2578 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DEFAULT);
2579 if (r < 0 || REPLYTYPE(r) == 4)
2582 smtpquit(m, mci, e);
2583 errno = mci->mci_errno;
2586 else if (REPLYTYPE(r) == 5)
2588 smtprset(m, mci, e);
2590 if (mci->mci_okrcpts <= 0)
2591 return mci->mci_retryrcpt ? EX_TEMPFAIL
2593 #endif /* PIPELINING */
2594 return EX_UNAVAILABLE;
2596 else if (REPLYTYPE(r) != 3)
2600 sm_syslog(LOG_CRIT, e->e_id,
2601 "%.100s: SMTP DATA-1 protocol error: %s",
2603 shortenstring(SmtpReplyBuffer, 403));
2605 smtprset(m, mci, e);
2606 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2609 if (mci->mci_okrcpts <= 0)
2610 return mci->mci_retryrcpt ? EX_TEMPFAIL
2612 #endif /* PIPELINING */
2617 if (mci->mci_okrcpts > 0)
2619 #endif /* PIPELINING */
2622 ** Set timeout around data writes. Make it at least large
2623 ** enough for DNS timeouts on all recipients plus some fudge
2624 ** factor. The main thing is that it should not be infinite.
2629 /* simulate a DATA timeout */
2633 timeout = DATA_PROGRESS_TIMEOUT * 1000;
2634 sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
2638 ** Output the actual message.
2641 if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
2646 /* simulate a DATA timeout */
2650 if (!(*e->e_putbody)(mci, e, NULL))
2654 ** Cleanup after sending message.
2660 #endif /* PIPELINING */
2662 #if _FFR_CATCH_BROKEN_MTAS
2663 if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2665 /* terminate the message */
2666 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
2668 if (TrafficLogFile != NULL)
2669 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2670 "%05d >>> .\n", (int) CurrentPid);
2674 sm_syslog(LOG_CRIT, e->e_id,
2675 "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
2677 mci->mci_errno = EIO;
2678 mci->mci_state = MCIS_ERROR;
2679 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
2680 smtpquit(m, mci, e);
2683 #endif /* _FFR_CATCH_BROKEN_MTAS */
2685 if (sm_io_error(mci->mci_out))
2687 /* error during processing -- don't send the dot */
2688 mci->mci_errno = EIO;
2689 mci->mci_state = MCIS_ERROR;
2690 mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
2691 smtpquit(m, mci, e);
2695 /* terminate the message */
2696 if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", m->m_eol) ==
2699 if (TrafficLogFile != NULL)
2700 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2701 "%05d >>> .\n", (int) CurrentPid);
2705 /* check for the results of the transaction */
2706 SmtpPhase = mci->mci_phase = "client DATA status";
2707 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2708 CurHostName, mci->mci_phase);
2709 if (bitnset(M_LMTP, m->m_flags))
2711 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT);
2714 if (mci->mci_state == MCIS_DATA)
2715 mci->mci_state = MCIS_OPEN;
2716 xstat = EX_NOTSTICKY;
2718 rstat = EX_TEMPFAIL;
2719 else if (REPLYTYPE(r) == 4)
2720 rstat = xstat = EX_TEMPFAIL;
2721 else if (REPLYTYPE(r) == 2)
2722 rstat = xstat = EX_OK;
2723 else if (REPLYCLASS(r) != 5)
2724 rstat = xstat = EX_PROTOCOL;
2725 else if (REPLYTYPE(r) == 5)
2726 rstat = EX_UNAVAILABLE;
2728 rstat = EX_PROTOCOL;
2729 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
2731 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2732 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2736 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
2737 SmtpPhase = mci->mci_phase = "idle";
2738 sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
2739 if (rstat != EX_PROTOCOL)
2743 sm_syslog(LOG_CRIT, e->e_id,
2744 "%.100s: SMTP DATA-2 protocol error: %s",
2746 shortenstring(SmtpReplyBuffer, 403));
2751 mci->mci_errno = errno;
2752 mci->mci_state = MCIS_ERROR;
2753 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
2756 ** If putbody() couldn't finish due to a timeout,
2757 ** rewind it here in the timeout handler. See
2758 ** comments at the end of putbody() for reasoning.
2761 if (e->e_dfp != NULL)
2762 (void) bfrewind(e->e_dfp);
2764 errno = mci->mci_errno;
2765 syserr("451 4.4.1 timeout writing message to %s", CurHostName);
2766 smtpquit(m, mci, e);
2771 ** SMTPGETSTAT -- get status code from DATA in LMTP
2774 ** m -- the mailer to which we are sending the message.
2775 ** mci -- the mailer connection structure.
2776 ** e -- the current envelope.
2779 ** The exit status corresponding to the reply code.
2783 smtpgetstat(m, mci, e)
2795 /* check for the results of the transaction */
2796 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT);
2799 xstat = EX_NOTSTICKY;
2800 if (REPLYTYPE(r) == 4)
2801 status = EX_TEMPFAIL;
2802 else if (REPLYTYPE(r) == 2)
2803 status = xstat = EX_OK;
2804 else if (REPLYCLASS(r) != 5)
2805 status = xstat = EX_PROTOCOL;
2806 else if (REPLYTYPE(r) == 5)
2807 status = EX_UNAVAILABLE;
2809 status = EX_PROTOCOL;
2810 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2811 (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2815 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]);
2816 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer);
2817 if (LogLevel > 1 && status == EX_PROTOCOL)
2819 sm_syslog(LOG_CRIT, e->e_id,
2820 "%.100s: SMTP DATA-3 protocol error: %s",
2822 shortenstring(SmtpReplyBuffer, 403));
2827 ** SMTPQUIT -- close the SMTP connection.
2830 ** m -- a pointer to the mailer.
2831 ** mci -- the mailer connection information.
2832 ** e -- the current envelope.
2838 ** sends the final protocol and closes the connection.
2847 bool oldSuprErrs = SuprErrs;
2851 if (mci->mci_state == MCIS_CLOSED)
2853 mci_close(mci, "smtpquit:1");
2857 oldcurhost = CurHostName;
2858 CurHostName = mci->mci_host; /* XXX UGLY XXX */
2859 if (CurHostName == NULL)
2860 CurHostName = MyHostName;
2863 mci->mci_okrcpts = 0;
2864 #endif /* PIPELINING */
2867 ** Suppress errors here -- we may be processing a different
2868 ** job when we do the quit connection, and we don't want the
2869 ** new job to be penalized for something that isn't it's
2875 /* send the quit message if we haven't gotten I/O error */
2876 if (mci->mci_state != MCIS_ERROR &&
2877 mci->mci_state != MCIS_QUITING)
2879 SmtpPhase = "client QUIT";
2880 mci->mci_state = MCIS_QUITING;
2881 smtpmessage("QUIT", m, mci);
2882 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL,
2884 SuprErrs = oldSuprErrs;
2885 if (mci->mci_state == MCIS_CLOSED)
2889 /* now actually close the connection and pick up the zombie */
2890 rcode = endmailer(mci, e, NULL);
2893 char *mailer = NULL;
2895 if (mci->mci_mailer != NULL &&
2896 mci->mci_mailer->m_name != NULL)
2897 mailer = mci->mci_mailer->m_name;
2899 /* look for naughty mailers */
2900 sm_syslog(LOG_ERR, e->e_id,
2901 "smtpquit: mailer%s%s exited with exit value %d",
2902 mailer == NULL ? "" : " ",
2903 mailer == NULL ? "" : mailer,
2907 SuprErrs = oldSuprErrs;
2910 CurHostName = oldcurhost;
2914 ** SMTPRSET -- send a RSET (reset) command
2917 ** m -- a pointer to the mailer.
2918 ** mci -- the mailer connection information.
2919 ** e -- the current envelope.
2925 ** closes the connection if there is no reply to RSET.
2936 CurHostName = mci->mci_host; /* XXX UGLY XXX */
2937 if (CurHostName == NULL)
2938 CurHostName = MyHostName;
2941 mci->mci_okrcpts = 0;
2942 #endif /* PIPELINING */
2945 ** Check if connection is gone, if so
2946 ** it's a tempfail and we use mci_errno
2950 if (mci->mci_state == MCIS_CLOSED)
2952 errno = mci->mci_errno;
2956 SmtpPhase = "client RSET";
2957 smtpmessage("RSET", m, mci);
2958 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT);
2963 ** Any response is deemed to be acceptable.
2964 ** The standard does not state the proper action
2965 ** to take when a value other than 250 is received.
2967 ** However, if 421 is returned for the RSET, leave
2968 ** mci_state alone (MCIS_SSD can be set in reply()
2969 ** and MCIS_CLOSED can be set in smtpquit() if
2970 ** reply() gets a 421 and calls smtpquit()).
2973 if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED)
2974 mci->mci_state = MCIS_OPEN;
2975 else if (mci->mci_exitstat == EX_OK)
2976 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL);
2979 ** SMTPPROBE -- check the connection state
2982 ** mci -- the mailer connection information.
2988 ** closes the connection if there is no reply to RSET.
2996 MAILER *m = mci->mci_mailer;
2998 extern ENVELOPE BlankEnvelope;
3000 CurHostName = mci->mci_host; /* XXX UGLY XXX */
3001 if (CurHostName == NULL)
3002 CurHostName = MyHostName;
3005 SmtpPhase = "client probe";
3006 smtpmessage("RSET", m, mci);
3007 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT);
3008 if (REPLYTYPE(r) != 2)
3009 smtpquit(m, mci, e);
3013 ** REPLY -- read arpanet reply
3016 ** m -- the mailer we are reading the reply from.
3017 ** mci -- the mailer connection info structure.
3018 ** e -- the current envelope.
3019 ** timeout -- the timeout for reads.
3020 ** pfunc -- processing function called on each line of response.
3021 ** If null, no special processing is done.
3022 ** enhstat -- optional, returns enhanced error code string (if set)
3023 ** rtype -- type of SmtpMsgBuffer: does it contains secret data?
3026 ** reply code it reads.
3029 ** flushes the mail file.
3033 reply(m, mci, e, timeout, pfunc, enhstat, rtype)
3038 void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
3042 register char *bufp;
3044 bool firstline = true;
3045 char junkbuf[MAXLINE];
3046 static char enhstatcode[ENHSCLEN];
3050 ** Flush the output before reading response.
3052 ** For SMTP pipelining, it would be better if we didn't do
3053 ** this if there was already data waiting to be read. But
3054 ** to do it properly means pushing it to the I/O library,
3055 ** since it really needs to be done below the buffer layer.
3058 if (mci->mci_out != NULL)
3059 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3062 sm_dprintf("reply\n");
3065 ** Read the input line, being careful not to hang.
3068 bufp = SmtpReplyBuffer;
3073 /* actually do the read */
3074 if (e->e_xfp != NULL) /* for debugging */
3075 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
3077 /* if we are in the process of closing just give the code */
3078 if (mci->mci_state == MCIS_CLOSED)
3081 /* don't try to read from a non-existent fd */
3082 if (mci->mci_in == NULL)
3084 if (mci->mci_errno == 0)
3085 mci->mci_errno = EBADF;
3087 /* errors on QUIT should be ignored */
3088 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3090 errno = mci->mci_errno;
3091 mci_close(mci, "reply:1");
3094 mci->mci_state = MCIS_ERROR;
3095 smtpquit(m, mci, e);
3096 errno = mci->mci_errno;
3100 if (mci->mci_out != NULL)
3101 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3103 /* get the line from the other side */
3104 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
3106 mci->mci_lastuse = curtime();
3111 extern char MsgBuf[];
3113 /* errors on QUIT should be ignored */
3114 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3116 mci_close(mci, "reply:2");
3120 /* if the remote end closed early, fake an error */
3124 (void) sm_snprintf(SmtpReplyBuffer,
3125 sizeof SmtpReplyBuffer,
3126 "421 4.4.1 Connection reset by %s",
3130 #else /* ECONNRESET */
3132 #endif /* ECONNRESET */
3135 mci->mci_errno = errno;
3136 oldholderrs = HoldErrs;
3138 usrerr("451 4.4.1 reply: read error from %s",
3140 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
3142 /* if debugging, pause so we can see state */
3145 mci->mci_state = MCIS_ERROR;
3146 smtpquit(m, mci, e);
3152 if (e->e_to != NULL)
3154 (void) sm_snprintf(p,
3157 shortenstring(e->e_to, MAXSHORTSTR));
3160 (void) sm_snprintf(p, SPACELEFT(wbuf, p),
3161 "reply(%.100s) during %s",
3162 CURHOSTNAME, SmtpPhase);
3166 HoldErrs = oldholderrs;
3170 fixcrlf(bufp, true);
3172 /* EHLO failure is not a real error */
3173 if (e->e_xfp != NULL && (bufp[0] == '4' ||
3174 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
3176 /* serious error -- log the previous command */
3179 /* inform user who we are chatting with */
3180 (void) sm_io_fprintf(CurEnv->e_xfp,
3182 "... while talking to %s:\n",
3184 SmtpNeedIntro = false;
3186 if (SmtpMsgBuffer[0] != '\0')
3188 (void) sm_io_fprintf(e->e_xfp,
3191 (rtype == XS_STARTTLS)
3192 ? "STARTTLS dialogue"
3193 : ((rtype == XS_AUTH)
3196 SmtpMsgBuffer[0] = '\0';
3199 /* now log the message as from the other side */
3200 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
3204 /* display the input for verbose mode */
3206 nmessage("050 %s", bufp);
3208 /* ignore improperly formatted input */
3209 if (!ISSMTPREPLY(bufp))
3212 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
3214 extenhsc(bufp + 4, ' ', enhstatcode) > 0)
3215 *enhstat = enhstatcode;
3217 /* process the line */
3219 (*pfunc)(bufp, firstline, m, mci, e);
3223 /* decode the reply code */
3226 /* extra semantics: 0xx codes are "informational" */
3230 /* if no continuation lines, return this line */
3234 /* first line of real reply -- ignore rest */
3239 ** Now look at SmtpReplyBuffer -- only care about the first
3240 ** line of the response from here on out.
3243 /* save temporary failure messages for posterity */
3244 if (SmtpReplyBuffer[0] == '4')
3245 (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof SmtpError);
3247 /* reply code 421 is "Service Shutting Down" */
3248 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
3249 mci->mci_state != MCIS_QUITING)
3251 /* send the quit protocol */
3252 mci->mci_state = MCIS_SSD;
3253 smtpquit(m, mci, e);
3259 ** SMTPMESSAGE -- send message to server
3263 ** m -- the mailer to control formatting.
3264 ** a, b, c -- parameters
3270 ** writes message to mci->mci_out.
3276 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
3277 #else /* __STDC__ */
3278 smtpmessage(f, m, mci, va_alist)
3283 #endif /* __STDC__ */
3287 SM_VA_START(ap, mci);
3288 (void) sm_vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
3291 if (tTd(18, 1) || Verbose)
3292 nmessage(">>> %s", SmtpMsgBuffer);
3293 if (TrafficLogFile != NULL)
3294 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
3295 "%05d >>> %s\n", (int) CurrentPid,
3297 if (mci->mci_out != NULL)
3299 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
3300 SmtpMsgBuffer, m == NULL ? "\r\n"
3303 else if (tTd(18, 1))
3305 sm_dprintf("smtpmessage: NULL mci_out\n");