Home | History | Annotate | Download | only in mech
      1 /*
      2  * lib/gssapi/generic/oid_ops.c
      3  *
      4  * Copyright 1995 by the Massachusetts Institute of Technology.
      5  * All Rights Reserved.
      6  *
      7  * Export of this software from the United States of America may
      8  *   require a specific license from the United States Government.
      9  *   It is the responsibility of any person or organization contemplating
     10  *   export to obtain such a license before exporting.
     11  *
     12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     13  * distribute this software and its documentation for any purpose and
     14  * without fee is hereby granted, provided that the above copyright
     15  * notice appear in all copies and that both that copyright notice and
     16  * this permission notice appear in supporting documentation, and that
     17  * the name of M.I.T. not be used in advertising or publicity pertaining
     18  * to distribution of the software without specific, written prior
     19  * permission.  Furthermore if you modify this software you must label
     20  * your software as modified software and not distribute it in such a
     21  * fashion that it might be confused with the original M.I.T. software.
     22  * M.I.T. makes no representations about the suitability of
     23  * this software for any purpose.  It is provided "as is" without express
     24  * or implied warranty.
     25  *
     26  */
     27 
     28 /*
     29  * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
     30  */
     31 
     32 #include "mglueP.h"
     33 #ifdef HAVE_UNISTD_H
     34 #include <unistd.h>
     35 #endif
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <stdio.h>
     39 #include <gssapi_generic.h>
     40 #include <errno.h>
     41 #include <ctype.h>
     42 
     43 OM_uint32
     44 generic_gss_release_oid(minor_status, oid)
     45     OM_uint32	*minor_status;
     46     gss_OID	*oid;
     47 {
     48     if (minor_status)
     49 	*minor_status = 0;
     50 
     51     if (oid == NULL || *oid == GSS_C_NO_OID)
     52 	return(GSS_S_COMPLETE);
     53 
     54     /*
     55      * The V2 API says the following!
     56      *
     57      * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
     58      * and will silently ignore attempts to free these OIDs; for other OIDs
     59      * it will call the C free() routine for both the OID data and the
     60      * descriptor.  This allows applications to freely mix their own heap-
     61      * allocated OID values with OIDs returned by GSS-API.
     62      */
     63 
     64     /*
     65      * We use the official OID definitions instead of the unofficial OID
     66      * defintions. But we continue to support the unofficial OID
     67      * gss_nt_service_name just in case if some gss applications use
     68      * the old OID.
     69      */
     70 
     71     if ((*oid != GSS_C_NT_USER_NAME) &&
     72 	(*oid != GSS_C_NT_MACHINE_UID_NAME) &&
     73 	(*oid != GSS_C_NT_STRING_UID_NAME) &&
     74 	(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
     75 	(*oid != GSS_C_NT_ANONYMOUS) &&
     76 	(*oid != GSS_C_NT_EXPORT_NAME) &&
     77 	(*oid != gss_nt_service_name)) {
     78 	free((*oid)->elements);
     79 	free(*oid);
     80     }
     81     *oid = GSS_C_NO_OID;
     82     return(GSS_S_COMPLETE);
     83 }
     84 
     85 OM_uint32
     86 generic_gss_copy_oid(minor_status, oid, new_oid)
     87 	OM_uint32	*minor_status;
     88 	gss_OID_desc * const oid;
     89 	gss_OID		*new_oid;
     90 {
     91 	gss_OID		p;
     92 
     93 	*minor_status = 0;
     94 
     95 	p = (gss_OID) malloc(sizeof(gss_OID_desc));
     96 	if (!p) {
     97 		*minor_status = ENOMEM;
     98 		return GSS_S_FAILURE;
     99 	}
    100 	p->length = oid->length;
    101 	p->elements = malloc(p->length);
    102 	if (!p->elements) {
    103 		free(p);
    104 		return GSS_S_FAILURE;
    105 	}
    106 	memcpy(p->elements, oid->elements, p->length);
    107 	*new_oid = p;
    108 	return(GSS_S_COMPLETE);
    109 }
    110 
    111 
    112 OM_uint32
    113 generic_gss_create_empty_oid_set(minor_status, oid_set)
    114     OM_uint32	*minor_status;
    115     gss_OID_set	*oid_set;
    116 {
    117     *minor_status = 0;
    118 
    119     if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
    120 	memset(*oid_set, 0, sizeof(gss_OID_set_desc));
    121 	return(GSS_S_COMPLETE);
    122     }
    123     else {
    124 	*minor_status = ENOMEM;
    125 	return(GSS_S_FAILURE);
    126     }
    127 }
    128 
    129 OM_uint32
    130 generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
    131     OM_uint32	*minor_status;
    132     gss_OID_desc * const member_oid;
    133     gss_OID_set	*oid_set;
    134 {
    135     gss_OID	elist;
    136     gss_OID	lastel;
    137 
    138     *minor_status = 0;
    139 
    140     if (member_oid == NULL || member_oid->length == 0 ||
    141 	member_oid->elements == NULL)
    142 	return (GSS_S_CALL_INACCESSIBLE_READ);
    143 
    144     elist = (*oid_set)->elements;
    145     /* Get an enlarged copy of the array */
    146     if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
    147 						  sizeof(gss_OID_desc)))) {
    148 	/* Copy in the old junk */
    149 	if (elist)
    150 	    memcpy((*oid_set)->elements,
    151 		   elist,
    152 		   ((*oid_set)->count * sizeof(gss_OID_desc)));
    153 
    154 	/* Duplicate the input element */
    155 	lastel = &(*oid_set)->elements[(*oid_set)->count];
    156 	if ((lastel->elements =
    157 	     (void *) malloc((size_t) member_oid->length))) {
    158 	    /* Success - copy elements */
    159 	    memcpy(lastel->elements, member_oid->elements,
    160 		   (size_t) member_oid->length);
    161 	    /* Set length */
    162 	    lastel->length = member_oid->length;
    163 
    164 	    /* Update count */
    165 	    (*oid_set)->count++;
    166 	    if (elist)
    167 		free(elist);
    168 	    *minor_status = 0;
    169 	    return(GSS_S_COMPLETE);
    170 	}
    171 	else
    172 	    free((*oid_set)->elements);
    173     }
    174     /* Failure - restore old contents of list */
    175     (*oid_set)->elements = elist;
    176     *minor_status = ENOMEM;
    177     return(GSS_S_FAILURE);
    178 }
    179 
    180 OM_uint32
    181 generic_gss_test_oid_set_member(minor_status, member, set, present)
    182     OM_uint32	*minor_status;
    183     gss_OID_desc * const member;
    184     gss_OID_set	set;
    185     int		*present;
    186 {
    187     OM_uint32	i;
    188     int		result;
    189 
    190     *minor_status = 0;
    191 
    192     if (member == NULL || set == NULL)
    193 	return (GSS_S_CALL_INACCESSIBLE_READ);
    194 
    195     if (present == NULL)
    196 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
    197 
    198     result = 0;
    199     for (i=0; i<set->count; i++) {
    200 	if ((set->elements[i].length == member->length) &&
    201 	    !memcmp(set->elements[i].elements,
    202 		    member->elements,
    203 		    (size_t) member->length)) {
    204 	    result = 1;
    205 	    break;
    206 	}
    207     }
    208     *present = result;
    209     return(GSS_S_COMPLETE);
    210 }
    211 
    212 /*
    213  * OID<->string routines.  These are uuuuugly.
    214  */
    215 OM_uint32
    216 generic_gss_oid_to_str(minor_status, oid, oid_str)
    217     OM_uint32		*minor_status;
    218     gss_OID_desc * const oid;
    219     gss_buffer_t	oid_str;
    220 {
    221     char		numstr[128];
    222     OM_uint32		number;
    223     int			numshift;
    224     OM_uint32 string_length;
    225     OM_uint32 i;
    226     unsigned char	*cp;
    227     char		*bp;
    228 
    229     if (minor_status != NULL)
    230 	*minor_status = 0;
    231 
    232     if (oid_str != GSS_C_NO_BUFFER) {
    233 	oid_str->length = 0;
    234 	oid_str->value = NULL;
    235     }
    236 
    237     if (oid == NULL || oid->length == 0 || oid->elements == NULL)
    238 	return (GSS_S_CALL_INACCESSIBLE_READ);
    239 
    240     if (oid_str == GSS_C_NO_BUFFER)
    241 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
    242 
    243     /* Decoded according to krb5/gssapi_krb5.c */
    244 
    245     /* First determine the size of the string */
    246     string_length = 0;
    247     number = 0;
    248     numshift = 0;
    249     cp = (unsigned char *) oid->elements;
    250     number = (unsigned long) cp[0];
    251     snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number/40);
    252     string_length += strlen(numstr);
    253     snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number%40);
    254     string_length += strlen(numstr);
    255     for (i=1; i<oid->length; i++) {
    256 	if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {/* XXX */
    257 	    number = (number << 7) | (cp[i] & 0x7f);
    258 	    numshift += 7;
    259 	}
    260 	else {
    261 	    return(GSS_S_FAILURE);
    262 	}
    263 	if ((cp[i] & 0x80) == 0) {
    264 	    snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number);
    265 	    string_length += strlen(numstr);
    266 	    number = 0;
    267 	    numshift = 0;
    268 	}
    269     }
    270     /*
    271      * If we get here, we've calculated the length of "n n n ... n ".  Add 4
    272      * here for "{ " and "}\0".
    273      */
    274     string_length += 4;
    275     if ((bp = (char *) malloc(string_length))) {
    276 	strcpy(bp, "{ ");
    277 	number = (OM_uint32) cp[0];
    278 	snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number/40);
    279 	strcat(bp, numstr);
    280 	snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number%40);
    281 	strcat(bp, numstr);
    282 	number = 0;
    283 	cp = (unsigned char *) oid->elements;
    284 	for (i=1; i<oid->length; i++) {
    285 	    number = (number << 7) | (cp[i] & 0x7f);
    286 	    if ((cp[i] & 0x80) == 0) {
    287 	        snprintf(numstr, sizeof(numstr), "%lu ", (unsigned long)number);
    288 		strcat(bp, numstr);
    289 		number = 0;
    290 	    }
    291 	}
    292 	strcat(bp, "}");
    293 	oid_str->length = strlen(bp)+1;
    294 	oid_str->value = (void *) bp;
    295 	return(GSS_S_COMPLETE);
    296     }
    297     *minor_status = ENOMEM;
    298     return(GSS_S_FAILURE);
    299 }
    300 
    301 OM_uint32
    302 generic_gss_str_to_oid(minor_status, oid_str, oid)
    303     OM_uint32		*minor_status;
    304     gss_buffer_t	oid_str;
    305     gss_OID		*oid;
    306 {
    307     unsigned char	*cp, *bp, *startp;
    308     int		brace;
    309     long	numbuf;
    310     long	onumbuf;
    311     OM_uint32	nbytes;
    312     int		index;
    313     unsigned char *op;
    314 
    315     if (minor_status != NULL)
    316 	*minor_status = 0;
    317 
    318     if (oid != NULL)
    319 	*oid = GSS_C_NO_OID;
    320 
    321     if (GSS_EMPTY_BUFFER(oid_str))
    322 	return (GSS_S_CALL_INACCESSIBLE_READ);
    323 
    324     if (oid == NULL)
    325 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
    326 
    327     brace = 0;
    328     bp = oid_str->value;
    329     cp = bp;
    330     /* Skip over leading space */
    331     while ((bp < &cp[oid_str->length]) && isspace(*bp))
    332 	bp++;
    333     if (*bp == '{') {
    334 	brace = 1;
    335 	bp++;
    336     }
    337     while ((bp < &cp[oid_str->length]) && isspace(*bp))
    338 	bp++;
    339     startp = bp;
    340     nbytes = 0;
    341 
    342     /*
    343      * The first two numbers are chewed up by the first octet.
    344      */
    345     if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
    346 	*minor_status = EINVAL;
    347 	return(GSS_S_FAILURE);
    348     }
    349     while ((bp < &cp[oid_str->length]) && isdigit(*bp))
    350 	bp++;
    351     while ((bp < &cp[oid_str->length]) && isspace(*bp))
    352 	bp++;
    353     if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
    354 	*minor_status = EINVAL;
    355 	return(GSS_S_FAILURE);
    356     }
    357     while ((bp < &cp[oid_str->length]) && isdigit(*bp))
    358 	bp++;
    359     while ((bp < &cp[oid_str->length]) &&
    360 	   (isspace(*bp) || *bp == '.'))
    361 	bp++;
    362     nbytes++;
    363     while (isdigit(*bp)) {
    364 	if (sscanf((char *)bp, "%ld", &numbuf) != 1) {
    365 	    return(GSS_S_FAILURE);
    366 	}
    367 	while (numbuf) {
    368 	    nbytes++;
    369 	    numbuf >>= 7;
    370 	}
    371 	while ((bp < &cp[oid_str->length]) && isdigit(*bp))
    372 	    bp++;
    373 	while ((bp < &cp[oid_str->length]) &&
    374 	       (isspace(*bp) || *bp == '.'))
    375 	    bp++;
    376     }
    377     if (brace && (*bp != '}')) {
    378 	return(GSS_S_FAILURE);
    379     }
    380 
    381     /*
    382      * Phew!  We've come this far, so the syntax is good.
    383      */
    384     if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
    385 	if (((*oid)->elements = (void *) malloc(nbytes))) {
    386 	    (*oid)->length = nbytes;
    387 	    op = (unsigned char *) (*oid)->elements;
    388 	    bp = startp;
    389 	    (void) sscanf((char *)bp, "%ld", &numbuf);
    390 	    while (isdigit(*bp))
    391 		bp++;
    392 	    while (isspace(*bp) || *bp == '.')
    393 		bp++;
    394 	    onumbuf = 40*numbuf;
    395 	    (void) sscanf((char *)bp, "%ld", &numbuf);
    396 	    onumbuf += numbuf;
    397 	    *op = (unsigned char) onumbuf;
    398 	    op++;
    399 	    while (isdigit(*bp))
    400 		bp++;
    401 	    while (isspace(*bp) || *bp == '.')
    402 		bp++;
    403 	    while (isdigit(*bp)) {
    404 		(void) sscanf((char *)bp, "%ld", &numbuf);
    405 		nbytes = 0;
    406 		/* Have to fill in the bytes msb-first */
    407 		onumbuf = numbuf;
    408 		while (numbuf) {
    409 		    nbytes++;
    410 		    numbuf >>= 7;
    411 		}
    412 		numbuf = onumbuf;
    413 		op += nbytes;
    414 		index = -1;
    415 		while (numbuf) {
    416 		    op[index] = (unsigned char) numbuf & 0x7f;
    417 		    if (index != -1)
    418 			op[index] |= 0x80;
    419 		    index--;
    420 		    numbuf >>= 7;
    421 		}
    422 		while (isdigit(*bp))
    423 		    bp++;
    424 		while (isspace(*bp) || *bp == '.')
    425 		    bp++;
    426 	    }
    427 	    return(GSS_S_COMPLETE);
    428 	}
    429 	else {
    430 	    free(*oid);
    431 	    *oid = GSS_C_NO_OID;
    432 	}
    433     }
    434     return(GSS_S_FAILURE);
    435 }
    436 
    437 /* Compose an OID of a prefix and an integer suffix */
    438 OM_uint32
    439 generic_gss_oid_compose(
    440     OM_uint32 *minor_status,
    441     const char *prefix,
    442     size_t prefix_len,
    443     int suffix,
    444     gss_OID_desc *oid)
    445 {
    446     int osuffix, i;
    447     size_t nbytes;
    448     unsigned char *op;
    449 
    450     if (oid == GSS_C_NO_OID) {
    451 	*minor_status = EINVAL;
    452 	return GSS_S_FAILURE;
    453     }
    454     if (oid->length < prefix_len) {
    455 	*minor_status = ERANGE;
    456 	return GSS_S_FAILURE;
    457     }
    458 
    459     memcpy(oid->elements, prefix, prefix_len);
    460 
    461     nbytes = 0;
    462     osuffix = suffix;
    463     while (suffix) {
    464 	nbytes++;
    465 	suffix >>= 7;
    466     }
    467     suffix = osuffix;
    468 
    469     if (oid->length < prefix_len + nbytes) {
    470 	*minor_status = ERANGE;
    471 	return GSS_S_FAILURE;
    472     }
    473 
    474     op = (unsigned char *) oid->elements + prefix_len + nbytes;
    475     i = -1;
    476     while (suffix) {
    477 	op[i] = (unsigned char)suffix & 0x7f;
    478 	if (i != -1)
    479 	    op[i] |= 0x80;
    480 	i--;
    481 	suffix >>= 7;
    482     }
    483 
    484     oid->length = prefix_len + nbytes;
    485 
    486     *minor_status = 0;
    487     return GSS_S_COMPLETE;
    488 }
    489 
    490 OM_uint32
    491 generic_gss_oid_decompose(
    492     OM_uint32 *minor_status,
    493     const char *prefix,
    494     size_t prefix_len,
    495     gss_OID_desc *oid,
    496     int *suffix)
    497 {
    498     size_t i, slen;
    499     unsigned char *op;
    500 
    501     if (oid->length < prefix_len ||
    502 	memcmp(oid->elements, prefix, prefix_len) != 0) {
    503 	return GSS_S_BAD_MECH;
    504     }
    505 
    506     op = (unsigned char *) oid->elements + prefix_len;
    507 
    508     *suffix = 0;
    509 
    510     slen = oid->length - prefix_len;
    511 
    512     for (i = 0; i < slen; i++) {
    513 	*suffix = (*suffix << 7) | (op[i] & 0x7f);
    514 	if (i + 1 != slen && (op[i] & 0x80) == 0) {
    515 	    *minor_status = EINVAL;
    516 	    return GSS_S_FAILURE;
    517 	}
    518     }
    519 
    520     return GSS_S_COMPLETE;
    521 }
    522 
    523 /*
    524  * Copyright 1993 by OpenVision Technologies, Inc.
    525  *
    526  * Permission to use, copy, modify, distribute, and sell this software
    527  * and its documentation for any purpose is hereby granted without fee,
    528  * provided that the above copyright notice appears in all copies and
    529  * that both that copyright notice and this permission notice appear in
    530  * supporting documentation, and that the name of OpenVision not be used
    531  * in advertising or publicity pertaining to distribution of the software
    532  * without specific, written prior permission. OpenVision makes no
    533  * representations about the suitability of this software for any
    534  * purpose.  It is provided "as is" without express or implied warranty.
    535  *
    536  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
    537  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
    538  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
    539  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
    540  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    541  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    542  * PERFORMANCE OF THIS SOFTWARE.
    543  */
    544 OM_uint32
    545 gssint_copy_oid_set(
    546     OM_uint32 *minor_status,
    547     const gss_OID_set_desc * const oidset,
    548     gss_OID_set *new_oidset
    549     )
    550 {
    551     gss_OID_set_desc *copy;
    552     OM_uint32 minor = 0;
    553     OM_uint32 major = GSS_S_COMPLETE;
    554     OM_uint32 index;
    555 
    556     if (minor_status != NULL)
    557 	*minor_status = 0;
    558 
    559     if (new_oidset != NULL)
    560 	*new_oidset = GSS_C_NO_OID_SET;
    561 
    562     if (oidset == GSS_C_NO_OID_SET)
    563 	return (GSS_S_CALL_INACCESSIBLE_READ);
    564 
    565     if (new_oidset == NULL)
    566 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
    567 
    568     if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
    569 	major = GSS_S_FAILURE;
    570 	goto done;
    571     }
    572 
    573     if ((copy->elements = (gss_OID_desc *)
    574 	 calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
    575 	major = GSS_S_FAILURE;
    576 	goto done;
    577     }
    578     copy->count = oidset->count;
    579 
    580     for (index = 0; index < copy->count; index++) {
    581 	gss_OID_desc *out = &copy->elements[index];
    582 	gss_OID_desc *in = &oidset->elements[index];
    583 
    584 	if ((out->elements = (void *) malloc(in->length)) == NULL) {
    585 	    major = GSS_S_FAILURE;
    586 	    goto done;
    587 	}
    588 	(void) memcpy(out->elements, in->elements, in->length);
    589 	out->length = in->length;
    590     }
    591 
    592     *new_oidset = copy;
    593 done:
    594     if (major != GSS_S_COMPLETE) {
    595 	(void) gss_release_oid_set(&minor, &copy);
    596     }
    597 
    598     return (major);
    599 }
    600