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 "krb5/gsskrb5_locl.h"
39
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
42
krb5_principal principal,
45
krb5_creds in_cred, *out_cred;
46
krb5_const_realm realm;
49
memset(&in_cred, 0, sizeof(in_cred));
50
in_cred.client = principal;
52
realm = krb5_principal_get_realm(context, principal);
54
_gsskrb5_clear_status ();
55
*minor_status = KRB5_PRINC_NOMATCH; /* XXX */
59
kret = krb5_make_principal(context, &in_cred.server,
60
realm, KRB5_TGS_NAME, realm, NULL);
66
kret = krb5_get_credentials(context, 0,
67
id, &in_cred, &out_cred);
68
krb5_free_principal(context, in_cred.server);
74
*lifetime = out_cred->times.endtime;
75
krb5_free_creds(context, out_cred);
77
return GSS_S_COMPLETE;
83
static krb5_error_code
84
get_keytab(krb5_context context, krb5_keytab *keytab)
89
HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
91
if (_gsskrb5_keytab != NULL) {
92
kret = krb5_kt_get_name(context,
94
kt_name, sizeof(kt_name));
96
kret = krb5_kt_resolve(context, kt_name, keytab);
98
kret = krb5_kt_default(context, keytab);
100
HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
105
static OM_uint32 acquire_initiator_cred
106
(OM_uint32 * minor_status,
107
krb5_context context,
108
const gss_name_t desired_name,
110
const gss_OID_set desired_mechs,
111
gss_cred_usage_t cred_usage,
113
gss_OID_set * actual_mechs,
119
krb5_principal def_princ;
120
krb5_get_init_creds_opt *opt;
123
krb5_error_code kret;
129
memset(&cred, 0, sizeof(cred));
132
* If we have a preferred principal, lets try to find it in all
133
* caches, otherwise, fall back to default cache, ignore all
134
* errors while searching.
137
if (handle->principal) {
138
kret = krb5_cc_cache_match (context,
142
ret = GSS_S_COMPLETE;
147
if (ccache == NULL) {
148
kret = krb5_cc_default(context, &ccache);
152
kret = krb5_cc_get_principal(context, ccache, &def_princ);
154
/* we'll try to use a keytab below */
155
krb5_cc_close(context, ccache);
158
} else if (handle->principal == NULL) {
159
kret = krb5_copy_principal(context, def_princ, &handle->principal);
162
} else if (handle->principal != NULL &&
163
krb5_principal_compare(context, handle->principal,
164
def_princ) == FALSE) {
165
krb5_free_principal(context, def_princ);
167
krb5_cc_close(context, ccache);
170
if (def_princ == NULL) {
171
/* We have no existing credentials cache,
172
* so attempt to get a TGT using a keytab.
174
if (handle->principal == NULL) {
175
kret = krb5_get_default_principal(context, &handle->principal);
179
kret = get_keytab(context, &keytab);
182
kret = krb5_get_init_creds_opt_alloc(context, &opt);
185
kret = krb5_get_init_creds_keytab(context, &cred,
186
handle->principal, keytab, 0, NULL, opt);
187
krb5_get_init_creds_opt_free(context, opt);
190
kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
193
kret = krb5_cc_initialize(context, ccache, cred.client);
195
krb5_cc_destroy(context, ccache);
198
kret = krb5_cc_store_cred(context, ccache, &cred);
200
krb5_cc_destroy(context, ccache);
203
handle->lifetime = cred.times.endtime;
204
handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
207
ret = __gsskrb5_ccache_lifetime(minor_status,
212
if (ret != GSS_S_COMPLETE) {
213
krb5_cc_close(context, ccache);
219
handle->ccache = ccache;
220
ret = GSS_S_COMPLETE;
223
if (cred.client != NULL)
224
krb5_free_cred_contents(context, &cred);
225
if (def_princ != NULL)
226
krb5_free_principal(context, def_princ);
228
krb5_kt_close(context, keytab);
229
if (ret != GSS_S_COMPLETE && kret != 0)
230
*minor_status = kret;
234
static OM_uint32 acquire_acceptor_cred
235
(OM_uint32 * minor_status,
236
krb5_context context,
237
const gss_name_t desired_name,
239
const gss_OID_set desired_mechs,
240
gss_cred_usage_t cred_usage,
242
gss_OID_set * actual_mechs,
247
krb5_error_code kret;
250
kret = get_keytab(context, &handle->keytab);
254
/* check that the requested principal exists in the keytab */
255
if (handle->principal) {
256
krb5_keytab_entry entry;
258
kret = krb5_kt_get_entry(context, handle->keytab,
259
handle->principal, 0, 0, &entry);
262
krb5_kt_free_entry(context, &entry);
263
ret = GSS_S_COMPLETE;
266
* Check if there is at least one entry in the keytab before
267
* declaring it as an useful keytab.
269
krb5_keytab_entry tmp;
272
kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
275
if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
276
krb5_kt_free_entry(context, &tmp);
277
ret = GSS_S_COMPLETE; /* ok found one entry */
279
krb5_kt_end_seq_get (context, handle->keytab, &c);
282
if (ret != GSS_S_COMPLETE) {
283
if (handle->keytab != NULL)
284
krb5_kt_close(context, handle->keytab);
286
*minor_status = kret;
292
OM_uint32 _gsskrb5_acquire_cred
293
(OM_uint32 * minor_status,
294
const gss_name_t desired_name,
296
const gss_OID_set desired_mechs,
297
gss_cred_usage_t cred_usage,
298
gss_cred_id_t * output_cred_handle,
299
gss_OID_set * actual_mechs,
303
krb5_context context;
307
if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
308
*minor_status = GSS_KRB5_S_G_BAD_USAGE;
309
return GSS_S_FAILURE;
312
GSSAPI_KRB5_INIT(&context);
314
*output_cred_handle = NULL;
318
*actual_mechs = GSS_C_NO_OID_SET;
323
ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
324
desired_mechs, &present);
329
return GSS_S_BAD_MECH;
333
handle = calloc(1, sizeof(*handle));
334
if (handle == NULL) {
335
*minor_status = ENOMEM;
336
return (GSS_S_FAILURE);
339
HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
341
if (desired_name != GSS_C_NO_NAME) {
343
ret = _gsskrb5_canon_name(minor_status, context, 0, desired_name,
346
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
351
if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
352
ret = acquire_initiator_cred(minor_status, context,
353
desired_name, time_req,
354
desired_mechs, cred_usage, handle,
355
actual_mechs, time_rec);
356
if (ret != GSS_S_COMPLETE) {
357
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
358
krb5_free_principal(context, handle->principal);
363
if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
364
ret = acquire_acceptor_cred(minor_status, context,
365
desired_name, time_req,
366
desired_mechs, cred_usage, handle, actual_mechs, time_rec);
367
if (ret != GSS_S_COMPLETE) {
368
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
369
krb5_free_principal(context, handle->principal);
374
ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
375
if (ret == GSS_S_COMPLETE)
376
ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
377
&handle->mechanisms);
378
if (ret == GSS_S_COMPLETE)
379
ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle,
380
NULL, time_rec, NULL, actual_mechs);
381
if (ret != GSS_S_COMPLETE) {
382
if (handle->mechanisms != NULL)
383
gss_release_oid_set(NULL, &handle->mechanisms);
384
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
385
krb5_free_principal(context, handle->principal);
391
ret = _gsskrb5_lifetime_left(minor_status,
399
handle->usage = cred_usage;
400
*output_cred_handle = (gss_cred_id_t)handle;
401
return (GSS_S_COMPLETE);