Line data Source code
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 : /*
34 : * glue routine for _gsskrb5_inquire_sec_context_by_oid
35 : */
36 :
37 : #include "gsskrb5_locl.h"
38 :
39 : static OM_uint32
40 107063 : get_bool(OM_uint32 *minor_status,
41 : const gss_buffer_t value,
42 : int *flag)
43 : {
44 107063 : if (value->value == NULL || value->length != 1) {
45 0 : *minor_status = EINVAL;
46 0 : return GSS_S_FAILURE;
47 : }
48 107063 : *flag = *((const char *)value->value) != 0;
49 107063 : return GSS_S_COMPLETE;
50 : }
51 :
52 : static OM_uint32
53 96452 : get_string(OM_uint32 *minor_status,
54 : const gss_buffer_t value,
55 : char **str)
56 : {
57 96452 : if (value == NULL || value->length == 0) {
58 6959 : *str = NULL;
59 : } else {
60 89493 : *str = malloc(value->length + 1);
61 89493 : if (*str == NULL) {
62 0 : *minor_status = 0;
63 0 : return GSS_S_UNAVAILABLE;
64 : }
65 89493 : memcpy(*str, value->value, value->length);
66 89493 : (*str)[value->length] = '\0';
67 : }
68 93260 : return GSS_S_COMPLETE;
69 : }
70 :
71 : static OM_uint32
72 0 : get_int32(OM_uint32 *minor_status,
73 : const gss_buffer_t value,
74 : OM_uint32 *ret)
75 : {
76 0 : *minor_status = 0;
77 0 : if (value == NULL || value->length == 0)
78 0 : *ret = 0;
79 0 : else if (value->length == sizeof(*ret))
80 0 : memcpy(ret, value->value, sizeof(*ret));
81 : else
82 0 : return GSS_S_UNAVAILABLE;
83 :
84 0 : return GSS_S_COMPLETE;
85 : }
86 :
87 : static OM_uint32
88 0 : set_int32(OM_uint32 *minor_status,
89 : const gss_buffer_t value,
90 : OM_uint32 set)
91 : {
92 0 : *minor_status = 0;
93 0 : if (value->length == sizeof(set))
94 0 : memcpy(value->value, &set, sizeof(set));
95 : else
96 0 : return GSS_S_UNAVAILABLE;
97 :
98 0 : return GSS_S_COMPLETE;
99 : }
100 :
101 : /*
102 : * GSS_KRB5_IMPORT_RFC4121_CONTEXT_X is an internal, private interface
103 : * to allow SAnon to create a skeletal context for using RFC4121 message
104 : * protection services.
105 : *
106 : * rfc4121_args ::= initiator_flag || flags || enctype || session key
107 : */
108 : static OM_uint32
109 0 : make_rfc4121_context(OM_uint32 *minor,
110 : krb5_context context,
111 : gss_ctx_id_t *context_handle,
112 : gss_const_buffer_t rfc4121_args)
113 : {
114 0 : OM_uint32 major = GSS_S_FAILURE, tmp;
115 0 : krb5_error_code ret;
116 0 : krb5_storage *sp = NULL;
117 0 : gsskrb5_ctx ctx = NULL;
118 0 : uint8_t initiator_flag;
119 0 : int32_t enctype;
120 0 : size_t keysize;
121 0 : krb5_keyblock *key;
122 :
123 0 : *minor = 0;
124 :
125 0 : sp = krb5_storage_from_readonly_mem(rfc4121_args->value, rfc4121_args->length);
126 0 : if (sp == NULL) {
127 0 : ret = ENOMEM;
128 0 : goto out;
129 : }
130 :
131 0 : krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST);
132 :
133 0 : ctx = calloc(1, sizeof(*ctx));
134 0 : if (ctx == NULL) {
135 0 : ret = ENOMEM;
136 0 : goto out;
137 : }
138 :
139 0 : ret = krb5_ret_uint8(sp, &initiator_flag);
140 0 : if (ret != 0)
141 0 : goto out;
142 :
143 0 : ret = krb5_ret_uint32(sp, &ctx->flags);
144 0 : if (ret != 0)
145 0 : goto out;
146 :
147 0 : ctx->more_flags = IS_CFX | ACCEPTOR_SUBKEY | OPEN;
148 0 : if (initiator_flag)
149 0 : ctx->more_flags |= LOCAL;
150 :
151 0 : ctx->state = initiator_flag ? INITIATOR_READY : ACCEPTOR_READY;
152 :
153 0 : ret = krb5_ret_int32(sp, &enctype);
154 0 : if (ret != 0)
155 0 : goto out;
156 :
157 0 : ret = krb5_enctype_keysize(context, enctype, &keysize);
158 0 : if (ret != 0)
159 0 : goto out;
160 :
161 0 : ctx->auth_context = calloc(1, sizeof(*ctx->auth_context));
162 0 : if (ctx->auth_context == NULL) {
163 0 : ret = ENOMEM;
164 0 : goto out;
165 : }
166 :
167 0 : key = calloc(1, sizeof(*key));
168 0 : if (key == NULL) {
169 0 : ret = ENOMEM;
170 0 : goto out;
171 : }
172 0 : if (initiator_flag)
173 0 : ctx->auth_context->remote_subkey = key;
174 : else
175 0 : ctx->auth_context->local_subkey = key;
176 :
177 0 : key->keytype = enctype;
178 0 : key->keyvalue.data = malloc(keysize);
179 0 : if (key->keyvalue.data == NULL) {
180 0 : ret = ENOMEM;
181 0 : goto out;
182 : }
183 :
184 0 : if (krb5_storage_read(sp, key->keyvalue.data, keysize) != keysize) {
185 0 : ret = EINVAL;
186 0 : goto out;
187 : }
188 0 : key->keyvalue.length = keysize;
189 :
190 0 : ret = krb5_crypto_init(context, key, 0, &ctx->crypto);
191 0 : if (ret != 0)
192 0 : goto out;
193 :
194 0 : major = _gssapi_msg_order_create(minor, &ctx->order,
195 0 : _gssapi_msg_order_f(ctx->flags),
196 : 0, 0, 1);
197 0 : if (major != GSS_S_COMPLETE)
198 0 : goto out;
199 :
200 0 : out:
201 0 : krb5_storage_free(sp);
202 :
203 0 : if (major != GSS_S_COMPLETE) {
204 0 : if (*minor == 0)
205 0 : *minor = ret;
206 0 : _gsskrb5_delete_sec_context(&tmp, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER);
207 : } else {
208 0 : *context_handle = (gss_ctx_id_t)ctx;
209 : }
210 :
211 0 : return major;
212 : }
213 :
214 : OM_uint32 GSSAPI_CALLCONV
215 292289 : _gsskrb5_set_sec_context_option
216 : (OM_uint32 *minor_status,
217 : gss_ctx_id_t *context_handle,
218 : const gss_OID desired_object,
219 : const gss_buffer_t value)
220 : {
221 10214 : krb5_context context;
222 10214 : OM_uint32 maj_stat;
223 :
224 292289 : GSSAPI_KRB5_INIT (&context);
225 :
226 292289 : if (value == GSS_C_NO_BUFFER) {
227 0 : *minor_status = EINVAL;
228 0 : return GSS_S_FAILURE;
229 : }
230 :
231 292289 : if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) {
232 0 : gsskrb5_ctx ctx;
233 0 : int flag;
234 :
235 0 : if (*context_handle == GSS_C_NO_CONTEXT) {
236 0 : *minor_status = EINVAL;
237 0 : return GSS_S_NO_CONTEXT;
238 : }
239 :
240 0 : maj_stat = get_bool(minor_status, value, &flag);
241 0 : if (maj_stat != GSS_S_COMPLETE)
242 0 : return maj_stat;
243 :
244 0 : ctx = (gsskrb5_ctx)*context_handle;
245 0 : HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
246 0 : if (flag)
247 0 : ctx->more_flags |= COMPAT_OLD_DES3;
248 : else
249 0 : ctx->more_flags &= ~COMPAT_OLD_DES3;
250 0 : ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
251 0 : HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
252 0 : return GSS_S_COMPLETE;
253 292289 : } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) {
254 3192 : int flag;
255 :
256 107063 : maj_stat = get_bool(minor_status, value, &flag);
257 107063 : if (maj_stat != GSS_S_COMPLETE)
258 0 : return maj_stat;
259 :
260 107063 : krb5_set_dns_canonicalize_hostname(context, flag);
261 107063 : return GSS_S_COMPLETE;
262 :
263 185226 : } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) {
264 0 : char *str;
265 :
266 0 : maj_stat = get_string(minor_status, value, &str);
267 0 : if (maj_stat != GSS_S_COMPLETE)
268 0 : return maj_stat;
269 :
270 0 : maj_stat = _gsskrb5_register_acceptor_identity(minor_status, str);
271 0 : free(str);
272 :
273 0 : return maj_stat;
274 :
275 185226 : } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) {
276 3192 : char *str;
277 :
278 96452 : maj_stat = get_string(minor_status, value, &str);
279 96452 : if (maj_stat != GSS_S_COMPLETE)
280 0 : return maj_stat;
281 96452 : if (str == NULL) {
282 6959 : *minor_status = 0;
283 6959 : return GSS_S_CALL_INACCESSIBLE_READ;
284 : }
285 :
286 89493 : krb5_set_default_realm(context, str);
287 89493 : free(str);
288 :
289 89493 : *minor_status = 0;
290 89493 : return GSS_S_COMPLETE;
291 :
292 88774 : } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) {
293 :
294 88774 : *minor_status = EINVAL;
295 88774 : return GSS_S_FAILURE;
296 :
297 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) {
298 0 : OM_uint32 offset;
299 0 : time_t t;
300 :
301 0 : maj_stat = get_int32(minor_status, value, &offset);
302 0 : if (maj_stat != GSS_S_COMPLETE)
303 0 : return maj_stat;
304 :
305 0 : t = time(NULL) + offset;
306 :
307 0 : krb5_set_real_time(context, t, 0);
308 :
309 0 : *minor_status = 0;
310 0 : return GSS_S_COMPLETE;
311 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) {
312 0 : krb5_timestamp sec;
313 0 : int32_t usec;
314 0 : time_t t;
315 :
316 0 : t = time(NULL);
317 :
318 0 : krb5_us_timeofday (context, &sec, &usec);
319 :
320 0 : maj_stat = set_int32(minor_status, value, sec - t);
321 0 : if (maj_stat != GSS_S_COMPLETE)
322 0 : return maj_stat;
323 :
324 0 : *minor_status = 0;
325 0 : return GSS_S_COMPLETE;
326 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_PLUGIN_REGISTER_X)) {
327 0 : struct gsskrb5_krb5_plugin c;
328 :
329 0 : if (value->length != sizeof(c)) {
330 0 : *minor_status = EINVAL;
331 0 : return GSS_S_FAILURE;
332 : }
333 0 : memcpy(&c, value->value, sizeof(c));
334 0 : krb5_plugin_register(context, c.type, c.name, c.symbol);
335 :
336 0 : *minor_status = 0;
337 0 : return GSS_S_COMPLETE;
338 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) {
339 0 : struct gsskrb5_ccache_name_args *args = value->value;
340 :
341 0 : if (value->length != sizeof(*args)) {
342 0 : *minor_status = EINVAL;
343 0 : return GSS_S_FAILURE;
344 : }
345 :
346 0 : return _gsskrb5_krb5_ccache_name(minor_status, args->name, &args->out_name);
347 0 : } else if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_RFC4121_CONTEXT_X)) {
348 0 : return make_rfc4121_context(minor_status, context, context_handle, value);
349 : }
350 :
351 0 : *minor_status = EINVAL;
352 0 : return GSS_S_FAILURE;
353 : }
|