xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/inq_context.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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  * Copyright (c) 2006-2008, Novell, Inc.
52  * All rights reserved.
53  *
54  * Redistribution and use in source and binary forms, with or without
55  * modification, are permitted provided that the following conditions are met:
56  *
57  *   * Redistributions of source code must retain the above copyright notice,
58  *       this list of conditions and the following disclaimer.
59  *   * Redistributions in binary form must reproduce the above copyright
60  *       notice, this list of conditions and the following disclaimer in the
61  *       documentation and/or other materials provided with the distribution.
62  *   * The copyright holder's name is not used to endorse or promote products
63  *       derived from this software without specific prior written permission.
64  *
65  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
66  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
69  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
70  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
71  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
72  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
73  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
74  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
75  * POSSIBILITY OF SUCH DAMAGE.
76  */
77 
78 #include "gssapiP_krb5.h"
79 
80 OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_name_t * initiator_name,gss_name_t * acceptor_name,OM_uint32 * lifetime_rec,gss_OID * mech_type,OM_uint32 * ret_flags,int * locally_initiated,int * opened)81 krb5_gss_inquire_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
82                          gss_name_t *initiator_name, gss_name_t *acceptor_name,
83                          OM_uint32 *lifetime_rec, gss_OID *mech_type,
84                          OM_uint32 *ret_flags, int *locally_initiated,
85                          int *opened)
86 {
87     krb5_context context;
88     krb5_error_code code;
89     krb5_gss_ctx_id_rec *ctx;
90     krb5_gss_name_t initiator, acceptor;
91     krb5_timestamp now, start;
92     OM_uint32 lifetime;
93 
94     if (initiator_name)
95         *initiator_name = (gss_name_t) NULL;
96     if (acceptor_name)
97         *acceptor_name = (gss_name_t) NULL;
98 
99     ctx = (krb5_gss_ctx_id_rec *) context_handle;
100     context = ctx->k5_context;
101 
102     /* RFC 2743 states that a partially completed context must return
103      * flags, locally_initiated, and open, and *may* return mech_type. */
104     if (ctx->established) {
105         initiator = NULL;
106         acceptor = NULL;
107 
108         if ((code = krb5_timeofday(context, &now))) {
109             *minor_status = code;
110             save_error_info(*minor_status, context);
111             return(GSS_S_FAILURE);
112         }
113 
114         /* Add the maximum allowable clock skew as a grace period for context
115          * expiration, just as we do for the ticket during authentication. */
116         start = ctx->initiate ? now : ts_incr(now, -context->clockskew);
117         lifetime = ts_interval(start, ctx->krb_times.endtime);
118 
119         if (initiator_name) {
120             code = kg_duplicate_name(context,
121                                      ctx->initiate ? ctx->here : ctx->there,
122                                      &initiator);
123             if (code) {
124                 *minor_status = code;
125                 save_error_info(*minor_status, context);
126                 return(GSS_S_FAILURE);
127             }
128         }
129 
130         if (acceptor_name) {
131             code = kg_duplicate_name(context,
132                                      ctx->initiate ? ctx->there : ctx->here,
133                                      &acceptor);
134             if (code) {
135                 if (initiator)
136                     kg_release_name(context, &initiator);
137                 *minor_status = code;
138                 save_error_info(*minor_status, context);
139                 return(GSS_S_FAILURE);
140             }
141         }
142 
143         if (initiator_name)
144             *initiator_name = (gss_name_t) initiator;
145 
146         if (acceptor_name)
147             *acceptor_name = (gss_name_t) acceptor;
148 
149         if (lifetime_rec)
150             *lifetime_rec = lifetime;
151     } else {
152         lifetime = 0;
153         if (initiator_name)
154             *initiator_name = GSS_C_NO_NAME;
155 
156         if (acceptor_name)
157             *acceptor_name = GSS_C_NO_NAME;
158 
159         if (lifetime_rec)
160             *lifetime_rec = 0;
161     }
162 
163     if (mech_type)
164         *mech_type = (gss_OID) ctx->mech_used;
165 
166     if (ret_flags)
167         *ret_flags = ctx->gss_flags;
168 
169     if (locally_initiated)
170         *locally_initiated = ctx->initiate;
171 
172     if (opened)
173         *opened = ctx->established;
174 
175     *minor_status = 0;
176     if (ctx->established)
177         return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
178     else
179         return GSS_S_COMPLETE;
180 }
181 
182 /* Add two buffers to data_set giving the contents and enctype of key. */
183 static OM_uint32
inq_session_key_result(OM_uint32 * minor_status,krb5_key key,gss_buffer_set_t * data_set)184 inq_session_key_result(OM_uint32 *minor_status, krb5_key key,
185                        gss_buffer_set_t *data_set)
186 {
187     gss_buffer_desc keyvalue, keyinfo;
188     OM_uint32 major, tmpmin;
189     unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
190     gss_OID_desc oid;
191 
192     keyvalue.value = key->keyblock.contents;
193     keyvalue.length = key->keyblock.length;
194     major = generic_gss_add_buffer_set_member(minor_status, &keyvalue,
195                                               data_set);
196     if (GSS_ERROR(major))
197         goto cleanup;
198 
199     oid.elements = oid_buf;
200     oid.length = sizeof(oid_buf);
201     major = generic_gss_oid_compose(minor_status,
202                                     GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
203                                     GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
204                                     key->keyblock.enctype, &oid);
205     if (GSS_ERROR(major))
206         goto cleanup;
207 
208     keyinfo.value = oid.elements;
209     keyinfo.length = oid.length;
210     major = generic_gss_add_buffer_set_member(minor_status, &keyinfo,
211                                               data_set);
212     if (GSS_ERROR(major))
213         goto cleanup;
214 
215     return GSS_S_COMPLETE;
216 
217 cleanup:
218     if (*data_set != GSS_C_NO_BUFFER_SET) {
219         if ((*data_set)->count != 0) {
220             zap((*data_set)->elements[0].value,
221                 (*data_set)->elements[0].length);
222         }
223         gss_release_buffer_set(&tmpmin, data_set);
224     }
225 
226     return major;
227 }
228 
229 OM_uint32
gss_krb5int_inq_sspi_session_key(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)230 gss_krb5int_inq_sspi_session_key(OM_uint32 *minor_status,
231                                  const gss_ctx_id_t context_handle,
232                                  const gss_OID desired_object,
233                                  gss_buffer_set_t *data_set)
234 {
235     krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
236     krb5_key key;
237 
238     if (ctx->terminated || !ctx->established) {
239         *minor_status = KG_CTX_INCOMPLETE;
240         return GSS_S_NO_CONTEXT;
241     }
242     key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
243     return inq_session_key_result(minor_status, key, data_set);
244 }
245 
246 OM_uint32
gss_krb5int_inq_odbc_session_key(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)247 gss_krb5int_inq_odbc_session_key(OM_uint32 *minor_status,
248                                  const gss_ctx_id_t context_handle,
249                                  const gss_OID desired_object,
250                                  gss_buffer_set_t *data_set)
251 {
252     OM_uint32 major;
253     krb5_error_code ret;
254     krb5_gss_ctx_id_t ctx = (krb5_gss_ctx_id_t)context_handle;
255     krb5_key key;
256 
257     if (ctx->terminated || !ctx->established) {
258         *minor_status = KG_CTX_INCOMPLETE;
259         return GSS_S_NO_CONTEXT;
260     }
261 
262     ret = krb5_auth_con_getkey_k(ctx->k5_context, ctx->auth_context, &key);
263     if (ret) {
264         *minor_status = ret;
265         return GSS_S_FAILURE;
266     }
267 
268     major = inq_session_key_result(minor_status, key, data_set);
269     krb5_k_free_key(ctx->k5_context, key);
270     return major;
271 }
272 
273 OM_uint32
gss_krb5int_extract_authz_data_from_sec_context(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)274 gss_krb5int_extract_authz_data_from_sec_context(
275     OM_uint32 *minor_status,
276     const gss_ctx_id_t context_handle,
277     const gss_OID desired_object,
278     gss_buffer_set_t *data_set)
279 {
280     OM_uint32 major_status;
281     krb5_gss_ctx_id_rec *ctx;
282     int ad_type = 0;
283     size_t i;
284 
285     *data_set = GSS_C_NO_BUFFER_SET;
286 
287     ctx = (krb5_gss_ctx_id_rec *) context_handle;
288 
289     major_status = generic_gss_oid_decompose(minor_status,
290                                              GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
291                                              GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
292                                              desired_object,
293                                              &ad_type);
294     if (major_status != GSS_S_COMPLETE || ad_type == 0) {
295         *minor_status = ENOENT;
296         return GSS_S_FAILURE;
297     }
298 
299     if (ctx->authdata != NULL) {
300         for (i = 0; ctx->authdata[i] != NULL; i++) {
301             if (ctx->authdata[i]->ad_type == ad_type) {
302                 gss_buffer_desc ad_data;
303 
304                 ad_data.length = ctx->authdata[i]->length;
305                 ad_data.value = ctx->authdata[i]->contents;
306 
307                 major_status = generic_gss_add_buffer_set_member(minor_status,
308                                                                  &ad_data, data_set);
309                 if (GSS_ERROR(major_status))
310                     break;
311             }
312         }
313     }
314 
315     if (GSS_ERROR(major_status)) {
316         OM_uint32 tmp;
317 
318         generic_gss_release_buffer_set(&tmp, data_set);
319     }
320 
321     return major_status;
322 }
323 
324 OM_uint32
gss_krb5int_extract_authtime_from_sec_context(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_oid,gss_buffer_set_t * data_set)325 gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
326                                               const gss_ctx_id_t context_handle,
327                                               const gss_OID desired_oid,
328                                               gss_buffer_set_t *data_set)
329 {
330     krb5_gss_ctx_id_rec *ctx;
331     gss_buffer_desc rep;
332 
333     ctx = (krb5_gss_ctx_id_rec *) context_handle;
334 
335     rep.value = &ctx->krb_times.authtime;
336     rep.length = sizeof(ctx->krb_times.authtime);
337 
338     return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
339 }
340 
341 OM_uint32
gss_krb5int_sec_context_sasl_ssf(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)342 gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status,
343                                  const gss_ctx_id_t context_handle,
344                                  const gss_OID desired_object,
345                                  gss_buffer_set_t *data_set)
346 {
347     krb5_gss_ctx_id_rec *ctx;
348     krb5_key key;
349     krb5_error_code code;
350     gss_buffer_desc ssfbuf;
351     unsigned int ssf;
352     uint8_t buf[4];
353 
354     ctx = (krb5_gss_ctx_id_rec *)context_handle;
355     key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
356 
357     code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf);
358     if (code)
359         return GSS_S_FAILURE;
360 
361     store_32_be(ssf, buf);
362     ssfbuf.value = buf;
363     ssfbuf.length = sizeof(buf);
364 
365     return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set);
366 }
367