~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/gssapi/spnego/compat.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 "spnego/spnego_locl.h"
 
34
 
 
35
RCSID("$Id$");
 
36
 
 
37
/*
 
38
 * Apparently Microsoft got the OID wrong, and used
 
39
 * 1.2.840.48018.1.2.2 instead. We need both this and
 
40
 * the correct Kerberos OID here in order to deal with
 
41
 * this. Because this is manifest in SPNEGO only I'd
 
42
 * prefer to deal with this here rather than inside the
 
43
 * Kerberos mechanism.
 
44
 */
 
45
gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
 
46
        {9, (void *)"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"};
 
47
 
 
48
gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
 
49
        {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
 
50
 
 
51
/*
 
52
 * Allocate a SPNEGO context handle
 
53
 */
 
54
OM_uint32 _gss_spnego_alloc_sec_context (OM_uint32 * minor_status,
 
55
                                         gss_ctx_id_t *context_handle)
 
56
{
 
57
    gssspnego_ctx ctx;
 
58
 
 
59
    ctx = calloc(1, sizeof(*ctx));
 
60
    if (ctx == NULL) {
 
61
        *minor_status = ENOMEM;
 
62
        return GSS_S_FAILURE;
 
63
    }
 
64
 
 
65
    ctx->initiator_mech_types.len = 0;
 
66
    ctx->initiator_mech_types.val = NULL;
 
67
    ctx->preferred_mech_type = GSS_C_NO_OID;
 
68
    ctx->negotiated_mech_type = GSS_C_NO_OID;
 
69
    ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
 
70
 
 
71
    /*
 
72
     * Cache these so we can return them before returning
 
73
     * GSS_S_COMPLETE, even if the mechanism has itself
 
74
     * completed earlier
 
75
     */
 
76
    ctx->mech_flags = 0;
 
77
    ctx->mech_time_rec = 0;
 
78
    ctx->mech_src_name = GSS_C_NO_NAME;
 
79
 
 
80
    ctx->open = 0;
 
81
    ctx->local = 0;
 
82
    ctx->require_mic = 0;
 
83
    ctx->verified_mic = 0;
 
84
 
 
85
    HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
 
86
 
 
87
    *context_handle = (gss_ctx_id_t)ctx;
 
88
 
 
89
    return GSS_S_COMPLETE;
 
90
}
 
91
 
 
92
/*
 
93
 * Free a SPNEGO context handle. The caller must have acquired
 
94
 * the lock before this is called.
 
95
 */
 
96
OM_uint32 _gss_spnego_internal_delete_sec_context
 
97
           (OM_uint32 *minor_status,
 
98
            gss_ctx_id_t *context_handle,
 
99
            gss_buffer_t output_token
 
100
           )
 
101
{
 
102
    gssspnego_ctx ctx;
 
103
    OM_uint32 ret, minor;
 
104
 
 
105
    *minor_status = 0;
 
106
 
 
107
    if (context_handle == NULL) {
 
108
        return GSS_S_NO_CONTEXT;
 
109
    }
 
110
 
 
111
    if (output_token != GSS_C_NO_BUFFER) {
 
112
        output_token->length = 0;
 
113
        output_token->value = NULL;
 
114
    }
 
115
 
 
116
    ctx = (gssspnego_ctx)*context_handle;
 
117
    *context_handle = GSS_C_NO_CONTEXT;
 
118
 
 
119
    if (ctx == NULL) {
 
120
        return GSS_S_NO_CONTEXT;
 
121
    }
 
122
 
 
123
    if (ctx->initiator_mech_types.val != NULL)
 
124
        free_MechTypeList(&ctx->initiator_mech_types);
 
125
 
 
126
    gss_release_oid(&minor, &ctx->preferred_mech_type);
 
127
    ctx->negotiated_mech_type = GSS_C_NO_OID;
 
128
 
 
129
    gss_release_name(&minor, &ctx->target_name);
 
130
    gss_release_name(&minor, &ctx->mech_src_name);
 
131
 
 
132
    if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) {
 
133
        ret = gss_delete_sec_context(minor_status,
 
134
                                     &ctx->negotiated_ctx_id,
 
135
                                     output_token);
 
136
        ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
 
137
    } else {
 
138
        ret = GSS_S_COMPLETE;
 
139
    }
 
140
 
 
141
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 
142
    HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
 
143
 
 
144
    free(ctx);
 
145
    *context_handle = NULL;
 
146
 
 
147
    return ret;
 
148
}
 
149
 
 
150
/*
 
151
 * For compatability with the Windows SPNEGO implementation, the
 
152
 * default is to ignore the mechListMIC unless CFX is used and
 
153
 * a non-preferred mechanism was negotiated
 
154
 */
 
155
 
 
156
OM_uint32
 
157
_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
 
158
                                 gssspnego_ctx ctx,
 
159
                                 int *require_mic)
 
160
{
 
161
    gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET;
 
162
    OM_uint32 minor;
 
163
 
 
164
    *minor_status = 0;
 
165
    *require_mic = 0;
 
166
 
 
167
    if (ctx == NULL) {
 
168
        return GSS_S_COMPLETE;
 
169
    }
 
170
 
 
171
    if (ctx->require_mic) {
 
172
        /* Acceptor requested it: mandatory to honour */
 
173
        *require_mic = 1;
 
174
        return GSS_S_COMPLETE;
 
175
    }
 
176
 
 
177
    /*
 
178
     * Check whether peer indicated implicit support for updated SPNEGO
 
179
     * (eg. in the Kerberos case by using CFX)
 
180
     */
 
181
    if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
 
182
                                       GSS_C_PEER_HAS_UPDATED_SPNEGO,
 
183
                                       &buffer_set) == GSS_S_COMPLETE) {
 
184
        *require_mic = 1;
 
185
        gss_release_buffer_set(&minor, &buffer_set);
 
186
    }
 
187
 
 
188
    /* Safe-to-omit MIC rules follow */
 
189
    if (*require_mic) {
 
190
        if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) {
 
191
            *require_mic = 0;
 
192
        } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) &&
 
193
                   gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) {
 
194
            *require_mic = 0;
 
195
        }
 
196
    }
 
197
 
 
198
    return GSS_S_COMPLETE;
 
199
}
 
200
 
 
201
static int
 
202
add_mech_type(gss_OID mech_type,
 
203
              int includeMSCompatOID,
 
204
              MechTypeList *mechtypelist)
 
205
{
 
206
    MechType mech;
 
207
    int ret;
 
208
 
 
209
    if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
 
210
        return 0;
 
211
 
 
212
    if (includeMSCompatOID &&
 
213
        gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) {
 
214
        ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements,
 
215
                          _gss_spnego_mskrb_mechanism_oid_desc.length,
 
216
                          &mech,
 
217
                          NULL);
 
218
        if (ret)
 
219
            return ret;
 
220
        ret = add_MechTypeList(mechtypelist, &mech);
 
221
        free_MechType(&mech);
 
222
        if (ret)
 
223
            return ret;
 
224
    }
 
225
    ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
 
226
    if (ret)
 
227
        return ret;
 
228
    ret = add_MechTypeList(mechtypelist, &mech);
 
229
    free_MechType(&mech);
 
230
    return ret;
 
231
}
 
232
 
 
233
 
 
234
OM_uint32
 
235
_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
 
236
                                   gss_name_t target_name,
 
237
                                   OM_uint32 (*func)(gss_name_t, gss_OID),
 
238
                                   int includeMSCompatOID,
 
239
                                   const gssspnego_cred cred_handle,
 
240
                                   MechTypeList *mechtypelist,
 
241
                                   gss_OID *preferred_mech)
 
242
{
 
243
    gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
 
244
    gss_OID first_mech = GSS_C_NO_OID;
 
245
    OM_uint32 ret;
 
246
    int i;
 
247
 
 
248
    mechtypelist->len = 0;
 
249
    mechtypelist->val = NULL;
 
250
 
 
251
    if (cred_handle != NULL) {
 
252
        ret = gss_inquire_cred(minor_status,
 
253
                               cred_handle->negotiated_cred_id,
 
254
                               NULL,
 
255
                               NULL,
 
256
                               NULL,
 
257
                               &supported_mechs);
 
258
    } else {
 
259
        ret = gss_indicate_mechs(minor_status, &supported_mechs);
 
260
    }
 
261
 
 
262
    if (ret != GSS_S_COMPLETE) {
 
263
        return ret;
 
264
    }
 
265
 
 
266
    if (supported_mechs->count == 0) {
 
267
        *minor_status = ENOENT;
 
268
        gss_release_oid_set(minor_status, &supported_mechs);
 
269
        return GSS_S_FAILURE;
 
270
    }
 
271
 
 
272
    ret = (*func)(target_name, GSS_KRB5_MECHANISM);
 
273
    if (ret == GSS_S_COMPLETE) {
 
274
        ret = add_mech_type(GSS_KRB5_MECHANISM,
 
275
                            includeMSCompatOID,
 
276
                            mechtypelist);
 
277
        if (!GSS_ERROR(ret))
 
278
            first_mech = GSS_KRB5_MECHANISM;
 
279
    }
 
280
    ret = GSS_S_COMPLETE;
 
281
 
 
282
    for (i = 0; i < supported_mechs->count; i++) {
 
283
        OM_uint32 subret;
 
284
        if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
 
285
            continue;
 
286
        if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
 
287
            continue;
 
288
 
 
289
        subret = (*func)(target_name, &supported_mechs->elements[i]);
 
290
        if (subret != GSS_S_COMPLETE)
 
291
            continue;
 
292
 
 
293
        ret = add_mech_type(&supported_mechs->elements[i],
 
294
                            includeMSCompatOID,
 
295
                            mechtypelist);
 
296
        if (ret != 0) {
 
297
            *minor_status = ret;
 
298
            ret = GSS_S_FAILURE;
 
299
            break;
 
300
        }
 
301
        if (first_mech == GSS_C_NO_OID)
 
302
            first_mech = &supported_mechs->elements[i];
 
303
    }
 
304
 
 
305
    if (mechtypelist->len == 0) {
 
306
        gss_release_oid_set(minor_status, &supported_mechs);
 
307
        *minor_status = 0;
 
308
        return GSS_S_BAD_MECH;
 
309
    }
 
310
 
 
311
    if (preferred_mech != NULL) {
 
312
        ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
 
313
        if (ret != GSS_S_COMPLETE)
 
314
            free_MechTypeList(mechtypelist);
 
315
    }
 
316
    gss_release_oid_set(minor_status, &supported_mechs);
 
317
 
 
318
    return ret;
 
319
}