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