1 /* 2 * lib/kdb/kdb_xdr.c 3 * 4 * Copyright 1995 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 28 #include "k5-int.h" 29 #include <string.h> 30 #include <stdio.h> 31 #include <errno.h> 32 #include "kdb_xdr.h" 33 34 krb5_error_code 35 krb5_encode_princ_dbkey(context, key, principal) 36 krb5_context context; 37 krb5_data *key; 38 krb5_const_principal principal; 39 { 40 char *princ_name; 41 krb5_error_code retval; 42 43 if (!(retval = krb5_unparse_name(context, principal, &princ_name))) { 44 /* need to store the NULL for decoding */ 45 key->length = strlen(princ_name)+1; 46 key->data = princ_name; 47 } 48 return(retval); 49 } 50 51 void 52 krb5_free_princ_dbkey(context, key) 53 krb5_context context; 54 krb5_data *key; 55 { 56 (void) krb5_free_data_contents(context, key); 57 } 58 59 krb5_error_code 60 krb5_encode_princ_contents(context, content, entry) 61 krb5_context context; 62 krb5_data * content; 63 krb5_db_entry * entry; 64 { 65 int i, j; 66 unsigned int unparse_princ_size; 67 char * unparse_princ; 68 char * nextloc; 69 krb5_tl_data * tl_data; 70 krb5_error_code retval; 71 krb5_int16 psize16; 72 73 /* 74 * Generate one lump of data from the krb5_db_entry. 75 * This data must be independent of byte order of the machine, 76 * compact and extensible. 77 */ 78 79 /* 80 * First allocate enough space for all the data. 81 * Need 2 bytes for the length of the base structure 82 * then 36 [ 8 * 4 + 2 * 2] bytes for the base information 83 * [ attributes, max_life, max_renewable_life, expiration, 84 * pw_expiration, last_success, last_failed, fail_auth_count ] 85 * [ n_key_data, n_tl_data ] 86 * then XX bytes [ e_length ] for the extra data [ e_data ] 87 * then XX bytes [ 2 for length + length for string ] for the principal, 88 * then (4 [type + length] + tl_data_length) bytes per tl_data 89 * then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data 90 */ 91 content->length = entry->len + entry->e_length; 92 93 if ((retval = krb5_unparse_name(context, entry->princ, &unparse_princ))) 94 return(retval); 95 96 unparse_princ_size = strlen(unparse_princ) + 1; 97 content->length += unparse_princ_size; 98 content->length += 2; 99 100 i = 0; 101 /* tl_data is a linked list */ 102 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 103 content->length += tl_data->tl_data_length; 104 content->length += 4; /* type, length */ 105 i++; 106 } 107 108 if (i != entry->n_tl_data) { 109 retval = KRB5_KDB_TRUNCATED_RECORD; 110 goto epc_error; 111 } 112 113 /* key_data is an array */ 114 for (i = 0; i < entry->n_key_data; i++) { 115 content->length += 4; /* Version, KVNO */ 116 for (j = 0; j < entry->key_data[i].key_data_ver; j++) { 117 content->length += entry->key_data[i].key_data_length[j]; 118 content->length += 4; /* type + length */ 119 } 120 } 121 122 if ((content->data = malloc(content->length)) == NULL) { 123 retval = ENOMEM; 124 goto epc_error; 125 } 126 127 /* 128 * Now we go through entry again, this time copying data 129 * These first entries are always saved regardless of version 130 */ 131 nextloc = content->data; 132 133 /* Base Length */ 134 krb5_kdb_encode_int16(entry->len, nextloc); 135 nextloc += 2; 136 137 /* Attributes */ 138 krb5_kdb_encode_int32(entry->attributes, nextloc); 139 nextloc += 4; 140 141 /* Max Life */ 142 krb5_kdb_encode_int32(entry->max_life, nextloc); 143 nextloc += 4; 144 145 /* Max Renewable Life */ 146 krb5_kdb_encode_int32(entry->max_renewable_life, nextloc); 147 nextloc += 4; 148 149 /* When the client expires */ 150 krb5_kdb_encode_int32(entry->expiration, nextloc); 151 nextloc += 4; 152 153 /* When its passwd expires */ 154 krb5_kdb_encode_int32(entry->pw_expiration, nextloc); 155 nextloc += 4; 156 157 /* Last successful passwd */ 158 krb5_kdb_encode_int32(entry->last_success, nextloc); 159 nextloc += 4; 160 161 /* Last failed passwd attempt */ 162 krb5_kdb_encode_int32(entry->last_failed, nextloc); 163 nextloc += 4; 164 165 /* # of failed passwd attempt */ 166 krb5_kdb_encode_int32(entry->fail_auth_count, nextloc); 167 nextloc += 4; 168 169 /* # tl_data strutures */ 170 krb5_kdb_encode_int16(entry->n_tl_data, nextloc); 171 nextloc += 2; 172 173 /* # key_data strutures */ 174 krb5_kdb_encode_int16(entry->n_key_data, nextloc); 175 nextloc += 2; 176 177 /* Put extended fields here */ 178 if (entry->len != KRB5_KDB_V1_BASE_LENGTH) 179 abort(); 180 181 /* Any extra data that this version doesn't understand. */ 182 if (entry->e_length) { 183 memcpy(nextloc, entry->e_data, entry->e_length); 184 nextloc += entry->e_length; 185 } 186 187 /* 188 * Now we get to the principal. 189 * To squeze a few extra bytes out it is always assumed to come 190 * after the base type. 191 */ 192 psize16 = (krb5_int16) unparse_princ_size; 193 krb5_kdb_encode_int16(psize16, nextloc); 194 nextloc += 2; 195 (void) memcpy(nextloc, unparse_princ, unparse_princ_size); 196 nextloc += unparse_princ_size; 197 198 /* tl_data is a linked list, of type, legth, contents */ 199 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 200 krb5_kdb_encode_int16(tl_data->tl_data_type, nextloc); 201 nextloc += 2; 202 krb5_kdb_encode_int16(tl_data->tl_data_length, nextloc); 203 nextloc += 2; 204 205 memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length); 206 nextloc += tl_data->tl_data_length; 207 } 208 209 /* key_data is an array */ 210 for (i = 0; i < entry->n_key_data; i++) { 211 krb5_kdb_encode_int16(entry->key_data[i].key_data_ver, nextloc); 212 nextloc += 2; 213 krb5_kdb_encode_int16(entry->key_data[i].key_data_kvno, nextloc); 214 nextloc += 2; 215 216 for (j = 0; j < entry->key_data[i].key_data_ver; j++) { 217 krb5_int16 type = entry->key_data[i].key_data_type[j]; 218 krb5_ui_2 length = entry->key_data[i].key_data_length[j]; 219 220 krb5_kdb_encode_int16(type, nextloc); 221 nextloc += 2; 222 krb5_kdb_encode_int16(length, nextloc); 223 nextloc += 2; 224 225 if (length) { 226 memcpy(nextloc, entry->key_data[i].key_data_contents[j],length); 227 nextloc += length; 228 } 229 } 230 } 231 232 epc_error:; 233 free(unparse_princ); 234 return retval; 235 } 236 237 void 238 krb5_free_princ_contents(context, contents) 239 krb5_context context; 240 krb5_data *contents; 241 { 242 krb5_free_data_contents(context, contents); 243 return; 244 } 245 246 krb5_error_code 247 krb5_decode_princ_contents(context, content, entry) 248 krb5_context context; 249 krb5_data * content; 250 krb5_db_entry * entry; 251 { 252 int sizeleft, i; 253 char * nextloc; 254 krb5_tl_data ** tl_data; 255 krb5_int16 i16; 256 257 krb5_error_code retval; 258 259 /* Zero out entry and NULL pointers */ 260 memset(entry, 0, sizeof(krb5_db_entry)); 261 262 /* 263 * undo the effects of encode_princ_contents. 264 * 265 * The first part is decoding the base type. If the base type is 266 * bigger than the original base type then the additional fields 267 * need to be filled in. If the base type is larger than any 268 * known base type the additional data goes in e_data. 269 */ 270 271 /* First do the easy stuff */ 272 nextloc = content->data; 273 sizeleft = content->length; 274 if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0) 275 return KRB5_KDB_TRUNCATED_RECORD; 276 277 /* Base Length */ 278 krb5_kdb_decode_int16(nextloc, entry->len); 279 nextloc += 2; 280 281 /* Attributes */ 282 krb5_kdb_decode_int32(nextloc, entry->attributes); 283 nextloc += 4; 284 285 /* Max Life */ 286 krb5_kdb_decode_int32(nextloc, entry->max_life); 287 nextloc += 4; 288 289 /* Max Renewable Life */ 290 krb5_kdb_decode_int32(nextloc, entry->max_renewable_life); 291 nextloc += 4; 292 293 /* When the client expires */ 294 krb5_kdb_decode_int32(nextloc, entry->expiration); 295 nextloc += 4; 296 297 /* When its passwd expires */ 298 krb5_kdb_decode_int32(nextloc, entry->pw_expiration); 299 nextloc += 4; 300 301 /* Last successful passwd */ 302 krb5_kdb_decode_int32(nextloc, entry->last_success); 303 nextloc += 4; 304 305 /* Last failed passwd attempt */ 306 krb5_kdb_decode_int32(nextloc, entry->last_failed); 307 nextloc += 4; 308 309 /* # of failed passwd attempt */ 310 krb5_kdb_decode_int32(nextloc, entry->fail_auth_count); 311 nextloc += 4; 312 313 /* # tl_data strutures */ 314 krb5_kdb_decode_int16(nextloc, entry->n_tl_data); 315 nextloc += 2; 316 317 if (entry->n_tl_data < 0) 318 return KRB5_KDB_TRUNCATED_RECORD; 319 320 /* # key_data strutures */ 321 krb5_kdb_decode_int16(nextloc, entry->n_key_data); 322 nextloc += 2; 323 324 if (entry->n_key_data < 0) 325 return KRB5_KDB_TRUNCATED_RECORD; 326 327 /* Check for extra data */ 328 if (entry->len > KRB5_KDB_V1_BASE_LENGTH) { 329 entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH; 330 if ((entry->e_data = (krb5_octet *)malloc(entry->e_length))) { 331 memcpy(entry->e_data, nextloc, entry->e_length); 332 nextloc += entry->e_length; 333 } else { 334 return ENOMEM; 335 } 336 } 337 338 /* 339 * Get the principal name for the entry 340 * (stored as a string which gets unparsed.) 341 */ 342 if ((sizeleft -= 2) < 0) { 343 retval = KRB5_KDB_TRUNCATED_RECORD; 344 goto error_out; 345 } 346 347 i = 0; 348 krb5_kdb_decode_int16(nextloc, i16); 349 i = (int) i16; 350 nextloc += 2; 351 352 if ((retval = krb5_parse_name(context, nextloc, &(entry->princ)))) 353 goto error_out; 354 if (((size_t) i != (strlen(nextloc) + 1)) || (sizeleft < i)) { 355 retval = KRB5_KDB_TRUNCATED_RECORD; 356 goto error_out; 357 } 358 sizeleft -= i; 359 nextloc += i; 360 361 /* tl_data is a linked list */ 362 tl_data = &entry->tl_data; 363 for (i = 0; i < entry->n_tl_data; i++) { 364 if ((sizeleft -= 4) < 0) { 365 retval = KRB5_KDB_TRUNCATED_RECORD; 366 goto error_out; 367 } 368 if ((*tl_data = (krb5_tl_data *) 369 malloc(sizeof(krb5_tl_data))) == NULL) { 370 retval = ENOMEM; 371 goto error_out; 372 } 373 (*tl_data)->tl_data_next = NULL; 374 (*tl_data)->tl_data_contents = NULL; 375 krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type); 376 nextloc += 2; 377 krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length); 378 nextloc += 2; 379 380 if ((sizeleft -= (*tl_data)->tl_data_length) < 0) { 381 retval = KRB5_KDB_TRUNCATED_RECORD; 382 goto error_out; 383 } 384 if (((*tl_data)->tl_data_contents = (krb5_octet *) 385 malloc((*tl_data)->tl_data_length)) == NULL) { 386 retval = ENOMEM; 387 goto error_out; 388 } 389 memcpy((*tl_data)->tl_data_contents,nextloc,(*tl_data)->tl_data_length); 390 nextloc += (*tl_data)->tl_data_length; 391 tl_data = &((*tl_data)->tl_data_next); 392 } 393 394 /* key_data is an array */ 395 if (entry->n_key_data && ((entry->key_data = (krb5_key_data *) 396 malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) { 397 retval = ENOMEM; 398 goto error_out; 399 } 400 for (i = 0; i < entry->n_key_data; i++) { 401 krb5_key_data * key_data; 402 int j; 403 404 if ((sizeleft -= 4) < 0) { 405 retval = KRB5_KDB_TRUNCATED_RECORD; 406 goto error_out; 407 } 408 key_data = entry->key_data + i; 409 memset(key_data, 0, sizeof(krb5_key_data)); 410 krb5_kdb_decode_int16(nextloc, key_data->key_data_ver); 411 nextloc += 2; 412 krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno); 413 nextloc += 2; 414 415 /* key_data_ver determins number of elements and how to unparse them. */ 416 if (key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) { 417 for (j = 0; j < key_data->key_data_ver; j++) { 418 if ((sizeleft -= 4) < 0) { 419 retval = KRB5_KDB_TRUNCATED_RECORD; 420 goto error_out; 421 } 422 krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]); 423 nextloc += 2; 424 krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]); 425 nextloc += 2; 426 427 if ((sizeleft -= key_data->key_data_length[j]) < 0) { 428 retval = KRB5_KDB_TRUNCATED_RECORD; 429 goto error_out; 430 } 431 if (key_data->key_data_length[j]) { 432 if ((key_data->key_data_contents[j] = (krb5_octet *) 433 malloc(key_data->key_data_length[j])) == NULL) { 434 retval = ENOMEM; 435 goto error_out; 436 } 437 memcpy(key_data->key_data_contents[j], nextloc, 438 key_data->key_data_length[j]); 439 nextloc += key_data->key_data_length[j]; 440 } 441 } 442 } else { 443 /* This isn't right. I'll fix it later */ 444 abort(); 445 } 446 } 447 return 0; 448 449 error_out:; 450 krb5_dbe_free_contents(context, entry); 451 return retval; 452 } 453 454 void 455 krb5_dbe_free_contents(context, entry) 456 krb5_context context; 457 krb5_db_entry * entry; 458 { 459 krb5_tl_data * tl_data_next; 460 krb5_tl_data * tl_data; 461 int i, j; 462 463 if (entry->e_data) 464 free(entry->e_data); 465 if (entry->princ) 466 krb5_free_principal(context, entry->princ); 467 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) { 468 tl_data_next = tl_data->tl_data_next; 469 if (tl_data->tl_data_contents) 470 free(tl_data->tl_data_contents); 471 free(tl_data); 472 } 473 if (entry->key_data) { 474 for (i = 0; i < entry->n_key_data; i++) { 475 for (j = 0; j < entry->key_data[i].key_data_ver; j++) { 476 if (entry->key_data[i].key_data_length[j]) { 477 if (entry->key_data[i].key_data_contents[j]) { 478 memset(entry->key_data[i].key_data_contents[j], 479 0, 480 (unsigned) entry->key_data[i].key_data_length[j]); 481 free (entry->key_data[i].key_data_contents[j]); 482 } 483 } 484 entry->key_data[i].key_data_contents[j] = NULL; 485 entry->key_data[i].key_data_length[j] = 0; 486 entry->key_data[i].key_data_type[j] = 0; 487 } 488 } 489 free(entry->key_data); 490 } 491 memset(entry, 0, sizeof(*entry)); 492 return; 493 } 494