/*
* Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * 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.
+ * 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.
+ * 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. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#include "hdb_locl.h"
/* keytab backend for HDB databases */
-RCSID("$Id: keytab.c,v 1.11 2006/04/27 11:01:30 lha Exp $");
-
struct hdb_data {
char *dbname;
- char *mkey;
+ char *mkey;
+};
+
+struct hdb_cursor {
+ HDB *db;
+ hdb_entry_ex hdb_entry;
+ int first, next;
+ int key_idx;
};
/*
d = malloc(sizeof(*d));
if(d == NULL) {
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
db = name;
- mkey = strrchr(name, ':');
+ mkey = strchr(name, ':');
if(mkey == NULL || mkey[1] == '\0') {
if(*name == '\0')
d->dbname = NULL;
d->dbname = strdup(name);
if(d->dbname == NULL) {
free(d);
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
}
d->dbname = malloc(mkey - db + 1);
if(d->dbname == NULL) {
free(d);
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
memmove(d->dbname, db, mkey - db);
if(d->mkey == NULL) {
free(d->dbname);
free(d);
- krb5_set_error_string(context, "malloc: out of memory");
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
}
return 0;
}
-static krb5_error_code
-hdb_get_name(krb5_context context,
- krb5_keytab id,
- char *name,
+static krb5_error_code
+hdb_get_name(krb5_context context,
+ krb5_keytab id,
+ char *name,
size_t namesize)
{
struct hdb_data *d = id->data;
- snprintf(name, namesize, "%s%s%s",
+ snprintf(name, namesize, "%s%s%s",
d->dbname ? d->dbname : "",
(d->dbname || d->mkey) ? ":" : "",
d->mkey ? d->mkey : "");
return 0;
}
-static void
-set_config (krb5_context context,
- const krb5_config_binding *binding,
- const char **dbname,
- const char **mkey)
-{
- *dbname = krb5_config_get_string(context, binding, "dbname", NULL);
- *mkey = krb5_config_get_string(context, binding, "mkey_file", NULL);
-}
-
/*
* try to figure out the database (`dbname') and master-key (`mkey')
* that should be used for `principal'.
*/
-static void
+static krb5_error_code
find_db (krb5_context context,
- const char **dbname,
- const char **mkey,
+ char **dbname,
+ char **mkey,
krb5_const_principal principal)
{
- const krb5_config_binding *top_bind = NULL;
- const krb5_config_binding *default_binding = NULL;
- const krb5_config_binding *db;
- krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal));
+ krb5_const_realm realm = krb5_principal_get_realm(context, principal);
+ krb5_error_code ret;
+ struct hdb_dbinfo *head, *dbinfo = NULL;
*dbname = *mkey = NULL;
- while ((db =
- krb5_config_get_next(context,
- NULL,
- &top_bind,
- krb5_config_list,
- "kdc",
- "database",
- NULL)) != NULL) {
- const char *p;
-
- p = krb5_config_get_string (context, db, "realm", NULL);
- if (p == NULL) {
- if(default_binding) {
- krb5_warnx(context, "WARNING: more than one realm-less "
- "database specification");
- krb5_warnx(context, "WARNING: using the first encountered");
- } else
- default_binding = db;
- } else if (strcmp (*prealm, p) == 0) {
- set_config (context, db, dbname, mkey);
+ ret = hdb_get_dbinfo(context, &head);
+ if (ret)
+ return ret;
+
+ while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) {
+ const char *p = hdb_dbinfo_get_realm(context, dbinfo);
+ if (p && strcmp (realm, p) == 0) {
+ p = hdb_dbinfo_get_dbname(context, dbinfo);
+ if (p)
+ *dbname = strdup(p);
+ p = hdb_dbinfo_get_mkey_file(context, dbinfo);
+ if (p)
+ *mkey = strdup(p);
break;
}
}
- if (*dbname == NULL && default_binding != NULL)
- set_config (context, default_binding, dbname, mkey);
+ hdb_free_dbinfo(context, &head);
if (*dbname == NULL)
- *dbname = HDB_DEFAULT_DB;
+ *dbname = strdup(HDB_DEFAULT_DB);
+ return 0;
}
/*
hdb_entry_ex ent;
krb5_error_code ret;
struct hdb_data *d = id->data;
- int i;
- HDB *db;
const char *dbname = d->dbname;
const char *mkey = d->mkey;
+ char *fdbname = NULL, *fmkey = NULL;
+ HDB *db;
+ int i;
- if (dbname == NULL)
- find_db (context, &dbname, &mkey, principal);
+ memset(&ent, 0, sizeof(ent));
+
+ if (dbname == NULL) {
+ ret = find_db(context, &fdbname, &fmkey, principal);
+ if (ret)
+ return ret;
+ dbname = fdbname;
+ mkey = fmkey;
+ }
ret = hdb_create (context, &db, dbname);
if (ret)
- return ret;
+ goto out2;
ret = hdb_set_master_keyfile (context, db, mkey);
if (ret) {
(*db->hdb_destroy)(context, db);
- return ret;
+ goto out2;
}
ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
if (ret) {
(*db->hdb_destroy)(context, db);
- return ret;
+ goto out2;
}
- ret = (*db->hdb_fetch)(context, db, principal, HDB_F_DECRYPT|HDB_F_GET_CLIENT|HDB_F_GET_SERVER, &ent);
-
+ ret = (*db->hdb_fetch)(context, db, principal,
+ HDB_F_DECRYPT|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ &ent);
- /* Shutdown the hdb on error */
if(ret == HDB_ERR_NOENTRY) {
- (*db->hdb_close)(context, db);
- (*db->hdb_destroy)(context, db);
- return KRB5_KT_NOTFOUND;
- } else if (ret) {
- (*db->hdb_close)(context, db);
- (*db->hdb_destroy)(context, db);
- return ret;
- }
+ ret = KRB5_KT_NOTFOUND;
+ goto out;
+ }else if(ret)
+ goto out;
+
if(kvno && ent.entry.kvno != kvno) {
- /* The order here matters, we must free these in this order
- * due to hdb-ldb and Samba4's talloc */
hdb_free_entry(context, &ent);
- (*db->hdb_close)(context, db);
- (*db->hdb_destroy)(context, db);
- return KRB5_KT_NOTFOUND;
+ ret = KRB5_KT_NOTFOUND;
+ goto out;
}
if(enctype == 0)
if(ent.entry.keys.len > 0)
if(ent.entry.keys.val[i].key.keytype == enctype) {
krb5_copy_principal(context, principal, &entry->principal);
entry->vno = ent.entry.kvno;
- krb5_copy_keyblock_contents(context,
- &ent.entry.keys.val[i].key,
+ krb5_copy_keyblock_contents(context,
+ &ent.entry.keys.val[i].key,
&entry->keyblock);
ret = 0;
break;
}
}
- /* The order here matters, we must free these in this order
- * due to hdb-ldb and Samba4's talloc */
hdb_free_entry(context, &ent);
+ out:
(*db->hdb_close)(context, db);
(*db->hdb_destroy)(context, db);
+ out2:
+ free(fdbname);
+ free(fmkey);
+ return ret;
+}
+
+/*
+ * find the keytab entry in `id' for `principal, kvno, enctype' and return
+ * it in `entry'. return 0 or an error code
+ */
+
+static krb5_error_code
+hdb_start_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ krb5_error_code ret;
+ struct hdb_cursor *c;
+ struct hdb_data *d = id->data;
+ const char *dbname = d->dbname;
+ const char *mkey = d->mkey;
+ HDB *db;
+
+ if (dbname == NULL) {
+ /*
+ * We don't support enumerating without being told what
+ * backend to enumerate on
+ */
+ ret = KRB5_KT_NOTFOUND;
+ return ret;
+ }
+
+ ret = hdb_create (context, &db, dbname);
+ if (ret)
+ return ret;
+ ret = hdb_set_master_keyfile (context, db, mkey);
+ if (ret) {
+ (*db->hdb_destroy)(context, db);
+ return ret;
+ }
+
+ ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
+ if (ret) {
+ (*db->hdb_destroy)(context, db);
+ return ret;
+ }
+
+ cursor->data = c = malloc (sizeof(*c));
+ if(c == NULL){
+ (*db->hdb_close)(context, db);
+ (*db->hdb_destroy)(context, db);
+ krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
+ return ENOMEM;
+ }
+
+ c->db = db;
+ c->first = TRUE;
+ c->next = TRUE;
+ c->key_idx = 0;
+
+ cursor->data = c;
return ret;
}
+static int
+hdb_next_entry(krb5_context context,
+ krb5_keytab id,
+ krb5_keytab_entry *entry,
+ krb5_kt_cursor *cursor)
+{
+ struct hdb_cursor *c = cursor->data;
+ krb5_error_code ret;
+
+ memset(entry, 0, sizeof(*entry));
+
+ if (c->first) {
+ c->first = FALSE;
+ ret = (c->db->hdb_firstkey)(context, c->db,
+ HDB_F_DECRYPT|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ &c->hdb_entry);
+ if (ret == HDB_ERR_NOENTRY)
+ return KRB5_KT_END;
+ else if (ret)
+ return ret;
+
+ if (c->hdb_entry.entry.keys.len == 0)
+ hdb_free_entry(context, &c->hdb_entry);
+ else
+ c->next = FALSE;
+ }
+
+ while (c->next) {
+ ret = (c->db->hdb_nextkey)(context, c->db,
+ HDB_F_DECRYPT|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ &c->hdb_entry);
+ if (ret == HDB_ERR_NOENTRY)
+ return KRB5_KT_END;
+ else if (ret)
+ return ret;
+
+ /* If no keys on this entry, try again */
+ if (c->hdb_entry.entry.keys.len == 0)
+ hdb_free_entry(context, &c->hdb_entry);
+ else
+ c->next = FALSE;
+ }
+
+ /*
+ * Return next enc type (keytabs are one slot per key, while
+ * hdb is one record per principal.
+ */
+
+ ret = krb5_copy_principal(context,
+ c->hdb_entry.entry.principal,
+ &entry->principal);
+ if (ret)
+ return ret;
+
+ entry->vno = c->hdb_entry.entry.kvno;
+ ret = krb5_copy_keyblock_contents(context,
+ &c->hdb_entry.entry.keys.val[c->key_idx].key,
+ &entry->keyblock);
+ if (ret) {
+ krb5_free_principal(context, entry->principal);
+ memset(entry, 0, sizeof(*entry));
+ return ret;
+ }
+ c->key_idx++;
+
+ /*
+ * Once we get to the end of the list, signal that we want the
+ * next entry
+ */
+
+ if (c->key_idx == c->hdb_entry.entry.keys.len) {
+ hdb_free_entry(context, &c->hdb_entry);
+ c->next = TRUE;
+ c->key_idx = 0;
+ }
+
+ return 0;
+}
+
+
+static int
+hdb_end_seq_get(krb5_context context,
+ krb5_keytab id,
+ krb5_kt_cursor *cursor)
+{
+ struct hdb_cursor *c = cursor->data;
+
+ if (!c->next)
+ hdb_free_entry(context, &c->hdb_entry);
+
+ (c->db->hdb_close)(context, c->db);
+ (c->db->hdb_destroy)(context, c->db);
+
+ free(c);
+ return 0;
+}
+
krb5_kt_ops hdb_kt_ops = {
"HDB",
hdb_resolve,
hdb_get_name,
hdb_close,
+ NULL, /* destroy */
hdb_get_entry,
- NULL, /* start_seq_get */
- NULL, /* next_entry */
- NULL, /* end_seq_get */
+ hdb_start_seq_get,
+ hdb_next_entry,
+ hdb_end_seq_get,
NULL, /* add */
NULL /* remove */
};