From 28d78c40ade22c4b5d445dbe23f18ca210e41f8c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 24 Jan 2006 05:31:08 +0000 Subject: r13107: Follow the lead of Heimdal's kpasswdd and use the HDB (hdb-ldb in our case) as the keytab. This avoids issues in replicated setups, as we will replicate the kpasswd key correctly (including from windows, which is why I care at the moment). Andrew Bartlett (This used to be commit 849500d1aa658817052423051b1f5d0b7a1db8e0) --- source4/heimdal/lib/hdb/hdb-protos.h | 6 + source4/heimdal/lib/hdb/hdb.c | 5 +- source4/heimdal/lib/hdb/keytab.c | 276 +++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 source4/heimdal/lib/hdb/keytab.c (limited to 'source4/heimdal/lib/hdb') diff --git a/source4/heimdal/lib/hdb/hdb-protos.h b/source4/heimdal/lib/hdb/hdb-protos.h index c221175e41..67e19f7e4a 100644 --- a/source4/heimdal/lib/hdb/hdb-protos.h +++ b/source4/heimdal/lib/hdb/hdb-protos.h @@ -490,6 +490,12 @@ hdb_ldapi_create ( HDB ** /*db*/, const char */*arg*/); +krb5_error_code +hdb_ldb_create ( + krb5_context /*context*/, + HDB ** /*db*/, + const char */*arg*/); + krb5_error_code hdb_list_builtin ( krb5_context /*context*/, diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index 5631d05332..406a50ecbd 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -54,6 +54,9 @@ static struct hdb_method methods[] = { #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE) {"ldap:", hdb_ldap_create}, {"ldapi:", hdb_ldapi_create}, +#endif +#ifdef _SAMBA_BUILD_ + {"ldb:", hdb_ldb_create}, #endif {NULL, NULL} }; @@ -395,6 +398,6 @@ hdb_create(krb5_context context, HDB **db, const char *filename) 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! (hdb_create(%s))", filename); return (*h->create)(context, db, residual); } diff --git a/source4/heimdal/lib/hdb/keytab.c b/source4/heimdal/lib/hdb/keytab.c new file mode 100644 index 0000000000..21ee2f4274 --- /dev/null +++ b/source4/heimdal/lib/hdb/keytab.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan + * (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: + * + * 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. 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. + */ + +#include "hdb_locl.h" + +/* keytab backend for HDB databases */ + +RCSID("$Id: keytab.c,v 1.8 2005/12/12 12:35:36 lha Exp $"); + +struct hdb_data { + char *dbname; + char *mkey; +}; + +/* + * the format for HDB keytabs is: + * HDB:[database:file:mkey] + */ + +static krb5_error_code +hdb_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct hdb_data *d; + const char *db, *mkey; + + d = malloc(sizeof(*d)); + if(d == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + db = name; + mkey = strrchr(name, ':'); + if(mkey == NULL || mkey[1] == '\0') { + if(*name == '\0') + d->dbname = NULL; + else { + d->dbname = strdup(name); + if(d->dbname == NULL) { + free(d); + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + } + d->mkey = NULL; + } else { + if((mkey - db) == 0) { + d->dbname = NULL; + } else { + d->dbname = malloc(mkey - db); + if(d->dbname == NULL) { + free(d); + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + memmove(d->dbname, db, mkey - db); + d->dbname[mkey - db] = '\0'; + } + d->mkey = strdup(mkey + 1); + if(d->mkey == NULL) { + free(d->dbname); + free(d); + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + } + id->data = d; + return 0; +} + +static krb5_error_code +hdb_close(krb5_context context, krb5_keytab id) +{ + struct hdb_data *d = id->data; + + free(d->dbname); + free(d->mkey); + free(d); + return 0; +} + +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", + 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 +find_db (krb5_context context, + const char **dbname, + const 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)); + + *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); + break; + } + } + if (*dbname == NULL && default_binding != NULL) + set_config (context, default_binding, dbname, mkey); + if (*dbname == NULL) + *dbname = HDB_DEFAULT_DB; +} + +/* + * 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_get_entry(krb5_context context, + krb5_keytab id, + krb5_const_principal principal, + krb5_kvno kvno, + krb5_enctype enctype, + krb5_keytab_entry *entry) +{ + 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; + + if (dbname == NULL) + find_db (context, &dbname, &mkey, principal); + + 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; + } + + ret = (*db->hdb_fetch)(context, db, HDB_F_DECRYPT, principal, HDB_ENT_TYPE_SERVER, &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; + } + 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; + } + if(enctype == 0) + if(ent.entry.keys.len > 0) + enctype = ent.entry.keys.val[0].key.keytype; + ret = KRB5_KT_NOTFOUND; + for(i = 0; i < ent.entry.keys.len; i++) { + 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, + &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); + (*db->hdb_close)(context, db); + (*db->hdb_destroy)(context, db); + return ret; +} + +krb5_kt_ops hdb_kt_ops = { + "HDB", + hdb_resolve, + hdb_get_name, + hdb_close, + hdb_get_entry, + NULL, /* start_seq_get */ + NULL, /* next_entry */ + NULL, /* end_seq_get */ + NULL, /* add */ + NULL /* remove */ +}; -- cgit