xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
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 2009 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    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
324    if (code) {
325        *minor_status = code;
326        return(GSS_S_FAILURE);
327    }
328 
329    code = krb5_gss_init_context(&context);
330    if (code) {
331        *minor_status = code;
332        return GSS_S_FAILURE;
333    }
334 
335    /* set up returns to be freeable */
336 
337    if (src_name)
338       *src_name = (gss_name_t) NULL;
339    output_token->length = 0;
340    output_token->value = NULL;
341    token.value = 0;
342    reqcksum.contents = 0;
343    ap_req.data = 0;
344    ap_rep.data = 0;
345 
346    if (mech_type)
347       *mech_type = GSS_C_NULL_OID;
348    /* initialize the delegated cred handle to NO_CREDENTIAL for now */
349    if (delegated_cred_handle)
350       *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
351 
352    /*
353     * Context handle must be unspecified.  Actually, it must be
354     * non-established, but currently, accept_sec_context never returns
355     * a non-established context handle.
356     */
357    /*SUPPRESS 29*/
358    if (*context_handle != GSS_C_NO_CONTEXT) {
359       *minor_status = 0;
360 
361        /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
362 	* for this error.  This conflicts somewhat with RFC2743 which states
363 	* GSS_S_NO_CONTEXT should be returned only for sucessor calls following
364 	* GSS_S_CONTINUE_NEEDED status returns.  Note the MIT code doesn't
365 	* return GSS_S_NO_CONTEXT at all.
366 	*/
367 
368       major_status = GSS_S_NO_CONTEXT;
369       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
370 	      "error GSS_S_NO_CONTEXT");
371       goto cleanup;
372    }
373 
374    /* verify the token's integrity, and leave the token in ap_req.
375       figure out which mech oid was used, and save it */
376 
377    ptr = (unsigned char *) input_token->value;
378 
379    if (!(code = g_verify_token_header(gss_mech_krb5,
380 				      (uint32_t *)&(ap_req.length),
381 				      &ptr, KG_TOK_CTX_AP_REQ,
382 				      input_token->length, 1))) {
383        mech_used = gss_mech_krb5;
384    } else if ((code == G_WRONG_MECH) &&
385 		!(code = g_verify_token_header(gss_mech_krb5_wrong,
386 						(uint32_t *)&(ap_req.length),
387 						&ptr, KG_TOK_CTX_AP_REQ,
388 						input_token->length, 1))) {
389 	mech_used = gss_mech_krb5_wrong;
390    } else if ((code == G_WRONG_MECH) &&
391 	      !(code = g_verify_token_header(gss_mech_krb5_old,
392 					     (uint32_t *)&(ap_req.length),
393 					     &ptr, KG_TOK_CTX_AP_REQ,
394 					     input_token->length, 1))) {
395        /*
396 	* Previous versions of this library used the old mech_id
397 	* and some broken behavior (wrong IV on checksum
398 	* encryption).  We support the old mech_id for
399 	* compatibility, and use it to decide when to use the
400 	* old behavior.
401 	*/
402        mech_used = gss_mech_krb5_old;
403   } else if (code == G_WRONG_TOKID) {
404 	major_status = GSS_S_CONTINUE_NEEDED;
405         code = KRB5KRB_AP_ERR_MSG_TYPE;
406         mech_used = gss_mech_krb5;
407         goto fail;
408    } else if (code == G_BAD_TOK_HEADER) {
409 	/* DCE style not encapsulated */
410         ap_req.length = input_token->length;
411         ap_req.data = input_token->value;
412         mech_used = gss_mech_krb5;
413         no_encap = 1;
414    } else {
415 	major_status = GSS_S_DEFECTIVE_TOKEN;
416         goto fail;
417    }
418 
419    sptr = (char *) ptr;
420    TREAD_STR(sptr, ap_req.data, ap_req.length);
421 
422    /*
423     * Solaris Kerberos:
424     *  We need to decode the request now so that we can get the
425     *  service principal in order to try and acquire a cred for it.
426     *  below in the "handle default cred handle" code block.
427     */
428    if (!krb5_is_ap_req(&ap_req)) {
429        code = KRB5KRB_AP_ERR_MSG_TYPE;
430        goto fail;
431    }
432    /* decode the AP-REQ into request */
433    if ((code = decode_krb5_ap_req(&ap_req, &request))) {
434        if (code == KRB5_BADMSGTYPE)
435            code = KRB5KRB_AP_ERR_BADVERSION;
436        goto fail;
437    }
438 
439    /* handle default cred handle */
440    /*
441     * Solaris Kerberos:
442     * If there is no princ associated with the cred then treat it the
443     * the same as GSS_C_NO_CREDENTIAL.
444     */
445    if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
446     ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
447        /* Note that we try to acquire a cred for the service principal
448 	* named in the AP-REQ. This allows us to implement option (ii)
449 	* of the recommended behaviour for GSS_Accept_sec_context() as
450 	* described in section 1.1.1.3 of RFC2743.
451 
452 	* This is far more useful that option (i), for which we would
453 	* acquire a cred for GSS_C_NO_NAME.
454 	*/
455        /* copy the princ from the ap-req or we'll lose it when we free
456 	  the ap-req */
457        krb5_principal princ;
458        if ((code = krb5_copy_principal(context, request->ticket->server,
459 				       &princ))) {
460            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
461 	            "krb5_copy_principal() error code %d", code);
462 	   major_status = GSS_S_FAILURE;
463 	   goto fail;
464        }
465        /* intern the acceptor name */
466        if (! kg_save_name((gss_name_t) princ)) {
467 	   code = G_VALIDATE_FAILED;
468 	   major_status = GSS_S_FAILURE;
469 	   goto fail;
470        }
471        major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
472 					    (gss_name_t) princ,
473 					    GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
474 					    GSS_C_ACCEPT, &cred_handle,
475 					    NULL, NULL);
476 
477        if (major_status != GSS_S_COMPLETE){
478 
479 	   /* Solaris kerberos: RFC2743 indicate this should be returned if we
480 	    * can't aquire a default cred.
481 	    */
482 	   KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
483 		  "krb5_gss_acquire_cred() error"
484 		   "orig major_status = %d, now = GSS_S_NO_CRED\n",
485 		   major_status);
486 
487 	   major_status = GSS_S_NO_CRED;
488 	   goto fail;
489        }
490 
491    } else {
492        cred_handle = verifier_cred_handle;
493    }
494 
495    major_status = krb5_gss_validate_cred((OM_uint32*) &code,
496 						 cred_handle);
497 
498    if (GSS_ERROR(major_status)){
499 
500        /* Solaris kerberos: RFC2743 indicate GSS_S_NO_CRED should be returned if
501 	* the supplied cred isn't valid.
502 	*/
503 
504        KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
505 	      "krb5_gss_validate_cred() error"
506 	       "orig major_status = %d, now = GSS_S_NO_CRED\n",
507 	       major_status);
508 
509        major_status = GSS_S_NO_CRED;
510        goto fail;
511    }
512 
513    cred = (krb5_gss_cred_id_t) cred_handle;
514 
515    /* make sure the supplied credentials are valid for accept */
516 
517    if ((cred->usage != GSS_C_ACCEPT) &&
518        (cred->usage != GSS_C_BOTH)) {
519        code = 0;
520       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
521 	      "error GSS_S_NO_CONTEXT");
522        major_status = GSS_S_NO_CRED;
523        goto fail;
524    }
525 
526    /* construct the sender_addr */
527 
528    if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
529        (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
530        /* XXX is this right? */
531        addr.addrtype = ADDRTYPE_INET;
532        addr.length = input_chan_bindings->initiator_address.length;
533        addr.contents = input_chan_bindings->initiator_address.value;
534 
535        paddr = &addr;
536    } else {
537        paddr = NULL;
538    }
539 
540    /* verify the AP_REQ message - setup the auth_context and rcache */
541 
542    if ((code = krb5_auth_con_init(context, &auth_context))) {
543        major_status = GSS_S_FAILURE;
544        /* Solaris Kerberos */
545        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
546 	      "krb5_auth_con_init() error code %d", code);
547        goto fail;
548    }
549 
550    (void) krb5_auth_con_setflags(context, auth_context,
551                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);
552 
553    if (cred->rcache) {
554        cred_rcache = 1;
555        if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
556 	   major_status = GSS_S_FAILURE;
557            /* Solaris Kerberos */
558 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
559 		    "krb5_auth_con_setrcache() error code %d", code);
560 	   goto fail;
561        }
562    }
563    if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
564        major_status = GSS_S_FAILURE;
565        /* Solaris Kerberos */
566        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
567 	      "krb5_auth_con_setaddrs() error code %d", code);
568        goto fail;
569    }
570 
571    if ((code = krb5_rd_req_decoded(context, &auth_context, request,
572 			   cred->princ, cred->keytab, NULL, &ticket))) {
573       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
574 	      "krb5_rd_req() error code %d", code);
575        if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) {
576            major_status = GSS_S_DEFECTIVE_CREDENTIAL;
577 	   code = KRB5KRB_AP_ERR_NOKEY;
578        }
579        else if (code == KRB5KRB_AP_WRONG_PRINC) {
580            major_status = GSS_S_NO_CRED;
581 	   code = KRB5KRB_AP_ERR_NOT_US;
582        }
583        else if (code == KRB5KRB_AP_ERR_REPEAT)
584            major_status = GSS_S_DUPLICATE_TOKEN;
585        else
586            major_status = GSS_S_FAILURE;
587        goto fail;
588    }
589    krb5_auth_con_setflags(context, auth_context,
590 			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
591 
592    krb5_auth_con_getauthenticator(context, auth_context, &authdat);
593 
594 #if 0
595    /* make sure the necessary parts of the authdat are present */
596 
597    if ((authdat->authenticator->subkey == NULL) ||
598        (authdat->ticket->enc_part2 == NULL)) {
599 	   code = KG_NO_SUBKEY;
600 	   major_status = GSS_S_FAILURE;
601 	   goto fail;
602    }
603 #endif
604 
605    {
606        /* gss krb5 v1 */
607 
608        /* stash this now, for later. */
609        code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
610        if (code) {
611 	   /* Solaris Kerberos */
612 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
613 		  "krb5_c_checksum_length() error code %d", code);
614 	   major_status = GSS_S_FAILURE;
615 	   goto fail;
616        }
617 
618        /* verify that the checksum is correct */
619 
620        /*
621 	 The checksum may be either exactly 24 bytes, in which case
622 	 no options are specified, or greater than 24 bytes, in which case
623 	 one or more options are specified. Currently, the only valid
624 	 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
625        */
626 
627        if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
628 	   (authdat->checksum->length < 24)) {
629 	   code = 0;
630 	   major_status = GSS_S_BAD_BINDINGS;
631 	   goto fail;
632        }
633 
634        /*
635 	 "Be liberal in what you accept, and
636 	 conservative in what you send"
637 	 -- rfc1123
638 
639 	 This code will let this acceptor interoperate with an initiator
640 	 using little-endian or big-endian integer encoding.
641        */
642 
643        ptr = (unsigned char *) authdat->checksum->contents;
644        bigend = 0;
645 
646        TREAD_INT(ptr, tmp, bigend);
647 
648        if (tmp != md5len) {
649 	   ptr = (unsigned char *) authdat->checksum->contents;
650 	   bigend = 1;
651 
652 	   TREAD_INT(ptr, tmp, bigend);
653 
654 	   if (tmp != md5len) {
655 	       code = KG_BAD_LENGTH;
656 	       major_status = GSS_S_FAILURE;
657 	       goto fail;
658 	   }
659        }
660 
661        /* at this point, bigend is set according to the initiator's
662 	  byte order */
663 
664 
665        /*
666           The following section of code attempts to implement the
667           optional channel binding facility as described in RFC2743.
668 
669           Since this facility is optional channel binding may or may
670           not have been provided by either the client or the server.
671 
672           If the server has specified input_chan_bindings equal to
673           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
674           the server does provide channel bindings then we compute
675           a checksum and compare against those provided by the
676           client.  If the check fails we test the clients checksum
677           to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
678           If either test succeeds we continue without error.
679         */
680        if ((code = kg_checksum_channel_bindings(context,
681 						input_chan_bindings,
682 						&reqcksum, bigend))) {
683 	   /* Solaris Kerberos */
684 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
685 		  "kg_checksum_channel_bindings() error code %d", code);
686 	 major_status = GSS_S_BAD_BINDINGS;
687 	 goto fail;
688        }
689 
690        TREAD_STR(ptr, ptr2, reqcksum.length);
691 
692        if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
693            if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
694                xfree(reqcksum.contents);
695                reqcksum.contents = 0;
696 		if ((code = kg_checksum_channel_bindings(context,
697                                                   GSS_C_NO_CHANNEL_BINDINGS,
698                                                   &reqcksum, bigend))) {
699                    major_status = GSS_S_BAD_BINDINGS;
700                    goto fail;
701 		}
702                if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
703                    code = 0;
704                    major_status = GSS_S_BAD_BINDINGS;
705                    goto fail;
706 		}
707            }
708 
709        }
710 
711        TREAD_INT(ptr, gss_flags, bigend);
712 
713        /* if the checksum length > 24, there are options to process */
714 
715        if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
716 
717 	   i = authdat->checksum->length - 24;
718 
719 	   if (i >= 4) {
720 
721 	       TREAD_INT16(ptr, option_id, bigend);
722 
723 	       TREAD_INT16(ptr, option.length, bigend);
724 
725 	       i -= 4;
726 
727 	       if (i < option.length || option.length < 0) {
728 		   code = KG_BAD_LENGTH;
729 		   major_status = GSS_S_FAILURE;
730 		   goto fail;
731 	       }
732 
733 	       /* have to use ptr2, since option.data is wrong type and
734 		  macro uses ptr as both lvalue and rvalue */
735 
736 	       TREAD_STR(ptr, ptr2, option.length);
737 	       option.data = (char *) ptr2;
738 
739 	       i -= option.length;
740 
741 	       if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
742 		   major_status = GSS_S_FAILURE;
743 		   goto fail;
744 	       }
745 
746 		   /* store the delegated credential */
747 
748 		   code = rd_and_store_for_creds(context, auth_context, &option,
749 						 (delegated_cred_handle) ?
750 						 &deleg_cred : NULL);
751 		   if (code) {
752 		       major_status = GSS_S_FAILURE;
753 		       goto fail;
754 		   }
755 
756 	   } /* if i >= 4 */
757 	   /* ignore any additional trailing data, for now */
758 #ifdef CFX_EXERCISE
759 	   {
760 	       FILE *f = fopen("/tmp/gsslog", "a");
761 	       if (f) {
762 		   fprintf(f,
763 			   "initial context token with delegation, %d extra bytes\n",
764 			   i);
765 		   fclose(f);
766 	       }
767 	   }
768 #endif
769        } else {
770 #ifdef CFX_EXERCISE
771 	   {
772 	       FILE *f = fopen("/tmp/gsslog", "a");
773 	       if (f) {
774 		   if (gss_flags & GSS_C_DELEG_FLAG)
775 		       fprintf(f,
776 			       "initial context token, delegation flag but too small\n");
777 		   else
778 		       /* no deleg flag, length might still be too big */
779 		       fprintf(f,
780 			       "initial context token, %d extra bytes\n",
781 			       authdat->checksum->length - 24);
782 		   fclose(f);
783 	       }
784 	   }
785 #endif
786        }
787    }
788 
789    /* create the ctx struct and start filling it in */
790 
791    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
792        == NULL) {
793        code = ENOMEM;
794        major_status = GSS_S_FAILURE;
795        goto fail;
796    }
797 
798    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
799    ctx->mech_used = (gss_OID) mech_used;
800    ctx->auth_context = auth_context;
801    ctx->initiate = 0;
802    ctx->gss_flags = (GSS_C_TRANS_FLAG |
803                     ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
804                             GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
805                             GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
806    ctx->seed_init = 0;
807    ctx->big_endian = bigend;
808    ctx->cred_rcache = cred_rcache;
809 
810    /* Intern the ctx pointer so that delete_sec_context works */
811    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
812        xfree(ctx);
813        ctx = 0;
814 
815 	/* Solaris Kerberos */
816        KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
817 	      "kg_save_ctx_id() error");
818        code = G_VALIDATE_FAILED;
819        major_status = GSS_S_FAILURE;
820        goto fail;
821    }
822 
823    /* XXX move this into gss_name_t */
824    if ((code = krb5_merge_authdata(context,
825 				ticket->enc_part2->authorization_data,
826 				authdat->authorization_data,
827 				&ctx->authdata))) {
828 	major_status = GSS_S_FAILURE;
829         goto fail;
830    }
831 
832    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
833 	/* Solaris Kerberos */
834        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
835 	      "krb5_copy_principal() error code %d", code);
836        major_status = GSS_S_FAILURE;
837        goto fail;
838    }
839 
840    if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
841 	/* Solaris Kerberos */
842        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
843 	      "krb5_copy_principal() 2 error code %d", code);
844        major_status = GSS_S_FAILURE;
845        goto fail;
846    }
847 
848    if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
849 					   &ctx->subkey))) {
850 	/* Solaris Kerberos */
851        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
852 	      "krb5_auth_con_getremotesubkey() error code %d", code);
853        major_status = GSS_S_FAILURE;
854        goto fail;
855    }
856 
857    /* use the session key if the subkey isn't present */
858 
859    if (ctx->subkey == NULL) {
860        if ((code = krb5_auth_con_getkey(context, auth_context,
861 					&ctx->subkey))) {
862 	/* Solaris Kerberos */
863 	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
864 		      "krb5_auth_con_getkey() error code %d", code);
865            *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
866 	   major_status = GSS_S_FAILURE;
867 	   goto fail;
868        }
869    }
870 
871    if (ctx->subkey == NULL) {
872        /* this isn't a very good error, but it's not clear to me this
873 	  can actually happen */
874        major_status = GSS_S_FAILURE;
875        code = KRB5KDC_ERR_NULL_KEY;
876        goto fail;
877    }
878 
879     /* Solaris Kerberos */
880    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
881 	   "ctx->subkey->enctype=%d", ctx->subkey->enctype);
882 
883    ctx->proto = 0;
884    switch(ctx->subkey->enctype) {
885    case ENCTYPE_DES_CBC_MD5:
886    case ENCTYPE_DES_CBC_CRC:
887        ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
888        ctx->signalg = SGN_ALG_DES_MAC_MD5;
889        ctx->cksum_size = 8;
890        ctx->sealalg = SEAL_ALG_DES;
891 
892        /* fill in the encryption descriptors */
893 
894        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
895 	   major_status = GSS_S_FAILURE;
896 	   goto fail;
897        }
898 
899        for (i=0; i<ctx->enc->length; i++)
900 	   /*SUPPRESS 113*/
901 	   ctx->enc->contents[i] ^= 0xf0;
902 
903        goto copy_subkey_to_seq;
904        break;
905 
906    case ENCTYPE_DES3_CBC_SHA1:
907        ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
908        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
909        ctx->cksum_size = 20;
910        ctx->sealalg = SEAL_ALG_DES3KD;
911 
912        /* fill in the encryption descriptors */
913    copy_subkey:
914        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
915 	   major_status = GSS_S_FAILURE;
916 	   goto fail;
917        }
918    copy_subkey_to_seq:
919        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
920 	   major_status = GSS_S_FAILURE;
921 	   goto fail;
922        }
923        break;
924 
925    case ENCTYPE_ARCFOUR_HMAC:
926        ctx->signalg = SGN_ALG_HMAC_MD5 ;
927        ctx->cksum_size = 8;
928        ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
929        goto copy_subkey;
930 
931    default:
932        ctx->signalg = -1;
933        ctx->sealalg = -1;
934        ctx->proto = 1;
935        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
936 					    &ctx->cksumtype);
937        if (code)
938 	   goto fail;
939        code = krb5_c_checksum_length(context, ctx->cksumtype,
940 		(size_t *)&ctx->cksum_size);
941        if (code)
942 	   goto fail;
943        ctx->have_acceptor_subkey = 0;
944        goto copy_subkey;
945    }
946 
947     /* Solaris Kerberos */
948    KRB5_LOG1(KRB5_ERR, "accept_sec_context:  subkey enctype = %d proto = %d",
949 	ctx->subkey->enctype, ctx->proto);
950 
951    ctx->endtime = ticket->enc_part2->times.endtime;
952    ctx->krb_flags = ticket->enc_part2->flags;
953 
954    krb5_free_ticket(context, ticket); /* Done with ticket */
955 
956    {
957        krb5_ui_4 seq_temp;
958        krb5_auth_con_getremoteseqnumber(context, auth_context,
959 		(krb5_int32 *)&seq_temp);
960        ctx->seq_recv = seq_temp;
961    }
962 
963    if ((code = krb5_timeofday(context, &now))) {
964        major_status = GSS_S_FAILURE;
965        goto fail;
966    }
967 
968    if (ctx->endtime < now) {
969        code = 0;
970        major_status = GSS_S_CREDENTIALS_EXPIRED;
971        goto fail;
972    }
973 
974    g_order_init(&(ctx->seqstate), ctx->seq_recv,
975 		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
976 		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
977 
978    /* at this point, the entire context structure is filled in,
979       so it can be released.  */
980 
981    /* generate an AP_REP if necessary */
982 
983    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
984        unsigned char * ptr3;
985        krb5_ui_4 seq_temp;
986        int cfx_generate_subkey;
987 
988        if (ctx->proto == 1)
989 	   cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
990        else
991 	   cfx_generate_subkey = 0;
992 
993        if (cfx_generate_subkey) {
994 	   krb5_int32 acflags;
995 	   code = krb5_auth_con_getflags(context, auth_context, &acflags);
996 	   if (code == 0) {
997 	       acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
998 	       code = krb5_auth_con_setflags(context, auth_context, acflags);
999 	   }
1000 	   if (code) {
1001 	       major_status = GSS_S_FAILURE;
1002 	       goto fail;
1003 	   }
1004        }
1005 
1006        if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1007 	   major_status = GSS_S_FAILURE;
1008 	   goto fail;
1009        }
1010 
1011        krb5_auth_con_getlocalseqnumber(context, auth_context,
1012 		(krb5_int32 *)&seq_temp);
1013        ctx->seq_send = seq_temp & 0xffffffffL;
1014 
1015        if (cfx_generate_subkey) {
1016 	   /* Get the new acceptor subkey.  With the code above, there
1017 	      should always be one if we make it to this point.  */
1018 	   code = krb5_auth_con_getsendsubkey(context, auth_context,
1019 					      &ctx->acceptor_subkey);
1020 	   if (code != 0) {
1021 	       major_status = GSS_S_FAILURE;
1022 	       goto fail;
1023 	   }
1024 	   code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
1025 						ctx->acceptor_subkey->enctype,
1026 						&ctx->acceptor_subkey_cksumtype);
1027 	   if (code) {
1028 	       major_status = GSS_S_FAILURE;
1029 	       goto fail;
1030 	   }
1031 	   ctx->have_acceptor_subkey = 1;
1032        }
1033 
1034        /* the reply token hasn't been sent yet, but that's ok. */
1035        ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1036        ctx->established = 1;
1037 
1038        token.length = g_token_size(mech_used, ap_rep.length);
1039 
1040        if ((token.value = (unsigned char *) xmalloc(token.length))
1041 	   == NULL) {
1042 	   major_status = GSS_S_FAILURE;
1043 	   code = ENOMEM;
1044 	   goto fail;
1045        }
1046        ptr3 = token.value;
1047        g_make_token_header(mech_used, ap_rep.length,
1048 			   &ptr3, KG_TOK_CTX_AP_REP);
1049 
1050        TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1051 
1052        ctx->established = 1;
1053 
1054    } else {
1055        token.length = 0;
1056        token.value = NULL;
1057        ctx->seq_send = ctx->seq_recv;
1058 
1059        ctx->established = 1;
1060    }
1061 
1062    /* set the return arguments */
1063 
1064    if (src_name) {
1065        if ((code = krb5_copy_principal(context, ctx->there, &name))) {
1066 	   major_status = GSS_S_FAILURE;
1067 	   goto fail;
1068        }
1069        /* intern the src_name */
1070        if (! kg_save_name((gss_name_t) name)) {
1071 	   code = G_VALIDATE_FAILED;
1072 	   major_status = GSS_S_FAILURE;
1073 	   goto fail;
1074        }
1075    }
1076 
1077    if (mech_type)
1078       *mech_type = (gss_OID) mech_used;
1079 
1080    if (time_rec)
1081       *time_rec = ctx->endtime - now;
1082 
1083    if (ret_flags)
1084       *ret_flags = ctx->gss_flags;
1085 
1086    *context_handle = (gss_ctx_id_t)ctx;
1087    *output_token = token;
1088 
1089    if (src_name)
1090       *src_name = (gss_name_t) name;
1091 
1092    if (delegated_cred_handle && deleg_cred) {
1093        if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1094            /* Solaris Kerberos */
1095 	   KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1096 		      "kg_save_cred_id() error");
1097 	   major_status = GSS_S_FAILURE;
1098 	   code = (OM_uint32) G_VALIDATE_FAILED;
1099 	   goto fail;
1100        }
1101 
1102        *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1103    }
1104 
1105    /* finally! */
1106 
1107    *minor_status = 0;
1108    major_status = GSS_S_COMPLETE;
1109 
1110  fail:
1111 
1112    if (authdat)
1113        krb5_free_authenticator(context, authdat);
1114    /* The ctx structure has the handle of the auth_context */
1115    if (auth_context && !ctx) {
1116        if (cred_rcache)
1117 	   (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1118 
1119        krb5_auth_con_free(context, auth_context);
1120    }
1121    if (reqcksum.contents)
1122        xfree(reqcksum.contents);
1123    if (ap_rep.data)
1124        xfree(ap_rep.data);
1125 
1126    if (request != NULL) {
1127 	saved_ap_options = request->ap_options;
1128 	krb5_free_ap_req(context, request);
1129 	request = NULL;
1130    }
1131 
1132    if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1133 	if (!verifier_cred_handle && cred_handle) {
1134 		krb5_gss_release_cred(minor_status, &cred_handle);
1135 	}
1136 
1137 	if (ctx)
1138 	    ctx->k5_context = context;
1139 
1140         return(major_status);
1141    }
1142 
1143    /* from here on is the real "fail" code */
1144 
1145    if (ctx)
1146        (void) krb5_gss_delete_sec_context(minor_status,
1147 					  (gss_ctx_id_t *) &ctx, NULL);
1148    if (deleg_cred) { /* free memory associated with the deleg credential */
1149        if (deleg_cred->ccache)
1150 	   (void)krb5_cc_close(context, deleg_cred->ccache);
1151        if (deleg_cred->princ)
1152 	   krb5_free_principal(context, deleg_cred->princ);
1153        xfree(deleg_cred);
1154    }
1155    if (token.value)
1156        xfree(token.value);
1157    if (name) {
1158        (void) kg_delete_name((gss_name_t) name);
1159        krb5_free_principal(context, name);
1160    }
1161 
1162    *minor_status = code;
1163 
1164    if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1165 	gss_flags |= GSS_C_MUTUAL_FLAG;
1166 
1167    if (cred
1168        && ((gss_flags & GSS_C_MUTUAL_FLAG)
1169 	   || (major_status == GSS_S_CONTINUE_NEEDED))) {
1170        unsigned int tmsglen;
1171        int toktype;
1172 
1173        /*
1174 	* The client is expecting a response, so we can send an
1175 	* error token back
1176 	*/
1177        memset(&krb_error_data, 0, sizeof(krb_error_data));
1178 
1179        /*
1180         * Solaris Kerberos: We need to remap error conditions for buggy
1181         * Windows clients if the MS_INTEROP env var has been set.
1182         */
1183        if ((code == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
1184 	  code == KRB5KRB_AP_ERR_NOKEY || code == KRB5KRB_AP_ERR_BADKEYVER)
1185 	  && krb5_getenv("MS_INTEROP")) {
1186            code = KRB5KRB_AP_ERR_MODIFIED;
1187 	   major_status = GSS_S_CONTINUE_NEEDED;
1188        }
1189 
1190 	    /*
1191 	     * SUNW17PACresync / Solaris Kerberos
1192 	     * Set e-data to Windows constant.
1193 	     * (verified by MSFT)
1194 	     *
1195 	     * This facilitates the Windows CIFS client clock skew
1196 	     * recovery feature.
1197 	     */
1198        if (code == KRB5KRB_AP_ERR_SKEW && krb5_getenv("MS_INTEROP")) {
1199 	    char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
1200 	    int len = strlen(ms_e_data);
1201 
1202 	    krb_error_data.e_data.data = malloc(len);
1203 	    if (krb_error_data.e_data.data) {
1204 		    (void) memcpy(krb_error_data.e_data.data, ms_e_data, len);
1205 		    krb_error_data.e_data.length = len;
1206 	    }
1207 	    major_status = GSS_S_CONTINUE_NEEDED;
1208 	}
1209 
1210        code -= ERROR_TABLE_BASE_krb5;
1211        if (code < 0 || code > 128)
1212 	   code = 60 /* KRB_ERR_GENERIC */;
1213 
1214        krb_error_data.error = code;
1215        (void) krb5_us_timeofday(context, &krb_error_data.stime,
1216 				&krb_error_data.susec);
1217        krb_error_data.server = cred->princ;
1218 
1219        code = krb5_mk_error(context, &krb_error_data, &scratch);
1220        if (code)
1221            goto cleanup;
1222 
1223        tmsglen = scratch.length;
1224        toktype = KG_TOK_CTX_ERROR;
1225 
1226        token.length = g_token_size(mech_used, tmsglen);
1227        token.value = (unsigned char *) xmalloc(token.length);
1228        if (!token.value)
1229 	  goto cleanup;
1230 
1231        ptr = token.value;
1232        g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1233 
1234        TWRITE_STR(ptr, scratch.data, scratch.length);
1235        xfree(scratch.data);
1236 
1237        *output_token = token;
1238    }
1239 
1240 cleanup:
1241    if (!verifier_cred_handle && cred_handle) {
1242 	krb5_gss_release_cred(&t_minor_status, &cred_handle);
1243    }
1244    krb5_free_context(context);
1245 
1246    /* Solaris Kerberos */
1247    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1248 	      "major_status = %d", major_status);
1249    return (major_status);
1250 }
1251