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