1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 by OpenVision Technologies, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name of OpenVision not be used
10 * in advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. OpenVision makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23 /*
24 * Copyright (c) 2006-2008, Novell, Inc.
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions are met:
29 *
30 * * Redistributions of source code must retain the above copyright notice,
31 * this list of conditions and the following disclaimer.
32 * * Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * * The copyright holder's name is not used to endorse or promote products
36 * derived from this software without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
42 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
43 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
44 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
46 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
48 * POSSIBILITY OF SUCH DAMAGE.
49 */
50
51 /*
52 * $Id$
53 */
54
55 #include "gssapiP_krb5.h"
56
57 OM_uint32 KRB5_CALLCONV
gss_krb5_get_tkt_flags(OM_uint32 * minor_status,gss_ctx_id_t context_handle,krb5_flags * ticket_flags)58 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
59 gss_ctx_id_t context_handle,
60 krb5_flags *ticket_flags)
61 {
62 static const gss_OID_desc req_oid = {
63 GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH,
64 GSS_KRB5_GET_TKT_FLAGS_OID };
65 OM_uint32 major_status;
66 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
67
68 if (ticket_flags == NULL)
69 return GSS_S_CALL_INACCESSIBLE_WRITE;
70
71 major_status = gss_inquire_sec_context_by_oid(minor_status,
72 context_handle,
73 (gss_OID)&req_oid,
74 &data_set);
75 if (major_status != GSS_S_COMPLETE)
76 return major_status;
77
78 if (data_set == GSS_C_NO_BUFFER_SET ||
79 data_set->count != 1 ||
80 data_set->elements[0].length != sizeof(*ticket_flags)) {
81 *minor_status = EINVAL;
82 return GSS_S_FAILURE;
83 }
84
85 *ticket_flags = *((krb5_flags *)data_set->elements[0].value);
86
87 gss_release_buffer_set(minor_status, &data_set);
88
89 *minor_status = 0;
90
91 return GSS_S_COMPLETE;
92 }
93
94 OM_uint32 KRB5_CALLCONV
gss_krb5_copy_ccache(OM_uint32 * minor_status,gss_cred_id_t cred_handle,krb5_ccache out_ccache)95 gss_krb5_copy_ccache(OM_uint32 *minor_status,
96 gss_cred_id_t cred_handle,
97 krb5_ccache out_ccache)
98 {
99 static const gss_OID_desc req_oid = {
100 GSS_KRB5_COPY_CCACHE_OID_LENGTH,
101 GSS_KRB5_COPY_CCACHE_OID };
102 OM_uint32 major_status;
103 gss_buffer_desc req_buffer;
104
105 if (out_ccache == NULL)
106 return GSS_S_CALL_INACCESSIBLE_WRITE;
107
108 req_buffer.value = out_ccache;
109 req_buffer.length = sizeof(out_ccache);
110
111 major_status = gss_set_cred_option(minor_status,
112 &cred_handle,
113 (gss_OID)&req_oid,
114 &req_buffer);
115
116 return major_status;
117 }
118
119 OM_uint32 KRB5_CALLCONV
gss_krb5_import_cred(OM_uint32 * minor_status,krb5_ccache id,krb5_principal keytab_principal,krb5_keytab keytab,gss_cred_id_t * cred)120 gss_krb5_import_cred(OM_uint32 *minor_status,
121 krb5_ccache id,
122 krb5_principal keytab_principal,
123 krb5_keytab keytab,
124 gss_cred_id_t *cred)
125 {
126 static const gss_OID_desc req_oid = {
127 GSS_KRB5_IMPORT_CRED_OID_LENGTH,
128 GSS_KRB5_IMPORT_CRED_OID };
129 OM_uint32 major_status;
130 struct krb5_gss_import_cred_req req;
131 gss_buffer_desc req_buffer;
132
133 if (cred == NULL)
134 return GSS_S_CALL_INACCESSIBLE_WRITE;
135
136 *cred = GSS_C_NO_CREDENTIAL;
137
138 req.id = id;
139 req.keytab_principal = keytab_principal;
140 req.keytab = keytab;
141
142 req_buffer.value = &req;
143 req_buffer.length = sizeof(req);
144
145 major_status = gss_set_cred_option(minor_status,
146 cred,
147 (gss_OID)&req_oid,
148 &req_buffer);
149
150 return major_status;
151 }
152
153 OM_uint32 KRB5_CALLCONV
gss_krb5_export_lucid_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,OM_uint32 version,void ** kctx)154 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
155 gss_ctx_id_t *context_handle,
156 OM_uint32 version,
157 void **kctx)
158 {
159 unsigned char oid_buf[GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH + 6];
160 gss_OID_desc req_oid;
161 OM_uint32 major_status, minor;
162 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
163
164 if (kctx == NULL)
165 return GSS_S_CALL_INACCESSIBLE_WRITE;
166
167 *kctx = NULL;
168
169 req_oid.elements = oid_buf;
170 req_oid.length = sizeof(oid_buf);
171
172 major_status = generic_gss_oid_compose(minor_status,
173 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
174 GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
175 (int)version,
176 &req_oid);
177 if (GSS_ERROR(major_status))
178 return major_status;
179
180 major_status = gss_inquire_sec_context_by_oid(minor_status,
181 *context_handle,
182 &req_oid,
183 &data_set);
184 if (GSS_ERROR(major_status))
185 return major_status;
186
187 if (data_set == GSS_C_NO_BUFFER_SET ||
188 data_set->count != 1 ||
189 data_set->elements[0].length != sizeof(void *)) {
190 *minor_status = EINVAL;
191 return GSS_S_FAILURE;
192 }
193
194 *kctx = *((void **)data_set->elements[0].value);
195
196 /* Clean up the context state (it is an error for
197 * someone to attempt to use this context again)
198 */
199 (void)gss_delete_sec_context(minor_status, context_handle, NULL);
200 *context_handle = GSS_C_NO_CONTEXT;
201
202 generic_gss_release_buffer_set(&minor, &data_set);
203
204 return GSS_S_COMPLETE;
205 }
206
207 OM_uint32 KRB5_CALLCONV
gss_krb5_set_allowable_enctypes(OM_uint32 * minor_status,gss_cred_id_t cred,OM_uint32 num_ktypes,krb5_enctype * ktypes)208 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
209 gss_cred_id_t cred,
210 OM_uint32 num_ktypes,
211 krb5_enctype *ktypes)
212 {
213 static const gss_OID_desc req_oid = {
214 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH,
215 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID };
216 OM_uint32 major_status;
217 struct krb5_gss_set_allowable_enctypes_req req;
218 gss_buffer_desc req_buffer;
219
220 req.num_ktypes = num_ktypes;
221 req.ktypes = ktypes;
222
223 req_buffer.length = sizeof(req);
224 req_buffer.value = &req;
225
226 major_status = gss_set_cred_option(minor_status,
227 &cred,
228 (gss_OID)&req_oid,
229 &req_buffer);
230
231 return major_status;
232 }
233
234 OM_uint32 KRB5_CALLCONV
gss_krb5_ccache_name(OM_uint32 * minor_status,const char * name,const char ** out_name)235 gss_krb5_ccache_name(OM_uint32 *minor_status,
236 const char *name,
237 const char **out_name)
238 {
239 static const gss_OID_desc req_oid = {
240 GSS_KRB5_CCACHE_NAME_OID_LENGTH,
241 GSS_KRB5_CCACHE_NAME_OID };
242 OM_uint32 major_status;
243 struct krb5_gss_ccache_name_req req;
244 gss_buffer_desc req_buffer;
245
246 req.name = name;
247 req.out_name = out_name;
248
249 req_buffer.length = sizeof(req);
250 req_buffer.value = &req;
251
252 major_status = gssspi_mech_invoke(minor_status,
253 (gss_OID)gss_mech_krb5,
254 (gss_OID)&req_oid,
255 &req_buffer);
256
257 return major_status;
258 }
259
260 OM_uint32 KRB5_CALLCONV
gss_krb5_free_lucid_sec_context(OM_uint32 * minor_status,void * kctx)261 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *kctx)
262 {
263 static const gss_OID_desc req_oid = {
264 GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH,
265 GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID };
266 OM_uint32 major_status;
267 gss_buffer_desc req_buffer;
268
269 req_buffer.length = sizeof(kctx);
270 req_buffer.value = kctx;
271
272 major_status = gssspi_mech_invoke(minor_status,
273 (gss_OID)gss_mech_krb5,
274 (gss_OID)&req_oid,
275 &req_buffer);
276
277 return major_status;
278 }
279
280 OM_uint32 KRB5_CALLCONV
krb5_gss_register_acceptor_identity(const char * keytab)281 krb5_gss_register_acceptor_identity(const char *keytab)
282 {
283 static const gss_OID_desc req_oid = {
284 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH,
285 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID };
286 OM_uint32 major_status;
287 OM_uint32 minor_status;
288 gss_buffer_desc req_buffer;
289
290 req_buffer.length = (keytab == NULL) ? 0 : strlen(keytab);
291 req_buffer.value = (char *)keytab;
292
293 major_status = gssspi_mech_invoke(&minor_status,
294 (gss_OID)gss_mech_krb5,
295 (gss_OID)&req_oid,
296 &req_buffer);
297
298 return major_status;
299 }
300
301 #ifndef _WIN32
302 krb5_error_code
krb5_gss_use_kdc_context(void)303 krb5_gss_use_kdc_context(void)
304 {
305 static const gss_OID_desc req_oid = {
306 GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH,
307 GSS_KRB5_USE_KDC_CONTEXT_OID };
308 OM_uint32 major_status;
309 OM_uint32 minor_status;
310 gss_buffer_desc req_buffer;
311 krb5_error_code ret;
312
313 req_buffer.length = 0;
314 req_buffer.value = NULL;
315
316 major_status = gssspi_mech_invoke(&minor_status,
317 (gss_OID)gss_mech_krb5,
318 (gss_OID)&req_oid,
319 &req_buffer);
320
321 if (major_status != GSS_S_COMPLETE) {
322 if (minor_status != 0)
323 ret = (krb5_error_code)minor_status;
324 else
325 ret = KRB5KRB_ERR_GENERIC;
326 } else
327 ret = 0;
328
329 return ret;
330 }
331 #endif
332
333 /*
334 * This API should go away and be replaced with an accessor
335 * into a gss_name_t.
336 */
337 OM_uint32 KRB5_CALLCONV
gsskrb5_extract_authz_data_from_sec_context(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int ad_type,gss_buffer_t ad_data)338 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
339 const gss_ctx_id_t context_handle,
340 int ad_type,
341 gss_buffer_t ad_data)
342 {
343 gss_OID_desc req_oid;
344 unsigned char oid_buf[GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH + 6];
345 OM_uint32 major_status;
346 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
347
348 if (ad_data == NULL)
349 return GSS_S_CALL_INACCESSIBLE_WRITE;
350
351 req_oid.elements = oid_buf;
352 req_oid.length = sizeof(oid_buf);
353
354 major_status = generic_gss_oid_compose(minor_status,
355 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
356 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
357 ad_type,
358 &req_oid);
359 if (GSS_ERROR(major_status))
360 return major_status;
361
362 major_status = gss_inquire_sec_context_by_oid(minor_status,
363 context_handle,
364 (gss_OID)&req_oid,
365 &data_set);
366 if (major_status != GSS_S_COMPLETE) {
367 return major_status;
368 }
369
370 if (data_set == GSS_C_NO_BUFFER_SET ||
371 data_set->count != 1) {
372 return GSS_S_FAILURE;
373 }
374
375 ad_data->length = data_set->elements[0].length;
376 ad_data->value = data_set->elements[0].value;
377
378 data_set->elements[0].length = 0;
379 data_set->elements[0].value = NULL;
380
381 data_set->count = 0;
382
383 gss_release_buffer_set(minor_status, &data_set);
384
385 return GSS_S_COMPLETE;
386 }
387
388 OM_uint32 KRB5_CALLCONV
gss_krb5_set_cred_rcache(OM_uint32 * minor_status,gss_cred_id_t cred,krb5_rcache rcache)389 gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
390 gss_cred_id_t cred,
391 krb5_rcache rcache)
392 {
393 static const gss_OID_desc req_oid = {
394 GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH,
395 GSS_KRB5_SET_CRED_RCACHE_OID };
396 OM_uint32 major_status;
397 gss_buffer_desc req_buffer;
398
399 req_buffer.length = sizeof(rcache);
400 req_buffer.value = rcache;
401
402 major_status = gss_set_cred_option(minor_status,
403 &cred,
404 (gss_OID)&req_oid,
405 &req_buffer);
406
407 return major_status;
408 }
409
410 OM_uint32 KRB5_CALLCONV
gsskrb5_extract_authtime_from_sec_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,krb5_timestamp * authtime)411 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
412 gss_ctx_id_t context_handle,
413 krb5_timestamp *authtime)
414 {
415 static const gss_OID_desc req_oid = {
416 GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
417 GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID };
418 OM_uint32 major_status;
419 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
420
421 if (authtime == NULL)
422 return GSS_S_CALL_INACCESSIBLE_WRITE;
423
424 major_status = gss_inquire_sec_context_by_oid(minor_status,
425 context_handle,
426 (gss_OID)&req_oid,
427 &data_set);
428 if (major_status != GSS_S_COMPLETE)
429 return major_status;
430
431 if (data_set == GSS_C_NO_BUFFER_SET ||
432 data_set->count != 1 ||
433 data_set->elements[0].length != sizeof(*authtime)) {
434 *minor_status = EINVAL;
435 return GSS_S_FAILURE;
436 }
437
438 *authtime = *((krb5_timestamp *)data_set->elements[0].value);
439
440 gss_release_buffer_set(minor_status, &data_set);
441
442 *minor_status = 0;
443
444 return GSS_S_COMPLETE;
445 }
446