diff options
| author | Cy Schubert <cy@FreeBSD.org> | 2017-07-07 17:03:42 +0000 |
|---|---|---|
| committer | Cy Schubert <cy@FreeBSD.org> | 2017-07-07 17:03:42 +0000 |
| commit | 33a9b234e7087f573ef08cd7318c6497ba08b439 (patch) | |
| tree | d0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/lib/gssapi/generic/oid_ops.c | |
Diffstat (limited to 'src/lib/gssapi/generic/oid_ops.c')
| -rw-r--r-- | src/lib/gssapi/generic/oid_ops.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c new file mode 100644 index 000000000000..6e294b9bcf94 --- /dev/null +++ b/src/lib/gssapi/generic/oid_ops.c @@ -0,0 +1,553 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* 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. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * 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. + */ +/* + * 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. + */ + +/* GSS-API V2 interfaces to manipulate OIDs */ + +#include "gssapiP_generic.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <gssapi/gssapi_generic.h> +#include <errno.h> +#include <ctype.h> + +/* + * The functions for allocating and releasing individual OIDs use malloc and + * free instead of the gssalloc wrappers, because the mechglue currently mixes + * generic_gss_copy_oid() with hand-freeing of OIDs. We do not need to free + * free OIDs allocated by mechanisms, so this should not be a problem. + */ + +OM_uint32 +generic_gss_release_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_C_NT_COMPOSITE_EXPORT) && + (*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(OM_uint32 *minor_status, + const gss_OID_desc * const oid, + gss_OID *new_oid) +{ + gss_OID p; + + *minor_status = 0; + + p = (gss_OID) malloc(sizeof(gss_OID_desc)); + if (!p) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + p->length = oid->length; + p->elements = malloc(p->length); + if (!p->elements) { + free(p); + return GSS_S_FAILURE; + } + memcpy(p->elements, oid->elements, p->length); + *new_oid = p; + return(GSS_S_COMPLETE); +} + + +OM_uint32 +generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set) +{ + *minor_status = 0; + + if (oid_set == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) { + memset(*oid_set, 0, sizeof(gss_OID_set_desc)); + return(GSS_S_COMPLETE); + } + else { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } +} + +OM_uint32 +generic_gss_add_oid_set_member(OM_uint32 *minor_status, + const gss_OID_desc * const member_oid, + gss_OID_set *oid_set) +{ + gss_OID elist; + gss_OID lastel; + + *minor_status = 0; + + if (member_oid == NULL || 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) gssalloc_malloc(((*oid_set)->count+1) * + sizeof(gss_OID_desc)))) { + /* Copy in the old junk */ + if (elist) + 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 *) gssalloc_malloc((size_t) member_oid->length))) { + /* Success - copy elements */ + memcpy(lastel->elements, member_oid->elements, + (size_t) member_oid->length); + /* Set length */ + lastel->length = member_oid->length; + + /* Update count */ + (*oid_set)->count++; + if (elist) + gssalloc_free(elist); + *minor_status = 0; + return(GSS_S_COMPLETE); + } + else + gssalloc_free((*oid_set)->elements); + } + /* Failure - restore old contents of list */ + (*oid_set)->elements = elist; + *minor_status = ENOMEM; + return(GSS_S_FAILURE); +} + +OM_uint32 +generic_gss_test_oid_set_member(OM_uint32 *minor_status, + const gss_OID_desc * const member, + gss_OID_set set, + int * present) +{ + OM_uint32 i; + int result; + + *minor_status = 0; + + if (member == NULL || 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, + (size_t) member->length)) { + result = 1; + break; + } + } + *present = result; + return(GSS_S_COMPLETE); +} + +OM_uint32 +generic_gss_oid_to_str(OM_uint32 *minor_status, + const gss_OID_desc * const oid, + gss_buffer_t oid_str) +{ + unsigned long number, n; + OM_uint32 i; + int first; + unsigned char *cp; + struct k5buf buf; + + if (minor_status != NULL) + *minor_status = 0; + + if (oid_str != GSS_C_NO_BUFFER) { + oid_str->length = 0; + oid_str->value = NULL; + } + + if (oid == NULL || 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); + + /* Decoded according to krb5/gssapi_krb5.c */ + + cp = (unsigned char *) oid->elements; + number = (unsigned long) cp[0]; + k5_buf_init_dynamic(&buf); + k5_buf_add(&buf, "{ "); + number = 0; + cp = (unsigned char *) oid->elements; + first = 1; + for (i = 0; i < oid->length; i++) { + number = (number << 7) | (cp[i] & 0x7f); + if ((cp[i] & 0x80) == 0) { + if (first) { + n = (number < 40) ? 0 : (number < 80) ? 1 : 2; + k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40)); + first = 0; + } else { + k5_buf_add_fmt(&buf, "%lu ", number); + } + number = 0; + } + } + k5_buf_add_len(&buf, "}\0", 2); + return k5buf_to_gss(minor_status, &buf, oid_str); +} + +/* Return the length of a DER OID subidentifier encoding. */ +static size_t +arc_encoded_length(unsigned long arc) +{ + size_t len = 1; + + for (arc >>= 7; arc; arc >>= 7) + len++; + return len; +} + +/* Encode a subidentifier into *bufp and advance it to the encoding's end. */ +static void +arc_encode(unsigned long arc, unsigned char **bufp) +{ + unsigned char *p; + + /* Advance to the end and encode backwards. */ + p = *bufp = *bufp + arc_encoded_length(arc); + *--p = arc & 0x7f; + for (arc >>= 7; arc; arc >>= 7) + *--p = (arc & 0x7f) | 0x80; +} + +/* Fetch an arc value from *bufp and advance past it and any following spaces + * or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */ +static int +get_arc(const unsigned char **bufp, const unsigned char *end, + unsigned long *arc_out) +{ + const unsigned char *p = *bufp; + unsigned long arc = 0, newval; + + if (p == end || !isdigit(*p)) + return 0; + for (; p < end && isdigit(*p); p++) { + newval = arc * 10 + (*p - '0'); + if (newval < arc) + return 0; + arc = newval; + } + while (p < end && (isspace(*p) || *p == '.')) + p++; + *bufp = p; + *arc_out = arc; + return 1; +} + +/* + * Convert a sequence of two or more decimal arc values into a DER-encoded OID. + * The values may be separated by any combination of whitespace and period + * characters, and may be optionally surrounded with braces. Leading + * whitespace and trailing garbage is allowed. The first arc value must be 0, + * 1, or 2, and the second value must be less than 40 if the first value is not + * 2. + */ +OM_uint32 +generic_gss_str_to_oid(OM_uint32 *minor_status, + gss_buffer_t oid_str, + gss_OID *oid_out) +{ + const unsigned char *p, *end, *arc3_start; + unsigned char *out; + unsigned long arc, arc1, arc2; + size_t nbytes; + int brace = 0; + gss_OID oid; + + if (minor_status != NULL) + *minor_status = 0; + + if (oid_out != NULL) + *oid_out = GSS_C_NO_OID; + + if (GSS_EMPTY_BUFFER(oid_str)) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (oid_out == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + /* Skip past initial spaces and, optionally, an open brace. */ + brace = 0; + p = oid_str->value; + end = p + oid_str->length; + while (p < end && isspace(*p)) + p++; + if (p < end && *p == '{') { + brace = 1; + p++; + } + while (p < end && isspace(*p)) + p++; + + /* Get the first two arc values, to be encoded as one subidentifier. */ + if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2)) + return (GSS_S_FAILURE); + if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80) + return (GSS_S_FAILURE); + arc3_start = p; + + /* Compute the total length of the encoding while checking syntax. */ + nbytes = arc_encoded_length(arc1 * 40 + arc2); + while (get_arc(&p, end, &arc)) + nbytes += arc_encoded_length(arc); + if (brace && (p == end || *p != '}')) + return (GSS_S_FAILURE); + + /* Allocate an oid structure. */ + oid = malloc(sizeof(*oid)); + if (oid == NULL) + return (GSS_S_FAILURE); + oid->elements = malloc(nbytes); + if (oid->elements == NULL) { + free(oid); + return (GSS_S_FAILURE); + } + oid->length = nbytes; + + out = oid->elements; + arc_encode(arc1 * 40 + arc2, &out); + p = arc3_start; + while (get_arc(&p, end, &arc)) + arc_encode(arc, &out); + assert(out - nbytes == oid->elements); + *oid_out = oid; + return(GSS_S_COMPLETE); +} + +/* Compose an OID of a prefix and an integer suffix */ +OM_uint32 +generic_gss_oid_compose(OM_uint32 *minor_status, + const char *prefix, + size_t prefix_len, + int suffix, + gss_OID_desc *oid) +{ + int osuffix, i; + size_t nbytes; + unsigned char *op; + + if (oid == GSS_C_NO_OID) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + if (oid->length < prefix_len) { + *minor_status = ERANGE; + return GSS_S_FAILURE; + } + + memcpy(oid->elements, prefix, prefix_len); + + nbytes = 0; + osuffix = suffix; + while (suffix) { + nbytes++; + suffix >>= 7; + } + suffix = osuffix; + + if (oid->length < prefix_len + nbytes) { + *minor_status = ERANGE; + return GSS_S_FAILURE; + } + + op = (unsigned char *) oid->elements + prefix_len + nbytes; + i = -1; + while (suffix) { + op[i] = (unsigned char)suffix & 0x7f; + if (i != -1) + op[i] |= 0x80; + i--; + suffix >>= 7; + } + + oid->length = prefix_len + nbytes; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +generic_gss_oid_decompose(OM_uint32 *minor_status, + const char *prefix, + size_t prefix_len, + gss_OID_desc *oid, + int *suffix) +{ + size_t i, slen; + unsigned char *op; + + if (oid->length < prefix_len || + memcmp(oid->elements, prefix, prefix_len) != 0) { + return GSS_S_BAD_MECH; + } + + op = (unsigned char *) oid->elements + prefix_len; + + *suffix = 0; + + slen = oid->length - prefix_len; + + for (i = 0; i < slen; i++) { + *suffix = (*suffix << 7) | (op[i] & 0x7f); + if (i + 1 != slen && (op[i] & 0x80) == 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +generic_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 i; + + 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 *) gssalloc_calloc(1, sizeof (*copy))) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + + if ((copy->elements = (gss_OID_desc *) + gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + copy->count = oidset->count; + + for (i = 0; i < copy->count; i++) { + gss_OID_desc *out = ©->elements[i]; + gss_OID_desc *in = &oidset->elements[i]; + + if ((out->elements = (void *) gssalloc_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) generic_gss_release_oid_set(&minor, ©); + } + + return (major); +} |
