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 <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <syslog.h>
38 #include <gssapi/gssapi.h>
39 #include <gssapi/gssapi_ext.h>
40 #include <rpc/rpc.h>
41 #include <rpc/rpcsec_defs.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 	uint_t			cu_xdrpos;
64 	uint_t			cu_sendsz;	/* send size */
65 	uint_t			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(char *mech, rpc_gss_OID *oid)
75 {
76 	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
77 		return (FALSE);
78 	return (TRUE);
79 }
80 
81 char *
82 __rpc_gss_oid_to_mech(rpc_gss_OID oid)
83 {
84 	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
85 }
86 
87 
88 bool_t
89 __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
90 {
91 	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
92 		return (FALSE);
93 	return (TRUE);
94 }
95 
96 char *
97 __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
98 {
99 	char *qop;
100 
101 	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
102 		return (NULL);
103 	return (qop);
104 }
105 
106 bool_t
107 __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
108 {
109 	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
110 		*num = rpc_gss_svc_integrity;
111 	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
112 		*num = rpc_gss_svc_privacy;
113 	else if (strcasecmp(svc, SVC_NONE) == 0)
114 		*num = rpc_gss_svc_none;
115 	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
116 		*num = rpc_gss_svc_default;
117 	else
118 		return (FALSE);
119 	return (TRUE);
120 }
121 
122 char *
123 __rpc_gss_num_to_svc(rpc_gss_service_t num)
124 {
125 	switch (num) {
126 	case rpc_gss_svc_integrity:
127 		return (strdup(SVC_INTEGRITY));
128 	case rpc_gss_svc_privacy:
129 		return (strdup(SVC_PRIVACY));
130 	case rpc_gss_svc_none:
131 		return (strdup(SVC_NONE));
132 	case rpc_gss_svc_default:
133 		return (strdup(SVC_DEFAULT));
134 	default:
135 		return (NULL);
136 	}
137 }
138 
139 /*
140  * Given the user name, node, and security domain, get the mechanism
141  * specific principal name (for the user name) in exported form.
142  */
143 bool_t
144 __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
145 				char *user, char *node, char *secdomain)
146 {
147 	gss_name_t		gss_name, gss_canon_name;
148 	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
149 	char			user_name[256], *s;
150 	gss_OID			mech_oid;
151 	int			nlen = 0, slen = 0, plen;
152 	OM_uint32		major, minor;
153 
154 	*principal = NULL;
155 	if (user == NULL || strlen(user) == 0)
156 		return (FALSE);
157 
158 	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
159 		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
160 			"mech oid");
161 		return (FALSE);
162 	}
163 
164 	if (secdomain != NULL)
165 		slen = strlen(secdomain);
166 
167 	if (node != NULL)
168 		nlen = strlen(node);
169 
170 	strcpy(user_name, user);
171 	if (nlen > 0) {
172 		strcat(user_name, "/");
173 		strcat(user_name, node);
174 	}
175 
176 	if (slen > 0) {
177 		strcat(user_name, "@");
178 		strcat(user_name, secdomain);
179 	}
180 
181 	name_buf.value = user_name;
182 	name_buf.length = strlen(user_name);
183 
184 	/*
185 	 *  Convert a text string to a GSSAPI Internal name.
186 	 */
187 	if ((major = gss_import_name(&minor, &name_buf,
188 		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
189 		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
190 			"failed 0x%x", major);
191 		return (FALSE);
192 	}
193 
194 	/*
195 	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
196 	 */
197 	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
198 		&gss_canon_name)) != GSS_S_COMPLETE) {
199 		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
200 			"failed 0x%x", major);
201 		gss_release_name(&minor, &gss_name);
202 		return (FALSE);
203 	}
204 	gss_release_name(&minor, &gss_name);
205 
206 	/*
207 	 *  Convert the MN Internal name to an exported flat name, so
208 	 *  it is suitable for binary comparison.
209 	 */
210 	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
211 		GSS_S_COMPLETE) {
212 		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
213 			"failed %x", major);
214 		gss_release_name(&minor, &gss_canon_name);
215 		return (FALSE);
216 	}
217 	gss_release_name(&minor, &gss_canon_name);
218 
219 	/*
220 	 *  Put the exported name into rpc_gss_principal_t structure.
221 	 */
222 	plen = RNDUP(name_buf.length) + sizeof (int);
223 	(*principal) = malloc(plen);
224 	if ((*principal) == NULL) {
225 		gss_release_buffer(&minor, &name_buf);
226 		return (FALSE);
227 	}
228 	bzero((caddr_t)(*principal), plen);
229 	(*principal)->len = RNDUP(name_buf.length);
230 	s = (*principal)->name;
231 	memcpy(s, name_buf.value, name_buf.length);
232 	gss_release_buffer(&minor, &name_buf);
233 
234 	return (TRUE);
235 }
236 
237 /*
238  * Return supported mechanisms.
239  */
240 char **
241 __rpc_gss_get_mechanisms(void)
242 {
243 	static char	*mech_list[MAX_MECH_OID_PAIRS+1];
244 
245 	*mech_list = NULL;
246 	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
247 	return (mech_list);
248 }
249 
250 /*
251  * For a given mechanism, return information about it.
252  */
253 /*
254  * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
255  */
256 
257 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
258 /* Don't know how to get the service type for a given mech.	*/
259 /* "service" should NOT be there!				*/
260 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
261 
262 char **
263 __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
264 {
265 	char **l;
266 
267 	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
268 	if (l == NULL)
269 		return (NULL);
270 
271 	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
272 		free(l);
273 		return (NULL);
274 	}
275 					/* !!!!!!!!!!!!!!!! */
276 	*service = rpc_gss_svc_privacy; /* What service type? */
277 					/* !!!!!!!!!!!!!!!! */
278 	return (l);
279 }
280 
281 /*
282  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
283  */
284 bool_t
285 __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
286 {
287 	*vers_hi = RPCSEC_GSS_VERSION;
288 	*vers_lo = RPCSEC_GSS_VERSION;
289 	return (TRUE);
290 }
291 
292 /*
293  * Check if a mechanism is installed.
294  */
295 bool_t
296 __rpc_gss_is_installed(char *mech)
297 {
298 	char **l;
299 
300 	if (mech == NULL)
301 		return (FALSE);
302 
303 	if ((l = __rpc_gss_get_mechanisms()) == NULL)
304 		return (FALSE);
305 
306 	while (*l != NULL) {
307 		if (strcmp(*l, mech) == 0)
308 			return (TRUE);
309 		l++;
310 	}
311 	return (FALSE);
312 }
313