xref: /freebsd/crypto/heimdal/lib/gssapi/spnego/cred_stubs.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
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 20619 2007-05-08 13:43:45Z lha $");
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