1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5 * Authors: Doug Rabson <dfr@rabson.org>
6 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/kobj.h>
33 #include <sys/lock.h>
34 #include <sys/malloc.h>
35 #include <sys/mutex.h>
36
37 #include <kgssapi/gssapi.h>
38 #include <kgssapi/gssapi_impl.h>
39 #include <rpc/rpc.h>
40
41 #include "gssd.h"
42 #include "kgss_if.h"
43
44 /*
45 * This function should only be called when the gssd
46 * daemon running on the system is an old one that
47 * does not use gss_krb5_export_lucid_sec_context().
48 */
gss_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)49 OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
50 gss_ctx_id_t *context_handle,
51 const gss_cred_id_t acceptor_cred_handle,
52 const gss_buffer_t input_token,
53 const gss_channel_bindings_t input_chan_bindings,
54 gss_name_t *src_name,
55 gss_OID *mech_type,
56 gss_buffer_t output_token,
57 OM_uint32 *ret_flags,
58 OM_uint32 *time_rec,
59 gss_cred_id_t *delegated_cred_handle)
60 {
61 struct accept_sec_context_res res;
62 struct accept_sec_context_args args;
63 enum clnt_stat stat;
64 gss_ctx_id_t ctx = *context_handle;
65 gss_name_t name;
66 gss_cred_id_t cred;
67 CLIENT *cl;
68
69 cl = kgss_gssd_client();
70 if (cl == NULL) {
71 *minor_status = 0;
72 return (GSS_S_FAILURE);
73 }
74
75 if (ctx)
76 args.ctx = ctx->handle;
77 else
78 args.ctx = 0;
79 if (acceptor_cred_handle)
80 args.cred = acceptor_cred_handle->handle;
81 else
82 args.cred = 0;
83 args.input_token = *input_token;
84 args.input_chan_bindings = input_chan_bindings;
85
86 bzero(&res, sizeof(res));
87 stat = gssd_accept_sec_context_1(&args, &res, cl);
88 CLNT_RELEASE(cl);
89 if (stat != RPC_SUCCESS) {
90 *minor_status = stat;
91 return (GSS_S_FAILURE);
92 }
93
94 if (res.major_status != GSS_S_COMPLETE
95 && res.major_status != GSS_S_CONTINUE_NEEDED) {
96 *minor_status = res.minor_status;
97 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
98 return (res.major_status);
99 }
100
101 *minor_status = res.minor_status;
102
103 if (!ctx) {
104 ctx = kgss_create_context(res.mech_type);
105 if (!ctx) {
106 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
107 *minor_status = 0;
108 return (GSS_S_BAD_MECH);
109 }
110 }
111 *context_handle = ctx;
112
113 ctx->handle = res.ctx;
114 name = malloc(sizeof(struct _gss_name_t), M_GSSAPI, M_WAITOK);
115 name->handle = res.src_name;
116 if (src_name) {
117 *src_name = name;
118 } else {
119 OM_uint32 junk;
120 gss_release_name(&junk, &name);
121 }
122 if (mech_type)
123 *mech_type = KGSS_MECH_TYPE(ctx);
124 kgss_copy_buffer(&res.output_token, output_token);
125 if (ret_flags)
126 *ret_flags = res.ret_flags;
127 if (time_rec)
128 *time_rec = res.time_rec;
129 cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK);
130 cred->handle = res.delegated_cred_handle;
131 if (delegated_cred_handle) {
132 *delegated_cred_handle = cred;
133 } else {
134 OM_uint32 junk;
135 gss_release_cred(&junk, &cred);
136 }
137
138 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
139
140 /*
141 * If the context establishment is complete, export it from
142 * userland and hand the result (which includes key material
143 * etc.) to the kernel implementation.
144 */
145 if (res.major_status == GSS_S_COMPLETE)
146 res.major_status = kgss_transfer_context(ctx, NULL);
147
148 return (res.major_status);
149 }
150
151 /*
152 * This function should be called when the gssd daemon is
153 * one that uses gss_krb5_export_lucid_sec_context().
154 * There is a lot of code common with
155 * gss_accept_sec_context(). However, the structures used
156 * are not the same and future changes may be needed for
157 * this one. As such, I have not factored out the common
158 * code.
159 * gss_supports_lucid() may be used to check to see if the
160 * gssd daemon uses gss_krb5_export_lucid_sec_context().
161 */
gss_accept_sec_context_lucid_v1(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle,gss_buffer_t exported_name,uid_t * uidp,gid_t * gidp,int * numgroups,gid_t * groups)162 OM_uint32 gss_accept_sec_context_lucid_v1(OM_uint32 *minor_status,
163 gss_ctx_id_t *context_handle,
164 const gss_cred_id_t acceptor_cred_handle,
165 const gss_buffer_t input_token,
166 const gss_channel_bindings_t input_chan_bindings,
167 gss_name_t *src_name,
168 gss_OID *mech_type,
169 gss_buffer_t output_token,
170 OM_uint32 *ret_flags,
171 OM_uint32 *time_rec,
172 gss_cred_id_t *delegated_cred_handle,
173 gss_buffer_t exported_name,
174 uid_t *uidp,
175 gid_t *gidp,
176 int *numgroups,
177 gid_t *groups)
178 {
179 struct accept_sec_context_lucid_v1_res res;
180 struct accept_sec_context_lucid_v1_args args;
181 enum clnt_stat stat;
182 gss_ctx_id_t ctx = *context_handle;
183 gss_name_t name;
184 gss_cred_id_t cred;
185 CLIENT *cl;
186
187 cl = kgss_gssd_client();
188 if (cl == NULL) {
189 *minor_status = 0;
190 return (GSS_S_FAILURE);
191 }
192
193 if (ctx)
194 args.ctx = ctx->handle;
195 else
196 args.ctx = 0;
197 if (acceptor_cred_handle)
198 args.cred = acceptor_cred_handle->handle;
199 else
200 args.cred = 0;
201 args.input_token = *input_token;
202 args.input_chan_bindings = input_chan_bindings;
203
204 bzero(&res, sizeof(res));
205 stat = gssd_accept_sec_context_lucid_v1_1(&args, &res, cl);
206 CLNT_RELEASE(cl);
207 if (stat != RPC_SUCCESS) {
208 *minor_status = stat;
209 return (GSS_S_FAILURE);
210 }
211
212 if (res.major_status != GSS_S_COMPLETE
213 && res.major_status != GSS_S_CONTINUE_NEEDED) {
214 *minor_status = res.minor_status;
215 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
216 return (res.major_status);
217 }
218
219 *minor_status = res.minor_status;
220
221 if (!ctx) {
222 ctx = kgss_create_context(res.mech_type);
223 if (!ctx) {
224 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
225 *minor_status = 0;
226 return (GSS_S_BAD_MECH);
227 }
228 }
229 *context_handle = ctx;
230
231 ctx->handle = res.ctx;
232 name = malloc(sizeof(struct _gss_name_t), M_GSSAPI, M_WAITOK);
233 name->handle = res.src_name;
234 if (src_name) {
235 *src_name = name;
236 } else {
237 OM_uint32 junk;
238 gss_release_name(&junk, &name);
239 }
240 if (mech_type)
241 *mech_type = KGSS_MECH_TYPE(ctx);
242 kgss_copy_buffer(&res.output_token, output_token);
243 if (ret_flags)
244 *ret_flags = res.ret_flags;
245 if (time_rec)
246 *time_rec = res.time_rec;
247 cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK);
248 cred->handle = res.delegated_cred_handle;
249 if (delegated_cred_handle) {
250 *delegated_cred_handle = cred;
251 } else {
252 OM_uint32 junk;
253 gss_release_cred(&junk, &cred);
254 }
255
256 /*
257 * If the context establishment is complete, export it from
258 * userland and hand the result (which includes key material
259 * etc.) to the kernel implementation.
260 */
261 if (res.major_status == GSS_S_COMPLETE) {
262 int i, n;
263
264 /* First, get the unix credentials. */
265 *uidp = res.uid;
266 *gidp = res.gid;
267 n = res.gidlist.gidlist_len;
268 if (n > *numgroups)
269 n = *numgroups;
270 for (i = 0; i < n; i++)
271 groups[i] = res.gidlist.gidlist_val[i];
272 *numgroups = n;
273
274 /* Next, get the exported_name. */
275 kgss_copy_buffer(&res.exported_name, exported_name);
276
277 /* Now, handle the lucid credential setup. */
278 res.major_status = kgss_transfer_context(ctx, &res.lucid);
279 if (res.major_status != GSS_S_COMPLETE)
280 printf("gss_accept_sec_context_lucid_v1: "
281 "transfer failed\n");
282 }
283
284 xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
285
286 return (res.major_status);
287 }
288