2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
34 #include "gsskrb5_locl.h"
37 __gsskrb5_ccache_lifetime(OM_uint32
*minor_status
,
40 krb5_principal principal
,
43 krb5_creds in_cred
, out_cred
;
44 krb5_const_realm realm
;
47 memset(&in_cred
, 0, sizeof(in_cred
));
48 in_cred
.client
= principal
;
50 realm
= krb5_principal_get_realm(context
, principal
);
52 _gsskrb5_clear_status ();
53 *minor_status
= KRB5_PRINC_NOMATCH
; /* XXX */
57 kret
= krb5_make_principal(context
, &in_cred
.server
,
58 realm
, KRB5_TGS_NAME
, realm
, NULL
);
64 kret
= krb5_cc_retrieve_cred(context
, id
, 0, &in_cred
, &out_cred
);
65 krb5_free_principal(context
, in_cred
.server
);
69 return GSS_S_COMPLETE
;
72 *lifetime
= out_cred
.times
.endtime
;
73 krb5_free_cred_contents(context
, &out_cred
);
75 return GSS_S_COMPLETE
;
81 static krb5_error_code
82 get_keytab(krb5_context context
, krb5_keytab
*keytab
)
86 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex
);
88 if (_gsskrb5_keytab
!= NULL
) {
91 kret
= krb5_kt_get_full_name(context
, _gsskrb5_keytab
, &name
);
93 kret
= krb5_kt_resolve(context
, name
, keytab
);
97 kret
= krb5_kt_default(context
, keytab
);
99 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex
);
104 static OM_uint32 acquire_initiator_cred
105 (OM_uint32
* minor_status
,
106 krb5_context context
,
107 const gss_OID credential_type
,
108 void *credential_data
,
109 const gss_name_t desired_name
,
111 const gss_OID desired_mech
,
112 gss_cred_usage_t cred_usage
,
118 krb5_principal def_princ
;
119 krb5_get_init_creds_opt
*opt
;
122 krb5_error_code kret
;
128 memset(&cred
, 0, sizeof(cred
));
131 * If we have a preferred principal, lets try to find it in all
132 * caches, otherwise, fall back to default cache, ignore all
133 * errors while searching.
136 if (credential_type
!= GSS_C_NO_OID
&&
137 !gss_oid_equal(credential_type
, GSS_C_CRED_PASSWORD
)) {
138 kret
= KRB5_NOCREDS_SUPPLIED
; /* XXX */
142 if (handle
->principal
) {
143 kret
= krb5_cc_cache_match (context
,
147 ret
= GSS_S_COMPLETE
;
152 if (ccache
== NULL
) {
153 kret
= krb5_cc_default(context
, &ccache
);
157 kret
= krb5_cc_get_principal(context
, ccache
, &def_princ
);
159 /* we'll try to use a keytab below */
160 krb5_cc_close(context
, ccache
);
163 } else if (handle
->principal
== NULL
) {
164 kret
= krb5_copy_principal(context
, def_princ
, &handle
->principal
);
167 } else if (handle
->principal
!= NULL
&&
168 krb5_principal_compare(context
, handle
->principal
,
169 def_princ
) == FALSE
) {
170 krb5_free_principal(context
, def_princ
);
172 krb5_cc_close(context
, ccache
);
175 if (def_princ
== NULL
) {
176 /* We have no existing credentials cache,
177 * so attempt to get a TGT using a keytab.
179 if (handle
->principal
== NULL
) {
180 kret
= krb5_get_default_principal(context
, &handle
->principal
);
184 kret
= krb5_get_init_creds_opt_alloc(context
, &opt
);
187 if (credential_type
!= GSS_C_NO_OID
&&
188 gss_oid_equal(credential_type
, GSS_C_CRED_PASSWORD
)) {
189 gss_buffer_t password
= (gss_buffer_t
)credential_data
;
191 /* XXX are we requiring password to be NUL terminated? */
193 kret
= krb5_get_init_creds_password(context
, &cred
,
196 NULL
, NULL
, 0, NULL
, opt
);
198 kret
= get_keytab(context
, &keytab
);
200 krb5_get_init_creds_opt_free(context
, opt
);
203 kret
= krb5_get_init_creds_keytab(context
, &cred
,
204 handle
->principal
, keytab
,
207 krb5_get_init_creds_opt_free(context
, opt
);
210 kret
= krb5_cc_new_unique(context
, krb5_cc_type_memory
,
214 kret
= krb5_cc_initialize(context
, ccache
, cred
.client
);
216 krb5_cc_destroy(context
, ccache
);
219 kret
= krb5_cc_store_cred(context
, ccache
, &cred
);
221 krb5_cc_destroy(context
, ccache
);
224 handle
->lifetime
= cred
.times
.endtime
;
225 handle
->cred_flags
|= GSS_CF_DESTROY_CRED_ON_RELEASE
;
228 ret
= __gsskrb5_ccache_lifetime(minor_status
,
233 if (ret
!= GSS_S_COMPLETE
) {
234 krb5_cc_close(context
, ccache
);
240 handle
->ccache
= ccache
;
241 ret
= GSS_S_COMPLETE
;
244 if (cred
.client
!= NULL
)
245 krb5_free_cred_contents(context
, &cred
);
246 if (def_princ
!= NULL
)
247 krb5_free_principal(context
, def_princ
);
249 krb5_kt_close(context
, keytab
);
250 if (ret
!= GSS_S_COMPLETE
&& kret
!= 0)
251 *minor_status
= kret
;
255 static OM_uint32 acquire_acceptor_cred
256 (OM_uint32
* minor_status
,
257 krb5_context context
,
258 const gss_OID credential_type
,
259 void *credential_data
,
260 const gss_name_t desired_name
,
262 const gss_OID desired_mech
,
263 gss_cred_usage_t cred_usage
,
268 krb5_error_code kret
;
272 if (credential_type
!= GSS_C_NO_OID
) {
277 kret
= get_keytab(context
, &handle
->keytab
);
281 /* check that the requested principal exists in the keytab */
282 if (handle
->principal
) {
283 krb5_keytab_entry entry
;
285 kret
= krb5_kt_get_entry(context
, handle
->keytab
,
286 handle
->principal
, 0, 0, &entry
);
289 krb5_kt_free_entry(context
, &entry
);
290 ret
= GSS_S_COMPLETE
;
293 * Check if there is at least one entry in the keytab before
294 * declaring it as an useful keytab.
296 krb5_keytab_entry tmp
;
299 kret
= krb5_kt_start_seq_get (context
, handle
->keytab
, &c
);
302 if (krb5_kt_next_entry(context
, handle
->keytab
, &tmp
, &c
) == 0) {
303 krb5_kt_free_entry(context
, &tmp
);
304 ret
= GSS_S_COMPLETE
; /* ok found one entry */
306 krb5_kt_end_seq_get (context
, handle
->keytab
, &c
);
309 if (ret
!= GSS_S_COMPLETE
) {
310 if (handle
->keytab
!= NULL
)
311 krb5_kt_close(context
, handle
->keytab
);
313 *minor_status
= kret
;
319 OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred
320 (OM_uint32
* minor_status
,
321 const gss_name_t desired_name
,
323 const gss_OID_set desired_mechs
,
324 gss_cred_usage_t cred_usage
,
325 gss_cred_id_t
* output_cred_handle
,
326 gss_OID_set
* actual_mechs
,
335 ret
= gss_test_oid_set_member(minor_status
, GSS_KRB5_MECHANISM
,
336 desired_mechs
, &present
);
341 return GSS_S_BAD_MECH
;
345 ret
= _gsskrb5_acquire_cred_ex(minor_status
,
357 ret
= _gsskrb5_inquire_cred(minor_status
, *output_cred_handle
,
358 NULL
, time_rec
, NULL
, actual_mechs
);
361 _gsskrb5_release_cred(&tmp
, output_cred_handle
);
367 OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ex
368 (OM_uint32
* minor_status
,
369 const gss_name_t desired_name
,
370 const gss_OID credential_type
,
371 void *credential_data
,
373 const gss_OID desired_mech
,
374 gss_cred_usage_t cred_usage
,
375 gss_cred_id_t
* output_cred_handle
378 krb5_context context
;
382 cred_usage
&= GSS_C_OPTION_MASK
;
384 if (cred_usage
!= GSS_C_ACCEPT
&& cred_usage
!= GSS_C_INITIATE
&& cred_usage
!= GSS_C_BOTH
) {
385 *minor_status
= GSS_KRB5_S_G_BAD_USAGE
;
386 return GSS_S_FAILURE
;
389 GSSAPI_KRB5_INIT(&context
);
391 *output_cred_handle
= NULL
;
393 handle
= calloc(1, sizeof(*handle
));
394 if (handle
== NULL
) {
395 *minor_status
= ENOMEM
;
396 return (GSS_S_FAILURE
);
399 HEIMDAL_MUTEX_init(&handle
->cred_id_mutex
);
401 if (desired_name
!= GSS_C_NO_NAME
) {
402 ret
= _gsskrb5_canon_name(minor_status
, context
, 1, NULL
,
403 desired_name
, &handle
->principal
);
405 HEIMDAL_MUTEX_destroy(&handle
->cred_id_mutex
);
410 if (cred_usage
== GSS_C_INITIATE
|| cred_usage
== GSS_C_BOTH
) {
411 ret
= acquire_initiator_cred(minor_status
, context
,
412 credential_type
, credential_data
,
413 desired_name
, time_req
,
414 desired_mech
, cred_usage
, handle
);
415 if (ret
!= GSS_S_COMPLETE
) {
416 HEIMDAL_MUTEX_destroy(&handle
->cred_id_mutex
);
417 krb5_free_principal(context
, handle
->principal
);
422 if (cred_usage
== GSS_C_ACCEPT
|| cred_usage
== GSS_C_BOTH
) {
423 ret
= acquire_acceptor_cred(minor_status
, context
,
424 credential_type
, credential_data
,
425 desired_name
, time_req
,
426 desired_mech
, cred_usage
, handle
);
427 if (ret
!= GSS_S_COMPLETE
) {
428 HEIMDAL_MUTEX_destroy(&handle
->cred_id_mutex
);
429 krb5_free_principal(context
, handle
->principal
);
434 ret
= gss_create_empty_oid_set(minor_status
, &handle
->mechanisms
);
435 if (ret
== GSS_S_COMPLETE
)
436 ret
= gss_add_oid_set_member(minor_status
, GSS_KRB5_MECHANISM
,
437 &handle
->mechanisms
);
438 if (ret
!= GSS_S_COMPLETE
) {
439 if (handle
->mechanisms
!= NULL
)
440 gss_release_oid_set(NULL
, &handle
->mechanisms
);
441 HEIMDAL_MUTEX_destroy(&handle
->cred_id_mutex
);
442 krb5_free_principal(context
, handle
->principal
);
446 handle
->usage
= cred_usage
;
448 *output_cred_handle
= (gss_cred_id_t
)handle
;
449 return (GSS_S_COMPLETE
);