| /* |
| * 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 = ©->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, ©); |
| } |
| |
| return (major); |
| } |