1 /*
2  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
3  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
4  * Use is subject to license terms.
5  */
6 /* -*- mode: c; indent-tabs-mode: nil -*- */
7 /*
8  * Copyright 1993 by OpenVision Technologies, Inc.
9  *
10  * Permission to use, copy, modify, distribute, and sell this software
11  * and its documentation for any purpose is hereby granted without fee,
12  * provided that the above copyright notice appears in all copies and
13  * that both that copyright notice and this permission notice appear in
14  * supporting documentation, and that the name of OpenVision not be used
15  * in advertising or publicity pertaining to distribution of the software
16  * without specific, written prior permission. OpenVision makes no
17  * representations about the suitability of this software for any
18  * purpose.  It is provided "as is" without express or implied warranty.
19  *
20  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26  * PERFORMANCE OF THIS SOFTWARE.
27  */
28 /*
29  * Copyright (c) 2006-2008, Novell, Inc.
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions are met:
34  *
35  *   * Redistributions of source code must retain the above copyright notice,
36  *       this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *       notice, this list of conditions and the following disclaimer in the
39  *       documentation and/or other materials provided with the distribution.
40  *   * The copyright holder's name is not used to endorse or promote products
41  *       derived from this software without specific prior written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
44  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
47  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53  * POSSIBILITY OF SUCH DAMAGE.
54  */
55 /*
56  * Copyright (c) 2006-2008, Novell, Inc.
57  * All rights reserved.
58  *
59  * Redistribution and use in source and binary forms, with or without
60  * modification, are permitted provided that the following conditions are met:
61  *
62  *   * Redistributions of source code must retain the above copyright notice,
63  *       this list of conditions and the following disclaimer.
64  *   * Redistributions in binary form must reproduce the above copyright
65  *       notice, this list of conditions and the following disclaimer in the
66  *       documentation and/or other materials provided with the distribution.
67  *   * The copyright holder's name is not used to endorse or promote products
68  *       derived from this software without specific prior written permission.
69  *
70  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
71  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
74  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
75  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
76  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
78  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
79  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
80  * POSSIBILITY OF SUCH DAMAGE.
81  */
82 
83 #include "gssapiP_krb5.h"
84 #include "mechglueP.h" /* SUNW17PACresync */
85 
86 OM_uint32
krb5_gss_inquire_context(minor_status,context_handle,initiator_name,acceptor_name,lifetime_rec,mech_type,ret_flags,locally_initiated,opened)87 krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
88                          acceptor_name, lifetime_rec, mech_type, ret_flags,
89                          locally_initiated, opened)
90     OM_uint32 *minor_status;
91     gss_ctx_id_t context_handle;
92     gss_name_t *initiator_name;
93     gss_name_t *acceptor_name;
94     OM_uint32 *lifetime_rec;
95     gss_OID *mech_type;
96     OM_uint32 *ret_flags;
97     int *locally_initiated;
98     int *opened;
99 {
100     krb5_context context;
101     krb5_error_code code;
102     krb5_gss_ctx_id_rec *ctx;
103     krb5_principal initiator, acceptor;
104     krb5_timestamp now;
105     krb5_deltat lifetime;
106 
107     if (initiator_name)
108         *initiator_name = (gss_name_t) NULL;
109     if (acceptor_name)
110         *acceptor_name = (gss_name_t) NULL;
111 
112     /* validate the context handle */
113     if (! kg_validate_ctx_id(context_handle)) {
114         *minor_status = (OM_uint32) G_VALIDATE_FAILED;
115         return(GSS_S_NO_CONTEXT);
116     }
117 
118     ctx = (krb5_gss_ctx_id_rec *) context_handle;
119 
120     if (! ctx->established) {
121         *minor_status = KG_CTX_INCOMPLETE;
122         return(GSS_S_NO_CONTEXT);
123     }
124 
125     initiator = NULL;
126     acceptor = NULL;
127     context = ctx->k5_context;
128 
129     if ((code = krb5_timeofday(context, &now))) {
130         *minor_status = code;
131         save_error_info(*minor_status, context);
132         return(GSS_S_FAILURE);
133     }
134 
135 
136     /* SUNW17PACresync - should be krb_times.endtime (revisit) */
137     if ((lifetime = ctx->endtime - now) < 0)
138         lifetime = 0;
139 
140     if (initiator_name) {
141         if ((code = krb5_copy_principal(context,
142                                         ctx->initiate?ctx->here:ctx->there,
143                                         &initiator))) {
144             *minor_status = code;
145             save_error_info(*minor_status, context);
146             return(GSS_S_FAILURE);
147         }
148         if (! kg_save_name((gss_name_t) initiator)) {
149             krb5_free_principal(context, initiator);
150             *minor_status = (OM_uint32) G_VALIDATE_FAILED;
151             return(GSS_S_FAILURE);
152         }
153     }
154 
155     if (acceptor_name) {
156         if ((code = krb5_copy_principal(context,
157                                         ctx->initiate?ctx->there:ctx->here,
158                                         &acceptor))) {
159             if (initiator) krb5_free_principal(context, initiator);
160             *minor_status = code;
161             save_error_info(*minor_status, context);
162             return(GSS_S_FAILURE);
163         }
164         if (! kg_save_name((gss_name_t) acceptor)) {
165             krb5_free_principal(context, acceptor);
166             if (initiator) {
167                 kg_delete_name((gss_name_t) initiator);
168                 krb5_free_principal(context, initiator);
169             }
170             *minor_status = (OM_uint32) G_VALIDATE_FAILED;
171             return(GSS_S_FAILURE);
172         }
173     }
174 
175     if (initiator_name)
176         *initiator_name = (gss_name_t) initiator;
177 
178     if (acceptor_name)
179         *acceptor_name = (gss_name_t) acceptor;
180 
181     if (lifetime_rec)
182         *lifetime_rec = lifetime;
183 
184     if (mech_type)
185         *mech_type = (gss_OID) ctx->mech_used;
186 
187     if (ret_flags)
188         *ret_flags = ctx->gss_flags;
189 
190     if (locally_initiated)
191         *locally_initiated = ctx->initiate;
192 
193     if (opened)
194         *opened = ctx->established;
195 
196     *minor_status = 0;
197 
198     return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
199 }
200 
201 OM_uint32
gss_krb5int_inq_session_key(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)202 gss_krb5int_inq_session_key(
203     OM_uint32 *minor_status,
204     const gss_ctx_id_t context_handle,
205     const gss_OID desired_object,
206     gss_buffer_set_t *data_set)
207 {
208     krb5_gss_ctx_id_rec *ctx;
209     krb5_keyblock *key;
210     gss_buffer_desc keyvalue, keyinfo;
211     OM_uint32 major_status, minor;
212     unsigned char oid_buf[GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH + 6];
213     gss_OID_desc oid;
214 
215     ctx = (krb5_gss_ctx_id_rec *) context_handle;
216     key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
217 
218     keyvalue.value = key->contents;
219     keyvalue.length = key->length;
220 
221     major_status = generic_gss_add_buffer_set_member(minor_status, &keyvalue, data_set);
222     if (GSS_ERROR(major_status))
223         goto cleanup;
224 
225     oid.elements = oid_buf;
226     oid.length = sizeof(oid_buf);
227 
228     major_status = generic_gss_oid_compose(minor_status,
229                                            GSS_KRB5_SESSION_KEY_ENCTYPE_OID,
230                                            GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
231                                            key->enctype,
232                                            &oid);
233     if (GSS_ERROR(major_status))
234         goto cleanup;
235 
236     keyinfo.value = oid.elements;
237     keyinfo.length = oid.length;
238 
239     major_status = generic_gss_add_buffer_set_member(minor_status, &keyinfo, data_set);
240     if (GSS_ERROR(major_status))
241         goto cleanup;
242 
243     return GSS_S_COMPLETE;
244 
245 cleanup:
246     if (*data_set != GSS_C_NO_BUFFER_SET) {
247         if ((*data_set)->count != 0)
248             memset((*data_set)->elements[0].value, 0, (*data_set)->elements[0].length);
249         gss_release_buffer_set(&minor, data_set);
250     }
251 
252     return major_status;
253 }
254 
255 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)256 gss_krb5int_extract_authz_data_from_sec_context(
257    OM_uint32 *minor_status,
258    const gss_ctx_id_t context_handle,
259    const gss_OID desired_object,
260    gss_buffer_set_t *data_set)
261 {
262     gss_buffer_desc ad_data;
263     OM_uint32 major_status;
264     krb5_error_code code;
265     krb5_gss_ctx_id_rec *ctx;
266     int ad_type = 0;
267     int i, j;
268 
269     *data_set = GSS_C_NO_BUFFER_SET;
270 
271     ctx = (krb5_gss_ctx_id_rec *) context_handle;
272 
273     major_status = generic_gss_oid_decompose(minor_status,
274                                              GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID,
275                                              GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH,
276                                              desired_object,
277                                              &ad_type);
278     if (major_status != GSS_S_COMPLETE || ad_type == 0) {
279         *minor_status = ENOENT;
280         return major_status; /* SUNW17PACresync */
281     }
282 
283     if (ctx->authdata != NULL) {
284         for (i = 0; ctx->authdata[i] != NULL; i++) {
285             if (ctx->authdata[i]->ad_type == ad_type) {
286 
287                 ad_data.length = ctx->authdata[i]->length;
288                 ad_data.value = ctx->authdata[i]->contents;
289 
290                 major_status = generic_gss_add_buffer_set_member(minor_status,
291                                                                  &ad_data, data_set);
292                 if (GSS_ERROR(major_status))
293                     break;
294             } else if (ctx->authdata[i]->ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
295                 /*
296                  * Solaris Kerberos (illumos)
297                  * Unwrap the AD-IF-RELEVANT object and look inside.
298                  */
299                 krb5_authdata **ad_if_relevant = NULL;
300                 code = krb5_decode_authdata_container(ctx->k5_context,
301                                                       KRB5_AUTHDATA_IF_RELEVANT,
302                                                       ctx->authdata[i],
303                                                       &ad_if_relevant);
304                 if (code != 0)
305                     continue;
306 
307                 for (j = 0; ad_if_relevant[j] != NULL; j++) {
308                     if (ad_if_relevant[j]->ad_type == ad_type) {
309                         ad_data.length = ad_if_relevant[j]->length;
310                         ad_data.value = ad_if_relevant[j]->contents;
311 
312                         major_status = generic_gss_add_buffer_set_member(minor_status,
313                                                                          &ad_data, data_set);
314                         if (GSS_ERROR(major_status)) {
315                             krb5_free_authdata(ctx->k5_context, ad_if_relevant);
316                             goto break2;
317                         }
318                     }
319                 }
320                 krb5_free_authdata(ctx->k5_context, ad_if_relevant);
321                 /* Solaris Kerberos (illumos) */
322             }
323         }
324     }
325 
326 break2:
327     if (GSS_ERROR(major_status)) {
328         OM_uint32 tmp;
329 
330         generic_gss_release_buffer_set(&tmp, data_set);
331     }
332 
333     return major_status;
334 }
335 
336 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)337 gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
338                                               const gss_ctx_id_t context_handle,
339                                               const gss_OID desired_oid,
340                                               gss_buffer_set_t *data_set)
341 {
342     krb5_gss_ctx_id_rec *ctx;
343     gss_buffer_desc rep;
344 
345     ctx = (krb5_gss_ctx_id_rec *) context_handle;
346 
347     rep.value = &ctx->krb_times.authtime;
348     rep.length = sizeof(ctx->krb_times.authtime);
349 
350     return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
351 }
352 
353