155682Smarkm/* 2102644Snectar * Copyright (c) 1999 - 2002 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "hdb_locl.h" 3555682Smarkm 3655682Smarkm/* keytab backend for HDB databases */ 3755682Smarkm 38178825SdfrRCSID("$Id: keytab.c 18380 2006-10-09 12:36:40Z lha $"); 3955682Smarkm 4055682Smarkmstruct hdb_data { 4155682Smarkm char *dbname; 4255682Smarkm char *mkey; 4355682Smarkm}; 4455682Smarkm 4572445Sassar/* 4672445Sassar * the format for HDB keytabs is: 47178825Sdfr * HDB:[database:file:mkey] 4872445Sassar */ 4972445Sassar 5055682Smarkmstatic krb5_error_code 5155682Smarkmhdb_resolve(krb5_context context, const char *name, krb5_keytab id) 5255682Smarkm{ 5355682Smarkm struct hdb_data *d; 5455682Smarkm const char *db, *mkey; 5572445Sassar 5655682Smarkm d = malloc(sizeof(*d)); 5790926Snectar if(d == NULL) { 5890926Snectar krb5_set_error_string(context, "malloc: out of memory"); 5955682Smarkm return ENOMEM; 6090926Snectar } 6155682Smarkm db = name; 6255682Smarkm mkey = strchr(name, ':'); 6355682Smarkm if(mkey == NULL || mkey[1] == '\0') { 6455682Smarkm if(*name == '\0') 6555682Smarkm d->dbname = NULL; 6655682Smarkm else { 6755682Smarkm d->dbname = strdup(name); 6855682Smarkm if(d->dbname == NULL) { 6955682Smarkm free(d); 7090926Snectar krb5_set_error_string(context, "malloc: out of memory"); 7155682Smarkm return ENOMEM; 7255682Smarkm } 7355682Smarkm } 7455682Smarkm d->mkey = NULL; 7555682Smarkm } else { 7655682Smarkm if((mkey - db) == 0) { 7755682Smarkm d->dbname = NULL; 7855682Smarkm } else { 79178825Sdfr d->dbname = malloc(mkey - db + 1); 8055682Smarkm if(d->dbname == NULL) { 8155682Smarkm free(d); 8290926Snectar krb5_set_error_string(context, "malloc: out of memory"); 8355682Smarkm return ENOMEM; 8455682Smarkm } 8572445Sassar memmove(d->dbname, db, mkey - db); 8655682Smarkm d->dbname[mkey - db] = '\0'; 8755682Smarkm } 8855682Smarkm d->mkey = strdup(mkey + 1); 8955682Smarkm if(d->mkey == NULL) { 9055682Smarkm free(d->dbname); 9155682Smarkm free(d); 9290926Snectar krb5_set_error_string(context, "malloc: out of memory"); 9355682Smarkm return ENOMEM; 9455682Smarkm } 9555682Smarkm } 9655682Smarkm id->data = d; 9755682Smarkm return 0; 9855682Smarkm} 9955682Smarkm 10055682Smarkmstatic krb5_error_code 10155682Smarkmhdb_close(krb5_context context, krb5_keytab id) 10255682Smarkm{ 10355682Smarkm struct hdb_data *d = id->data; 10472445Sassar 10572445Sassar free(d->dbname); 10672445Sassar free(d->mkey); 10755682Smarkm free(d); 10855682Smarkm return 0; 10955682Smarkm} 11055682Smarkm 11155682Smarkmstatic krb5_error_code 11255682Smarkmhdb_get_name(krb5_context context, 11355682Smarkm krb5_keytab id, 11455682Smarkm char *name, 11555682Smarkm size_t namesize) 11655682Smarkm{ 11755682Smarkm struct hdb_data *d = id->data; 11872445Sassar 11955682Smarkm snprintf(name, namesize, "%s%s%s", 12055682Smarkm d->dbname ? d->dbname : "", 12155682Smarkm (d->dbname || d->mkey) ? ":" : "", 12255682Smarkm d->mkey ? d->mkey : ""); 12355682Smarkm return 0; 12455682Smarkm} 12555682Smarkm 12672445Sassarstatic void 12772445Sassarset_config (krb5_context context, 128178825Sdfr const krb5_config_binding *binding, 12972445Sassar const char **dbname, 13072445Sassar const char **mkey) 13172445Sassar{ 13272445Sassar *dbname = krb5_config_get_string(context, binding, "dbname", NULL); 13372445Sassar *mkey = krb5_config_get_string(context, binding, "mkey_file", NULL); 13472445Sassar} 13572445Sassar 13672445Sassar/* 13772445Sassar * try to figure out the database (`dbname') and master-key (`mkey') 13872445Sassar * that should be used for `principal'. 13972445Sassar */ 14072445Sassar 14172445Sassarstatic void 14272445Sassarfind_db (krb5_context context, 14372445Sassar const char **dbname, 14472445Sassar const char **mkey, 14572445Sassar krb5_const_principal principal) 14672445Sassar{ 147102644Snectar const krb5_config_binding *top_bind = NULL; 148178825Sdfr const krb5_config_binding *default_binding = NULL; 149178825Sdfr const krb5_config_binding *db; 150178825Sdfr krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal)); 15172445Sassar 15272445Sassar *dbname = *mkey = NULL; 15372445Sassar 154178825Sdfr while ((db = 15572445Sassar krb5_config_get_next(context, 15672445Sassar NULL, 15772445Sassar &top_bind, 15872445Sassar krb5_config_list, 15972445Sassar "kdc", 16072445Sassar "database", 16172445Sassar NULL)) != NULL) { 16272445Sassar const char *p; 16372445Sassar 16472445Sassar p = krb5_config_get_string (context, db, "realm", NULL); 16572445Sassar if (p == NULL) { 16672445Sassar if(default_binding) { 16772445Sassar krb5_warnx(context, "WARNING: more than one realm-less " 16872445Sassar "database specification"); 16972445Sassar krb5_warnx(context, "WARNING: using the first encountered"); 17072445Sassar } else 17172445Sassar default_binding = db; 17272445Sassar } else if (strcmp (*prealm, p) == 0) { 17372445Sassar set_config (context, db, dbname, mkey); 17472445Sassar break; 17572445Sassar } 17672445Sassar } 17772445Sassar if (*dbname == NULL && default_binding != NULL) 17872445Sassar set_config (context, default_binding, dbname, mkey); 17972445Sassar if (*dbname == NULL) 18072445Sassar *dbname = HDB_DEFAULT_DB; 18172445Sassar} 18272445Sassar 18372445Sassar/* 18472445Sassar * find the keytab entry in `id' for `principal, kvno, enctype' and return 18572445Sassar * it in `entry'. return 0 or an error code 18672445Sassar */ 18772445Sassar 18855682Smarkmstatic krb5_error_code 18955682Smarkmhdb_get_entry(krb5_context context, 19055682Smarkm krb5_keytab id, 19155682Smarkm krb5_const_principal principal, 19255682Smarkm krb5_kvno kvno, 19355682Smarkm krb5_enctype enctype, 19455682Smarkm krb5_keytab_entry *entry) 19555682Smarkm{ 196178825Sdfr hdb_entry_ex ent; 19755682Smarkm krb5_error_code ret; 19855682Smarkm struct hdb_data *d = id->data; 19955682Smarkm int i; 20072445Sassar HDB *db; 20172445Sassar const char *dbname = d->dbname; 20272445Sassar const char *mkey = d->mkey; 20355682Smarkm 204178825Sdfr memset(&ent, 0, sizeof(ent)); 205178825Sdfr 20672445Sassar if (dbname == NULL) 20772445Sassar find_db (context, &dbname, &mkey, principal); 20872445Sassar 20972445Sassar ret = hdb_create (context, &db, dbname); 21055682Smarkm if (ret) 21155682Smarkm return ret; 21272445Sassar ret = hdb_set_master_keyfile (context, db, mkey); 21372445Sassar if (ret) { 214178825Sdfr (*db->hdb_destroy)(context, db); 21572445Sassar return ret; 21672445Sassar } 21772445Sassar 218178825Sdfr ret = (*db->hdb_open)(context, db, O_RDONLY, 0); 21972445Sassar if (ret) { 220178825Sdfr (*db->hdb_destroy)(context, db); 22172445Sassar return ret; 22272445Sassar } 223178825Sdfr ret = (*db->hdb_fetch)(context, db, principal, 224178825Sdfr HDB_F_DECRYPT| 225178825Sdfr HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, 226178825Sdfr &ent); 22772445Sassar 228178825Sdfr if(ret == HDB_ERR_NOENTRY) { 229178825Sdfr ret = KRB5_KT_NOTFOUND; 230178825Sdfr goto out; 231178825Sdfr }else if(ret) 232178825Sdfr goto out; 233178825Sdfr 234178825Sdfr if(kvno && ent.entry.kvno != kvno) { 23555682Smarkm hdb_free_entry(context, &ent); 236178825Sdfr ret = KRB5_KT_NOTFOUND; 237178825Sdfr goto out; 23855682Smarkm } 23955682Smarkm if(enctype == 0) 240178825Sdfr if(ent.entry.keys.len > 0) 241178825Sdfr enctype = ent.entry.keys.val[0].key.keytype; 24255682Smarkm ret = KRB5_KT_NOTFOUND; 243178825Sdfr for(i = 0; i < ent.entry.keys.len; i++) { 244178825Sdfr if(ent.entry.keys.val[i].key.keytype == enctype) { 24555682Smarkm krb5_copy_principal(context, principal, &entry->principal); 246178825Sdfr entry->vno = ent.entry.kvno; 24755682Smarkm krb5_copy_keyblock_contents(context, 248178825Sdfr &ent.entry.keys.val[i].key, 24955682Smarkm &entry->keyblock); 25055682Smarkm ret = 0; 25155682Smarkm break; 25255682Smarkm } 25355682Smarkm } 25455682Smarkm hdb_free_entry(context, &ent); 255178825Sdfrout: 256178825Sdfr (*db->hdb_close)(context, db); 257178825Sdfr (*db->hdb_destroy)(context, db); 25855682Smarkm return ret; 25955682Smarkm} 26055682Smarkm 26155682Smarkmkrb5_kt_ops hdb_kt_ops = { 26255682Smarkm "HDB", 26355682Smarkm hdb_resolve, 26455682Smarkm hdb_get_name, 26555682Smarkm hdb_close, 26655682Smarkm hdb_get_entry, 26755682Smarkm NULL, /* start_seq_get */ 26855682Smarkm NULL, /* next_entry */ 26955682Smarkm NULL, /* end_seq_get */ 27055682Smarkm NULL, /* add */ 27155682Smarkm NULL /* remove */ 27255682Smarkm}; 273