OpenSolaris_b135/lib/rpcsec_gss/rpcsec_gss_utils.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_defs.h>

#define	SVC_INTEGRITY	"integrity"
#define	SVC_PRIVACY	"privacy"
#define	SVC_NONE	"none"
#define	SVC_DEFAULT	"default"

#define	MCALL_MSG_SIZE 24
/*
 * Private data kept per client handle
 */
struct cu_data {
	int			cu_fd;		/* connections fd */
	bool_t			cu_closeit;	/* opened by library */
	struct netbuf		cu_raddr;	/* remote address */
	struct timeval		cu_wait;	/* retransmit interval */
	struct timeval		cu_total;	/* total time for the call */
	struct rpc_err		cu_error;
	struct t_unitdata	*cu_tr_data;
	XDR			cu_outxdrs;
	char			*cu_outbuf_start;
	char			cu_outbuf[MCALL_MSG_SIZE];
	uint_t			cu_xdrpos;
	uint_t			cu_sendsz;	/* send size */
	uint_t			cu_recvsz;	/* recv size */
	struct pollfd		pfdp;
	char			cu_inbuf[1];
};

/*
 * Internal utility routines.
 */
bool_t
__rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
{
	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
		return (FALSE);
	return (TRUE);
}

char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)
{
	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
}


bool_t
__rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
{
	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
		return (FALSE);
	return (TRUE);
}

char *
__rpc_gss_num_to_qop(char *mech, OM_uint32 num)
{
	char *qop;

	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
		return (NULL);
	return (qop);
}

bool_t
__rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
{
	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
		*num = rpc_gss_svc_integrity;
	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
		*num = rpc_gss_svc_privacy;
	else if (strcasecmp(svc, SVC_NONE) == 0)
		*num = rpc_gss_svc_none;
	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
		*num = rpc_gss_svc_default;
	else
		return (FALSE);
	return (TRUE);
}

char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)
{
	switch (num) {
	case rpc_gss_svc_integrity:
		return (strdup(SVC_INTEGRITY));
	case rpc_gss_svc_privacy:
		return (strdup(SVC_PRIVACY));
	case rpc_gss_svc_none:
		return (strdup(SVC_NONE));
	case rpc_gss_svc_default:
		return (strdup(SVC_DEFAULT));
	default:
		return (NULL);
	}
}

/*
 * Given the user name, node, and security domain, get the mechanism
 * specific principal name (for the user name) in exported form.
 */
bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
				char *user, char *node, char *secdomain)
{
	gss_name_t		gss_name, gss_canon_name;
	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
	char			user_name[256], *s;
	gss_OID			mech_oid;
	int			nlen = 0, slen = 0, plen;
	OM_uint32		major, minor;

	*principal = NULL;
	if (user == NULL || strlen(user) == 0)
		return (FALSE);

	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
			"mech oid");
		return (FALSE);
	}

	if (secdomain != NULL)
		slen = strlen(secdomain);

	if (node != NULL)
		nlen = strlen(node);

	strcpy(user_name, user);
	if (nlen > 0) {
		strcat(user_name, "/");
		strcat(user_name, node);
	}

	if (slen > 0) {
		strcat(user_name, "@");
		strcat(user_name, secdomain);
	}

	name_buf.value = user_name;
	name_buf.length = strlen(user_name);

	/*
	 *  Convert a text string to a GSSAPI Internal name.
	 */
	if ((major = gss_import_name(&minor, &name_buf,
		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
			"failed 0x%x", major);
		return (FALSE);
	}

	/*
	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
	 */
	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
		&gss_canon_name)) != GSS_S_COMPLETE) {
		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
			"failed 0x%x", major);
		gss_release_name(&minor, &gss_name);
		return (FALSE);
	}
	gss_release_name(&minor, &gss_name);

	/*
	 *  Convert the MN Internal name to an exported flat name, so
	 *  it is suitable for binary comparison.
	 */
	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
		GSS_S_COMPLETE) {
		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
			"failed %x", major);
		gss_release_name(&minor, &gss_canon_name);
		return (FALSE);
	}
	gss_release_name(&minor, &gss_canon_name);

	/*
	 *  Put the exported name into rpc_gss_principal_t structure.
	 */
	plen = RNDUP(name_buf.length) + sizeof (int);
	(*principal) = malloc(plen);
	if ((*principal) == NULL) {
		gss_release_buffer(&minor, &name_buf);
		return (FALSE);
	}
	bzero((caddr_t)(*principal), plen);
	(*principal)->len = RNDUP(name_buf.length);
	s = (*principal)->name;
	memcpy(s, name_buf.value, name_buf.length);
	gss_release_buffer(&minor, &name_buf);

	return (TRUE);
}

/*
 * Return supported mechanisms.
 */
char **
__rpc_gss_get_mechanisms(void)
{
	static char	*mech_list[MAX_MECH_OID_PAIRS+1];

	*mech_list = NULL;
	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
	return (mech_list);
}

/*
 * For a given mechanism, return information about it.
 */
/*
 * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
 */

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* Don't know how to get the service type for a given mech.	*/
/* "service" should NOT be there!				*/
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */

char **
__rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
{
	char **l;

	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
	if (l == NULL)
		return (NULL);

	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
		free(l);
		return (NULL);
	}
					/* !!!!!!!!!!!!!!!! */
	*service = rpc_gss_svc_privacy; /* What service type? */
					/* !!!!!!!!!!!!!!!! */
	return (l);
}

/*
 * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
 */
bool_t
__rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
{
	*vers_hi = RPCSEC_GSS_VERSION;
	*vers_lo = RPCSEC_GSS_VERSION;
	return (TRUE);
}

/*
 * Check if a mechanism is installed.
 */
bool_t
__rpc_gss_is_installed(char *mech)
{
	char **l;

	if (mech == NULL)
		return (FALSE);

	if ((l = __rpc_gss_get_mechanisms()) == NULL)
		return (FALSE);

	while (*l != NULL) {
		if (strcmp(*l, mech) == 0)
			return (TRUE);
		l++;
	}
	return (FALSE);
}