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