xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c (revision 4e567b4443d7a1680a7319275e5288eef2c92319)
1 /*
2  * Copyright 2000, 2004  by the Massachusetts Institute of Technology.
3  * All Rights Reserved.
4  *
5  * Export of this software from the United States of America may
6  *   require a specific license from the United States Government.
7  *   It is the responsibility of any person or organization contemplating
8  *   export to obtain such a license before exporting.
9  *
10  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11  * distribute this software and its documentation for any purpose and
12  * without fee is hereby granted, provided that the above copyright
13  * notice appear in all copies and that both that copyright notice and
14  * this permission notice appear in supporting documentation, and that
15  * the name of M.I.T. not be used in advertising or publicity pertaining
16  * to distribution of the software without specific, written prior
17  * permission.  Furthermore if you modify this software you must label
18  * your software as modified software and not distribute it in such a
19  * fashion that it might be confused with the original M.I.T. software.
20  * M.I.T. makes no representations about the suitability of
21  * this software for any purpose.  It is provided "as is" without express
22  * or implied warranty.
23  *
24  */
25 /*
26  * Copyright 1993 by OpenVision Technologies, Inc.
27  *
28  * Permission to use, copy, modify, distribute, and sell this software
29  * and its documentation for any purpose is hereby granted without fee,
30  * provided that the above copyright notice appears in all copies and
31  * that both that copyright notice and this permission notice appear in
32  * supporting documentation, and that the name of OpenVision not be used
33  * in advertising or publicity pertaining to distribution of the software
34  * without specific, written prior permission. OpenVision makes no
35  * representations about the suitability of this software for any
36  * purpose.  It is provided "as is" without express or implied warranty.
37  *
38  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44  * PERFORMANCE OF THIS SOFTWARE.
45  */
46 
47 /*
48  * Copyright (C) 1998 by the FundsXpress, INC.
49  *
50  * All rights reserved.
51  *
52  * Export of this software from the United States of America may require
53  * a specific license from the United States Government.  It is the
54  * responsibility of any person or organization contemplating export to
55  * obtain such a license before exporting.
56  *
57  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
58  * distribute this software and its documentation for any purpose and
59  * without fee is hereby granted, provided that the above copyright
60  * notice appear in all copies and that both that copyright notice and
61  * this permission notice appear in supporting documentation, and that
62  * the name of FundsXpress. not be used in advertising or publicity pertaining
63  * to distribution of the software without specific, written prior
64  * permission.  FundsXpress makes no representations about the suitability of
65  * this software for any purpose.  It is provided "as is" without express
66  * or implied warranty.
67  *
68  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
69  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
70  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
71  */
72 
73 /*
74  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
75  * Use is subject to license terms.
76  */
77 
78 #include "k5-int.h"
79 #include "gssapiP_krb5.h"
80 #ifdef HAVE_MEMORY_H
81 #include <memory.h>
82 #endif
83 #include <assert.h>
84 #include "auth_con.h"
85 
86 #ifdef CFX_EXERCISE
87 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
88 #else
89 #define CFX_ACCEPTOR_SUBKEY 1
90 #endif
91 
92 /*
93  * Decode, decrypt and store the forwarded creds in the local ccache.
94  * and populate the callers delegated credential handle if it
95  * was provided.
96  */
97 static krb5_error_code
98 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
99     krb5_context context;
100     krb5_auth_context auth_context;
101     krb5_data *inbuf;
102     krb5_gss_cred_id_t *out_cred;
103 {
104     krb5_creds ** creds = NULL;
105     krb5_error_code retval;
106     krb5_ccache ccache = NULL;
107     krb5_gss_cred_id_t cred = NULL;
108     krb5_auth_context new_auth_ctx = NULL;
109 	krb5_int32 flags_org;
110 
111     /* Solaris Kerberos */
112     KRB5_LOG0(KRB5_INFO, "rd_and_store_for_creds() start");
113 
114 	if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
115 		return retval;
116 	krb5_auth_con_setflags(context, auth_context,
117 			       0);
118 
119 	/*
120 	 * By the time krb5_rd_cred is called here (after krb5_rd_req has been
121 	 * called in krb5_gss_accept_sec_context), the "keyblock" field of
122 	 * auth_context contains a pointer to the session key, and the
123 	 * "recv_subkey" field might contain a session subkey.  Either of
124 	 * these (the "recv_subkey" if it isn't NULL, otherwise the
125 	 * "keyblock") might have been used to encrypt the encrypted part of
126 	 * the KRB_CRED message that contains the forwarded credentials.  (The
127 	 * Java Crypto and Security Implementation from the DSTC in Australia
128 	 * always uses the session key.  But apparently it never negotiates a
129 	 * subkey, so this code works fine against a JCSI client.)  Up to the
130 	 * present, though, GSSAPI clients linked against the MIT code (which
131 	 * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
132 	 * all -- at this level.  So if the first call to krb5_rd_cred fails,
133 	 * we should call it a second time with another auth context freshly
134 	 * created by krb5_auth_con_init.  All of its keyblock fields will be
135 	 * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
136 	 * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
137 	 * message in the clear -- the "authenticator" whose "checksum" ends up
138 	 * containing the KRB_CRED message does get encrypted.)
139 	 */
140     /* Solaris Kerberos */
141     if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) {
142 	krb5_enctype enctype = ENCTYPE_NULL;
143 	/*
144 	 * If the client is using non-DES enctypes it really ought to
145 	 * send encrypted KRB-CREDs...
146 	 */
147 	if (auth_context->keyblock != NULL)
148 	    enctype = auth_context->keyblock->enctype;
149 	switch (enctype) {
150 	case ENCTYPE_DES_CBC_MD5:
151 	case ENCTYPE_DES_CBC_CRC:
152 	case ENCTYPE_DES3_CBC_SHA1:
153 	    break;
154 	default:
155 	    KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
156 		    "krb5_rd_cred() retval = %d\n", retval);
157 	    goto cleanup;
158 	    /* NOTREACHED */
159 	    break;
160 	}
161 
162 	/* Try to krb5_rd_cred() likely unencrypted KRB-CRED */
163 		if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
164 			goto cleanup;
165 		krb5_auth_con_setflags(context, new_auth_ctx, 0);
166 		if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
167 					   &creds, NULL))) {
168 			/* Solaris Kerberos */
169 			KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
170 			    "krb5_rd_cred() retval = %d\n", retval);
171 			goto cleanup;
172 		}
173     }
174 
175     if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
176 	ccache = NULL;
177         goto cleanup;
178     }
179 
180     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) {
181 	/* Solaris Kerberos */
182 	KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
183 		"krb5_cc_initialize() retval = %d\n", retval);
184 	goto cleanup;
185     }
186 
187     if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) {
188 	/* Solaris Kerberos */
189 	KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
190 		"krb5_cc_store_cred() retval = %d\n", retval);
191 	goto cleanup;
192     }
193 
194     /* generate a delegated credential handle */
195     if (out_cred) {
196 	/* allocate memory for a cred_t... */
197 	if (!(cred =
198 	      (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
199 	    retval = ENOMEM; /* out of memory? */
200 	    *out_cred = NULL;
201 	    goto cleanup;
202 	}
203 
204 	/* zero it out... */
205 	/* Solaris Kerberos */
206 	(void) memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
207 
208 	retval = k5_mutex_init(&cred->lock);
209 	if (retval) {
210 	    xfree(cred);
211 	    cred = NULL;
212 	    goto cleanup;
213 	}
214 
215 	/* copy the client principle into it... */
216 	if ((retval =
217 	     krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
218 	     /* Solaris Kerberos */
219 	    KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
220 		    "krb5_copy_principal() retval = %d\n", retval);
221 	    k5_mutex_destroy(&cred->lock);
222 	    retval = ENOMEM; /* out of memory? */
223 	    xfree(cred); /* clean up memory on failure */
224 	    cred = NULL;
225 	    goto cleanup;
226 	}
227 
228 	cred->usage = GSS_C_INITIATE; /* we can't accept with this */
229 	/* cred->princ already set */
230 	cred->prerfc_mech = 1; /* this cred will work with all three mechs */
231 	cred->rfc_mech = 1;
232 	cred->keytab = NULL; /* no keytab associated with this... */
233 	cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
234 	cred->ccache = ccache; /* the ccache containing the credential */
235 	ccache = NULL; /* cred takes ownership so don't destroy */
236     }
237 
238     /* If there were errors, there might have been a memory leak
239        if (!cred)
240        if ((retval = krb5_cc_close(context, ccache)))
241        goto cleanup;
242     */
243 cleanup:
244     if (creds)
245 	krb5_free_tgt_creds(context, creds);
246 
247     if (ccache)
248 	(void)krb5_cc_destroy(context, ccache);
249 
250     if (out_cred)
251 	*out_cred = cred; /* return credential */
252 
253     if (new_auth_ctx)
254 	krb5_auth_con_free(context, new_auth_ctx);
255 
256     krb5_auth_con_setflags(context, auth_context, flags_org);
257 
258     /* Solaris Kerberos */
259     KRB5_LOG(KRB5_INFO, "rd_and_store_for_creds() end retval %d", retval);
260     return retval;
261 }
262 
263 /*
264  * SUNW15resync
265  * Most of the logic here left "as is" because of lots of fixes MIT
266  * does not have yet
267  */
268 OM_uint32
269 krb5_gss_accept_sec_context(minor_status, context_handle,
270 			    verifier_cred_handle, input_token,
271 			    input_chan_bindings, src_name, mech_type,
272 			    output_token, ret_flags, time_rec,
273 			    delegated_cred_handle)
274      OM_uint32 *minor_status;
275      gss_ctx_id_t *context_handle;
276      gss_cred_id_t verifier_cred_handle;
277      gss_buffer_t input_token;
278      gss_channel_bindings_t input_chan_bindings;
279      gss_name_t *src_name;
280      gss_OID *mech_type;
281      gss_buffer_t output_token;
282      OM_uint32 *ret_flags;
283      OM_uint32 *time_rec;
284      gss_cred_id_t *delegated_cred_handle;
285 {
286    krb5_context context;
287    unsigned char *ptr, *ptr2;
288    krb5_gss_ctx_id_rec *ctx = 0;
289    char *sptr;
290    long tmp;
291    size_t md5len;
292    int bigend;
293    krb5_gss_cred_id_t cred = 0;
294    krb5_data ap_rep, ap_req;
295    krb5_ap_req *request = NULL;
296    int i;
297    krb5_error_code code;
298    krb5_address addr, *paddr;
299    krb5_authenticator *authdat = 0;
300    krb5_checksum reqcksum;
301    krb5_principal name = NULL;
302    krb5_ui_4 gss_flags = 0;
303    krb5_timestamp now;
304    gss_buffer_desc token;
305    krb5_auth_context auth_context = NULL;
306    krb5_ticket * ticket = NULL;
307    int option_id;
308    krb5_data option;
309    const gss_OID_desc *mech_used = NULL;
310    OM_uint32 major_status = GSS_S_FAILURE;
311    krb5_error krb_error_data;
312    krb5_data scratch;
313    gss_cred_id_t cred_handle = NULL;
314    krb5_gss_cred_id_t deleg_cred = NULL;
315    OM_uint32 saved_ap_options = 0;
316    krb5int_access kaccess;
317    int cred_rcache = 0;
318    int no_encap;
319    OM_uint32 t_minor_status = 0;
320 
321    KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
322 
323    /* Solaris Kerberos */
324    memset(&krb_error_data, 0, sizeof(krb_error_data));
325 
326    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
327    if (code) {
328        *minor_status = code;
329        return(GSS_S_FAILURE);
330    }
331 
332    code = krb5_gss_init_context(&context);
333    if (code) {
334        *minor_status = code;
335        return GSS_S_FAILURE;
336    }
337 
338    /* set up returns to be freeable */
339 
340    if (src_name)
341       *src_name = (gss_name_t) NULL;
342    output_token->length = 0;
343    output_token->value = NULL;
344    token.value = 0;
345    reqcksum.contents = 0;
346    ap_req.data = 0;
347    ap_rep.data = 0;
348 
349    if (mech_type)
350       *mech_type = GSS_C_NULL_OID;
351    /* initialize the delegated cred handle to NO_CREDENTIAL for now */
352    if (delegated_cred_handle)
353       *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
354 
355    /*
356     * Context handle must be unspecified.  Actually, it must be
357     * non-established, but currently, accept_sec_context never returns
358     * a non-established context handle.
359     */
360    /*SUPPRESS 29*/
361    if (*context_handle != GSS_C_NO_CONTEXT) {
362       *minor_status = 0;
363 
364        /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
365 	* for this error.  This conflicts somewhat with RFC2743 which states
366 	* GSS_S_NO_CONTEXT should be returned only for sucessor calls following
367 	* GSS_S_CONTINUE_NEEDED status returns.  Note the MIT code doesn't
368 	* return GSS_S_NO_CONTEXT at all.
369 	*/
370 
371       major_status = GSS_S_NO_CONTEXT;
372       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
373 	      "error GSS_S_NO_CONTEXT");
374       goto cleanup;
375    }
376 
377    /* verify the token's integrity, and leave the token in ap_req.
378       figure out which mech oid was used, and save it */
379 
380    ptr = (unsigned char *) input_token->value;
381 
382    if (!(code = g_verify_token_header(gss_mech_krb5,
383 				      (uint32_t *)&(ap_req.length),
384 				      &ptr, KG_TOK_CTX_AP_REQ,
385 				      input_token->length, 1))) {
386        mech_used = gss_mech_krb5;
387    } else if ((code == G_WRONG_MECH) &&
388 		!(code = g_verify_token_header(gss_mech_krb5_wrong,
389 						(uint32_t *)&(ap_req.length),
390 						&ptr, KG_TOK_CTX_AP_REQ,
391 						input_token->length, 1))) {
392 	mech_used = gss_mech_krb5_wrong;
393    } else if ((code == G_WRONG_MECH) &&
394 	      !(code = g_verify_token_header(gss_mech_krb5_old,
395 					     (uint32_t *)&(ap_req.length),
396 					     &ptr, KG_TOK_CTX_AP_REQ,
397 					     input_token->length, 1))) {
398        /*
399 	* Previous versions of this library used the old mech_id
400 	* and some broken behavior (wrong IV on checksum
401 	* encryption).  We support the old mech_id for
402 	* compatibility, and use it to decide when to use the
403 	* old behavior.
404 	*/
405        mech_used = gss_mech_krb5_old;
406   } else if (code == G_WRONG_TOKID) {
407 	major_status = GSS_S_CONTINUE_NEEDED;
408         code = KRB5KRB_AP_ERR_MSG_TYPE;
409         mech_used = gss_mech_krb5;
410         goto fail;
411    } else if (code == G_BAD_TOK_HEADER) {
412 	/* DCE style not encapsulated */
413         ap_req.length = input_token->length;
414         ap_req.data = input_token->value;
415         mech_used = gss_mech_krb5;
416         no_encap = 1;
417    } else {
418 	major_status = GSS_S_DEFECTIVE_TOKEN;
419         goto fail;
420    }
421 
422    sptr = (char *) ptr;
423    TREAD_STR(sptr, ap_req.data, ap_req.length);
424 
425    /*
426     * Solaris Kerberos:
427     *  We need to decode the request now so that we can get the
428     *  service principal in order to try and acquire a cred for it.
429     *  below in the "handle default cred handle" code block.
430     */
431    if (!krb5_is_ap_req(&ap_req)) {
432        code = KRB5KRB_AP_ERR_MSG_TYPE;
433        goto fail;
434    }
435    /* decode the AP-REQ into request */
436    if ((code = decode_krb5_ap_req(&ap_req, &request))) {
437        if (code == KRB5_BADMSGTYPE)
438            code = KRB5KRB_AP_ERR_BADVERSION;
439        goto fail;
440    }
441 
442    /* handle default cred handle */
443    /*
444     * Solaris Kerberos:
445     * If there is no princ associated with the cred then treat it the
446     * the same as GSS_C_NO_CREDENTIAL.
447     */
448    if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
449     ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
450        /* Note that we try to acquire a cred for the service principal
451 	* named in the AP-REQ. This allows us to implement option (ii)
452 	* of the recommended behaviour for GSS_Accept_sec_context() as
453 	* described in section 1.1.1.3 of RFC2743.
454 
455 	* This is far more useful that option (i), for which we would
456 	* acquire a cred for GSS_C_NO_NAME.
457 	*/
458        /* copy the princ from the ap-req or we'll lose it when we free
459 	  the ap-req */
460        krb5_principal princ;
461        if ((code = krb5_copy_principal(context, request->ticket->server,
462 				       &princ))) {
463            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
464 	            "krb5_copy_principal() error code %d", code);
465 	   major_status = GSS_S_FAILURE;
466 	   goto fail;
467        }
468        /* intern the acceptor name */
469        if (! kg_save_name((gss_name_t) princ)) {
470 	   code = G_VALIDATE_FAILED;
471 	   major_status = GSS_S_FAILURE;
472 	   goto fail;
473        }
474        major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
475 					    (gss_name_t) princ,
476 					    GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
477 					    GSS_C_ACCEPT, &cred_handle,
478 					    NULL, NULL);
479 
480        if (major_status != GSS_S_COMPLETE){
481 
482 	   /* Solaris kerberos: RFC2743 indicate this should be returned if we
483 	    * can't aquire a default cred.
484 	    */
485 	   KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
486 		  "krb5_gss_acquire_cred() error"
487 		   "orig major_status = %d, now = GSS_S_NO_CRED\n",
488 		   major_status);
489 
490 	   major_status = GSS_S_NO_CRED;
491 	   goto fail;
492        }
493 
494    } else {
495        cred_handle = verifier_cred_handle;
496    }
497 
498    major_status = krb5_gss_validate_cred((OM_uint32*) &code,
499 						 cred_handle);
500 
501    if (GSS_ERROR(major_status)){
502 
503        /* Solaris kerberos: RFC2743 indicate GSS_S_NO_CRED should be returned if
504 	* the supplied cred isn't valid.
505 	*/
506 
507        KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
508 	      "krb5_gss_validate_cred() error"
509 	       "orig major_status = %d, now = GSS_S_NO_CRED\n",
510 	       major_status);
511 
512        major_status = GSS_S_NO_CRED;
513        goto fail;
514    }
515 
516    cred = (krb5_gss_cred_id_t) cred_handle;
517 
518    /* make sure the supplied credentials are valid for accept */
519 
520    if ((cred->usage != GSS_C_ACCEPT) &&
521        (cred->usage != GSS_C_BOTH)) {
522        code = 0;
523       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
524 	      "error GSS_S_NO_CONTEXT");
525        major_status = GSS_S_NO_CRED;
526        goto fail;
527    }
528 
529    /* construct the sender_addr */
530 
531    if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
532        (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
533        /* XXX is this right? */
534        addr.addrtype = ADDRTYPE_INET;
535        addr.length = input_chan_bindings->initiator_address.length;
536        addr.contents = input_chan_bindings->initiator_address.value;
537 
538        paddr = &addr;
539    } else {
540        paddr = NULL;
541    }
542 
543    /* verify the AP_REQ message - setup the auth_context and rcache */
544 
545    if ((code = krb5_auth_con_init(context, &auth_context))) {
546        major_status = GSS_S_FAILURE;
547        /* Solaris Kerberos */
548        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
549 	      "krb5_auth_con_init() error code %d", code);
550        goto fail;
551    }
552 
553    (void) krb5_auth_con_setflags(context, auth_context,
554                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);
555 
556    if (cred->rcache) {
557        cred_rcache = 1;
558        if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
559 	   major_status = GSS_S_FAILURE;
560            /* Solaris Kerberos */
561 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
562 		    "krb5_auth_con_setrcache() error code %d", code);
563 	   goto fail;
564        }
565    }
566    if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
567        major_status = GSS_S_FAILURE;
568        /* Solaris Kerberos */
569        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
570 	      "krb5_auth_con_setaddrs() error code %d", code);
571        goto fail;
572    }
573 
574    if ((code = krb5_rd_req_decoded(context, &auth_context, request,
575 			   cred->princ, cred->keytab, NULL, &ticket))) {
576       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
577 	      "krb5_rd_req() error code %d", code);
578        if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) {
579            major_status = GSS_S_DEFECTIVE_CREDENTIAL;
580 	   code = KRB5KRB_AP_ERR_NOKEY;
581        }
582        else if (code == KRB5KRB_AP_WRONG_PRINC) {
583            major_status = GSS_S_NO_CRED;
584 	   code = KRB5KRB_AP_ERR_NOT_US;
585        }
586        else if (code == KRB5KRB_AP_ERR_REPEAT)
587            major_status = GSS_S_DUPLICATE_TOKEN;
588        else
589            major_status = GSS_S_FAILURE;
590        goto fail;
591    }
592    krb5_auth_con_setflags(context, auth_context,
593 			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
594 
595    krb5_auth_con_getauthenticator(context, auth_context, &authdat);
596 
597 #if 0
598    /* make sure the necessary parts of the authdat are present */
599 
600    if ((authdat->authenticator->subkey == NULL) ||
601        (authdat->ticket->enc_part2 == NULL)) {
602 	   code = KG_NO_SUBKEY;
603 	   major_status = GSS_S_FAILURE;
604 	   goto fail;
605    }
606 #endif
607 
608    {
609        /* gss krb5 v1 */
610 
611        /* stash this now, for later. */
612        code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
613        if (code) {
614 	   /* Solaris Kerberos */
615 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
616 		  "krb5_c_checksum_length() error code %d", code);
617 	   major_status = GSS_S_FAILURE;
618 	   goto fail;
619        }
620 
621        /* verify that the checksum is correct */
622 
623        /*
624 	 The checksum may be either exactly 24 bytes, in which case
625 	 no options are specified, or greater than 24 bytes, in which case
626 	 one or more options are specified. Currently, the only valid
627 	 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
628        */
629 
630        if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
631 	   (authdat->checksum->length < 24)) {
632 	   code = 0;
633 	   major_status = GSS_S_BAD_BINDINGS;
634 	   goto fail;
635        }
636 
637        /*
638 	 "Be liberal in what you accept, and
639 	 conservative in what you send"
640 	 -- rfc1123
641 
642 	 This code will let this acceptor interoperate with an initiator
643 	 using little-endian or big-endian integer encoding.
644        */
645 
646        ptr = (unsigned char *) authdat->checksum->contents;
647        bigend = 0;
648 
649        TREAD_INT(ptr, tmp, bigend);
650 
651        if (tmp != md5len) {
652 	   ptr = (unsigned char *) authdat->checksum->contents;
653 	   bigend = 1;
654 
655 	   TREAD_INT(ptr, tmp, bigend);
656 
657 	   if (tmp != md5len) {
658 	       code = KG_BAD_LENGTH;
659 	       major_status = GSS_S_FAILURE;
660 	       goto fail;
661 	   }
662        }
663 
664        /* at this point, bigend is set according to the initiator's
665 	  byte order */
666 
667 
668        /*
669           The following section of code attempts to implement the
670           optional channel binding facility as described in RFC2743.
671 
672           Since this facility is optional channel binding may or may
673           not have been provided by either the client or the server.
674 
675           If the server has specified input_chan_bindings equal to
676           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
677           the server does provide channel bindings then we compute
678           a checksum and compare against those provided by the
679           client.  If the check fails we test the clients checksum
680           to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
681           If either test succeeds we continue without error.
682         */
683        if ((code = kg_checksum_channel_bindings(context,
684 						input_chan_bindings,
685 						&reqcksum, bigend))) {
686 	   /* Solaris Kerberos */
687 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
688 		  "kg_checksum_channel_bindings() error code %d", code);
689 	 major_status = GSS_S_BAD_BINDINGS;
690 	 goto fail;
691        }
692 
693        TREAD_STR(ptr, ptr2, reqcksum.length);
694 
695        if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
696            if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
697                xfree(reqcksum.contents);
698                reqcksum.contents = 0;
699 		if ((code = kg_checksum_channel_bindings(context,
700                                                   GSS_C_NO_CHANNEL_BINDINGS,
701                                                   &reqcksum, bigend))) {
702                    major_status = GSS_S_BAD_BINDINGS;
703                    goto fail;
704 		}
705                if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
706                    code = 0;
707                    major_status = GSS_S_BAD_BINDINGS;
708                    goto fail;
709 		}
710            }
711 
712        }
713 
714        TREAD_INT(ptr, gss_flags, bigend);
715 
716        /* if the checksum length > 24, there are options to process */
717 
718        if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
719 
720 	   i = authdat->checksum->length - 24;
721 
722 	   if (i >= 4) {
723 
724 	       TREAD_INT16(ptr, option_id, bigend);
725 
726 	       TREAD_INT16(ptr, option.length, bigend);
727 
728 	       i -= 4;
729 
730 	       if (i < option.length || option.length < 0) {
731 		   code = KG_BAD_LENGTH;
732 		   major_status = GSS_S_FAILURE;
733 		   goto fail;
734 	       }
735 
736 	       /* have to use ptr2, since option.data is wrong type and
737 		  macro uses ptr as both lvalue and rvalue */
738 
739 	       TREAD_STR(ptr, ptr2, option.length);
740 	       option.data = (char *) ptr2;
741 
742 	       i -= option.length;
743 
744 	       if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
745 		   major_status = GSS_S_FAILURE;
746 		   goto fail;
747 	       }
748 
749 		   /* store the delegated credential */
750 
751 		   code = rd_and_store_for_creds(context, auth_context, &option,
752 						 (delegated_cred_handle) ?
753 						 &deleg_cred : NULL);
754 		   if (code) {
755 		       major_status = GSS_S_FAILURE;
756 		       goto fail;
757 		   }
758 
759 	   } /* if i >= 4 */
760 	   /* ignore any additional trailing data, for now */
761 #ifdef CFX_EXERCISE
762 	   {
763 	       FILE *f = fopen("/tmp/gsslog", "a");
764 	       if (f) {
765 		   fprintf(f,
766 			   "initial context token with delegation, %d extra bytes\n",
767 			   i);
768 		   fclose(f);
769 	       }
770 	   }
771 #endif
772        } else {
773 #ifdef CFX_EXERCISE
774 	   {
775 	       FILE *f = fopen("/tmp/gsslog", "a");
776 	       if (f) {
777 		   if (gss_flags & GSS_C_DELEG_FLAG)
778 		       fprintf(f,
779 			       "initial context token, delegation flag but too small\n");
780 		   else
781 		       /* no deleg flag, length might still be too big */
782 		       fprintf(f,
783 			       "initial context token, %d extra bytes\n",
784 			       authdat->checksum->length - 24);
785 		   fclose(f);
786 	       }
787 	   }
788 #endif
789        }
790    }
791 
792    /* create the ctx struct and start filling it in */
793 
794    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
795        == NULL) {
796        code = ENOMEM;
797        major_status = GSS_S_FAILURE;
798        goto fail;
799    }
800 
801    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
802    ctx->mech_used = (gss_OID) mech_used;
803    ctx->auth_context = auth_context;
804    ctx->initiate = 0;
805    ctx->gss_flags = (GSS_C_TRANS_FLAG |
806                     ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
807                             GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
808                             GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
809    ctx->seed_init = 0;
810    ctx->big_endian = bigend;
811    ctx->cred_rcache = cred_rcache;
812 
813    /* Intern the ctx pointer so that delete_sec_context works */
814    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
815        xfree(ctx);
816        ctx = 0;
817 
818 	/* Solaris Kerberos */
819        KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
820 	      "kg_save_ctx_id() error");
821        code = G_VALIDATE_FAILED;
822        major_status = GSS_S_FAILURE;
823        goto fail;
824    }
825 
826    /* XXX move this into gss_name_t */
827    if ((code = krb5_merge_authdata(context,
828 				ticket->enc_part2->authorization_data,
829 				authdat->authorization_data,
830 				&ctx->authdata))) {
831 	major_status = GSS_S_FAILURE;
832         goto fail;
833    }
834 
835    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
836 	/* Solaris Kerberos */
837        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
838 	      "krb5_copy_principal() error code %d", code);
839        major_status = GSS_S_FAILURE;
840        goto fail;
841    }
842 
843    if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
844 	/* Solaris Kerberos */
845        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
846 	      "krb5_copy_principal() 2 error code %d", code);
847        major_status = GSS_S_FAILURE;
848        goto fail;
849    }
850 
851    if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
852 					   &ctx->subkey))) {
853 	/* Solaris Kerberos */
854        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
855 	      "krb5_auth_con_getremotesubkey() error code %d", code);
856        major_status = GSS_S_FAILURE;
857        goto fail;
858    }
859 
860    /* use the session key if the subkey isn't present */
861 
862    if (ctx->subkey == NULL) {
863        if ((code = krb5_auth_con_getkey(context, auth_context,
864 					&ctx->subkey))) {
865 	/* Solaris Kerberos */
866 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
867 		      "krb5_auth_con_getkey() error code %d", code);
868            *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
869 	   major_status = GSS_S_FAILURE;
870 	   goto fail;
871        }
872    }
873 
874    if (ctx->subkey == NULL) {
875        /* this isn't a very good error, but it's not clear to me this
876 	  can actually happen */
877        major_status = GSS_S_FAILURE;
878        code = KRB5KDC_ERR_NULL_KEY;
879        goto fail;
880    }
881 
882     /* Solaris Kerberos */
883    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
884 	   "ctx->subkey->enctype=%d", ctx->subkey->enctype);
885 
886    ctx->proto = 0;
887    switch(ctx->subkey->enctype) {
888    case ENCTYPE_DES_CBC_MD5:
889    case ENCTYPE_DES_CBC_CRC:
890        ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
891        ctx->signalg = SGN_ALG_DES_MAC_MD5;
892        ctx->cksum_size = 8;
893        ctx->sealalg = SEAL_ALG_DES;
894 
895        /* fill in the encryption descriptors */
896 
897        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
898 	   major_status = GSS_S_FAILURE;
899 	   goto fail;
900        }
901 
902        for (i=0; i<ctx->enc->length; i++)
903 	   /*SUPPRESS 113*/
904 	   ctx->enc->contents[i] ^= 0xf0;
905 
906        goto copy_subkey_to_seq;
907        break;
908 
909    case ENCTYPE_DES3_CBC_SHA1:
910        ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
911        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
912        ctx->cksum_size = 20;
913        ctx->sealalg = SEAL_ALG_DES3KD;
914 
915        /* fill in the encryption descriptors */
916    copy_subkey:
917        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
918 	   major_status = GSS_S_FAILURE;
919 	   goto fail;
920        }
921    copy_subkey_to_seq:
922        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
923 	   major_status = GSS_S_FAILURE;
924 	   goto fail;
925        }
926        break;
927 
928    case ENCTYPE_ARCFOUR_HMAC:
929        ctx->signalg = SGN_ALG_HMAC_MD5 ;
930        ctx->cksum_size = 8;
931        ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
932        goto copy_subkey;
933 
934    default:
935        ctx->signalg = -1;
936        ctx->sealalg = -1;
937        ctx->proto = 1;
938        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
939 					    &ctx->cksumtype);
940        if (code)
941 	   goto fail;
942        code = krb5_c_checksum_length(context, ctx->cksumtype,
943 		(size_t *)&ctx->cksum_size);
944        if (code)
945 	   goto fail;
946        ctx->have_acceptor_subkey = 0;
947        goto copy_subkey;
948    }
949 
950     /* Solaris Kerberos */
951    KRB5_LOG1(KRB5_ERR, "accept_sec_context:  subkey enctype = %d proto = %d",
952 	ctx->subkey->enctype, ctx->proto);
953 
954    ctx->endtime = ticket->enc_part2->times.endtime;
955    ctx->krb_flags = ticket->enc_part2->flags;
956 
957    krb5_free_ticket(context, ticket); /* Done with ticket */
958 
959    {
960        krb5_ui_4 seq_temp;
961        krb5_auth_con_getremoteseqnumber(context, auth_context,
962 		(krb5_int32 *)&seq_temp);
963        ctx->seq_recv = seq_temp;
964    }
965 
966    if ((code = krb5_timeofday(context, &now))) {
967        major_status = GSS_S_FAILURE;
968        goto fail;
969    }
970 
971    if (ctx->endtime < now) {
972        code = 0;
973        major_status = GSS_S_CREDENTIALS_EXPIRED;
974        goto fail;
975    }
976 
977    g_order_init(&(ctx->seqstate), ctx->seq_recv,
978 		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
979 		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
980 
981    /* at this point, the entire context structure is filled in,
982       so it can be released.  */
983 
984    /* generate an AP_REP if necessary */
985 
986    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
987        unsigned char * ptr3;
988        krb5_ui_4 seq_temp;
989        int cfx_generate_subkey;
990 
991        if (ctx->proto == 1)
992 	   cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
993        else
994 	   cfx_generate_subkey = 0;
995 
996        if (cfx_generate_subkey) {
997 	   krb5_int32 acflags;
998 	   code = krb5_auth_con_getflags(context, auth_context, &acflags);
999 	   if (code == 0) {
1000 	       acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1001 	       code = krb5_auth_con_setflags(context, auth_context, acflags);
1002 	   }
1003 	   if (code) {
1004 	       major_status = GSS_S_FAILURE;
1005 	       goto fail;
1006 	   }
1007        }
1008 
1009        if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1010 	   major_status = GSS_S_FAILURE;
1011 	   goto fail;
1012        }
1013 
1014        krb5_auth_con_getlocalseqnumber(context, auth_context,
1015 		(krb5_int32 *)&seq_temp);
1016        ctx->seq_send = seq_temp & 0xffffffffL;
1017 
1018        if (cfx_generate_subkey) {
1019 	   /* Get the new acceptor subkey.  With the code above, there
1020 	      should always be one if we make it to this point.  */
1021 	   code = krb5_auth_con_getsendsubkey(context, auth_context,
1022 					      &ctx->acceptor_subkey);
1023 	   if (code != 0) {
1024 	       major_status = GSS_S_FAILURE;
1025 	       goto fail;
1026 	   }
1027 	   code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
1028 						ctx->acceptor_subkey->enctype,
1029 						&ctx->acceptor_subkey_cksumtype);
1030 	   if (code) {
1031 	       major_status = GSS_S_FAILURE;
1032 	       goto fail;
1033 	   }
1034 	   ctx->have_acceptor_subkey = 1;
1035        }
1036 
1037        /* the reply token hasn't been sent yet, but that's ok. */
1038        ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1039        ctx->established = 1;
1040 
1041        token.length = g_token_size(mech_used, ap_rep.length);
1042 
1043        if ((token.value = (unsigned char *) xmalloc(token.length))
1044 	   == NULL) {
1045 	   major_status = GSS_S_FAILURE;
1046 	   code = ENOMEM;
1047 	   goto fail;
1048        }
1049        ptr3 = token.value;
1050        g_make_token_header(mech_used, ap_rep.length,
1051 			   &ptr3, KG_TOK_CTX_AP_REP);
1052 
1053        TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1054 
1055        ctx->established = 1;
1056 
1057    } else {
1058        token.length = 0;
1059        token.value = NULL;
1060        ctx->seq_send = ctx->seq_recv;
1061 
1062        ctx->established = 1;
1063    }
1064 
1065    /* set the return arguments */
1066 
1067    if (src_name) {
1068        if ((code = krb5_copy_principal(context, ctx->there, &name))) {
1069 	   major_status = GSS_S_FAILURE;
1070 	   goto fail;
1071        }
1072        /* intern the src_name */
1073        if (! kg_save_name((gss_name_t) name)) {
1074 	   code = G_VALIDATE_FAILED;
1075 	   major_status = GSS_S_FAILURE;
1076 	   goto fail;
1077        }
1078    }
1079 
1080    if (mech_type)
1081       *mech_type = (gss_OID) mech_used;
1082 
1083    if (time_rec)
1084       *time_rec = ctx->endtime - now;
1085 
1086    if (ret_flags)
1087       *ret_flags = ctx->gss_flags;
1088 
1089    *context_handle = (gss_ctx_id_t)ctx;
1090    *output_token = token;
1091 
1092    if (src_name)
1093       *src_name = (gss_name_t) name;
1094 
1095    if (delegated_cred_handle && deleg_cred) {
1096        if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1097            /* Solaris Kerberos */
1098 	   KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1099 		      "kg_save_cred_id() error");
1100 	   major_status = GSS_S_FAILURE;
1101 	   code = (OM_uint32) G_VALIDATE_FAILED;
1102 	   goto fail;
1103        }
1104 
1105        *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1106    }
1107 
1108    /* finally! */
1109 
1110    *minor_status = 0;
1111    major_status = GSS_S_COMPLETE;
1112 
1113  fail:
1114 
1115    if (authdat)
1116        krb5_free_authenticator(context, authdat);
1117    /* The ctx structure has the handle of the auth_context */
1118    if (auth_context && !ctx) {
1119        if (cred_rcache)
1120 	   (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1121 
1122        krb5_auth_con_free(context, auth_context);
1123    }
1124    if (reqcksum.contents)
1125        xfree(reqcksum.contents);
1126    if (ap_rep.data)
1127        xfree(ap_rep.data);
1128 
1129    if (request != NULL) {
1130 	saved_ap_options = request->ap_options;
1131 	krb5_free_ap_req(context, request);
1132 	request = NULL;
1133    }
1134 
1135    if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1136 	if (!verifier_cred_handle && cred_handle) {
1137 		krb5_gss_release_cred(minor_status, &cred_handle);
1138 	}
1139 
1140 	if (ctx)
1141 	    ctx->k5_context = context;
1142 
1143         return(major_status);
1144    }
1145 
1146    /* from here on is the real "fail" code */
1147 
1148    if (ctx)
1149        (void) krb5_gss_delete_sec_context(minor_status,
1150 					  (gss_ctx_id_t *) &ctx, NULL);
1151    if (deleg_cred) { /* free memory associated with the deleg credential */
1152        if (deleg_cred->ccache)
1153 	   (void)krb5_cc_close(context, deleg_cred->ccache);
1154        if (deleg_cred->princ)
1155 	   krb5_free_principal(context, deleg_cred->princ);
1156        xfree(deleg_cred);
1157    }
1158    if (token.value)
1159        xfree(token.value);
1160    if (name) {
1161        (void) kg_delete_name((gss_name_t) name);
1162        krb5_free_principal(context, name);
1163    }
1164 
1165    *minor_status = code;
1166 
1167    if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1168 	gss_flags |= GSS_C_MUTUAL_FLAG;
1169 
1170    if (cred
1171        && ((gss_flags & GSS_C_MUTUAL_FLAG)
1172 	   || (major_status == GSS_S_CONTINUE_NEEDED))) {
1173        unsigned int tmsglen;
1174        int toktype;
1175 
1176        /*
1177 	* The client is expecting a response, so we can send an
1178 	* error token back
1179 	*/
1180 
1181        /*
1182         * Solaris Kerberos: We need to remap error conditions for buggy
1183         * Windows clients if the MS_INTEROP env var has been set.
1184         */
1185        if ((code == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
1186 	  code == KRB5KRB_AP_ERR_NOKEY || code == KRB5KRB_AP_ERR_BADKEYVER)
1187 	  && krb5_getenv("MS_INTEROP")) {
1188            code = KRB5KRB_AP_ERR_MODIFIED;
1189 	   major_status = GSS_S_CONTINUE_NEEDED;
1190        }
1191 
1192 	    /*
1193 	     * SUNW17PACresync / Solaris Kerberos
1194 	     * Set e-data to Windows constant.
1195 	     * (verified by MSFT)
1196 	     *
1197 	     * This facilitates the Windows CIFS client clock skew
1198 	     * recovery feature.
1199 	     */
1200        if (code == KRB5KRB_AP_ERR_SKEW && krb5_getenv("MS_INTEROP")) {
1201 	    char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
1202 	    int len = strlen(ms_e_data);
1203 
1204 	    krb_error_data.e_data.data = malloc(len);
1205 	    if (krb_error_data.e_data.data) {
1206 		    (void) memcpy(krb_error_data.e_data.data, ms_e_data, len);
1207 		    krb_error_data.e_data.length = len;
1208 	    }
1209 	    major_status = GSS_S_CONTINUE_NEEDED;
1210 	}
1211 
1212        code -= ERROR_TABLE_BASE_krb5;
1213        if (code < 0 || code > 128)
1214 	   code = 60 /* KRB_ERR_GENERIC */;
1215 
1216        krb_error_data.error = code;
1217        (void) krb5_us_timeofday(context, &krb_error_data.stime,
1218 				&krb_error_data.susec);
1219        krb_error_data.server = cred->princ;
1220 
1221        code = krb5_mk_error(context, &krb_error_data, &scratch);
1222        if (code)
1223            goto cleanup;
1224 
1225        tmsglen = scratch.length;
1226        toktype = KG_TOK_CTX_ERROR;
1227 
1228        token.length = g_token_size(mech_used, tmsglen);
1229        token.value = (unsigned char *) xmalloc(token.length);
1230        if (!token.value)
1231 	  goto cleanup;
1232 
1233        ptr = token.value;
1234        g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1235 
1236        TWRITE_STR(ptr, scratch.data, scratch.length);
1237        xfree(scratch.data);
1238 
1239        *output_token = token;
1240    }
1241 
1242 cleanup:
1243 
1244    /* Solaris Kerberos */
1245    if (krb_error_data.e_data.data != NULL)
1246         free(krb_error_data.e_data.data);
1247 
1248    if (!verifier_cred_handle && cred_handle) {
1249 	krb5_gss_release_cred(&t_minor_status, &cred_handle);
1250    }
1251    krb5_free_context(context);
1252 
1253    /* Solaris Kerberos */
1254    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1255 	      "major_status = %d", major_status);
1256    return (major_status);
1257 }
1258