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 */
52struct 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 */
73bool_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
81char *
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
88bool_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
96char *
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
106bool_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
122char *
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 */
143bool_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 */
240char **
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
262char **
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 */
284bool_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 */
295bool_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