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