xref: /titanic_50/usr/src/lib/rpcsec_gss/rpcsec_gss_utils.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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  * Copyright (c) 1986-1995,1997, by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <strings.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <syslog.h>
37 #include <gssapi/gssapi.h>
38 #include <gssapi/gssapi_ext.h>
39 #include <rpc/rpc.h>
40 #include <rpc/rpcsec_defs.h>
41 #include <rpc/trace.h>
42 
43 #define	SVC_INTEGRITY	"integrity"
44 #define	SVC_PRIVACY	"privacy"
45 #define	SVC_NONE	"none"
46 #define	SVC_DEFAULT	"default"
47 
48 #define	MCALL_MSG_SIZE 24
49 /*
50  * Private data kept per client handle
51  */
52 struct cu_data {
53 	int			cu_fd;		/* connections fd */
54 	bool_t			cu_closeit;	/* opened by library */
55 	struct netbuf		cu_raddr;	/* remote address */
56 	struct timeval		cu_wait;	/* retransmit interval */
57 	struct timeval		cu_total;	/* total time for the call */
58 	struct rpc_err		cu_error;
59 	struct t_unitdata	*cu_tr_data;
60 	XDR			cu_outxdrs;
61 	char			*cu_outbuf_start;
62 	char			cu_outbuf[MCALL_MSG_SIZE];
63 	u_int			cu_xdrpos;
64 	u_int			cu_sendsz;	/* send size */
65 	u_int			cu_recvsz;	/* recv size */
66 	struct pollfd		pfdp;
67 	char			cu_inbuf[1];
68 };
69 
70 /*
71  * Internal utility routines.
72  */
73 bool_t
74 __rpc_gss_mech_to_oid(mech, oid)
75 	char	*mech;
76 	rpc_gss_OID	*oid;
77 {
78 
79 	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
80 		return (FALSE);
81 
82 	return (TRUE);
83 }
84 
85 char *
86 __rpc_gss_oid_to_mech(oid)
87 	rpc_gss_OID	oid;
88 {
89 
90 	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
91 }
92 
93 
94 bool_t
95 __rpc_gss_qop_to_num(qop, mech, num)
96 	char		*qop;
97 	char		*mech;
98 	OM_uint32	*num;
99 {
100 
101 	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
102 		return (FALSE);
103 	return (TRUE);
104 }
105 
106 char *
107 __rpc_gss_num_to_qop(mech, num)
108 	char		*mech;
109 	OM_uint32	num;
110 {
111 	char *qop;
112 
113 	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
114 		return (NULL);
115 	return (qop);
116 }
117 
118 bool_t
119 __rpc_gss_svc_to_num(svc, num)
120 	char			*svc;
121 	rpc_gss_service_t	*num;
122 {
123 	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
124 		*num = rpc_gss_svc_integrity;
125 	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
126 		*num = rpc_gss_svc_privacy;
127 	else if (strcasecmp(svc, SVC_NONE) == 0)
128 		*num = rpc_gss_svc_none;
129 	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
130 		*num = rpc_gss_svc_default;
131 	else
132 		return (FALSE);
133 	return (TRUE);
134 }
135 
136 char *
137 __rpc_gss_num_to_svc(num)
138 	rpc_gss_service_t	num;
139 {
140 	switch (num) {
141 	case rpc_gss_svc_integrity:
142 		return (strdup(SVC_INTEGRITY));
143 	case rpc_gss_svc_privacy:
144 		return (strdup(SVC_PRIVACY));
145 	case rpc_gss_svc_none:
146 		return (strdup(SVC_NONE));
147 	case rpc_gss_svc_default:
148 		return (strdup(SVC_DEFAULT));
149 	default:
150 		return (NULL);
151 	}
152 }
153 
154 /*
155  * Given the user name, node, and security domain, get the mechanism
156  * specific principal name (for the user name) in exported form.
157  */
158 bool_t
159 __rpc_gss_get_principal_name(principal, mech, user, node, secdomain)
160 	rpc_gss_principal_t	*principal;
161 	char			*mech;
162 	char			*user;
163 	char			*node;
164 	char			*secdomain;
165 {
166 	gss_name_t		gss_name, gss_canon_name;
167 	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
168 	char			user_name[256], *s;
169 	gss_OID			mech_oid;
170 	int			nlen = 0, slen = 0, plen;
171 	OM_uint32		major, minor;
172 
173 	*principal = NULL;
174 	if (user == NULL || strlen(user) == 0)
175 		return (FALSE);
176 
177 	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
178 		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
179 			"mech oid");
180 		return (FALSE);
181 	}
182 
183 	if (secdomain != NULL)
184 		slen = strlen(secdomain);
185 
186 	if (node != NULL)
187 		nlen = strlen(node);
188 
189 	strcpy(user_name, user);
190 	if (nlen > 0) {
191 		strcat(user_name, "/");
192 		strcat(user_name, node);
193 	}
194 
195 	if (slen > 0) {
196 		strcat(user_name, "@");
197 		strcat(user_name, secdomain);
198 	}
199 
200 	name_buf.value = user_name;
201 	name_buf.length = strlen(user_name);
202 
203 	/*
204 	 *  Convert a text string to a GSSAPI Internal name.
205 	 */
206 	if ((major = gss_import_name(&minor, &name_buf,
207 		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
208 		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
209 			"failed 0x%x", major);
210 		return (FALSE);
211 	}
212 
213 	/*
214 	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
215 	 */
216 	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
217 		&gss_canon_name)) != GSS_S_COMPLETE) {
218 		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
219 			"failed 0x%x", major);
220 		gss_release_name(&minor, &gss_name);
221 		return (FALSE);
222 	}
223 	gss_release_name(&minor, &gss_name);
224 
225 	/*
226 	 *  Convert the MN Internal name to an exported flat name, so
227 	 *  it is suitable for binary comparison.
228 	 */
229 	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
230 		GSS_S_COMPLETE) {
231 		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
232 			"failed %x", major);
233 		gss_release_name(&minor, &gss_canon_name);
234 		return (FALSE);
235 	}
236 	gss_release_name(&minor, &gss_canon_name);
237 
238 	/*
239 	 *  Put the exported name into rpc_gss_principal_t structure.
240 	 */
241 	plen = RNDUP(name_buf.length) + sizeof (int);
242 	(*principal) = (rpc_gss_principal_t)malloc(plen);
243 	if ((*principal) == NULL) {
244 		gss_release_buffer(&minor, &name_buf);
245 		return (FALSE);
246 	}
247 	bzero((caddr_t)(*principal), plen);
248 	(*principal)->len = RNDUP(name_buf.length);
249 	s = (*principal)->name;
250 	memcpy(s, name_buf.value, name_buf.length);
251 	gss_release_buffer(&minor, &name_buf);
252 
253 	return (TRUE);
254 }
255 
256 /*
257  * Return supported mechanisms.
258  */
259 char **
260 __rpc_gss_get_mechanisms()
261 {
262 	static char	*mech_list[MAX_MECH_OID_PAIRS+1];
263 
264 	*mech_list = NULL;
265 	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
266 	return (mech_list);
267 }
268 
269 /*
270  * For a given mechanism, return information about it.
271  */
272 /*
273  * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
274  */
275 
276 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
277 /* Don't know how to get the service type for a given mech.	*/
278 /* "service" should NOT be there!				*/
279 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
280 
281 char **
282 __rpc_gss_get_mech_info(mech, service)
283 	char			*mech;
284 	rpc_gss_service_t	*service;
285 {
286 	char **l;
287 
288 	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
289 	if (l == NULL)
290 		return (NULL);
291 
292 	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
293 		free(l);
294 		return (NULL);
295 	}
296 					/* !!!!!!!!!!!!!!!! */
297 	*service = rpc_gss_svc_privacy; /* What service type? */
298 					/* !!!!!!!!!!!!!!!! */
299 	return (l);
300 }
301 
302 /*
303  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
304  */
305 bool_t
306 __rpc_gss_get_versions(vers_hi, vers_lo)
307 	u_int	*vers_hi;
308 	u_int	*vers_lo;
309 {
310 	*vers_hi = RPCSEC_GSS_VERSION;
311 	*vers_lo = RPCSEC_GSS_VERSION;
312 	return (TRUE);
313 }
314 
315 /*
316  * Check if a mechanism is installed.
317  */
318 bool_t
319 __rpc_gss_is_installed(mech)
320 	char	*mech;
321 {
322 	char **l;
323 
324 	if (mech == NULL)
325 		return (FALSE);
326 
327 	if ((l = __rpc_gss_get_mechanisms()) == NULL)
328 		return (FALSE);
329 
330 	while (*l != NULL) {
331 		if (strcmp(*l, mech) == 0)
332 			return (TRUE);
333 		l++;
334 	}
335 	return (FALSE);
336 }
337