123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- /* SASL server API implementation
- * Rob Siemborski
- * Tim Martin
- */
- /*
- * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The name "Carnegie Mellon University" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For permission or any other legal
- * details, please contact
- * Carnegie Mellon University
- * Center for Technology Transfer and Enterprise Creation
- * 4615 Forbes Avenue
- * Suite 302
- * Pittsburgh, PA 15213
- * (412) 268-7393, fax: (412) 268-7395
- * innovation@andrew.cmu.edu
- *
- * 4. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by Computing Services
- * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
- *
- * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
- * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
- * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <config.h>
- /* sasldb stuff */
- #include <stdio.h>
- #include "sasl.h"
- #include "saslutil.h"
- #include "saslplug.h"
- #include "../sasldb/sasldb.h"
- #include "plugin_common.h"
- static int sasldb_auxprop_lookup(void *glob_context __attribute__((unused)),
- sasl_server_params_t *sparams,
- unsigned flags,
- const char *user,
- unsigned ulen)
- {
- char *userid = NULL;
- char *realm = NULL;
- const char *user_realm = NULL;
- int ret;
- const struct propval *to_fetch, *cur;
- char value[8192];
- size_t value_len;
- char *user_buf;
- int verify_against_hashed_password;
- int saw_user_password = 0;
- if (!sparams || !user) return SASL_BADPARAM;
- user_buf = sparams->utils->malloc(ulen + 1);
- if(!user_buf) {
- ret = SASL_NOMEM;
- goto done;
- }
- memcpy(user_buf, user, ulen);
- user_buf[ulen] = '\0';
- if(sparams->user_realm) {
- user_realm = sparams->user_realm;
- } else {
- user_realm = sparams->serverFQDN;
- }
- ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
- sparams->serverFQDN, user_buf);
- if(ret != SASL_OK) goto done;
- to_fetch = sparams->utils->prop_get(sparams->propctx);
- if (!to_fetch) {
- ret = SASL_NOMEM;
- goto done;
- }
- verify_against_hashed_password = flags & SASL_AUXPROP_VERIFY_AGAINST_HASH;
- /* Use a fake value to signal that we have no property to lookup */
- ret = SASL_CONTINUE;
- for(cur = to_fetch; cur->name; cur++) {
- int cur_ret;
- const char *realname = cur->name;
-
- /* Only look up properties that apply to this lookup! */
- if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue;
- if(!(flags & SASL_AUXPROP_AUTHZID)) {
- if(cur->name[0] != '*') continue;
- else realname = cur->name + 1;
- }
-
- /* If it's there already, we want to see if it needs to be
- * overridden. userPassword is a special case, because it's value
- is always present if SASL_AUXPROP_VERIFY_AGAINST_HASH is specified.
- When SASL_AUXPROP_VERIFY_AGAINST_HASH is set, we just clear userPassword. */
- if (cur->values && !(flags & SASL_AUXPROP_OVERRIDE) &&
- (verify_against_hashed_password == 0 ||
- strcasecmp(realname, SASL_AUX_PASSWORD_PROP) != 0)) {
- continue;
- } else if (cur->values) {
- sparams->utils->prop_erase(sparams->propctx, cur->name);
- }
- if (strcasecmp(realname, SASL_AUX_PASSWORD_PROP) == 0) {
- saw_user_password = 1;
- }
- cur_ret = _sasldb_getdata(sparams->utils,
- sparams->utils->conn, userid, realm,
- realname, value, sizeof(value), &value_len);
- /* 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 */
- continue;
- }
- sparams->utils->prop_set(sparams->propctx, cur->name,
- 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:
- if (userid) sparams->utils->free(userid);
- if (realm) sparams->utils->free(realm);
- if (user_buf) sparams->utils->free(user_buf);
- return ret;
- }
- static int sasldb_auxprop_store(void *glob_context __attribute__((unused)),
- sasl_server_params_t *sparams,
- struct propctx *ctx,
- const char *user,
- unsigned ulen)
- {
- char *userid = NULL;
- char *realm = NULL;
- const char *user_realm = NULL;
- int ret = SASL_FAIL;
- const struct propval *to_store, *cur;
- char *user_buf;
- /* just checking if we are enabled */
- if(!ctx) return SASL_OK;
-
- if(!sparams || !user) return SASL_BADPARAM;
- user_buf = sparams->utils->malloc(ulen + 1);
- if(!user_buf) {
- ret = SASL_NOMEM;
- goto done;
- }
- memcpy(user_buf, user, ulen);
- user_buf[ulen] = '\0';
- if(sparams->user_realm) {
- user_realm = sparams->user_realm;
- } else {
- user_realm = sparams->serverFQDN;
- }
- ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
- sparams->serverFQDN, user_buf);
- if(ret != SASL_OK) goto done;
- to_store = sparams->utils->prop_get(ctx);
- if(!to_store) {
- ret = SASL_BADPARAM;
- goto done;
- }
- ret = SASL_OK;
- for (cur = to_store; cur->name; cur++) {
- const char *value = (cur->values && cur->values[0]) ? cur->values[0] : NULL;
- if (cur->name[0] == '*') {
- continue;
- }
- /* WARN: We only support one value right now. */
- ret = _sasldb_putdata(sparams->utils,
- sparams->utils->conn,
- userid,
- realm,
- cur->name,
- value,
- value ? strlen(value) : 0);
- if (value == NULL && ret == SASL_NOUSER) {
- /* Deleting something which is not there is not an error */
- ret = SASL_OK;
- }
- if (ret != SASL_OK) {
- /* We've already failed, no point in continuing */
- break;
- }
- }
- done:
- if (userid) sparams->utils->free(userid);
- if (realm) sparams->utils->free(realm);
- if (user_buf) sparams->utils->free(user_buf);
- return ret;
- }
- static sasl_auxprop_plug_t sasldb_auxprop_plugin = {
- 0, /* Features */
- 0, /* spare */
- NULL, /* glob_context */
- sasldb_auxprop_free, /* auxprop_free */
- sasldb_auxprop_lookup, /* auxprop_lookup */
- "sasldb", /* name */
- sasldb_auxprop_store /* auxprop_store */
- };
- int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
- int max_version,
- int *out_version,
- sasl_auxprop_plug_t **plug,
- const char *plugname __attribute__((unused)))
- {
- if(!out_version || !plug) return SASL_BADPARAM;
- /* Do we have database support? */
- /* Note that we can use a NULL sasl_conn_t because our
- * sasl_utils_t is "blessed" with the global callbacks */
- if(_sasl_check_db(utils, NULL) != SASL_OK)
- 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;
-
- *out_version = SASL_AUXPROP_PLUG_VERSION;
- *plug = &sasldb_auxprop_plugin;
- return SASL_OK;
- }
|