17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*61961e0fSrobinson 
237c478bd9Sstevel@tonic-gate /*
24*61961e0fSrobinson  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*61961e0fSrobinson  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <syslog.h>
367c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
377c478bd9Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
387c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
397c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #define	SVC_INTEGRITY	"integrity"
427c478bd9Sstevel@tonic-gate #define	SVC_PRIVACY	"privacy"
437c478bd9Sstevel@tonic-gate #define	SVC_NONE	"none"
447c478bd9Sstevel@tonic-gate #define	SVC_DEFAULT	"default"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	MCALL_MSG_SIZE 24
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Private data kept per client handle
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate struct cu_data {
517c478bd9Sstevel@tonic-gate 	int			cu_fd;		/* connections fd */
527c478bd9Sstevel@tonic-gate 	bool_t			cu_closeit;	/* opened by library */
537c478bd9Sstevel@tonic-gate 	struct netbuf		cu_raddr;	/* remote address */
547c478bd9Sstevel@tonic-gate 	struct timeval		cu_wait;	/* retransmit interval */
557c478bd9Sstevel@tonic-gate 	struct timeval		cu_total;	/* total time for the call */
567c478bd9Sstevel@tonic-gate 	struct rpc_err		cu_error;
577c478bd9Sstevel@tonic-gate 	struct t_unitdata	*cu_tr_data;
587c478bd9Sstevel@tonic-gate 	XDR			cu_outxdrs;
597c478bd9Sstevel@tonic-gate 	char			*cu_outbuf_start;
607c478bd9Sstevel@tonic-gate 	char			cu_outbuf[MCALL_MSG_SIZE];
61*61961e0fSrobinson 	uint_t			cu_xdrpos;
62*61961e0fSrobinson 	uint_t			cu_sendsz;	/* send size */
63*61961e0fSrobinson 	uint_t			cu_recvsz;	/* recv size */
647c478bd9Sstevel@tonic-gate 	struct pollfd		pfdp;
657c478bd9Sstevel@tonic-gate 	char			cu_inbuf[1];
667c478bd9Sstevel@tonic-gate };
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Internal utility routines.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)72*61961e0fSrobinson __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
757c478bd9Sstevel@tonic-gate 		return (FALSE);
767c478bd9Sstevel@tonic-gate 	return (TRUE);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)80*61961e0fSrobinson __rpc_gss_oid_to_mech(rpc_gss_OID oid)
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate 	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)87*61961e0fSrobinson __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
907c478bd9Sstevel@tonic-gate 		return (FALSE);
917c478bd9Sstevel@tonic-gate 	return (TRUE);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate char *
__rpc_gss_num_to_qop(char * mech,OM_uint32 num)95*61961e0fSrobinson __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate 	char *qop;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
1007c478bd9Sstevel@tonic-gate 		return (NULL);
1017c478bd9Sstevel@tonic-gate 	return (qop);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_svc_to_num(char * svc,rpc_gss_service_t * num)105*61961e0fSrobinson __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
1087c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_integrity;
1097c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
1107c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_privacy;
1117c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_NONE) == 0)
1127c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_none;
1137c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
1147c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_default;
1157c478bd9Sstevel@tonic-gate 	else
1167c478bd9Sstevel@tonic-gate 		return (FALSE);
1177c478bd9Sstevel@tonic-gate 	return (TRUE);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)121*61961e0fSrobinson __rpc_gss_num_to_svc(rpc_gss_service_t num)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	switch (num) {
1247c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_integrity:
1257c478bd9Sstevel@tonic-gate 		return (strdup(SVC_INTEGRITY));
1267c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_privacy:
1277c478bd9Sstevel@tonic-gate 		return (strdup(SVC_PRIVACY));
1287c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_none:
1297c478bd9Sstevel@tonic-gate 		return (strdup(SVC_NONE));
1307c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_default:
1317c478bd9Sstevel@tonic-gate 		return (strdup(SVC_DEFAULT));
1327c478bd9Sstevel@tonic-gate 	default:
1337c478bd9Sstevel@tonic-gate 		return (NULL);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Given the user name, node, and security domain, get the mechanism
1397c478bd9Sstevel@tonic-gate  * specific principal name (for the user name) in exported form.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mech,char * user,char * node,char * secdomain)142*61961e0fSrobinson __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
143*61961e0fSrobinson 				char *user, char *node, char *secdomain)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	gss_name_t		gss_name, gss_canon_name;
1467c478bd9Sstevel@tonic-gate 	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
1477c478bd9Sstevel@tonic-gate 	char			user_name[256], *s;
1487c478bd9Sstevel@tonic-gate 	gss_OID			mech_oid;
1497c478bd9Sstevel@tonic-gate 	int			nlen = 0, slen = 0, plen;
1507c478bd9Sstevel@tonic-gate 	OM_uint32		major, minor;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	*principal = NULL;
1537c478bd9Sstevel@tonic-gate 	if (user == NULL || strlen(user) == 0)
1547c478bd9Sstevel@tonic-gate 		return (FALSE);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
1577c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
1587c478bd9Sstevel@tonic-gate 			"mech oid");
1597c478bd9Sstevel@tonic-gate 		return (FALSE);
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	if (secdomain != NULL)
1637c478bd9Sstevel@tonic-gate 		slen = strlen(secdomain);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (node != NULL)
1667c478bd9Sstevel@tonic-gate 		nlen = strlen(node);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	strcpy(user_name, user);
1697c478bd9Sstevel@tonic-gate 	if (nlen > 0) {
1707c478bd9Sstevel@tonic-gate 		strcat(user_name, "/");
1717c478bd9Sstevel@tonic-gate 		strcat(user_name, node);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (slen > 0) {
1757c478bd9Sstevel@tonic-gate 		strcat(user_name, "@");
1767c478bd9Sstevel@tonic-gate 		strcat(user_name, secdomain);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	name_buf.value = user_name;
1807c478bd9Sstevel@tonic-gate 	name_buf.length = strlen(user_name);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 *  Convert a text string to a GSSAPI Internal name.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if ((major = gss_import_name(&minor, &name_buf,
1867c478bd9Sstevel@tonic-gate 		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
1877c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
1887c478bd9Sstevel@tonic-gate 			"failed 0x%x", major);
1897c478bd9Sstevel@tonic-gate 		return (FALSE);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/*
1937c478bd9Sstevel@tonic-gate 	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
1947c478bd9Sstevel@tonic-gate 	 */
1957c478bd9Sstevel@tonic-gate 	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
1967c478bd9Sstevel@tonic-gate 		&gss_canon_name)) != GSS_S_COMPLETE) {
1977c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
1987c478bd9Sstevel@tonic-gate 			"failed 0x%x", major);
1997c478bd9Sstevel@tonic-gate 		gss_release_name(&minor, &gss_name);
2007c478bd9Sstevel@tonic-gate 		return (FALSE);
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 	gss_release_name(&minor, &gss_name);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 *  Convert the MN Internal name to an exported flat name, so
2067c478bd9Sstevel@tonic-gate 	 *  it is suitable for binary comparison.
2077c478bd9Sstevel@tonic-gate 	 */
2087c478bd9Sstevel@tonic-gate 	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
2097c478bd9Sstevel@tonic-gate 		GSS_S_COMPLETE) {
2107c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
2117c478bd9Sstevel@tonic-gate 			"failed %x", major);
2127c478bd9Sstevel@tonic-gate 		gss_release_name(&minor, &gss_canon_name);
2137c478bd9Sstevel@tonic-gate 		return (FALSE);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	gss_release_name(&minor, &gss_canon_name);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/*
2187c478bd9Sstevel@tonic-gate 	 *  Put the exported name into rpc_gss_principal_t structure.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	plen = RNDUP(name_buf.length) + sizeof (int);
221*61961e0fSrobinson 	(*principal) = malloc(plen);
2227c478bd9Sstevel@tonic-gate 	if ((*principal) == NULL) {
2237c478bd9Sstevel@tonic-gate 		gss_release_buffer(&minor, &name_buf);
2247c478bd9Sstevel@tonic-gate 		return (FALSE);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	bzero((caddr_t)(*principal), plen);
2277c478bd9Sstevel@tonic-gate 	(*principal)->len = RNDUP(name_buf.length);
2287c478bd9Sstevel@tonic-gate 	s = (*principal)->name;
2297c478bd9Sstevel@tonic-gate 	memcpy(s, name_buf.value, name_buf.length);
2307c478bd9Sstevel@tonic-gate 	gss_release_buffer(&minor, &name_buf);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (TRUE);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * Return supported mechanisms.
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate char **
__rpc_gss_get_mechanisms(void)239*61961e0fSrobinson __rpc_gss_get_mechanisms(void)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	static char	*mech_list[MAX_MECH_OID_PAIRS+1];
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	*mech_list = NULL;
2447c478bd9Sstevel@tonic-gate 	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
2457c478bd9Sstevel@tonic-gate 	return (mech_list);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * For a given mechanism, return information about it.
2507c478bd9Sstevel@tonic-gate  */
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate  * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
2567c478bd9Sstevel@tonic-gate /* Don't know how to get the service type for a given mech.	*/
2577c478bd9Sstevel@tonic-gate /* "service" should NOT be there!				*/
2587c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate char **
__rpc_gss_get_mech_info(char * mech,rpc_gss_service_t * service)261*61961e0fSrobinson __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	char **l;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
2667c478bd9Sstevel@tonic-gate 	if (l == NULL)
2677c478bd9Sstevel@tonic-gate 		return (NULL);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
2707c478bd9Sstevel@tonic-gate 		free(l);
2717c478bd9Sstevel@tonic-gate 		return (NULL);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2747c478bd9Sstevel@tonic-gate 	*service = rpc_gss_svc_privacy; /* What service type? */
2757c478bd9Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2767c478bd9Sstevel@tonic-gate 	return (l);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
2817c478bd9Sstevel@tonic-gate  */
2827c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)283*61961e0fSrobinson __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	*vers_hi = RPCSEC_GSS_VERSION;
2867c478bd9Sstevel@tonic-gate 	*vers_lo = RPCSEC_GSS_VERSION;
2877c478bd9Sstevel@tonic-gate 	return (TRUE);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Check if a mechanism is installed.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_is_installed(char * mech)294*61961e0fSrobinson __rpc_gss_is_installed(char *mech)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	char **l;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (mech == NULL)
2997c478bd9Sstevel@tonic-gate 		return (FALSE);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	if ((l = __rpc_gss_get_mechanisms()) == NULL)
3027c478bd9Sstevel@tonic-gate 		return (FALSE);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	while (*l != NULL) {
3057c478bd9Sstevel@tonic-gate 		if (strcmp(*l, mech) == 0)
3067c478bd9Sstevel@tonic-gate 			return (TRUE);
3077c478bd9Sstevel@tonic-gate 		l++;
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 	return (FALSE);
3107c478bd9Sstevel@tonic-gate }
311