1 /* 2 * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 36 RCSID("$Id: keytab_keyfile.c,v 1.11 2001/05/14 06:14:49 assar Exp $"); 37 38 /* afs keyfile operations --------------------------------------- */ 39 40 /* 41 * Minimum tools to handle the AFS KeyFile. 42 * 43 * Format of the KeyFile is: 44 * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys} 45 * 46 * It just adds to the end of the keyfile, deleting isn't implemented. 47 * Use your favorite text/hex editor to delete keys. 48 * 49 */ 50 51 #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell" 52 #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf" 53 54 struct akf_data { 55 int num_entries; 56 char *filename; 57 char *cell; 58 char *realm; 59 }; 60 61 /* 62 * set `d->cell' and `d->realm' 63 */ 64 65 static int 66 get_cell_and_realm (krb5_context context, 67 struct akf_data *d) 68 { 69 FILE *f; 70 char buf[BUFSIZ], *cp; 71 int ret; 72 73 f = fopen (AFS_SERVERTHISCELL, "r"); 74 if (f == NULL) { 75 ret = errno; 76 krb5_set_error_string (context, "open %s: %s", AFS_SERVERTHISCELL, 77 strerror(ret)); 78 return ret; 79 } 80 if (fgets (buf, sizeof(buf), f) == NULL) { 81 fclose (f); 82 krb5_set_error_string (context, "no cell in %s", AFS_SERVERTHISCELL); 83 return EINVAL; 84 } 85 if (buf[strlen(buf) - 1] == '\n') 86 buf[strlen(buf) - 1] = '\0'; 87 fclose(f); 88 89 d->cell = strdup (buf); 90 if (d->cell == NULL) { 91 krb5_set_error_string (context, "malloc: out of memory"); 92 return ENOMEM; 93 } 94 95 f = fopen (AFS_SERVERMAGICKRBCONF, "r"); 96 if (f != NULL) { 97 if (fgets (buf, sizeof(buf), f) == NULL) { 98 fclose (f); 99 krb5_set_error_string (context, "no realm in %s", 100 AFS_SERVERMAGICKRBCONF); 101 return EINVAL; 102 } 103 if (buf[strlen(buf)-1] == '\n') 104 buf[strlen(buf)-1] = '\0'; 105 fclose(f); 106 } 107 /* uppercase */ 108 for (cp = buf; *cp != '\0'; cp++) 109 *cp = toupper(*cp); 110 111 d->realm = strdup (buf); 112 if (d->realm == NULL) { 113 free (d->cell); 114 krb5_set_error_string (context, "malloc: out of memory"); 115 return ENOMEM; 116 } 117 return 0; 118 } 119 120 /* 121 * init and get filename 122 */ 123 124 static krb5_error_code 125 akf_resolve(krb5_context context, const char *name, krb5_keytab id) 126 { 127 int ret; 128 struct akf_data *d = malloc(sizeof (struct akf_data)); 129 130 if (d == NULL) { 131 krb5_set_error_string (context, "malloc: out of memory"); 132 return ENOMEM; 133 } 134 135 d->num_entries = 0; 136 ret = get_cell_and_realm (context, d); 137 if (ret) { 138 free (d); 139 return ret; 140 } 141 d->filename = strdup (name); 142 if (d->filename == NULL) { 143 free (d->cell); 144 free (d->realm); 145 free (d); 146 krb5_set_error_string (context, "malloc: out of memory"); 147 return ENOMEM; 148 } 149 id->data = d; 150 151 return 0; 152 } 153 154 /* 155 * cleanup 156 */ 157 158 static krb5_error_code 159 akf_close(krb5_context context, krb5_keytab id) 160 { 161 struct akf_data *d = id->data; 162 163 free (d->filename); 164 free (d->cell); 165 free (d); 166 return 0; 167 } 168 169 /* 170 * Return filename 171 */ 172 173 static krb5_error_code 174 akf_get_name(krb5_context context, 175 krb5_keytab id, 176 char *name, 177 size_t name_sz) 178 { 179 struct akf_data *d = id->data; 180 181 strlcpy (name, d->filename, name_sz); 182 return 0; 183 } 184 185 /* 186 * Init 187 */ 188 189 static krb5_error_code 190 akf_start_seq_get(krb5_context context, 191 krb5_keytab id, 192 krb5_kt_cursor *c) 193 { 194 int32_t ret; 195 struct akf_data *d = id->data; 196 197 c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600); 198 if (c->fd < 0) { 199 ret = errno; 200 krb5_set_error_string(context, "open(%s): %s", d->filename, 201 strerror(ret)); 202 return ret; 203 } 204 205 c->sp = krb5_storage_from_fd(c->fd); 206 ret = krb5_ret_int32(c->sp, &d->num_entries); 207 if(ret) { 208 krb5_storage_free(c->sp); 209 close(c->fd); 210 krb5_clear_error_string (context); 211 if(ret == KRB5_CC_END) 212 return KRB5_KT_NOTFOUND; 213 return ret; 214 } 215 216 return 0; 217 } 218 219 static krb5_error_code 220 akf_next_entry(krb5_context context, 221 krb5_keytab id, 222 krb5_keytab_entry *entry, 223 krb5_kt_cursor *cursor) 224 { 225 struct akf_data *d = id->data; 226 int32_t kvno; 227 off_t pos; 228 int ret; 229 230 pos = cursor->sp->seek(cursor->sp, 0, SEEK_CUR); 231 232 if ((pos - 4) / (4 + 8) >= d->num_entries) 233 return KRB5_KT_END; 234 235 ret = krb5_make_principal (context, &entry->principal, 236 d->realm, "afs", d->cell, NULL); 237 if (ret) 238 goto out; 239 240 ret = krb5_ret_int32(cursor->sp, &kvno); 241 if (ret) { 242 krb5_free_principal (context, entry->principal); 243 goto out; 244 } 245 246 entry->vno = kvno; 247 248 entry->keyblock.keytype = ETYPE_DES_CBC_MD5; 249 entry->keyblock.keyvalue.length = 8; 250 entry->keyblock.keyvalue.data = malloc (8); 251 if (entry->keyblock.keyvalue.data == NULL) { 252 krb5_free_principal (context, entry->principal); 253 krb5_set_error_string (context, "malloc: out of memory"); 254 ret = ENOMEM; 255 goto out; 256 } 257 258 ret = cursor->sp->fetch(cursor->sp, entry->keyblock.keyvalue.data, 8); 259 if(ret != 8) 260 ret = (ret < 0) ? errno : KRB5_KT_END; 261 else 262 ret = 0; 263 264 entry->timestamp = time(NULL); 265 266 out: 267 cursor->sp->seek(cursor->sp, pos + 4 + 8, SEEK_SET); 268 return ret; 269 } 270 271 static krb5_error_code 272 akf_end_seq_get(krb5_context context, 273 krb5_keytab id, 274 krb5_kt_cursor *cursor) 275 { 276 krb5_storage_free(cursor->sp); 277 close(cursor->fd); 278 return 0; 279 } 280 281 static krb5_error_code 282 akf_add_entry(krb5_context context, 283 krb5_keytab id, 284 krb5_keytab_entry *entry) 285 { 286 struct akf_data *d = id->data; 287 int fd, created = 0; 288 krb5_error_code ret; 289 290 fd = open (d->filename, O_RDWR | O_BINARY); 291 if (fd < 0) { 292 fd = open (d->filename, 293 O_RDWR | O_BINARY | O_CREAT, 0600); 294 if (fd < 0) { 295 ret = errno; 296 krb5_set_error_string(context, "open(%s): %s", d->filename, 297 strerror(ret)); 298 return ret; 299 } 300 created = 1; 301 } 302 303 if (entry->keyblock.keyvalue.length == 8 304 && entry->keyblock.keytype == ETYPE_DES_CBC_MD5) { 305 306 int32_t len; 307 krb5_storage *sp; 308 309 sp = krb5_storage_from_fd(fd); 310 if(sp == NULL) { 311 close(fd); 312 krb5_set_error_string (context, "malloc: out of memory"); 313 return ENOMEM; 314 } 315 if (created) 316 len = 0; 317 else { 318 if((*sp->seek)(sp, 0, SEEK_SET) < 0) { 319 ret = errno; 320 krb5_storage_free(sp); 321 close(fd); 322 krb5_set_error_string (context, "seek: %s", strerror(ret)); 323 return ret; 324 } 325 326 ret = krb5_ret_int32(sp, &len); 327 if(ret) { 328 krb5_storage_free(sp); 329 close(fd); 330 return ret; 331 } 332 } 333 len++; 334 335 if((*sp->seek)(sp, 0, SEEK_SET) < 0) { 336 ret = errno; 337 krb5_storage_free(sp); 338 close(fd); 339 krb5_set_error_string (context, "seek: %s", strerror(ret)); 340 return ret; 341 } 342 343 ret = krb5_store_int32(sp, len); 344 if(ret) { 345 krb5_storage_free(sp); 346 close(fd); 347 return ret; 348 } 349 350 351 if((*sp->seek)(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) { 352 ret = errno; 353 krb5_storage_free(sp); 354 close(fd); 355 krb5_set_error_string (context, "seek: %s", strerror(ret)); 356 return ret; 357 } 358 359 ret = krb5_store_int32(sp, entry->vno); 360 if(ret) { 361 krb5_storage_free(sp); 362 close(fd); 363 return ret; 364 } 365 ret = sp->store(sp, entry->keyblock.keyvalue.data, 366 entry->keyblock.keyvalue.length); 367 if(ret != entry->keyblock.keyvalue.length) { 368 krb5_storage_free(sp); 369 close(fd); 370 if(ret < 0) 371 return errno; 372 return ENOTTY; 373 } 374 krb5_storage_free(sp); 375 } 376 close (fd); 377 return 0; 378 } 379 380 const krb5_kt_ops krb5_akf_ops = { 381 "AFSKEYFILE", 382 akf_resolve, 383 akf_get_name, 384 akf_close, 385 NULL, /* get */ 386 akf_start_seq_get, 387 akf_next_entry, 388 akf_end_seq_get, 389 akf_add_entry, 390 NULL /* remove */ 391 }; 392