OpenSolaris_b135/cmd/gss/gsscred/gsscred_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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

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

/*
 *
 *  gsscred utility
 *  Manages mapping between a security principal name and unix uid
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "gsscred.h"

/* From g_glue.c */

extern int
get_der_length(unsigned char **, unsigned int, unsigned int *);

extern unsigned int
der_length_size(unsigned int);

extern int
put_der_length(unsigned int, unsigned char **, unsigned int);



/*
 * GSS export name constants
 */
static const char *expNameTokId = "\x04\x01";
static const int expNameTokIdLen = 2;
static const int mechOidLenLen = 2;
static const int mechOidTagLen = 1;


/*
 * Internal utility routines.
 */

/*
 * gsscred_read_config_file
 *
 * function to read the optional gsscred configuration file
 * which specifies which backend to use to store the gsscred
 * table.
 *
 * we now only support flat files (btw, this file for backend is Obsoleted
 * by PSARC)
 */
int
gsscred_read_config_file(void)
{
	return (GSSCRED_FLAT_FILE);
} /* gsscred_read_config_file */


/*
 * gsscred_MakeName
 *
 * construct a principal name in the GSS_C_NT_EXPORT_NAME format.
 */
int gsscred_MakeName(const gss_OID mechOid, const char *name,
		const char *nameOidStr, gss_buffer_t nameOut)
{
	gss_OID nameOid;
	gss_name_t intName;
	OM_uint32 minor, major;
	gss_buffer_desc aName = GSS_C_EMPTY_BUFFER, oidStr;

	nameOut->length = 0;
	nameOut->value = NULL;

	/* we need to import the name, then canonicalize it, then export it */
	if (nameOidStr == NULL)
		nameOid = (gss_OID)GSS_C_NT_USER_NAME;
	else {
		oidStr.length = strlen(nameOidStr);
		oidStr.value = (void *)nameOidStr;
		if (gss_str_to_oid(&minor, &oidStr, &nameOid) !=
			GSS_S_COMPLETE) {
			(void) fprintf(stderr,
				gettext("\nInvalid name oid supplied [%s].\n"),
				nameOidStr);
			return (0);
		}
	}

	/* first import the name */
	aName.length = strlen(name);
	aName.value = (void*)name;
	major = gss_import_name(&minor, &aName, nameOid, &intName);
	if (nameOidStr != NULL) {
		free(nameOid->elements);
		free(nameOid);
	}

	if (major != GSS_S_COMPLETE) {
		(void) fprintf(stderr,
			gettext("\nInternal error importing name [%s].\n"),
			name);
		return (0);
	}

	/* now canonicalize the name */
	if (gss_canonicalize_name(&minor, intName, mechOid, NULL)
	    != GSS_S_COMPLETE) {
		(void) fprintf(stderr,
			gettext("\nInternal error canonicalizing name"
				" [%s].\n"),
			name);
		(void) gss_release_name(&minor, &intName);
		return (0);
	}

	/* now convert to export format */
	if (gss_export_name(&minor, intName, nameOut) != GSS_S_COMPLETE) {
		(void) fprintf(stderr,
			gettext("\nInternal error exporting name [%s].\n"),
			name);
		(void) gss_release_name(&minor, &intName);
		return (0);
	}

	(void) gss_release_name(&minor, &intName);
	return (1);
} /* *******  makeName ****** */


/*
 * Constructs a part of the GSS_NT_EXPORT_NAME
 * Only the mechanism independent name part is created.
 */
int
gsscred_MakeNameHeader(const gss_OID mechOid, gss_buffer_t outNameHdr)
{
	unsigned char *buf = NULL;
	int mechOidDERLength, mechOidLength;

	/* determine the length of buffer needed */
	mechOidDERLength = der_length_size(mechOid->length);
	outNameHdr->length = mechOidLenLen + mechOidTagLen +
		mechOidDERLength + expNameTokIdLen + mechOid->length;
	if ((outNameHdr->value = (void*)malloc(outNameHdr->length)) == NULL) {
		outNameHdr->length = 0;
		return (0);
	}

	/* start by putting the token id */
	buf = (unsigned char *) outNameHdr->value;
	(void) memset(outNameHdr->value, '\0', outNameHdr->length);
	(void) memcpy(buf, expNameTokId, expNameTokIdLen);
	buf += expNameTokIdLen;

	/*
	 * next 2 bytes contain the mech oid length (includes
	 * DER encoding)
	 */
	mechOidLength =  mechOidTagLen + mechOidDERLength +
				mechOid->length;

	*buf++ = (mechOidLength & 0xFF00) >> 8;
	*buf++ = (mechOidLength & 0x00FF);
	*buf++ = 0x06;
	if (put_der_length(mechOid->length, &buf,
		mechOidDERLength) != 0) {
		/* free the buffer */
		free(outNameHdr->value);
		return (0);
	}

	/* now add the mechanism oid */
	(void) memcpy(buf, mechOid->elements, mechOid->length);

	/* we stop here because the rest is mechanism specific */
	return (1);
} /* gsscred_MakeNameHeader */


/*
 * Converts the supplied string to HEX.
 * The passed in buffer must be twice as long as the input buffer.
 * Long form is used (i.e. '\0' will become '00').  This is needed
 * to enable proper re-parsing of names.
 */
int
gsscred_AsHex(gss_buffer_t dataIn, gss_buffer_t dataOut)
{
	int i;
	char *out, *in;
	unsigned int tmp;

	if (dataOut->length < ((dataIn->length *2) + 1))
		return (0);

	out = (char *)dataOut->value;
	in = (char *)dataIn->value;
	dataOut->length = 0;

	for (i = 0; i < dataIn->length; i++) {
		tmp = (unsigned int)(*in++)&0xff;
		(void) sprintf(out, "%02X", tmp);
		out++;
		out++;
	}
	dataOut->length = out - (char *)dataOut->value;
	*out = '\0';

	return (1);
} /* ******* gsscred_AsHex ******* */


/*
 * GSS entry point for retrieving user uid mappings.
 * The name buffer contains a principal name in exported format.
 */
int
gss_getGssCredEntry(const gss_buffer_t expName, uid_t *uid)
{
	int tableSource;
	unsigned char *buf;
	gss_buffer_desc mechOidDesc = GSS_C_EMPTY_BUFFER,
		mechHexOidDesc = GSS_C_EMPTY_BUFFER,
		expNameHexDesc = GSS_C_EMPTY_BUFFER;
	char oidHexBuf[256], expNameHexBuf[1024];
	unsigned int dummy;
	int len;

	tableSource = gsscred_read_config_file();

	/*
	 * for xfn (ldap?), we must first construct, a hex mechansim oid string
	 */
	if (expName->length < (expNameTokIdLen + mechOidLenLen +
					mechOidTagLen))
	    return (0);

	buf = (unsigned char *)expName->value;
	buf += expNameTokIdLen;

	/* skip oid length - get to der */
	buf++;
	buf++;

	/* skip oid tag */
	buf++;

	/* get oid length */
	len = get_der_length(&buf,
			(expName->length - expNameTokIdLen
			- mechOidLenLen - mechOidTagLen), &dummy);
	if (len  == -1)
		return (0);
	else
		mechOidDesc.length = len;

	if (expName->length <
		(expNameTokIdLen + mechOidLenLen + mechOidDesc.length
			+  dummy+ mechOidTagLen))
		return (0);

	mechOidDesc.value = (void *)buf;

	/* convert the oid buffer to hex */
	mechHexOidDesc.value = (void*) oidHexBuf;
	mechHexOidDesc.length = sizeof (oidHexBuf);
	if (!gsscred_AsHex(&mechOidDesc, &mechHexOidDesc))
		return (0);

	/* also need to convert the name buffer into hex */
	expNameHexDesc.value = expNameHexBuf;
	expNameHexDesc.length = sizeof (expNameHexBuf);
	if (!gsscred_AsHex(expName, &expNameHexDesc))
		return (0);

	if (tableSource == GSSCRED_FLAT_FILE)
		return (file_getGssCredUid(&expNameHexDesc, uid));

	return (0);  /* XXX for new backends (ldap, dss), 0->1 probably */
} /* gss_getGssCredEntry */