Path: blob/main/crypto/krb5/src/plugins/kdb/db2/kdb_xdr.c
34914 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* plugins/kdb/db2/kdb_xdr.c */2/*3* Copyright 1995 by the Massachusetts Institute of Technology.4* All Rights Reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/2526#include "k5-int.h"27#include <string.h>28#include <stdio.h>29#include <errno.h>30#include "kdb_xdr.h"3132krb5_error_code33krb5_encode_princ_dbkey(krb5_context context, krb5_data *key,34krb5_const_principal principal)35{36char *princ_name;37krb5_error_code retval;3839if (!(retval = krb5_unparse_name(context, principal, &princ_name))) {40/* need to store the NULL for decoding */41key->length = strlen(princ_name)+1;42key->data = princ_name;43}44return(retval);45}4647krb5_error_code48krb5_encode_princ_entry(krb5_context context, krb5_data *content,49krb5_db_entry *entry)50{51int i, j;52unsigned int unparse_princ_size;53char * unparse_princ;54unsigned char * nextloc;55krb5_tl_data * tl_data;56krb5_error_code retval;57krb5_int16 psize16;5859/*60* Generate one lump of data from the krb5_db_entry.61* This data must be independent of byte order of the machine,62* compact and extensible.63*/6465/*66* First allocate enough space for all the data.67* Need 2 bytes for the length of the base structure68* then 36 [ 8 * 4 + 2 * 2] bytes for the base information69* [ attributes, max_life, max_renewable_life, expiration,70* pw_expiration, last_success, last_failed, fail_auth_count ]71* [ n_key_data, n_tl_data ]72* then XX bytes [ e_length ] for the extra data [ e_data ]73* then XX bytes [ 2 for length + length for string ] for the principal,74* then (4 [type + length] + tl_data_length) bytes per tl_data75* then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data76*/77content->length = entry->len + entry->e_length;7879if ((retval = krb5_unparse_name(context, entry->princ, &unparse_princ)))80return(retval);8182unparse_princ_size = strlen(unparse_princ) + 1;83content->length += unparse_princ_size;84content->length += 2;8586i = 0;87/* tl_data is a linked list */88for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {89content->length += tl_data->tl_data_length;90content->length += 4; /* type, length */91i++;92}9394if (i != entry->n_tl_data) {95retval = KRB5_KDB_TRUNCATED_RECORD;96goto epc_error;97}9899/* key_data is an array */100for (i = 0; i < entry->n_key_data; i++) {101content->length += 4; /* Version, KVNO */102for (j = 0; j < entry->key_data[i].key_data_ver; j++) {103content->length += entry->key_data[i].key_data_length[j];104content->length += 4; /* type + length */105}106}107108if ((content->data = malloc(content->length)) == NULL) {109retval = ENOMEM;110goto epc_error;111}112113/*114* Now we go through entry again, this time copying data115* These first entries are always saved regardless of version116*/117nextloc = (unsigned char *)content->data;118119/* Base Length */120krb5_kdb_encode_int16(entry->len, nextloc);121nextloc += 2;122123/* Attributes */124krb5_kdb_encode_int32(entry->attributes, nextloc);125nextloc += 4;126127/* Max Life */128krb5_kdb_encode_int32(entry->max_life, nextloc);129nextloc += 4;130131/* Max Renewable Life */132krb5_kdb_encode_int32(entry->max_renewable_life, nextloc);133nextloc += 4;134135/* When the client expires */136krb5_kdb_encode_int32(entry->expiration, nextloc);137nextloc += 4;138139/* When its passwd expires */140krb5_kdb_encode_int32(entry->pw_expiration, nextloc);141nextloc += 4;142143/* Last successful passwd */144krb5_kdb_encode_int32(entry->last_success, nextloc);145nextloc += 4;146147/* Last failed passwd attempt */148krb5_kdb_encode_int32(entry->last_failed, nextloc);149nextloc += 4;150151/* # of failed passwd attempt */152krb5_kdb_encode_int32(entry->fail_auth_count, nextloc);153nextloc += 4;154155/* # tl_data structures */156krb5_kdb_encode_int16(entry->n_tl_data, nextloc);157nextloc += 2;158159/* # key_data structures */160krb5_kdb_encode_int16(entry->n_key_data, nextloc);161nextloc += 2;162163/* Put extended fields here */164if (entry->len != KRB5_KDB_V1_BASE_LENGTH)165abort();166167/* Any extra data that this version doesn't understand. */168if (entry->e_length) {169memcpy(nextloc, entry->e_data, entry->e_length);170nextloc += entry->e_length;171}172173/*174* Now we get to the principal.175* To squeze a few extra bytes out it is always assumed to come176* after the base type.177*/178psize16 = (krb5_int16) unparse_princ_size;179krb5_kdb_encode_int16(psize16, nextloc);180nextloc += 2;181(void) memcpy(nextloc, unparse_princ, unparse_princ_size);182nextloc += unparse_princ_size;183184/* tl_data is a linked list, of type, length, contents */185for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {186krb5_kdb_encode_int16(tl_data->tl_data_type, nextloc);187nextloc += 2;188krb5_kdb_encode_int16(tl_data->tl_data_length, nextloc);189nextloc += 2;190191memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length);192nextloc += tl_data->tl_data_length;193}194195/* key_data is an array */196for (i = 0; i < entry->n_key_data; i++) {197krb5_kdb_encode_int16(entry->key_data[i].key_data_ver, nextloc);198nextloc += 2;199krb5_kdb_encode_int16(entry->key_data[i].key_data_kvno, nextloc);200nextloc += 2;201202for (j = 0; j < entry->key_data[i].key_data_ver; j++) {203krb5_int16 type = entry->key_data[i].key_data_type[j];204krb5_ui_2 length = entry->key_data[i].key_data_length[j];205206krb5_kdb_encode_int16(type, nextloc);207nextloc += 2;208krb5_kdb_encode_int16(length, nextloc);209nextloc += 2;210211if (length) {212memcpy(nextloc, entry->key_data[i].key_data_contents[j],length);213nextloc += length;214}215}216}217218epc_error:;219free(unparse_princ);220return retval;221}222223krb5_error_code224krb5_decode_princ_entry(krb5_context context, krb5_data *content,225krb5_db_entry **entry_ptr)226{227int sizeleft, i;228unsigned char * nextloc;229krb5_tl_data ** tl_data;230krb5_int16 i16;231krb5_db_entry * entry;232krb5_error_code retval;233234*entry_ptr = NULL;235236entry = k5alloc(sizeof(*entry), &retval);237if (entry == NULL)238return retval;239240/*241* Reverse the encoding of encode_princ_entry.242*243* The first part is decoding the base type. If the base type is244* bigger than the original base type then the additional fields245* need to be filled in. If the base type is larger than any246* known base type the additional data goes in e_data.247*/248249/* First do the easy stuff */250nextloc = (unsigned char *)content->data;251sizeleft = content->length;252if (sizeleft < KRB5_KDB_V1_BASE_LENGTH) {253retval = KRB5_KDB_TRUNCATED_RECORD;254goto error_out;255}256sizeleft -= KRB5_KDB_V1_BASE_LENGTH;257258/* Base Length */259krb5_kdb_decode_int16(nextloc, entry->len);260nextloc += 2;261262/* Attributes */263krb5_kdb_decode_int32(nextloc, entry->attributes);264nextloc += 4;265266/* Max Life */267krb5_kdb_decode_int32(nextloc, entry->max_life);268nextloc += 4;269270/* Max Renewable Life */271krb5_kdb_decode_int32(nextloc, entry->max_renewable_life);272nextloc += 4;273274/* When the client expires */275krb5_kdb_decode_int32(nextloc, entry->expiration);276nextloc += 4;277278/* When its passwd expires */279krb5_kdb_decode_int32(nextloc, entry->pw_expiration);280nextloc += 4;281282/* Last successful passwd */283krb5_kdb_decode_int32(nextloc, entry->last_success);284nextloc += 4;285286/* Last failed passwd attempt */287krb5_kdb_decode_int32(nextloc, entry->last_failed);288nextloc += 4;289290/* # of failed passwd attempt */291krb5_kdb_decode_int32(nextloc, entry->fail_auth_count);292nextloc += 4;293294/* # tl_data structures */295krb5_kdb_decode_int16(nextloc, entry->n_tl_data);296nextloc += 2;297298if (entry->n_tl_data < 0) {299retval = KRB5_KDB_TRUNCATED_RECORD;300goto error_out;301}302303/* # key_data structures */304krb5_kdb_decode_int16(nextloc, entry->n_key_data);305nextloc += 2;306307if (entry->n_key_data < 0) {308retval = KRB5_KDB_TRUNCATED_RECORD;309goto error_out;310}311312/* Check for extra data */313if (entry->len > KRB5_KDB_V1_BASE_LENGTH) {314entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH;315entry->e_data = k5memdup(nextloc, entry->e_length, &retval);316if (entry->e_data == NULL)317goto error_out;318nextloc += entry->e_length;319}320321/*322* Get the principal name for the entry323* (stored as a string which gets unparsed.)324*/325if (sizeleft < 2) {326retval = KRB5_KDB_TRUNCATED_RECORD;327goto error_out;328}329sizeleft -= 2;330331i = 0;332krb5_kdb_decode_int16(nextloc, i16);333i = (int) i16;334nextloc += 2;335if (i <= 0 || i > sizeleft || nextloc[i - 1] != '\0' ||336memchr((char *)nextloc, '\0', i - 1) != NULL) {337retval = KRB5_KDB_TRUNCATED_RECORD;338goto error_out;339}340341if ((retval = krb5_parse_name(context, (char *)nextloc, &(entry->princ))))342goto error_out;343sizeleft -= i;344nextloc += i;345346/* tl_data is a linked list */347tl_data = &entry->tl_data;348for (i = 0; i < entry->n_tl_data; i++) {349if (sizeleft < 4) {350retval = KRB5_KDB_TRUNCATED_RECORD;351goto error_out;352}353sizeleft -= 4;354if ((*tl_data = (krb5_tl_data *)355malloc(sizeof(krb5_tl_data))) == NULL) {356retval = ENOMEM;357goto error_out;358}359(*tl_data)->tl_data_next = NULL;360(*tl_data)->tl_data_contents = NULL;361krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type);362nextloc += 2;363krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length);364nextloc += 2;365366if ((*tl_data)->tl_data_length > sizeleft) {367retval = KRB5_KDB_TRUNCATED_RECORD;368goto error_out;369}370sizeleft -= (*tl_data)->tl_data_length;371(*tl_data)->tl_data_contents =372k5memdup(nextloc, (*tl_data)->tl_data_length, &retval);373if ((*tl_data)->tl_data_contents == NULL)374goto error_out;375nextloc += (*tl_data)->tl_data_length;376tl_data = &((*tl_data)->tl_data_next);377}378379/* key_data is an array */380if (entry->n_key_data && ((entry->key_data = (krb5_key_data *)381malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) {382retval = ENOMEM;383goto error_out;384}385for (i = 0; i < entry->n_key_data; i++) {386krb5_key_data * key_data;387int j;388389if (sizeleft < 4) {390retval = KRB5_KDB_TRUNCATED_RECORD;391goto error_out;392}393sizeleft -= 4;394key_data = entry->key_data + i;395memset(key_data, 0, sizeof(krb5_key_data));396krb5_kdb_decode_int16(nextloc, key_data->key_data_ver);397nextloc += 2;398krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno);399nextloc += 2;400401/* key_data_ver determines number of elements and how to unparse402* them. */403if (key_data->key_data_ver >= 0 &&404key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) {405for (j = 0; j < key_data->key_data_ver; j++) {406if (sizeleft < 4) {407retval = KRB5_KDB_TRUNCATED_RECORD;408goto error_out;409}410sizeleft -= 4;411krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]);412nextloc += 2;413krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]);414nextloc += 2;415416if (key_data->key_data_length[j] > sizeleft) {417retval = KRB5_KDB_TRUNCATED_RECORD;418goto error_out;419}420sizeleft -= key_data->key_data_length[j];421if (key_data->key_data_length[j]) {422key_data->key_data_contents[j] =423k5memdup(nextloc, key_data->key_data_length[j],424&retval);425if (key_data->key_data_contents[j] == NULL)426goto error_out;427nextloc += key_data->key_data_length[j];428}429}430} else {431retval = KRB5_KDB_BAD_VERSION;432goto error_out;433}434}435*entry_ptr = entry;436return 0;437438error_out:439krb5_db_free_principal(context, entry);440return retval;441}442443444