Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
34914 views
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
31
static OM_uint32
32
parse_header(const gss_buffer_t input_token, gss_OID mech_oid)
33
{
34
unsigned char *p = input_token->value;
35
size_t len = input_token->length;
36
size_t a, b;
37
38
/*
39
* Token must start with [APPLICATION 0] SEQUENCE.
40
* But if it doesn't assume it is DCE-STYLE Kerberos!
41
*/
42
if (len == 0)
43
return (GSS_S_DEFECTIVE_TOKEN);
44
45
p++;
46
len--;
47
48
/*
49
* Decode the length and make sure it agrees with the
50
* token length.
51
*/
52
if (len == 0)
53
return (GSS_S_DEFECTIVE_TOKEN);
54
if ((*p & 0x80) == 0) {
55
a = *p;
56
p++;
57
len--;
58
} else {
59
b = *p & 0x7f;
60
p++;
61
len--;
62
if (len < b)
63
return (GSS_S_DEFECTIVE_TOKEN);
64
a = 0;
65
while (b) {
66
a = (a << 8) | *p;
67
p++;
68
len--;
69
b--;
70
}
71
}
72
if (a != len)
73
return (GSS_S_DEFECTIVE_TOKEN);
74
75
/*
76
* Decode the OID for the mechanism. Simplify life by
77
* assuming that the OID length is less than 128 bytes.
78
*/
79
if (len < 2 || *p != 0x06)
80
return (GSS_S_DEFECTIVE_TOKEN);
81
if ((p[1] & 0x80) || p[1] > (len - 2))
82
return (GSS_S_DEFECTIVE_TOKEN);
83
mech_oid->length = p[1];
84
p += 2;
85
len -= 2;
86
mech_oid->elements = p;
87
88
return GSS_S_COMPLETE;
89
}
90
91
static gss_OID_desc krb5_mechanism =
92
{9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
93
static gss_OID_desc ntlm_mechanism =
94
{10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")};
95
static gss_OID_desc spnego_mechanism =
96
{6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")};
97
98
static OM_uint32
99
choose_mech(const gss_buffer_t input, gss_OID mech_oid)
100
{
101
OM_uint32 status;
102
103
/*
104
* First try to parse the gssapi token header and see if it's a
105
* correct header, use that in the first hand.
106
*/
107
108
status = parse_header(input, mech_oid);
109
if (status == GSS_S_COMPLETE)
110
return GSS_S_COMPLETE;
111
112
/*
113
* Lets guess what mech is really is, callback function to mech ??
114
*/
115
116
if (input->length > 8 &&
117
memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0)
118
{
119
*mech_oid = ntlm_mechanism;
120
return GSS_S_COMPLETE;
121
} else if (input->length != 0 &&
122
((const char *)input->value)[0] == 0x6E)
123
{
124
/* Could be a raw AP-REQ (check for APPLICATION tag) */
125
*mech_oid = krb5_mechanism;
126
return GSS_S_COMPLETE;
127
} else if (input->length == 0) {
128
/*
129
* There is the a wierd mode of SPNEGO (in CIFS and
130
* SASL GSS-SPENGO where the first token is zero
131
* length and the acceptor returns a mech_list, lets
132
* hope that is what is happening now.
133
*
134
* http://msdn.microsoft.com/en-us/library/cc213114.aspx
135
* "NegTokenInit2 Variation for Server-Initiation"
136
*/
137
*mech_oid = spnego_mechanism;
138
return GSS_S_COMPLETE;
139
}
140
return status;
141
}
142
143
144
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
145
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
gss_OID mech_ret_type = NULL;
165
166
*minor_status = 0;
167
if (src_name)
168
*src_name = GSS_C_NO_NAME;
169
if (mech_type)
170
*mech_type = GSS_C_NO_OID;
171
if (ret_flags)
172
*ret_flags = 0;
173
if (time_rec)
174
*time_rec = 0;
175
if (delegated_cred_handle)
176
*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
177
_mg_buffer_zero(output_token);
178
179
180
/*
181
* If this is the first call (*context_handle is NULL), we must
182
* parse the input token to figure out the mechanism to use.
183
*/
184
if (*context_handle == GSS_C_NO_CONTEXT) {
185
gss_OID_desc mech_oid;
186
187
major_status = choose_mech(input_token, &mech_oid);
188
if (major_status != GSS_S_COMPLETE)
189
return major_status;
190
191
/*
192
* Now that we have a mechanism, we can find the
193
* implementation.
194
*/
195
ctx = malloc(sizeof(struct _gss_context));
196
if (!ctx) {
197
*minor_status = ENOMEM;
198
return (GSS_S_DEFECTIVE_TOKEN);
199
}
200
memset(ctx, 0, sizeof(struct _gss_context));
201
m = ctx->gc_mech = __gss_get_mechanism(&mech_oid);
202
if (!m) {
203
free(ctx);
204
return (GSS_S_BAD_MECH);
205
}
206
*context_handle = (gss_ctx_id_t) ctx;
207
} else {
208
m = ctx->gc_mech;
209
}
210
211
if (cred) {
212
HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link)
213
if (mc->gmc_mech == m)
214
break;
215
if (!mc) {
216
gss_delete_sec_context(&junk, context_handle, NULL);
217
return (GSS_S_BAD_MECH);
218
}
219
acceptor_mc = mc->gmc_cred;
220
} else {
221
acceptor_mc = GSS_C_NO_CREDENTIAL;
222
}
223
delegated_mc = GSS_C_NO_CREDENTIAL;
224
225
mech_ret_flags = 0;
226
major_status = m->gm_accept_sec_context(minor_status,
227
&ctx->gc_ctx,
228
acceptor_mc,
229
input_token,
230
input_chan_bindings,
231
&src_mn,
232
&mech_ret_type,
233
output_token,
234
&mech_ret_flags,
235
time_rec,
236
&delegated_mc);
237
if (major_status != GSS_S_COMPLETE &&
238
major_status != GSS_S_CONTINUE_NEEDED)
239
{
240
_gss_mg_error(m, major_status, *minor_status);
241
gss_delete_sec_context(&junk, context_handle, NULL);
242
return (major_status);
243
}
244
245
if (mech_type)
246
*mech_type = mech_ret_type;
247
248
if (src_name && src_mn) {
249
/*
250
* Make a new name and mark it as an MN.
251
*/
252
struct _gss_name *name = _gss_make_name(m, src_mn);
253
254
if (!name) {
255
m->gm_release_name(minor_status, &src_mn);
256
gss_delete_sec_context(&junk, context_handle, NULL);
257
return (GSS_S_FAILURE);
258
}
259
*src_name = (gss_name_t) name;
260
} else if (src_mn) {
261
m->gm_release_name(minor_status, &src_mn);
262
}
263
264
if (mech_ret_flags & GSS_C_DELEG_FLAG) {
265
if (!delegated_cred_handle) {
266
m->gm_release_cred(minor_status, &delegated_mc);
267
mech_ret_flags &=
268
~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
269
} else if (gss_oid_equal(mech_ret_type, &m->gm_mech_oid) == 0) {
270
/*
271
* If the returned mech_type is not the same
272
* as the mech, assume its pseudo mech type
273
* and the returned type is already a
274
* mech-glue object
275
*/
276
*delegated_cred_handle = delegated_mc;
277
278
} else if (delegated_mc) {
279
struct _gss_cred *dcred;
280
struct _gss_mechanism_cred *dmc;
281
282
dcred = malloc(sizeof(struct _gss_cred));
283
if (!dcred) {
284
*minor_status = ENOMEM;
285
gss_delete_sec_context(&junk, context_handle, NULL);
286
return (GSS_S_FAILURE);
287
}
288
HEIM_SLIST_INIT(&dcred->gc_mc);
289
dmc = malloc(sizeof(struct _gss_mechanism_cred));
290
if (!dmc) {
291
free(dcred);
292
*minor_status = ENOMEM;
293
gss_delete_sec_context(&junk, context_handle, NULL);
294
return (GSS_S_FAILURE);
295
}
296
dmc->gmc_mech = m;
297
dmc->gmc_mech_oid = &m->gm_mech_oid;
298
dmc->gmc_cred = delegated_mc;
299
HEIM_SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link);
300
301
*delegated_cred_handle = (gss_cred_id_t) dcred;
302
}
303
}
304
305
if (ret_flags)
306
*ret_flags = mech_ret_flags;
307
return (major_status);
308
}
309
310