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 bool_t conf_state; 149 bool_t ret = FALSE; 150 int size; 151 152 /* 153 * Create a temporary XDR/buffer to hold the data to be wrapped. 154 * We need an extra bit for the sequence number serialized first. 155 */ 156 size = xdr_sizeof(xdr_func, xdr_ptr) + BYTES_PER_XDR_UNIT; 157 temp_data = kmem_alloc(size, KM_SLEEP); 158 out_buf.length = 0; 159 160 xdrmem_create(&temp_xdrs, temp_data, size, XDR_ENCODE); 161 162 /* 163 * serialize the sequence number into tmp memory 164 */ 165 if (!xdr_u_int(&temp_xdrs, &seq_num)) 166 goto fail; 167 168 /* 169 * serialize the arguments into tmp memory 170 */ 171 if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) 172 goto fail; 173 174 /* 175 * Data to be wrapped goes in in_buf. If privacy is used, 176 * out_buf will have wrapped data (in_buf will no longer be 177 * needed). If integrity is used, out_buf will have checksum 178 * which will follow the data in in_buf. 179 */ 180 in_buf.length = xdr_getpos(&temp_xdrs); 181 in_buf.value = (char *)temp_xdrs.x_base; 182 183 switch (service) { 184 case rpc_gss_svc_privacy: 185 186 if ((major = kgss_seal(&minor, context, TRUE, qop, &in_buf, 187 &conf_state, &out_buf)) != GSS_S_COMPLETE) { 188 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_seal failed." 189 "major = %x, minor = %x", major, minor); 190 goto fail; 191 } 192 in_buf.length = 0; /* in_buf not needed */ 193 if (!conf_state) 194 goto fail; 195 break; 196 case rpc_gss_svc_integrity: 197 if ((major = kgss_sign(&minor, context, qop, &in_buf, 198 &out_buf)) != GSS_S_COMPLETE) { 199 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_sign failed." 200 "major = %x, minor = %x", major, minor); 201 goto fail; 202 } 203 break; 204 default: 205 goto fail; 206 } 207 208 /* 209 * write out in_buf and out_buf as needed 210 */ 211 if (in_buf.length != 0) { 212 if (!__xdr_gss_buf(out_xdrs, &in_buf)) 213 goto fail; 214 } 215 216 if (!__xdr_gss_buf(out_xdrs, &out_buf)) 217 goto fail; 218 ret = TRUE; 219 fail: 220 kmem_free(temp_data, size); 221 if (out_buf.length != 0) 222 (void) gss_release_buffer(&minor, &out_buf); 223 return (ret); 224 } 225 226 /* 227 * Generic routine to unwrap data used by client and server sides. 228 */ 229 bool_t 230 __rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, 231 xdr_func, xdr_ptr) 232 rpc_gss_service_t service; 233 gss_ctx_id_t context; 234 uint_t seq_num; 235 OM_uint32 qop_check; 236 XDR *in_xdrs; 237 bool_t (*xdr_func)(); 238 caddr_t xdr_ptr; 239 { 240 gss_buffer_desc in_buf, out_buf; 241 XDR temp_xdrs; 242 uint_t seq_num2; 243 bool_t conf = FALSE; 244 OM_uint32 major = GSS_S_COMPLETE, minor = 0; 245 int qop = 0; 246 247 in_buf.value = NULL; 248 out_buf.value = NULL; 249 250 /* 251 * Pull out wrapped data. For privacy service, this is the 252 * encrypted data. For integrity service, this is the data 253 * followed by a checksum. 254 */ 255 if (!__xdr_gss_buf(in_xdrs, &in_buf)) { 256 return (FALSE); 257 } 258 259 if (service == rpc_gss_svc_privacy) { 260 major = GSS_S_FAILURE; 261 major = kgss_unseal(&minor, context, &in_buf, &out_buf, &conf, 262 &qop); 263 kmem_free(in_buf.value, in_buf.length); 264 if (major != GSS_S_COMPLETE) { 265 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_unseal failed." 266 "major = %x, minor = %x", major, minor); 267 return (FALSE); 268 } 269 /* 270 * Keep the returned token (unencrypted data) in in_buf. 271 */ 272 in_buf.length = out_buf.length; 273 in_buf.value = out_buf.value; 274 275 /* 276 * If privacy was not used, or if QOP is not what we are 277 * expecting, fail. 278 */ 279 if (!conf || qop != qop_check) 280 goto fail; 281 282 } else if (service == rpc_gss_svc_integrity) { 283 if (!__xdr_gss_buf(in_xdrs, &out_buf)) { 284 return (FALSE); 285 } 286 major = kgss_verify(&minor, context, &in_buf, &out_buf, 287 &qop); 288 kmem_free(out_buf.value, out_buf.length); 289 if (major != GSS_S_COMPLETE) { 290 kmem_free(in_buf.value, in_buf.length); 291 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_verify failed." 292 "major = %x, minor = %x", major, minor); 293 return (FALSE); 294 } 295 296 /* 297 * If QOP is not what we are expecting, fail. 298 */ 299 if (qop != qop_check) 300 goto fail; 301 } 302 303 xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE); 304 305 /* 306 * The data consists of the sequence number followed by the 307 * arguments. Make sure sequence number is what we are 308 * expecting (i.e., the value in the header). 309 */ 310 if (!xdr_u_int(&temp_xdrs, &seq_num2)) 311 goto fail; 312 if (seq_num2 != seq_num) 313 goto fail; 314 315 /* 316 * Deserialize the arguments into xdr_ptr, and release in_buf. 317 */ 318 if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) { 319 goto fail; 320 } 321 322 if (service == rpc_gss_svc_privacy) 323 (void) gss_release_buffer(&minor, &in_buf); 324 else 325 kmem_free(in_buf.value, in_buf.length); 326 XDR_DESTROY(&temp_xdrs); 327 return (TRUE); 328 fail: 329 XDR_DESTROY(&temp_xdrs); 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 return (FALSE); 335 } 336