Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
[kai/samba.git] / source4 / heimdal / lib / gssapi / spnego / cred_stubs.c
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 #include "spnego/spnego_locl.h"
34
35 RCSID("$Id$");
36
37 OM_uint32
38 _gss_spnego_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
39 {
40     gssspnego_cred cred;
41     OM_uint32 ret;
42     
43     *minor_status = 0;
44
45     if (*cred_handle == GSS_C_NO_CREDENTIAL) {
46         return GSS_S_COMPLETE;
47     }
48     cred = (gssspnego_cred)*cred_handle;
49
50     ret = gss_release_cred(minor_status, &cred->negotiated_cred_id);
51
52     free(cred);
53     *cred_handle = GSS_C_NO_CREDENTIAL;
54
55     return ret;
56 }
57
58 OM_uint32
59 _gss_spnego_alloc_cred(OM_uint32 *minor_status,
60                        gss_cred_id_t mech_cred_handle,
61                        gss_cred_id_t *cred_handle)
62 {
63     gssspnego_cred cred;
64
65     if (*cred_handle != GSS_C_NO_CREDENTIAL) {
66         *minor_status = EINVAL;
67         return GSS_S_FAILURE;
68     }
69
70     cred = calloc(1, sizeof(*cred));
71     if (cred == NULL) {
72         *cred_handle = GSS_C_NO_CREDENTIAL;
73         *minor_status = ENOMEM;
74         return GSS_S_FAILURE;
75     }
76
77     cred->negotiated_cred_id = mech_cred_handle;
78
79     *cred_handle = (gss_cred_id_t)cred;
80
81     return GSS_S_COMPLETE; 
82 }
83
84 /*
85  * For now, just a simple wrapper that avoids recursion. When
86  * we support gss_{get,set}_neg_mechs() we will need to expose
87  * more functionality.
88  */
89 OM_uint32 _gss_spnego_acquire_cred
90 (OM_uint32 *minor_status,
91  const gss_name_t desired_name,
92  OM_uint32 time_req,
93  const gss_OID_set desired_mechs,
94  gss_cred_usage_t cred_usage,
95  gss_cred_id_t * output_cred_handle,
96  gss_OID_set * actual_mechs,
97  OM_uint32 * time_rec
98     )
99 {
100     const spnego_name dname = (const spnego_name)desired_name;
101     gss_name_t name = GSS_C_NO_NAME;
102     OM_uint32 ret, tmp;
103     gss_OID_set_desc actual_desired_mechs;
104     gss_OID_set mechs;
105     int i, j;
106     gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
107     gssspnego_cred cred;
108
109     *output_cred_handle = GSS_C_NO_CREDENTIAL;
110
111     if (dname) {
112         ret = gss_import_name(minor_status, &dname->value, &dname->type, &name);
113         if (ret) {
114             return ret;
115         }
116     }
117     
118     ret = gss_indicate_mechs(minor_status, &mechs);
119     if (ret != GSS_S_COMPLETE) {
120         gss_release_name(minor_status, &name);
121         return ret;
122     }
123
124     /* Remove ourselves from this list */
125     actual_desired_mechs.count = mechs->count;
126     actual_desired_mechs.elements = malloc(actual_desired_mechs.count *
127                                            sizeof(gss_OID_desc));
128     if (actual_desired_mechs.elements == NULL) {
129         *minor_status = ENOMEM;
130         ret = GSS_S_FAILURE;
131         goto out;
132     }
133
134     for (i = 0, j = 0; i < mechs->count; i++) {
135         if (gss_oid_equal(&mechs->elements[i], GSS_SPNEGO_MECHANISM))
136             continue;
137
138         actual_desired_mechs.elements[j] = mechs->elements[i];
139         j++;
140     }
141     actual_desired_mechs.count = j;
142
143     ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
144                                  &cred_handle);
145     if (ret != GSS_S_COMPLETE)
146         goto out;
147
148     cred = (gssspnego_cred)cred_handle;
149     ret = gss_acquire_cred(minor_status, name,
150                            time_req, &actual_desired_mechs,
151                            cred_usage,
152                            &cred->negotiated_cred_id,
153                            actual_mechs, time_rec);
154     if (ret != GSS_S_COMPLETE)
155         goto out;
156
157     *output_cred_handle = cred_handle;
158
159 out:
160     gss_release_name(minor_status, &name);
161     gss_release_oid_set(&tmp, &mechs);
162     if (actual_desired_mechs.elements != NULL) {
163         free(actual_desired_mechs.elements);
164     }
165     if (ret != GSS_S_COMPLETE) {
166         _gss_spnego_release_cred(&tmp, &cred_handle);
167     }
168
169     return ret;
170 }
171
172 OM_uint32 _gss_spnego_inquire_cred
173            (OM_uint32 * minor_status,
174             const gss_cred_id_t cred_handle,
175             gss_name_t * name,
176             OM_uint32 * lifetime,
177             gss_cred_usage_t * cred_usage,
178             gss_OID_set * mechanisms
179            )
180 {
181     gssspnego_cred cred;
182     spnego_name sname = NULL;
183     OM_uint32 ret;
184
185     if (cred_handle == GSS_C_NO_CREDENTIAL) {
186         *minor_status = 0;
187         return GSS_S_NO_CRED;
188     }
189
190     if (name) {
191         sname = calloc(1, sizeof(*sname));
192         if (sname == NULL) {
193             *minor_status = ENOMEM;
194             return GSS_S_FAILURE;
195         }
196     }
197
198     cred = (gssspnego_cred)cred_handle;
199
200     ret = gss_inquire_cred(minor_status,
201                            cred->negotiated_cred_id,
202                            sname ? &sname->mech : NULL,
203                            lifetime,
204                            cred_usage,
205                            mechanisms);
206     if (ret) {
207         if (sname)
208             free(sname);
209         return ret;
210     }
211     if (name)
212         *name = (gss_name_t)sname;
213
214     return ret;
215 }
216
217 OM_uint32 _gss_spnego_add_cred (
218             OM_uint32 * minor_status,
219             const gss_cred_id_t input_cred_handle,
220             const gss_name_t desired_name,
221             const gss_OID desired_mech,
222             gss_cred_usage_t cred_usage,
223             OM_uint32 initiator_time_req,
224             OM_uint32 acceptor_time_req,
225             gss_cred_id_t * output_cred_handle,
226             gss_OID_set * actual_mechs,
227             OM_uint32 * initiator_time_rec,
228             OM_uint32 * acceptor_time_rec
229            )
230 {
231     gss_cred_id_t spnego_output_cred_handle = GSS_C_NO_CREDENTIAL;
232     OM_uint32 ret, tmp;
233     gssspnego_cred input_cred, output_cred;
234
235     *output_cred_handle = GSS_C_NO_CREDENTIAL;
236
237     ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
238                                  &spnego_output_cred_handle);
239     if (ret)
240         return ret;
241
242     input_cred = (gssspnego_cred)input_cred_handle;
243     output_cred = (gssspnego_cred)spnego_output_cred_handle;
244
245     ret = gss_add_cred(minor_status,
246                        input_cred->negotiated_cred_id,
247                        desired_name,
248                        desired_mech,
249                        cred_usage,
250                        initiator_time_req,
251                        acceptor_time_req,
252                        &output_cred->negotiated_cred_id,
253                        actual_mechs,
254                        initiator_time_rec,
255                        acceptor_time_rec);
256     if (ret) {
257         _gss_spnego_release_cred(&tmp, &spnego_output_cred_handle);
258         return ret;
259     }
260
261     *output_cred_handle = spnego_output_cred_handle;
262
263     return GSS_S_COMPLETE;
264 }
265
266 OM_uint32 _gss_spnego_inquire_cred_by_mech (
267             OM_uint32 * minor_status,
268             const gss_cred_id_t cred_handle,
269             const gss_OID mech_type,
270             gss_name_t * name,
271             OM_uint32 * initiator_lifetime,
272             OM_uint32 * acceptor_lifetime,
273             gss_cred_usage_t * cred_usage
274            )
275 {
276     gssspnego_cred cred;
277     spnego_name sname = NULL;
278     OM_uint32 ret;
279
280     if (cred_handle == GSS_C_NO_CREDENTIAL) {
281         *minor_status = 0;
282         return GSS_S_NO_CRED;
283     }
284
285     if (name) {
286         sname = calloc(1, sizeof(*sname));
287         if (sname == NULL) {
288             *minor_status = ENOMEM;
289             return GSS_S_FAILURE;
290         }
291     }
292
293     cred = (gssspnego_cred)cred_handle;
294
295     ret = gss_inquire_cred_by_mech(minor_status,
296                                    cred->negotiated_cred_id,
297                                    mech_type,
298                                    sname ? &sname->mech : NULL,
299                                    initiator_lifetime,
300                                    acceptor_lifetime,
301                                    cred_usage);
302
303     if (ret) {
304         if (sname)
305             free(sname);
306         return ret;
307     }
308     if (name)
309         *name = (gss_name_t)sname;
310
311     return GSS_S_COMPLETE;
312 }
313
314 OM_uint32 _gss_spnego_inquire_cred_by_oid
315            (OM_uint32 * minor_status,
316             const gss_cred_id_t cred_handle,
317             const gss_OID desired_object,
318             gss_buffer_set_t *data_set)
319 {
320     gssspnego_cred cred;
321     OM_uint32 ret;
322
323     if (cred_handle == GSS_C_NO_CREDENTIAL) {
324         *minor_status = 0;
325         return GSS_S_NO_CRED;
326     }
327     cred = (gssspnego_cred)cred_handle;
328
329     ret = gss_inquire_cred_by_oid(minor_status,
330                                   cred->negotiated_cred_id,
331                                   desired_object,
332                                   data_set);
333
334     return ret;
335 }
336
337 OM_uint32
338 _gss_spnego_set_cred_option (OM_uint32 *minor_status,
339                              gss_cred_id_t *cred_handle,
340                              const gss_OID object,
341                              const gss_buffer_t value)
342 {
343     gssspnego_cred cred;
344
345     if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
346         *minor_status = 0;
347         return GSS_S_NO_CRED;
348     }
349
350     cred = (gssspnego_cred)*cred_handle;
351     return gss_set_cred_option(minor_status,
352                               &cred->negotiated_cred_id,
353                               object,
354                               value);
355 }
356