1b528cefcSMark Murray /* 2b528cefcSMark 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 36b528cefcSMark Murray RCSID("$Id: keytab_keyfile.c,v 1.7 2000/01/02 04:00:22 assar 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 66b528cefcSMark Murray get_cell_and_realm (struct akf_data *d) 67b528cefcSMark Murray { 68b528cefcSMark Murray FILE *f; 69b528cefcSMark Murray char buf[BUFSIZ], *cp; 70b528cefcSMark Murray 71b528cefcSMark Murray f = fopen (AFS_SERVERTHISCELL, "r"); 72b528cefcSMark Murray if (f == NULL) 73b528cefcSMark Murray return errno; 74b528cefcSMark Murray if (fgets (buf, sizeof(buf), f) == NULL) { 75b528cefcSMark Murray fclose (f); 76b528cefcSMark Murray return EINVAL; 77b528cefcSMark Murray } 78b528cefcSMark Murray if (buf[strlen(buf) - 1] == '\n') 79b528cefcSMark Murray buf[strlen(buf) - 1] = '\0'; 80b528cefcSMark Murray fclose(f); 81b528cefcSMark Murray 82b528cefcSMark Murray d->cell = strdup (buf); 83b528cefcSMark Murray if (d->cell == NULL) 84b528cefcSMark Murray return errno; 85b528cefcSMark Murray 86b528cefcSMark Murray f = fopen (AFS_SERVERMAGICKRBCONF, "r"); 87b528cefcSMark Murray if (f != NULL) { 88b528cefcSMark Murray if (fgets (buf, sizeof(buf), f) == NULL) { 89b528cefcSMark Murray fclose (f); 90b528cefcSMark Murray return EINVAL; 91b528cefcSMark Murray } 92b528cefcSMark Murray if (buf[strlen(buf)-1] == '\n') 93b528cefcSMark Murray buf[strlen(buf)-1] = '\0'; 94b528cefcSMark Murray fclose(f); 95b528cefcSMark Murray } 96b528cefcSMark Murray /* uppercase */ 97b528cefcSMark Murray for (cp = buf; *cp != '\0'; cp++) 98b528cefcSMark Murray *cp = toupper(*cp); 99b528cefcSMark Murray 100b528cefcSMark Murray d->realm = strdup (buf); 101b528cefcSMark Murray if (d->realm == NULL) { 102b528cefcSMark Murray free (d->cell); 103b528cefcSMark Murray return errno; 104b528cefcSMark Murray } 105b528cefcSMark Murray return 0; 106b528cefcSMark Murray } 107b528cefcSMark Murray 108b528cefcSMark Murray /* 109b528cefcSMark Murray * init and get filename 110b528cefcSMark Murray */ 111b528cefcSMark Murray 112b528cefcSMark Murray static krb5_error_code 113b528cefcSMark Murray akf_resolve(krb5_context context, const char *name, krb5_keytab id) 114b528cefcSMark Murray { 115b528cefcSMark Murray int ret; 116b528cefcSMark Murray struct akf_data *d = malloc(sizeof (struct akf_data)); 117b528cefcSMark Murray 118b528cefcSMark Murray if (d == NULL) 119b528cefcSMark Murray return errno; 120b528cefcSMark Murray 121b528cefcSMark Murray d->num_entries = 0; 122b528cefcSMark Murray ret = get_cell_and_realm (d); 123b528cefcSMark Murray if (ret) { 124b528cefcSMark Murray free (d); 125b528cefcSMark Murray return ret; 126b528cefcSMark Murray } 127b528cefcSMark Murray d->filename = strdup (name); 128b528cefcSMark Murray if (d->filename == NULL) { 129b528cefcSMark Murray free (d->cell); 130b528cefcSMark Murray free (d->realm); 131b528cefcSMark Murray free (d); 132b528cefcSMark Murray return ENOMEM; 133b528cefcSMark Murray } 134b528cefcSMark Murray id->data = d; 135b528cefcSMark Murray 136b528cefcSMark Murray return 0; 137b528cefcSMark Murray } 138b528cefcSMark Murray 139b528cefcSMark Murray /* 140b528cefcSMark Murray * cleanup 141b528cefcSMark Murray */ 142b528cefcSMark Murray 143b528cefcSMark Murray static krb5_error_code 144b528cefcSMark Murray akf_close(krb5_context context, krb5_keytab id) 145b528cefcSMark Murray { 146b528cefcSMark Murray struct akf_data *d = id->data; 147b528cefcSMark Murray 148b528cefcSMark Murray free (d->filename); 149b528cefcSMark Murray free (d->cell); 150b528cefcSMark Murray free (d); 151b528cefcSMark Murray return 0; 152b528cefcSMark Murray } 153b528cefcSMark Murray 154b528cefcSMark Murray /* 155b528cefcSMark Murray * Return filename 156b528cefcSMark Murray */ 157b528cefcSMark Murray 158b528cefcSMark Murray static krb5_error_code 159b528cefcSMark Murray akf_get_name(krb5_context context, 160b528cefcSMark Murray krb5_keytab id, 161b528cefcSMark Murray char *name, 162b528cefcSMark Murray size_t name_sz) 163b528cefcSMark Murray { 164b528cefcSMark Murray struct akf_data *d = id->data; 165b528cefcSMark Murray 166b528cefcSMark Murray strlcpy (name, d->filename, name_sz); 167b528cefcSMark Murray return 0; 168b528cefcSMark Murray } 169b528cefcSMark Murray 170b528cefcSMark Murray /* 171b528cefcSMark Murray * Init 172b528cefcSMark Murray */ 173b528cefcSMark Murray 174b528cefcSMark Murray static krb5_error_code 175b528cefcSMark Murray akf_start_seq_get(krb5_context context, 176b528cefcSMark Murray krb5_keytab id, 177b528cefcSMark Murray krb5_kt_cursor *c) 178b528cefcSMark Murray { 179b528cefcSMark Murray int32_t ret; 180b528cefcSMark Murray struct akf_data *d = id->data; 181b528cefcSMark Murray 182b528cefcSMark Murray c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600); 183b528cefcSMark Murray if (c->fd < 0) 184b528cefcSMark Murray return errno; 185b528cefcSMark Murray 186b528cefcSMark Murray c->sp = krb5_storage_from_fd(c->fd); 187b528cefcSMark Murray ret = krb5_ret_int32(c->sp, &d->num_entries); 188b528cefcSMark Murray if(ret) { 189b528cefcSMark Murray krb5_storage_free(c->sp); 190b528cefcSMark Murray close(c->fd); 191b528cefcSMark Murray return ret; 192b528cefcSMark Murray } 193b528cefcSMark Murray 194b528cefcSMark Murray return 0; 195b528cefcSMark Murray } 196b528cefcSMark Murray 197b528cefcSMark Murray static krb5_error_code 198b528cefcSMark Murray akf_next_entry(krb5_context context, 199b528cefcSMark Murray krb5_keytab id, 200b528cefcSMark Murray krb5_keytab_entry *entry, 201b528cefcSMark Murray krb5_kt_cursor *cursor) 202b528cefcSMark Murray { 203b528cefcSMark Murray struct akf_data *d = id->data; 204b528cefcSMark Murray int32_t kvno; 205b528cefcSMark Murray off_t pos; 206b528cefcSMark Murray int ret; 207b528cefcSMark Murray 208b528cefcSMark Murray pos = cursor->sp->seek(cursor->sp, 0, SEEK_CUR); 209b528cefcSMark Murray 210b528cefcSMark Murray if ((pos - 4) / (4 + 8) >= d->num_entries) 211b528cefcSMark Murray return KRB5_KT_END; 212b528cefcSMark Murray 213b528cefcSMark Murray ret = krb5_make_principal (context, &entry->principal, 214b528cefcSMark Murray d->realm, "afs", d->cell, NULL); 215b528cefcSMark Murray if (ret) 216b528cefcSMark Murray goto out; 217b528cefcSMark Murray 218b528cefcSMark Murray ret = krb5_ret_int32(cursor->sp, &kvno); 219b528cefcSMark Murray if (ret) { 220b528cefcSMark Murray krb5_free_principal (context, entry->principal); 221b528cefcSMark Murray goto out; 222b528cefcSMark Murray } 223b528cefcSMark Murray 224b528cefcSMark Murray entry->vno = (int8_t) kvno; 225b528cefcSMark Murray 226b528cefcSMark Murray entry->keyblock.keytype = ETYPE_DES_CBC_MD5; 227b528cefcSMark Murray entry->keyblock.keyvalue.length = 8; 228b528cefcSMark Murray entry->keyblock.keyvalue.data = malloc (8); 229b528cefcSMark Murray if (entry->keyblock.keyvalue.data == NULL) { 230b528cefcSMark Murray krb5_free_principal (context, entry->principal); 231b528cefcSMark Murray ret = ENOMEM; 232b528cefcSMark Murray goto out; 233b528cefcSMark Murray } 234b528cefcSMark Murray 235b528cefcSMark Murray ret = cursor->sp->fetch(cursor->sp, entry->keyblock.keyvalue.data, 8); 236b528cefcSMark Murray if(ret != 8) 237b528cefcSMark Murray ret = (ret < 0) ? errno : KRB5_KT_END; 238b528cefcSMark Murray 239b528cefcSMark Murray entry->timestamp = time(NULL); 240b528cefcSMark Murray 241b528cefcSMark Murray out: 242b528cefcSMark Murray cursor->sp->seek(cursor->sp, pos + 4 + 8, SEEK_SET); 243b528cefcSMark Murray return ret; 244b528cefcSMark Murray } 245b528cefcSMark Murray 246b528cefcSMark Murray static krb5_error_code 247b528cefcSMark Murray akf_end_seq_get(krb5_context context, 248b528cefcSMark Murray krb5_keytab id, 249b528cefcSMark Murray krb5_kt_cursor *cursor) 250b528cefcSMark Murray { 251b528cefcSMark Murray krb5_storage_free(cursor->sp); 252b528cefcSMark Murray close(cursor->fd); 253b528cefcSMark Murray return 0; 254b528cefcSMark Murray } 255b528cefcSMark Murray 256b528cefcSMark Murray static krb5_error_code 257b528cefcSMark Murray akf_add_entry(krb5_context context, 258b528cefcSMark Murray krb5_keytab id, 259b528cefcSMark Murray krb5_keytab_entry *entry) 260b528cefcSMark Murray { 261b528cefcSMark Murray struct akf_data *d = id->data; 262b528cefcSMark Murray int fd, created = 0; 263b528cefcSMark Murray int32_t kvno; 264b528cefcSMark Murray 265b528cefcSMark Murray fd = open (d->filename, O_RDWR | O_BINARY); 266b528cefcSMark Murray if (fd < 0) { 267b528cefcSMark Murray fd = open (d->filename, 268b528cefcSMark Murray O_RDWR | O_BINARY | O_CREAT, 0600); 269b528cefcSMark Murray if (fd < 0) 270b528cefcSMark Murray return errno; 271b528cefcSMark Murray created = 1; 272b528cefcSMark Murray } 273b528cefcSMark Murray 274b528cefcSMark Murray if (entry->keyblock.keyvalue.length == 8 275b528cefcSMark Murray && entry->keyblock.keytype == ETYPE_DES_CBC_MD5) { 276b528cefcSMark Murray 277b528cefcSMark Murray int32_t len = 0; 278b528cefcSMark Murray 279b528cefcSMark Murray if (!created) { 280b528cefcSMark Murray if (lseek (fd, 0, SEEK_SET)) 281b528cefcSMark Murray return errno; 282b528cefcSMark Murray 283b528cefcSMark Murray if (read (fd, &len, sizeof(len)) != sizeof(len)) 284b528cefcSMark Murray return errno; 285b528cefcSMark Murray } 286b528cefcSMark Murray len += 1; 287b528cefcSMark Murray 288b528cefcSMark Murray if (lseek (fd, 0, SEEK_SET)) 289b528cefcSMark Murray return errno; 290b528cefcSMark Murray 291b528cefcSMark Murray if (write (fd, &len, sizeof(len)) != sizeof(len)) 292b528cefcSMark Murray return errno; 293b528cefcSMark Murray 294b528cefcSMark Murray if (lseek (fd, 4 + (len-1) * (8+4), SEEK_SET)) 295b528cefcSMark Murray return errno; 296b528cefcSMark Murray 297b528cefcSMark Murray kvno = entry->vno; 298b528cefcSMark Murray write(fd, &kvno, sizeof(kvno)); 299b528cefcSMark Murray write(fd, entry->keyblock.keyvalue.data, 8); 300b528cefcSMark Murray } 301b528cefcSMark Murray close (fd); 302b528cefcSMark Murray return 0; 303b528cefcSMark Murray } 304b528cefcSMark Murray 305b528cefcSMark Murray const krb5_kt_ops krb5_akf_ops = { 306b528cefcSMark Murray "AFSKEYFILE", 307b528cefcSMark Murray akf_resolve, 308b528cefcSMark Murray akf_get_name, 309b528cefcSMark Murray akf_close, 310b528cefcSMark Murray NULL, /* get */ 311b528cefcSMark Murray akf_start_seq_get, 312b528cefcSMark Murray akf_next_entry, 313b528cefcSMark Murray akf_end_seq_get, 314b528cefcSMark Murray akf_add_entry, 315b528cefcSMark Murray NULL /* remove */ 316b528cefcSMark Murray }; 317