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