diff options
Diffstat (limited to 'crypto/heimdal/lib/hdb/hdb.c')
-rw-r--r-- | crypto/heimdal/lib/hdb/hdb.c | 220 |
1 files changed, 196 insertions, 24 deletions
diff --git a/crypto/heimdal/lib/hdb/hdb.c b/crypto/heimdal/lib/hdb/hdb.c index 95fde19..a515709 100644 --- a/crypto/heimdal/lib/hdb/hdb.c +++ b/crypto/heimdal/lib/hdb/hdb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,11 @@ #include "hdb_locl.h" -RCSID("$Id: hdb.c,v 1.44 2001/08/09 08:41:48 assar Exp $"); +RCSID("$Id: hdb.c 20214 2007-02-09 21:51:10Z lha $"); + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif struct hdb_method { const char *prefix; @@ -47,19 +51,23 @@ static struct hdb_method methods[] = { #if HAVE_NDBM {"ndbm:", hdb_ndbm_create}, #endif -#ifdef OPENLDAP +#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE) {"ldap:", hdb_ldap_create}, + {"ldapi:", hdb_ldapi_create}, #endif -#if HAVE_DB1 || HAVE_DB3 - {"", hdb_db_create}, -#elif defined(HAVE_NDBM) - {"", hdb_ndbm_create}, -#elif defined(OPENLDAP) - {"", hdb_ldap_create}, +#ifdef HAVE_LDB /* Used for integrated samba build */ + {"ldb:", hdb_ldb_create}, #endif {NULL, NULL} }; +#if HAVE_DB1 || HAVE_DB3 +static struct hdb_method dbmetod = {"", hdb_db_create }; +#elif defined(HAVE_NDBM) +static struct hdb_method dbmetod = {"", hdb_ndbm_create }; +#endif + + krb5_error_code hdb_next_enctype2key(krb5_context context, const hdb_entry *e, @@ -70,11 +78,15 @@ hdb_next_enctype2key(krb5_context context, for (k = *key ? (*key) + 1 : e->keys.val; k < e->keys.val + e->keys.len; - k++) + k++) + { if(k->key.keytype == enctype){ *key = k; return 0; } + } + krb5_set_error_string(context, "No next enctype %d for hdb-entry", + (int)enctype); return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ } @@ -128,16 +140,19 @@ hdb_unlock(int fd) } void -hdb_free_entry(krb5_context context, hdb_entry *ent) +hdb_free_entry(krb5_context context, hdb_entry_ex *ent) { int i; - for(i = 0; i < ent->keys.len; ++i) { - Key *k = &ent->keys.val[i]; + if (ent->free_entry) + (*ent->free_entry)(context, ent); + + for(i = 0; i < ent->entry.keys.len; ++i) { + Key *k = &ent->entry.keys.val[i]; memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); } - free_hdb_entry(ent); + free_hdb_entry(&ent->entry); } krb5_error_code @@ -148,13 +163,15 @@ hdb_foreach(krb5_context context, void *data) { krb5_error_code ret; - hdb_entry entry; - ret = db->firstkey(context, db, flags, &entry); + hdb_entry_ex entry; + ret = db->hdb_firstkey(context, db, flags, &entry); + if (ret == 0) + krb5_clear_error_string(context); while(ret == 0){ ret = (*func)(context, db, &entry, data); hdb_free_entry(context, &entry); if(ret == 0) - ret = db->nextkey(context, db, flags, &entry); + ret = db->hdb_nextkey(context, db, flags, &entry); } if(ret == HDB_ERR_NOENTRY) ret = 0; @@ -166,15 +183,22 @@ hdb_check_db_format(krb5_context context, HDB *db) { krb5_data tag; krb5_data version; - krb5_error_code ret; + krb5_error_code ret, ret2; unsigned ver; int foo; + ret = db->hdb_lock(context, db, HDB_RLOCK); + if (ret) + return ret; + tag.data = HDB_DB_FORMAT_ENTRY; tag.length = strlen(tag.data); - ret = (*db->_get)(context, db, tag, &version); + ret = (*db->hdb__get)(context, db, tag, &version); + ret2 = db->hdb_unlock(context, db); if(ret) return ret; + if (ret2) + return ret2; foo = sscanf(version.data, "%u", &ver); krb5_data_free (&version); if (foo != 1) @@ -187,7 +211,7 @@ hdb_check_db_format(krb5_context context, HDB *db) krb5_error_code hdb_init_db(krb5_context context, HDB *db) { - krb5_error_code ret; + krb5_error_code ret, ret2; krb5_data tag; krb5_data version; char ver[32]; @@ -196,15 +220,118 @@ hdb_init_db(krb5_context context, HDB *db) if(ret != HDB_ERR_NOENTRY) return ret; + ret = db->hdb_lock(context, db, HDB_WLOCK); + if (ret) + return ret; + tag.data = HDB_DB_FORMAT_ENTRY; tag.length = strlen(tag.data); snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT); version.data = ver; version.length = strlen(version.data) + 1; /* zero terminated */ - ret = (*db->_put)(context, db, 0, tag, version); - return ret; + ret = (*db->hdb__put)(context, db, 0, tag, version); + ret2 = db->hdb_unlock(context, db); + if (ret) { + if (ret2) + krb5_clear_error_string(context); + return ret; + } + return ret2; } +#ifdef HAVE_DLOPEN + + /* + * Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so, + * looking for the hdb_NAME_create symbol. + */ + +static const struct hdb_method * +find_dynamic_method (krb5_context context, + const char *filename, + const char **rest) +{ + static struct hdb_method method; + struct hdb_so_method *mso; + char *prefix, *path, *symbol; + const char *p; + void *dl; + size_t len; + + p = strchr(filename, ':'); + + /* if no prefix, don't know what module to load, just ignore it */ + if (p == NULL) + return NULL; + + len = p - filename; + *rest = filename + len + 1; + + prefix = strndup(filename, len); + if (prefix == NULL) + krb5_errx(context, 1, "out of memory"); + + if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1) + krb5_errx(context, 1, "out of memory"); + +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + + dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (dl == NULL) { + krb5_warnx(context, "error trying to load dynamic module %s: %s\n", + path, dlerror()); + free(prefix); + free(path); + return NULL; + } + + if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1) + krb5_errx(context, 1, "out of memory"); + + mso = dlsym(dl, symbol); + if (mso == NULL) { + krb5_warnx(context, "error finding symbol %s in %s: %s\n", + symbol, path, dlerror()); + dlclose(dl); + free(symbol); + free(prefix); + free(path); + return NULL; + } + free(path); + free(symbol); + + if (mso->version != HDB_INTERFACE_VERSION) { + krb5_warnx(context, + "error wrong version in shared module %s " + "version: %d should have been %d\n", + prefix, mso->version, HDB_INTERFACE_VERSION); + dlclose(dl); + free(prefix); + return NULL; + } + + if (mso->create == NULL) { + krb5_errx(context, 1, + "no entry point function in shared mod %s ", + prefix); + dlclose(dl); + free(prefix); + return NULL; + } + + method.create = mso->create; + method.prefix = prefix; + + return &method; +} +#endif /* HAVE_DLOPEN */ + /* * find the relevant method for `filename', returning a pointer to the * rest in `rest'. @@ -216,15 +343,56 @@ find_method (const char *filename, const char **rest) { const struct hdb_method *h; - for (h = methods; h->prefix != NULL; ++h) + for (h = methods; h->prefix != NULL; ++h) { if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) { *rest = filename + strlen(h->prefix); return h; } + } +#if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_NDBM) + if (strncmp(filename, "/", 1) == 0 + || strncmp(filename, "./", 2) == 0 + || strncmp(filename, "../", 3) == 0) + { + *rest = filename; + return &dbmetod; + } +#endif + return NULL; } krb5_error_code +hdb_list_builtin(krb5_context context, char **list) +{ + const struct hdb_method *h; + size_t len = 0; + char *buf = NULL; + + for (h = methods; h->prefix != NULL; ++h) { + if (h->prefix[0] == '\0') + continue; + len += strlen(h->prefix) + 2; + } + + len += 1; + buf = malloc(len); + if (buf == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + buf[0] = '\0'; + + for (h = methods; h->prefix != NULL; ++h) { + if (h != methods) + strlcat(buf, ", ", len); + strlcat(buf, h->prefix, len); + } + *list = buf; + return 0; +} + +krb5_error_code hdb_create(krb5_context context, HDB **db, const char *filename) { const struct hdb_method *h; @@ -234,7 +402,11 @@ hdb_create(krb5_context context, HDB **db, const char *filename) filename = HDB_DEFAULT_DB; krb5_add_et_list(context, initialize_hdb_error_table_r); h = find_method (filename, &residual); +#ifdef HAVE_DLOPEN + if (h == NULL) + h = find_dynamic_method (context, filename, &residual); +#endif if (h == NULL) - krb5_errx(context, 1, "No database support! (hdb_create)"); + krb5_errx(context, 1, "No database support for %s", filename); return (*h->create)(context, db, residual); } |