1/*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * Copyright 2000, 2004  by the Massachusetts Institute of Technology.
6 * All Rights Reserved.
7 *
8 * Export of this software from the United States of America may
9 *   require a specific license from the United States Government.
10 *   It is the responsibility of any person or organization contemplating
11 *   export to obtain such a license before exporting.
12 *
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission.  Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * M.I.T. makes no representations about the suitability of
24 * this software for any purpose.  It is provided "as is" without express
25 * or implied warranty.
26 *
27 */
28/*
29 * Copyright 1993 by OpenVision Technologies, Inc.
30 *
31 * Permission to use, copy, modify, distribute, and sell this software
32 * and its documentation for any purpose is hereby granted without fee,
33 * provided that the above copyright notice appears in all copies and
34 * that both that copyright notice and this permission notice appear in
35 * supporting documentation, and that the name of OpenVision not be used
36 * in advertising or publicity pertaining to distribution of the software
37 * without specific, written prior permission. OpenVision makes no
38 * representations about the suitability of this software for any
39 * purpose.  It is provided "as is" without express or implied warranty.
40 *
41 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
43 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
44 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
45 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
46 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
47 * PERFORMANCE OF THIS SOFTWARE.
48 */
49
50/*
51 * Copyright (C) 1998 by the FundsXpress, INC.
52 *
53 * All rights reserved.
54 *
55 * Export of this software from the United States of America may require
56 * a specific license from the United States Government.  It is the
57 * responsibility of any person or organization contemplating export to
58 * obtain such a license before exporting.
59 *
60 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
61 * distribute this software and its documentation for any purpose and
62 * without fee is hereby granted, provided that the above copyright
63 * notice appear in all copies and that both that copyright notice and
64 * this permission notice appear in supporting documentation, and that
65 * the name of FundsXpress. not be used in advertising or publicity pertaining
66 * to distribution of the software without specific, written prior
67 * permission.  FundsXpress makes no representations about the suitability of
68 * this software for any purpose.  It is provided "as is" without express
69 * or implied warranty.
70 *
71 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
72 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
73 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
74 */
75
76#include "k5-int.h"
77#include "gssapiP_krb5.h"
78#ifdef HAVE_MEMORY_H
79#include <memory.h>
80#endif
81#include <assert.h>
82#include "auth_con.h"
83#ifdef CFX_EXERCISE
84#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
85#else
86#define CFX_ACCEPTOR_SUBKEY 1
87#endif
88#include <syslog.h>
89#include <locale.h> /* Solaris Kerberos */
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 */
96static krb5_error_code
97rd_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    */
242cleanup:
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 */
267OM_uint32
268krb5_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 client_name = NULL;
301   krb5_principal server_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   int acquire_fail = 0;
321
322   KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
323
324   /* Solaris Kerberos */
325   memset(&krb_error_data, 0, sizeof(krb_error_data));
326
327   code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
328   if (code) {
329       *minor_status = code;
330       return(GSS_S_FAILURE);
331   }
332
333   code = krb5_gss_init_context(&context);
334   if (code) {
335       *minor_status = code;
336       return GSS_S_FAILURE;
337   }
338
339   /* set up returns to be freeable */
340
341   if (src_name)
342      *src_name = (gss_name_t) NULL;
343   output_token->length = 0;
344   output_token->value = NULL;
345   token.value = 0;
346   reqcksum.contents = 0;
347   ap_req.data = 0;
348   ap_rep.data = 0;
349
350   if (mech_type)
351      *mech_type = GSS_C_NULL_OID;
352   /* initialize the delegated cred handle to NO_CREDENTIAL for now */
353   if (delegated_cred_handle)
354      *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
355
356   /*
357    * Context handle must be unspecified.  Actually, it must be
358    * non-established, but currently, accept_sec_context never returns
359    * a non-established context handle.
360    */
361   /*SUPPRESS 29*/
362   if (*context_handle != GSS_C_NO_CONTEXT) {
363      *minor_status = 0;
364
365       /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
366	* for this error.  This conflicts somewhat with RFC2743 which states
367	* GSS_S_NO_CONTEXT should be returned only for sucessor calls following
368	* GSS_S_CONTINUE_NEEDED status returns.  Note the MIT code doesn't
369	* return GSS_S_NO_CONTEXT at all.
370	*/
371
372      major_status = GSS_S_NO_CONTEXT;
373      KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
374	      "error GSS_S_NO_CONTEXT");
375      goto cleanup;
376   }
377
378   /* verify the token's integrity, and leave the token in ap_req.
379      figure out which mech oid was used, and save it */
380
381   ptr = (unsigned char *) input_token->value;
382
383   if (!(code = g_verify_token_header(gss_mech_krb5,
384				      (uint32_t *)&(ap_req.length),
385				      &ptr, KG_TOK_CTX_AP_REQ,
386				      input_token->length, 1))) {
387       mech_used = gss_mech_krb5;
388   } else if ((code == G_WRONG_MECH) &&
389		!(code = g_verify_token_header(gss_mech_krb5_wrong,
390						(uint32_t *)&(ap_req.length),
391						&ptr, KG_TOK_CTX_AP_REQ,
392						input_token->length, 1))) {
393	mech_used = gss_mech_krb5_wrong;
394   } else if ((code == G_WRONG_MECH) &&
395	      !(code = g_verify_token_header(gss_mech_krb5_old,
396					     (uint32_t *)&(ap_req.length),
397					     &ptr, KG_TOK_CTX_AP_REQ,
398					     input_token->length, 1))) {
399       /*
400	* Previous versions of this library used the old mech_id
401	* and some broken behavior (wrong IV on checksum
402	* encryption).  We support the old mech_id for
403	* compatibility, and use it to decide when to use the
404	* old behavior.
405	*/
406       mech_used = gss_mech_krb5_old;
407  } else if (code == G_WRONG_TOKID) {
408	major_status = GSS_S_CONTINUE_NEEDED;
409        code = KRB5KRB_AP_ERR_MSG_TYPE;
410        mech_used = gss_mech_krb5;
411        goto fail;
412   } else if (code == G_BAD_TOK_HEADER) {
413	/* DCE style not encapsulated */
414        ap_req.length = input_token->length;
415        ap_req.data = input_token->value;
416        mech_used = gss_mech_krb5;
417        no_encap = 1;
418   } else {
419	major_status = GSS_S_DEFECTIVE_TOKEN;
420        goto fail;
421   }
422
423   sptr = (char *) ptr;
424   TREAD_STR(sptr, ap_req.data, ap_req.length);
425
426   /*
427    * Solaris Kerberos:
428    *  We need to decode the request now so that we can get the
429    *  service principal in order to try and acquire a cred for it.
430    *  below in the "handle default cred handle" code block.
431    */
432   if (!krb5_is_ap_req(&ap_req)) {
433       code = KRB5KRB_AP_ERR_MSG_TYPE;
434       goto fail;
435   }
436   /* decode the AP-REQ into request */
437   if ((code = decode_krb5_ap_req(&ap_req, &request))) {
438       if (code == KRB5_BADMSGTYPE)
439           code = KRB5KRB_AP_ERR_BADVERSION;
440       goto fail;
441   }
442
443   /* handle default cred handle */
444   /*
445    * Solaris Kerberos:
446    * If there is no princ associated with the cred then treat it the
447    * the same as GSS_C_NO_CREDENTIAL.
448    */
449   if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
450    ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
451       /* Note that we try to acquire a cred for the service principal
452	* named in the AP-REQ. This allows us to implement option (ii)
453	* of the recommended behaviour for GSS_Accept_sec_context() as
454	* described in section 1.1.1.3 of RFC2743.
455
456	* This is far more useful that option (i), for which we would
457	* acquire a cred for GSS_C_NO_NAME.
458	*/
459       /* copy the princ from the ap-req or we'll lose it when we free
460	  the ap-req */
461       krb5_principal princ;
462       if ((code = krb5_copy_principal(context, request->ticket->server,
463				       &princ))) {
464           KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
465	            "krb5_copy_principal() error code %d", code);
466	   major_status = GSS_S_FAILURE;
467	   goto fail;
468       }
469       /* intern the acceptor name */
470       if (! kg_save_name((gss_name_t) princ)) {
471	   code = G_VALIDATE_FAILED;
472	   major_status = GSS_S_FAILURE;
473	   goto fail;
474       }
475       major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
476					    (gss_name_t) princ,
477					    GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
478					    GSS_C_ACCEPT, &cred_handle,
479					    NULL, NULL);
480
481       if (major_status != GSS_S_COMPLETE){
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	   acquire_fail = 1;
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       save_error_info((OM_uint32)code, context);
548       /* Solaris Kerberos */
549       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
550	      "krb5_auth_con_init() error code %d", code);
551       goto fail;
552   }
553
554   (void) krb5_auth_con_setflags(context, auth_context,
555                          KRB5_AUTH_CONTEXT_DO_SEQUENCE);
556
557   if (cred->rcache) {
558       cred_rcache = 1;
559       if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
560	   major_status = GSS_S_FAILURE;
561           /* Solaris Kerberos */
562	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
563		    "krb5_auth_con_setrcache() error code %d", code);
564	   goto fail;
565       }
566   }
567   if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
568       major_status = GSS_S_FAILURE;
569       /* Solaris Kerberos */
570       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
571	      "krb5_auth_con_setaddrs() error code %d", code);
572       goto fail;
573   }
574
575   if ((code = krb5_rd_req_decoded(context, &auth_context, request,
576			   cred->princ, cred->keytab, NULL, &ticket))) {
577       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
578	      "krb5_rd_req() error code %d", code);
579       if (code == KRB5_KT_KVNONOTFOUND) {
580	   char *s_name;
581	   if (krb5_unparse_name(context, cred->princ, &s_name) == 0) {
582	       krb5_set_error_message(context, KRB5KRB_AP_ERR_BADKEYVER,
583				    dgettext(TEXT_DOMAIN,
584					    "Key version %d is not available for principal %s"),
585				    request->ticket->enc_part.kvno,
586				    s_name);
587	       krb5_free_unparsed_name(context, s_name);
588	   }
589	   major_status = GSS_S_DEFECTIVE_CREDENTIAL;
590	   code = KRB5KRB_AP_ERR_BADKEYVER;
591       } else if (code == KRB5_KT_NOTFOUND) {
592	   char *s_name;
593	   if (krb5_unparse_name(context, cred->princ, &s_name) == 0) {
594	       krb5_set_error_message(context, KRB5KRB_AP_ERR_NOKEY,
595				    dgettext(TEXT_DOMAIN,
596					    "Service key %s not available"),
597				    s_name);
598	       krb5_free_unparsed_name(context, s_name);
599	   }
600           major_status = GSS_S_DEFECTIVE_CREDENTIAL;
601	   code = KRB5KRB_AP_ERR_NOKEY;
602       }
603       else if (code == KRB5KRB_AP_WRONG_PRINC) {
604           major_status = GSS_S_NO_CRED;
605	   code = KRB5KRB_AP_ERR_NOT_US;
606       }
607       else if (code == KRB5KRB_AP_ERR_REPEAT)
608           major_status = GSS_S_DUPLICATE_TOKEN;
609       else
610           major_status = GSS_S_FAILURE;
611       goto fail;
612   }
613   krb5_auth_con_setflags(context, auth_context,
614			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
615
616   /* Solaris Kerberos */
617   code = krb5_auth_con_getauthenticator(context, auth_context, &authdat);
618   if (code) {
619	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
620		  "krb5_auth_con_getauthenticator() error code %d", code);
621	   major_status = GSS_S_FAILURE;
622	   goto fail;
623   }
624
625#if 0
626   /* make sure the necessary parts of the authdat are present */
627
628   if ((authdat->authenticator->subkey == NULL) ||
629       (authdat->ticket->enc_part2 == NULL)) {
630	   code = KG_NO_SUBKEY;
631	   major_status = GSS_S_FAILURE;
632	   goto fail;
633   }
634#endif
635
636   {
637       /* gss krb5 v1 */
638
639       /* stash this now, for later. */
640       code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
641       if (code) {
642	   /* Solaris Kerberos */
643	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
644		  "krb5_c_checksum_length() error code %d", code);
645	   major_status = GSS_S_FAILURE;
646	   goto fail;
647       }
648
649       /* verify that the checksum is correct */
650       if (authdat->checksum == NULL) {
651          /* missing checksum counts as "inappropriate type" */
652          code = KRB5KRB_AP_ERR_INAPP_CKSUM;
653          major_status = GSS_S_FAILURE;
654          goto fail;
655       }
656
657       /*
658	 The checksum may be either exactly 24 bytes, in which case
659	 no options are specified, or greater than 24 bytes, in which case
660	 one or more options are specified. Currently, the only valid
661	 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
662       */
663
664       if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
665	   (authdat->checksum->length < 24)) {
666	   code = 0;
667	   major_status = GSS_S_BAD_BINDINGS;
668	   goto fail;
669       }
670
671       /*
672	 "Be liberal in what you accept, and
673	 conservative in what you send"
674	 -- rfc1123
675
676	 This code will let this acceptor interoperate with an initiator
677	 using little-endian or big-endian integer encoding.
678       */
679
680       ptr = (unsigned char *) authdat->checksum->contents;
681       bigend = 0;
682
683       TREAD_INT(ptr, tmp, bigend);
684
685       if (tmp != md5len) {
686	   ptr = (unsigned char *) authdat->checksum->contents;
687	   bigend = 1;
688
689	   TREAD_INT(ptr, tmp, bigend);
690
691	   if (tmp != md5len) {
692	       code = KG_BAD_LENGTH;
693	       major_status = GSS_S_FAILURE;
694	       goto fail;
695	   }
696       }
697
698       /* at this point, bigend is set according to the initiator's
699	  byte order */
700
701
702       /*
703          The following section of code attempts to implement the
704          optional channel binding facility as described in RFC2743.
705
706          Since this facility is optional channel binding may or may
707          not have been provided by either the client or the server.
708
709          If the server has specified input_chan_bindings equal to
710          GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
711          the server does provide channel bindings then we compute
712          a checksum and compare against those provided by the
713          client.  If the check fails we test the clients checksum
714          to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
715          If either test succeeds we continue without error.
716        */
717       if ((code = kg_checksum_channel_bindings(context,
718						input_chan_bindings,
719						&reqcksum, bigend))) {
720	   /* Solaris Kerberos */
721	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
722		  "kg_checksum_channel_bindings() error code %d", code);
723	 major_status = GSS_S_BAD_BINDINGS;
724	 goto fail;
725       }
726
727       TREAD_STR(ptr, ptr2, reqcksum.length);
728
729       if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
730           if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
731               xfree(reqcksum.contents);
732               reqcksum.contents = 0;
733		if ((code = kg_checksum_channel_bindings(context,
734                                                  GSS_C_NO_CHANNEL_BINDINGS,
735                                                  &reqcksum, bigend))) {
736                   major_status = GSS_S_BAD_BINDINGS;
737                   goto fail;
738		}
739               if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
740                   code = 0;
741                   major_status = GSS_S_BAD_BINDINGS;
742                   goto fail;
743		}
744           }
745
746       }
747
748       TREAD_INT(ptr, gss_flags, bigend);
749
750       /* if the checksum length > 24, there are options to process */
751
752       if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
753
754	   i = authdat->checksum->length - 24;
755
756	   if (i >= 4) {
757
758	       TREAD_INT16(ptr, option_id, bigend);
759
760	       TREAD_INT16(ptr, option.length, bigend);
761
762	       i -= 4;
763
764	       if (i < option.length || option.length < 0) {
765		   code = KG_BAD_LENGTH;
766		   major_status = GSS_S_FAILURE;
767		   goto fail;
768	       }
769
770	       /* have to use ptr2, since option.data is wrong type and
771		  macro uses ptr as both lvalue and rvalue */
772
773	       TREAD_STR(ptr, ptr2, option.length);
774	       option.data = (char *) ptr2;
775
776	       i -= option.length;
777
778	       if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
779		   major_status = GSS_S_FAILURE;
780		   goto fail;
781	       }
782
783		   /* store the delegated credential */
784
785		   code = rd_and_store_for_creds(context, auth_context, &option,
786						 (delegated_cred_handle) ?
787						 &deleg_cred : NULL);
788		   if (code) {
789		       major_status = GSS_S_FAILURE;
790		       goto fail;
791		   }
792
793	   } /* if i >= 4 */
794	   /* ignore any additional trailing data, for now */
795#ifdef CFX_EXERCISE
796	   {
797	       FILE *f = fopen("/tmp/gsslog", "a");
798	       if (f) {
799		   fprintf(f,
800			   "initial context token with delegation, %d extra bytes\n",
801			   i);
802		   fclose(f);
803	       }
804	   }
805#endif
806       } else {
807#ifdef CFX_EXERCISE
808	   {
809	       FILE *f = fopen("/tmp/gsslog", "a");
810	       if (f) {
811		   if (gss_flags & GSS_C_DELEG_FLAG)
812		       fprintf(f,
813			       "initial context token, delegation flag but too small\n");
814		   else
815		       /* no deleg flag, length might still be too big */
816		       fprintf(f,
817			       "initial context token, %d extra bytes\n",
818			       authdat->checksum->length - 24);
819		   fclose(f);
820	       }
821	   }
822#endif
823       }
824   }
825
826   /* create the ctx struct and start filling it in */
827
828   if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
829       == NULL) {
830       code = ENOMEM;
831       major_status = GSS_S_FAILURE;
832       goto fail;
833   }
834
835   memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
836   ctx->mech_used = (gss_OID) mech_used;
837   ctx->auth_context = auth_context;
838   ctx->initiate = 0;
839   ctx->gss_flags = (GSS_C_TRANS_FLAG |
840                    ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
841                            GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
842                            GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
843   ctx->seed_init = 0;
844   ctx->big_endian = bigend;
845   ctx->cred_rcache = cred_rcache;
846
847   /* Intern the ctx pointer so that delete_sec_context works */
848   if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
849       xfree(ctx);
850       ctx = 0;
851
852	/* Solaris Kerberos */
853       KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
854	      "kg_save_ctx_id() error");
855       code = G_VALIDATE_FAILED;
856       major_status = GSS_S_FAILURE;
857       goto fail;
858   }
859
860   /* XXX move this into gss_name_t */
861   if ((code = krb5_merge_authdata(context,
862				ticket->enc_part2->authorization_data,
863				authdat->authorization_data,
864				&ctx->authdata))) {
865	major_status = GSS_S_FAILURE;
866        goto fail;
867   }
868
869   if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
870	/* Solaris Kerberos */
871       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
872	      "krb5_copy_principal() error code %d", code);
873       major_status = GSS_S_FAILURE;
874       goto fail;
875   }
876
877   if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
878	/* Solaris Kerberos */
879       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
880	      "krb5_copy_principal() 2 error code %d", code);
881       major_status = GSS_S_FAILURE;
882       goto fail;
883   }
884
885   if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
886					   &ctx->subkey))) {
887	/* Solaris Kerberos */
888       KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
889	      "krb5_auth_con_getremotesubkey() error code %d", code);
890       major_status = GSS_S_FAILURE;
891       goto fail;
892   }
893
894   /* use the session key if the subkey isn't present */
895
896   if (ctx->subkey == NULL) {
897       if ((code = krb5_auth_con_getkey(context, auth_context,
898					&ctx->subkey))) {
899	/* Solaris Kerberos */
900	   KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
901		      "krb5_auth_con_getkey() error code %d", code);
902           *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
903	   major_status = GSS_S_FAILURE;
904	   goto fail;
905       }
906   }
907
908   if (ctx->subkey == NULL) {
909       /* this isn't a very good error, but it's not clear to me this
910	  can actually happen */
911       major_status = GSS_S_FAILURE;
912       code = KRB5KDC_ERR_NULL_KEY;
913       goto fail;
914   }
915
916    /* Solaris Kerberos */
917   KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
918	   "ctx->subkey->enctype=%d", ctx->subkey->enctype);
919
920   ctx->proto = 0;
921   switch(ctx->subkey->enctype) {
922   case ENCTYPE_DES_CBC_MD5:
923   case ENCTYPE_DES_CBC_CRC:
924       ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
925       ctx->signalg = SGN_ALG_DES_MAC_MD5;
926       ctx->cksum_size = 8;
927       ctx->sealalg = SEAL_ALG_DES;
928
929       /* fill in the encryption descriptors */
930
931       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
932	   major_status = GSS_S_FAILURE;
933	   goto fail;
934       }
935
936       for (i=0; i<ctx->enc->length; i++)
937	   /*SUPPRESS 113*/
938	   ctx->enc->contents[i] ^= 0xf0;
939
940       goto copy_subkey_to_seq;
941       break;
942
943   case ENCTYPE_DES3_CBC_SHA1:
944       ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
945       ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
946       ctx->cksum_size = 20;
947       ctx->sealalg = SEAL_ALG_DES3KD;
948
949       /* fill in the encryption descriptors */
950   copy_subkey:
951       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
952	   major_status = GSS_S_FAILURE;
953	   goto fail;
954       }
955   copy_subkey_to_seq:
956       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
957	   major_status = GSS_S_FAILURE;
958	   goto fail;
959       }
960       break;
961
962   case ENCTYPE_ARCFOUR_HMAC:
963       ctx->signalg = SGN_ALG_HMAC_MD5 ;
964       ctx->cksum_size = 8;
965       ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
966       goto copy_subkey;
967
968   default:
969       ctx->signalg = -1;
970       ctx->sealalg = -1;
971       ctx->proto = 1;
972       code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
973					    &ctx->cksumtype);
974       if (code)
975	   goto fail;
976       code = krb5_c_checksum_length(context, ctx->cksumtype,
977		(size_t *)&ctx->cksum_size);
978       if (code)
979	   goto fail;
980       ctx->have_acceptor_subkey = 0;
981       goto copy_subkey;
982   }
983
984    /* Solaris Kerberos */
985   KRB5_LOG1(KRB5_ERR, "accept_sec_context:  subkey enctype = %d proto = %d",
986	ctx->subkey->enctype, ctx->proto);
987
988   ctx->endtime = ticket->enc_part2->times.endtime;
989   ctx->krb_flags = ticket->enc_part2->flags;
990
991   krb5_free_ticket(context, ticket); /* Done with ticket */
992
993   {
994       krb5_ui_4 seq_temp;
995       krb5_auth_con_getremoteseqnumber(context, auth_context,
996		(krb5_int32 *)&seq_temp);
997       ctx->seq_recv = seq_temp;
998   }
999
1000   if ((code = krb5_timeofday(context, &now))) {
1001       major_status = GSS_S_FAILURE;
1002       goto fail;
1003   }
1004
1005   if (ctx->endtime < now) {
1006       code = 0;
1007       major_status = GSS_S_CREDENTIALS_EXPIRED;
1008       goto fail;
1009   }
1010
1011   g_order_init(&(ctx->seqstate), ctx->seq_recv,
1012		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
1013		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
1014
1015   /* at this point, the entire context structure is filled in,
1016      so it can be released.  */
1017
1018   /* generate an AP_REP if necessary */
1019
1020   if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1021       unsigned char * ptr3;
1022       krb5_ui_4 seq_temp;
1023       int cfx_generate_subkey;
1024
1025       if (ctx->proto == 1)
1026	   cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1027       else
1028	   cfx_generate_subkey = 0;
1029
1030       if (cfx_generate_subkey) {
1031	   krb5_int32 acflags;
1032	   code = krb5_auth_con_getflags(context, auth_context, &acflags);
1033	   if (code == 0) {
1034	       acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1035	       code = krb5_auth_con_setflags(context, auth_context, acflags);
1036	   }
1037	   if (code) {
1038	       major_status = GSS_S_FAILURE;
1039	       goto fail;
1040	   }
1041       }
1042
1043       if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1044	   major_status = GSS_S_FAILURE;
1045	   goto fail;
1046       }
1047
1048       krb5_auth_con_getlocalseqnumber(context, auth_context,
1049		(krb5_int32 *)&seq_temp);
1050       ctx->seq_send = seq_temp & 0xffffffffL;
1051
1052       if (cfx_generate_subkey) {
1053	   /* Get the new acceptor subkey.  With the code above, there
1054	      should always be one if we make it to this point.  */
1055	   code = krb5_auth_con_getsendsubkey(context, auth_context,
1056					      &ctx->acceptor_subkey);
1057	   if (code != 0) {
1058	       major_status = GSS_S_FAILURE;
1059	       goto fail;
1060	   }
1061	   code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
1062						ctx->acceptor_subkey->enctype,
1063						&ctx->acceptor_subkey_cksumtype);
1064	   if (code) {
1065	       major_status = GSS_S_FAILURE;
1066	       goto fail;
1067	   }
1068	   ctx->have_acceptor_subkey = 1;
1069       }
1070
1071       /* the reply token hasn't been sent yet, but that's ok. */
1072       ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1073       ctx->established = 1;
1074
1075       token.length = g_token_size(mech_used, ap_rep.length);
1076
1077       if ((token.value = (unsigned char *) xmalloc(token.length))
1078	   == NULL) {
1079	   major_status = GSS_S_FAILURE;
1080	   code = ENOMEM;
1081	   goto fail;
1082       }
1083       ptr3 = token.value;
1084       g_make_token_header(mech_used, ap_rep.length,
1085			   &ptr3, KG_TOK_CTX_AP_REP);
1086
1087       TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1088
1089       ctx->established = 1;
1090
1091   } else {
1092       token.length = 0;
1093       token.value = NULL;
1094       ctx->seq_send = ctx->seq_recv;
1095
1096       ctx->established = 1;
1097   }
1098
1099   /* set the return arguments */
1100
1101   /*
1102    * Solaris Kerberos
1103    * Regardless of src_name, get name for error msg if neeeded.
1104    */
1105   if ((code = krb5_copy_principal(context, ctx->there, &client_name))) {
1106	major_status = GSS_S_FAILURE;
1107	goto fail;
1108   }
1109   if ((code = krb5_copy_principal(context, ctx->here, &server_name))) {
1110	major_status = GSS_S_FAILURE;
1111	goto fail;
1112   }
1113   /* intern the src_name */
1114   if (! kg_save_name((gss_name_t) client_name)) {
1115	code = G_VALIDATE_FAILED;
1116	major_status = GSS_S_FAILURE;
1117	goto fail;
1118   }
1119
1120   if (time_rec)
1121      *time_rec = ctx->endtime - now;
1122
1123   if (ret_flags)
1124      *ret_flags = ctx->gss_flags;
1125
1126   *context_handle = (gss_ctx_id_t)ctx;
1127   *output_token = token;
1128
1129   if (src_name)
1130      *src_name = (gss_name_t) client_name;
1131
1132   if (delegated_cred_handle && deleg_cred) {
1133       if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1134           /* Solaris Kerberos */
1135	   KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1136		      "kg_save_cred_id() error");
1137	   major_status = GSS_S_FAILURE;
1138	   code = (OM_uint32) G_VALIDATE_FAILED;
1139	   goto fail;
1140       }
1141
1142       *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1143   }
1144
1145   /* finally! */
1146
1147   *minor_status = 0;
1148   major_status = GSS_S_COMPLETE;
1149
1150 fail:
1151   if (mech_type) {
1152	unsigned int min;
1153	gss_buffer_desc oidstr;
1154	oidstr.value = NULL;
1155
1156	/*
1157	 * This needs to be set/returned even on fail so
1158	 * gss_accept_sec_context() can map_error_oid() the correct
1159	 * error/oid for later use by gss_display_status().
1160	 * (needed in CIFS/SPNEGO case)
1161	 */
1162	*mech_type = (gss_OID) mech_used;
1163
1164	(void) gss_oid_to_str(&min, *mech_type, &oidstr);
1165   }
1166
1167   if (authdat)
1168       krb5_free_authenticator(context, authdat);
1169   /* The ctx structure has the handle of the auth_context */
1170   if (auth_context && !ctx) {
1171       if (cred_rcache)
1172	   (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1173
1174       krb5_auth_con_free(context, auth_context);
1175   }
1176   if (reqcksum.contents)
1177       xfree(reqcksum.contents);
1178   if (ap_rep.data)
1179       xfree(ap_rep.data);
1180
1181   if (request != NULL) {
1182	saved_ap_options = request->ap_options;
1183	krb5_free_ap_req(context, request);
1184	request = NULL;
1185   }
1186
1187   if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1188	if (!verifier_cred_handle && cred_handle) {
1189		krb5_gss_release_cred(minor_status, &cred_handle);
1190	}
1191
1192	if (ctx)
1193	    ctx->k5_context = context;
1194
1195        return(major_status);
1196   }
1197
1198   /* from here on is the real "fail" code */
1199
1200   if (ctx)
1201       (void) krb5_gss_delete_sec_context(minor_status,
1202					  (gss_ctx_id_t *) &ctx, NULL);
1203   if (deleg_cred) { /* free memory associated with the deleg credential */
1204       if (deleg_cred->ccache)
1205	   (void)krb5_cc_close(context, deleg_cred->ccache);
1206       if (deleg_cred->princ)
1207	   krb5_free_principal(context, deleg_cred->princ);
1208       xfree(deleg_cred);
1209   }
1210   if (token.value)
1211       xfree(token.value);
1212
1213   *minor_status = code;
1214
1215   if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1216	gss_flags |= GSS_C_MUTUAL_FLAG;
1217
1218   if (cred
1219       && ((gss_flags & GSS_C_MUTUAL_FLAG)
1220	   || (major_status == GSS_S_CONTINUE_NEEDED))) {
1221       unsigned int tmsglen;
1222       int toktype;
1223
1224       /*
1225	* The client is expecting a response, so we can send an
1226	* error token back
1227	*/
1228
1229       /*
1230        * Solaris Kerberos: We need to remap error conditions for buggy
1231        * Windows clients if the MS_INTEROP env var has been set.
1232        */
1233       if ((code == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
1234	  code == KRB5KRB_AP_ERR_NOKEY || code == KRB5KRB_AP_ERR_BADKEYVER)
1235	  && krb5_getenv("MS_INTEROP")) {
1236           code = KRB5KRB_AP_ERR_MODIFIED;
1237	   major_status = GSS_S_CONTINUE_NEEDED;
1238       }
1239
1240	    /*
1241	     * SUNW17PACresync / Solaris Kerberos
1242	     * Set e-data to Windows constant.
1243	     * (verified by MSFT)
1244	     *
1245	     * This facilitates the Windows CIFS client clock skew
1246	     * recovery feature.
1247	     */
1248       if (code == KRB5KRB_AP_ERR_SKEW && krb5_getenv("MS_INTEROP")) {
1249	    char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
1250	    int len = strlen(ms_e_data);
1251
1252	    krb_error_data.e_data.data = malloc(len);
1253	    if (krb_error_data.e_data.data) {
1254		    (void) memcpy(krb_error_data.e_data.data, ms_e_data, len);
1255		    krb_error_data.e_data.length = len;
1256	    }
1257	    major_status = GSS_S_CONTINUE_NEEDED;
1258       }
1259
1260       code -= ERROR_TABLE_BASE_krb5;
1261       if (code < 0 || code > 128)
1262	   code = 60 /* KRB_ERR_GENERIC */;
1263
1264       krb_error_data.error = code;
1265       (void) krb5_us_timeofday(context, &krb_error_data.stime,
1266				&krb_error_data.susec);
1267       krb_error_data.server = cred->princ;
1268
1269       code = krb5_mk_error(context, &krb_error_data, &scratch);
1270       if (code)
1271           goto cleanup;
1272
1273       tmsglen = scratch.length;
1274       toktype = KG_TOK_CTX_ERROR;
1275
1276       token.length = g_token_size(mech_used, tmsglen);
1277       token.value = (unsigned char *) xmalloc(token.length);
1278       if (!token.value)
1279	  goto cleanup;
1280
1281       ptr = token.value;
1282       g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1283
1284       TWRITE_STR(ptr, scratch.data, scratch.length);
1285       xfree(scratch.data);
1286
1287       *output_token = token;
1288   }
1289
1290cleanup:
1291   /* Solaris Kerberos */
1292   if (krb_error_data.e_data.data != NULL)
1293        free(krb_error_data.e_data.data);
1294
1295   if (!verifier_cred_handle && cred_handle) {
1296	krb5_gss_release_cred(&t_minor_status, &cred_handle);
1297   }
1298
1299   /*
1300    * Solaris Kerberos
1301    * Enhance the error message.
1302    */
1303   if (GSS_ERROR(major_status)) {
1304       if (client_name && server_name &&
1305	 (*minor_status == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
1306	    char *c_name = NULL;
1307	    char *s_name = NULL;
1308	    krb5_error_code cret, sret;
1309	    cret = krb5_unparse_name(context, (krb5_principal) client_name,
1310				    &c_name);
1311	    sret = krb5_unparse_name(context, (krb5_principal) server_name,
1312				    &s_name);
1313	    krb5_set_error_message(context, *minor_status,
1314				dgettext(TEXT_DOMAIN,
1315					"Decrypt integrity check failed for client '%s' and server '%s'"),
1316				cret == 0 ? c_name : "unknown",
1317				sret == 0 ? s_name : "unknown");
1318	    if (s_name)
1319		    krb5_free_unparsed_name(context, s_name);
1320	    if (c_name)
1321		    krb5_free_unparsed_name(context, c_name);
1322	    }
1323       /*
1324	* Solaris Kerberos
1325	* krb5_gss_acquire_cred() does not take a context arg
1326	* (and does a save_error_info() itself) so re-calling
1327	* save_error_info() here is trouble.
1328	*/
1329       if (!acquire_fail)
1330	    save_error_info(*minor_status, context);
1331   }
1332   if (client_name) {
1333	(void) kg_delete_name((gss_name_t) client_name);
1334   }
1335   if (server_name)
1336	krb5_free_principal(context, server_name);
1337   krb5_free_context(context);
1338
1339   /* Solaris Kerberos */
1340   KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1341	      "major_status = %d", major_status);
1342   return (major_status);
1343}
1344