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