xref: /onnv-gate/usr/src/lib/rpcsec_gss/rpcsec_gss_utils.c (revision 132:e3f7eaf7dde4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*132Srobinson 
230Sstevel@tonic-gate /*
24*132Srobinson  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*132Srobinson  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <syslog.h>
380Sstevel@tonic-gate #include <gssapi/gssapi.h>
390Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
400Sstevel@tonic-gate #include <rpc/rpc.h>
410Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define	SVC_INTEGRITY	"integrity"
440Sstevel@tonic-gate #define	SVC_PRIVACY	"privacy"
450Sstevel@tonic-gate #define	SVC_NONE	"none"
460Sstevel@tonic-gate #define	SVC_DEFAULT	"default"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	MCALL_MSG_SIZE 24
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Private data kept per client handle
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate struct cu_data {
530Sstevel@tonic-gate 	int			cu_fd;		/* connections fd */
540Sstevel@tonic-gate 	bool_t			cu_closeit;	/* opened by library */
550Sstevel@tonic-gate 	struct netbuf		cu_raddr;	/* remote address */
560Sstevel@tonic-gate 	struct timeval		cu_wait;	/* retransmit interval */
570Sstevel@tonic-gate 	struct timeval		cu_total;	/* total time for the call */
580Sstevel@tonic-gate 	struct rpc_err		cu_error;
590Sstevel@tonic-gate 	struct t_unitdata	*cu_tr_data;
600Sstevel@tonic-gate 	XDR			cu_outxdrs;
610Sstevel@tonic-gate 	char			*cu_outbuf_start;
620Sstevel@tonic-gate 	char			cu_outbuf[MCALL_MSG_SIZE];
63*132Srobinson 	uint_t			cu_xdrpos;
64*132Srobinson 	uint_t			cu_sendsz;	/* send size */
65*132Srobinson 	uint_t			cu_recvsz;	/* recv size */
660Sstevel@tonic-gate 	struct pollfd		pfdp;
670Sstevel@tonic-gate 	char			cu_inbuf[1];
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Internal utility routines.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate bool_t
__rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)74*132Srobinson __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
770Sstevel@tonic-gate 		return (FALSE);
780Sstevel@tonic-gate 	return (TRUE);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate 
810Sstevel@tonic-gate char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)82*132Srobinson __rpc_gss_oid_to_mech(rpc_gss_OID oid)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 
880Sstevel@tonic-gate bool_t
__rpc_gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)89*132Srobinson __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
920Sstevel@tonic-gate 		return (FALSE);
930Sstevel@tonic-gate 	return (TRUE);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate char *
__rpc_gss_num_to_qop(char * mech,OM_uint32 num)97*132Srobinson __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	char *qop;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
1020Sstevel@tonic-gate 		return (NULL);
1030Sstevel@tonic-gate 	return (qop);
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate bool_t
__rpc_gss_svc_to_num(char * svc,rpc_gss_service_t * num)107*132Srobinson __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
1100Sstevel@tonic-gate 		*num = rpc_gss_svc_integrity;
1110Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
1120Sstevel@tonic-gate 		*num = rpc_gss_svc_privacy;
1130Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_NONE) == 0)
1140Sstevel@tonic-gate 		*num = rpc_gss_svc_none;
1150Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
1160Sstevel@tonic-gate 		*num = rpc_gss_svc_default;
1170Sstevel@tonic-gate 	else
1180Sstevel@tonic-gate 		return (FALSE);
1190Sstevel@tonic-gate 	return (TRUE);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)123*132Srobinson __rpc_gss_num_to_svc(rpc_gss_service_t num)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	switch (num) {
1260Sstevel@tonic-gate 	case rpc_gss_svc_integrity:
1270Sstevel@tonic-gate 		return (strdup(SVC_INTEGRITY));
1280Sstevel@tonic-gate 	case rpc_gss_svc_privacy:
1290Sstevel@tonic-gate 		return (strdup(SVC_PRIVACY));
1300Sstevel@tonic-gate 	case rpc_gss_svc_none:
1310Sstevel@tonic-gate 		return (strdup(SVC_NONE));
1320Sstevel@tonic-gate 	case rpc_gss_svc_default:
1330Sstevel@tonic-gate 		return (strdup(SVC_DEFAULT));
1340Sstevel@tonic-gate 	default:
1350Sstevel@tonic-gate 		return (NULL);
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * Given the user name, node, and security domain, get the mechanism
1410Sstevel@tonic-gate  * specific principal name (for the user name) in exported form.
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mech,char * user,char * node,char * secdomain)144*132Srobinson __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
145*132Srobinson 				char *user, char *node, char *secdomain)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate 	gss_name_t		gss_name, gss_canon_name;
1480Sstevel@tonic-gate 	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
1490Sstevel@tonic-gate 	char			user_name[256], *s;
1500Sstevel@tonic-gate 	gss_OID			mech_oid;
1510Sstevel@tonic-gate 	int			nlen = 0, slen = 0, plen;
1520Sstevel@tonic-gate 	OM_uint32		major, minor;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	*principal = NULL;
1550Sstevel@tonic-gate 	if (user == NULL || strlen(user) == 0)
1560Sstevel@tonic-gate 		return (FALSE);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
1590Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
1600Sstevel@tonic-gate 			"mech oid");
1610Sstevel@tonic-gate 		return (FALSE);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (secdomain != NULL)
1650Sstevel@tonic-gate 		slen = strlen(secdomain);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	if (node != NULL)
1680Sstevel@tonic-gate 		nlen = strlen(node);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	strcpy(user_name, user);
1710Sstevel@tonic-gate 	if (nlen > 0) {
1720Sstevel@tonic-gate 		strcat(user_name, "/");
1730Sstevel@tonic-gate 		strcat(user_name, node);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (slen > 0) {
1770Sstevel@tonic-gate 		strcat(user_name, "@");
1780Sstevel@tonic-gate 		strcat(user_name, secdomain);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	name_buf.value = user_name;
1820Sstevel@tonic-gate 	name_buf.length = strlen(user_name);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	/*
1850Sstevel@tonic-gate 	 *  Convert a text string to a GSSAPI Internal name.
1860Sstevel@tonic-gate 	 */
1870Sstevel@tonic-gate 	if ((major = gss_import_name(&minor, &name_buf,
1880Sstevel@tonic-gate 		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
1890Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
1900Sstevel@tonic-gate 			"failed 0x%x", major);
1910Sstevel@tonic-gate 		return (FALSE);
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
1960Sstevel@tonic-gate 	 */
1970Sstevel@tonic-gate 	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
1980Sstevel@tonic-gate 		&gss_canon_name)) != GSS_S_COMPLETE) {
1990Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
2000Sstevel@tonic-gate 			"failed 0x%x", major);
2010Sstevel@tonic-gate 		gss_release_name(&minor, &gss_name);
2020Sstevel@tonic-gate 		return (FALSE);
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 	gss_release_name(&minor, &gss_name);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 *  Convert the MN Internal name to an exported flat name, so
2080Sstevel@tonic-gate 	 *  it is suitable for binary comparison.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
2110Sstevel@tonic-gate 		GSS_S_COMPLETE) {
2120Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
2130Sstevel@tonic-gate 			"failed %x", major);
2140Sstevel@tonic-gate 		gss_release_name(&minor, &gss_canon_name);
2150Sstevel@tonic-gate 		return (FALSE);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 	gss_release_name(&minor, &gss_canon_name);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 *  Put the exported name into rpc_gss_principal_t structure.
2210Sstevel@tonic-gate 	 */
2220Sstevel@tonic-gate 	plen = RNDUP(name_buf.length) + sizeof (int);
223*132Srobinson 	(*principal) = malloc(plen);
2240Sstevel@tonic-gate 	if ((*principal) == NULL) {
2250Sstevel@tonic-gate 		gss_release_buffer(&minor, &name_buf);
2260Sstevel@tonic-gate 		return (FALSE);
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 	bzero((caddr_t)(*principal), plen);
2290Sstevel@tonic-gate 	(*principal)->len = RNDUP(name_buf.length);
2300Sstevel@tonic-gate 	s = (*principal)->name;
2310Sstevel@tonic-gate 	memcpy(s, name_buf.value, name_buf.length);
2320Sstevel@tonic-gate 	gss_release_buffer(&minor, &name_buf);
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	return (TRUE);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * Return supported mechanisms.
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate char **
__rpc_gss_get_mechanisms(void)241*132Srobinson __rpc_gss_get_mechanisms(void)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	static char	*mech_list[MAX_MECH_OID_PAIRS+1];
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	*mech_list = NULL;
2460Sstevel@tonic-gate 	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
2470Sstevel@tonic-gate 	return (mech_list);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  * For a given mechanism, return information about it.
2520Sstevel@tonic-gate  */
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
2580Sstevel@tonic-gate /* Don't know how to get the service type for a given mech.	*/
2590Sstevel@tonic-gate /* "service" should NOT be there!				*/
2600Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate char **
__rpc_gss_get_mech_info(char * mech,rpc_gss_service_t * service)263*132Srobinson __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	char **l;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
2680Sstevel@tonic-gate 	if (l == NULL)
2690Sstevel@tonic-gate 		return (NULL);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
2720Sstevel@tonic-gate 		free(l);
2730Sstevel@tonic-gate 		return (NULL);
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2760Sstevel@tonic-gate 	*service = rpc_gss_svc_privacy; /* What service type? */
2770Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2780Sstevel@tonic-gate 	return (l);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
2830Sstevel@tonic-gate  */
2840Sstevel@tonic-gate bool_t
__rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)285*132Srobinson __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	*vers_hi = RPCSEC_GSS_VERSION;
2880Sstevel@tonic-gate 	*vers_lo = RPCSEC_GSS_VERSION;
2890Sstevel@tonic-gate 	return (TRUE);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * Check if a mechanism is installed.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate bool_t
__rpc_gss_is_installed(char * mech)296*132Srobinson __rpc_gss_is_installed(char *mech)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	char **l;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (mech == NULL)
3010Sstevel@tonic-gate 		return (FALSE);
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if ((l = __rpc_gss_get_mechanisms()) == NULL)
3040Sstevel@tonic-gate 		return (FALSE);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	while (*l != NULL) {
3070Sstevel@tonic-gate 		if (strcmp(*l, mech) == 0)
3080Sstevel@tonic-gate 			return (TRUE);
3090Sstevel@tonic-gate 		l++;
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 	return (FALSE);
3120Sstevel@tonic-gate }
313