1b528cefcSMark Murray /* 213e3f4d6SMark Murray * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "krb5_locl.h" 35b528cefcSMark Murray 3613e3f4d6SMark Murray RCSID("$Id: keytab.c,v 1.46 2000/02/07 03:18:05 assar Exp $"); 37b528cefcSMark Murray 38b528cefcSMark Murray /* 39b528cefcSMark Murray * Register a new keytab in `ops' 40b528cefcSMark Murray * Return 0 or an error. 41b528cefcSMark Murray */ 42b528cefcSMark Murray 43b528cefcSMark Murray krb5_error_code 44b528cefcSMark Murray krb5_kt_register(krb5_context context, 45b528cefcSMark Murray const krb5_kt_ops *ops) 46b528cefcSMark Murray { 47b528cefcSMark Murray struct krb5_keytab_data *tmp; 48b528cefcSMark Murray 49b528cefcSMark Murray tmp = realloc(context->kt_types, 50b528cefcSMark Murray (context->num_kt_types + 1) * sizeof(*context->kt_types)); 51b528cefcSMark Murray if(tmp == NULL) 52b528cefcSMark Murray return ENOMEM; 53b528cefcSMark Murray memcpy(&tmp[context->num_kt_types], ops, 54b528cefcSMark Murray sizeof(tmp[context->num_kt_types])); 55b528cefcSMark Murray context->kt_types = tmp; 56b528cefcSMark Murray context->num_kt_types++; 57b528cefcSMark Murray return 0; 58b528cefcSMark Murray } 59b528cefcSMark Murray 60b528cefcSMark Murray /* 61b528cefcSMark Murray * Resolve the keytab name (of the form `type:residual') in `name' 62b528cefcSMark Murray * into a keytab in `id'. 63b528cefcSMark Murray * Return 0 or an error 64b528cefcSMark Murray */ 65b528cefcSMark Murray 66b528cefcSMark Murray krb5_error_code 67b528cefcSMark Murray krb5_kt_resolve(krb5_context context, 68b528cefcSMark Murray const char *name, 69b528cefcSMark Murray krb5_keytab *id) 70b528cefcSMark Murray { 71b528cefcSMark Murray krb5_keytab k; 72b528cefcSMark Murray int i; 73b528cefcSMark Murray const char *type, *residual; 74b528cefcSMark Murray size_t type_len; 75b528cefcSMark Murray krb5_error_code ret; 76b528cefcSMark Murray 77b528cefcSMark Murray residual = strchr(name, ':'); 78b528cefcSMark Murray if(residual == NULL) { 79b528cefcSMark Murray type = "FILE"; 80b528cefcSMark Murray type_len = strlen(type); 81b528cefcSMark Murray residual = name; 82b528cefcSMark Murray } else { 83b528cefcSMark Murray type = name; 84b528cefcSMark Murray type_len = residual - name; 85b528cefcSMark Murray residual++; 86b528cefcSMark Murray } 87b528cefcSMark Murray 88b528cefcSMark Murray for(i = 0; i < context->num_kt_types; i++) { 89b528cefcSMark Murray if(strncmp(type, context->kt_types[i].prefix, type_len) == 0) 90b528cefcSMark Murray break; 91b528cefcSMark Murray } 92b528cefcSMark Murray if(i == context->num_kt_types) 93b528cefcSMark Murray return KRB5_KT_UNKNOWN_TYPE; 94b528cefcSMark Murray 95b528cefcSMark Murray k = malloc (sizeof(*k)); 96b528cefcSMark Murray if (k == NULL) 97b528cefcSMark Murray return ENOMEM; 98b528cefcSMark Murray memcpy(k, &context->kt_types[i], sizeof(*k)); 99b528cefcSMark Murray k->data = NULL; 100b528cefcSMark Murray ret = (*k->resolve)(context, residual, k); 101b528cefcSMark Murray if(ret) { 102b528cefcSMark Murray free(k); 103b528cefcSMark Murray k = NULL; 104b528cefcSMark Murray } 105b528cefcSMark Murray *id = k; 106b528cefcSMark Murray return ret; 107b528cefcSMark Murray } 108b528cefcSMark Murray 109b528cefcSMark Murray /* 110b528cefcSMark Murray * copy the name of the default keytab into `name'. 111b528cefcSMark Murray * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. 112b528cefcSMark Murray */ 113b528cefcSMark Murray 114b528cefcSMark Murray krb5_error_code 115b528cefcSMark Murray krb5_kt_default_name(krb5_context context, char *name, size_t namesize) 116b528cefcSMark Murray { 11713e3f4d6SMark Murray if (strlcpy (name, context->default_keytab, namesize) >= namesize) 118b528cefcSMark Murray return KRB5_CONFIG_NOTENUFSPACE; 119b528cefcSMark Murray return 0; 120b528cefcSMark Murray } 121b528cefcSMark Murray 122b528cefcSMark Murray /* 123b528cefcSMark Murray * Set `id' to the default keytab. 124b528cefcSMark Murray * Return 0 or an error. 125b528cefcSMark Murray */ 126b528cefcSMark Murray 127b528cefcSMark Murray krb5_error_code 128b528cefcSMark Murray krb5_kt_default(krb5_context context, krb5_keytab *id) 129b528cefcSMark Murray { 130b528cefcSMark Murray return krb5_kt_resolve (context, context->default_keytab, id); 131b528cefcSMark Murray } 132b528cefcSMark Murray 133b528cefcSMark Murray /* 134b528cefcSMark Murray * Read the key identified by `(principal, vno, enctype)' from the 135b528cefcSMark Murray * keytab in `keyprocarg' (the default if == NULL) into `*key'. 136b528cefcSMark Murray * Return 0 or an error. 137b528cefcSMark Murray */ 138b528cefcSMark Murray 139b528cefcSMark Murray krb5_error_code 140b528cefcSMark Murray krb5_kt_read_service_key(krb5_context context, 141b528cefcSMark Murray krb5_pointer keyprocarg, 142b528cefcSMark Murray krb5_principal principal, 143b528cefcSMark Murray krb5_kvno vno, 144b528cefcSMark Murray krb5_enctype enctype, 145b528cefcSMark Murray krb5_keyblock **key) 146b528cefcSMark Murray { 147b528cefcSMark Murray krb5_keytab keytab; 148b528cefcSMark Murray krb5_keytab_entry entry; 149b528cefcSMark Murray krb5_error_code ret; 150b528cefcSMark Murray 151b528cefcSMark Murray if (keyprocarg) 152b528cefcSMark Murray ret = krb5_kt_resolve (context, keyprocarg, &keytab); 153b528cefcSMark Murray else 154b528cefcSMark Murray ret = krb5_kt_default (context, &keytab); 155b528cefcSMark Murray 156b528cefcSMark Murray if (ret) 157b528cefcSMark Murray return ret; 158b528cefcSMark Murray 159b528cefcSMark Murray ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 160b528cefcSMark Murray krb5_kt_close (context, keytab); 161b528cefcSMark Murray if (ret) 162b528cefcSMark Murray return ret; 163b528cefcSMark Murray ret = krb5_copy_keyblock (context, &entry.keyblock, key); 164b528cefcSMark Murray krb5_kt_free_entry(context, &entry); 165b528cefcSMark Murray return ret; 166b528cefcSMark Murray } 167b528cefcSMark Murray 168b528cefcSMark Murray /* 169b528cefcSMark Murray * Retrieve the name of the keytab `keytab' into `name', `namesize' 170b528cefcSMark Murray * Return 0 or an error. 171b528cefcSMark Murray */ 172b528cefcSMark Murray 173b528cefcSMark Murray krb5_error_code 174b528cefcSMark Murray krb5_kt_get_name(krb5_context context, 175b528cefcSMark Murray krb5_keytab keytab, 176b528cefcSMark Murray char *name, 177b528cefcSMark Murray size_t namesize) 178b528cefcSMark Murray { 179b528cefcSMark Murray return (*keytab->get_name)(context, keytab, name, namesize); 180b528cefcSMark Murray } 181b528cefcSMark Murray 182b528cefcSMark Murray /* 183b528cefcSMark Murray * Finish using the keytab in `id'. All resources will be released. 184b528cefcSMark Murray * Return 0 or an error. 185b528cefcSMark Murray */ 186b528cefcSMark Murray 187b528cefcSMark Murray krb5_error_code 188b528cefcSMark Murray krb5_kt_close(krb5_context context, 189b528cefcSMark Murray krb5_keytab id) 190b528cefcSMark Murray { 191b528cefcSMark Murray krb5_error_code ret; 192b528cefcSMark Murray 193b528cefcSMark Murray ret = (*id->close)(context, id); 194b528cefcSMark Murray if(ret == 0) 195b528cefcSMark Murray free(id); 196b528cefcSMark Murray return ret; 197b528cefcSMark Murray } 198b528cefcSMark Murray 199b528cefcSMark Murray /* 200b528cefcSMark Murray * Compare `entry' against `principal, vno, enctype'. 201b528cefcSMark Murray * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 202b528cefcSMark Murray * Return TRUE if they compare the same, FALSE otherwise. 203b528cefcSMark Murray */ 204b528cefcSMark Murray 205b528cefcSMark Murray krb5_boolean 206b528cefcSMark Murray krb5_kt_compare(krb5_context context, 207b528cefcSMark Murray krb5_keytab_entry *entry, 208b528cefcSMark Murray krb5_const_principal principal, 209b528cefcSMark Murray krb5_kvno vno, 210b528cefcSMark Murray krb5_enctype enctype) 211b528cefcSMark Murray { 212b528cefcSMark Murray if(principal != NULL && 213b528cefcSMark Murray !krb5_principal_compare(context, entry->principal, principal)) 214b528cefcSMark Murray return FALSE; 215b528cefcSMark Murray if(vno && vno != entry->vno) 216b528cefcSMark Murray return FALSE; 217b528cefcSMark Murray if(enctype && enctype != entry->keyblock.keytype) 218b528cefcSMark Murray return FALSE; 219b528cefcSMark Murray return TRUE; 220b528cefcSMark Murray } 221b528cefcSMark Murray 222b528cefcSMark Murray /* 223b528cefcSMark Murray * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 224b528cefcSMark Murray * from the keytab `id'. 225b528cefcSMark Murray * Return 0 or an error. 226b528cefcSMark Murray */ 227b528cefcSMark Murray 228b528cefcSMark Murray krb5_error_code 229b528cefcSMark Murray krb5_kt_get_entry(krb5_context context, 230b528cefcSMark Murray krb5_keytab id, 231b528cefcSMark Murray krb5_const_principal principal, 232b528cefcSMark Murray krb5_kvno kvno, 233b528cefcSMark Murray krb5_enctype enctype, 234b528cefcSMark Murray krb5_keytab_entry *entry) 235b528cefcSMark Murray { 236b528cefcSMark Murray krb5_keytab_entry tmp; 237b528cefcSMark Murray krb5_error_code ret; 238b528cefcSMark Murray krb5_kt_cursor cursor; 239b528cefcSMark Murray 240b528cefcSMark Murray if(id->get) 241b528cefcSMark Murray return (*id->get)(context, id, principal, kvno, enctype, entry); 242b528cefcSMark Murray 243b528cefcSMark Murray ret = krb5_kt_start_seq_get (context, id, &cursor); 244b528cefcSMark Murray if (ret) 245b528cefcSMark Murray return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */ 246b528cefcSMark Murray 247b528cefcSMark Murray entry->vno = 0; 248b528cefcSMark Murray while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 249b528cefcSMark Murray if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 250b528cefcSMark Murray if (kvno == tmp.vno) { 251b528cefcSMark Murray krb5_kt_copy_entry_contents (context, &tmp, entry); 252b528cefcSMark Murray krb5_kt_free_entry (context, &tmp); 253b528cefcSMark Murray krb5_kt_end_seq_get(context, id, &cursor); 254b528cefcSMark Murray return 0; 255b528cefcSMark Murray } else if (kvno == 0 && tmp.vno > entry->vno) { 256b528cefcSMark Murray if (entry->vno) 257b528cefcSMark Murray krb5_kt_free_entry (context, entry); 258b528cefcSMark Murray krb5_kt_copy_entry_contents (context, &tmp, entry); 259b528cefcSMark Murray } 260b528cefcSMark Murray } 261b528cefcSMark Murray krb5_kt_free_entry(context, &tmp); 262b528cefcSMark Murray } 263b528cefcSMark Murray krb5_kt_end_seq_get (context, id, &cursor); 264b528cefcSMark Murray if (entry->vno) 265b528cefcSMark Murray return 0; 266b528cefcSMark Murray else 267b528cefcSMark Murray return KRB5_KT_NOTFOUND; 268b528cefcSMark Murray } 269b528cefcSMark Murray 270b528cefcSMark Murray /* 271b528cefcSMark Murray * Copy the contents of `in' into `out'. 272b528cefcSMark Murray * Return 0 or an error. 273b528cefcSMark Murray */ 274b528cefcSMark Murray 275b528cefcSMark Murray krb5_error_code 276b528cefcSMark Murray krb5_kt_copy_entry_contents(krb5_context context, 277b528cefcSMark Murray const krb5_keytab_entry *in, 278b528cefcSMark Murray krb5_keytab_entry *out) 279b528cefcSMark Murray { 280b528cefcSMark Murray krb5_error_code ret; 281b528cefcSMark Murray 282b528cefcSMark Murray memset(out, 0, sizeof(*out)); 283b528cefcSMark Murray out->vno = in->vno; 284b528cefcSMark Murray 285b528cefcSMark Murray ret = krb5_copy_principal (context, in->principal, &out->principal); 286b528cefcSMark Murray if (ret) 287b528cefcSMark Murray goto fail; 288b528cefcSMark Murray ret = krb5_copy_keyblock_contents (context, 289b528cefcSMark Murray &in->keyblock, 290b528cefcSMark Murray &out->keyblock); 291b528cefcSMark Murray if (ret) 292b528cefcSMark Murray goto fail; 293b528cefcSMark Murray out->timestamp = in->timestamp; 294b528cefcSMark Murray return 0; 295b528cefcSMark Murray fail: 296b528cefcSMark Murray krb5_kt_free_entry (context, out); 297b528cefcSMark Murray return ret; 298b528cefcSMark Murray } 299b528cefcSMark Murray 300b528cefcSMark Murray /* 301b528cefcSMark Murray * Free the contents of `entry'. 302b528cefcSMark Murray */ 303b528cefcSMark Murray 304b528cefcSMark Murray krb5_error_code 305b528cefcSMark Murray krb5_kt_free_entry(krb5_context context, 306b528cefcSMark Murray krb5_keytab_entry *entry) 307b528cefcSMark Murray { 308b528cefcSMark Murray krb5_free_principal (context, entry->principal); 309b528cefcSMark Murray krb5_free_keyblock_contents (context, &entry->keyblock); 310b528cefcSMark Murray return 0; 311b528cefcSMark Murray } 312b528cefcSMark Murray 313b528cefcSMark Murray #if 0 314b528cefcSMark Murray static int 315b528cefcSMark Murray xxxlock(int fd, int write) 316b528cefcSMark Murray { 317b528cefcSMark Murray if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) { 318b528cefcSMark Murray sleep(1); 319b528cefcSMark Murray if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) 320b528cefcSMark Murray return -1; 321b528cefcSMark Murray } 322b528cefcSMark Murray return 0; 323b528cefcSMark Murray } 324b528cefcSMark Murray 325b528cefcSMark Murray static void 326b528cefcSMark Murray xxxunlock(int fd) 327b528cefcSMark Murray { 328b528cefcSMark Murray flock(fd, LOCK_UN); 329b528cefcSMark Murray } 330b528cefcSMark Murray #endif 331b528cefcSMark Murray 332b528cefcSMark Murray /* 333b528cefcSMark Murray * Set `cursor' to point at the beginning of `id'. 334b528cefcSMark Murray * Return 0 or an error. 335b528cefcSMark Murray */ 336b528cefcSMark Murray 337b528cefcSMark Murray krb5_error_code 338b528cefcSMark Murray krb5_kt_start_seq_get(krb5_context context, 339b528cefcSMark Murray krb5_keytab id, 340b528cefcSMark Murray krb5_kt_cursor *cursor) 341b528cefcSMark Murray { 342b528cefcSMark Murray if(id->start_seq_get == NULL) 343b528cefcSMark Murray return HEIM_ERR_OPNOTSUPP; 344b528cefcSMark Murray return (*id->start_seq_get)(context, id, cursor); 345b528cefcSMark Murray } 346b528cefcSMark Murray 347b528cefcSMark Murray /* 348b528cefcSMark Murray * Get the next entry from `id' pointed to by `cursor' and advance the 349b528cefcSMark Murray * `cursor'. 350b528cefcSMark Murray * Return 0 or an error. 351b528cefcSMark Murray */ 352b528cefcSMark Murray 353b528cefcSMark Murray krb5_error_code 354b528cefcSMark Murray krb5_kt_next_entry(krb5_context context, 355b528cefcSMark Murray krb5_keytab id, 356b528cefcSMark Murray krb5_keytab_entry *entry, 357b528cefcSMark Murray krb5_kt_cursor *cursor) 358b528cefcSMark Murray { 359b528cefcSMark Murray if(id->next_entry == NULL) 360b528cefcSMark Murray return HEIM_ERR_OPNOTSUPP; 361b528cefcSMark Murray return (*id->next_entry)(context, id, entry, cursor); 362b528cefcSMark Murray } 363b528cefcSMark Murray 364b528cefcSMark Murray /* 365b528cefcSMark Murray * Release all resources associated with `cursor'. 366b528cefcSMark Murray */ 367b528cefcSMark Murray 368b528cefcSMark Murray krb5_error_code 369b528cefcSMark Murray krb5_kt_end_seq_get(krb5_context context, 370b528cefcSMark Murray krb5_keytab id, 371b528cefcSMark Murray krb5_kt_cursor *cursor) 372b528cefcSMark Murray { 373b528cefcSMark Murray if(id->end_seq_get == NULL) 374b528cefcSMark Murray return HEIM_ERR_OPNOTSUPP; 375b528cefcSMark Murray return (*id->end_seq_get)(context, id, cursor); 376b528cefcSMark Murray } 377b528cefcSMark Murray 378b528cefcSMark Murray /* 379b528cefcSMark Murray * Add the entry in `entry' to the keytab `id'. 380b528cefcSMark Murray * Return 0 or an error. 381b528cefcSMark Murray */ 382b528cefcSMark Murray 383b528cefcSMark Murray krb5_error_code 384b528cefcSMark Murray krb5_kt_add_entry(krb5_context context, 385b528cefcSMark Murray krb5_keytab id, 386b528cefcSMark Murray krb5_keytab_entry *entry) 387b528cefcSMark Murray { 388b528cefcSMark Murray if(id->add == NULL) 389b528cefcSMark Murray return KRB5_KT_NOWRITE; 39013e3f4d6SMark Murray entry->timestamp = time(NULL); 391b528cefcSMark Murray return (*id->add)(context, id,entry); 392b528cefcSMark Murray } 393b528cefcSMark Murray 394b528cefcSMark Murray /* 395b528cefcSMark Murray * Remove the entry `entry' from the keytab `id'. 396b528cefcSMark Murray * Return 0 or an error. 397b528cefcSMark Murray */ 398b528cefcSMark Murray 399b528cefcSMark Murray krb5_error_code 400b528cefcSMark Murray krb5_kt_remove_entry(krb5_context context, 401b528cefcSMark Murray krb5_keytab id, 402b528cefcSMark Murray krb5_keytab_entry *entry) 403b528cefcSMark Murray { 404b528cefcSMark Murray if(id->remove == NULL) 405b528cefcSMark Murray return KRB5_KT_NOWRITE; 406b528cefcSMark Murray return (*id->remove)(context, id, entry); 407b528cefcSMark Murray } 408