2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * lib/gssapi/generic/oid_ops.c
2N/A *
2N/A * Copyright 1995 by the Massachusetts Institute of Technology.
2N/A * All Rights Reserved.
2N/A *
2N/A * Export of this software from the United States of America may
2N/A * require a specific license from the United States Government.
2N/A * It is the responsibility of any person or organization contemplating
2N/A * export to obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of M.I.T. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A *
2N/A */
2N/A
2N/A/*
2N/A * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
2N/A */
2N/A
2N/A#include "gssapiP_generic.h"
2N/A#ifdef HAVE_UNISTD_H
2N/A#include <unistd.h>
2N/A#endif
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <stdio.h>
2N/A#include <gssapi_generic.h> /* Solaris Kerberos */
2N/A#include <errno.h>
2N/A#include <ctype.h>
2N/A
2N/AOM_uint32
2N/Ageneric_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
2N/A{
2N/A if (minor_status)
2N/A *minor_status = 0;
2N/A
2N/A if (oid == NULL || *oid == GSS_C_NO_OID)
2N/A return(GSS_S_COMPLETE);
2N/A
2N/A /*
2N/A * The V2 API says the following!
2N/A *
2N/A * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
2N/A * and will silently ignore attempts to free these OIDs; for other OIDs
2N/A * it will call the C free() routine for both the OID data and the
2N/A * descriptor. This allows applications to freely mix their own heap-
2N/A * allocated OID values with OIDs returned by GSS-API.
2N/A */
2N/A
2N/A /*
2N/A * We use the official OID definitions instead of the unofficial OID
2N/A * defintions. But we continue to support the unofficial OID
2N/A * gss_nt_service_name just in case if some gss applications use
2N/A * the old OID.
2N/A */
2N/A
2N/A if ((*oid != GSS_C_NT_USER_NAME) &&
2N/A (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
2N/A (*oid != GSS_C_NT_STRING_UID_NAME) &&
2N/A (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
2N/A (*oid != GSS_C_NT_ANONYMOUS) &&
2N/A (*oid != GSS_C_NT_EXPORT_NAME) &&
2N/A (*oid != gss_nt_service_name)) {
2N/A free((*oid)->elements);
2N/A free(*oid);
2N/A }
2N/A *oid = GSS_C_NO_OID;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A
2N/A#if 0 /************** Begin IFDEF'ed OUT *******************************/
2N/AOM_uint32
2N/Ageneric_gss_copy_oid(OM_uint32 *minor_status,
2N/A const gss_OID_desc * const oid,
2N/A gss_OID *new_oid)
2N/A{
2N/A gss_OID p;
2N/A
2N/A *minor_status = 0;
2N/A
2N/A p = (gss_OID) malloc(sizeof(gss_OID_desc));
2N/A if (!p) {
2N/A *minor_status = ENOMEM;
2N/A return GSS_S_FAILURE;
2N/A }
2N/A p->length = oid->length;
2N/A p->elements = malloc(p->length);
2N/A if (!p->elements) {
2N/A free(p);
2N/A return GSS_S_FAILURE;
2N/A }
2N/A memcpy(p->elements, oid->elements, p->length);
2N/A *new_oid = p;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A#endif /**************** END IFDEF'ed OUT *******************************/
2N/A
2N/A
2N/AOM_uint32
2N/Ageneric_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
2N/A{
2N/A *minor_status = 0;
2N/A
2N/A if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
2N/A memset(*oid_set, 0, sizeof(gss_OID_set_desc));
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A else {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A}
2N/A
2N/A#if 0 /************** Begin IFDEF'ed OUT *******************************/
2N/AOM_uint32
2N/Ageneric_gss_add_oid_set_member(OM_uint32 *minor_status,
2N/A const gss_OID_desc * const member_oid,
2N/A gss_OID_set *oid_set)
2N/A{
2N/A gss_OID elist;
2N/A gss_OID lastel;
2N/A
2N/A *minor_status = 0;
2N/A
2N/A if (member_oid == NULL || member_oid->length == 0 ||
2N/A member_oid->elements == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A elist = (*oid_set)->elements;
2N/A /* Get an enlarged copy of the array */
2N/A if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
2N/A sizeof(gss_OID_desc)))) {
2N/A /* Copy in the old junk */
2N/A if (elist)
2N/A memcpy((*oid_set)->elements,
2N/A elist,
2N/A ((*oid_set)->count * sizeof(gss_OID_desc)));
2N/A
2N/A /* Duplicate the input element */
2N/A lastel = &(*oid_set)->elements[(*oid_set)->count];
2N/A if ((lastel->elements =
2N/A (void *) malloc((size_t) member_oid->length))) {
2N/A /* Success - copy elements */
2N/A memcpy(lastel->elements, member_oid->elements,
2N/A (size_t) member_oid->length);
2N/A /* Set length */
2N/A lastel->length = member_oid->length;
2N/A
2N/A /* Update count */
2N/A (*oid_set)->count++;
2N/A if (elist)
2N/A free(elist);
2N/A *minor_status = 0;
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A else
2N/A free((*oid_set)->elements);
2N/A }
2N/A /* Failure - restore old contents of list */
2N/A (*oid_set)->elements = elist;
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A}
2N/A
2N/AOM_uint32
2N/Ageneric_gss_test_oid_set_member(OM_uint32 *minor_status,
2N/A const gss_OID_desc * const member,
2N/A gss_OID_set set,
2N/A int * present)
2N/A{
2N/A OM_uint32 i;
2N/A int result;
2N/A
2N/A *minor_status = 0;
2N/A
2N/A if (member == NULL || set == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A if (present == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A result = 0;
2N/A for (i=0; i<set->count; i++) {
2N/A if ((set->elements[i].length == member->length) &&
2N/A !memcmp(set->elements[i].elements,
2N/A member->elements,
2N/A (size_t) member->length)) {
2N/A result = 1;
2N/A break;
2N/A }
2N/A }
2N/A *present = result;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A#endif /**************** END IFDEF'ed OUT *******************************/
2N/A
2N/A/*
2N/A * OID<->string routines. These are uuuuugly.
2N/A */
2N/AOM_uint32
2N/Ageneric_gss_oid_to_str(OM_uint32 *minor_status,
2N/A const gss_OID_desc * const oid,
2N/A gss_buffer_t oid_str)
2N/A{
2N/A OM_uint32 number;
2N/A OM_uint32 i;
2N/A unsigned char *cp;
2N/A char *bp;
2N/A struct k5buf buf;
2N/A
2N/A if (minor_status != NULL)
2N/A *minor_status = 0;
2N/A
2N/A if (oid_str != GSS_C_NO_BUFFER) {
2N/A oid_str->length = 0;
2N/A oid_str->value = NULL;
2N/A }
2N/A
2N/A if (oid == NULL || oid->length == 0 || oid->elements == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A if (oid_str == GSS_C_NO_BUFFER)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A /* Decoded according to krb5/gssapi_krb5.c */
2N/A
2N/A cp = (unsigned char *) oid->elements;
2N/A number = (unsigned long) cp[0];
2N/A krb5int_buf_init_dynamic(&buf);
2N/A krb5int_buf_add_fmt(&buf, "{ %lu %lu ", (unsigned long)number/40,
2N/A (unsigned long)number%40);
2N/A number = 0;
2N/A cp = (unsigned char *) oid->elements;
2N/A for (i=1; i<oid->length; i++) {
2N/A number = (number << 7) | (cp[i] & 0x7f);
2N/A if ((cp[i] & 0x80) == 0) {
2N/A krb5int_buf_add_fmt(&buf, "%lu ", (unsigned long)number);
2N/A number = 0;
2N/A }
2N/A }
2N/A krb5int_buf_add(&buf, "}");
2N/A bp = krb5int_buf_data(&buf);
2N/A if (bp == NULL) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A oid_str->length = krb5int_buf_len(&buf)+1;
2N/A oid_str->value = (void *) bp;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A
2N/AOM_uint32
2N/Ageneric_gss_str_to_oid(OM_uint32 *minor_status,
2N/A gss_buffer_t oid_str,
2N/A gss_OID * oid)
2N/A{
2N/A unsigned char *cp, *bp, *startp;
2N/A int brace;
2N/A long numbuf;
2N/A long onumbuf;
2N/A OM_uint32 nbytes;
2N/A int i;
2N/A unsigned char *op;
2N/A
2N/A if (minor_status != NULL)
2N/A *minor_status = 0;
2N/A
2N/A if (oid != NULL)
2N/A *oid = GSS_C_NO_OID;
2N/A
2N/A if (GSS_EMPTY_BUFFER(oid_str))
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A if (oid == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A brace = 0;
2N/A bp = oid_str->value;
2N/A cp = bp;
2N/A /* Skip over leading space */
2N/A while ((bp < &cp[oid_str->length]) && isspace(*bp))
2N/A bp++;
2N/A if (*bp == '{') {
2N/A brace = 1;
2N/A bp++;
2N/A }
2N/A while ((bp < &cp[oid_str->length]) && isspace(*bp))
2N/A bp++;
2N/A startp = bp;
2N/A nbytes = 0;
2N/A
2N/A /*
2N/A * The first two numbers are chewed up by the first octet.
2N/A */
2N/A if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
2N/A *minor_status = EINVAL;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A while ((bp < &cp[oid_str->length]) && isdigit(*bp))
2N/A bp++;
2N/A while ((bp < &cp[oid_str->length]) &&
2N/A (isspace(*bp) || *bp == '.'))
2N/A bp++;
2N/A if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
2N/A *minor_status = EINVAL;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A while ((bp < &cp[oid_str->length]) && isdigit(*bp))
2N/A bp++;
2N/A while ((bp < &cp[oid_str->length]) &&
2N/A (isspace(*bp) || *bp == '.'))
2N/A bp++;
2N/A nbytes++;
2N/A while (isdigit(*bp)) {
2N/A if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A while (numbuf) {
2N/A nbytes++;
2N/A numbuf >>= 7;
2N/A }
2N/A while ((bp < &cp[oid_str->length]) && isdigit(*bp))
2N/A bp++;
2N/A while ((bp < &cp[oid_str->length]) &&
2N/A (isspace(*bp) || *bp == '.'))
2N/A bp++;
2N/A }
2N/A if (brace && (*bp != '}')) {
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A
2N/A /*
2N/A * Phew! We've come this far, so the syntax is good.
2N/A */
2N/A if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
2N/A if (((*oid)->elements = (void *) malloc(nbytes))) {
2N/A (*oid)->length = nbytes;
2N/A op = (unsigned char *) (*oid)->elements;
2N/A bp = startp;
2N/A (void) sscanf((char *)bp, "%ld", &numbuf);
2N/A while (isdigit(*bp))
2N/A bp++;
2N/A while (isspace(*bp) || *bp == '.')
2N/A bp++;
2N/A onumbuf = 40*numbuf;
2N/A (void) sscanf((char *)bp, "%ld", &numbuf);
2N/A onumbuf += numbuf;
2N/A *op = (unsigned char) onumbuf;
2N/A op++;
2N/A while (isdigit(*bp))
2N/A bp++;
2N/A while (isspace(*bp) || *bp == '.')
2N/A bp++;
2N/A while (isdigit(*bp)) {
2N/A (void) sscanf((char *)bp, "%ld", &numbuf);
2N/A nbytes = 0;
2N/A /* Have to fill in the bytes msb-first */
2N/A onumbuf = numbuf;
2N/A while (numbuf) {
2N/A nbytes++;
2N/A numbuf >>= 7;
2N/A }
2N/A numbuf = onumbuf;
2N/A op += nbytes;
2N/A i = -1;
2N/A while (numbuf) {
2N/A op[i] = (unsigned char) numbuf & 0x7f;
2N/A if (i != -1)
2N/A op[i] |= 0x80;
2N/A i--;
2N/A numbuf >>= 7;
2N/A }
2N/A while (isdigit(*bp))
2N/A bp++;
2N/A while (isspace(*bp) || *bp == '.')
2N/A bp++;
2N/A }
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A else {
2N/A free(*oid);
2N/A *oid = GSS_C_NO_OID;
2N/A }
2N/A }
2N/A return(GSS_S_FAILURE);
2N/A}
2N/A
2N/A/* Compose an OID of a prefix and an integer suffix */
2N/AOM_uint32
2N/Ageneric_gss_oid_compose(OM_uint32 *minor_status,
2N/A const char *prefix,
2N/A size_t prefix_len,
2N/A int suffix,
2N/A gss_OID_desc *oid)
2N/A{
2N/A int osuffix, i;
2N/A size_t nbytes;
2N/A unsigned char *op;
2N/A
2N/A if (oid == GSS_C_NO_OID) {
2N/A *minor_status = EINVAL;
2N/A return GSS_S_FAILURE;
2N/A }
2N/A if (oid->length < prefix_len) {
2N/A *minor_status = ERANGE;
2N/A return GSS_S_FAILURE;
2N/A }
2N/A
2N/A memcpy(oid->elements, prefix, prefix_len);
2N/A
2N/A nbytes = 0;
2N/A osuffix = suffix;
2N/A while (suffix) {
2N/A nbytes++;
2N/A suffix >>= 7;
2N/A }
2N/A suffix = osuffix;
2N/A
2N/A if (oid->length < prefix_len + nbytes) {
2N/A *minor_status = ERANGE;
2N/A return GSS_S_FAILURE;
2N/A }
2N/A
2N/A op = (unsigned char *) oid->elements + prefix_len + nbytes;
2N/A i = -1;
2N/A while (suffix) {
2N/A op[i] = (unsigned char)suffix & 0x7f;
2N/A if (i != -1)
2N/A op[i] |= 0x80;
2N/A i--;
2N/A suffix >>= 7;
2N/A }
2N/A
2N/A oid->length = prefix_len + nbytes;
2N/A
2N/A *minor_status = 0;
2N/A return GSS_S_COMPLETE;
2N/A}
2N/A
2N/AOM_uint32
2N/Ageneric_gss_oid_decompose(OM_uint32 *minor_status,
2N/A const char *prefix,
2N/A size_t prefix_len,
2N/A gss_OID_desc *oid,
2N/A int *suffix)
2N/A{
2N/A size_t i, slen;
2N/A unsigned char *op;
2N/A
2N/A if (oid->length < prefix_len ||
2N/A memcmp(oid->elements, prefix, prefix_len) != 0) {
2N/A return GSS_S_BAD_MECH;
2N/A }
2N/A
2N/A op = (unsigned char *) oid->elements + prefix_len;
2N/A
2N/A *suffix = 0;
2N/A
2N/A slen = oid->length - prefix_len;
2N/A
2N/A for (i = 0; i < slen; i++) {
2N/A *suffix = (*suffix << 7) | (op[i] & 0x7f);
2N/A if (i + 1 != slen && (op[i] & 0x80) == 0) {
2N/A *minor_status = EINVAL;
2N/A return GSS_S_FAILURE;
2N/A }
2N/A }
2N/A
2N/A return GSS_S_COMPLETE;
2N/A}
2N/A
2N/A/*
2N/A * Copyright 1993 by OpenVision Technologies, Inc.
2N/A *
2N/A * Permission to use, copy, modify, distribute, and sell this software
2N/A * and its documentation for any purpose is hereby granted without fee,
2N/A * provided that the above copyright notice appears in all copies and
2N/A * that both that copyright notice and this permission notice appear in
2N/A * supporting documentation, and that the name of OpenVision not be used
2N/A * in advertising or publicity pertaining to distribution of the software
2N/A * without specific, written prior permission. OpenVision makes no
2N/A * representations about the suitability of this software for any
2N/A * purpose. It is provided "as is" without express or implied warranty.
2N/A *
2N/A * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2N/A * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
2N/A * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2N/A * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
2N/A * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2N/A * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2N/A * PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/AOM_uint32
2N/Ageneric_gss_copy_oid_set(OM_uint32 *minor_status,
2N/A const gss_OID_set_desc * const oidset,
2N/A gss_OID_set *new_oidset)
2N/A{
2N/A gss_OID_set_desc *copy;
2N/A OM_uint32 minor = 0;
2N/A OM_uint32 major = GSS_S_COMPLETE;
2N/A OM_uint32 i;
2N/A
2N/A if (minor_status != NULL)
2N/A *minor_status = 0;
2N/A
2N/A if (new_oidset != NULL)
2N/A *new_oidset = GSS_C_NO_OID_SET;
2N/A
2N/A if (oidset == GSS_C_NO_OID_SET)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A if (new_oidset == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
2N/A major = GSS_S_FAILURE;
2N/A goto done;
2N/A }
2N/A
2N/A if ((copy->elements = (gss_OID_desc *)
2N/A calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
2N/A major = GSS_S_FAILURE;
2N/A goto done;
2N/A }
2N/A copy->count = oidset->count;
2N/A
2N/A for (i = 0; i < copy->count; i++) {
2N/A gss_OID_desc *out = &copy->elements[i];
2N/A gss_OID_desc *in = &oidset->elements[i];
2N/A
2N/A if ((out->elements = (void *) malloc(in->length)) == NULL) {
2N/A major = GSS_S_FAILURE;
2N/A goto done;
2N/A }
2N/A (void) memcpy(out->elements, in->elements, in->length);
2N/A out->length = in->length;
2N/A }
2N/A
2N/A *new_oidset = copy;
2N/Adone:
2N/A if (major != GSS_S_COMPLETE) {
2N/A (void) gss_release_oid_set(&minor, &copy);
2N/A }
2N/A
2N/A return (major);
2N/A}