summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/src/usersmtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/src/usersmtp.c')
-rw-r--r--contrib/sendmail/src/usersmtp.c301
1 files changed, 276 insertions, 25 deletions
diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c
index 3996627..2ec9ac4 100644
--- a/contrib/sendmail/src/usersmtp.c
+++ b/contrib/sendmail/src/usersmtp.c
@@ -13,7 +13,7 @@
#include <sendmail.h>
-SM_RCSID("@(#)$Id: usersmtp.c,v 1.1.1.11 2002/04/10 03:04:52 gshapiro Exp $")
+SM_RCSID("@(#)$Id: usersmtp.c,v 8.437 2002/05/24 18:53:48 gshapiro Exp $")
#include <sysexits.h>
@@ -95,7 +95,7 @@ smtpinit(m, mci, e, onlyhelo)
CurHostName = MyHostName;
SmtpNeedIntro = true;
state = mci->mci_state;
- switch (mci->mci_state)
+ switch (state)
{
case MCIS_MAIL:
case MCIS_RCPT:
@@ -603,7 +603,9 @@ getsasldata(line, firstline, m, mci, e)
{
int len;
int result;
+# if SASL < 20000
char *out;
+# endif /* SASL < 20000 */
/* if not a continue we don't care about it */
len = strlen(line);
@@ -619,9 +621,29 @@ getsasldata(line, firstline, m, mci, e)
/* forget about "334 " */
line += 4;
len -= 4;
+# if SASL >= 20000
+ /* XXX put this into a macro/function? It's duplicated below */
+ if (mci->mci_sasl_string != NULL)
+ {
+ if (mci->mci_sasl_string_len <= len)
+ {
+ sm_free(mci->mci_sasl_string); /* XXX */
+ mci->mci_sasl_string = xalloc(len + 1);
+ }
+ }
+ else
+ mci->mci_sasl_string = xalloc(len + 1);
+ result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
+ (unsigned int *) &mci->mci_sasl_string_len);
+ if (result != SASL_OK)
+ {
+ mci->mci_sasl_string_len = 0;
+ *mci->mci_sasl_string = '\0';
+ }
+# else /* SASL >= 20000 */
out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
- result = sasl_decode64(line, len, out, (unsigned int *)&len);
+ result = sasl_decode64(line, len, out, (unsigned int *) &len);
if (result != SASL_OK)
{
len = 0;
@@ -648,6 +670,7 @@ getsasldata(line, firstline, m, mci, e)
memcpy(mci->mci_sasl_string, out, len);
mci->mci_sasl_string[len] = '\0';
mci->mci_sasl_string_len = len;
+# endif /* SASL >= 20000 */
return;
}
/*
@@ -894,8 +917,14 @@ getauth(mci, e, sai)
unsigned int len;
/* '=base64' (decode) */
+# if SASL >= 20000
+ r = sasl_decode64(pvp[i + 1] + 3,
+ (unsigned int) l, (*sai)[r],
+ (unsigned int) l + 1, &len);
+# else /* SASL >= 20000 */
r = sasl_decode64(pvp[i + 1] + 3,
(unsigned int) l, (*sai)[r], &len);
+# endif /* SASL >= 20000 */
if (r != SASL_OK)
goto fail;
got |= 1 << r;
@@ -903,7 +932,7 @@ getauth(mci, e, sai)
else
goto fail;
if (tTd(95, 5))
- sm_syslog(LOG_WARNING, NOQID, "getauth %s=%s",
+ sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
sasl_info_name[r], (*sai)[r]);
++i;
}
@@ -949,6 +978,111 @@ getauth(mci, e, sai)
(*sai)[i] = NULL; /* just clear; rpool */
return ret;
}
+
+# if SASL >= 20000
+/*
+** GETSIMPLE -- callback to get userid or authid
+**
+** Parameters:
+** context -- sai
+** id -- what to do
+** result -- (pointer to) result
+** len -- (pointer to) length of result
+**
+** Returns:
+** OK/failure values
+*/
+
+static int
+getsimple(context, id, result, len)
+ void *context;
+ int id;
+ const char **result;
+ unsigned *len;
+{
+ SASL_AI_T *sai;
+
+ if (result == NULL || context == NULL)
+ return SASL_BADPARAM;
+ sai = (SASL_AI_T *) context;
+
+ switch (id)
+ {
+ case SASL_CB_USER:
+ *result = (*sai)[SASL_USER];
+ if (tTd(95, 5))
+ sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
+ *result);
+ if (len != NULL)
+ *len = *result != NULL ? strlen(*result) : 0;
+ break;
+
+ case SASL_CB_AUTHNAME:
+ *result = (*sai)[SASL_AUTHID];
+ if (tTd(95, 5))
+ sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
+ *result);
+ if (len != NULL)
+ *len = *result != NULL ? strlen(*result) : 0;
+ break;
+
+ case SASL_CB_LANGUAGE:
+ *result = NULL;
+ if (len != NULL)
+ *len = 0;
+ break;
+
+ default:
+ return SASL_BADPARAM;
+ }
+ return SASL_OK;
+}
+/*
+** GETSECRET -- callback to get password
+**
+** Parameters:
+** conn -- connection information
+** context -- sai
+** id -- what to do
+** psecret -- (pointer to) result
+**
+** Returns:
+** OK/failure values
+*/
+
+static int
+getsecret(conn, context, id, psecret)
+ sasl_conn_t *conn;
+ SM_UNUSED(void *context);
+ int id;
+ sasl_secret_t **psecret;
+{
+ int len;
+ char *authpass;
+ MCI *mci;
+
+ if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
+ return SASL_BADPARAM;
+
+ mci = (MCI *) context;
+ authpass = mci->mci_sai[SASL_PASSWORD];
+ len = strlen(authpass);
+
+ /*
+ ** use an rpool because we are responsible for free()ing the secret,
+ ** but we can't free() it until after the auth completes
+ */
+
+ *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
+ sizeof(sasl_secret_t) +
+ len + 1);
+ if (*psecret == NULL)
+ return SASL_FAIL;
+ (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
+ (*psecret)->len = (unsigned long) len;
+ return SASL_OK;
+}
+# else /* SASL >= 20000 */
/*
** GETSIMPLE -- callback to get userid or authid
**
@@ -1013,7 +1147,7 @@ getsimple(context, id, result, len)
(void) sm_strlcpy(s, (*sai)[SASL_USER], l);
*result = s;
if (tTd(95, 5))
- sm_syslog(LOG_WARNING, NOQID, "AUTH username '%s'",
+ sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
*result);
if (len != NULL)
*len = *result != NULL ? strlen(*result) : 0;
@@ -1084,7 +1218,7 @@ getsimple(context, id, result, len)
(void) sm_strlcpy(s, authid, l);
*result = s;
if (tTd(95, 5))
- sm_syslog(LOG_WARNING, NOQID, "AUTH authid '%s'",
+ sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
*result);
if (len != NULL)
*len = authid ? strlen(authid) : 0;
@@ -1139,6 +1273,8 @@ getsecret(conn, context, id, psecret)
(*psecret)->len = (unsigned long) len;
return SASL_OK;
}
+# endif /* SASL >= 20000 */
+
/*
** SAFESASLFILE -- callback for sasl: is file safe?
**
@@ -1161,9 +1297,17 @@ safesaslfile(context, file, type)
safesaslfile(context, file)
#endif /* SASL > 10515 */
void *context;
+# if SASL >= 20000
+ const char *file;
+# else /* SASL >= 20000 */
char *file;
+# endif /* SASL >= 20000 */
#if SASL > 10515
+# if SASL >= 20000
+ sasl_verify_type_t type;
+# else /* SASL >= 20000 */
int type;
+# endif /* SASL >= 20000 */
#endif /* SASL > 10515 */
{
long sff;
@@ -1205,7 +1349,7 @@ safesaslfile(context, file)
}
#endif /* SASL <= 10515 */
- p = file;
+ p = (char *) file;
if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
S_IRUSR, NULL)) == 0)
return SASL_OK;
@@ -1401,16 +1545,22 @@ attemptauth(m, mci, e, sai)
SASL_AI_T *sai;
{
int saslresult, smtpresult;
+# if SASL >= 20000
+ sasl_ssf_t ssf;
+ const char *auth_id;
+ const char *out;
+# else /* SASL >= 20000 */
sasl_external_properties_t ssf;
- sasl_interact_t *client_interact = NULL;
char *out;
+# endif /* SASL >= 20000 */
unsigned int outlen;
+ sasl_interact_t *client_interact = NULL;
char *mechusing;
sasl_security_properties_t ssp;
char in64[MAXOUTLEN];
-#if NETINET
+#if NETINET || (NETINET6 && SASL >= 20000)
extern SOCKADDR CurHostAddr;
-#endif /* NETINET */
+#endif /* NETINET || (NETINET6 && SASL >= 20000) */
/* no mechanism selected (yet) */
(*sai)[SASL_MECH] = NULL;
@@ -1420,9 +1570,16 @@ attemptauth(m, mci, e, sai)
sasl_dispose(&(mci->mci_conn));
/* make a new client sasl connection */
+# if SASL >= 20000
+ saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
+ : "smtp",
+ CurHostName, NULL, NULL, NULL, 0,
+ &mci->mci_conn);
+# else /* SASL >= 20000 */
saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
: "smtp",
CurHostName, NULL, 0, &mci->mci_conn);
+# endif /* SASL >= 20000 */
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
@@ -1443,22 +1600,96 @@ attemptauth(m, mci, e, sai)
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
+# if SASL >= 20000
+ /* external security strength factor, authentication id */
+ ssf = 0;
+ auth_id = NULL;
+# if STARTTLS
+ out = macvalue(macid("{cert_subject}"), e);
+ if (out != NULL && *out != '\0')
+ auth_id = out;
+ out = macvalue(macid("{cipher_bits}"), e);
+ if (out != NULL && *out != '\0')
+ ssf = atoi(out);
+# endif /* STARTTLS */
+ saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
+ if (saslresult != SASL_OK)
+ return EX_TEMPFAIL;
+ saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
+ if (saslresult != SASL_OK)
+ return EX_TEMPFAIL;
+
+# if NETINET || NETINET6
+ /* set local/remote ipv4 addresses */
+ if (mci->mci_out != NULL && (
+# if NETINET6
+ CurHostAddr.sa.sa_family == AF_INET6 ||
+# endif /* NETINET6 */
+ CurHostAddr.sa.sa_family == AF_INET))
+ {
+ SOCKADDR_LEN_T addrsize;
+ SOCKADDR saddr_l;
+ char localip[60], remoteip[60];
+
+ switch (CurHostAddr.sa.sa_family)
+ {
+ case AF_INET:
+ addrsize = sizeof(struct sockaddr_in);
+ break;
+# if NETINET6
+ case AF_INET6:
+ addrsize = sizeof(struct sockaddr_in6);
+ break;
+# endif /* NETINET6 */
+ default:
+ break;
+ }
+ if (iptostring(&CurHostAddr, addrsize,
+ remoteip, sizeof remoteip))
+ {
+ if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
+ remoteip) != SASL_OK)
+ return EX_TEMPFAIL;
+ }
+ addrsize = sizeof(saddr_l);
+ if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
+ NULL),
+ (struct sockaddr *) &saddr_l, &addrsize) == 0)
+ {
+ if (iptostring(&saddr_l, addrsize,
+ localip, sizeof localip))
+ {
+ if (sasl_setprop(mci->mci_conn,
+ SASL_IPLOCALPORT,
+ localip) != SASL_OK)
+ return EX_TEMPFAIL;
+ }
+ }
+ }
+# endif /* NETINET || NETINET6 */
+
+ /* start client side of sasl */
+ saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
+ &client_interact,
+ &out, &outlen,
+ (const char **) &mechusing);
+# else /* SASL >= 20000 */
/* external security strength factor, authentication id */
ssf.ssf = 0;
ssf.auth_id = NULL;
-#if STARTTLS
+# if STARTTLS
out = macvalue(macid("{cert_subject}"), e);
if (out != NULL && *out != '\0')
ssf.auth_id = out;
out = macvalue(macid("{cipher_bits}"), e);
if (out != NULL && *out != '\0')
ssf.ssf = atoi(out);
-#endif /* STARTTLS */
+# endif /* STARTTLS */
saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
-#if NETINET
+# if NETINET
/* set local/remote ipv4 addresses */
if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
{
@@ -1479,13 +1710,14 @@ attemptauth(m, mci, e, sai)
return EX_TEMPFAIL;
}
}
-#endif /* NETINET */
+# endif /* NETINET */
/* start client side of sasl */
saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
NULL, &client_interact,
&out, &outlen,
- (const char **)&mechusing);
+ (const char **) &mechusing);
+# endif /* SASL >= 20000 */
if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
{
@@ -1501,7 +1733,22 @@ attemptauth(m, mci, e, sai)
(*sai)[SASL_MECH] = mechusing;
/* send the info across the wire */
- if (outlen > 0)
+ if (out == NULL)
+ {
+ /* no initial response */
+ smtpmessage("AUTH %s", m, mci, mechusing);
+ }
+ else if (outlen == 0)
+ {
+ /*
+ ** zero-length initial response, per RFC 2554 4.:
+ ** "Unlike a zero-length client answer to a 334 reply, a zero-
+ ** length initial response is sent as a single equals sign"
+ */
+
+ smtpmessage("AUTH %s =", m, mci, mechusing);
+ }
+ else
{
saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL);
if (saslresult != SASL_OK) /* internal error */
@@ -1513,11 +1760,9 @@ attemptauth(m, mci, e, sai)
}
smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
}
- else
- {
- smtpmessage("AUTH %s", m, mci, mechusing);
- }
+# if SASL < 20000
sm_sasl_free(out); /* XXX only if no rpool is used */
+# endif /* SASL < 20000 */
/* get the reply */
smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL);
@@ -1581,7 +1826,9 @@ attemptauth(m, mci, e, sai)
}
else
in64[0] = '\0';
+# if SASL < 20000
sm_sasl_free(out); /* XXX only if no rpool is used */
+# endif /* SASL < 20000 */
smtpmessage("%s", m, mci, in64);
smtpresult = reply(m, mci, e, TimeOuts.to_auth,
getsasldata, NULL);
@@ -1660,12 +1907,16 @@ smtpauth(m, mci, e)
return EX_UNAVAILABLE;
/* set the context for the callback function to sai */
- callbacks[CB_PASS_IDX].context = (void *)&mci->mci_sai;
- callbacks[CB_USER_IDX].context = (void *)&mci->mci_sai;
- callbacks[CB_AUTHNAME_IDX].context = (void *)&mci->mci_sai;
- callbacks[CB_GETREALM_IDX].context = (void *)&mci->mci_sai;
+# if SASL >= 20000
+ callbacks[CB_PASS_IDX].context = (void *) mci;
+# else /* SASL >= 20000 */
+ callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
+# endif /* SASL >= 20000 */
+ callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
+ callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
+ callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
#if 0
- callbacks[CB_SAFESASL_IDX].context = (void *)&mci->mci_sai;
+ callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
#endif /* 0 */
/* set default value for realm */
OpenPOWER on IntegriCloud