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
kg_oid_externalize(kcontext,arg,buffer,lenremain)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
kg_oid_internalize(kcontext,argp,buffer,lenremain)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
kg_oid_size(kcontext,arg,sizep)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
kg_queue_externalize(kcontext,arg,buffer,lenremain)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
kg_queue_internalize(kcontext,argp,buffer,lenremain)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
kg_queue_size(kcontext,arg,sizep)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
kg_ctx_size(kcontext,arg,sizep)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
kg_ctx_externalize(kcontext,arg,buffer,lenremain)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
kg_ctx_internalize(kcontext,argp,buffer,lenremain)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