/* * 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 #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include /* * 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); }