1 /*
2  * Copyright 2004 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 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 
39 /* Solaris Kerberos:  order is important here.  include gssapiP_krb5.h
40  * before all others, otherwise we get a LINT error from MALLOC macro
41  * being redefined in mechglueP.h */
42 #include <gssapiP_krb5.h>
43 #include <k5-int.h>
44 
45 /*
46  * This module contains routines to [de]serialize
47  *	krb5_gss_enc_desc and krb5_gss_ctx_id_t.
48  * XXX This whole serialization abstraction is unnecessary in a
49  * non-messaging environment, which krb5 is.  Someday, this should
50  * all get redone without the extra level of indirection. I've done
51  * some of this work here, since adding new serializers is an internal
52  * krb5 interface, and I won't use those.  There is some more
53  * deobfuscation (no longer anonymizing pointers, mostly) which could
54  * still be done. --marc
55  */
56 
57 /*ARGSUSED*/
58 static krb5_error_code
59 kg_oid_externalize(kcontext, arg, buffer, lenremain)
60     krb5_context	kcontext;
61     krb5_pointer	arg;
62     krb5_octet		**buffer;
63     size_t		*lenremain;
64 {
65      gss_OID oid = (gss_OID) arg;
66      krb5_error_code err;
67 
68      err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
69      if (err)
70         return err;
71      err = krb5_ser_pack_int32((krb5_int32) oid->length,
72                                buffer, lenremain);
73      if (err)
74         return err;
75      err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
76                                oid->length, buffer, lenremain);
77      if (err)
78         return err;
79      err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
80      return err;
81 }
82 
83 /*ARGSUSED*/
84 static krb5_error_code
85 kg_oid_internalize(kcontext, argp, buffer, lenremain)
86     krb5_context	kcontext;
87     krb5_pointer	*argp;
88     krb5_octet		**buffer;
89     size_t		*lenremain;
90 {
91      /* Solaris Kerberos:  note that by copying the argp pointer directly here,
92       * we avoid doing all the MALLOC and FREE calls later.
93       * Don't forget that when argp is ctx->mech_used, then this memory was
94       * already allocated.
95       */
96      gss_OID oid = (gss_OID)argp;
97      krb5_int32 ibuf;
98      krb5_octet		*bp;
99      size_t		remain;
100 
101      bp = *buffer;
102      remain = *lenremain;
103 
104      /* Read in and check our magic number */
105      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
106 	return (EINVAL);
107 
108      if (ibuf != KV5M_GSS_OID)
109 	 return (EINVAL);
110 /*   oid = (gss_OID) MALLOC(sizeof(gss_OID_desc));
111      if (oid == NULL)
112 	  return ENOMEM;
113 */
114 
115      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
116          return EINVAL;
117      }
118      oid->length = ibuf;
119      oid->elements = MALLOC(ibuf);
120      if (oid->elements == NULL) {
121              oid->length = 0;
122 	     return (ENOMEM);
123      }
124 
125      if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
126                                oid->length, &bp, &remain)) {
127          FREE(oid->elements, oid->length);
128          oid->length = 0;
129          return (EINVAL);
130      }
131 
132      /* Read in and check our trailing magic number */
133      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
134 	FREE (oid->elements, oid->length);
135 	oid->length = 0;
136 	return (EINVAL);
137      }
138 
139      if (ibuf != KV5M_GSS_OID) {
140 	FREE (oid->elements, oid->length);
141 	oid->length = 0;
142 	return (EINVAL);
143      }
144 
145      *buffer = bp;
146      *lenremain = remain;
147      /* *argp = (krb5_pointer) oid; */
148      return 0;
149 }
150 /*ARGSUSED*/
151 krb5_error_code
152 kg_oid_size(kcontext, arg, sizep)
153     krb5_context	kcontext;
154     krb5_pointer	arg;
155     size_t		*sizep;
156 {
157    krb5_error_code kret;
158    gss_OID oid;
159    size_t required;
160 
161    kret = EINVAL;
162    oid = (gss_OID) arg;
163    if (oid)  {
164       required = 2*sizeof(krb5_int32); /* For the header and trailer */
165       required += sizeof(krb5_int32);
166       required += oid->length;
167 
168       kret = 0;
169 
170       *sizep += required;
171    }
172 
173    return(kret);
174 }
175 
176 /*ARGSUSED*/
177 static krb5_error_code
178 kg_queue_externalize(kcontext, arg, buffer, lenremain)
179     krb5_context	kcontext;
180     krb5_pointer	arg;
181     krb5_octet		**buffer;
182     size_t		*lenremain;
183 {
184     krb5_error_code err;
185     err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
186     if (err == 0)
187 	err = g_queue_externalize(arg, buffer, lenremain);
188     if (err == 0)
189 	err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
190     return err;
191 }
192 
193 /*ARGSUSED*/
194 static krb5_error_code
195 kg_queue_internalize(kcontext, argp, buffer, lenremain)
196     krb5_context	kcontext;
197     krb5_pointer	*argp;
198     krb5_octet		**buffer;
199     size_t		*lenremain;
200 {
201      krb5_int32 ibuf;
202      krb5_octet		*bp;
203      size_t		remain;
204      krb5_error_code    err;
205 
206      bp = *buffer;
207      remain = *lenremain;
208 
209      /* Read in and check our magic number */
210      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
211 	return (EINVAL);
212 
213      if (ibuf != KV5M_GSS_QUEUE)
214 	 return (EINVAL);
215 
216      err = g_queue_internalize(argp, &bp, &remain);
217      if (err)
218         return err;
219 
220      /* Read in and check our trailing magic number */
221      if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
222 	return (EINVAL);
223 
224      if (ibuf != KV5M_GSS_QUEUE)
225 	 return (EINVAL);
226 
227      *buffer = bp;
228      *lenremain = remain;
229      return 0;
230 }
231 /*ARGSUSED*/
232 krb5_error_code
233 kg_queue_size(kcontext, arg, sizep)
234     krb5_context	kcontext;
235     krb5_pointer	arg;
236     size_t		*sizep;
237 {
238    krb5_error_code kret;
239    size_t required;
240 
241    kret = EINVAL;
242    if (arg) {
243       required = 2*sizeof(krb5_int32); /* For the header and trailer */
244       (void) g_queue_size(arg, &required);
245 
246       kret = 0;
247       *sizep += required;
248    }
249    return(kret);
250 }
251 
252 /*
253  * Determine the size required for this krb5_gss_ctx_id_rec.
254  */
255 krb5_error_code
256 kg_ctx_size(kcontext, arg, sizep)
257     krb5_context	kcontext;
258     krb5_pointer	arg;
259     size_t		*sizep;
260 {
261     krb5_error_code	kret;
262     krb5_gss_ctx_id_rec	*ctx;
263     size_t		required;
264 
265     KRB5_LOG0(KRB5_INFO, "kg_ctx_size() start \n");
266 
267     /*
268      * krb5_gss_ctx_id_rec requires:
269      *  krb5_int32      for KG_CONTEXT
270      *  krb5_int32      for initiate.
271      *  krb5_int32      for established.
272      *  krb5_int32      for big_endian.
273      *  krb5_int32      for have_acceptor_subkey.
274      *  krb5_int32      for seed_init.
275      *  krb5_int32      for gss_flags.
276      *  sizeof(seed)    for seed
277      *  krb5_int32      for signalg.
278      *  krb5_int32      for cksum_size.
279      *  krb5_int32      for sealalg.
280      *  krb5_int32      for endtime.
281      *  krb5_int32      for flags.
282      *  krb5_int64      for seq_send.
283      *  krb5_int64      for seq_recv.
284      *  ...             for mech_used
285      *  ...             for here
286      *  ...             for there
287      *  ...             for subkey
288      *  ...             for enc
289      *  ...             for seq
290      *  ...             for seqstate
291      *  ...             for auth_context
292      *  krb5_int32      for proto
293      *  krb5_int32      for cksumtype
294      *  ...             for acceptor_subkey
295      *  krb5_int32      for acceptor_key_cksumtype
296      *  krb5_int32      for trailer.
297      */
298 
299     kret = EINVAL;
300     ctx = (krb5_gss_ctx_id_rec *) arg;
301     if (ctx) {
302 	required = 16*sizeof(krb5_int32);
303 	required += 2*sizeof(krb5_int64);
304 	required += sizeof(ctx->seed);
305 
306 	kret = 0;
307 	if (!kret && ctx->here)
308 	    kret = krb5_size_opaque(kcontext,
309 				    KV5M_PRINCIPAL,
310 				    (krb5_pointer) ctx->here,
311 				    &required);
312 
313 	if (!kret && ctx->there)
314 	    kret = krb5_size_opaque(kcontext,
315 				    KV5M_PRINCIPAL,
316 				    (krb5_pointer) ctx->there,
317 				    &required);
318 
319 	if (!kret && ctx->subkey)
320 	    kret = krb5_size_opaque(kcontext,
321 				    KV5M_KEYBLOCK,
322 				    (krb5_pointer) ctx->subkey,
323 				    &required);
324 
325 	if (!kret && ctx->enc)
326 	    kret = krb5_size_opaque(kcontext,
327 				    KV5M_KEYBLOCK,
328 				    (krb5_pointer) ctx->enc,
329 				    &required);
330 
331 	if (!kret && ctx->seq)
332 	    kret = krb5_size_opaque(kcontext,
333 				    KV5M_KEYBLOCK,
334 				    (krb5_pointer) ctx->seq,
335 				    &required);
336 
337 	if (!kret)
338 	    kret = kg_oid_size(kcontext,
339 			       (krb5_pointer) &ctx->mech_used,
340 			       &required);
341 
342 	if (!kret && ctx->seqstate)
343 	    kret = kg_queue_size(kcontext, ctx->seqstate, &required);
344 #ifndef PROVIDE_KERNEL_IMPORT
345 	if (!kret)
346 	    kret = krb5_size_opaque(kcontext,
347 				    KV5M_AUTH_CONTEXT,
348 				    (krb5_pointer) ctx->auth_context,
349 				    &required);
350 #endif
351 	if (!kret && ctx->acceptor_subkey)
352             kret = krb5_size_opaque(kcontext,
353                                     KV5M_KEYBLOCK,
354                                     (krb5_pointer) ctx->acceptor_subkey,
355                                     &required);
356 
357 	if (!kret)
358 	    *sizep += required;
359     }
360     KRB5_LOG1(KRB5_INFO, "kg_ctx_size() end, kret = %d required = %lu\n", kret, required);
361     return(kret);
362 }
363 
364 /*
365  * Externalize this krb5_gss_ctx_id_ret.
366  */
367 krb5_error_code
368 kg_ctx_externalize(kcontext, arg, buffer, lenremain)
369     krb5_context	kcontext;
370     krb5_pointer	arg;
371     krb5_octet		**buffer;
372     size_t		*lenremain;
373 {
374     krb5_error_code	kret;
375     krb5_gss_ctx_id_rec	*ctx;
376     size_t		required;
377     krb5_octet		*bp;
378     size_t		remain;
379     /* SOLARIS KERBEROS: do not use accessor */
380 
381     KRB5_LOG0(KRB5_INFO, "kg_ctx_externalize() start\n");
382 
383     required = 0;
384     bp = *buffer;
385     remain = *lenremain;
386     kret = EINVAL;
387     ctx = (krb5_gss_ctx_id_rec *) arg;
388     if (ctx) {
389 	kret = ENOMEM;
390 	if (!kg_ctx_size(kcontext, arg, &required) &&
391 	    (required <= remain)) {
392 	    /* Our identifier */
393 	    (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
394 
395 	    /* Now static data */
396             (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
397                                        &bp, &remain);
398             (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
399                                        &bp, &remain);
400             (void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian,
401                                        &bp, &remain);
402             (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
403                                        &bp, &remain);
404             (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
405                                        &bp, &remain);
406             (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
407                                        &bp, &remain);
408             (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
409                                        sizeof(ctx->seed),
410                                        &bp, &remain);
411 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
412 				       &bp, &remain);
413 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
414 				       &bp, &remain);
415 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
416 				       &bp, &remain);
417 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->endtime,
418 				       &bp, &remain);
419 	    (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
420 				       &bp, &remain);
421 	    (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_send,
422 				       &bp, &remain);
423 	    (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_recv,
424 				       &bp, &remain);
425 
426 	    /* Now dynamic data */
427 	    kret = 0;
428 
429 	    if (!kret && &(ctx->mech_used))
430 		 kret = kg_oid_externalize(kcontext, &(ctx->mech_used),
431 					   &bp, &remain);
432 
433 	    if (!kret && ctx->here)
434 		kret = krb5_externalize_opaque(kcontext,
435 					       KV5M_PRINCIPAL,
436 					       (krb5_pointer) ctx->here,
437 					       &bp, &remain);
438 
439 	    if (!kret && ctx->there)
440 		kret = krb5_externalize_opaque(kcontext,
441 					       KV5M_PRINCIPAL,
442 					       (krb5_pointer) ctx->there,
443 					       &bp, &remain);
444 
445 	    if (!kret && ctx->subkey)
446 		kret = krb5_externalize_opaque(kcontext,
447 					       KV5M_KEYBLOCK,
448 					       (krb5_pointer) ctx->subkey,
449 					       &bp, &remain);
450 
451 	    if (!kret && ctx->enc)
452 		kret = krb5_externalize_opaque(kcontext,
453 					       KV5M_KEYBLOCK,
454 					       (krb5_pointer) ctx->enc,
455 					       &bp, &remain);
456 
457 	    if (!kret && ctx->seq)
458 		kret = krb5_externalize_opaque(kcontext,
459 					       KV5M_KEYBLOCK,
460 					       (krb5_pointer) ctx->seq,
461 					       &bp, &remain);
462 
463 	    if (!kret && ctx->seqstate)
464 		kret = kg_queue_externalize(kcontext,
465 					    ctx->seqstate, &bp, &remain);
466 
467 #ifndef PROVIDE_KERNEL_IMPORT
468 	    if (!kret)
469 		kret = krb5_externalize_opaque(kcontext,
470 					       KV5M_AUTH_CONTEXT,
471 					       (krb5_pointer) ctx->auth_context,
472 					       &bp, &remain);
473 #endif
474             if (!kret)
475 		kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
476                                            &bp, &remain);
477             if (!kret)
478 		kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
479                                            &bp, &remain);
480             if (!kret && ctx->acceptor_subkey)
481 		kret = krb5_externalize_opaque(kcontext,
482                                                KV5M_KEYBLOCK,
483                                                (krb5_pointer) ctx->acceptor_subkey,
484                                                &bp, &remain);
485             if (!kret)
486 		kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
487                                            &bp, &remain);
488 
489 	    if (!kret)
490 		(void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
491 	    if (!kret) {
492 		*buffer = bp;
493 		*lenremain = remain;
494 	    }
495 	}
496     }
497     KRB5_LOG(KRB5_INFO, "kg_ctx_externalize() end, kret = %d\n", kret);
498     return(kret);
499 }
500 
501 /*
502  * Internalize this krb5_gss_ctx_id_t.
503  */
504 krb5_error_code
505 kg_ctx_internalize(kcontext, argp, buffer, lenremain)
506     krb5_context	kcontext;
507     krb5_pointer	*argp;
508     krb5_octet		**buffer;
509     size_t		*lenremain;
510 {
511     krb5_error_code	kret;
512     krb5_gss_ctx_id_rec	*ctx;
513     krb5_int32		ibuf;
514     krb5_octet		*bp;
515     size_t		remain;
516 
517     KRB5_LOG0(KRB5_INFO, "kg_ctx_internalize() start\n");
518 
519     bp = *buffer;
520     remain = *lenremain;
521     kret = EINVAL;
522     /* Read our magic number */
523     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
524 	ibuf = 0;
525     if (ibuf == KG_CONTEXT) {
526 	kret = ENOMEM;
527 
528 	/* Get a context */
529 	if ((remain >= (16*sizeof(krb5_int32)
530 			+ 2*sizeof(krb5_int64)
531 			+ sizeof(ctx->seed))) &&
532 	    (ctx = (krb5_gss_ctx_id_rec *)
533 	     xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
534 	    (void) memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
535 
536 	    /* Get static data */
537             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
538             ctx->initiate = (int) ibuf;
539             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
540             ctx->established = (int) ibuf;
541             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
542             ctx->big_endian = (int) ibuf;
543             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
544             ctx->have_acceptor_subkey = (int) ibuf;
545             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
546             ctx->seed_init = (int) ibuf;
547             (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
548             ctx->gss_flags = (int) ibuf;
549 	    (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
550 					 sizeof(ctx->seed),
551 					 &bp, &remain);
552 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
553 	    ctx->signalg = (int) ibuf;
554 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
555 	    ctx->cksum_size = (int) ibuf;
556 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
557 	    ctx->sealalg = (int) ibuf;
558 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
559 	    ctx->endtime = (krb5_timestamp) ibuf;
560 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
561 	    ctx->krb_flags = (krb5_flags) ibuf;
562 	    (void) krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_send), &bp, &remain);
563 	    (void) krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_recv), &bp, &remain);
564 	    if ((kret = kg_oid_internalize(kcontext,
565 				(krb5_pointer)&ctx->mech_used, &bp,
566 				&remain))) {
567 		 if (kret == EINVAL)
568 		      kret = 0;
569 	    }
570 	    /* Now get substructure data */
571 	    if ((kret = krb5_internalize_opaque(kcontext,
572 						KV5M_PRINCIPAL,
573 						(krb5_pointer *) &ctx->here,
574 						&bp, &remain))) {
575 		if (kret == EINVAL)
576 		    kret = 0;
577 	    }
578 	    if (!kret &&
579 		(kret = krb5_internalize_opaque(kcontext,
580 						KV5M_PRINCIPAL,
581 						(krb5_pointer *) &ctx->there,
582 						&bp, &remain))) {
583 		if (kret == EINVAL)
584 		    kret = 0;
585 	    }
586 	    if (!kret &&
587 		(kret = krb5_internalize_opaque(kcontext,
588 						KV5M_KEYBLOCK,
589 						(krb5_pointer *) &ctx->subkey,
590 						&bp, &remain))) {
591 		if (kret == EINVAL)
592 		    kret = 0;
593 	    }
594 	    if (!kret &&
595 		(kret = krb5_internalize_opaque(kcontext,
596 						KV5M_KEYBLOCK,
597 						(krb5_pointer *) &ctx->enc,
598 						&bp, &remain))) {
599 		if (kret == EINVAL)
600 		    kret = 0;
601 	    }
602 	    if (!kret &&
603 		(kret = krb5_internalize_opaque(kcontext,
604 						KV5M_KEYBLOCK,
605 						(krb5_pointer *) &ctx->seq,
606 						&bp, &remain))) {
607 		if (kret == EINVAL)
608 		    kret = 0;
609 	    }
610 
611 	    if (!kret) {
612 		kret = kg_queue_internalize(kcontext, &ctx->seqstate,
613 					    &bp, &remain);
614 		if (kret == EINVAL)
615 		    kret = 0;
616 	    }
617 #ifndef PROVIDE_KERNEL_IMPORT
618      	    if (!kret)
619 		kret = krb5_internalize_opaque(kcontext,
620 					       KV5M_AUTH_CONTEXT,
621 				       (krb5_pointer *) &ctx->auth_context,
622 					       &bp, &remain);
623 #endif
624 	    if (!kret)
625 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
626 	    ctx->proto = ibuf;
627 	    if (!kret)
628 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
629 	    ctx->cksumtype = ibuf;
630 	    if (!kret &&
631 		(kret = krb5_internalize_opaque(kcontext,
632 						KV5M_KEYBLOCK,
633 						(krb5_pointer *) &ctx->acceptor_subkey,
634 						&bp, &remain))) {
635 		if (kret == EINVAL)
636                     kret = 0;
637             }
638             if (!kret)
639 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
640             ctx->acceptor_subkey_cksumtype = ibuf;
641 done:
642 	    /* Get trailer */
643             if (!kret)
644 		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
645 
646             if (!kret && ibuf != KG_CONTEXT)
647 		kret = EINVAL;
648 
649             if (!kret) {
650 		*buffer = bp;
651 		*lenremain = remain;
652 		*argp = (krb5_pointer) ctx;
653 	    } else {
654 		if (!kret && (ibuf != KG_CONTEXT))
655 		    kret = EINVAL;
656 		if (ctx->seq)
657 		    krb5_free_keyblock(kcontext, ctx->seq);
658 		if (ctx->enc)
659 		    krb5_free_keyblock(kcontext, ctx->enc);
660 		if (ctx->subkey)
661 		    krb5_free_keyblock(kcontext, ctx->subkey);
662 		if (ctx->there)
663 		    krb5_free_principal(kcontext, ctx->there);
664 		if (ctx->here)
665 		    krb5_free_principal(kcontext, ctx->here);
666 		xfree_wrap(ctx, sizeof (krb5_gss_ctx_id_rec));
667 	    }
668 	}
669     }
670 
671     KRB5_LOG(KRB5_INFO, "kg_ctx_internalize() end kret = %d\n", kret);
672 
673     return(kret);
674 }
675