1b528cefcSMark Murray /* 24137ff4cSJacques Vidrine * Copyright (c) 1997 - 2002 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 368373020dSJacques Vidrine RCSID("$Id: keytab_keyfile.c,v 1.13 2002/04/18 14:04:21 joda Exp $"); 37b528cefcSMark Murray 38b528cefcSMark Murray /* afs keyfile operations --------------------------------------- */ 39b528cefcSMark Murray 40b528cefcSMark Murray /* 41b528cefcSMark Murray * Minimum tools to handle the AFS KeyFile. 42b528cefcSMark Murray * 43b528cefcSMark Murray * Format of the KeyFile is: 44b528cefcSMark Murray * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys} 45b528cefcSMark Murray * 46b528cefcSMark Murray * It just adds to the end of the keyfile, deleting isn't implemented. 47b528cefcSMark Murray * Use your favorite text/hex editor to delete keys. 48b528cefcSMark Murray * 49b528cefcSMark Murray */ 50b528cefcSMark Murray 51b528cefcSMark Murray #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell" 52b528cefcSMark Murray #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf" 53b528cefcSMark Murray 54b528cefcSMark Murray struct akf_data { 55b528cefcSMark Murray int num_entries; 56b528cefcSMark Murray char *filename; 57b528cefcSMark Murray char *cell; 58b528cefcSMark Murray char *realm; 59b528cefcSMark Murray }; 60b528cefcSMark Murray 61b528cefcSMark Murray /* 62b528cefcSMark Murray * set `d->cell' and `d->realm' 63b528cefcSMark Murray */ 64b528cefcSMark Murray 65b528cefcSMark Murray static int 66adb0ddaeSAssar Westerlund get_cell_and_realm (krb5_context context, 67adb0ddaeSAssar Westerlund struct akf_data *d) 68b528cefcSMark Murray { 69b528cefcSMark Murray FILE *f; 70b528cefcSMark Murray char buf[BUFSIZ], *cp; 71adb0ddaeSAssar Westerlund int ret; 72b528cefcSMark Murray 73b528cefcSMark Murray f = fopen (AFS_SERVERTHISCELL, "r"); 74adb0ddaeSAssar Westerlund if (f == NULL) { 75adb0ddaeSAssar Westerlund ret = errno; 76adb0ddaeSAssar Westerlund krb5_set_error_string (context, "open %s: %s", AFS_SERVERTHISCELL, 77adb0ddaeSAssar Westerlund strerror(ret)); 78adb0ddaeSAssar Westerlund return ret; 79adb0ddaeSAssar Westerlund } 80b528cefcSMark Murray if (fgets (buf, sizeof(buf), f) == NULL) { 81b528cefcSMark Murray fclose (f); 82adb0ddaeSAssar Westerlund krb5_set_error_string (context, "no cell in %s", AFS_SERVERTHISCELL); 83b528cefcSMark Murray return EINVAL; 84b528cefcSMark Murray } 85b528cefcSMark Murray if (buf[strlen(buf) - 1] == '\n') 86b528cefcSMark Murray buf[strlen(buf) - 1] = '\0'; 87b528cefcSMark Murray fclose(f); 88b528cefcSMark Murray 89b528cefcSMark Murray d->cell = strdup (buf); 90adb0ddaeSAssar Westerlund if (d->cell == NULL) { 91adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 92adb0ddaeSAssar Westerlund return ENOMEM; 93adb0ddaeSAssar Westerlund } 94b528cefcSMark Murray 95b528cefcSMark Murray f = fopen (AFS_SERVERMAGICKRBCONF, "r"); 96b528cefcSMark Murray if (f != NULL) { 97b528cefcSMark Murray if (fgets (buf, sizeof(buf), f) == NULL) { 98b528cefcSMark Murray fclose (f); 99adb0ddaeSAssar Westerlund krb5_set_error_string (context, "no realm in %s", 100adb0ddaeSAssar Westerlund AFS_SERVERMAGICKRBCONF); 101b528cefcSMark Murray return EINVAL; 102b528cefcSMark Murray } 103b528cefcSMark Murray if (buf[strlen(buf)-1] == '\n') 104b528cefcSMark Murray buf[strlen(buf)-1] = '\0'; 105b528cefcSMark Murray fclose(f); 106b528cefcSMark Murray } 107b528cefcSMark Murray /* uppercase */ 108b528cefcSMark Murray for (cp = buf; *cp != '\0'; cp++) 109b528cefcSMark Murray *cp = toupper(*cp); 110b528cefcSMark Murray 111b528cefcSMark Murray d->realm = strdup (buf); 112b528cefcSMark Murray if (d->realm == NULL) { 113b528cefcSMark Murray free (d->cell); 114adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 115adb0ddaeSAssar Westerlund return ENOMEM; 116b528cefcSMark Murray } 117b528cefcSMark Murray return 0; 118b528cefcSMark Murray } 119b528cefcSMark Murray 120b528cefcSMark Murray /* 121b528cefcSMark Murray * init and get filename 122b528cefcSMark Murray */ 123b528cefcSMark Murray 124b528cefcSMark Murray static krb5_error_code 125b528cefcSMark Murray akf_resolve(krb5_context context, const char *name, krb5_keytab id) 126b528cefcSMark Murray { 127b528cefcSMark Murray int ret; 128b528cefcSMark Murray struct akf_data *d = malloc(sizeof (struct akf_data)); 129b528cefcSMark Murray 130adb0ddaeSAssar Westerlund if (d == NULL) { 131adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 132adb0ddaeSAssar Westerlund return ENOMEM; 133adb0ddaeSAssar Westerlund } 134b528cefcSMark Murray 135b528cefcSMark Murray d->num_entries = 0; 136adb0ddaeSAssar Westerlund ret = get_cell_and_realm (context, d); 137b528cefcSMark Murray if (ret) { 138b528cefcSMark Murray free (d); 139b528cefcSMark Murray return ret; 140b528cefcSMark Murray } 141b528cefcSMark Murray d->filename = strdup (name); 142b528cefcSMark Murray if (d->filename == NULL) { 143b528cefcSMark Murray free (d->cell); 144b528cefcSMark Murray free (d->realm); 145b528cefcSMark Murray free (d); 146adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 147b528cefcSMark Murray return ENOMEM; 148b528cefcSMark Murray } 149b528cefcSMark Murray id->data = d; 150b528cefcSMark Murray 151b528cefcSMark Murray return 0; 152b528cefcSMark Murray } 153b528cefcSMark Murray 154b528cefcSMark Murray /* 155b528cefcSMark Murray * cleanup 156b528cefcSMark Murray */ 157b528cefcSMark Murray 158b528cefcSMark Murray static krb5_error_code 159b528cefcSMark Murray akf_close(krb5_context context, krb5_keytab id) 160b528cefcSMark Murray { 161b528cefcSMark Murray struct akf_data *d = id->data; 162b528cefcSMark Murray 163b528cefcSMark Murray free (d->filename); 164b528cefcSMark Murray free (d->cell); 165b528cefcSMark Murray free (d); 166b528cefcSMark Murray return 0; 167b528cefcSMark Murray } 168b528cefcSMark Murray 169b528cefcSMark Murray /* 170b528cefcSMark Murray * Return filename 171b528cefcSMark Murray */ 172b528cefcSMark Murray 173b528cefcSMark Murray static krb5_error_code 174b528cefcSMark Murray akf_get_name(krb5_context context, 175b528cefcSMark Murray krb5_keytab id, 176b528cefcSMark Murray char *name, 177b528cefcSMark Murray size_t name_sz) 178b528cefcSMark Murray { 179b528cefcSMark Murray struct akf_data *d = id->data; 180b528cefcSMark Murray 181b528cefcSMark Murray strlcpy (name, d->filename, name_sz); 182b528cefcSMark Murray return 0; 183b528cefcSMark Murray } 184b528cefcSMark Murray 185b528cefcSMark Murray /* 186b528cefcSMark Murray * Init 187b528cefcSMark Murray */ 188b528cefcSMark Murray 189b528cefcSMark Murray static krb5_error_code 190b528cefcSMark Murray akf_start_seq_get(krb5_context context, 191b528cefcSMark Murray krb5_keytab id, 192b528cefcSMark Murray krb5_kt_cursor *c) 193b528cefcSMark Murray { 194b528cefcSMark Murray int32_t ret; 195b528cefcSMark Murray struct akf_data *d = id->data; 196b528cefcSMark Murray 197b528cefcSMark Murray c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600); 198adb0ddaeSAssar Westerlund if (c->fd < 0) { 199adb0ddaeSAssar Westerlund ret = errno; 200adb0ddaeSAssar Westerlund krb5_set_error_string(context, "open(%s): %s", d->filename, 201adb0ddaeSAssar Westerlund strerror(ret)); 202adb0ddaeSAssar Westerlund return ret; 203adb0ddaeSAssar Westerlund } 204b528cefcSMark Murray 205b528cefcSMark Murray c->sp = krb5_storage_from_fd(c->fd); 206b528cefcSMark Murray ret = krb5_ret_int32(c->sp, &d->num_entries); 207b528cefcSMark Murray if(ret) { 208b528cefcSMark Murray krb5_storage_free(c->sp); 209b528cefcSMark Murray close(c->fd); 210adb0ddaeSAssar Westerlund krb5_clear_error_string (context); 2118373020dSJacques Vidrine if(ret == KRB5_KT_END) 212adb0ddaeSAssar Westerlund return KRB5_KT_NOTFOUND; 213b528cefcSMark Murray return ret; 214b528cefcSMark Murray } 215b528cefcSMark Murray 216b528cefcSMark Murray return 0; 217b528cefcSMark Murray } 218b528cefcSMark Murray 219b528cefcSMark Murray static krb5_error_code 220b528cefcSMark Murray akf_next_entry(krb5_context context, 221b528cefcSMark Murray krb5_keytab id, 222b528cefcSMark Murray krb5_keytab_entry *entry, 223b528cefcSMark Murray krb5_kt_cursor *cursor) 224b528cefcSMark Murray { 225b528cefcSMark Murray struct akf_data *d = id->data; 226b528cefcSMark Murray int32_t kvno; 227b528cefcSMark Murray off_t pos; 228b528cefcSMark Murray int ret; 229b528cefcSMark Murray 2308373020dSJacques Vidrine pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); 231b528cefcSMark Murray 232b528cefcSMark Murray if ((pos - 4) / (4 + 8) >= d->num_entries) 233b528cefcSMark Murray return KRB5_KT_END; 234b528cefcSMark Murray 235b528cefcSMark Murray ret = krb5_make_principal (context, &entry->principal, 236b528cefcSMark Murray d->realm, "afs", d->cell, NULL); 237b528cefcSMark Murray if (ret) 238b528cefcSMark Murray goto out; 239b528cefcSMark Murray 240b528cefcSMark Murray ret = krb5_ret_int32(cursor->sp, &kvno); 241b528cefcSMark Murray if (ret) { 242b528cefcSMark Murray krb5_free_principal (context, entry->principal); 243b528cefcSMark Murray goto out; 244b528cefcSMark Murray } 245b528cefcSMark Murray 2465e9cd1aeSAssar Westerlund entry->vno = kvno; 247b528cefcSMark Murray 248b528cefcSMark Murray entry->keyblock.keytype = ETYPE_DES_CBC_MD5; 249b528cefcSMark Murray entry->keyblock.keyvalue.length = 8; 250b528cefcSMark Murray entry->keyblock.keyvalue.data = malloc (8); 251b528cefcSMark Murray if (entry->keyblock.keyvalue.data == NULL) { 252b528cefcSMark Murray krb5_free_principal (context, entry->principal); 253adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 254b528cefcSMark Murray ret = ENOMEM; 255b528cefcSMark Murray goto out; 256b528cefcSMark Murray } 257b528cefcSMark Murray 2588373020dSJacques Vidrine ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8); 259b528cefcSMark Murray if(ret != 8) 260b528cefcSMark Murray ret = (ret < 0) ? errno : KRB5_KT_END; 2615e9cd1aeSAssar Westerlund else 2625e9cd1aeSAssar Westerlund ret = 0; 263b528cefcSMark Murray 264b528cefcSMark Murray entry->timestamp = time(NULL); 265b528cefcSMark Murray 266b528cefcSMark Murray out: 2678373020dSJacques Vidrine krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET); 268b528cefcSMark Murray return ret; 269b528cefcSMark Murray } 270b528cefcSMark Murray 271b528cefcSMark Murray static krb5_error_code 272b528cefcSMark Murray akf_end_seq_get(krb5_context context, 273b528cefcSMark Murray krb5_keytab id, 274b528cefcSMark Murray krb5_kt_cursor *cursor) 275b528cefcSMark Murray { 276b528cefcSMark Murray krb5_storage_free(cursor->sp); 277b528cefcSMark Murray close(cursor->fd); 278b528cefcSMark Murray return 0; 279b528cefcSMark Murray } 280b528cefcSMark Murray 281b528cefcSMark Murray static krb5_error_code 282b528cefcSMark Murray akf_add_entry(krb5_context context, 283b528cefcSMark Murray krb5_keytab id, 284b528cefcSMark Murray krb5_keytab_entry *entry) 285b528cefcSMark Murray { 286b528cefcSMark Murray struct akf_data *d = id->data; 287b528cefcSMark Murray int fd, created = 0; 2885e9cd1aeSAssar Westerlund krb5_error_code ret; 2894137ff4cSJacques Vidrine int32_t len; 2904137ff4cSJacques Vidrine krb5_storage *sp; 2914137ff4cSJacques Vidrine 2924137ff4cSJacques Vidrine 2934137ff4cSJacques Vidrine if (entry->keyblock.keyvalue.length != 8 2944137ff4cSJacques Vidrine || entry->keyblock.keytype != ETYPE_DES_CBC_MD5) 2954137ff4cSJacques Vidrine return 0; 296b528cefcSMark Murray 297b528cefcSMark Murray fd = open (d->filename, O_RDWR | O_BINARY); 298b528cefcSMark Murray if (fd < 0) { 299b528cefcSMark Murray fd = open (d->filename, 300b528cefcSMark Murray O_RDWR | O_BINARY | O_CREAT, 0600); 301adb0ddaeSAssar Westerlund if (fd < 0) { 302adb0ddaeSAssar Westerlund ret = errno; 303adb0ddaeSAssar Westerlund krb5_set_error_string(context, "open(%s): %s", d->filename, 304adb0ddaeSAssar Westerlund strerror(ret)); 305adb0ddaeSAssar Westerlund return ret; 306adb0ddaeSAssar Westerlund } 307b528cefcSMark Murray created = 1; 308b528cefcSMark Murray } 309b528cefcSMark Murray 3105e9cd1aeSAssar Westerlund sp = krb5_storage_from_fd(fd); 3115e9cd1aeSAssar Westerlund if(sp == NULL) { 3125e9cd1aeSAssar Westerlund close(fd); 313adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 3145e9cd1aeSAssar Westerlund return ENOMEM; 3155e9cd1aeSAssar Westerlund } 3165e9cd1aeSAssar Westerlund if (created) 3175e9cd1aeSAssar Westerlund len = 0; 3185e9cd1aeSAssar Westerlund else { 3198373020dSJacques Vidrine if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) { 320adb0ddaeSAssar Westerlund ret = errno; 3215e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3225e9cd1aeSAssar Westerlund close(fd); 323adb0ddaeSAssar Westerlund krb5_set_error_string (context, "seek: %s", strerror(ret)); 324adb0ddaeSAssar Westerlund return ret; 325b528cefcSMark Murray } 326b528cefcSMark Murray 3275e9cd1aeSAssar Westerlund ret = krb5_ret_int32(sp, &len); 3285e9cd1aeSAssar Westerlund if(ret) { 3295e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3305e9cd1aeSAssar Westerlund close(fd); 3315e9cd1aeSAssar Westerlund return ret; 3325e9cd1aeSAssar Westerlund } 3335e9cd1aeSAssar Westerlund } 3345e9cd1aeSAssar Westerlund len++; 3355e9cd1aeSAssar Westerlund 3368373020dSJacques Vidrine if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) { 337adb0ddaeSAssar Westerlund ret = errno; 3385e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3395e9cd1aeSAssar Westerlund close(fd); 340adb0ddaeSAssar Westerlund krb5_set_error_string (context, "seek: %s", strerror(ret)); 341adb0ddaeSAssar Westerlund return ret; 3425e9cd1aeSAssar Westerlund } 343b528cefcSMark Murray 3445e9cd1aeSAssar Westerlund ret = krb5_store_int32(sp, len); 3455e9cd1aeSAssar Westerlund if(ret) { 3465e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3475e9cd1aeSAssar Westerlund close(fd); 3485e9cd1aeSAssar Westerlund return ret; 3495e9cd1aeSAssar Westerlund } 3505e9cd1aeSAssar Westerlund 3515e9cd1aeSAssar Westerlund 3528373020dSJacques Vidrine if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) { 353adb0ddaeSAssar Westerlund ret = errno; 3545e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3555e9cd1aeSAssar Westerlund close(fd); 356adb0ddaeSAssar Westerlund krb5_set_error_string (context, "seek: %s", strerror(ret)); 357adb0ddaeSAssar Westerlund return ret; 3585e9cd1aeSAssar Westerlund } 359b528cefcSMark Murray 3605e9cd1aeSAssar Westerlund ret = krb5_store_int32(sp, entry->vno); 3615e9cd1aeSAssar Westerlund if(ret) { 3625e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3635e9cd1aeSAssar Westerlund close(fd); 3645e9cd1aeSAssar Westerlund return ret; 3655e9cd1aeSAssar Westerlund } 3668373020dSJacques Vidrine ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data, 3675e9cd1aeSAssar Westerlund entry->keyblock.keyvalue.length); 3685e9cd1aeSAssar Westerlund if(ret != entry->keyblock.keyvalue.length) { 3695e9cd1aeSAssar Westerlund krb5_storage_free(sp); 3705e9cd1aeSAssar Westerlund close(fd); 3715e9cd1aeSAssar Westerlund if(ret < 0) 372b528cefcSMark Murray return errno; 3735e9cd1aeSAssar Westerlund return ENOTTY; 3745e9cd1aeSAssar Westerlund } 3755e9cd1aeSAssar Westerlund krb5_storage_free(sp); 376b528cefcSMark Murray close (fd); 377b528cefcSMark Murray return 0; 378b528cefcSMark Murray } 379b528cefcSMark Murray 380b528cefcSMark Murray const krb5_kt_ops krb5_akf_ops = { 381b528cefcSMark Murray "AFSKEYFILE", 382b528cefcSMark Murray akf_resolve, 383b528cefcSMark Murray akf_get_name, 384b528cefcSMark Murray akf_close, 385b528cefcSMark Murray NULL, /* get */ 386b528cefcSMark Murray akf_start_seq_get, 387b528cefcSMark Murray akf_next_entry, 388b528cefcSMark Murray akf_end_seq_get, 389b528cefcSMark Murray akf_add_entry, 390b528cefcSMark Murray NULL /* remove */ 391b528cefcSMark Murray }; 392