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