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
rpcgss_calls_init(void)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 *
rpc_gss_seccreate(CLIENT * clnt,char * principal,char * mechanism,rpc_gss_service_t service_type,char * qop,rpc_gss_options_req_t * options_req,rpc_gss_options_ret_t * options_ret)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
rpc_gss_set_defaults(AUTH * auth,rpc_gss_service_t service,char * qop)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
rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mechanism,char * user_name,char * node,char * secdomain)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 **
rpc_gss_get_mechanisms(void)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 **
rpc_gss_get_mech_info(char * mechanism,rpc_gss_service_t * service)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
rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)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
rpc_gss_is_installed(char * mechanism)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
rpc_gss_set_svc_name(char * principal,char * mechanism,uint_t req_time,uint_t program,uint_t version)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
rpc_gss_set_callback(rpc_gss_callback_t * cb)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
rpc_gss_getcred(struct svc_req * req,rpc_gss_rawcred_t ** rcred,rpc_gss_ucred_t ** ucred,void ** cookie)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
rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)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
rpc_gss_qop_to_num(char * qop,char * mech,uint_t * num)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
__svcrpcsec_gss(struct svc_req * rqst,struct rpc_msg * msg,bool_t * no_dispatch)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
__rpc_gss_wrap(AUTH * auth,char * buf,uint_t buflen,XDR * out_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)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
__rpc_gss_unwrap(AUTH * auth,XDR * in_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)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
rpc_gss_max_data_length(AUTH * rpcgss_handle,int max_tp_unit_len)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
rpc_gss_svc_max_data_length(struct svc_req * req,int max_tp_unit_len)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
rpc_gss_get_error(rpc_gss_error_t * error)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