OpenSolaris_b135/lib/libgss/oid_ops.c

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

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

/*
 * lib/gssapi/generic/oid_ops.c
 *
 * Copyright 1995 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
 */

#include <mechglueP.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>

/*
 * this oid is defined in the oid structure but not exported to
 * external callers; we must still ensure that we do not delete it.
 */
extern const gss_OID_desc * const gss_nt_service_name;


OM_uint32
generic_gss_release_oid(minor_status, oid)
OM_uint32	*minor_status;
gss_OID	*oid;
{
	if (minor_status)
		*minor_status = 0;

	if (oid == NULL || *oid == GSS_C_NO_OID)
		return (GSS_S_COMPLETE);

	/*
	 * The V2 API says the following!
	 *
	 * gss_release_oid[()] will recognize any of the GSSAPI's own OID
	 * values, and will silently ignore attempts to free these OIDs;
	 * for other OIDs it will call the C free() routine for both the OID
	 * data and the descriptor.  This allows applications to freely mix
	 * their own heap allocated OID values with OIDs returned by GSS-API.
	 */

	/*
	 * We use the official OID definitions instead of the unofficial OID
	 * defintions. But we continue to support the unofficial OID
	 * gss_nt_service_name just in case if some gss applications use
	 * the old OID.
	 */

	if ((*oid != GSS_C_NT_USER_NAME) &&
		(*oid != GSS_C_NT_MACHINE_UID_NAME) &&
		(*oid != GSS_C_NT_STRING_UID_NAME) &&
		(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
		(*oid != GSS_C_NT_ANONYMOUS) &&
		(*oid != GSS_C_NT_EXPORT_NAME) &&
		(*oid != gss_nt_service_name)) {
		free((*oid)->elements);
		free(*oid);
	}
	*oid = GSS_C_NO_OID;
	return (GSS_S_COMPLETE);
}

OM_uint32
generic_gss_copy_oid(minor_status, oid, new_oid)
	OM_uint32	*minor_status;
	const gss_OID	oid;
	gss_OID		*new_oid;
{
	gss_OID p;

	if (minor_status)
		*minor_status = 0;

	if (new_oid == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	if (oid == GSS_C_NO_OID)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	p = (gss_OID) malloc(sizeof (gss_OID_desc));
	if (!p) {
		return (GSS_S_FAILURE);
	}
	p->length = oid->length;
	p->elements = malloc(p->length);
	if (!p->elements) {
		free(p);
		return (GSS_S_FAILURE);
	}
	(void) memcpy(p->elements, oid->elements, p->length);
	*new_oid = p;
	return (GSS_S_COMPLETE);
}


OM_uint32
generic_gss_create_empty_oid_set(minor_status, oid_set)
OM_uint32 *minor_status;
gss_OID_set *oid_set;
{
	if (minor_status)
		*minor_status = 0;

	if (oid_set == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	if ((*oid_set = (gss_OID_set) malloc(sizeof (gss_OID_set_desc)))) {
		(void) memset(*oid_set, 0, sizeof (gss_OID_set_desc));
		return (GSS_S_COMPLETE);
	} else {
		return (GSS_S_FAILURE);
	}
}

OM_uint32
generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
OM_uint32 *minor_status;
const gss_OID member_oid;
gss_OID_set *oid_set;
{
	gss_OID elist;
	gss_OID lastel;

	if (minor_status)
		*minor_status = 0;

	if (member_oid == GSS_C_NO_OID || member_oid->length == 0 ||
		member_oid->elements == NULL)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if (oid_set == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	elist = (*oid_set)->elements;
	/* Get an enlarged copy of the array */
	if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
					sizeof (gss_OID_desc)))) {
		/* Copy in the old junk */
		if (elist)
			(void) memcpy((*oid_set)->elements, elist,
				((*oid_set)->count * sizeof (gss_OID_desc)));

		/* Duplicate the input element */
		lastel = &(*oid_set)->elements[(*oid_set)->count];
		if ((lastel->elements =
			(void *) malloc(member_oid->length))) {

			/* Success - copy elements */
			(void) memcpy(lastel->elements, member_oid->elements,
					member_oid->length);
			/* Set length */
			lastel->length = member_oid->length;

			/* Update count */
			(*oid_set)->count++;
			if (elist)
				free(elist);
			return (GSS_S_COMPLETE);
		} else
			free((*oid_set)->elements);
	}
	/* Failure - restore old contents of list */
	(*oid_set)->elements = elist;
	return (GSS_S_FAILURE);
}

OM_uint32
generic_gss_test_oid_set_member(minor_status, member, set, present)
    OM_uint32		*minor_status;
    const gss_OID	member;
    const gss_OID_set	set;
    int			*present;
{
	OM_uint32 i;
	int result;

	if (minor_status)
		*minor_status = 0;

	if (member == GSS_C_NO_OID || set == NULL)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if (present == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	result = 0;
	for (i = 0; i < set->count; i++) {
		if ((set->elements[i].length == member->length) &&
			!memcmp(set->elements[i].elements,
				member->elements, member->length)) {
			result = 1;
			break;
		}
	}
	*present = result;
	return (GSS_S_COMPLETE);
}

/*
 * OID<->string routines.  These are uuuuugly.
 */
OM_uint32
generic_gss_oid_to_str(minor_status, oid, oid_str)
OM_uint32 *minor_status;
const gss_OID oid;
gss_buffer_t oid_str;
{
	char numstr[128];
	OM_uint32 number;
	int numshift;
	OM_uint32 string_length;
	OM_uint32 i;
	unsigned char *cp;
	char *bp;

	if (minor_status != NULL)
		*minor_status = 0;

	if (oid_str != GSS_C_NO_BUFFER) {
		oid_str->length = 0;
		oid_str->value = NULL;
	}

	if (oid == GSS_C_NO_OID || oid->length == 0 || oid->elements == NULL)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if (oid_str == GSS_C_NO_BUFFER)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	/* First determine the size of the string */
	string_length = 0;
	number = 0;
	numshift = 0;
	cp = (unsigned char *) oid->elements;
	number = (OM_uint32) cp[0];
	(void) sprintf(numstr, "%d ", number/40);
	string_length += strlen(numstr);
	(void) sprintf(numstr, "%d ", number%40);
	string_length += strlen(numstr);
	for (i = 1; i < oid->length; i++) {
		if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {
			number = (number << 7) | (cp[i] & 0x7f);
			numshift += 7;
		} else {
			return (GSS_S_FAILURE);
		}

		if ((cp[i] & 0x80) == 0) {
			(void) sprintf(numstr, "%d ", number);
			string_length += strlen(numstr);
			number = 0;
			numshift = 0;
		}
	}
	/*
	 * If we get here, we've calculated the length of "n n n ... n ".  Add 4
	 * here for "{ " and "}\0".
	 */
	string_length += 4;
	if ((bp = (char *)malloc(string_length))) {
		(void) strcpy(bp, "{ ");
		number = (OM_uint32) cp[0];
		(void) sprintf(numstr, "%d ", number/40);
		(void) strcat(bp, numstr);
		(void) sprintf(numstr, "%d ", number%40);
		(void) strcat(bp, numstr);
		number = 0;
		cp = (unsigned char *) oid->elements;
		for (i = 1; i < oid->length; i++) {
			number = (number << 7) | (cp[i] & 0x7f);
			if ((cp[i] & 0x80) == 0) {
				(void) sprintf(numstr, "%d ", number);
				(void) strcat(bp, numstr);
				number = 0;
			}
		}
		(void) strcat(bp, "}");
		oid_str->length = strlen(bp)+1;
		oid_str->value = (void *) bp;
		return (GSS_S_COMPLETE);
	}
	return (GSS_S_FAILURE);
}

/*
 * This routine will handle 2 types of oid string formats:
 * 	1 - { 1 2 3 4 }  where the braces are optional
 *	2 - 1.2.3.4 this is an alernative format
 * The first format is mandated by the gss spec.  The
 * second format is popular outside of the gss community so
 * has been added.
 */
OM_uint32
generic_gss_str_to_oid(minor_status, oid_str, oid)
OM_uint32 *minor_status;
const gss_buffer_t oid_str;
gss_OID *oid;
{
	char *cp, *bp, *startp;
	int brace;
	int numbuf;
	int onumbuf;
	OM_uint32 nbytes;
	int index;
	unsigned char *op;

	if (minor_status != NULL)
		*minor_status = 0;

	if (oid != NULL)
		*oid = GSS_C_NO_OID;

	if (GSS_EMPTY_BUFFER(oid_str))
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if (oid == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	brace = 0;
	bp = (char *)oid_str->value;
	cp = bp;
	/* Skip over leading space */
	while ((bp < &cp[oid_str->length]) && isspace(*bp))
		bp++;
	if (*bp == '{') {
		brace = 1;
		bp++;
	}
	while ((bp < &cp[oid_str->length]) && isspace(*bp))
		bp++;
	startp = bp;
	nbytes = 0;

	/*
	 * The first two numbers are chewed up by the first octet.
	 */
	if (sscanf(bp, "%d", &numbuf) != 1) {
		return (GSS_S_FAILURE);
	}
	while ((bp < &cp[oid_str->length]) && isdigit(*bp))
		bp++;
	while ((bp < &cp[oid_str->length]) &&
		(isspace(*bp) || *bp == '.'))
		bp++;
	if (sscanf(bp, "%d", &numbuf) != 1) {
		return (GSS_S_FAILURE);
	}
	while ((bp < &cp[oid_str->length]) && isdigit(*bp))
		bp++;
	while ((bp < &cp[oid_str->length]) &&
		(isspace(*bp) || *bp == '.'))
		bp++;
	nbytes++;
	while (isdigit(*bp)) {
		if (sscanf(bp, "%d", &numbuf) != 1) {
			return (GSS_S_FAILURE);
		}
		while (numbuf) {
			nbytes++;
			numbuf >>= 7;
		}
		while ((bp < &cp[oid_str->length]) && isdigit(*bp))
			bp++;
		while ((bp < &cp[oid_str->length]) &&
			(isspace(*bp) || *bp == '.'))
			bp++;
	}
	if (brace && (*bp != '}')) {
		return (GSS_S_FAILURE);
	}

	/*
	 * Phew!  We've come this far, so the syntax is good.
	 */
	if ((*oid = (gss_OID) malloc(sizeof (gss_OID_desc)))) {
		if (((*oid)->elements = (void *) malloc(nbytes))) {
			(*oid)->length = nbytes;
			op = (unsigned char *) (*oid)->elements;
			bp = startp;
			(void) sscanf(bp, "%d", &numbuf);
			while (isdigit(*bp))
				bp++;
			while (isspace(*bp) || *bp == '.')
				bp++;
			onumbuf = 40*numbuf;
			(void) sscanf(bp, "%d", &numbuf);
			onumbuf += numbuf;
			*op = (unsigned char) onumbuf;
			op++;
			while (isdigit(*bp))
				bp++;
			while (isspace(*bp) || *bp == '.')
				bp++;
			while (isdigit(*bp)) {
				(void) sscanf(bp, "%d", &numbuf);
				nbytes = 0;
		/* Have to fill in the bytes msb-first */
				onumbuf = numbuf;
				while (numbuf) {
					nbytes++;
					numbuf >>= 7;
				}
				numbuf = onumbuf;
				op += nbytes;
				index = -1;
				while (numbuf) {
					op[index] = (unsigned char)
							numbuf & 0x7f;
					if (index != -1)
						op[index] |= 0x80;
					index--;
					numbuf >>= 7;
				}
				while (isdigit(*bp))
					bp++;
				while (isspace(*bp) || *bp == '.')
					bp++;
			}
			return (GSS_S_COMPLETE);
		} else {
			free(*oid);
			*oid = GSS_C_NO_OID;
		}
	}
	return (GSS_S_FAILURE);
}

/*
 * Copyright 1993 by OpenVision Technologies, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appears in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of OpenVision not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission. OpenVision makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
OM_uint32
gss_copy_oid_set(
	OM_uint32 *minor_status,
	const gss_OID_set_desc * const oidset,
	gss_OID_set *new_oidset
)
{
	gss_OID_set_desc *copy;
	OM_uint32 minor = 0;
	OM_uint32 major = GSS_S_COMPLETE;
	OM_uint32 index;

	if (minor_status != NULL)
		*minor_status = 0;

	if (new_oidset != NULL)
		*new_oidset = GSS_C_NO_OID_SET;

	if (oidset == GSS_C_NO_OID_SET)
		return (GSS_S_CALL_INACCESSIBLE_READ);

	if (new_oidset == NULL)
		return (GSS_S_CALL_INACCESSIBLE_WRITE);

	if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
		major = GSS_S_FAILURE;
		goto done;
	}

	if ((copy->elements = (gss_OID_desc *)
	    calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
		major = GSS_S_FAILURE;
		goto done;
	}
	copy->count = oidset->count;

	for (index = 0; index < copy->count; index++) {
		gss_OID_desc *out = &copy->elements[index];
		gss_OID_desc *in = &oidset->elements[index];

		if ((out->elements = (void *) malloc(in->length)) == NULL) {
			major = GSS_S_FAILURE;
			goto done;
		}
		(void) memcpy(out->elements, in->elements, in->length);
		out->length = in->length;
	}

	*new_oidset = copy;
done:
	if (major != GSS_S_COMPLETE) {
		(void) gss_release_oid_set(&minor, &copy);
	}

	return (major);
}