checkpw.c   checkpw.c 
/* SASL server API implementation /* SASL server API implementation
* Rob Siemborski * Rob Siemborski
* Tim Martin * Tim Martin
* $Id: checkpw.c,v 1.73 2006/03/13 18:30:41 mel Exp $ * $Id: checkpw.c,v 1.79 2009/05/08 00:43:44 murch Exp $
*/ */
/* /*
* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved . * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved .
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
skipping to change at line 77 skipping to change at line 77
#ifndef WIN32 #ifndef WIN32
#include <strings.h> #include <strings.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/un.h> #include <sys/un.h>
#else #else
#include <string.h> #include <string.h>
#endif #endif
#include <limits.h>
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#ifdef HAVE_PWD_H #ifdef HAVE_PWD_H
#include <pwd.h> #include <pwd.h>
#endif /* HAVE_PWD_H */ #endif /* HAVE_PWD_H */
#ifdef HAVE_SHADOW_H #ifdef HAVE_SHADOW_H
#include <shadow.h> #include <shadow.h>
#endif /* HAVE_SHADOW_H */ #endif /* HAVE_SHADOW_H */
skipping to change at line 128 skipping to change at line 129
_sasl_MD5Update(&ctx, "sasldb", 6); _sasl_MD5Update(&ctx, "sasldb", 6);
_sasl_MD5Update(&ctx, passwd, (unsigned int) passlen); _sasl_MD5Update(&ctx, passwd, (unsigned int) passlen);
memcpy((*secret)->data, salt, 16); memcpy((*secret)->data, salt, 16);
(*secret)->data[16] = '\0'; (*secret)->data[16] = '\0';
_sasl_MD5Final((*secret)->data + 17, &ctx); _sasl_MD5Final((*secret)->data + 17, &ctx);
(*secret)->len = sec_len; (*secret)->len = sec_len;
return SASL_OK; return SASL_OK;
} }
/* erase & dispose of a sasl_secret_t /* verify user password using auxprop plugins
*/ */
static int auxprop_verify_password(sasl_conn_t *conn, static int auxprop_verify_password(sasl_conn_t *conn,
const char *userstr, const char *userstr,
const char *passwd, const char *passwd,
const char *service __attribute__((unused )), const char *service __attribute__((unused )),
const char *user_realm __attribute__((unu sed))) const char *user_realm __attribute__((unu sed)))
{ {
int ret = SASL_FAIL; int ret = SASL_FAIL;
char *userid = NULL;
char *realm = NULL;
int result = SASL_OK; int result = SASL_OK;
sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn; sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
const char *password_request[] = { SASL_AUX_PASSWORD, const char *password_request[] = { SASL_AUX_PASSWORD,
"*cmusaslsecretPLAIN", "*cmusaslsecretPLAIN",
NULL }; NULL };
struct propval auxprop_values[3]; struct propval auxprop_values[3];
if (!conn || !userstr) if (!conn || !userstr)
return SASL_BADPARAM; return SASL_BADPARAM;
/* We need to clear any previous results and re-canonify to /* We need to clear any previous results and re-canonify to
* ensure correctness */ * ensure correctness */
prop_clear(sconn->sparams->propctx, 0); prop_clear (sconn->sparams->propctx, 0);
/* ensure its requested */ /* ensure its requested */
result = prop_request(sconn->sparams->propctx, password_request); result = prop_request(sconn->sparams->propctx, password_request);
if(result != SASL_OK) return result; if(result != SASL_OK) return result;
result = _sasl_canon_user(conn, userstr, 0, result = _sasl_canon_user_lookup (conn,
SASL_CU_AUTHID | SASL_CU_AUTHZID, userstr,
&(conn->oparams)); 0,
SASL_CU_AUTHID | SASL_CU_AUTHZID,
&(conn->oparams));
if(result != SASL_OK) return result; if(result != SASL_OK) return result;
result = prop_getnames(sconn->sparams->propctx, password_request, result = prop_getnames(sconn->sparams->propctx, password_request,
auxprop_values); auxprop_values);
if(result < 0) if (result < 0) {
return result; return result;
}
if((!auxprop_values[0].name /* Verify that the returned <name>s are correct.
|| !auxprop_values[0].values || !auxprop_values[0].values[0]) But we defer checking for NULL values till after we verify
&& (!auxprop_values[1].name that a passwd is specified. */
|| !auxprop_values[1].values || !auxprop_values[1].values[0])) if (!auxprop_values[0].name && !auxprop_values[1].name) {
return SASL_NOUSER; return SASL_NOUSER;
}
/* It is possible for us to get useful information out of just /* It is possible for us to get useful information out of just
* the lookup, so we won't check that we have a password until now */ * the lookup, so we won't check that we have a password until now */
if(!passwd) { if(!passwd) {
ret = SASL_BADPARAM; ret = SASL_BADPARAM;
goto done; goto done;
} }
if ((!auxprop_values[0].values || !auxprop_values[0].values[0])
&& (!auxprop_values[1].values || !auxprop_values[1].values[0])) {
return SASL_NOUSER;
}
/* At the point this has been called, the username has been canonified /* At the point this has been called, the username has been canonified
* and we've done the auxprop lookup. This should be easy. */ * and we've done the auxprop lookup. This should be easy. */
if(auxprop_values[0].name if(auxprop_values[0].name
&& auxprop_values[0].values && auxprop_values[0].values
&& auxprop_values[0].values[0] && auxprop_values[0].values[0]
&& !strcmp(auxprop_values[0].values[0], passwd)) { && !strcmp(auxprop_values[0].values[0], passwd)) {
/* We have a plaintext version and it matched! */ /* We have a plaintext version and it matched! */
return SASL_OK; return SASL_OK;
} else if(auxprop_values[1].name } else if(auxprop_values[1].name
&& auxprop_values[1].values && auxprop_values[1].values
skipping to change at line 222 skipping to change at line 230
} else { } else {
/* passwords do not match */ /* passwords do not match */
ret = SASL_BADAUTH; ret = SASL_BADAUTH;
} }
/* erase the plaintext password */ /* erase the plaintext password */
sconn->sparams->utils->prop_erase(sconn->sparams->propctx, sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
password_request[0]); password_request[0]);
done: done:
if (userid) sasl_FREE(userid); /* We're not going to erase the property here because other people
if (realm) sasl_FREE(realm); * may want it */
return ret;
}
/* Verify user password using auxprop plugins. Allow verification against a
hashed password,
* or non-retrievable password. Don't use cmusaslsecretPLAIN attribute.
*
* This function is similar to auxprop_verify_password().
*/
static int auxprop_verify_password_hashed(sasl_conn_t *conn,
const char *userstr,
const char *passwd,
const char *service __attribute__(
(unused)),
const char *user_realm __attribute
__((unused)))
{
int ret = SASL_FAIL;
int result = SASL_OK;
sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
const char *password_request[] = { SASL_AUX_PASSWORD,
NULL };
struct propval auxprop_values[2];
unsigned extra_cu_flags = 0;
if (!conn || !userstr)
return SASL_BADPARAM;
/* We need to clear any previous results and re-canonify to
* ensure correctness */
prop_clear(sconn->sparams->propctx, 0);
/* ensure its requested */
result = prop_request(sconn->sparams->propctx, password_request);
if (result != SASL_OK) return result;
/* We need to pass "password" down to the auxprop_lookup */
/* NB: We don't support binary passwords */
if (passwd != NULL) {
prop_set (sconn->sparams->propctx,
SASL_AUX_PASSWORD,
passwd,
-1);
extra_cu_flags = SASL_CU_VERIFY_AGAINST_HASH;
}
result = _sasl_canon_user_lookup (conn,
userstr,
0,
SASL_CU_AUTHID | SASL_CU_AUTHZID | ext
ra_cu_flags,
&(conn->oparams));
if (result != SASL_OK) return result;
result = prop_getnames(sconn->sparams->propctx, password_request,
auxprop_values);
if (result < 0) {
return result;
}
/* Verify that the returned <name>s are correct.
But we defer checking for NULL values till after we verify
that a passwd is specified. */
if (!auxprop_values[0].name && !auxprop_values[1].name) {
return SASL_NOUSER;
}
/* It is possible for us to get useful information out of just
* the lookup, so we won't check that we have a password until now */
if (!passwd) {
ret = SASL_BADPARAM;
goto done;
}
if ((!auxprop_values[0].values || !auxprop_values[0].values[0])) {
return SASL_NOUSER;
}
/* At the point this has been called, the username has been canonified
* and we've done the auxprop lookup. This should be easy. */
/* NB: Note that if auxprop_lookup failed to verify the password,
then the userPassword property value would be NULL */
if (auxprop_values[0].name
&& auxprop_values[0].values
&& auxprop_values[0].values[0]
&& !strcmp(auxprop_values[0].values[0], passwd)) {
/* We have a plaintext version and it matched! */
return SASL_OK;
} else {
/* passwords do not match */
ret = SASL_BADAUTH;
}
done:
/* We're not going to erase the property here because other people /* We're not going to erase the property here because other people
* may want it */ * may want it */
return ret; return ret;
} }
#ifdef DO_SASL_CHECKAPOP #ifdef DO_SASL_CHECKAPOP
int _sasl_auxprop_verify_apop(sasl_conn_t *conn, int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
const char *userstr, const char *userstr,
const char *challenge, const char *challenge,
const char *response, const char *response,
skipping to change at line 592 skipping to change at line 693
*rtmp = '\0'; *rtmp = '\0';
user_realm = rtmp + 1; user_realm = rtmp + 1;
} }
/* /*
* build request of the form: * build request of the form:
* *
* count authid count password count service count realm * count authid count password count service count realm
*/ */
{ {
unsigned short u_len, p_len, s_len, r_len; unsigned short max_len, req_len, u_len, p_len, s_len, r_len;
max_len = (unsigned short) sizeof(query);
/* prevent buffer overflow */
if ((strlen(userid) > USHRT_MAX) ||
(strlen(passwd) > USHRT_MAX) ||
(strlen(service) > USHRT_MAX) ||
(user_realm && (strlen(user_realm) > USHRT_MAX))) {
goto toobig;
}
u_len = (strlen(userid)); u_len = (strlen(userid));
p_len = (strlen(passwd)); p_len = (strlen(passwd));
s_len = (strlen(service)); s_len = (strlen(service));
r_len = ((user_realm ? strlen(user_realm) : 0)); r_len = ((user_realm ? strlen(user_realm) : 0));
if (u_len + p_len + s_len + r_len + 30 > (unsigned short) sizeof(que /* prevent buffer overflow */
ry)) { req_len = 30;
/* request just too damn big */ if (max_len - req_len < u_len) goto toobig;
sasl_seterror(conn, 0, "saslauthd request too large"); req_len += u_len;
goto fail; if (max_len - req_len < p_len) goto toobig;
} req_len += p_len;
if (max_len - req_len < s_len) goto toobig;
req_len += s_len;
if (max_len - req_len < r_len) goto toobig;
u_len = htons(u_len); u_len = htons(u_len);
p_len = htons(p_len); p_len = htons(p_len);
s_len = htons(s_len); s_len = htons(s_len);
r_len = htons(r_len); r_len = htons(r_len);
memcpy(query_end, &u_len, sizeof(unsigned short)); memcpy(query_end, &u_len, sizeof(unsigned short));
query_end += sizeof(unsigned short); query_end += sizeof(unsigned short);
while (*userid) *query_end++ = *userid++; while (*userid) *query_end++ = *userid++;
skipping to change at line 734 skipping to change at line 849
if(freeme) free(freeme); if(freeme) free(freeme);
if (!strncmp(response, "OK", 2)) { if (!strncmp(response, "OK", 2)) {
return SASL_OK; return SASL_OK;
} }
sasl_seterror(conn, SASL_NOLOG, "authentication failed"); sasl_seterror(conn, SASL_NOLOG, "authentication failed");
return SASL_BADAUTH; return SASL_BADAUTH;
toobig:
/* request just too damn big */
sasl_seterror(conn, 0, "saslauthd request too large");
fail: fail:
if (freeme) free(freeme); if (freeme) free(freeme);
return SASL_FAIL; return SASL_FAIL;
} }
#endif #endif
#ifdef HAVE_AUTHDAEMON #ifdef HAVE_AUTHDAEMON
/* /*
* Preliminary support for Courier's authdaemond. * Preliminary support for Courier's authdaemond.
skipping to change at line 963 skipping to change at line 1082
const char *user_realm __attribute__((unused))) const char *user_realm __attribute__((unused)))
{ {
_sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s", _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
userstr); userstr);
return SASL_OK; return SASL_OK;
} }
#endif #endif
struct sasl_verify_password_s _sasl_verify_password[] = { struct sasl_verify_password_s _sasl_verify_password[] = {
{ "auxprop", &auxprop_verify_password }, { "auxprop", &auxprop_verify_password },
{ "auxprop-hashed", &auxprop_verify_password_hashed },
#ifdef HAVE_PWCHECK #ifdef HAVE_PWCHECK
{ "pwcheck", &pwcheck_verify_password }, { "pwcheck", &pwcheck_verify_password },
#endif #endif
#ifdef HAVE_SASLAUTHD #ifdef HAVE_SASLAUTHD
{ "saslauthd", &saslauthd_verify_password }, { "saslauthd", &saslauthd_verify_password },
#endif #endif
#ifdef HAVE_AUTHDAEMON #ifdef HAVE_AUTHDAEMON
{ "authdaemond", &authdaemon_verify_password }, { "authdaemond", &authdaemon_verify_password },
#endif #endif
#ifdef HAVE_ALWAYSTRUE #ifdef HAVE_ALWAYSTRUE
 End of changes. 16 change blocks. 
23 lines changed or deleted 146 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/