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 */ 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 */ 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