~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/gssapi/krb5/acquire_cred.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "krb5/gsskrb5_locl.h"
 
35
 
 
36
RCSID("$Id$");
 
37
 
 
38
OM_uint32
 
39
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
 
40
                          krb5_context context,
 
41
                          krb5_ccache id,
 
42
                          krb5_principal principal,
 
43
                          OM_uint32 *lifetime)
 
44
{
 
45
    krb5_creds in_cred, *out_cred;
 
46
    krb5_const_realm realm;
 
47
    krb5_error_code kret;
 
48
 
 
49
    memset(&in_cred, 0, sizeof(in_cred));
 
50
    in_cred.client = principal;
 
51
        
 
52
    realm = krb5_principal_get_realm(context,  principal);
 
53
    if (realm == NULL) {
 
54
        _gsskrb5_clear_status ();
 
55
        *minor_status = KRB5_PRINC_NOMATCH; /* XXX */
 
56
        return GSS_S_FAILURE;
 
57
    }
 
58
 
 
59
    kret = krb5_make_principal(context, &in_cred.server,
 
60
                               realm, KRB5_TGS_NAME, realm, NULL);
 
61
    if (kret) {
 
62
        *minor_status = kret;
 
63
        return GSS_S_FAILURE;
 
64
    }
 
65
 
 
66
    kret = krb5_get_credentials(context, 0,
 
67
                                id, &in_cred, &out_cred);
 
68
    krb5_free_principal(context, in_cred.server);
 
69
    if (kret) {
 
70
        *minor_status = kret;
 
71
        return GSS_S_FAILURE;
 
72
    }
 
73
 
 
74
    *lifetime = out_cred->times.endtime;
 
75
    krb5_free_creds(context, out_cred);
 
76
 
 
77
    return GSS_S_COMPLETE;
 
78
}
 
79
 
 
80
 
 
81
 
 
82
 
 
83
static krb5_error_code
 
84
get_keytab(krb5_context context, krb5_keytab *keytab)
 
85
{
 
86
    char kt_name[256];
 
87
    krb5_error_code kret;
 
88
 
 
89
    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
 
90
 
 
91
    if (_gsskrb5_keytab != NULL) {
 
92
        kret = krb5_kt_get_name(context,
 
93
                                _gsskrb5_keytab,
 
94
                                kt_name, sizeof(kt_name));
 
95
        if (kret == 0)
 
96
            kret = krb5_kt_resolve(context, kt_name, keytab);
 
97
    } else
 
98
        kret = krb5_kt_default(context, keytab);
 
99
 
 
100
    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
 
101
 
 
102
    return (kret);
 
103
}
 
104
 
 
105
static OM_uint32 acquire_initiator_cred
 
106
                  (OM_uint32 * minor_status,
 
107
                   krb5_context context,
 
108
                   const gss_name_t desired_name,
 
109
                   OM_uint32 time_req,
 
110
                   const gss_OID_set desired_mechs,
 
111
                   gss_cred_usage_t cred_usage,
 
112
                   gsskrb5_cred handle,
 
113
                   gss_OID_set * actual_mechs,
 
114
                   OM_uint32 * time_rec
 
115
                  )
 
116
{
 
117
    OM_uint32 ret;
 
118
    krb5_creds cred;
 
119
    krb5_principal def_princ;
 
120
    krb5_get_init_creds_opt *opt;
 
121
    krb5_ccache ccache;
 
122
    krb5_keytab keytab;
 
123
    krb5_error_code kret;
 
124
 
 
125
    keytab = NULL;
 
126
    ccache = NULL;
 
127
    def_princ = NULL;
 
128
    ret = GSS_S_FAILURE;
 
129
    memset(&cred, 0, sizeof(cred));
 
130
 
 
131
    /*
 
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.
 
135
     */
 
136
 
 
137
    if (handle->principal) {
 
138
        kret = krb5_cc_cache_match (context,
 
139
                                    handle->principal,
 
140
                                    &ccache);
 
141
        if (kret == 0) {
 
142
            ret = GSS_S_COMPLETE;
 
143
            goto found;
 
144
        }
 
145
    }
 
146
 
 
147
    if (ccache == NULL) {
 
148
        kret = krb5_cc_default(context, &ccache);
 
149
        if (kret)
 
150
            goto end;
 
151
    }
 
152
    kret = krb5_cc_get_principal(context, ccache, &def_princ);
 
153
    if (kret != 0) {
 
154
        /* we'll try to use a keytab below */
 
155
        krb5_cc_close(context, ccache);
 
156
        def_princ = NULL;
 
157
        kret = 0;
 
158
    } else if (handle->principal == NULL)  {
 
159
        kret = krb5_copy_principal(context, def_princ, &handle->principal);
 
160
        if (kret)
 
161
            goto end;
 
162
    } else if (handle->principal != NULL &&
 
163
               krb5_principal_compare(context, handle->principal,
 
164
                                      def_princ) == FALSE) {
 
165
        krb5_free_principal(context, def_princ);
 
166
        def_princ = NULL;
 
167
        krb5_cc_close(context, ccache);
 
168
        ccache = NULL;
 
169
    }
 
170
    if (def_princ == NULL) {
 
171
        /* We have no existing credentials cache,
 
172
         * so attempt to get a TGT using a keytab.
 
173
         */
 
174
        if (handle->principal == NULL) {
 
175
            kret = krb5_get_default_principal(context, &handle->principal);
 
176
            if (kret)
 
177
                goto end;
 
178
        }
 
179
        kret = get_keytab(context, &keytab);
 
180
        if (kret)
 
181
            goto end;
 
182
        kret = krb5_get_init_creds_opt_alloc(context, &opt);
 
183
        if (kret)
 
184
            goto end;
 
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);
 
188
        if (kret)
 
189
            goto end;
 
190
        kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
 
191
        if (kret)
 
192
            goto end;
 
193
        kret = krb5_cc_initialize(context, ccache, cred.client);
 
194
        if (kret) {
 
195
            krb5_cc_destroy(context, ccache);
 
196
            goto end;
 
197
        }
 
198
        kret = krb5_cc_store_cred(context, ccache, &cred);
 
199
        if (kret) {
 
200
            krb5_cc_destroy(context, ccache);
 
201
            goto end;
 
202
        }
 
203
        handle->lifetime = cred.times.endtime;
 
204
        handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
 
205
    } else {
 
206
 
 
207
        ret = __gsskrb5_ccache_lifetime(minor_status,
 
208
                                        context,
 
209
                                        ccache,
 
210
                                        handle->principal,
 
211
                                        &handle->lifetime);
 
212
        if (ret != GSS_S_COMPLETE) {
 
213
            krb5_cc_close(context, ccache);
 
214
            goto end;
 
215
        }
 
216
        kret = 0;
 
217
    }
 
218
 found:
 
219
    handle->ccache = ccache;
 
220
    ret = GSS_S_COMPLETE;
 
221
 
 
222
end:
 
223
    if (cred.client != NULL)
 
224
        krb5_free_cred_contents(context, &cred);
 
225
    if (def_princ != NULL)
 
226
        krb5_free_principal(context, def_princ);
 
227
    if (keytab != NULL)
 
228
        krb5_kt_close(context, keytab);
 
229
    if (ret != GSS_S_COMPLETE && kret != 0)
 
230
        *minor_status = kret;
 
231
    return (ret);
 
232
}
 
233
 
 
234
static OM_uint32 acquire_acceptor_cred
 
235
                  (OM_uint32 * minor_status,
 
236
                   krb5_context context,
 
237
                   const gss_name_t desired_name,
 
238
                   OM_uint32 time_req,
 
239
                   const gss_OID_set desired_mechs,
 
240
                   gss_cred_usage_t cred_usage,
 
241
                   gsskrb5_cred handle,
 
242
                   gss_OID_set * actual_mechs,
 
243
                   OM_uint32 * time_rec
 
244
                  )
 
245
{
 
246
    OM_uint32 ret;
 
247
    krb5_error_code kret;
 
248
 
 
249
    ret = GSS_S_FAILURE;
 
250
    kret = get_keytab(context, &handle->keytab);
 
251
    if (kret)
 
252
        goto end;
 
253
 
 
254
    /* check that the requested principal exists in the keytab */
 
255
    if (handle->principal) {
 
256
        krb5_keytab_entry entry;
 
257
 
 
258
        kret = krb5_kt_get_entry(context, handle->keytab,
 
259
                                 handle->principal, 0, 0, &entry);
 
260
        if (kret)
 
261
            goto end;
 
262
        krb5_kt_free_entry(context, &entry);
 
263
        ret = GSS_S_COMPLETE;
 
264
    } else {
 
265
        /*
 
266
         * Check if there is at least one entry in the keytab before
 
267
         * declaring it as an useful keytab.
 
268
         */
 
269
        krb5_keytab_entry tmp;
 
270
        krb5_kt_cursor c;
 
271
 
 
272
        kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
 
273
        if (kret)
 
274
            goto end;
 
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 */
 
278
        }
 
279
        krb5_kt_end_seq_get (context, handle->keytab, &c);
 
280
    }
 
281
end:
 
282
    if (ret != GSS_S_COMPLETE) {
 
283
        if (handle->keytab != NULL)
 
284
            krb5_kt_close(context, handle->keytab);
 
285
        if (kret != 0) {
 
286
            *minor_status = kret;
 
287
        }
 
288
    }
 
289
    return (ret);
 
290
}
 
291
 
 
292
OM_uint32 _gsskrb5_acquire_cred
 
293
(OM_uint32 * minor_status,
 
294
 const gss_name_t desired_name,
 
295
 OM_uint32 time_req,
 
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,
 
300
 OM_uint32 * time_rec
 
301
    )
 
302
{
 
303
    krb5_context context;
 
304
    gsskrb5_cred handle;
 
305
    OM_uint32 ret;
 
306
 
 
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;
 
310
    }
 
311
 
 
312
    GSSAPI_KRB5_INIT(&context);
 
313
 
 
314
    *output_cred_handle = NULL;
 
315
    if (time_rec)
 
316
        *time_rec = 0;
 
317
    if (actual_mechs)
 
318
        *actual_mechs = GSS_C_NO_OID_SET;
 
319
 
 
320
    if (desired_mechs) {
 
321
        int present = 0;
 
322
 
 
323
        ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
 
324
                                      desired_mechs, &present);
 
325
        if (ret)
 
326
            return ret;
 
327
        if (!present) {
 
328
            *minor_status = 0;
 
329
            return GSS_S_BAD_MECH;
 
330
        }
 
331
    }
 
332
 
 
333
    handle = calloc(1, sizeof(*handle));
 
334
    if (handle == NULL) {
 
335
        *minor_status = ENOMEM;
 
336
        return (GSS_S_FAILURE);
 
337
    }
 
338
 
 
339
    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
 
340
 
 
341
    if (desired_name != GSS_C_NO_NAME) {
 
342
 
 
343
        ret = _gsskrb5_canon_name(minor_status, context, 0, desired_name,
 
344
                                  &handle->principal);
 
345
        if (ret) {
 
346
            HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
 
347
            free(handle);
 
348
            return ret;
 
349
        }
 
350
    }
 
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);
 
359
            free(handle);
 
360
            return (ret);
 
361
        }
 
362
    }
 
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);
 
370
            free(handle);
 
371
            return (ret);
 
372
        }
 
373
    }
 
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);
 
386
        free(handle);
 
387
        return (ret);
 
388
    }
 
389
    *minor_status = 0;
 
390
    if (time_rec) {
 
391
        ret = _gsskrb5_lifetime_left(minor_status,
 
392
                                     context,
 
393
                                     handle->lifetime,
 
394
                                     time_rec);
 
395
 
 
396
        if (ret)
 
397
            return ret;
 
398
    }
 
399
    handle->usage = cred_usage;
 
400
    *output_cred_handle = (gss_cred_id_t)handle;
 
401
    return (GSS_S_COMPLETE);
 
402
}