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