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/ |