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 #include <sys/proc.h> 37 38 #include <kgssapi/gssapi.h> 39 #include <kgssapi/gssapi_impl.h> 40 #include <rpc/rpc.h> 41 42 #include "gssd.h" 43 #include "kgss_if.h" 44 45 /* 46 * This function should only be called when the gssd 47 * daemon running on the system is an old one that 48 * does not use gss_krb5_export_lucid_sec_context(). 49 */ 50 OM_uint32 51 gss_init_sec_context(OM_uint32 * minor_status, 52 const gss_cred_id_t initiator_cred_handle, 53 gss_ctx_id_t * context_handle, 54 const gss_name_t target_name, 55 const gss_OID input_mech_type, 56 OM_uint32 req_flags, 57 OM_uint32 time_req, 58 const gss_channel_bindings_t input_chan_bindings, 59 const gss_buffer_t input_token, 60 gss_OID * actual_mech_type, 61 gss_buffer_t output_token, 62 OM_uint32 * ret_flags, 63 OM_uint32 * time_rec) 64 { 65 struct init_sec_context_res res; 66 struct init_sec_context_args args; 67 enum clnt_stat stat; 68 gss_ctx_id_t ctx = *context_handle; 69 CLIENT *cl; 70 71 *minor_status = 0; 72 73 cl = kgss_gssd_client(); 74 if (cl == NULL) 75 return (GSS_S_FAILURE); 76 77 args.uid = curthread->td_ucred->cr_uid; 78 if (initiator_cred_handle) 79 args.cred = initiator_cred_handle->handle; 80 else 81 args.cred = 0; 82 if (ctx) 83 args.ctx = ctx->handle; 84 else 85 args.ctx = 0; 86 args.name = target_name->handle; 87 args.mech_type = input_mech_type; 88 args.req_flags = req_flags; 89 args.time_req = time_req; 90 args.input_chan_bindings = input_chan_bindings; 91 if (input_token) 92 args.input_token = *input_token; 93 else { 94 args.input_token.length = 0; 95 args.input_token.value = NULL; 96 } 97 98 bzero(&res, sizeof(res)); 99 stat = gssd_init_sec_context_1(&args, &res, cl); 100 CLNT_RELEASE(cl); 101 if (stat != RPC_SUCCESS) { 102 *minor_status = stat; 103 return (GSS_S_FAILURE); 104 } 105 106 if (res.major_status != GSS_S_COMPLETE 107 && res.major_status != GSS_S_CONTINUE_NEEDED) { 108 *minor_status = res.minor_status; 109 xdr_free((xdrproc_t) xdr_init_sec_context_res, &res); 110 return (res.major_status); 111 } 112 113 *minor_status = res.minor_status; 114 115 if (!ctx) { 116 ctx = kgss_create_context(res.actual_mech_type); 117 if (!ctx) { 118 xdr_free((xdrproc_t) xdr_init_sec_context_res, &res); 119 *minor_status = 0; 120 return (GSS_S_BAD_MECH); 121 } 122 } 123 *context_handle = ctx; 124 ctx->handle = res.ctx; 125 if (actual_mech_type) 126 *actual_mech_type = KGSS_MECH_TYPE(ctx); 127 kgss_copy_buffer(&res.output_token, output_token); 128 if (ret_flags) 129 *ret_flags = res.ret_flags; 130 if (time_rec) 131 *time_rec = res.time_rec; 132 133 xdr_free((xdrproc_t) xdr_init_sec_context_res, &res); 134 135 /* 136 * If the context establishment is complete, export it from 137 * userland and hand the result (which includes key material 138 * etc.) to the kernel implementation. 139 */ 140 if (res.major_status == GSS_S_COMPLETE) 141 res.major_status = kgss_transfer_context(ctx, NULL); 142 143 return (res.major_status); 144 } 145 146 OM_uint32 147 gss_supports_lucid(uint32_t *minor_status, uint32_t *vers) 148 { 149 struct supports_lucid_res res; 150 enum clnt_stat stat; 151 CLIENT *cl; 152 153 *minor_status = 0; 154 155 cl = kgss_gssd_client(); 156 if (cl == NULL) 157 return (GSS_S_FAILURE); 158 159 bzero(&res, sizeof(res)); 160 stat = gssd_supports_lucid_1(NULL, &res, cl); 161 CLNT_RELEASE(cl); 162 if (stat != RPC_SUCCESS) { 163 *minor_status = stat; 164 return (GSS_S_FAILURE); 165 } 166 167 if (vers) 168 *vers = res.vers; 169 170 return (res.major_status); 171 } 172 173 /* 174 * This function should be called when the gssd daemon is 175 * one that uses gss_krb5_export_lucid_sec_context(). 176 * There is a lot of code common with 177 * gss_init_sec_context(). However, the structures used 178 * are not the same and future changes may be needed for 179 * this one. As such, I have not factored out the common 180 * code. 181 * gss_supports_lucid() may be used to check to see if the 182 * gssd daemon uses gss_krb5_export_lucid_sec_context(). 183 */ 184 OM_uint32 185 gss_init_sec_context_lucid_v1(OM_uint32 * minor_status, 186 const gss_cred_id_t initiator_cred_handle, 187 gss_ctx_id_t * context_handle, 188 const gss_name_t target_name, 189 const gss_OID input_mech_type, 190 OM_uint32 req_flags, 191 OM_uint32 time_req, 192 const gss_channel_bindings_t input_chan_bindings, 193 const gss_buffer_t input_token, 194 gss_OID * actual_mech_type, 195 gss_buffer_t output_token, 196 OM_uint32 * ret_flags, 197 OM_uint32 * time_rec) 198 { 199 struct init_sec_context_lucid_v1_res res; 200 struct init_sec_context_lucid_v1_args args; 201 enum clnt_stat stat; 202 gss_ctx_id_t ctx = *context_handle; 203 CLIENT *cl; 204 205 *minor_status = 0; 206 207 cl = kgss_gssd_client(); 208 if (cl == NULL) 209 return (GSS_S_FAILURE); 210 211 args.uid = curthread->td_ucred->cr_uid; 212 if (initiator_cred_handle) 213 args.cred = initiator_cred_handle->handle; 214 else 215 args.cred = 0; 216 if (ctx) 217 args.ctx = ctx->handle; 218 else 219 args.ctx = 0; 220 args.name = target_name->handle; 221 args.mech_type = input_mech_type; 222 args.req_flags = req_flags; 223 args.time_req = time_req; 224 args.input_chan_bindings = input_chan_bindings; 225 if (input_token) 226 args.input_token = *input_token; 227 else { 228 args.input_token.length = 0; 229 args.input_token.value = NULL; 230 } 231 232 bzero(&res, sizeof(res)); 233 stat = gssd_init_sec_context_lucid_v1_1(&args, &res, cl); 234 CLNT_RELEASE(cl); 235 if (stat != RPC_SUCCESS) { 236 *minor_status = stat; 237 return (GSS_S_FAILURE); 238 } 239 240 if (res.major_status != GSS_S_COMPLETE 241 && res.major_status != GSS_S_CONTINUE_NEEDED) { 242 *minor_status = res.minor_status; 243 xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res); 244 return (res.major_status); 245 } 246 247 *minor_status = res.minor_status; 248 249 if (!ctx) { 250 ctx = kgss_create_context(res.actual_mech_type); 251 if (!ctx) { 252 xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res); 253 *minor_status = 0; 254 return (GSS_S_BAD_MECH); 255 } 256 } 257 *context_handle = ctx; 258 ctx->handle = res.ctx; 259 if (actual_mech_type) 260 *actual_mech_type = KGSS_MECH_TYPE(ctx); 261 kgss_copy_buffer(&res.output_token, output_token); 262 if (ret_flags) 263 *ret_flags = res.ret_flags; 264 if (time_rec) 265 *time_rec = res.time_rec; 266 267 /* 268 * If the context establishment is complete, export it from 269 * userland and hand the result (which includes key material 270 * etc.) to the kernel implementation. 271 */ 272 if (res.major_status == GSS_S_COMPLETE) { 273 res.major_status = kgss_transfer_context(ctx, &res.lucid); 274 if (res.major_status != GSS_S_COMPLETE) 275 printf("gss_init_sec_context_lucid_v1: " 276 "transfer failed\n"); 277 } 278 279 xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res); 280 281 return (res.major_status); 282 } 283