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