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