r19604: This is a massive commit, and I appologise in advance for it's size.
[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: cred_stubs.c,v 1.5 2006/10/07 22:27:04 lha Exp $");
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     OM_uint32 ret, tmp;
101     gss_OID_set_desc actual_desired_mechs;
102     gss_OID_set mechs;
103     int i, j;
104     gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
105     gssspnego_cred cred;
106
107     *output_cred_handle = GSS_C_NO_CREDENTIAL;
108
109     ret = gss_indicate_mechs(minor_status, &mechs);
110     if (ret != GSS_S_COMPLETE)
111         return ret;
112
113     /* Remove ourselves from this list */
114     actual_desired_mechs.count = mechs->count;
115     actual_desired_mechs.elements = malloc(actual_desired_mechs.count *
116                                            sizeof(gss_OID_desc));
117     if (actual_desired_mechs.elements == NULL) {
118         *minor_status = ENOMEM;
119         ret = GSS_S_FAILURE;
120         goto out;
121     }
122
123     for (i = 0, j = 0; i < mechs->count; i++) {
124         if (gss_oid_equal(&mechs->elements[i], GSS_SPNEGO_MECHANISM))
125             continue;
126
127         actual_desired_mechs.elements[j] = mechs->elements[i];
128         j++;
129     }
130     actual_desired_mechs.count = j;
131
132     ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
133                                  &cred_handle);
134     if (ret != GSS_S_COMPLETE)
135         goto out;
136
137     cred = (gssspnego_cred)cred_handle;
138     ret = gss_acquire_cred(minor_status, desired_name,
139                            time_req, &actual_desired_mechs,
140                            cred_usage,
141                            &cred->negotiated_cred_id,
142                            actual_mechs, time_rec);
143     if (ret != GSS_S_COMPLETE)
144         goto out;
145
146     *output_cred_handle = cred_handle;
147
148 out:
149     gss_release_oid_set(&tmp, &mechs);
150     if (actual_desired_mechs.elements != NULL) {
151         free(actual_desired_mechs.elements);
152     }
153     if (ret != GSS_S_COMPLETE) {
154         _gss_spnego_release_cred(&tmp, &cred_handle);
155     }
156
157     return ret;
158 }
159
160 OM_uint32 _gss_spnego_inquire_cred
161            (OM_uint32 * minor_status,
162             const gss_cred_id_t cred_handle,
163             gss_name_t * name,
164             OM_uint32 * lifetime,
165             gss_cred_usage_t * cred_usage,
166             gss_OID_set * mechanisms
167            )
168 {
169     gssspnego_cred cred;
170     OM_uint32 ret;
171
172     if (cred_handle == GSS_C_NO_CREDENTIAL) {
173         *minor_status = 0;
174         return GSS_S_NO_CRED;
175     }
176
177     cred = (gssspnego_cred)cred_handle;
178
179     ret = gss_inquire_cred(minor_status,
180                            cred->negotiated_cred_id,
181                            name,
182                            lifetime,
183                            cred_usage,
184                            mechanisms);
185
186     return ret;
187 }
188
189 OM_uint32 _gss_spnego_add_cred (
190             OM_uint32 * minor_status,
191             const gss_cred_id_t input_cred_handle,
192             const gss_name_t desired_name,
193             const gss_OID desired_mech,
194             gss_cred_usage_t cred_usage,
195             OM_uint32 initiator_time_req,
196             OM_uint32 acceptor_time_req,
197             gss_cred_id_t * output_cred_handle,
198             gss_OID_set * actual_mechs,
199             OM_uint32 * initiator_time_rec,
200             OM_uint32 * acceptor_time_rec
201            )
202 {
203     gss_cred_id_t spnego_output_cred_handle = GSS_C_NO_CREDENTIAL;
204     OM_uint32 ret, tmp;
205     gssspnego_cred input_cred, output_cred;
206
207     *output_cred_handle = GSS_C_NO_CREDENTIAL;
208
209     ret = _gss_spnego_alloc_cred(minor_status, GSS_C_NO_CREDENTIAL,
210                                  &spnego_output_cred_handle);
211     if (ret)
212         return ret;
213
214     input_cred = (gssspnego_cred)input_cred_handle;
215     output_cred = (gssspnego_cred)spnego_output_cred_handle;
216
217     ret = gss_add_cred(minor_status,
218                        input_cred->negotiated_cred_id,
219                        desired_name,
220                        desired_mech,
221                        cred_usage,
222                        initiator_time_req,
223                        acceptor_time_req,
224                        &output_cred->negotiated_cred_id,
225                        actual_mechs,
226                        initiator_time_rec,
227                        acceptor_time_rec);
228     if (ret) {
229         _gss_spnego_release_cred(&tmp, &spnego_output_cred_handle);
230         return ret;
231     }
232
233     *output_cred_handle = spnego_output_cred_handle;
234
235     return GSS_S_COMPLETE;
236 }
237
238 OM_uint32 _gss_spnego_inquire_cred_by_mech (
239             OM_uint32 * minor_status,
240             const gss_cred_id_t cred_handle,
241             const gss_OID mech_type,
242             gss_name_t * name,
243             OM_uint32 * initiator_lifetime,
244             OM_uint32 * acceptor_lifetime,
245             gss_cred_usage_t * cred_usage
246            )
247 {
248     gssspnego_cred cred;
249     OM_uint32 ret;
250
251     if (cred_handle == GSS_C_NO_CREDENTIAL) {
252         *minor_status = 0;
253         return GSS_S_NO_CRED;
254     }
255
256     cred = (gssspnego_cred)cred_handle;
257
258     ret = gss_inquire_cred_by_mech(minor_status,
259                                    cred->negotiated_cred_id,
260                                    mech_type,
261                                    name,
262                                    initiator_lifetime,
263                                    acceptor_lifetime,
264                                    cred_usage);
265
266     return ret;
267 }
268
269 OM_uint32 _gss_spnego_inquire_cred_by_oid
270            (OM_uint32 * minor_status,
271             const gss_cred_id_t cred_handle,
272             const gss_OID desired_object,
273             gss_buffer_set_t *data_set)
274 {
275     gssspnego_cred cred;
276     OM_uint32 ret;
277
278     if (cred_handle == GSS_C_NO_CREDENTIAL) {
279         *minor_status = 0;
280         return GSS_S_NO_CRED;
281     }
282     cred = (gssspnego_cred)cred_handle;
283
284     ret = gss_inquire_cred_by_oid(minor_status,
285                                   cred->negotiated_cred_id,
286                                   desired_object,
287                                   data_set);
288
289     return ret;
290 }
291