krb5_error_code krb5_decode_princ_entry(krb5_context context, krb5_data *content, krb5_db_entry **entry_ptr) { int sizeleft, i; unsigned char * nextloc; krb5_tl_data ** tl_data; krb5_int16 i16; krb5_db_entry * entry; krb5_error_code retval; *entry_ptr = NULL; entry = k5alloc(sizeof(*entry), &retval); if (entry == NULL) return retval; /* * Reverse the encoding of encode_princ_entry. * * The first part is decoding the base type. If the base type is * bigger than the original base type then the additional fields * need to be filled in. If the base type is larger than any * known base type the additional data goes in e_data. */ /* First do the easy stuff */ nextloc = (unsigned char *)content->data; sizeleft = content->length; if (sizeleft < KRB5_KDB_V1_BASE_LENGTH) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= KRB5_KDB_V1_BASE_LENGTH; /* Base Length */ krb5_kdb_decode_int16(nextloc, entry->len); nextloc += 2; /* Attributes */ krb5_kdb_decode_int32(nextloc, entry->attributes); nextloc += 4; /* Max Life */ krb5_kdb_decode_int32(nextloc, entry->max_life); nextloc += 4; /* Max Renewable Life */ krb5_kdb_decode_int32(nextloc, entry->max_renewable_life); nextloc += 4; /* When the client expires */ krb5_kdb_decode_int32(nextloc, entry->expiration); nextloc += 4; /* When its passwd expires */ krb5_kdb_decode_int32(nextloc, entry->pw_expiration); nextloc += 4; /* Last successful passwd */ krb5_kdb_decode_int32(nextloc, entry->last_success); nextloc += 4; /* Last failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->last_failed); nextloc += 4; /* # of failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->fail_auth_count); nextloc += 4; /* # tl_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_tl_data); nextloc += 2; if (entry->n_tl_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* # key_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_key_data); nextloc += 2; if (entry->n_key_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* Check for extra data */ if (entry->len > KRB5_KDB_V1_BASE_LENGTH) { entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH; entry->e_data = k5memdup(nextloc, entry->e_length, &retval); if (entry->e_data == NULL) goto error_out; nextloc += entry->e_length; } /* * Get the principal name for the entry * (stored as a string which gets unparsed.) */ if (sizeleft < 2) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 2; i = 0; krb5_kdb_decode_int16(nextloc, i16); i = (int) i16; nextloc += 2; if (i <= 0 || i > sizeleft || nextloc[i - 1] != '\0' || memchr((char *)nextloc, '\0', i - 1) != NULL) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } if ((retval = krb5_parse_name(context, (char *)nextloc, &(entry->princ)))) goto error_out; sizeleft -= i; nextloc += i; /* tl_data is a linked list */ tl_data = &entry->tl_data; for (i = 0; i < entry->n_tl_data; i++) { if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; if ((*tl_data = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) == NULL) { retval = ENOMEM; goto error_out; } (*tl_data)->tl_data_next = NULL; (*tl_data)->tl_data_contents = NULL; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type); nextloc += 2; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length); nextloc += 2; if ((*tl_data)->tl_data_length > sizeleft) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= (*tl_data)->tl_data_length; (*tl_data)->tl_data_contents = k5memdup(nextloc, (*tl_data)->tl_data_length, &retval); if ((*tl_data)->tl_data_contents == NULL) goto error_out; nextloc += (*tl_data)->tl_data_length; tl_data = &((*tl_data)->tl_data_next); } /* key_data is an array */ if (entry->n_key_data && ((entry->key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) { retval = ENOMEM; goto error_out; } for (i = 0; i < entry->n_key_data; i++) { krb5_key_data * key_data; int j; if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; key_data = entry->key_data + i; memset(key_data, 0, sizeof(krb5_key_data)); krb5_kdb_decode_int16(nextloc, key_data->key_data_ver); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno); nextloc += 2; /* key_data_ver determins number of elements and how to unparse them. */ if (key_data->key_data_ver >= 0 && key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) { for (j = 0; j < key_data->key_data_ver; j++) { if (sizeleft < 4) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= 4; krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]); nextloc += 2; if (key_data->key_data_length[j] > sizeleft) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= key_data->key_data_length[j]; if (key_data->key_data_length[j]) { key_data->key_data_contents[j] = k5memdup(nextloc, key_data->key_data_length[j], &retval); if (key_data->key_data_contents[j] == NULL) goto error_out; nextloc += key_data->key_data_length[j]; } } } else { retval = KRB5_KDB_BAD_VERSION; goto error_out; } } *entry_ptr = entry; return 0; error_out: krb5_db_free_principal(context, entry); return retval; }
krb5_error_code krb5_dbekd_decrypt_key_data( krb5_context context, const krb5_keyblock * mkey, const krb5_key_data * key_data, krb5_keyblock * dbkey, krb5_keysalt * keysalt) { krb5_error_code retval = 0; krb5_int16 tmplen; krb5_octet * ptr; krb5_enc_data cipher; krb5_data plain; ptr = key_data->key_data_contents[0]; if (ptr) { krb5_kdb_decode_int16(ptr, tmplen); ptr += 2; cipher.enctype = ENCTYPE_UNKNOWN; cipher.ciphertext.length = key_data->key_data_length[0]-2; cipher.ciphertext.data = (char *)ptr; /* SUNWresync121 XXX */ plain.length = key_data->key_data_length[0]-2; if ((plain.data = (char *) malloc(plain.length)) == NULL) return(ENOMEM); (void) memset(plain.data, 0, plain.length); if ((retval = krb5_c_decrypt(context, mkey, 0 /* XXX */, 0, &cipher, &plain))) { krb5_xfree(plain.data); return retval; } /* tmplen is the true length of the key. plain.data is the plaintext data length, but it may be padded, since the old-style etypes didn't store the real length. I can check to make sure that there are enough bytes, but I can't do any better than that. */ if (tmplen > plain.length) { krb5_xfree(plain.data); return(KRB5_CRYPTO_INTERNAL); } dbkey->magic = KV5M_KEYBLOCK; dbkey->enctype = key_data->key_data_type[0]; dbkey->length = tmplen; dbkey->contents = (unsigned char *) plain.data; /* SUNWresync121 XXX */ dbkey->dk_list = NULL; dbkey->hKey = CK_INVALID_HANDLE; } /* Decode salt data */ if (keysalt) { if (key_data->key_data_ver == 2) { keysalt->type = key_data->key_data_type[1]; if ((keysalt->data.length = key_data->key_data_length[1])) { if (!(keysalt->data.data=(char *)malloc(keysalt->data.length))){ if (key_data->key_data_contents[0]) { krb5_xfree(dbkey->contents); dbkey->contents = 0; dbkey->length = 0; } return ENOMEM; } memcpy(keysalt->data.data, key_data->key_data_contents[1], (size_t) keysalt->data.length); } else keysalt->data.data = (char *) NULL; } else { keysalt->type = KRB5_KDB_SALTTYPE_NORMAL; keysalt->data.data = (char *) NULL; keysalt->data.length = 0; } } return retval; }