1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1996,1997,1999,2002-2003 Sun Microsystems, Inc. 24 * All rights reserved. Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 29 * 30 * $Header: 31 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi_misc.c,v 1.10 32 * 1994/10/27 12:39:23 jik Exp $ 33 */ 34 35 /* 36 * Copyright (c) 2013 by Delphix. All rights reserved. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/types.h> 41 #include <sys/stream.h> 42 #include <sys/strsubr.h> 43 #include <sys/cmn_err.h> 44 #include <gssapi/gssapi.h> 45 #include <rpc/rpc.h> 46 #include <rpc/rpcsec_defs.h> 47 48 /* 49 * The initial allocation size for dynamic allocation. 50 */ 51 #define CKU_INITSIZE 2048 52 53 /* 54 * The size of additional allocations, if required. It is larger to 55 * reduce the number of actual allocations. 56 */ 57 #define CKU_ALLOCSIZE 8192 58 59 60 /* 61 * Miscellaneous XDR routines. 62 */ 63 bool_t 64 __xdr_gss_buf(xdrs, buf) 65 XDR *xdrs; 66 gss_buffer_t buf; 67 { 68 uint_t cast_len, bound_len; 69 70 /* 71 * We go through this contortion because size_t is a now a ulong, 72 * GSS-API uses ulongs. 73 */ 74 75 if (xdrs->x_op != XDR_DECODE) { 76 bound_len = cast_len = (uint_t)buf->length; 77 } else { 78 bound_len = (uint_t)-1; 79 } 80 81 if (xdr_bytes(xdrs, (char **)&buf->value, &cast_len, 82 bound_len) == TRUE) { 83 if (xdrs->x_op == XDR_DECODE) 84 buf->length = cast_len; 85 86 return (TRUE); 87 } 88 89 return (FALSE); 90 } 91 92 bool_t 93 __xdr_rpc_gss_creds(xdrs, creds) 94 XDR *xdrs; 95 rpc_gss_creds *creds; 96 { 97 if (!xdr_u_int(xdrs, (uint_t *)&creds->version) || 98 !xdr_u_int(xdrs, (uint_t *)&creds->gss_proc) || 99 !xdr_u_int(xdrs, (uint_t *)&creds->seq_num) || 100 !xdr_u_int(xdrs, (uint_t *)&creds->service) || 101 !__xdr_gss_buf(xdrs, &creds->ctx_handle)) 102 return (FALSE); 103 return (TRUE); 104 } 105 106 bool_t 107 __xdr_rpc_gss_init_arg(xdrs, init_arg) 108 XDR *xdrs; 109 rpc_gss_init_arg *init_arg; 110 { 111 if (!__xdr_gss_buf(xdrs, init_arg)) 112 return (FALSE); 113 return (TRUE); 114 } 115 116 bool_t 117 __xdr_rpc_gss_init_res(xdrs, init_res) 118 XDR *xdrs; 119 rpc_gss_init_res *init_res; 120 { 121 if (!__xdr_gss_buf(xdrs, &init_res->ctx_handle) || 122 !xdr_u_int(xdrs, (uint_t *)&init_res->gss_major) || 123 !xdr_u_int(xdrs, (uint_t *)&init_res->gss_minor) || 124 !xdr_u_int(xdrs, (uint_t *)&init_res->seq_window) || 125 !__xdr_gss_buf(xdrs, &init_res->token)) 126 return (FALSE); 127 return (TRUE); 128 } 129 130 /* 131 * Generic routine to wrap data used by client and server sides. 132 */ 133 bool_t 134 __rpc_gss_wrap_data(service, qop, context, seq_num, out_xdrs, 135 xdr_func, xdr_ptr) 136 OM_uint32 qop; 137 rpc_gss_service_t service; 138 gss_ctx_id_t context; 139 uint_t seq_num; 140 XDR *out_xdrs; 141 bool_t (*xdr_func)(); 142 caddr_t xdr_ptr; 143 { 144 OM_uint32 major, minor; 145 gss_buffer_desc in_buf, out_buf; 146 XDR temp_xdrs; 147 char *temp_data; 148 /* EXPORT DELETE START */ 149 bool_t conf_state; 150 /* EXPORT DELETE END */ 151 bool_t ret = FALSE; 152 int size; 153 154 /* 155 * Create a temporary XDR/buffer to hold the data to be wrapped. 156 * We need an extra bit for the sequence number serialized first. 157 */ 158 size = xdr_sizeof(xdr_func, xdr_ptr) + BYTES_PER_XDR_UNIT; 159 temp_data = kmem_alloc(size, KM_SLEEP); 160 out_buf.length = 0; 161 162 xdrmem_create(&temp_xdrs, temp_data, size, XDR_ENCODE); 163 164 /* 165 * serialize the sequence number into tmp memory 166 */ 167 if (!xdr_u_int(&temp_xdrs, &seq_num)) 168 goto fail; 169 170 /* 171 * serialize the arguments into tmp memory 172 */ 173 if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) 174 goto fail; 175 176 /* 177 * Data to be wrapped goes in in_buf. If privacy is used, 178 * out_buf will have wrapped data (in_buf will no longer be 179 * needed). If integrity is used, out_buf will have checksum 180 * which will follow the data in in_buf. 181 */ 182 in_buf.length = xdr_getpos(&temp_xdrs); 183 in_buf.value = (char *)temp_xdrs.x_base; 184 185 switch (service) { 186 case rpc_gss_svc_privacy: 187 188 /* EXPORT DELETE START */ 189 if ((major = kgss_seal(&minor, context, TRUE, qop, &in_buf, 190 &conf_state, &out_buf)) != GSS_S_COMPLETE) { 191 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_seal failed." 192 "major = %x, minor = %x", major, minor); 193 goto fail; 194 } 195 in_buf.length = 0; /* in_buf not needed */ 196 if (!conf_state) 197 /* EXPORT DELETE END */ 198 goto fail; 199 /* EXPORT DELETE START */ 200 break; 201 /* EXPORT DELETE END */ 202 case rpc_gss_svc_integrity: 203 if ((major = kgss_sign(&minor, context, qop, &in_buf, 204 &out_buf)) != GSS_S_COMPLETE) { 205 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_sign failed." 206 "major = %x, minor = %x", major, minor); 207 goto fail; 208 } 209 break; 210 default: 211 goto fail; 212 } 213 214 /* 215 * write out in_buf and out_buf as needed 216 */ 217 if (in_buf.length != 0) { 218 if (!__xdr_gss_buf(out_xdrs, &in_buf)) 219 goto fail; 220 } 221 222 if (!__xdr_gss_buf(out_xdrs, &out_buf)) 223 goto fail; 224 ret = TRUE; 225 fail: 226 kmem_free(temp_data, size); 227 if (out_buf.length != 0) 228 (void) gss_release_buffer(&minor, &out_buf); 229 return (ret); 230 } 231 232 /* 233 * Generic routine to unwrap data used by client and server sides. 234 */ 235 bool_t 236 __rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, 237 xdr_func, xdr_ptr) 238 rpc_gss_service_t service; 239 gss_ctx_id_t context; 240 uint_t seq_num; 241 OM_uint32 qop_check; 242 XDR *in_xdrs; 243 bool_t (*xdr_func)(); 244 caddr_t xdr_ptr; 245 { 246 gss_buffer_desc in_buf, out_buf; 247 XDR temp_xdrs; 248 uint_t seq_num2; 249 bool_t conf = FALSE; 250 OM_uint32 major = GSS_S_COMPLETE, minor = 0; 251 int qop = 0; 252 253 in_buf.value = NULL; 254 out_buf.value = NULL; 255 256 /* 257 * Pull out wrapped data. For privacy service, this is the 258 * encrypted data. For integrity service, this is the data 259 * followed by a checksum. 260 */ 261 if (!__xdr_gss_buf(in_xdrs, &in_buf)) { 262 return (FALSE); 263 } 264 265 if (service == rpc_gss_svc_privacy) { 266 major = GSS_S_FAILURE; 267 /* EXPORT DELETE START */ 268 major = kgss_unseal(&minor, context, &in_buf, &out_buf, &conf, 269 &qop); 270 /* EXPORT DELETE END */ 271 kmem_free(in_buf.value, in_buf.length); 272 if (major != GSS_S_COMPLETE) { 273 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_unseal failed." 274 "major = %x, minor = %x", major, minor); 275 return (FALSE); 276 } 277 /* 278 * Keep the returned token (unencrypted data) in in_buf. 279 */ 280 in_buf.length = out_buf.length; 281 in_buf.value = out_buf.value; 282 283 /* 284 * If privacy was not used, or if QOP is not what we are 285 * expecting, fail. 286 */ 287 if (!conf || qop != qop_check) 288 goto fail; 289 290 } else if (service == rpc_gss_svc_integrity) { 291 if (!__xdr_gss_buf(in_xdrs, &out_buf)) { 292 return (FALSE); 293 } 294 major = kgss_verify(&minor, context, &in_buf, &out_buf, 295 &qop); 296 kmem_free(out_buf.value, out_buf.length); 297 if (major != GSS_S_COMPLETE) { 298 kmem_free(in_buf.value, in_buf.length); 299 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_verify failed." 300 "major = %x, minor = %x", major, minor); 301 return (FALSE); 302 } 303 304 /* 305 * If QOP is not what we are expecting, fail. 306 */ 307 if (qop != qop_check) 308 goto fail; 309 } 310 311 xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE); 312 313 /* 314 * The data consists of the sequence number followed by the 315 * arguments. Make sure sequence number is what we are 316 * expecting (i.e., the value in the header). 317 */ 318 if (!xdr_u_int(&temp_xdrs, &seq_num2)) 319 goto fail; 320 if (seq_num2 != seq_num) 321 goto fail; 322 323 /* 324 * Deserialize the arguments into xdr_ptr, and release in_buf. 325 */ 326 if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) { 327 goto fail; 328 } 329 330 if (service == rpc_gss_svc_privacy) 331 (void) gss_release_buffer(&minor, &in_buf); 332 else 333 kmem_free(in_buf.value, in_buf.length); 334 XDR_DESTROY(&temp_xdrs); 335 return (TRUE); 336 fail: 337 XDR_DESTROY(&temp_xdrs); 338 if (service == rpc_gss_svc_privacy) 339 (void) gss_release_buffer(&minor, &in_buf); 340 else 341 kmem_free(in_buf.value, in_buf.length); 342 return (FALSE); 343 }