~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.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) 2005 Doug Rabson
 
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
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
24
 * SUCH DAMAGE.
 
25
 *
 
26
 *      $FreeBSD: src/lib/libgssapi/gss_accept_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
 
27
 */
 
28
 
 
29
#include "mech_locl.h"
 
30
RCSID("$Id$");
 
31
 
 
32
static OM_uint32
 
33
parse_header(const gss_buffer_t input_token, gss_OID mech_oid)
 
34
{
 
35
        unsigned char *p = input_token->value;
 
36
        size_t len = input_token->length;
 
37
        size_t a, b;
 
38
        
 
39
        /*
 
40
         * Token must start with [APPLICATION 0] SEQUENCE.
 
41
         * But if it doesn't assume it is DCE-STYLE Kerberos!
 
42
         */
 
43
        if (len == 0)
 
44
                return (GSS_S_DEFECTIVE_TOKEN);
 
45
        
 
46
        p++;
 
47
        len--;
 
48
                
 
49
        /*
 
50
         * Decode the length and make sure it agrees with the
 
51
         * token length.
 
52
         */
 
53
        if (len == 0)
 
54
                return (GSS_S_DEFECTIVE_TOKEN);
 
55
        if ((*p & 0x80) == 0) {
 
56
                a = *p;
 
57
                p++;
 
58
                len--;
 
59
        } else {
 
60
                b = *p & 0x7f;
 
61
                p++;
 
62
                len--;
 
63
                if (len < b)
 
64
                    return (GSS_S_DEFECTIVE_TOKEN);
 
65
                a = 0;
 
66
                while (b) {
 
67
                    a = (a << 8) | *p;
 
68
                    p++;
 
69
                    len--;
 
70
                    b--;
 
71
                }
 
72
        }
 
73
        if (a != len)
 
74
                return (GSS_S_DEFECTIVE_TOKEN);
 
75
                
 
76
        /*
 
77
         * Decode the OID for the mechanism. Simplify life by
 
78
         * assuming that the OID length is less than 128 bytes.
 
79
         */
 
80
        if (len < 2 || *p != 0x06)
 
81
                return (GSS_S_DEFECTIVE_TOKEN);
 
82
        if ((p[1] & 0x80) || p[1] > (len - 2))
 
83
                return (GSS_S_DEFECTIVE_TOKEN);
 
84
        mech_oid->length = p[1];
 
85
        p += 2;
 
86
        len -= 2;
 
87
        mech_oid->elements = p;
 
88
        
 
89
        return GSS_S_COMPLETE;
 
90
}               
 
91
 
 
92
static gss_OID_desc krb5_mechanism =
 
93
    {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
 
94
static gss_OID_desc ntlm_mechanism =
 
95
    {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")};
 
96
static gss_OID_desc spnego_mechanism =
 
97
    {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")};
 
98
 
 
99
static OM_uint32
 
100
choose_mech(const gss_buffer_t input, gss_OID mech_oid)
 
101
{
 
102
        OM_uint32 status;
 
103
 
 
104
        /*
 
105
         * First try to parse the gssapi token header and see if it's a
 
106
         * correct header, use that in the first hand.
 
107
         */
 
108
 
 
109
        status = parse_header(input, mech_oid);
 
110
        if (status == GSS_S_COMPLETE)
 
111
            return GSS_S_COMPLETE;
 
112
 
 
113
        /*
 
114
         * Lets guess what mech is really is, callback function to mech ??
 
115
         */
 
116
 
 
117
        if (input->length > 8 &&
 
118
            memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0)
 
119
        {
 
120
                *mech_oid = ntlm_mechanism;
 
121
                return GSS_S_COMPLETE;
 
122
        } else if (input->length != 0 &&
 
123
                   ((const char *)input->value)[0] == 0x6E)
 
124
        {
 
125
                /* Could be a raw AP-REQ (check for APPLICATION tag) */
 
126
                *mech_oid = krb5_mechanism;
 
127
                return GSS_S_COMPLETE;
 
128
        } else if (input->length == 0) {
 
129
                /*
 
130
                 * There is the a wierd mode of SPNEGO (in CIFS and
 
131
                 * SASL GSS-SPENGO where the first token is zero
 
132
                 * length and the acceptor returns a mech_list, lets
 
133
                 * hope that is what is happening now.
 
134
                 *
 
135
                 * http://msdn.microsoft.com/en-us/library/cc213114.aspx
 
136
                 * "NegTokenInit2 Variation for Server-Initiation"
 
137
                 */
 
138
                *mech_oid = spnego_mechanism;
 
139
                return GSS_S_COMPLETE;
 
140
        }
 
141
        return status;
 
142
}
 
143
 
 
144
 
 
145
OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
 
146
    gss_ctx_id_t *context_handle,
 
147
    const gss_cred_id_t acceptor_cred_handle,
 
148
    const gss_buffer_t input_token,
 
149
    const gss_channel_bindings_t input_chan_bindings,
 
150
    gss_name_t *src_name,
 
151
    gss_OID *mech_type,
 
152
    gss_buffer_t output_token,
 
153
    OM_uint32 *ret_flags,
 
154
    OM_uint32 *time_rec,
 
155
    gss_cred_id_t *delegated_cred_handle)
 
156
{
 
157
        OM_uint32 major_status, mech_ret_flags, junk;
 
158
        gssapi_mech_interface m;
 
159
        struct _gss_context *ctx = (struct _gss_context *) *context_handle;
 
160
        struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle;
 
161
        struct _gss_mechanism_cred *mc;
 
162
        gss_cred_id_t acceptor_mc, delegated_mc;
 
163
        gss_name_t src_mn;
 
164
 
 
165
        *minor_status = 0;
 
166
        if (src_name)
 
167
            *src_name = GSS_C_NO_NAME;
 
168
        if (mech_type)
 
169
            *mech_type = GSS_C_NO_OID;
 
170
        if (ret_flags)
 
171
            *ret_flags = 0;
 
172
        if (time_rec)
 
173
            *time_rec = 0;
 
174
        if (delegated_cred_handle)
 
175
            *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 
176
        _mg_buffer_zero(output_token);
 
177
 
 
178
 
 
179
        /*
 
180
         * If this is the first call (*context_handle is NULL), we must
 
181
         * parse the input token to figure out the mechanism to use.
 
182
         */
 
183
        if (*context_handle == GSS_C_NO_CONTEXT) {
 
184
                gss_OID_desc mech_oid;
 
185
 
 
186
                major_status = choose_mech(input_token, &mech_oid);
 
187
                if (major_status != GSS_S_COMPLETE)
 
188
                        return major_status;
 
189
 
 
190
                /*
 
191
                 * Now that we have a mechanism, we can find the
 
192
                 * implementation.
 
193
                 */
 
194
                ctx = malloc(sizeof(struct _gss_context));
 
195
                if (!ctx) {
 
196
                        *minor_status = ENOMEM;
 
197
                        return (GSS_S_DEFECTIVE_TOKEN);
 
198
                }
 
199
                memset(ctx, 0, sizeof(struct _gss_context));
 
200
                m = ctx->gc_mech = __gss_get_mechanism(&mech_oid);
 
201
                if (!m) {
 
202
                        free(ctx);
 
203
                        return (GSS_S_BAD_MECH);
 
204
                }
 
205
                *context_handle = (gss_ctx_id_t) ctx;
 
206
        } else {
 
207
                m = ctx->gc_mech;
 
208
        }
 
209
 
 
210
        if (cred) {
 
211
                SLIST_FOREACH(mc, &cred->gc_mc, gmc_link)
 
212
                        if (mc->gmc_mech == m)
 
213
                                break;
 
214
                if (!mc) {
 
215
                        gss_delete_sec_context(&junk, context_handle, NULL);
 
216
                        return (GSS_S_BAD_MECH);
 
217
                }
 
218
                acceptor_mc = mc->gmc_cred;
 
219
        } else {
 
220
                acceptor_mc = GSS_C_NO_CREDENTIAL;
 
221
        }
 
222
        delegated_mc = GSS_C_NO_CREDENTIAL;
 
223
        
 
224
        mech_ret_flags = 0;
 
225
        major_status = m->gm_accept_sec_context(minor_status,
 
226
            &ctx->gc_ctx,
 
227
            acceptor_mc,
 
228
            input_token,
 
229
            input_chan_bindings,
 
230
            &src_mn,
 
231
            mech_type,
 
232
            output_token,
 
233
            &mech_ret_flags,
 
234
            time_rec,
 
235
            &delegated_mc);
 
236
        if (major_status != GSS_S_COMPLETE &&
 
237
            major_status != GSS_S_CONTINUE_NEEDED)
 
238
        {
 
239
                _gss_mg_error(m, major_status, *minor_status);
 
240
                gss_delete_sec_context(&junk, context_handle, NULL);
 
241
                return (major_status);
 
242
        }
 
243
 
 
244
        if (src_name && src_mn) {
 
245
                /*
 
246
                 * Make a new name and mark it as an MN.
 
247
                 */
 
248
                struct _gss_name *name = _gss_make_name(m, src_mn);
 
249
 
 
250
                if (!name) {
 
251
                        m->gm_release_name(minor_status, &src_mn);
 
252
                        gss_delete_sec_context(&junk, context_handle, NULL);
 
253
                        return (GSS_S_FAILURE);
 
254
                }
 
255
                *src_name = (gss_name_t) name;
 
256
        } else if (src_mn) {
 
257
                m->gm_release_name(minor_status, &src_mn);
 
258
        }
 
259
 
 
260
        if (mech_ret_flags & GSS_C_DELEG_FLAG) {
 
261
                if (!delegated_cred_handle) {
 
262
                        m->gm_release_cred(minor_status, &delegated_mc);
 
263
                        *ret_flags &= ~GSS_C_DELEG_FLAG;
 
264
                } else if (delegated_mc) {
 
265
                        struct _gss_cred *dcred;
 
266
                        struct _gss_mechanism_cred *dmc;
 
267
 
 
268
                        dcred = malloc(sizeof(struct _gss_cred));
 
269
                        if (!dcred) {
 
270
                                *minor_status = ENOMEM;
 
271
                                gss_delete_sec_context(&junk, context_handle, NULL);
 
272
                                return (GSS_S_FAILURE);
 
273
                        }
 
274
                        SLIST_INIT(&dcred->gc_mc);
 
275
                        dmc = malloc(sizeof(struct _gss_mechanism_cred));
 
276
                        if (!dmc) {
 
277
                                free(dcred);
 
278
                                *minor_status = ENOMEM;
 
279
                                gss_delete_sec_context(&junk, context_handle, NULL);
 
280
                                return (GSS_S_FAILURE);
 
281
                        }
 
282
                        dmc->gmc_mech = m;
 
283
                        dmc->gmc_mech_oid = &m->gm_mech_oid;
 
284
                        dmc->gmc_cred = delegated_mc;
 
285
                        SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link);
 
286
 
 
287
                        *delegated_cred_handle = (gss_cred_id_t) dcred;
 
288
                }
 
289
        }
 
290
 
 
291
        if (ret_flags)
 
292
            *ret_flags = mech_ret_flags;
 
293
        return (major_status);
 
294
}