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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 31 * 32 * $Header: 33 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi_misc.c,v 1.10 34 * 1994/10/27 12:39:23 jik Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/stream.h> 40 #include <sys/strsubr.h> 41 #include <sys/cmn_err.h> 42 #include <gssapi/gssapi.h> 43 #include <rpc/rpc.h> 44 #include <rpc/rpcsec_defs.h> 45 46 /* 47 * The initial allocation size for dynamic allocation. 48 */ 49 #define CKU_INITSIZE 2048 50 51 /* 52 * The size of additional allocations, if required. It is larger to 53 * reduce the number of actual allocations. 54 */ 55 #define CKU_ALLOCSIZE 8192 56 57 58 /* 59 * Miscellaneous XDR routines. 60 */ 61 bool_t 62 __xdr_gss_buf(xdrs, buf) 63 XDR *xdrs; 64 gss_buffer_t buf; 65 { 66 uint_t cast_len, bound_len; 67 68 /* 69 * We go through this contortion because size_t is a now a ulong, 70 * GSS-API uses ulongs. 71 */ 72 73 if (xdrs->x_op != XDR_DECODE) { 74 bound_len = cast_len = (uint_t)buf->length; 75 } else { 76 bound_len = (uint_t)-1; 77 } 78 79 if (xdr_bytes(xdrs, (char **)&buf->value, &cast_len, 80 bound_len) == TRUE) { 81 if (xdrs->x_op == XDR_DECODE) 82 buf->length = cast_len; 83 84 return (TRUE); 85 } 86 87 return (FALSE); 88 } 89 90 bool_t 91 __xdr_rpc_gss_creds(xdrs, creds) 92 XDR *xdrs; 93 rpc_gss_creds *creds; 94 { 95 if (!xdr_u_int(xdrs, (uint_t *)&creds->version) || 96 !xdr_u_int(xdrs, (uint_t *)&creds->gss_proc) || 97 !xdr_u_int(xdrs, (uint_t *)&creds->seq_num) || 98 !xdr_u_int(xdrs, (uint_t *)&creds->service) || 99 !__xdr_gss_buf(xdrs, &creds->ctx_handle)) 100 return (FALSE); 101 return (TRUE); 102 } 103 104 bool_t 105 __xdr_rpc_gss_init_arg(xdrs, init_arg) 106 XDR *xdrs; 107 rpc_gss_init_arg *init_arg; 108 { 109 if (!__xdr_gss_buf(xdrs, init_arg)) 110 return (FALSE); 111 return (TRUE); 112 } 113 114 bool_t 115 __xdr_rpc_gss_init_res(xdrs, init_res) 116 XDR *xdrs; 117 rpc_gss_init_res *init_res; 118 { 119 if (!__xdr_gss_buf(xdrs, &init_res->ctx_handle) || 120 !xdr_u_int(xdrs, (uint_t *)&init_res->gss_major) || 121 !xdr_u_int(xdrs, (uint_t *)&init_res->gss_minor) || 122 !xdr_u_int(xdrs, (uint_t *)&init_res->seq_window) || 123 !__xdr_gss_buf(xdrs, &init_res->token)) 124 return (FALSE); 125 return (TRUE); 126 } 127 128 /* 129 * Generic routine to wrap data used by client and server sides. 130 */ 131 bool_t 132 __rpc_gss_wrap_data(service, qop, context, seq_num, out_xdrs, 133 xdr_func, xdr_ptr) 134 OM_uint32 qop; 135 rpc_gss_service_t service; 136 gss_ctx_id_t context; 137 uint_t seq_num; 138 XDR *out_xdrs; 139 bool_t (*xdr_func)(); 140 caddr_t xdr_ptr; 141 { 142 OM_uint32 major, minor; 143 gss_buffer_desc in_buf, out_buf; 144 XDR temp_xdrs; 145 char *mp; 146 /* EXPORT DELETE START */ 147 bool_t conf_state; 148 /* EXPORT DELETE END */ 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 mp = kmem_alloc(size, KM_SLEEP); 158 out_buf.length = 0; 159 160 xdrmem_create(&temp_xdrs, mp, 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 /* EXPORT DELETE START */ 187 if ((major = kgss_seal(&minor, context, TRUE, qop, &in_buf, 188 &conf_state, &out_buf)) != GSS_S_COMPLETE) { 189 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_seal failed." 190 "major = %x, minor = %x", major, minor); 191 goto fail; 192 } 193 in_buf.length = 0; /* in_buf not needed */ 194 if (!conf_state) 195 /* EXPORT DELETE END */ 196 goto fail; 197 /* EXPORT DELETE START */ 198 break; 199 /* EXPORT DELETE END */ 200 case rpc_gss_svc_integrity: 201 if ((major = kgss_sign(&minor, context, qop, &in_buf, 202 &out_buf)) != GSS_S_COMPLETE) { 203 RPCGSS_LOG1(1, "rpc_gss_wrap: kgss_sign failed." 204 "major = %x, minor = %x", major, minor); 205 goto fail; 206 } 207 break; 208 default: 209 goto fail; 210 } 211 212 /* 213 * write out in_buf and out_buf as needed 214 */ 215 if (in_buf.length != 0) { 216 if (!__xdr_gss_buf(out_xdrs, &in_buf)) 217 goto fail; 218 } 219 220 if (!__xdr_gss_buf(out_xdrs, &out_buf)) 221 goto fail; 222 ret = TRUE; 223 fail: 224 kmem_free(mp, size); 225 if (out_buf.length != 0) 226 (void) gss_release_buffer(&minor, &out_buf); 227 return (ret); 228 } 229 230 /* 231 * Generic routine to unwrap data used by client and server sides. 232 */ 233 bool_t 234 __rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, 235 xdr_func, xdr_ptr) 236 rpc_gss_service_t service; 237 gss_ctx_id_t context; 238 uint_t seq_num; 239 OM_uint32 qop_check; 240 XDR *in_xdrs; 241 bool_t (*xdr_func)(); 242 caddr_t xdr_ptr; 243 { 244 gss_buffer_desc in_buf, out_buf; 245 XDR temp_xdrs; 246 uint_t seq_num2; 247 bool_t conf = FALSE; 248 OM_uint32 major = GSS_S_COMPLETE, minor = 0; 249 int qop = 0; 250 251 in_buf.value = NULL; 252 out_buf.value = NULL; 253 254 /* 255 * Pull out wrapped data. For privacy service, this is the 256 * encrypted data. For integrity service, this is the data 257 * followed by a checksum. 258 */ 259 if (!__xdr_gss_buf(in_xdrs, &in_buf)) { 260 return (FALSE); 261 } 262 263 if (service == rpc_gss_svc_privacy) { 264 major = GSS_S_FAILURE; 265 /* EXPORT DELETE START */ 266 major = kgss_unseal(&minor, context, &in_buf, &out_buf, &conf, 267 &qop); 268 /* EXPORT DELETE END */ 269 kmem_free(in_buf.value, in_buf.length); 270 if (major != GSS_S_COMPLETE) { 271 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_unseal failed." 272 "major = %x, minor = %x", major, minor); 273 return (FALSE); 274 } 275 /* 276 * Keep the returned token (unencrypted data) in in_buf. 277 */ 278 in_buf.length = out_buf.length; 279 in_buf.value = out_buf.value; 280 281 /* 282 * If privacy was not used, or if QOP is not what we are 283 * expecting, fail. 284 */ 285 if (!conf || qop != qop_check) 286 goto fail; 287 288 } else if (service == rpc_gss_svc_integrity) { 289 if (!__xdr_gss_buf(in_xdrs, &out_buf)) { 290 return (FALSE); 291 } 292 major = kgss_verify(&minor, context, &in_buf, &out_buf, 293 &qop); 294 kmem_free(out_buf.value, out_buf.length); 295 if (major != GSS_S_COMPLETE) { 296 kmem_free(in_buf.value, in_buf.length); 297 RPCGSS_LOG1(1, "rpc_gss_unwrap: kgss_verify failed." 298 "major = %x, minor = %x", major, minor); 299 return (FALSE); 300 } 301 302 /* 303 * If QOP is not what we are expecting, fail. 304 */ 305 if (qop != qop_check) 306 goto fail; 307 } 308 309 xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE); 310 311 /* 312 * The data consists of the sequence number followed by the 313 * arguments. Make sure sequence number is what we are 314 * expecting (i.e., the value in the header). 315 */ 316 if (!xdr_u_int(&temp_xdrs, &seq_num2)) 317 goto fail; 318 if (seq_num2 != seq_num) 319 goto fail; 320 321 /* 322 * Deserialize the arguments into xdr_ptr, and release in_buf. 323 */ 324 if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) { 325 goto fail; 326 } 327 328 if (service == rpc_gss_svc_privacy) 329 (void) gss_release_buffer(&minor, &in_buf); 330 else 331 kmem_free(in_buf.value, in_buf.length); 332 XDR_DESTROY(&temp_xdrs); 333 return (TRUE); 334 fail: 335 XDR_DESTROY(&temp_xdrs); 336 if (service == rpc_gss_svc_privacy) 337 (void) gss_release_buffer(&minor, &in_buf); 338 else 339 kmem_free(in_buf.value, in_buf.length); 340 return (FALSE); 341 } 342