~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.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) 2004, PADL Software Pty Ltd.
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 *
 
12
 * 2. Redistributions in binary form must reproduce the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer in the
 
14
 *    documentation and/or other materials provided with the distribution.
 
15
 *
 
16
 * 3. Neither the name of PADL Software nor the names of its contributors
 
17
 *    may be used to endorse or promote products derived from this software
 
18
 *    without specific prior written permission.
 
19
 *
 
20
 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
 
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
 
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
30
 * SUCH DAMAGE.
 
31
 */
 
32
 
 
33
#include "krb5/gsskrb5_locl.h"
 
34
 
 
35
RCSID("$Id$");
 
36
 
 
37
static int
 
38
oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
 
39
{
 
40
    int ret;
 
41
    heim_oid oid;
 
42
    heim_oid prefix;
 
43
 
 
44
    *suffix = 0;
 
45
 
 
46
    ret = der_get_oid(oid_enc->elements, oid_enc->length,
 
47
                      &oid, NULL);
 
48
    if (ret) {
 
49
        return 0;
 
50
    }
 
51
 
 
52
    ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
 
53
                      &prefix, NULL);
 
54
    if (ret) {
 
55
        der_free_oid(&oid);
 
56
        return 0;
 
57
    }
 
58
 
 
59
    ret = 0;
 
60
 
 
61
    if (oid.length - 1 == prefix.length) {
 
62
        *suffix = oid.components[oid.length - 1];
 
63
        oid.length--;
 
64
        ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
 
65
        oid.length++;
 
66
    }
 
67
 
 
68
    der_free_oid(&oid);
 
69
    der_free_oid(&prefix);
 
70
 
 
71
    return ret;
 
72
}
 
73
 
 
74
static OM_uint32 inquire_sec_context_tkt_flags
 
75
           (OM_uint32 *minor_status,
 
76
            const gsskrb5_ctx context_handle,
 
77
            gss_buffer_set_t *data_set)
 
78
{
 
79
    OM_uint32 tkt_flags;
 
80
    unsigned char buf[4];
 
81
    gss_buffer_desc value;
 
82
 
 
83
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
84
 
 
85
    if (context_handle->ticket == NULL) {
 
86
        HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
87
        _gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags");
 
88
        *minor_status = EINVAL;
 
89
        return GSS_S_BAD_MECH;
 
90
    }
 
91
 
 
92
    tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags);
 
93
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
94
 
 
95
    _gsskrb5_encode_om_uint32(tkt_flags, buf);
 
96
    value.length = sizeof(buf);
 
97
    value.value = buf;
 
98
 
 
99
    return gss_add_buffer_set_member(minor_status,
 
100
                                     &value,
 
101
                                     data_set);
 
102
}
 
103
 
 
104
enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY };
 
105
 
 
106
static OM_uint32 inquire_sec_context_get_subkey
 
107
           (OM_uint32 *minor_status,
 
108
            const gsskrb5_ctx context_handle,
 
109
            krb5_context context,
 
110
            enum keytype keytype,
 
111
            gss_buffer_set_t *data_set)
 
112
{
 
113
    krb5_keyblock *key = NULL;
 
114
    krb5_storage *sp = NULL;
 
115
    krb5_data data;
 
116
    OM_uint32 maj_stat = GSS_S_COMPLETE;
 
117
    krb5_error_code ret;
 
118
 
 
119
    krb5_data_zero(&data);
 
120
 
 
121
    sp = krb5_storage_emem();
 
122
    if (sp == NULL) {
 
123
        _gsskrb5_clear_status();
 
124
        ret = ENOMEM;
 
125
        goto out;
 
126
    }
 
127
 
 
128
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
129
    switch(keytype) {
 
130
    case ACCEPTOR_KEY:
 
131
        ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key);
 
132
        break;
 
133
    case INITIATOR_KEY:
 
134
        ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key);
 
135
        break;
 
136
    case TOKEN_KEY:
 
137
        ret = _gsskrb5i_get_token_key(context_handle, context, &key);
 
138
        break;
 
139
    default:
 
140
        _gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype);
 
141
        ret = EINVAL;
 
142
        break;
 
143
   }
 
144
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
145
    if (ret)
 
146
        goto out;
 
147
    if (key == NULL) {
 
148
        _gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype);
 
149
        ret = EINVAL;
 
150
        goto out;
 
151
    }
 
152
 
 
153
    ret = krb5_store_keyblock(sp, *key);
 
154
    krb5_free_keyblock (context, key);
 
155
    if (ret)
 
156
        goto out;
 
157
 
 
158
    ret = krb5_storage_to_data(sp, &data);
 
159
    if (ret)
 
160
        goto out;
 
161
 
 
162
    {
 
163
        gss_buffer_desc value;
 
164
        
 
165
        value.length = data.length;
 
166
        value.value = data.data;
 
167
        
 
168
        maj_stat = gss_add_buffer_set_member(minor_status,
 
169
                                             &value,
 
170
                                             data_set);
 
171
    }
 
172
 
 
173
out:
 
174
    krb5_data_free(&data);
 
175
    if (sp)
 
176
        krb5_storage_free(sp);
 
177
    if (ret) {
 
178
        *minor_status = ret;
 
179
        maj_stat = GSS_S_FAILURE;
 
180
    }
 
181
    return maj_stat;
 
182
}
 
183
 
 
184
static OM_uint32 inquire_sec_context_authz_data
 
185
           (OM_uint32 *minor_status,
 
186
            const gsskrb5_ctx context_handle,
 
187
            krb5_context context,
 
188
            unsigned ad_type,
 
189
            gss_buffer_set_t *data_set)
 
190
{
 
191
    krb5_data data;
 
192
    gss_buffer_desc ad_data;
 
193
    OM_uint32 ret;
 
194
 
 
195
    *minor_status = 0;
 
196
    *data_set = GSS_C_NO_BUFFER_SET;
 
197
 
 
198
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
199
    if (context_handle->ticket == NULL) {
 
200
        HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
201
        *minor_status = EINVAL;
 
202
        _gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from");
 
203
        return GSS_S_NO_CONTEXT;
 
204
    }
 
205
 
 
206
    ret = krb5_ticket_get_authorization_data_type(context,
 
207
                                                  context_handle->ticket,
 
208
                                                  ad_type,
 
209
                                                  &data);
 
210
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
211
    if (ret) {
 
212
        *minor_status = ret;
 
213
        return GSS_S_FAILURE;
 
214
    }
 
215
 
 
216
    ad_data.value = data.data;
 
217
    ad_data.length = data.length;
 
218
 
 
219
    ret = gss_add_buffer_set_member(minor_status,
 
220
                                    &ad_data,
 
221
                                    data_set);
 
222
 
 
223
    krb5_data_free(&data);
 
224
 
 
225
    return ret;
 
226
}
 
227
 
 
228
static OM_uint32 inquire_sec_context_has_updated_spnego
 
229
           (OM_uint32 *minor_status,
 
230
            const gsskrb5_ctx context_handle,
 
231
            gss_buffer_set_t *data_set)
 
232
{
 
233
    int is_updated = 0;
 
234
 
 
235
    *minor_status = 0;
 
236
    *data_set = GSS_C_NO_BUFFER_SET;
 
237
 
 
238
    /*
 
239
     * For Windows SPNEGO implementations, both the initiator and the
 
240
     * acceptor are assumed to have been updated if a "newer" [CLAR] or
 
241
     * different enctype is negotiated for use by the Kerberos GSS-API
 
242
     * mechanism.
 
243
     */
 
244
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
245
    _gsskrb5i_is_cfx(context_handle, &is_updated);
 
246
    if (is_updated == 0) {
 
247
        krb5_keyblock *acceptor_subkey;
 
248
 
 
249
        if (context_handle->more_flags & LOCAL)
 
250
            acceptor_subkey = context_handle->auth_context->remote_subkey;
 
251
        else
 
252
            acceptor_subkey = context_handle->auth_context->local_subkey;
 
253
 
 
254
        if (acceptor_subkey != NULL)
 
255
            is_updated = (acceptor_subkey->keytype !=
 
256
                          context_handle->auth_context->keyblock->keytype);
 
257
    }
 
258
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
259
 
 
260
    return is_updated ? GSS_S_COMPLETE : GSS_S_FAILURE;
 
261
}
 
262
 
 
263
/*
 
264
 *
 
265
 */
 
266
 
 
267
static OM_uint32
 
268
export_lucid_sec_context_v1(OM_uint32 *minor_status,
 
269
                            gsskrb5_ctx context_handle,
 
270
                            krb5_context context,
 
271
                            gss_buffer_set_t *data_set)
 
272
{
 
273
    krb5_storage *sp = NULL;
 
274
    OM_uint32 major_status = GSS_S_COMPLETE;
 
275
    krb5_error_code ret;
 
276
    krb5_keyblock *key = NULL;
 
277
    int32_t number;
 
278
    int is_cfx;
 
279
    krb5_data data;
 
280
 
 
281
    *minor_status = 0;
 
282
 
 
283
    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 
284
 
 
285
    _gsskrb5i_is_cfx(context_handle, &is_cfx);
 
286
 
 
287
    sp = krb5_storage_emem();
 
288
    if (sp == NULL) {
 
289
        _gsskrb5_clear_status();
 
290
        ret = ENOMEM;
 
291
        goto out;
 
292
    }
 
293
 
 
294
    ret = krb5_store_int32(sp, 1);
 
295
    if (ret) goto out;
 
296
    ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0);
 
297
    if (ret) goto out;
 
298
    ret = krb5_store_int32(sp, context_handle->lifetime);
 
299
    if (ret) goto out;
 
300
    krb5_auth_con_getlocalseqnumber (context,
 
301
                                     context_handle->auth_context,
 
302
                                     &number);
 
303
    ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
 
304
    if (ret) goto out;
 
305
    ret = krb5_store_uint32(sp, (uint32_t)number);
 
306
    if (ret) goto out;
 
307
    krb5_auth_getremoteseqnumber (context,
 
308
                                  context_handle->auth_context,
 
309
                                  &number);
 
310
    ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
 
311
    if (ret) goto out;
 
312
    ret = krb5_store_uint32(sp, (uint32_t)number);
 
313
    if (ret) goto out;
 
314
    ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
 
315
    if (ret) goto out;
 
316
 
 
317
    ret = _gsskrb5i_get_token_key(context_handle, context, &key);
 
318
    if (ret) goto out;
 
319
 
 
320
    if (is_cfx == 0) {
 
321
        int sign_alg, seal_alg;
 
322
 
 
323
        switch (key->keytype) {
 
324
        case ETYPE_DES_CBC_CRC:
 
325
        case ETYPE_DES_CBC_MD4:
 
326
        case ETYPE_DES_CBC_MD5:
 
327
            sign_alg = 0;
 
328
            seal_alg = 0;
 
329
            break;
 
330
        case ETYPE_DES3_CBC_MD5:
 
331
        case ETYPE_DES3_CBC_SHA1:
 
332
            sign_alg = 4;
 
333
            seal_alg = 2;
 
334
            break;
 
335
        case ETYPE_ARCFOUR_HMAC_MD5:
 
336
        case ETYPE_ARCFOUR_HMAC_MD5_56:
 
337
            sign_alg = 17;
 
338
            seal_alg = 16;
 
339
            break;
 
340
        default:
 
341
            sign_alg = -1;
 
342
            seal_alg = -1;
 
343
            break;
 
344
        }
 
345
        ret = krb5_store_int32(sp, sign_alg);
 
346
        if (ret) goto out;
 
347
        ret = krb5_store_int32(sp, seal_alg);
 
348
        if (ret) goto out;
 
349
        /* ctx_key */
 
350
        ret = krb5_store_keyblock(sp, *key);
 
351
        if (ret) goto out;
 
352
    } else {
 
353
        int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0;
 
354
 
 
355
        /* have_acceptor_subkey */
 
356
        ret = krb5_store_int32(sp, subkey_p);
 
357
        if (ret) goto out;
 
358
        /* ctx_key */
 
359
        ret = krb5_store_keyblock(sp, *key);
 
360
        if (ret) goto out;
 
361
        /* acceptor_subkey */
 
362
        if (subkey_p) {
 
363
            ret = krb5_store_keyblock(sp, *key);
 
364
            if (ret) goto out;
 
365
        }
 
366
    }
 
367
    ret = krb5_storage_to_data(sp, &data);
 
368
    if (ret) goto out;
 
369
 
 
370
    {
 
371
        gss_buffer_desc ad_data;
 
372
 
 
373
        ad_data.value = data.data;
 
374
        ad_data.length = data.length;
 
375
 
 
376
        ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set);
 
377
        krb5_data_free(&data);
 
378
        if (ret)
 
379
            goto out;
 
380
    }
 
381
 
 
382
out:
 
383
    if (key)
 
384
        krb5_free_keyblock (context, key);
 
385
    if (sp)
 
386
        krb5_storage_free(sp);
 
387
    if (ret) {
 
388
        *minor_status = ret;
 
389
        major_status = GSS_S_FAILURE;
 
390
    }
 
391
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 
392
    return major_status;
 
393
}
 
394
 
 
395
static OM_uint32
 
396
get_authtime(OM_uint32 *minor_status,
 
397
             gsskrb5_ctx ctx,
 
398
             gss_buffer_set_t *data_set)
 
399
 
 
400
{
 
401
    gss_buffer_desc value;
 
402
    unsigned char buf[4];
 
403
    OM_uint32 authtime;
 
404
 
 
405
    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 
406
    if (ctx->ticket == NULL) {
 
407
        HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 
408
        _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from");
 
409
        *minor_status = EINVAL;
 
410
        return GSS_S_FAILURE;
 
411
    }
 
412
 
 
413
    authtime = ctx->ticket->ticket.authtime;
 
414
 
 
415
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 
416
 
 
417
    _gsskrb5_encode_om_uint32(authtime, buf);
 
418
    value.length = sizeof(buf);
 
419
    value.value = buf;
 
420
 
 
421
    return gss_add_buffer_set_member(minor_status,
 
422
                                     &value,
 
423
                                     data_set);
 
424
}
 
425
 
 
426
 
 
427
static OM_uint32
 
428
get_service_keyblock
 
429
        (OM_uint32 *minor_status,
 
430
         gsskrb5_ctx ctx,
 
431
         gss_buffer_set_t *data_set)
 
432
{
 
433
    krb5_storage *sp = NULL;
 
434
    krb5_data data;
 
435
    OM_uint32 maj_stat = GSS_S_COMPLETE;
 
436
    krb5_error_code ret = EINVAL;
 
437
 
 
438
    sp = krb5_storage_emem();
 
439
    if (sp == NULL) {
 
440
        _gsskrb5_clear_status();
 
441
        *minor_status = ENOMEM;
 
442
        return GSS_S_FAILURE;
 
443
    }
 
444
 
 
445
    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 
446
    if (ctx->service_keyblock == NULL) {
 
447
        HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 
448
        _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
 
449
        *minor_status = EINVAL;
 
450
        return GSS_S_FAILURE;
 
451
    }
 
452
 
 
453
    krb5_data_zero(&data);
 
454
 
 
455
    ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
 
456
 
 
457
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 
458
 
 
459
    if (ret)
 
460
        goto out;
 
461
 
 
462
    ret = krb5_storage_to_data(sp, &data);
 
463
    if (ret)
 
464
        goto out;
 
465
 
 
466
    {
 
467
        gss_buffer_desc value;
 
468
        
 
469
        value.length = data.length;
 
470
        value.value = data.data;
 
471
        
 
472
        maj_stat = gss_add_buffer_set_member(minor_status,
 
473
                                             &value,
 
474
                                             data_set);
 
475
    }
 
476
 
 
477
out:
 
478
    krb5_data_free(&data);
 
479
    if (sp)
 
480
        krb5_storage_free(sp);
 
481
    if (ret) {
 
482
        *minor_status = ret;
 
483
        maj_stat = GSS_S_FAILURE;
 
484
    }
 
485
    return maj_stat;
 
486
}
 
487
/*
 
488
 *
 
489
 */
 
490
 
 
491
OM_uint32 _gsskrb5_inquire_sec_context_by_oid
 
492
           (OM_uint32 *minor_status,
 
493
            const gss_ctx_id_t context_handle,
 
494
            const gss_OID desired_object,
 
495
            gss_buffer_set_t *data_set)
 
496
{
 
497
    krb5_context context;
 
498
    const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
 
499
    unsigned suffix;
 
500
 
 
501
    if (ctx == NULL) {
 
502
        *minor_status = EINVAL;
 
503
        return GSS_S_NO_CONTEXT;
 
504
    }
 
505
 
 
506
    GSSAPI_KRB5_INIT (&context);
 
507
 
 
508
    if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
 
509
        return inquire_sec_context_tkt_flags(minor_status,
 
510
                                             ctx,
 
511
                                             data_set);
 
512
    } else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
 
513
        return inquire_sec_context_has_updated_spnego(minor_status,
 
514
                                                      ctx,
 
515
                                                      data_set);
 
516
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
 
517
        return inquire_sec_context_get_subkey(minor_status,
 
518
                                              ctx,
 
519
                                              context,
 
520
                                              TOKEN_KEY,
 
521
                                              data_set);
 
522
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
 
523
        return inquire_sec_context_get_subkey(minor_status,
 
524
                                              ctx,
 
525
                                              context,
 
526
                                              INITIATOR_KEY,
 
527
                                              data_set);
 
528
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
 
529
        return inquire_sec_context_get_subkey(minor_status,
 
530
                                              ctx,
 
531
                                              context,
 
532
                                              ACCEPTOR_KEY,
 
533
                                              data_set);
 
534
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
 
535
        return get_authtime(minor_status, ctx, data_set);
 
536
    } else if (oid_prefix_equal(desired_object,
 
537
                                GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
 
538
                                &suffix)) {
 
539
        return inquire_sec_context_authz_data(minor_status,
 
540
                                              ctx,
 
541
                                              context,
 
542
                                              suffix,
 
543
                                              data_set);
 
544
    } else if (oid_prefix_equal(desired_object,
 
545
                                GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
 
546
                                &suffix)) {
 
547
        if (suffix == 1)
 
548
            return export_lucid_sec_context_v1(minor_status,
 
549
                                               ctx,
 
550
                                               context,
 
551
                                               data_set);
 
552
        *minor_status = 0;
 
553
        return GSS_S_FAILURE;
 
554
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
 
555
        return get_service_keyblock(minor_status, ctx, data_set);
 
556
    } else {
 
557
        *minor_status = 0;
 
558
        return GSS_S_FAILURE;
 
559
    }
 
560
}
 
561