sasldb.c | sasldb.c | |||
---|---|---|---|---|
/* SASL server API implementation | /* SASL server API implementation | |||
* Rob Siemborski | * Rob Siemborski | |||
* Tim Martin | * Tim Martin | |||
* $Id: sasldb.c,v 1.11 2006/04/03 10:58:19 mel Exp $ | * $Id: sasldb.c,v 1.17 2009/03/10 14:37:03 mel 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 59 | skipping to change at line 59 | |||
#include <stdio.h> | #include <stdio.h> | |||
#include "sasl.h" | #include "sasl.h" | |||
#include "saslutil.h" | #include "saslutil.h" | |||
#include "saslplug.h" | #include "saslplug.h" | |||
#include "../sasldb/sasldb.h" | #include "../sasldb/sasldb.h" | |||
#include "plugin_common.h" | #include "plugin_common.h" | |||
static void sasldb_auxprop_lookup(void *glob_context __attribute__((unused) ), | static int sasldb_auxprop_lookup(void *glob_context __attribute__((unused)) , | |||
sasl_server_params_t *sparams, | sasl_server_params_t *sparams, | |||
unsigned flags, | unsigned flags, | |||
const char *user, | const char *user, | |||
unsigned ulen) | unsigned ulen) | |||
{ | { | |||
char *userid = NULL; | char *userid = NULL; | |||
char *realm = NULL; | char *realm = NULL; | |||
const char *user_realm = NULL; | const char *user_realm = NULL; | |||
int ret; | int ret; | |||
const struct propval *to_fetch, *cur; | const struct propval *to_fetch, *cur; | |||
char value[8192]; | char value[8192]; | |||
size_t value_len; | size_t value_len; | |||
char *user_buf; | char *user_buf; | |||
int verify_against_hashed_password; | ||||
int saw_user_password = 0; | ||||
if(!sparams || !user) return; | if (!sparams || !user) return SASL_BADPARAM; | |||
user_buf = sparams->utils->malloc(ulen + 1); | user_buf = sparams->utils->malloc(ulen + 1); | |||
if(!user_buf) { | if(!user_buf) { | |||
ret = SASL_NOMEM; | ||||
goto done; | goto done; | |||
} | } | |||
memcpy(user_buf, user, ulen); | memcpy(user_buf, user, ulen); | |||
user_buf[ulen] = '\0'; | user_buf[ulen] = '\0'; | |||
if(sparams->user_realm) { | if(sparams->user_realm) { | |||
user_realm = sparams->user_realm; | user_realm = sparams->user_realm; | |||
} else { | } else { | |||
user_realm = sparams->serverFQDN; | user_realm = sparams->serverFQDN; | |||
} | } | |||
ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm, | ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm, | |||
sparams->serverFQDN, user_buf); | sparams->serverFQDN, user_buf); | |||
if(ret != SASL_OK) goto done; | if(ret != SASL_OK) goto done; | |||
to_fetch = sparams->utils->prop_get(sparams->propctx); | to_fetch = sparams->utils->prop_get(sparams->propctx); | |||
if(!to_fetch) goto done; | if (!to_fetch) { | |||
ret = SASL_NOMEM; | ||||
goto done; | ||||
} | ||||
verify_against_hashed_password = flags & SASL_AUXPROP_VERIFY_AGAINST_HA | ||||
SH; | ||||
/* Use a fake value to signal that we have no property to lookup */ | ||||
ret = SASL_CONTINUE; | ||||
for(cur = to_fetch; cur->name; cur++) { | for(cur = to_fetch; cur->name; cur++) { | |||
int cur_ret; | ||||
const char *realname = cur->name; | const char *realname = cur->name; | |||
/* Only look up properties that apply to this lookup! */ | /* Only look up properties that apply to this lookup! */ | |||
if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue; | if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue; | |||
if(!(flags & SASL_AUXPROP_AUTHZID)) { | if(!(flags & SASL_AUXPROP_AUTHZID)) { | |||
if(cur->name[0] != '*') continue; | if(cur->name[0] != '*') continue; | |||
else realname = cur->name + 1; | else realname = cur->name + 1; | |||
} | } | |||
/* If it's there already, we want to see if it needs to be | /* If it's there already, we want to see if it needs to be | |||
* overridden */ | * overridden. userPassword is a special case, because it's value | |||
if(cur->values && !(flags & SASL_AUXPROP_OVERRIDE)) | is always present if SASL_AUXPROP_VERIFY_AGAINST_HASH is specifie | |||
d. | ||||
When SASL_AUXPROP_VERIFY_AGAINST_HASH is set, we just clear userP | ||||
assword. */ | ||||
if (cur->values && !(flags & SASL_AUXPROP_OVERRIDE) && | ||||
(verify_against_hashed_password == 0 || | ||||
strcasecmp(realname, SASL_AUX_PASSWORD_PROP) != 0)) { | ||||
continue; | continue; | |||
else if(cur->values) | } else if (cur->values) { | |||
sparams->utils->prop_erase(sparams->propctx, cur->name); | sparams->utils->prop_erase(sparams->propctx, cur->name); | |||
} | ||||
if (strcasecmp(realname, SASL_AUX_PASSWORD_PROP) == 0) { | ||||
saw_user_password = 1; | ||||
} | ||||
ret = _sasldb_getdata(sparams->utils, | cur_ret = _sasldb_getdata(sparams->utils, | |||
sparams->utils->conn, userid, realm, | sparams->utils->conn, userid, realm, | |||
realname, value, sizeof(value), &value_len); | realname, value, sizeof(value), &value_len); | |||
if(ret != SASL_OK) { | ||||
/* Assumption: cur_ret is never SASL_CONTINUE */ | ||||
/* If this is the first property we've tried to fetch ==> | ||||
always set the global error code. | ||||
If we had SASL_NOUSER ==> any other error code overrides it | ||||
(including SASL_NOUSER). */ | ||||
if (ret == SASL_CONTINUE || ret == SASL_NOUSER) { | ||||
ret = cur_ret; | ||||
} else if (ret == SASL_OK) { | ||||
/* Any error code other than SASL_NOUSER overrides SASL_OK. | ||||
(And SASL_OK overrides SASL_OK as well) */ | ||||
if (cur_ret != SASL_NOUSER) { | ||||
ret = cur_ret; | ||||
} | ||||
} | ||||
/* Any other global error code is left as is */ | ||||
if (cur_ret != SASL_OK) { | ||||
if (cur_ret != SASL_NOUSER) { | ||||
/* No point in continuing if we hit any serious error */ | ||||
break; | ||||
} | ||||
/* We didn't find it, leave it as not found */ | /* We didn't find it, leave it as not found */ | |||
continue; | continue; | |||
} | } | |||
sparams->utils->prop_set(sparams->propctx, cur->name, | sparams->utils->prop_set(sparams->propctx, cur->name, | |||
value, (unsigned) value_len); | value, (unsigned) value_len); | |||
} | } | |||
/* [Keep in sync with LDAPDB, SQL] | ||||
If ret is SASL_CONTINUE, it means that no properties were requested | ||||
(or maybe some were requested, but they already have values and | ||||
SASL_AUXPROP_OVERRIDE flag is not set). | ||||
Always return SASL_OK in this case. */ | ||||
if (ret == SASL_CONTINUE) { | ||||
ret = SASL_OK; | ||||
} | ||||
if (flags & SASL_AUXPROP_AUTHZID) { | ||||
/* This is a lie, but the caller can't handle | ||||
when we return SASL_NOUSER for authorization identity lookup. */ | ||||
if (ret == SASL_NOUSER) { | ||||
ret = SASL_OK; | ||||
} | ||||
} else { | ||||
if (ret == SASL_NOUSER && saw_user_password == 0) { | ||||
/* Verify user existence by checking presence of | ||||
the userPassword attribute */ | ||||
ret = _sasldb_getdata(sparams->utils, | ||||
sparams->utils->conn, | ||||
userid, | ||||
realm, | ||||
SASL_AUX_PASSWORD_PROP, | ||||
value, | ||||
sizeof(value), | ||||
&value_len); | ||||
} | ||||
} | ||||
done: | done: | |||
if (userid) sparams->utils->free(userid); | if (userid) sparams->utils->free(userid); | |||
if (realm) sparams->utils->free(realm); | if (realm) sparams->utils->free(realm); | |||
if (user_buf) sparams->utils->free(user_buf); | if (user_buf) sparams->utils->free(user_buf); | |||
return ret; | ||||
} | } | |||
static int sasldb_auxprop_store(void *glob_context __attribute__((unused)), | static int sasldb_auxprop_store(void *glob_context __attribute__((unused)), | |||
sasl_server_params_t *sparams, | sasl_server_params_t *sparams, | |||
struct propctx *ctx, | struct propctx *ctx, | |||
const char *user, | const char *user, | |||
unsigned ulen) | unsigned ulen) | |||
{ | { | |||
char *userid = NULL; | char *userid = NULL; | |||
char *realm = NULL; | char *realm = NULL; | |||
const char *user_realm = NULL; | const char *user_realm = NULL; | |||
int ret = SASL_FAIL; | int ret = SASL_FAIL; | |||
int tmp_res; | ||||
const struct propval *to_store, *cur; | const struct propval *to_store, *cur; | |||
char *user_buf; | char *user_buf; | |||
/* just checking if we are enabled */ | /* just checking if we are enabled */ | |||
if(!ctx) return SASL_OK; | if(!ctx) return SASL_OK; | |||
if(!sparams || !user) return SASL_BADPARAM; | if(!sparams || !user) return SASL_BADPARAM; | |||
user_buf = sparams->utils->malloc(ulen + 1); | user_buf = sparams->utils->malloc(ulen + 1); | |||
if(!user_buf) { | if(!user_buf) { | |||
skipping to change at line 176 | skipping to change at line 249 | |||
ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm, | ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm, | |||
sparams->serverFQDN, user_buf); | sparams->serverFQDN, user_buf); | |||
if(ret != SASL_OK) goto done; | if(ret != SASL_OK) goto done; | |||
to_store = sparams->utils->prop_get(ctx); | to_store = sparams->utils->prop_get(ctx); | |||
if(!to_store) { | if(!to_store) { | |||
ret = SASL_BADPARAM; | ret = SASL_BADPARAM; | |||
goto done; | goto done; | |||
} | } | |||
/* All iterations return SASL_NOUSER ==> ret = SASL_N | ret = SASL_OK; | |||
OUSER | for (cur = to_store; cur->name; cur++) { | |||
Some iterations return SASL_OK and some SASL_NOUSER ==> ret = SASL_O | char * value = (cur->values && cur->values[0]) ? cur->values[0] : NU | |||
K | LL; | |||
At least one iteration returns any other error ==> ret = the er | ||||
ror */ | if (cur->name[0] == '*') { | |||
ret = SASL_NOUSER; | continue; | |||
for(cur = to_store; cur->name; cur++) { | } | |||
/* We only support one value at a time right now. */ | ||||
tmp_res = _sasldb_putdata(sparams->utils, sparams->utils->conn, | /* WARN: We only support one value right now. */ | |||
userid, realm, cur->name, | ret = _sasldb_putdata(sparams->utils, | |||
cur->values && cur->values[0] ? | sparams->utils->conn, | |||
cur->values[0] : NULL, | userid, | |||
cur->values && cur->values[0] ? | realm, | |||
strlen(cur->values[0]) : 0); | cur->name, | |||
/* SASL_NOUSER is returned when _sasldb_putdata fails to delete | value, | |||
a non-existent entry, which should not be treated as an error */ | value ? strlen(value) : 0); | |||
if ((tmp_res != SASL_NOUSER) && | ||||
(ret == SASL_NOUSER || ret == SASL_OK)) { | if (value == NULL && ret == SASL_NOUSER) { | |||
ret = tmp_res; | /* Deleting something which is not there is not an error */ | |||
} | ret = SASL_OK; | |||
} | ||||
/* Abort the loop if an error has occurred */ | ||||
if (ret != SASL_NOUSER && ret != SASL_OK) { | if (ret != SASL_OK) { | |||
break; | /* We've already failed, no point in continuing */ | |||
} | break; | |||
} | ||||
} | } | |||
done: | done: | |||
if (userid) sparams->utils->free(userid); | if (userid) sparams->utils->free(userid); | |||
if (realm) sparams->utils->free(realm); | if (realm) sparams->utils->free(realm); | |||
if (user_buf) sparams->utils->free(user_buf); | if (user_buf) sparams->utils->free(user_buf); | |||
return ret; | return ret; | |||
} | } | |||
skipping to change at line 233 | skipping to change at line 309 | |||
const char *plugname __attribute__((unused))) | const char *plugname __attribute__((unused))) | |||
{ | { | |||
if(!out_version || !plug) return SASL_BADPARAM; | if(!out_version || !plug) return SASL_BADPARAM; | |||
/* Do we have database support? */ | /* Do we have database support? */ | |||
/* Note that we can use a NULL sasl_conn_t because our | /* Note that we can use a NULL sasl_conn_t because our | |||
* sasl_utils_t is "blessed" with the global callbacks */ | * sasl_utils_t is "blessed" with the global callbacks */ | |||
if(_sasl_check_db(utils, NULL) != SASL_OK) | if(_sasl_check_db(utils, NULL) != SASL_OK) | |||
return SASL_NOMECH; | return SASL_NOMECH; | |||
/* Check if libsasl API is older than ours. If it is, fail */ | ||||
if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS; | if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS; | |||
*out_version = SASL_AUXPROP_PLUG_VERSION; | *out_version = SASL_AUXPROP_PLUG_VERSION; | |||
*plug = &sasldb_auxprop_plugin; | *plug = &sasldb_auxprop_plugin; | |||
return SASL_OK; | return SASL_OK; | |||
} | } | |||
End of changes. 18 change blocks. | ||||
36 lines changed or deleted | 114 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/ |