keytab.c revision 178826
1254885Sdumbbell/* 2254885Sdumbbell * Copyright (c) 1999 - 2002 Kungliga Tekniska H�gskolan 3254885Sdumbbell * (Royal Institute of Technology, Stockholm, Sweden). 4254885Sdumbbell * All rights reserved. 5254885Sdumbbell * 6254885Sdumbbell * Redistribution and use in source and binary forms, with or without 7254885Sdumbbell * modification, are permitted provided that the following conditions 8254885Sdumbbell * are met: 9254885Sdumbbell * 10254885Sdumbbell * 1. Redistributions of source code must retain the above copyright 11254885Sdumbbell * notice, this list of conditions and the following disclaimer. 12254885Sdumbbell * 13254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 14254885Sdumbbell * notice, this list of conditions and the following disclaimer in the 15254885Sdumbbell * documentation and/or other materials provided with the distribution. 16254885Sdumbbell * 17254885Sdumbbell * 3. Neither the name of the Institute nor the names of its contributors 18254885Sdumbbell * may be used to endorse or promote products derived from this software 19254885Sdumbbell * without specific prior written permission. 20254885Sdumbbell * 21254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24254885Sdumbbell * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31254885Sdumbbell * SUCH DAMAGE. 32254885Sdumbbell */ 33254885Sdumbbell 34254885Sdumbbell#include "hdb_locl.h" 35254885Sdumbbell 36254885Sdumbbell/* keytab backend for HDB databases */ 37254885Sdumbbell 38254885SdumbbellRCSID("$Id: keytab.c 18380 2006-10-09 12:36:40Z lha $"); 39254885Sdumbbell 40254885Sdumbbellstruct hdb_data { 41254885Sdumbbell char *dbname; 42254885Sdumbbell char *mkey; 43254885Sdumbbell}; 44254885Sdumbbell 45254885Sdumbbell/* 46254885Sdumbbell * the format for HDB keytabs is: 47254885Sdumbbell * HDB:[database:file:mkey] 48254885Sdumbbell */ 49254885Sdumbbell 50254885Sdumbbellstatic krb5_error_code 51254885Sdumbbellhdb_resolve(krb5_context context, const char *name, krb5_keytab id) 52254885Sdumbbell{ 53254885Sdumbbell struct hdb_data *d; 54254885Sdumbbell const char *db, *mkey; 55254885Sdumbbell 56254885Sdumbbell d = malloc(sizeof(*d)); 57254885Sdumbbell if(d == NULL) { 58254885Sdumbbell krb5_set_error_string(context, "malloc: out of memory"); 59254885Sdumbbell return ENOMEM; 60254885Sdumbbell } 61254885Sdumbbell db = name; 62254885Sdumbbell mkey = strchr(name, ':'); 63254885Sdumbbell if(mkey == NULL || mkey[1] == '\0') { 64254885Sdumbbell if(*name == '\0') 65254885Sdumbbell d->dbname = NULL; 66254885Sdumbbell else { 67254885Sdumbbell d->dbname = strdup(name); 68254885Sdumbbell if(d->dbname == NULL) { 69254885Sdumbbell free(d); 70254885Sdumbbell krb5_set_error_string(context, "malloc: out of memory"); 71254885Sdumbbell return ENOMEM; 72254885Sdumbbell } 73254885Sdumbbell } 74254885Sdumbbell d->mkey = NULL; 75254885Sdumbbell } else { 76254885Sdumbbell if((mkey - db) == 0) { 77254885Sdumbbell d->dbname = NULL; 78254885Sdumbbell } else { 79254885Sdumbbell d->dbname = malloc(mkey - db + 1); 80254885Sdumbbell if(d->dbname == NULL) { 81254885Sdumbbell free(d); 82254885Sdumbbell krb5_set_error_string(context, "malloc: out of memory"); 83254885Sdumbbell return ENOMEM; 84254885Sdumbbell } 85254885Sdumbbell memmove(d->dbname, db, mkey - db); 86254885Sdumbbell d->dbname[mkey - db] = '\0'; 87254885Sdumbbell } 88254885Sdumbbell d->mkey = strdup(mkey + 1); 89254885Sdumbbell if(d->mkey == NULL) { 90254885Sdumbbell free(d->dbname); 91254885Sdumbbell free(d); 92254885Sdumbbell krb5_set_error_string(context, "malloc: out of memory"); 93254885Sdumbbell return ENOMEM; 94254885Sdumbbell } 95254885Sdumbbell } 96254885Sdumbbell id->data = d; 97254885Sdumbbell return 0; 98254885Sdumbbell} 99254885Sdumbbell 100254885Sdumbbellstatic krb5_error_code 101254885Sdumbbellhdb_close(krb5_context context, krb5_keytab id) 102254885Sdumbbell{ 103254885Sdumbbell struct hdb_data *d = id->data; 104254885Sdumbbell 105254885Sdumbbell free(d->dbname); 106254885Sdumbbell free(d->mkey); 107254885Sdumbbell free(d); 108254885Sdumbbell return 0; 109254885Sdumbbell} 110254885Sdumbbell 111254885Sdumbbellstatic krb5_error_code 112254885Sdumbbellhdb_get_name(krb5_context context, 113254885Sdumbbell krb5_keytab id, 114254885Sdumbbell char *name, 115254885Sdumbbell size_t namesize) 116254885Sdumbbell{ 117254885Sdumbbell struct hdb_data *d = id->data; 118254885Sdumbbell 119254885Sdumbbell snprintf(name, namesize, "%s%s%s", 120254885Sdumbbell d->dbname ? d->dbname : "", 121254885Sdumbbell (d->dbname || d->mkey) ? ":" : "", 122254885Sdumbbell d->mkey ? d->mkey : ""); 123254885Sdumbbell return 0; 124254885Sdumbbell} 125254885Sdumbbell 126254885Sdumbbellstatic void 127254885Sdumbbellset_config (krb5_context context, 128254885Sdumbbell const krb5_config_binding *binding, 129254885Sdumbbell const char **dbname, 130254885Sdumbbell const char **mkey) 131254885Sdumbbell{ 132254885Sdumbbell *dbname = krb5_config_get_string(context, binding, "dbname", NULL); 133254885Sdumbbell *mkey = krb5_config_get_string(context, binding, "mkey_file", NULL); 134254885Sdumbbell} 135254885Sdumbbell 136254885Sdumbbell/* 137254885Sdumbbell * try to figure out the database (`dbname') and master-key (`mkey') 138254885Sdumbbell * that should be used for `principal'. 139254885Sdumbbell */ 140254885Sdumbbell 141254885Sdumbbellstatic void 142254885Sdumbbellfind_db (krb5_context context, 143282199Sdumbbell const char **dbname, 144254885Sdumbbell const char **mkey, 145254885Sdumbbell krb5_const_principal principal) 146254885Sdumbbell{ 147254885Sdumbbell const krb5_config_binding *top_bind = NULL; 148254885Sdumbbell const krb5_config_binding *default_binding = NULL; 149254885Sdumbbell const krb5_config_binding *db; 150254885Sdumbbell krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal)); 151254885Sdumbbell 152254885Sdumbbell *dbname = *mkey = NULL; 153254885Sdumbbell 154254885Sdumbbell while ((db = 155254885Sdumbbell krb5_config_get_next(context, 156254885Sdumbbell NULL, 157254885Sdumbbell &top_bind, 158254885Sdumbbell krb5_config_list, 159254885Sdumbbell "kdc", 160254885Sdumbbell "database", 161254885Sdumbbell NULL)) != NULL) { 162254885Sdumbbell const char *p; 163254885Sdumbbell 164254885Sdumbbell p = krb5_config_get_string (context, db, "realm", NULL); 165254885Sdumbbell if (p == NULL) { 166254885Sdumbbell if(default_binding) { 167254885Sdumbbell krb5_warnx(context, "WARNING: more than one realm-less " 168254885Sdumbbell "database specification"); 169254885Sdumbbell krb5_warnx(context, "WARNING: using the first encountered"); 170254885Sdumbbell } else 171254885Sdumbbell default_binding = db; 172254885Sdumbbell } else if (strcmp (*prealm, p) == 0) { 173254885Sdumbbell set_config (context, db, dbname, mkey); 174254885Sdumbbell break; 175254885Sdumbbell } 176282199Sdumbbell } 177254885Sdumbbell if (*dbname == NULL && default_binding != NULL) 178254885Sdumbbell set_config (context, default_binding, dbname, mkey); 179254885Sdumbbell if (*dbname == NULL) 180254885Sdumbbell *dbname = HDB_DEFAULT_DB; 181254885Sdumbbell} 182254885Sdumbbell 183254885Sdumbbell/* 184254885Sdumbbell * find the keytab entry in `id' for `principal, kvno, enctype' and return 185254885Sdumbbell * it in `entry'. return 0 or an error code 186254885Sdumbbell */ 187254885Sdumbbell 188254885Sdumbbellstatic krb5_error_code 189254885Sdumbbellhdb_get_entry(krb5_context context, 190254885Sdumbbell krb5_keytab id, 191254885Sdumbbell krb5_const_principal principal, 192254885Sdumbbell krb5_kvno kvno, 193254885Sdumbbell krb5_enctype enctype, 194254885Sdumbbell krb5_keytab_entry *entry) 195254885Sdumbbell{ 196254885Sdumbbell hdb_entry_ex ent; 197254885Sdumbbell krb5_error_code ret; 198254885Sdumbbell struct hdb_data *d = id->data; 199254885Sdumbbell int i; 200254885Sdumbbell HDB *db; 201254885Sdumbbell const char *dbname = d->dbname; 202254885Sdumbbell const char *mkey = d->mkey; 203254885Sdumbbell 204254885Sdumbbell memset(&ent, 0, sizeof(ent)); 205254885Sdumbbell 206254885Sdumbbell if (dbname == NULL) 207254885Sdumbbell find_db (context, &dbname, &mkey, principal); 208254885Sdumbbell 209254885Sdumbbell ret = hdb_create (context, &db, dbname); 210254885Sdumbbell if (ret) 211254885Sdumbbell return ret; 212254885Sdumbbell ret = hdb_set_master_keyfile (context, db, mkey); 213254885Sdumbbell if (ret) { 214254885Sdumbbell (*db->hdb_destroy)(context, db); 215254885Sdumbbell return ret; 216254885Sdumbbell } 217254885Sdumbbell 218254885Sdumbbell ret = (*db->hdb_open)(context, db, O_RDONLY, 0); 219254885Sdumbbell if (ret) { 220254885Sdumbbell (*db->hdb_destroy)(context, db); 221254885Sdumbbell return ret; 222254885Sdumbbell } 223254885Sdumbbell ret = (*db->hdb_fetch)(context, db, principal, 224254885Sdumbbell HDB_F_DECRYPT| 225254885Sdumbbell HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, 226254885Sdumbbell &ent); 227254885Sdumbbell 228254885Sdumbbell if(ret == HDB_ERR_NOENTRY) { 229254885Sdumbbell ret = KRB5_KT_NOTFOUND; 230254885Sdumbbell goto out; 231254885Sdumbbell }else if(ret) 232254885Sdumbbell goto out; 233254885Sdumbbell 234254885Sdumbbell if(kvno && ent.entry.kvno != kvno) { 235254885Sdumbbell hdb_free_entry(context, &ent); 236254885Sdumbbell ret = KRB5_KT_NOTFOUND; 237254885Sdumbbell goto out; 238254885Sdumbbell } 239254885Sdumbbell if(enctype == 0) 240254885Sdumbbell if(ent.entry.keys.len > 0) 241254885Sdumbbell enctype = ent.entry.keys.val[0].key.keytype; 242254885Sdumbbell ret = KRB5_KT_NOTFOUND; 243254885Sdumbbell for(i = 0; i < ent.entry.keys.len; i++) { 244254885Sdumbbell if(ent.entry.keys.val[i].key.keytype == enctype) { 245254885Sdumbbell krb5_copy_principal(context, principal, &entry->principal); 246254885Sdumbbell entry->vno = ent.entry.kvno; 247254885Sdumbbell krb5_copy_keyblock_contents(context, 248254885Sdumbbell &ent.entry.keys.val[i].key, 249254885Sdumbbell &entry->keyblock); 250254885Sdumbbell ret = 0; 251254885Sdumbbell break; 252254885Sdumbbell } 253254885Sdumbbell } 254254885Sdumbbell hdb_free_entry(context, &ent); 255254885Sdumbbellout: 256254885Sdumbbell (*db->hdb_close)(context, db); 257254885Sdumbbell (*db->hdb_destroy)(context, db); 258254885Sdumbbell return ret; 259254885Sdumbbell} 260254885Sdumbbell 261254885Sdumbbellkrb5_kt_ops hdb_kt_ops = { 262254885Sdumbbell "HDB", 263254885Sdumbbell hdb_resolve, 264282199Sdumbbell hdb_get_name, 265254885Sdumbbell hdb_close, 266254885Sdumbbell hdb_get_entry, 267254885Sdumbbell NULL, /* start_seq_get */ 268254885Sdumbbell NULL, /* next_entry */ 269254885Sdumbbell NULL, /* end_seq_get */ 270254885Sdumbbell NULL, /* add */ 271254885Sdumbbell NULL /* remove */ 272254885Sdumbbell}; 273254885Sdumbbell