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