Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "gsskrb5_locl.h"
35 :
36 : /*
37 : * Find an element in a cred store. Returns GSS_S_COMPLETE if the cred store
38 : * is absent or well formed, irrespective of whether the element exists. The
39 : * caller should check for *value != NULL before using; values are typically
40 : * optional, hence this behavior. (The caller should validate the return
41 : * value at least once though, to check it is well-formed.)
42 : */
43 : OM_uint32
44 287464 : __gsskrb5_cred_store_find(OM_uint32 *minor_status,
45 : gss_const_key_value_set_t cred_store,
46 : const char *key,
47 : const char **value)
48 : {
49 3524 : size_t i;
50 :
51 287464 : *value = NULL;
52 :
53 287464 : if (cred_store == GSS_C_NO_CRED_STORE)
54 0 : return GSS_S_COMPLETE;
55 287464 : else if (cred_store->count == 0) {
56 0 : *minor_status = GSS_KRB5_S_G_BAD_USAGE;
57 0 : return GSS_S_NO_CRED;
58 : }
59 :
60 574928 : for (i = 0; i < cred_store->count; i++) {
61 287464 : if (strcmp(key, cred_store->elements[i].key) == 0) {
62 71866 : if (*value) {
63 0 : *value = NULL;
64 0 : *minor_status = GSS_KRB5_S_G_BAD_USAGE;
65 0 : return GSS_S_DUPLICATE_ELEMENT;
66 : }
67 71866 : *value = cred_store->elements[i].value;
68 : }
69 : }
70 :
71 283940 : return GSS_S_COMPLETE;
72 : }
73 :
74 : OM_uint32
75 63240 : __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
76 : krb5_context context,
77 : krb5_ccache id,
78 : krb5_principal principal,
79 : OM_uint32 *lifetime)
80 : {
81 1466 : krb5_error_code kret;
82 1466 : time_t left;
83 :
84 63240 : kret = krb5_cc_get_lifetime(context, id, &left);
85 63240 : if (kret) {
86 0 : *minor_status = kret;
87 0 : return GSS_S_FAILURE;
88 : }
89 :
90 63240 : *lifetime = left;
91 :
92 63240 : return GSS_S_COMPLETE;
93 : }
94 :
95 :
96 :
97 :
98 : static krb5_error_code
99 0 : get_system_keytab(krb5_context context,
100 : gss_const_key_value_set_t cred_store,
101 : krb5_keytab *keytab)
102 : {
103 0 : krb5_error_code kret;
104 0 : const char *cs_ktname;
105 0 : OM_uint32 tmp;
106 :
107 0 : __gsskrb5_cred_store_find(&tmp, cred_store, "keytab", &cs_ktname);
108 :
109 0 : HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
110 :
111 0 : if (cs_ktname)
112 0 : kret = krb5_kt_resolve(context, cs_ktname, keytab);
113 0 : else if (_gsskrb5_keytab != NULL) {
114 0 : char *name = NULL;
115 :
116 0 : kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
117 0 : if (kret == 0) {
118 0 : kret = krb5_kt_resolve(context, name, keytab);
119 0 : krb5_xfree(name);
120 : }
121 : } else
122 0 : kret = krb5_kt_default(context, keytab);
123 :
124 0 : HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
125 :
126 0 : return (kret);
127 : }
128 :
129 : static krb5_error_code
130 0 : get_client_keytab(krb5_context context,
131 : gss_const_key_value_set_t cred_store,
132 : krb5_const_principal principal,
133 : krb5_keytab *keytab)
134 : {
135 0 : krb5_error_code ret;
136 0 : const char *cs_ktname;
137 0 : OM_uint32 tmp;
138 :
139 0 : __gsskrb5_cred_store_find(&tmp, cred_store, "client_keytab", &cs_ktname);
140 :
141 0 : if (cs_ktname)
142 0 : ret = krb5_kt_resolve(context, cs_ktname, keytab);
143 : else {
144 0 : char *name = NULL;
145 0 : ret = _krb5_kt_client_default_name(context, &name);
146 0 : if (ret == 0)
147 0 : ret = krb5_kt_resolve(context, name, keytab);
148 0 : krb5_xfree(name);
149 : }
150 :
151 0 : if (ret == 0 && principal) {
152 0 : krb5_keytab_entry entry;
153 :
154 0 : ret = krb5_kt_get_entry(context, *keytab, principal,
155 : 0, 0, &entry);
156 0 : if (ret == 0)
157 0 : krb5_kt_free_entry(context, &entry);
158 : }
159 :
160 0 : if (ret) {
161 0 : if (*keytab) {
162 0 : krb5_kt_close(context, *keytab);
163 0 : *keytab = NULL;
164 : }
165 :
166 0 : ret = get_system_keytab(context, GSS_C_NO_CRED_STORE, keytab);
167 : }
168 :
169 0 : return ret;
170 : }
171 :
172 : static krb5_boolean
173 0 : is_valid_password_cred_store(gss_const_key_value_set_t cred_store)
174 : {
175 0 : size_t i;
176 :
177 0 : if (cred_store == GSS_C_NO_CRED_STORE)
178 0 : return TRUE;
179 :
180 : /* XXX don't check keytab, someday we will allow password+acceptor creds */
181 0 : for (i = 0; i < cred_store->count; i++) {
182 0 : if (strcmp(cred_store->elements[i].key, "ccache") == 0 ||
183 0 : strcmp(cred_store->elements[i].key, "client_keytab") == 0)
184 0 : return FALSE;
185 : }
186 :
187 0 : return TRUE;
188 : }
189 :
190 : /*
191 : * This function produces a cred with a MEMORY ccache containing a TGT
192 : * acquired with a password.
193 : */
194 : static OM_uint32
195 0 : acquire_cred_with_password(OM_uint32 *minor_status,
196 : krb5_context context,
197 : const char *password,
198 : OM_uint32 time_req,
199 : gss_OID_set desired_mechs,
200 : gss_cred_usage_t cred_usage,
201 : gss_const_key_value_set_t cred_store,
202 : gsskrb5_cred handle)
203 : {
204 0 : OM_uint32 ret = GSS_S_FAILURE;
205 0 : krb5_creds cred;
206 0 : krb5_init_creds_context ctx = NULL;
207 0 : krb5_get_init_creds_opt *opt = NULL;
208 0 : krb5_ccache ccache = NULL;
209 0 : krb5_error_code kret;
210 0 : time_t now;
211 0 : OM_uint32 left;
212 0 : const char *realm;
213 :
214 0 : if (!is_valid_password_cred_store(cred_store)) {
215 0 : *minor_status = GSS_KRB5_S_G_BAD_PASSWORD_CRED_STORE;
216 0 : return GSS_S_NO_CRED;
217 : }
218 :
219 0 : if (cred_usage == GSS_C_ACCEPT) {
220 : /*
221 : * TODO: Here we should eventually support user2user (when we get
222 : * support for that via an extension to the mechanism
223 : * allowing for more than two security context tokens),
224 : * and/or new unique MEMORY keytabs (we have MEMORY keytab
225 : * support, but we don't have a keytab equivalent of
226 : * krb5_cc_new_unique()). Either way, for now we can't
227 : * support this.
228 : */
229 0 : *minor_status = ENOTSUP; /* XXX Better error? */
230 0 : return GSS_S_FAILURE;
231 : }
232 :
233 0 : memset(&cred, 0, sizeof(cred));
234 :
235 0 : if (handle->principal == NULL) {
236 0 : kret = krb5_get_default_principal(context, &handle->principal);
237 0 : if (kret)
238 0 : goto end;
239 : }
240 0 : realm = krb5_principal_get_realm(context, handle->principal);
241 :
242 0 : kret = krb5_get_init_creds_opt_alloc(context, &opt);
243 0 : if (kret == 0) {
244 0 : krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm,
245 : opt);
246 0 : kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, 0,
247 : opt, &ctx);
248 : }
249 0 : if (kret == 0)
250 0 : kret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx);
251 0 : if (kret == 0)
252 0 : kret = krb5_init_creds_set_password(context, ctx, password);
253 :
254 : /*
255 : * Get the current time before the AS exchange so we don't
256 : * accidentally end up returning a value that puts advertised
257 : * expiration past the real expiration.
258 : *
259 : * We need to do this because krb5_cc_get_lifetime() returns a
260 : * relative time that we need to add to the current time. We ought
261 : * to have a version of krb5_cc_get_lifetime() that returns absolute
262 : * time...
263 : */
264 0 : krb5_timeofday(context, &now);
265 :
266 0 : if (kret == 0)
267 0 : kret = krb5_init_creds_get(context, ctx);
268 0 : if (kret == 0)
269 0 : kret = krb5_init_creds_get_creds(context, ctx, &cred);
270 0 : if (kret == 0)
271 0 : kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
272 0 : if (kret == 0)
273 0 : kret = krb5_cc_initialize(context, ccache, cred.client);
274 0 : if (kret == 0)
275 0 : kret = krb5_init_creds_store(context, ctx, ccache);
276 0 : if (kret == 0)
277 0 : kret = krb5_cc_store_cred(context, ccache, &cred);
278 0 : if (kret)
279 0 : goto end;
280 :
281 0 : handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
282 :
283 0 : ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache,
284 : handle->principal, &left);
285 0 : if (ret != GSS_S_COMPLETE)
286 0 : goto end;
287 0 : handle->endtime = now + left;
288 0 : handle->ccache = ccache;
289 0 : ccache = NULL;
290 0 : ret = GSS_S_COMPLETE;
291 :
292 0 : end:
293 0 : krb5_get_init_creds_opt_free(context, opt);
294 0 : if (ctx)
295 0 : krb5_init_creds_free(context, ctx);
296 0 : if (ccache != NULL)
297 0 : krb5_cc_destroy(context, ccache);
298 0 : if (cred.client != NULL)
299 0 : krb5_free_cred_contents(context, &cred);
300 0 : if (ret != GSS_S_COMPLETE)
301 0 : *minor_status = kret;
302 0 : return (ret);
303 : }
304 :
305 : /*
306 : * Acquires an initiator credential from a ccache or using a keytab.
307 : */
308 : static OM_uint32
309 0 : acquire_initiator_cred(OM_uint32 *minor_status,
310 : krb5_context context,
311 : OM_uint32 time_req,
312 : gss_OID_set desired_mechs,
313 : gss_cred_usage_t cred_usage,
314 : gss_const_key_value_set_t cred_store,
315 : gsskrb5_cred handle)
316 : {
317 0 : OM_uint32 ret;
318 0 : krb5_creds cred;
319 0 : krb5_get_init_creds_opt *opt;
320 0 : krb5_principal def_princ = NULL;
321 0 : krb5_ccache def_ccache = NULL;
322 0 : krb5_ccache ccache = NULL; /* we may store into this ccache */
323 0 : krb5_keytab keytab = NULL;
324 0 : krb5_error_code kret = 0;
325 0 : OM_uint32 left;
326 0 : const char *cs_ccache_name;
327 0 : time_t lifetime = 0;
328 0 : time_t now;
329 :
330 0 : memset(&cred, 0, sizeof(cred));
331 :
332 0 : ret = __gsskrb5_cred_store_find(minor_status, cred_store,
333 : "ccache", &cs_ccache_name);
334 0 : if (GSS_ERROR(ret))
335 0 : return ret;
336 :
337 0 : ret = GSS_S_FAILURE;
338 :
339 : /*
340 : * Get current time early so we can set handle->endtime to a value that
341 : * cannot accidentally be past the real endtime. We need a variant of
342 : * krb5_cc_get_lifetime() that returns absolute endtime.
343 : */
344 0 : krb5_timeofday(context, &now);
345 :
346 : /*
347 : * First look for a ccache that has the desired_name (which may be
348 : * the default credential name), unless a specific credential cache
349 : * was included in cred_store.
350 : *
351 : * If we don't have an unexpired credential, acquire one with a
352 : * keytab.
353 : *
354 : * If we acquire one with a keytab, save it in the ccache we found
355 : * with the expired credential, if any.
356 : *
357 : * If we don't have any such ccache, then use a MEMORY ccache.
358 : */
359 :
360 0 : if (handle->principal != NULL && cs_ccache_name == NULL) {
361 : /*
362 : * Not default credential case. See if we can find a ccache in
363 : * the cccol for the desired_name.
364 : */
365 0 : kret = krb5_cc_cache_match(context,
366 : handle->principal,
367 : &ccache);
368 0 : if (kret == 0) {
369 0 : kret = krb5_cc_get_lifetime(context, ccache, &lifetime);
370 0 : if (kret == 0) {
371 0 : if (lifetime > 0)
372 0 : goto found;
373 : else
374 0 : goto try_keytab;
375 : }
376 : }
377 : /*
378 : * Fall through. We shouldn't find this in the default ccache
379 : * either, but we'll give it a try, then we'll try using a keytab.
380 : */
381 : }
382 :
383 : /*
384 : * Either desired_name was GSS_C_NO_NAME (default cred) or
385 : * krb5_cc_cache_match() failed (or found expired).
386 : */
387 0 : if (cs_ccache_name)
388 0 : kret = krb5_cc_resolve(context, cs_ccache_name, &def_ccache);
389 : else
390 0 : kret = krb5_cc_default(context, &def_ccache);
391 0 : if (kret != 0)
392 0 : goto try_keytab;
393 0 : kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime);
394 0 : if (kret != 0)
395 0 : lifetime = 0;
396 0 : kret = krb5_cc_get_principal(context, def_ccache, &def_princ);
397 0 : if (kret != 0)
398 0 : goto try_keytab;
399 : /*
400 : * Have a default ccache; see if it matches desired_name.
401 : */
402 0 : if (handle->principal == NULL ||
403 0 : krb5_principal_compare(context, handle->principal,
404 : def_princ) == TRUE) {
405 : /*
406 : * It matches.
407 : *
408 : * If we end up trying a keytab then we can write the result to
409 : * the default ccache.
410 : */
411 0 : if (handle->principal == NULL) {
412 0 : kret = krb5_copy_principal(context, def_princ, &handle->principal);
413 0 : if (kret)
414 0 : goto end;
415 : }
416 0 : if (ccache != NULL)
417 0 : krb5_cc_close(context, ccache);
418 0 : ccache = def_ccache;
419 0 : def_ccache = NULL;
420 0 : if (lifetime > 0)
421 0 : goto found;
422 : /* else we fall through and try using a keytab */
423 : }
424 :
425 0 : try_keytab:
426 0 : if (handle->principal == NULL) {
427 : /* We need to know what client principal to use */
428 0 : kret = krb5_get_default_principal(context, &handle->principal);
429 0 : if (kret)
430 0 : goto end;
431 : }
432 0 : kret = get_client_keytab(context, cred_store, handle->principal, &keytab);
433 0 : if (kret)
434 0 : goto end;
435 :
436 0 : kret = krb5_get_init_creds_opt_alloc(context, &opt);
437 0 : if (kret)
438 0 : goto end;
439 0 : krb5_timeofday(context, &now);
440 0 : kret = krb5_get_init_creds_keytab(context, &cred, handle->principal,
441 : keytab, 0, NULL, opt);
442 0 : krb5_get_init_creds_opt_free(context, opt);
443 0 : if (kret)
444 0 : goto end;
445 :
446 : /*
447 : * We got a credential with a keytab. Save it if we can.
448 : */
449 0 : if (ccache == NULL) {
450 : /*
451 : * There's no ccache we can overwrite with the credentials we acquired
452 : * with a keytab. We'll use a MEMORY ccache then.
453 : *
454 : * Note that an application that falls into this repeatedly will do an
455 : * AS exchange every time it acquires a credential handle. Hopefully
456 : * this doesn't happen much. A workaround is to kinit -k once so that
457 : * we always re-initialize the matched/default ccache here. I.e., once
458 : * there's a FILE/DIR ccache, we'll keep it frash automatically if we
459 : * have a keytab, but if there's no FILE/DIR ccache, then we'll
460 : * get a fresh credential *every* time we're asked.
461 : */
462 0 : kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
463 0 : if (kret)
464 0 : goto end;
465 0 : handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
466 : } /* else we'll re-initialize whichever ccache we matched above */
467 :
468 0 : kret = krb5_cc_initialize(context, ccache, cred.client);
469 0 : if (kret)
470 0 : goto end;
471 0 : kret = krb5_cc_store_cred(context, ccache, &cred);
472 0 : if (kret)
473 0 : goto end;
474 :
475 0 : found:
476 0 : assert(handle->principal != NULL);
477 0 : ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache,
478 : handle->principal, &left);
479 0 : if (ret != GSS_S_COMPLETE)
480 0 : goto end;
481 0 : handle->endtime = now + left;
482 0 : handle->ccache = ccache;
483 0 : ccache = NULL;
484 0 : ret = GSS_S_COMPLETE;
485 0 : kret = 0;
486 :
487 0 : end:
488 0 : if (ccache != NULL) {
489 0 : if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0)
490 0 : krb5_cc_destroy(context, ccache);
491 : else
492 0 : krb5_cc_close(context, ccache);
493 : }
494 0 : if (def_ccache != NULL)
495 0 : krb5_cc_close(context, def_ccache);
496 0 : if (cred.client != NULL)
497 0 : krb5_free_cred_contents(context, &cred);
498 0 : if (def_princ != NULL)
499 0 : krb5_free_principal(context, def_princ);
500 0 : if (keytab != NULL)
501 0 : krb5_kt_close(context, keytab);
502 0 : if (ret != GSS_S_COMPLETE && kret != 0)
503 0 : *minor_status = kret;
504 0 : return (ret);
505 : }
506 :
507 : static OM_uint32
508 0 : acquire_acceptor_cred(OM_uint32 * minor_status,
509 : krb5_context context,
510 : OM_uint32 time_req,
511 : gss_OID_set desired_mechs,
512 : gss_cred_usage_t cred_usage,
513 : gss_const_key_value_set_t cred_store,
514 : gsskrb5_cred handle)
515 : {
516 0 : OM_uint32 ret;
517 0 : krb5_error_code kret;
518 :
519 0 : ret = GSS_S_FAILURE;
520 :
521 0 : kret = get_system_keytab(context, cred_store, &handle->keytab);
522 0 : if (kret)
523 0 : goto end;
524 :
525 : /* check that the requested principal exists in the keytab */
526 0 : if (handle->principal) {
527 0 : krb5_keytab_entry entry;
528 :
529 0 : kret = krb5_kt_get_entry(context, handle->keytab,
530 0 : handle->principal, 0, 0, &entry);
531 0 : if (kret)
532 0 : goto end;
533 0 : krb5_kt_free_entry(context, &entry);
534 0 : ret = GSS_S_COMPLETE;
535 : } else {
536 : /*
537 : * Check if there is at least one entry in the keytab before
538 : * declaring it as an useful keytab.
539 : */
540 0 : krb5_keytab_entry tmp;
541 0 : krb5_kt_cursor c;
542 :
543 0 : kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
544 0 : if (kret)
545 0 : goto end;
546 0 : if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
547 0 : krb5_kt_free_entry(context, &tmp);
548 0 : ret = GSS_S_COMPLETE; /* ok found one entry */
549 : }
550 0 : krb5_kt_end_seq_get (context, handle->keytab, &c);
551 : }
552 0 : end:
553 0 : if (ret != GSS_S_COMPLETE) {
554 0 : if (handle->keytab != NULL)
555 0 : krb5_kt_close(context, handle->keytab);
556 0 : if (kret != 0) {
557 0 : *minor_status = kret;
558 : }
559 : }
560 0 : return (ret);
561 : }
562 :
563 :
564 0 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from
565 : (OM_uint32 * minor_status,
566 : gss_const_name_t desired_name,
567 : OM_uint32 time_req,
568 : gss_OID_set desired_mechs,
569 : gss_cred_usage_t cred_usage,
570 : gss_const_key_value_set_t cred_store,
571 : gss_cred_id_t * output_cred_handle,
572 : gss_OID_set *actual_mechs,
573 : OM_uint32 *time_rec
574 : )
575 : {
576 0 : krb5_context context;
577 0 : gsskrb5_cred handle;
578 0 : OM_uint32 ret;
579 0 : const char *password = NULL;
580 :
581 0 : if (desired_mechs) {
582 0 : int present = 0;
583 :
584 0 : ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
585 : desired_mechs, &present);
586 0 : if (ret)
587 0 : return ret;
588 0 : if (!present) {
589 0 : *minor_status = 0;
590 0 : return GSS_S_BAD_MECH;
591 : }
592 : }
593 :
594 0 : cred_usage &= GSS_C_OPTION_MASK;
595 :
596 0 : if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE &&
597 : cred_usage != GSS_C_BOTH) {
598 0 : *minor_status = GSS_KRB5_S_G_BAD_USAGE;
599 0 : return GSS_S_FAILURE;
600 : }
601 :
602 0 : ret = __gsskrb5_cred_store_find(minor_status, cred_store,
603 : "password", &password);
604 0 : if (GSS_ERROR(ret))
605 0 : return ret;
606 :
607 0 : GSSAPI_KRB5_INIT(&context);
608 :
609 0 : *output_cred_handle = GSS_C_NO_CREDENTIAL;
610 :
611 0 : handle = calloc(1, sizeof(*handle));
612 0 : if (handle == NULL) {
613 0 : *minor_status = ENOMEM;
614 0 : return GSS_S_FAILURE;
615 : }
616 :
617 0 : handle->destination_realm = NULL;
618 0 : HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
619 :
620 0 : if (desired_name != GSS_C_NO_NAME) {
621 0 : ret = _gsskrb5_canon_name(minor_status, context,
622 : desired_name, &handle->principal);
623 0 : if (ret) {
624 0 : HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
625 0 : free(handle);
626 0 : return ret;
627 : }
628 : }
629 :
630 0 : if (password) {
631 0 : ret = acquire_cred_with_password(minor_status, context, password, time_req,
632 : desired_mechs, cred_usage, cred_store, handle);
633 0 : if (ret != GSS_S_COMPLETE) {
634 0 : HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
635 0 : krb5_free_principal(context, handle->principal);
636 0 : free(handle);
637 0 : return (ret);
638 : }
639 : } else {
640 : /*
641 : * Acquire a credential from the specified or background credential
642 : * store (ccache, keytab).
643 : */
644 0 : if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
645 0 : ret = acquire_initiator_cred(minor_status, context, time_req,
646 : desired_mechs, cred_usage,
647 : cred_store, handle);
648 0 : if (ret != GSS_S_COMPLETE) {
649 0 : HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
650 0 : krb5_free_principal(context, handle->principal);
651 0 : free(handle);
652 0 : return (ret);
653 : }
654 : }
655 0 : if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
656 0 : ret = acquire_acceptor_cred(minor_status, context, time_req,
657 : desired_mechs, cred_usage,
658 : cred_store, handle);
659 0 : if (ret != GSS_S_COMPLETE) {
660 0 : HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
661 0 : krb5_free_principal(context, handle->principal);
662 0 : free(handle);
663 0 : return (ret);
664 : }
665 : }
666 : }
667 0 : ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
668 0 : if (ret == GSS_S_COMPLETE)
669 0 : ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
670 : &handle->mechanisms);
671 0 : handle->usage = cred_usage;
672 0 : if (ret == GSS_S_COMPLETE)
673 0 : ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle,
674 : NULL, time_rec, NULL, actual_mechs);
675 0 : if (ret != GSS_S_COMPLETE) {
676 0 : if (handle->mechanisms != NULL)
677 0 : gss_release_oid_set(NULL, &handle->mechanisms);
678 0 : HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
679 0 : krb5_free_principal(context, handle->principal);
680 0 : free(handle);
681 0 : return (ret);
682 : }
683 0 : *minor_status = 0;
684 0 : *output_cred_handle = (gss_cred_id_t)handle;
685 0 : return (GSS_S_COMPLETE);
686 : }
|