1 /* 2 * lib/krb5/krb/ser_ctx.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 /* 29 * ser_ctx.c - Routines to deal with serializing the krb5_context and 30 * krb5_os_context structures. 31 */ 32 #include "k5-int.h" 33 34 /* 35 * Routines to deal with externalizing the krb5_context: 36 * krb5_context_size(); 37 * krb5_context_externalize(); 38 * krb5_context_internalize(); 39 * 40 * Routines to deal with externalizing the krb5_os_context: 41 * krb5_oscontext_size(); 42 * krb5_oscontext_externalize(); 43 * krb5_oscontext_internalize(); 44 * 45 * Routines to deal with externalizing the profile. 46 * profile_ser_size(); 47 * profile_ser_externalize(); 48 * profile_ser_internalize(); 49 * 50 * Interface to initialize serializing of krb5_context and krb5_os_context: 51 * krb5_ser_context_init(); 52 */ 53 static krb5_error_code krb5_context_size 54 (krb5_context, krb5_pointer, size_t *); 55 static krb5_error_code krb5_context_externalize 56 (krb5_context, krb5_pointer, krb5_octet **, size_t *); 57 static krb5_error_code krb5_context_internalize 58 (krb5_context,krb5_pointer *, krb5_octet **, size_t *); 59 static krb5_error_code krb5_oscontext_size 60 (krb5_context, krb5_pointer, size_t *); 61 static krb5_error_code krb5_oscontext_externalize 62 (krb5_context, krb5_pointer, krb5_octet **, size_t *); 63 static krb5_error_code krb5_oscontext_internalize 64 (krb5_context,krb5_pointer *, krb5_octet **, size_t *); 65 #ifndef _KERNEL 66 krb5_error_code profile_ser_size 67 (krb5_context, krb5_pointer, size_t *); 68 krb5_error_code profile_ser_externalize 69 (krb5_context, krb5_pointer, krb5_octet **, size_t *); 70 krb5_error_code profile_ser_internalize 71 (krb5_context,krb5_pointer *, krb5_octet **, size_t *); 72 #endif 73 /* Local data */ 74 static const krb5_ser_entry krb5_context_ser_entry = { 75 KV5M_CONTEXT, /* Type */ 76 krb5_context_size, /* Sizer routine */ 77 krb5_context_externalize, /* Externalize routine */ 78 krb5_context_internalize /* Internalize routine */ 79 }; 80 static const krb5_ser_entry krb5_oscontext_ser_entry = { 81 KV5M_OS_CONTEXT, /* Type */ 82 krb5_oscontext_size, /* Sizer routine */ 83 krb5_oscontext_externalize, /* Externalize routine */ 84 krb5_oscontext_internalize /* Internalize routine */ 85 }; 86 #ifndef _KERNEL 87 static const krb5_ser_entry krb5_profile_ser_entry = { 88 PROF_MAGIC_PROFILE, /* Type */ 89 profile_ser_size, /* Sizer routine */ 90 profile_ser_externalize, /* Externalize routine */ 91 profile_ser_internalize /* Internalize routine */ 92 }; 93 #endif 94 95 /* 96 * krb5_context_size() - Determine the size required to externalize the 97 * krb5_context. 98 */ 99 static krb5_error_code 100 krb5_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) 101 { 102 krb5_error_code kret; 103 size_t required; 104 krb5_context context; 105 106 /* 107 * The KRB5 context itself requires: 108 * krb5_int32 for KV5M_CONTEXT 109 * krb5_int32 for sizeof(default_realm) 110 * strlen(default_realm) for default_realm. 111 * krb5_int32 for n_in_tkt_ktypes*sizeof(krb5_int32) 112 * nktypes*sizeof(krb5_int32) for in_tkt_ktypes. 113 * krb5_int32 for n_tgs_ktypes*sizeof(krb5_int32) 114 * nktypes*sizeof(krb5_int32) for tgs_ktypes. 115 * krb5_int32 for clockskew 116 * krb5_int32 for kdc_req_sumtype 117 * krb5_int32 for ap_req_sumtype 118 * krb5_int32 for safe_sumtype 119 * krb5_int32 for kdc_default_options 120 * krb5_int32 for library_options 121 * krb5_int32 for profile_secure 122 * krb5_int32 for fcc_default_format 123 * krb5_int32 for scc_default_format 124 * <> for os_context 125 * <> for db_context 126 * <> for profile 127 * krb5_int32 for trailer. 128 */ 129 kret = EINVAL; 130 if ((context = (krb5_context) arg)) { 131 /* Calculate base length */ 132 required = (14 * sizeof(krb5_int32) + 133 (context->in_tkt_ktype_count * sizeof(krb5_int32)) + 134 (context->tgs_ktype_count * sizeof(krb5_int32))); 135 136 if (context->default_realm) 137 required += strlen(context->default_realm); 138 /* Calculate size required by os_context, if appropriate */ 139 if (context->os_context) 140 kret = krb5_size_opaque(kcontext, 141 KV5M_OS_CONTEXT, 142 (krb5_pointer) context->os_context, 143 &required); 144 145 /* Calculate size required by db_context, if appropriate */ 146 if (!kret && context->db_context) 147 kret = krb5_size_opaque(kcontext, 148 KV5M_DB_CONTEXT, 149 (krb5_pointer) context->db_context, 150 &required); 151 152 /* Finally, calculate size required by profile, if appropriate */ 153 if (!kret && context->profile) 154 kret = krb5_size_opaque(kcontext, 155 PROF_MAGIC_PROFILE, 156 (krb5_pointer) context->profile, 157 &required); 158 } 159 if (!kret) 160 *sizep += required; 161 return(kret); 162 } 163 164 /* 165 * krb5_context_externalize() - Externalize the krb5_context. 166 */ 167 static krb5_error_code 168 krb5_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) 169 { 170 krb5_error_code kret; 171 krb5_context context; 172 size_t required; 173 krb5_octet *bp; 174 size_t remain; 175 int i; 176 177 required = 0; 178 bp = *buffer; 179 remain = *lenremain; 180 context = (krb5_context) arg; 181 if (!context) 182 return (EINVAL); 183 KRB5_VERIFY_MAGIC(context, KV5M_CONTEXT); 184 185 if ((kret = krb5_context_size(kcontext, arg, &required))) 186 return (kret); 187 188 if (required > remain) 189 return (ENOMEM); 190 191 /* First write our magic number */ 192 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain); 193 if (kret) 194 return (kret); 195 196 /* Now sizeof default realm */ 197 kret = krb5_ser_pack_int32((context->default_realm) ? 198 (krb5_int32) strlen(context->default_realm) : 0, 199 &bp, &remain); 200 if (kret) 201 return (kret); 202 203 /* Now default_realm bytes */ 204 if (context->default_realm) { 205 kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm, 206 strlen(context->default_realm), 207 &bp, &remain); 208 if (kret) 209 return (kret); 210 } 211 212 /* Now number of initial ticket ktypes */ 213 kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktype_count, 214 &bp, &remain); 215 if (kret) 216 return (kret); 217 218 /* Now serialize ktypes */ 219 for (i=0; i<context->in_tkt_ktype_count; i++) { 220 kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktypes[i], 221 &bp, &remain); 222 if (kret) 223 return (kret); 224 } 225 226 /* Now number of default ktypes */ 227 kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktype_count, 228 &bp, &remain); 229 if (kret) 230 return (kret); 231 232 /* Now serialize ktypes */ 233 for (i=0; i<context->tgs_ktype_count; i++) { 234 kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktypes[i], 235 &bp, &remain); 236 if (kret) 237 return (kret); 238 } 239 240 /* Now allowable clockskew */ 241 kret = krb5_ser_pack_int32((krb5_int32) context->clockskew, 242 &bp, &remain); 243 if (kret) 244 return (kret); 245 246 /* Now kdc_req_sumtype */ 247 kret = krb5_ser_pack_int32((krb5_int32) context->kdc_req_sumtype, 248 &bp, &remain); 249 if (kret) 250 return (kret); 251 252 /* Now default ap_req_sumtype */ 253 kret = krb5_ser_pack_int32((krb5_int32) context->default_ap_req_sumtype, 254 &bp, &remain); 255 if (kret) 256 return (kret); 257 258 /* Now default safe_sumtype */ 259 kret = krb5_ser_pack_int32((krb5_int32) context->default_safe_sumtype, 260 &bp, &remain); 261 if (kret) 262 return (kret); 263 264 /* Now kdc_default_options */ 265 kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options, 266 &bp, &remain); 267 if (kret) 268 return (kret); 269 270 /* Now library_options */ 271 kret = krb5_ser_pack_int32((krb5_int32) context->library_options, 272 &bp, &remain); 273 if (kret) 274 return (kret); 275 276 /* Now profile_secure */ 277 kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure, 278 &bp, &remain); 279 if (kret) 280 return (kret); 281 282 /* Now fcc_default_format */ 283 kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format, 284 &bp, &remain); 285 if (kret) 286 return (kret); 287 288 /* Now scc_default_format */ 289 kret = krb5_ser_pack_int32((krb5_int32) context->scc_default_format, 290 &bp, &remain); 291 if (kret) 292 return (kret); 293 294 /* Now handle os_context, if appropriate */ 295 if (context->os_context) { 296 kret = krb5_externalize_opaque(kcontext, KV5M_OS_CONTEXT, 297 (krb5_pointer) context->os_context, 298 &bp, &remain); 299 if (kret) 300 return (kret); 301 } 302 303 /* Now handle database context, if appropriate */ 304 if (context->db_context) { 305 kret = krb5_externalize_opaque(kcontext, KV5M_DB_CONTEXT, 306 (krb5_pointer) context->db_context, 307 &bp, &remain); 308 if (kret) 309 return (kret); 310 } 311 312 /* Finally, handle profile, if appropriate */ 313 if (context->profile) { 314 kret = krb5_externalize_opaque(kcontext, PROF_MAGIC_PROFILE, 315 (krb5_pointer) context->profile, 316 &bp, &remain); 317 if (kret) 318 return (kret); 319 } 320 321 /* 322 * If we were successful, write trailer then update the pointer and 323 * remaining length; 324 */ 325 kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain); 326 if (kret) 327 return (kret); 328 329 *buffer = bp; 330 *lenremain = remain; 331 332 return (0); 333 } 334 335 /* 336 * krb5_context_internalize() - Internalize the krb5_context. 337 */ 338 static krb5_error_code 339 krb5_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) 340 { 341 krb5_error_code kret; 342 krb5_context context; 343 krb5_int32 ibuf; 344 krb5_octet *bp; 345 size_t remain; 346 int i; 347 348 bp = *buffer; 349 remain = *lenremain; 350 351 /* Read our magic number */ 352 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 353 return (EINVAL); 354 355 if (ibuf != KV5M_CONTEXT) 356 return (EINVAL); 357 358 /* Get memory for the context */ 359 context = (krb5_context) MALLOC(sizeof(struct _krb5_context)); 360 if (!context) 361 return (ENOMEM); 362 (void) memset(context, 0, sizeof(struct _krb5_context)); 363 364 /* Get the size of the default realm */ 365 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 366 goto cleanup; 367 368 if (ibuf) { 369 context->default_realm = (char *) MALLOC((size_t) ibuf+1); 370 if (!context->default_realm) { 371 kret = ENOMEM; 372 goto cleanup; 373 } 374 375 kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm, 376 (size_t) ibuf, &bp, &remain); 377 if (kret) 378 goto cleanup; 379 380 context->default_realm[ibuf] = '\0'; 381 } 382 383 /* Get the number of in_tkt_ktypes */ 384 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 385 goto cleanup; 386 387 context->in_tkt_ktype_count = (int) ibuf; 388 context->in_tkt_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) * 389 (context->in_tkt_ktype_count+1)); 390 if (!context->in_tkt_ktypes) { 391 kret = ENOMEM; 392 goto cleanup; 393 } 394 (void) memset(context->in_tkt_ktypes, 0, (sizeof(krb5_enctype) * 395 (context->in_tkt_ktype_count + 1))); 396 397 for (i=0; i<context->in_tkt_ktype_count; i++) { 398 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 399 goto cleanup; 400 context->in_tkt_ktypes[i] = (krb5_enctype) ibuf; 401 } 402 403 /* Get the number of tgs_ktypes */ 404 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 405 goto cleanup; 406 407 context->tgs_ktype_count = (int) ibuf; 408 context->tgs_ktypes = (krb5_enctype *) MALLOC(sizeof(krb5_enctype) * 409 (context->tgs_ktype_count+1)); 410 if (!context->tgs_ktypes) { 411 kret = ENOMEM; 412 goto cleanup; 413 } 414 (void) memset(context->tgs_ktypes, 0, (sizeof(krb5_enctype) * 415 (context->tgs_ktype_count + 1))); 416 for (i=0; i<context->tgs_ktype_count; i++) { 417 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 418 goto cleanup; 419 context->tgs_ktypes[i] = (krb5_enctype) ibuf; 420 } 421 422 /* Allowable checksum */ 423 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 424 goto cleanup; 425 context->clockskew = (krb5_deltat) ibuf; 426 427 /* kdc_req_sumtype */ 428 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 429 goto cleanup; 430 context->kdc_req_sumtype = (krb5_cksumtype) ibuf; 431 432 /* default ap_req_sumtype */ 433 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 434 goto cleanup; 435 context->default_ap_req_sumtype = (krb5_cksumtype) ibuf; 436 437 /* default_safe_sumtype */ 438 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 439 goto cleanup; 440 context->default_safe_sumtype = (krb5_cksumtype) ibuf; 441 442 /* kdc_default_options */ 443 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 444 goto cleanup; 445 context->kdc_default_options = (krb5_flags) ibuf; 446 447 /* library_options */ 448 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 449 goto cleanup; 450 context->library_options = (krb5_flags) ibuf; 451 452 /* profile_secure */ 453 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 454 goto cleanup; 455 context->profile_secure = (krb5_boolean) ibuf; 456 457 /* fcc_default_format */ 458 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 459 goto cleanup; 460 context->fcc_default_format = (int) ibuf; 461 462 /* scc_default_format */ 463 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 464 goto cleanup; 465 context->scc_default_format = (int) ibuf; 466 467 /* Attempt to read in the os_context. It's an array now, but 468 we still treat it in most places as a separate object with 469 a pointer. */ 470 { 471 krb5_os_context osp = 0; 472 kret = krb5_internalize_opaque(kcontext, KV5M_OS_CONTEXT, 473 (krb5_pointer *) &osp, 474 &bp, &remain); 475 if (kret && (kret != EINVAL) && (kret != ENOENT)) 476 goto cleanup; 477 /* Put the newly allocated data into the krb5_context 478 structure where we're really keeping it these days. */ 479 if (osp) 480 *context->os_context = *osp; 481 free(osp); 482 } 483 484 /* Attempt to read in the db_context */ 485 kret = krb5_internalize_opaque(kcontext, KV5M_DB_CONTEXT, 486 (krb5_pointer *) &context->db_context, 487 &bp, &remain); 488 if (kret && (kret != EINVAL) && (kret != ENOENT)) 489 goto cleanup; 490 491 #ifndef _KERNEL 492 /* Attempt to read in the profile */ 493 kret = krb5_internalize_opaque(kcontext, PROF_MAGIC_PROFILE, 494 (krb5_pointer *) &context->profile, 495 &bp, &remain); 496 #endif 497 if (kret && (kret != EINVAL) && (kret != ENOENT)) 498 goto cleanup; 499 500 /* Finally, find the trailer */ 501 if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) 502 goto cleanup; 503 504 if (ibuf != KV5M_CONTEXT) { 505 kret = EINVAL; 506 goto cleanup; 507 } 508 509 context->magic = KV5M_CONTEXT; 510 *buffer = bp; 511 *lenremain = remain; 512 *argp = (krb5_pointer) context; 513 514 return 0; 515 516 cleanup: 517 if (context) 518 krb5_free_context(context); 519 return(kret); 520 } 521 522 /* 523 * krb5_oscontext_size() - Determine the size required to externalize 524 * the krb5_os_context. 525 */ 526 /*ARGSUSED*/ 527 static krb5_error_code 528 krb5_oscontext_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) 529 { 530 /* 531 * We need five 32-bit integers: 532 * two for header and trailer 533 * one each for time_offset, usec_offset and os_flags 534 */ 535 *sizep += (5*sizeof(krb5_int32)); 536 return(0); 537 } 538 539 /* 540 * krb5_oscontext_externalize() - Externalize the krb5_os_context. 541 */ 542 static krb5_error_code 543 krb5_oscontext_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) 544 { 545 krb5_error_code kret; 546 krb5_os_context os_ctx; 547 size_t required; 548 krb5_octet *bp; 549 size_t remain; 550 551 required = 0; 552 bp = *buffer; 553 remain = *lenremain; 554 kret = EINVAL; 555 if ((os_ctx = (krb5_os_context) arg)) { 556 kret = ENOMEM; 557 if (!krb5_oscontext_size(kcontext, arg, &required) && 558 (required <= remain)) { 559 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain); 560 (void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain); 561 (void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain); 562 (void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain); 563 (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain); 564 565 /* Handle any other OS context here */ 566 kret = 0; 567 if (!kret) { 568 *buffer = bp; 569 *lenremain = remain; 570 } 571 } 572 } 573 return(kret); 574 } 575 576 /* 577 * krb5_oscontext_internalize() - Internalize the krb5_os_context. 578 */ 579 /*ARGSUSED*/ 580 static krb5_error_code 581 krb5_oscontext_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) 582 { 583 krb5_error_code kret; 584 krb5_os_context os_ctx; 585 krb5_int32 ibuf; 586 krb5_octet *bp; 587 size_t remain; 588 589 bp = *buffer; 590 remain = *lenremain; 591 kret = EINVAL; 592 os_ctx = (krb5_os_context) NULL; 593 /* Read our magic number */ 594 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 595 ibuf = 0; 596 if (ibuf == KV5M_OS_CONTEXT) { 597 kret = ENOMEM; 598 599 /* Get memory for the context */ 600 if ((os_ctx = (krb5_os_context) 601 MALLOC(sizeof(struct _krb5_os_context))) && 602 (remain >= 4*sizeof(krb5_int32))) { 603 (void) memset(os_ctx, 0, sizeof(struct _krb5_os_context)); 604 os_ctx->magic = KV5M_OS_CONTEXT; 605 606 /* Read out our context */ 607 (void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain); 608 (void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain); 609 (void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain); 610 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 611 612 if (ibuf == KV5M_OS_CONTEXT) { 613 os_ctx->magic = KV5M_OS_CONTEXT; 614 kret = 0; 615 *buffer = bp; 616 *lenremain = remain; 617 } else 618 kret = EINVAL; 619 } 620 } 621 if (!kret) { 622 *argp = (krb5_pointer) os_ctx; 623 } 624 else { 625 if (os_ctx) 626 FREE(os_ctx, sizeof(struct _krb5_os_context)); 627 } 628 return(kret); 629 } 630 631 /* 632 * Register the context serializers. 633 */ 634 krb5_error_code KRB5_CALLCONV 635 krb5_ser_context_init(krb5_context kcontext) 636 { 637 krb5_error_code kret; 638 kret = krb5_register_serializer(kcontext, &krb5_context_ser_entry); 639 if (!kret) 640 kret = krb5_register_serializer(kcontext, &krb5_oscontext_ser_entry); 641 642 /* Profile nformation need not be serialzied when we are importing the 643 * context into kernel. Besides the function pointers to file access 644 * routines can't be used in the kernel. 645 646 * Any info needed from the profile is already a part of the 647 * exported context obviating the need for importer to know about 648 * profile config files. 649 650 */ 651 652 #ifndef _KERNEL 653 if (!kret) 654 kret = krb5_register_serializer(kcontext, &krb5_profile_ser_entry); 655 #endif 656 return(kret); 657 } 658