-: 0:Source:kdb_default.c -: 0:Graph:/var/tsitkova/Sources/v10/trunk/src/lib/kdb/kdb_default.so.gcno -: 0:Data:/var/tsitkova/Sources/v10/trunk/src/lib/kdb/kdb_default.so.gcda -: 0:Runs:956 -: 0:Programs:1 -: 1:/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -: 2:/* lib/kdb/kdb_default.c */ -: 3:/* -: 4: * Copyright 1995, 2009 by the Massachusetts Institute of Technology. -: 5: * All Rights Reserved. -: 6: * -: 7: * Export of this software from the United States of America may -: 8: * require a specific license from the United States Government. -: 9: * It is the responsibility of any person or organization contemplating -: 10: * export to obtain such a license before exporting. -: 11: * -: 12: * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and -: 13: * distribute this software and its documentation for any purpose and -: 14: * without fee is hereby granted, provided that the above copyright -: 15: * notice appear in all copies and that both that copyright notice and -: 16: * this permission notice appear in supporting documentation, and that -: 17: * the name of M.I.T. not be used in advertising or publicity pertaining -: 18: * to distribution of the software without specific, written prior -: 19: * permission. Furthermore if you modify this software you must label -: 20: * your software as modified software and not distribute it in such a -: 21: * fashion that it might be confused with the original M.I.T. software. -: 22: * M.I.T. makes no representations about the suitability of -: 23: * this software for any purpose. It is provided "as is" without express -: 24: * or implied warranty. -: 25: */ -: 26:/* -: 27: * Copyright 2009 Sun Microsystems, Inc. All rights reserved. -: 28: * Use is subject to license terms. -: 29: */ -: 30: -: 31:#include "k5-int.h" -: 32:#include "kdb.h" -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37: -: 38: -: 39:/* -: 40: * Given a particular enctype and optional salttype and kvno, find the -: 41: * most appropriate krb5_key_data entry of the database entry. -: 42: * -: 43: * If stype or kvno is negative, it is ignored. -: 44: * If kvno is 0 get the key which is maxkvno for the princ and matches -: 45: * the other attributes. -: 46: */ -: 47:krb5_error_code 1994: 48:krb5_dbe_def_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap) -: 49: krb5_context kcontext; -: 50: krb5_db_entry *dbentp; -: 51: krb5_int32 *start; -: 52: krb5_int32 ktype; -: 53: krb5_int32 stype; -: 54: krb5_int32 kvno; -: 55: krb5_key_data **kdatap; -: 56:{ -: 57: int i, idx; -: 58: int maxkvno; -: 59: krb5_key_data *datap; -: 60: krb5_error_code ret; 1994: 61: krb5_boolean saw_non_permitted = FALSE; -: 62: 1994: 63: ret = 0; 1994: 64: if (kvno == -1 && stype == -1 && ktype == -1) #####: 65: kvno = 0; -: 66: 1994: 67: if (kvno == 0) { -: 68: /* Get the max key version */ 6283: 69: for (i = 0; i < dbentp->n_key_data; i++) { 4454: 70: if (kvno < dbentp->key_data[i].key_data_kvno) { 1829: 71: kvno = dbentp->key_data[i].key_data_kvno; -: 72: } -: 73: } -: 74: } -: 75: 1994: 76: maxkvno = -1; 1994: 77: idx = -1; 1994: 78: datap = (krb5_key_data *) NULL; 6733: 79: for (i = *start; i < dbentp->n_key_data; i++) { -: 80: krb5_boolean similar; -: 81: krb5_int32 db_stype; -: 82: 4739: 83: ret = 0; 4739: 84: if (dbentp->key_data[i].key_data_ver > 1) { 48: 85: db_stype = dbentp->key_data[i].key_data_type[1]; -: 86: } else { 4691: 87: db_stype = KRB5_KDB_SALTTYPE_NORMAL; -: 88: } -: 89: -: 90: /* Match this entry against the arguments. */ 4739: 91: if (ktype != -1) { 1614: 92: ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype, 1614: 93: dbentp->key_data[i].key_data_type[0], -: 94: &similar); 1614: 95: if (ret != 0 || !similar) 1097: 96: continue; -: 97: } 3642: 98: if (stype >= 0 && db_stype != stype) #####: 99: continue; 3642: 100: if (kvno >= 0 && dbentp->key_data[i].key_data_kvno != kvno) 3: 101: continue; -: 102: -: 103: /* Filter out non-permitted enctypes. */ 3639: 104: if (!krb5_is_permitted_enctype(kcontext, 3639: 105: dbentp->key_data[i].key_data_type[0])) { #####: 106: saw_non_permitted = TRUE; #####: 107: continue; -: 108: } -: 109: 3639: 110: if (dbentp->key_data[i].key_data_kvno > maxkvno) { 1875: 111: maxkvno = dbentp->key_data[i].key_data_kvno; 1875: 112: datap = &dbentp->key_data[i]; 1875: 113: idx = i; -: 114: } -: 115: } -: 116: /* If we scanned the whole set of keys and matched only non-permitted -: 117: * enctypes, indicate that. */ 1994: 118: if (maxkvno < 0 && *start == 0 && saw_non_permitted) #####: 119: ret = KRB5_KDB_NO_PERMITTED_KEY; 1994: 120: if (maxkvno < 0) 119: 121: return ret ? ret : KRB5_KDB_NO_MATCHING_KEY; 1875: 122: *kdatap = datap; 1875: 123: *start = idx+1; 1875: 124: return 0; -: 125:} -: 126: -: 127:/* -: 128: * kdb default functions. Ideally, some other file should have this functions. For now, TBD. -: 129: */ -: 130:#ifndef min -: 131:#define min(a,b) (((a) < (b)) ? (a) : (b)) -: 132:#endif -: 133: -: 134:krb5_error_code 99: 135:krb5_def_store_mkey_list(krb5_context context, -: 136: char *keyfile, -: 137: krb5_principal mname, -: 138: krb5_keylist_node *keylist, -: 139: char *master_pwd) -: 140:{ 99: 141: krb5_error_code retval = 0; -: 142: char defkeyfile[MAXPATHLEN+1]; 99: 143: char *tmp_ktname = NULL, *tmp_ktpath; 99: 144: krb5_data *realm = krb5_princ_realm(context, mname); 99: 145: krb5_keytab kt = NULL; -: 146: krb5_keytab_entry new_entry; -: 147: struct stat stb; -: 148: int statrc; -: 149: 99: 150: if (!keyfile) { #####: 151: (void) snprintf(defkeyfile, sizeof(defkeyfile), "%s%s", -: 152: DEFAULT_KEYFILE_STUB, realm->data); #####: 153: keyfile = defkeyfile; -: 154: } -: 155: -: 156: /* -: 157: * XXX making the assumption that the keyfile is in a dir that requires root -: 158: * privilege to write to thus making timing attacks unlikely. -: 159: */ 99: 160: if ((statrc = stat(keyfile, &stb)) >= 0) { -: 161: /* if keyfile exists it better be a regular file */ #####: 162: if (!S_ISREG(stb.st_mode)) { #####: 163: retval = EINVAL; #####: 164: krb5_set_error_message(context, retval, #####: 165: _("keyfile (%s) is not a regular file: %s"), -: 166: keyfile, error_message(retval)); #####: 167: goto out; -: 168: } -: 169: } -: 170: -: 171: /* Use temp keytab file name in case creation of keytab fails */ -: 172: -: 173: /* create temp file template for use by mktemp() */ 99: 174: if ((retval = asprintf(&tmp_ktname, "WRFILE:%s_XXXXXX", keyfile)) < 0) { #####: 175: krb5_set_error_message(context, retval, #####: 176: _("Could not create temp keytab file name.")); #####: 177: goto out; -: 178: } -: 179: -: 180: /* -: 181: * Set tmp_ktpath to point to the keyfile path (skip WRFILE:). Subtracting -: 182: * 1 to account for NULL terminator in sizeof calculation of a string -: 183: * constant. Used further down. -: 184: */ 99: 185: tmp_ktpath = tmp_ktname + (sizeof("WRFILE:") - 1); -: 186: 99: 187: if (mktemp(tmp_ktpath) == NULL) { #####: 188: retval = errno; #####: 189: krb5_set_error_message(context, retval, #####: 190: _("Could not create temp stash file: %s"), #####: 191: error_message(errno)); #####: 192: goto out; -: 193: } -: 194: -: 195: /* create new stash keytab using temp file name */ 99: 196: retval = krb5_kt_resolve(context, tmp_ktname, &kt); 99: 197: if (retval != 0) #####: 198: goto out; -: 199: 297: 200: while (keylist && !retval) { 99: 201: memset(&new_entry, 0, sizeof(new_entry)); 99: 202: new_entry.principal = mname; 99: 203: new_entry.key = keylist->keyblock; 99: 204: new_entry.vno = keylist->kvno; -: 205: 99: 206: retval = krb5_kt_add_entry(context, kt, &new_entry); 99: 207: keylist = keylist->next; -: 208: } 99: 209: krb5_kt_close(context, kt); -: 210: 99: 211: if (retval != 0) { -: 212: /* delete tmp keyfile if it exists and an error occurrs */ #####: 213: if (stat(keyfile, &stb) >= 0) #####: 214: (void) unlink(tmp_ktpath); -: 215: } else { -: 216: /* rename original keyfile to original filename */ 99: 217: if (rename(tmp_ktpath, keyfile) < 0) { #####: 218: retval = errno; #####: 219: krb5_set_error_message(context, retval, #####: 220: _("rename of temporary keyfile (%s) to " -: 221: "(%s) failed: %s"), tmp_ktpath, keyfile, #####: 222: error_message(errno)); -: 223: } -: 224: } -: 225: -: 226:out: 99: 227: if (tmp_ktname != NULL) 99: 228: free(tmp_ktname); -: 229: 99: 230: return retval; -: 231:} -: 232: -: 233:static krb5_error_code 1: 234:krb5_db_def_fetch_mkey_stash(krb5_context context, -: 235: const char *keyfile, -: 236: krb5_keyblock *key, -: 237: krb5_kvno *kvno) -: 238:{ 1: 239: krb5_error_code retval = 0; -: 240: krb5_ui_2 enctype; -: 241: krb5_ui_4 keylength; 1: 242: FILE *kf = NULL; -: 243: -: 244:#ifdef ANSI_STDIO 1: 245: if (!(kf = fopen(keyfile, "rb"))) -: 246:#else -: 247: if (!(kf = fopen(keyfile, "r"))) -: 248:#endif #####: 249: return KRB5_KDB_CANTREAD_STORED; 1: 250: set_cloexec_file(kf); -: 251: 1: 252: if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) { #####: 253: retval = KRB5_KDB_CANTREAD_STORED; #####: 254: goto errout; -: 255: } -: 256: -: 257:#if BIG_ENDIAN_MASTER_KEY -: 258: enctype = ntohs((uint16_t) enctype); -: 259:#endif -: 260: 1: 261: if (key->enctype == ENCTYPE_UNKNOWN) 1: 262: key->enctype = enctype; #####: 263: else if (enctype != key->enctype) { #####: 264: retval = KRB5_KDB_BADSTORED_MKEY; #####: 265: goto errout; -: 266: } -: 267: 1: 268: if (fread((krb5_pointer) &keylength, -: 269: sizeof(keylength), 1, kf) != 1) { #####: 270: retval = KRB5_KDB_CANTREAD_STORED; #####: 271: goto errout; -: 272: } -: 273: -: 274:#if BIG_ENDIAN_MASTER_KEY -: 275: key->length = ntohl((uint32_t) keylength); -: 276:#else 1: 277: key->length = keylength; -: 278:#endif -: 279: 1: 280: if (!key->length || ((int) key->length) < 0) { #####: 281: retval = KRB5_KDB_BADSTORED_MKEY; #####: 282: goto errout; -: 283: } -: 284: 1: 285: if (!(key->contents = (krb5_octet *)malloc(key->length))) { #####: 286: retval = ENOMEM; #####: 287: goto errout; -: 288: } -: 289: 1: 290: if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]), -: 291: key->length, kf) != key->length) { #####: 292: retval = KRB5_KDB_CANTREAD_STORED; #####: 293: zap(key->contents, key->length); #####: 294: free(key->contents); #####: 295: key->contents = 0; -: 296: } else 1: 297: retval = 0; -: 298: -: 299: /* -: 300: * Note, the old stash format did not store the kvno and at this point it -: 301: * can be assumed to be 1 as is the case for the mkey princ. If the kvno is -: 302: * passed in and isn't ignore_vno just leave it alone as this could cause -: 303: * verifcation trouble if the mkey princ is using a kvno other than 1. -: 304: */ 1: 305: if (kvno && *kvno == IGNORE_VNO) 1: 306: *kvno = 1; -: 307: -: 308:errout: 1: 309: (void) fclose(kf); 1: 310: return retval; -: 311:} -: 312: -: 313:static krb5_error_code 765: 314:krb5_db_def_fetch_mkey_keytab(krb5_context context, -: 315: const char *keyfile, -: 316: krb5_principal mname, -: 317: krb5_keyblock *key, -: 318: krb5_kvno *kvno) -: 319:{ 765: 320: krb5_error_code retval = 0; 765: 321: krb5_keytab kt = NULL; -: 322: krb5_keytab_entry kt_ent; 765: 323: krb5_enctype enctype = IGNORE_ENCTYPE; -: 324: 765: 325: if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0) #####: 326: goto errout; -: 327: -: 328: /* override default */ 765: 329: if (key->enctype != ENCTYPE_UNKNOWN) #####: 330: enctype = key->enctype; -: 331: 765: 332: if ((retval = krb5_kt_get_entry(context, kt, mname, -: 333: kvno ? *kvno : IGNORE_VNO, -: 334: enctype, -: 335: &kt_ent)) == 0) { -: 336: 764: 337: if (key->enctype == ENCTYPE_UNKNOWN) 764: 338: key->enctype = kt_ent.key.enctype; -: 339: 764: 340: if (((int) kt_ent.key.length) < 0) { #####: 341: retval = KRB5_KDB_BADSTORED_MKEY; #####: 342: krb5_kt_free_entry(context, &kt_ent); #####: 343: goto errout; -: 344: } -: 345: 764: 346: key->length = kt_ent.key.length; -: 347: -: 348: /* -: 349: * If a kvno pointer was passed in and it dereferences the -: 350: * IGNORE_VNO value then it should be assigned the value of the kvno -: 351: * found in the keytab otherwise the KNVO specified should be the -: 352: * same as the one returned from the keytab. -: 353: */ 764: 354: if (kvno != NULL && *kvno == IGNORE_VNO) 764: 355: *kvno = kt_ent.vno; -: 356: -: 357: /* -: 358: * kt_ent will be free'd so need to allocate and copy key contents for -: 359: * output to caller. -: 360: */ 764: 361: if (!(key->contents = (krb5_octet *)malloc(key->length))) { #####: 362: retval = ENOMEM; #####: 363: krb5_kt_free_entry(context, &kt_ent); #####: 364: goto errout; -: 365: } 764: 366: memcpy(key->contents, kt_ent.key.contents, kt_ent.key.length); 764: 367: krb5_kt_free_entry(context, &kt_ent); -: 368: } -: 369: -: 370:errout: 765: 371: if (kt) 765: 372: krb5_kt_close(context, kt); -: 373: 765: 374: return retval; -: 375:} -: 376: -: 377:krb5_error_code 765: 378:krb5_db_def_fetch_mkey(krb5_context context, -: 379: krb5_principal mname, -: 380: krb5_keyblock *key, -: 381: krb5_kvno *kvno, -: 382: char *db_args) -: 383:{ -: 384: krb5_error_code retval; -: 385: char keyfile[MAXPATHLEN+1]; 765: 386: krb5_data *realm = krb5_princ_realm(context, mname); -: 387: 765: 388: key->magic = KV5M_KEYBLOCK; -: 389: 765: 390: if (db_args != NULL) { 765: 391: (void) strncpy(keyfile, db_args, sizeof(keyfile)); -: 392: } else { #####: 393: (void) snprintf(keyfile, sizeof(keyfile), "%s%s", -: 394: DEFAULT_KEYFILE_STUB, realm->data); -: 395: } -: 396: /* null terminate no matter what */ 765: 397: keyfile[sizeof(keyfile) - 1] = '\0'; -: 398: -: 399: /* Try the keytab and old stash file formats. */ 765: 400: retval = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno); 765: 401: if (retval == KRB5_KEYTAB_BADVNO) 1: 402: retval = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno); -: 403: -: 404: /* -: 405: * Use a generic error code for failure to retrieve the master -: 406: * key, but set a message indicating the actual error. -: 407: */ 765: 408: if (retval != 0) { #####: 409: krb5_set_error_message(context, KRB5_KDB_CANTREAD_STORED, #####: 410: _("Can not fetch master key (error: %s)."), -: 411: error_message(retval)); #####: 412: return KRB5_KDB_CANTREAD_STORED; -: 413: } else 765: 414: return 0; -: 415:} -: 416: -: 417:krb5_error_code 775: 418:krb5_def_fetch_mkey_list(krb5_context context, -: 419: krb5_principal mprinc, -: 420: const krb5_keyblock *mkey, -: 421: krb5_kvno mkvno, -: 422: krb5_keylist_node **mkeys_list) -: 423:{ -: 424: krb5_error_code retval; -: 425: krb5_db_entry *master_entry; 775: 426: krb5_boolean found_key = FALSE; -: 427: krb5_keyblock cur_mkey; 775: 428: krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node; -: 429: krb5_key_data *key_data; 775: 430: krb5_mkey_aux_node *mkey_aux_data_list = NULL, *aux_data_entry; -: 431: int i; -: 432: 775: 433: if (mkeys_list == NULL) #####: 434: return (EINVAL); -: 435: 775: 436: memset(&cur_mkey, 0, sizeof(cur_mkey)); -: 437: 775: 438: retval = krb5_db_get_principal(context, mprinc, 0, &master_entry); 775: 439: if (retval == KRB5_KDB_NOENTRY) #####: 440: return (KRB5_KDB_NOMASTERKEY); 775: 441: if (retval) #####: 442: return (retval); -: 443: -: 444: /* -: 445: * Check if the input mkey is the latest key and if it isn't then find the -: 446: * latest mkey. -: 447: */ -: 448: 775: 449: if (mkey->enctype == master_entry->key_data[0].key_data_type[0]) { 775: 450: if (krb5_dbe_decrypt_key_data(context, mkey, 775: 451: &master_entry->key_data[0], -: 452: &cur_mkey, NULL) == 0) { 775: 453: found_key = TRUE; -: 454: } -: 455: } -: 456: 775: 457: if (!found_key) { #####: 458: if ((retval = krb5_dbe_lookup_mkey_aux(context, master_entry, -: 459: &mkey_aux_data_list))) #####: 460: goto clean_n_exit; -: 461: #####: 462: for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL; #####: 463: aux_data_entry = aux_data_entry->next) { -: 464: #####: 465: if (krb5_dbe_decrypt_key_data(context, mkey, #####: 466: &aux_data_entry->latest_mkey, -: 467: &cur_mkey, NULL) == 0) { #####: 468: found_key = TRUE; #####: 469: break; -: 470: } -: 471: } #####: 472: if (found_key != TRUE) { #####: 473: krb5_set_error_message(context, KRB5_KDB_BADMASTERKEY, #####: 474: _("Unable to decrypt latest master key " -: 475: "with the provided master key\n")); #####: 476: retval = KRB5_KDB_BADMASTERKEY; #####: 477: goto clean_n_exit; -: 478: } -: 479: } -: 480: -: 481: /* -: 482: * Extract all the mkeys from master_entry using the most current mkey and -: 483: * create a mkey list for the mkeys field in kdc_realm_t. -: 484: */ -: 485: 775: 486: mkey_list_head = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node)); 775: 487: if (mkey_list_head == NULL) { #####: 488: retval = ENOMEM; #####: 489: goto clean_n_exit; -: 490: } -: 491: 775: 492: memset(mkey_list_head, 0, sizeof(krb5_keylist_node)); -: 493: -: 494: /* Set mkey_list_head to the current mkey as an optimization. */ -: 495: /* mkvno may not be latest so ... */ 775: 496: mkey_list_head->kvno = master_entry->key_data[0].key_data_kvno; -: 497: /* this is the latest clear mkey (avoids a redundant decrypt) */ 775: 498: mkey_list_head->keyblock = cur_mkey; -: 499: -: 500: /* loop through any other master keys creating a list of krb5_keylist_nodes */ 775: 501: mkey_list_node = &mkey_list_head->next; 775: 502: for (i = 1; i < master_entry->n_key_data; i++) { #####: 503: if (*mkey_list_node == NULL) { -: 504: /* *mkey_list_node points to next field of previous node */ #####: 505: *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node)); #####: 506: if (*mkey_list_node == NULL) { #####: 507: retval = ENOMEM; #####: 508: goto clean_n_exit; -: 509: } #####: 510: memset(*mkey_list_node, 0, sizeof(krb5_keylist_node)); -: 511: } #####: 512: key_data = &master_entry->key_data[i]; #####: 513: retval = krb5_dbe_decrypt_key_data(context, &cur_mkey, key_data, #####: 514: &((*mkey_list_node)->keyblock), -: 515: NULL); #####: 516: if (retval) #####: 517: goto clean_n_exit; -: 518: #####: 519: (*mkey_list_node)->kvno = key_data->key_data_kvno; #####: 520: mkey_list_node = &((*mkey_list_node)->next); -: 521: } -: 522: 775: 523: *mkeys_list = mkey_list_head; -: 524: -: 525:clean_n_exit: 775: 526: krb5_db_free_principal(context, master_entry); 775: 527: krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_list); 775: 528: if (retval != 0) #####: 529: krb5_dbe_free_key_list(context, mkey_list_head); 775: 530: return retval; -: 531:}