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