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
generic_gss_release_oid(minor_status,oid)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
generic_gss_copy_oid(minor_status,oid,new_oid)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
generic_gss_create_empty_oid_set(minor_status,oid_set)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
generic_gss_add_oid_set_member(minor_status,member_oid,oid_set)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
generic_gss_test_oid_set_member(minor_status,member,set,present)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
generic_gss_oid_to_str(minor_status,oid,oid_str)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
generic_gss_str_to_oid(minor_status,oid_str,oid)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
generic_gss_oid_compose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,int suffix,gss_OID_desc * oid)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
generic_gss_oid_decompose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,gss_OID_desc * oid,int * suffix)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
gssint_copy_oid_set(OM_uint32 * minor_status,const gss_OID_set_desc * const oidset,gss_OID_set * new_oidset)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