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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "mt.h" 30 #include "rpc_mt.h" 31 #include <stdio.h> 32 #include <atomic.h> 33 #include <sys/errno.h> 34 #include <dlfcn.h> 35 #include <rpc/rpc.h> 36 37 #define RPCSEC "rpcsec.so.1" 38 39 typedef struct { 40 AUTH *(*rpc_gss_seccreate)(); 41 bool_t (*rpc_gss_set_defaults)(); 42 bool_t (*rpc_gss_get_principal_name)(); 43 char **(*rpc_gss_get_mechanisms)(); 44 char **(*rpc_gss_get_mech_info)(); 45 bool_t (*rpc_gss_get_versions)(); 46 bool_t (*rpc_gss_is_installed)(); 47 bool_t (*rpc_gss_set_svc_name)(); 48 bool_t (*rpc_gss_set_callback)(); 49 bool_t (*rpc_gss_getcred)(); 50 bool_t (*rpc_gss_mech_to_oid)(); 51 bool_t (*rpc_gss_qop_to_num)(); 52 enum auth_stat (*__svcrpcsec_gss)(); 53 bool_t (*__rpc_gss_wrap)(); 54 bool_t (*__rpc_gss_unwrap)(); 55 int (*rpc_gss_max_data_length)(); 56 int (*rpc_gss_svc_max_data_length)(); 57 void (*rpc_gss_get_error)(); 58 } rpcgss_calls_t; 59 60 static rpcgss_calls_t calls; 61 static mutex_t rpcgss_calls_mutex = DEFAULTMUTEX; 62 static bool_t initialized = FALSE; 63 64 static bool_t 65 rpcgss_calls_init(void) 66 { 67 void *handle; 68 bool_t ret = FALSE; 69 70 if (initialized) { 71 membar_consumer(); 72 return (TRUE); 73 } 74 (void) mutex_lock(&rpcgss_calls_mutex); 75 if (initialized) { 76 (void) mutex_unlock(&rpcgss_calls_mutex); 77 membar_consumer(); 78 return (TRUE); 79 } 80 81 if ((handle = dlopen(RPCSEC, RTLD_LAZY)) == NULL) 82 goto done; 83 84 if ((calls.rpc_gss_seccreate = (AUTH *(*)()) dlsym(handle, 85 "__rpc_gss_seccreate")) == NULL) 86 goto done; 87 if ((calls.rpc_gss_set_defaults = (bool_t (*)()) dlsym(handle, 88 "__rpc_gss_set_defaults")) == NULL) 89 goto done; 90 if ((calls.rpc_gss_get_principal_name = (bool_t (*)()) dlsym(handle, 91 "__rpc_gss_get_principal_name")) == NULL) 92 goto done; 93 if ((calls.rpc_gss_get_mechanisms = (char **(*)()) dlsym(handle, 94 "__rpc_gss_get_mechanisms")) == NULL) 95 goto done; 96 if ((calls.rpc_gss_get_mech_info = (char **(*)()) dlsym(handle, 97 "__rpc_gss_get_mech_info")) == NULL) 98 goto done; 99 if ((calls.rpc_gss_get_versions = (bool_t (*)()) dlsym(handle, 100 "__rpc_gss_get_versions")) == NULL) 101 goto done; 102 if ((calls.rpc_gss_is_installed = (bool_t (*)()) dlsym(handle, 103 "__rpc_gss_is_installed")) == NULL) 104 goto done; 105 if ((calls.rpc_gss_set_svc_name = (bool_t (*)()) dlsym(handle, 106 "__rpc_gss_set_svc_name")) == NULL) 107 goto done; 108 if ((calls.rpc_gss_set_callback = (bool_t (*)()) dlsym(handle, 109 "__rpc_gss_set_callback")) == NULL) 110 goto done; 111 if ((calls.rpc_gss_getcred = (bool_t (*)()) dlsym(handle, 112 "__rpc_gss_getcred")) == NULL) 113 goto done; 114 if ((calls.rpc_gss_mech_to_oid = (bool_t (*)()) dlsym(handle, 115 "__rpc_gss_mech_to_oid")) == NULL) 116 goto done; 117 118 if ((calls.rpc_gss_qop_to_num = (bool_t (*)()) dlsym(handle, 119 "__rpc_gss_qop_to_num")) == NULL) 120 goto done; 121 if ((calls.__svcrpcsec_gss = (enum auth_stat (*)()) dlsym(handle, 122 "__svcrpcsec_gss")) == NULL) 123 goto done; 124 if ((calls.__rpc_gss_wrap = (bool_t (*)()) dlsym(handle, 125 "__rpc_gss_wrap")) == NULL) 126 goto done; 127 if ((calls.__rpc_gss_unwrap = (bool_t (*)()) dlsym(handle, 128 "__rpc_gss_unwrap")) == NULL) 129 goto done; 130 if ((calls.rpc_gss_max_data_length = (int (*)()) dlsym(handle, 131 "__rpc_gss_max_data_length")) == NULL) 132 goto done; 133 if ((calls.rpc_gss_svc_max_data_length = (int (*)()) dlsym(handle, 134 "__rpc_gss_svc_max_data_length")) == NULL) 135 goto done; 136 if ((calls.rpc_gss_get_error = (void (*)()) dlsym(handle, 137 "__rpc_gss_get_error")) == NULL) 138 goto done; 139 ret = TRUE; 140 done: 141 if (!ret) { 142 if (handle != NULL) 143 (void) dlclose(handle); 144 } 145 membar_producer(); 146 initialized = ret; 147 (void) mutex_unlock(&rpcgss_calls_mutex); 148 return (ret); 149 } 150 151 AUTH * 152 rpc_gss_seccreate( 153 CLIENT *clnt, /* associated client handle */ 154 char *principal, /* server service principal */ 155 char *mechanism, /* security mechanism */ 156 rpc_gss_service_t service_type, /* security service */ 157 char *qop, /* requested QOP */ 158 rpc_gss_options_req_t *options_req, /* requested options */ 159 rpc_gss_options_ret_t *options_ret) /* returned options */ 160 { 161 if (!rpcgss_calls_init()) 162 return (NULL); 163 return ((*calls.rpc_gss_seccreate)(clnt, principal, mechanism, 164 service_type, qop, options_req, options_ret)); 165 } 166 167 bool_t 168 rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, char *qop) 169 { 170 if (!rpcgss_calls_init()) 171 return (FALSE); 172 return ((*calls.rpc_gss_set_defaults)(auth, service, qop)); 173 } 174 175 bool_t 176 rpc_gss_get_principal_name( 177 rpc_gss_principal_t *principal, 178 char *mechanism, 179 char *user_name, 180 char *node, 181 char *secdomain) 182 { 183 if (!rpcgss_calls_init()) 184 return (FALSE); 185 return ((*calls.rpc_gss_get_principal_name)(principal, mechanism, 186 user_name, node, secdomain)); 187 } 188 189 char ** 190 rpc_gss_get_mechanisms(void) 191 { 192 if (!rpcgss_calls_init()) 193 return (NULL); 194 return ((*calls.rpc_gss_get_mechanisms)()); 195 } 196 197 char ** 198 rpc_gss_get_mech_info(char *mechanism, rpc_gss_service_t *service) 199 { 200 if (!rpcgss_calls_init()) 201 return (NULL); 202 return ((*calls.rpc_gss_get_mech_info)(mechanism, service)); 203 } 204 205 bool_t 206 rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo) 207 { 208 if (!rpcgss_calls_init()) 209 return (FALSE); 210 return ((*calls.rpc_gss_get_versions)(vers_hi, vers_lo)); 211 } 212 213 bool_t 214 rpc_gss_is_installed(char *mechanism) 215 { 216 if (!rpcgss_calls_init()) 217 return (FALSE); 218 return ((*calls.rpc_gss_is_installed)(mechanism)); 219 } 220 221 bool_t 222 rpc_gss_set_svc_name( 223 char *principal, /* server service principal name */ 224 char *mechanism, 225 uint_t req_time, 226 uint_t program, 227 uint_t version) 228 { 229 if (!rpcgss_calls_init()) 230 return (FALSE); 231 return ((*calls.rpc_gss_set_svc_name)(principal, mechanism, req_time, 232 program, version)); 233 } 234 235 bool_t 236 rpc_gss_set_callback(rpc_gss_callback_t *cb) 237 { 238 if (!rpcgss_calls_init()) 239 return (FALSE); 240 return ((*calls.rpc_gss_set_callback)(cb)); 241 } 242 243 bool_t 244 rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred, 245 rpc_gss_ucred_t **ucred, void **cookie) 246 { 247 if (!rpcgss_calls_init()) 248 return (FALSE); 249 return ((*calls.rpc_gss_getcred)(req, rcred, ucred, cookie)); 250 } 251 252 bool_t 253 rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid) 254 { 255 if (!rpcgss_calls_init()) 256 return (FALSE); 257 return ((*calls.rpc_gss_mech_to_oid)(mech, oid)); 258 } 259 260 bool_t 261 rpc_gss_qop_to_num(char *qop, char *mech, uint_t *num) 262 { 263 if (!rpcgss_calls_init()) 264 return (FALSE); 265 return ((*calls.rpc_gss_qop_to_num)(qop, mech, num)); 266 } 267 268 enum auth_stat 269 __svcrpcsec_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) 270 { 271 if (!rpcgss_calls_init()) 272 return (AUTH_FAILED); 273 return ((*calls.__svcrpcsec_gss)(rqst, msg, no_dispatch)); 274 } 275 276 bool_t 277 __rpc_gss_wrap(AUTH *auth, char *buf, uint_t buflen, XDR *out_xdrs, 278 bool_t (*xdr_func)(), caddr_t xdr_ptr) 279 { 280 if (!rpcgss_calls_init()) 281 return (FALSE); 282 return ((*calls.__rpc_gss_wrap)(auth, buf, buflen, out_xdrs, 283 xdr_func, xdr_ptr)); 284 } 285 286 bool_t 287 __rpc_gss_unwrap(AUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(), 288 caddr_t xdr_ptr) 289 { 290 if (!rpcgss_calls_init()) 291 return (FALSE); 292 return ((*calls.__rpc_gss_unwrap)(auth, in_xdrs, xdr_func, xdr_ptr)); 293 } 294 295 int 296 rpc_gss_max_data_length(AUTH *rpcgss_handle, int max_tp_unit_len) 297 { 298 if (!rpcgss_calls_init()) 299 return (0); 300 return ((*calls.rpc_gss_max_data_length)(rpcgss_handle, 301 max_tp_unit_len)); 302 } 303 304 int 305 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) 306 { 307 if (!rpcgss_calls_init()) 308 return (0); 309 return ((*calls.rpc_gss_svc_max_data_length)(req, max_tp_unit_len)); 310 } 311 312 void 313 rpc_gss_get_error(rpc_gss_error_t *error) 314 { 315 if (!rpcgss_calls_init()) { 316 error->rpc_gss_error = RPC_GSS_ER_SYSTEMERROR; 317 error->system_error = ENOTSUP; 318 return; 319 } 320 (*calls.rpc_gss_get_error)(error); 321 } 322