Home | History | Annotate | Download | only in mech
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * lib/gssapi/krb5/ser_sctx.c
      9  *
     10  * Copyright 1995, 2004 by the Massachusetts Institute of Technology.
     11  * All Rights Reserved.
     12  *
     13  * Export of this software from the United States of America may
     14  *   require a specific license from the United States Government.
     15  *   It is the responsibility of any person or organization contemplating
     16  *   export to obtain such a license before exporting.
     17  *
     18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     19  * distribute this software and its documentation for any purpose and
     20  * without fee is hereby granted, provided that the above copyright
     21  * notice appear in all copies and that both that copyright notice and
     22  * this permission notice appear in supporting documentation, and that
     23  * the name of M.I.T. not be used in advertising or publicity pertaining
     24  * to distribution of the software without specific, written prior
     25  * permission.  Furthermore if you modify this software you must label
     26  * your software as modified software and not distribute it in such a
     27  * fashion that it might be confused with the original M.I.T. software.
     28  * M.I.T. makes no representations about the suitability of
     29  * this software for any purpose.  It is provided "as is" without express
     30  * or implied warranty.
     31  *
     32  */
     33 
     34 /*
     35  * ser_sctx.c - Handle [de]serialization of GSSAPI security context.
     36  */
     37  /* Solaris Kerberos:  order is important here.  include gssapiP_krb5.h
     38   * before all others, otherwise we get a LINT error from MALLOC macro
     39   * being redefined in mechglueP.h */
     40 #include "gssapiP_krb5.h"
     41 #include "k5-int.h"
     42 
     43 /*
     44  * This module contains routines to [de]serialize
     45  *	krb5_gss_enc_desc and krb5_gss_ctx_id_t.
     46  * XXX This whole serialization abstraction is unnecessary in a
     47  * non-messaging environment, which krb5 is.  Someday, this should
     48  * all get redone without the extra level of indirection. I've done
     49  * some of this work here, since adding new serializers is an internal
     50  * krb5 interface, and I won't use those.  There is some more
     51  * deobfuscation (no longer anonymizing pointers, mostly) which could
     52  * still be done. --marc
     53  */
     54 
     55 /*ARGSUSED*/
     56 static krb5_error_code
     57 kg_oid_externalize(kcontext, arg, buffer, lenremain)
     58     krb5_context	kcontext;
     59     krb5_pointer	arg;
     60     krb5_octet		**buffer;
     61     size_t		*lenremain;
     62 {
     63      gss_OID oid = (gss_OID) arg;
     64      krb5_error_code err;
     65 
     66      err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
     67      if (err)
     68 	 return err;
     69      err = krb5_ser_pack_int32((krb5_int32) oid->length,
     70 			       buffer, lenremain);
     71      if (err)
     72 	 return err;
     73      err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
     74 			       oid->length, buffer, lenremain);
     75      if (err)
     76 	 return err;
     77      err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
     78      return err;
     79 }
     80 
     81 /*ARGSUSED*/
     82 static krb5_error_code
     83 kg_oid_internalize(kcontext, argp, buffer, lenremain)
     84     krb5_context	kcontext;
     85     krb5_pointer	*argp;
     86     krb5_octet		**buffer;
     87     size_t		*lenremain;
     88 {
     89      gss_OID oid;
     90      krb5_int32 ibuf;
     91      krb5_octet		*bp;
     92      size_t		remain;
     93 
     94      bp = *buffer;
     95      remain = *lenremain;
     96 
     97      /* Read in and check our magic number */
     98      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
     99 	return (EINVAL);
    100 
    101      if (ibuf != KV5M_GSS_OID)
    102 	 return (EINVAL);
    103 
    104      oid = (gss_OID) MALLOC(sizeof(gss_OID_desc));
    105      if (oid == NULL)
    106 	  return ENOMEM;
    107      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
    108          FREE(oid, sizeof(gss_OID_desc));
    109 	 return EINVAL;
    110      }
    111      oid->length = ibuf;
    112      oid->elements = MALLOC(ibuf);
    113      if (oid->elements == 0) {
    114              FREE(oid, sizeof(gss_OID_desc));
    115 	     return ENOMEM;
    116      }
    117      if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
    118 			       oid->length, &bp, &remain)) {
    119          FREE(oid->elements, oid->length);
    120          FREE(oid, sizeof(gss_OID_desc));
    121 	 return EINVAL;
    122      }
    123 
    124      /* Read in and check our trailing magic number */
    125      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
    126          FREE(oid->elements, oid->length);
    127          FREE(oid, sizeof(gss_OID_desc));
    128 	 return (EINVAL);
    129      }
    130 
    131      if (ibuf != KV5M_GSS_OID) {
    132          FREE(oid->elements, oid->length);
    133          FREE(oid, sizeof(gss_OID_desc));
    134 	 return (EINVAL);
    135      }
    136 
    137      *buffer = bp;
    138      *lenremain = remain;
    139      *argp = (krb5_pointer) oid;
    140      return 0;
    141 }
    142 
    143 /*ARGSUSED*/
    144 static krb5_error_code
    145 kg_oid_size(kcontext, arg, sizep)
    146     krb5_context	kcontext;
    147     krb5_pointer	arg;
    148     size_t		*sizep;
    149 {
    150    krb5_error_code kret;
    151    gss_OID oid;
    152    size_t required;
    153 
    154    kret = EINVAL;
    155    /*LINTED*/
    156    if ((oid = (gss_OID) arg)) {
    157       required = 2*sizeof(krb5_int32); /* For the header and trailer */
    158       required += sizeof(krb5_int32);
    159       required += oid->length;
    160 
    161       kret = 0;
    162 
    163       *sizep += required;
    164    }
    165 
    166    return(kret);
    167 }
    168 
    169 /*ARGSUSED*/
    170 static krb5_error_code
    171 kg_queue_externalize(kcontext, arg, buffer, lenremain)
    172     krb5_context	kcontext;
    173     krb5_pointer	arg;
    174     krb5_octet		**buffer;
    175     size_t		*lenremain;
    176 {
    177     krb5_error_code err;
    178     err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
    179     if (err == 0)
    180 	err = g_queue_externalize(arg, buffer, lenremain);
    181     if (err == 0)
    182 	err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
    183     return err;
    184 }
    185 
    186 /*ARGSUSED*/
    187 static krb5_error_code
    188 kg_queue_internalize(kcontext, argp, buffer, lenremain)
    189     krb5_context	kcontext;
    190     krb5_pointer	*argp;
    191     krb5_octet		**buffer;
    192     size_t		*lenremain;
    193 {
    194      krb5_int32 ibuf;
    195      krb5_octet		*bp;
    196      size_t		remain;
    197      krb5_error_code	err;
    198 
    199      bp = *buffer;
    200      remain = *lenremain;
    201 
    202      /* Read in and check our magic number */
    203      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
    204 	return (EINVAL);
    205 
    206      if (ibuf != KV5M_GSS_QUEUE)
    207 	 return (EINVAL);
    208 
    209      err = g_queue_internalize(argp, &bp, &remain);
    210      if (err)
    211 	  return err;
    212 
    213      /* Read in and check our trailing magic number */
    214      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
    215 	 g_order_free(argp);
    216 	 return (EINVAL);
    217      }
    218 
    219      if (ibuf != KV5M_GSS_QUEUE) {
    220 	 g_order_free(argp);
    221 	 return (EINVAL);
    222      }
    223 
    224      *buffer = bp;
    225      *lenremain = remain;
    226      return 0;
    227 }
    228 
    229 /*ARGSUSED*/
    230 static krb5_error_code
    231 kg_queue_size(kcontext, arg, sizep)
    232     krb5_context	kcontext;
    233     krb5_pointer	arg;
    234     size_t		*sizep;
    235 {
    236    krb5_error_code kret;
    237    size_t required;
    238 
    239    kret = EINVAL;
    240    if (arg) {
    241       required = 2*sizeof(krb5_int32); /* For the header and trailer */
    242       (void) g_queue_size(arg, &required);
    243 
    244       kret = 0;
    245       *sizep += required;
    246    }
    247    return(kret);
    248 }
    249 
    250 /*
    251  * Determine the size required for this krb5_gss_ctx_id_rec.
    252  */
    253 krb5_error_code
    254 kg_ctx_size(kcontext, arg, sizep)
    255     krb5_context	kcontext;
    256     krb5_pointer	arg;
    257     size_t		*sizep;
    258 {
    259     krb5_error_code	kret;
    260     krb5_gss_ctx_id_rec	*ctx;
    261     size_t		required;
    262 
    263     /*
    264      * krb5_gss_ctx_id_rec requires:
    265      *	krb5_int32	for KG_CONTEXT
    266      *	krb5_int32	for initiate.
    267      *	krb5_int32	for established.
    268      *	krb5_int32	for big_endian.
    269      *	krb5_int32	for have_acceptor_subkey.
    270      *	krb5_int32	for seed_init.
    271      *	krb5_int32	for gss_flags.
    272      *	sizeof(seed)	for seed
    273      *	...		for here
    274      *	...		for there
    275      *	...		for subkey
    276      *  krb5_int32	for signalg.
    277      *  krb5_int32	for cksum_size.
    278      *  krb5_int32	for sealalg.
    279      *	...		for enc
    280      *	...		for seq
    281      *	krb5_int32	for endtime.
    282      *	krb5_int32	for flags.
    283      *	krb5_int64	for seq_send.
    284      *	krb5_int64	for seq_recv.
    285      *	...		for seqstate
    286      *	...		for auth_context
    287      *	...		for mech_used
    288      *	krb5_int32	for proto
    289      *	krb5_int32	for cksumtype
    290      *	...		for acceptor_subkey
    291      *	krb5_int32	for acceptor_key_cksumtype
    292      *	krb5_int32	for cred_rcache
    293      *	krb5_int32	for trailer.
    294      */
    295     kret = EINVAL;
    296     /*LINTED*/
    297     if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
    298 	required = 17*sizeof(krb5_int32);
    299 	required += 2*sizeof(krb5_int64);
    300 	required += sizeof(ctx->seed);
    301 
    302 	kret = 0;
    303 	if (!kret && ctx->here)
    304 	    kret = krb5_size_opaque(kcontext,
    305 				    KV5M_PRINCIPAL,
    306 				    (krb5_pointer) ctx->here,
    307 				    &required);
    308 
    309 	if (!kret && ctx->there)
    310 	    kret = krb5_size_opaque(kcontext,
    311 				    KV5M_PRINCIPAL,
    312 				    (krb5_pointer) ctx->there,
    313 				    &required);
    314 
    315 	if (!kret && ctx->subkey)
    316 	    kret = krb5_size_opaque(kcontext,
    317 				    KV5M_KEYBLOCK,
    318 				    (krb5_pointer) ctx->subkey,
    319 				    &required);
    320 
    321 	if (!kret && ctx->enc)
    322 	    kret = krb5_size_opaque(kcontext,
    323 				    KV5M_KEYBLOCK,
    324 				    (krb5_pointer) ctx->enc,
    325 				    &required);
    326 
    327 	if (!kret && ctx->seq)
    328 	    kret = krb5_size_opaque(kcontext,
    329 				    KV5M_KEYBLOCK,
    330 				    (krb5_pointer) ctx->seq,
    331 				    &required);
    332 
    333 	if (!kret)
    334 	    kret = kg_oid_size(kcontext,
    335 			       (krb5_pointer) ctx->mech_used,
    336 			       &required);
    337 
    338 	if (!kret && ctx->seqstate)
    339 	    kret = kg_queue_size(kcontext, ctx->seqstate, &required);
    340 
    341 #ifndef PROVIDE_KERNEL_IMPORT
    342 	if (!kret)
    343 	    kret = krb5_size_opaque(kcontext,
    344 				    KV5M_CONTEXT,
    345 				    (krb5_pointer) ctx->k5_context,
    346 				    &required);
    347 	if (!kret)
    348 	    kret = krb5_size_opaque(kcontext,
    349 				    KV5M_AUTH_CONTEXT,
    350 				    (krb5_pointer) ctx->auth_context,
    351 				    &required);
    352 #endif
    353 
    354 	if (!kret && ctx->acceptor_subkey)
    355 	    kret = krb5_size_opaque(kcontext,
    356 				    KV5M_KEYBLOCK,
    357 				    (krb5_pointer) ctx->acceptor_subkey,
    358 				    &required);
    359 	if (!kret)
    360 	    *sizep += required;
    361     }
    362     return(kret);
    363 }
    364 
    365 /*
    366  * Externalize this krb5_gss_ctx_id_ret.
    367  */
    368 krb5_error_code
    369 kg_ctx_externalize(kcontext, arg, buffer, lenremain)
    370     krb5_context	kcontext;
    371     krb5_pointer	arg;
    372     krb5_octet		**buffer;
    373     size_t		*lenremain;
    374 {
    375     krb5_error_code	kret;
    376     krb5_gss_ctx_id_rec	*ctx;
    377     size_t		required;
    378     krb5_octet		*bp;
    379     size_t		remain;
    380 #ifndef _KERNEL
    381     krb5int_access kaccess;
    382 
    383     kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
    384     if (kret)
    385         return(kret);
    386 #endif
    387 
    388     required = 0;
    389     bp = *buffer;
    390     remain = *lenremain;
    391     kret = EINVAL;
    392     /*LINTED*/
    393     if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
    394 	kret = ENOMEM;
    395 	if (!kg_ctx_size(kcontext, arg, &required) &&
    396 	    (required <= remain)) {
    397 	    /* Our identifier */
    398 	    (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
    399 
    400 	    /* Now static data */
    401 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
    402 				       &bp, &remain);
    403 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
    404 				       &bp, &remain);
    405 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian,
    406 				       &bp, &remain);
    407 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
    408 				       &bp, &remain);
    409 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
    410 				       &bp, &remain);
    411 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
    412 				       &bp, &remain);
    413 	    (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
    414 				       sizeof(ctx->seed),
    415 				       &bp, &remain);
    416 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
    417 				       &bp, &remain);
    418 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
    419 				       &bp, &remain);
    420 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
    421 				       &bp, &remain);
    422 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->endtime,
    423 				       &bp, &remain);
    424 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
    425 				       &bp, &remain);
    426 #ifndef _KERNEL
    427 	    (void) (*kaccess.krb5_ser_pack_int64)((krb5_int64) ctx->seq_send,
    428 				       &bp, &remain);
    429 	    (void) (*kaccess.krb5_ser_pack_int64)((krb5_int64) ctx->seq_recv,
    430 				       &bp, &remain);
    431 #else
    432 	    (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_send,
    433 				       &bp, &remain);
    434 	    (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_recv,
    435 				       &bp, &remain);
    436 #endif
    437 
    438 	    /* Now dynamic data */
    439 	    kret = 0;
    440 
    441 	    if (!kret && ctx->mech_used)
    442 		 kret = kg_oid_externalize(kcontext, ctx->mech_used,
    443 					   &bp, &remain);
    444 
    445 	    if (!kret && ctx->here)
    446 		kret = krb5_externalize_opaque(kcontext,
    447 					       KV5M_PRINCIPAL,
    448 					       (krb5_pointer) ctx->here,
    449 					       &bp, &remain);
    450 
    451 	    if (!kret && ctx->there)
    452 		kret = krb5_externalize_opaque(kcontext,
    453 					       KV5M_PRINCIPAL,
    454 					       (krb5_pointer) ctx->there,
    455 					       &bp, &remain);
    456 
    457 	    if (!kret && ctx->subkey)
    458 		kret = krb5_externalize_opaque(kcontext,
    459 					       KV5M_KEYBLOCK,
    460 					       (krb5_pointer) ctx->subkey,
    461 					       &bp, &remain);
    462 
    463 	    if (!kret && ctx->enc)
    464 		kret = krb5_externalize_opaque(kcontext,
    465 					       KV5M_KEYBLOCK,
    466 					       (krb5_pointer) ctx->enc,
    467 					       &bp, &remain);
    468 
    469 	    if (!kret && ctx->seq)
    470 		kret = krb5_externalize_opaque(kcontext,
    471 					       KV5M_KEYBLOCK,
    472 					       (krb5_pointer) ctx->seq,
    473 					       &bp, &remain);
    474 
    475 	    if (!kret && ctx->seqstate)
    476 		kret = kg_queue_externalize(kcontext,
    477 					    ctx->seqstate, &bp, &remain);
    478 
    479 #ifndef PROVIDE_KERNEL_IMPORT
    480 	    if (!kret)
    481 		kret = krb5_externalize_opaque(kcontext,
    482 					       KV5M_CONTEXT,
    483 					       (krb5_pointer) ctx->k5_context,
    484 					       &bp, &remain);
    485 	    if (!kret)
    486 		kret = krb5_externalize_opaque(kcontext,
    487 					       KV5M_AUTH_CONTEXT,
    488 					       (krb5_pointer) ctx->auth_context,
    489 					       &bp, &remain);
    490 #endif
    491 	    if (!kret)
    492 		kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
    493 					   &bp, &remain);
    494 	    if (!kret)
    495 		kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
    496 					   &bp, &remain);
    497 	    if (!kret && ctx->acceptor_subkey)
    498 		kret = krb5_externalize_opaque(kcontext,
    499 					       KV5M_KEYBLOCK,
    500 					       (krb5_pointer) ctx->acceptor_subkey,
    501 					       &bp, &remain);
    502 	    if (!kret)
    503 		kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
    504 					   &bp, &remain);
    505 
    506 	    if (!kret)
    507 		kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
    508 					   &bp, &remain);
    509 	    /* trailer */
    510 	    if (!kret)
    511 		kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
    512 	    if (!kret) {
    513 		*buffer = bp;
    514 		*lenremain = remain;
    515 	    }
    516 	}
    517     }
    518     return(kret);
    519 }
    520 
    521 /*
    522  * Internalize this krb5_gss_ctx_id_t.
    523  */
    524 krb5_error_code
    525 kg_ctx_internalize(kcontext, argp, buffer, lenremain)
    526     krb5_context	kcontext;
    527     krb5_pointer	*argp;
    528     krb5_octet		**buffer;
    529     size_t		*lenremain;
    530 {
    531     krb5_error_code	kret;
    532     krb5_gss_ctx_id_rec	*ctx;
    533     krb5_int32		ibuf;
    534     krb5_octet		*bp;
    535     size_t		remain;
    536 #ifndef _KERNEL
    537     krb5int_access kaccess;
    538 
    539     kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
    540     if (kret)
    541         return(kret);
    542 #endif
    543 
    544     bp = *buffer;
    545     remain = *lenremain;
    546     kret = EINVAL;
    547     /* Read our magic number */
    548     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
    549 	ibuf = 0;
    550     if (ibuf == KG_CONTEXT) {
    551 	kret = ENOMEM;
    552 
    553 	/* Get a context */
    554 	if ((remain >= (17*sizeof(krb5_int32)
    555 			+ 2*sizeof(krb5_int64)
    556 			+ sizeof(ctx->seed))) &&
    557 	    (ctx = (krb5_gss_ctx_id_rec *)
    558 	     xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
    559 	    (void) memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
    560 
    561 	    ctx->k5_context = kcontext;
    562 
    563 	    /* Get static data */
    564 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    565 	    ctx->initiate = (int) ibuf;
    566 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    567 	    ctx->established = (int) ibuf;
    568 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    569 	    ctx->big_endian = (int) ibuf;
    570 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    571 	    ctx->have_acceptor_subkey = (int) ibuf;
    572 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    573 	    ctx->seed_init = (int) ibuf;
    574 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    575 	    ctx->gss_flags = (int) ibuf;
    576 	    (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
    577 					 sizeof(ctx->seed),
    578 					 &bp, &remain);
    579 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    580 	    ctx->signalg = (int) ibuf;
    581 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    582 	    ctx->cksum_size = (int) ibuf;
    583 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    584 	    ctx->sealalg = (int) ibuf;
    585 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    586 	    ctx->endtime = (krb5_timestamp) ibuf;
    587 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    588 	    ctx->krb_flags = (krb5_flags) ibuf;
    589 #ifndef _KERNEL
    590 	    (void) (*kaccess.krb5_ser_unpack_int64)((krb5_int64 *)&ctx->seq_send, &bp, &remain);
    591 	    kret = (*kaccess.krb5_ser_unpack_int64)((krb5_int64 *)&ctx->seq_recv, &bp, &remain);
    592 #else
    593 	    (void) krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_send),
    594 					&bp, &remain);
    595 	    kret = krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_recv),
    596 					&bp, &remain);
    597 #endif
    598 	    if (kret) {
    599 		xfree_wrap(ctx, sizeof (krb5_gss_ctx_id_rec));
    600 		return kret;
    601 	    }
    602 
    603 	    if ((kret = kg_oid_internalize(kcontext,
    604 					(krb5_pointer *) &ctx->mech_used, &bp,
    605 					   &remain))) {
    606 		 if (kret == EINVAL)
    607 		      kret = 0;
    608 	    }
    609 	    /* Now get substructure data */
    610 	    if ((kret = krb5_internalize_opaque(kcontext,
    611 						KV5M_PRINCIPAL,
    612 						(krb5_pointer *) &ctx->here,
    613 						&bp, &remain))) {
    614 		if (kret == EINVAL)
    615 		    kret = 0;
    616 	    }
    617 	    if (!kret &&
    618 		(kret = krb5_internalize_opaque(kcontext,
    619 						KV5M_PRINCIPAL,
    620 						(krb5_pointer *) &ctx->there,
    621 						&bp, &remain))) {
    622 		if (kret == EINVAL)
    623 		    kret = 0;
    624 	    }
    625 	    if (!kret &&
    626 		(kret = krb5_internalize_opaque(kcontext,
    627 						KV5M_KEYBLOCK,
    628 						(krb5_pointer *) &ctx->subkey,
    629 						&bp, &remain))) {
    630 		if (kret == EINVAL)
    631 		    kret = 0;
    632 	    }
    633 	    if (!kret &&
    634 		(kret = krb5_internalize_opaque(kcontext,
    635 						KV5M_KEYBLOCK,
    636 						(krb5_pointer *) &ctx->enc,
    637 						&bp, &remain))) {
    638 		if (kret == EINVAL)
    639 		    kret = 0;
    640 	    }
    641 	    if (!kret &&
    642 		(kret = krb5_internalize_opaque(kcontext,
    643 						KV5M_KEYBLOCK,
    644 						(krb5_pointer *) &ctx->seq,
    645 						&bp, &remain))) {
    646 		if (kret == EINVAL)
    647 		    kret = 0;
    648 	    }
    649 
    650 	    if (!kret) {
    651 		kret = kg_queue_internalize(kcontext, &ctx->seqstate,
    652 					    &bp, &remain);
    653 		if (kret == EINVAL)
    654 		    kret = 0;
    655 	    }
    656 
    657 #ifndef PROVIDE_KERNEL_IMPORT
    658 	    if (!kret)
    659 		kret = krb5_internalize_opaque(kcontext,
    660 					       KV5M_CONTEXT,
    661 					       (krb5_pointer *) &ctx->k5_context,
    662 					       &bp, &remain);
    663 
    664 	    if (!kret)
    665 		kret = krb5_internalize_opaque(kcontext,
    666 					       KV5M_AUTH_CONTEXT,
    667 				       (krb5_pointer *) &ctx->auth_context,
    668 					       &bp, &remain);
    669 #endif
    670 	    if (!kret)
    671 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    672 	    ctx->proto = ibuf;
    673 	    if (!kret)
    674 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    675 	    ctx->cksumtype = ibuf;
    676 	    if (!kret &&
    677 		(kret = krb5_internalize_opaque(kcontext,
    678 						KV5M_KEYBLOCK,
    679 						(krb5_pointer *) &ctx->acceptor_subkey,
    680 						&bp, &remain))) {
    681 		if (kret == EINVAL)
    682 		    kret = 0;
    683 	    }
    684 	    if (!kret)
    685 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    686 	    ctx->cred_rcache = ibuf;
    687 	    if (!kret)
    688 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    689 	    ctx->acceptor_subkey_cksumtype = ibuf;
    690 
    691 	    /* Get trailer */
    692 	    if (!kret)
    693 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    694 	    if (!kret && ibuf != KG_CONTEXT)
    695 		kret = EINVAL;
    696 
    697 	    if (!kret) {
    698 		*buffer = bp;
    699 		*lenremain = remain;
    700 		*argp = (krb5_pointer) ctx;
    701 	    } else {
    702 		if (ctx->seq)
    703 		    krb5_free_keyblock(kcontext, ctx->seq);
    704 		if (ctx->enc)
    705 		    krb5_free_keyblock(kcontext, ctx->enc);
    706 		if (ctx->subkey)
    707 		    krb5_free_keyblock(kcontext, ctx->subkey);
    708 		if (ctx->there)
    709 		    krb5_free_principal(kcontext, ctx->there);
    710 		if (ctx->here)
    711 		    krb5_free_principal(kcontext, ctx->here);
    712 		xfree_wrap(ctx, sizeof (krb5_gss_ctx_id_rec));
    713 	    }
    714 	}
    715     }
    716     return(kret);
    717 }
    718