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