bc3b7c7f921fa63e22ffae61b217cb5d6da22ed7
[krb5.git] / src / lib / gssapi / krb5 / krb5_gss_glue.c
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
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
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
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
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)krb5_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
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
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
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
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
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
338 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
339                                             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
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
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 }