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