1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
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 * Copyright 1993 by OpenVision Technologies, Inc.
28 *
29 * Permission to use, copy, modify, distribute, and sell this software
30 * and its documentation for any purpose is hereby granted without fee,
31 * provided that the above copyright notice appears in all copies and
32 * that both that copyright notice and this permission notice appear in
33 * supporting documentation, and that the name of OpenVision not be used
34 * in advertising or publicity pertaining to distribution of the software
35 * without specific, written prior permission. OpenVision makes no
36 * representations about the suitability of this software for any
37 * purpose. It is provided "as is" without express or implied warranty.
38 *
39 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
40 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
41 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
42 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
43 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
44 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
45 * PERFORMANCE OF THIS SOFTWARE.
46 */
47
48 /* GSS-API V2 interfaces to manipulate OIDs */
49
50 #include "gssapiP_generic.h"
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdio.h>
57 #include <gssapi/gssapi_generic.h>
58 #include <errno.h>
59 #include <ctype.h>
60
61 /*
62 * The functions for allocating and releasing individual OIDs use malloc and
63 * free instead of the gssalloc wrappers, because the mechglue currently mixes
64 * generic_gss_copy_oid() with hand-freeing of OIDs. We do not need to free
65 * free OIDs allocated by mechanisms, so this should not be a problem.
66 */
67
68 OM_uint32
generic_gss_release_oid(OM_uint32 * minor_status,gss_OID * oid)69 generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
70 {
71 if (minor_status)
72 *minor_status = 0;
73
74 if (oid == NULL || *oid == GSS_C_NO_OID)
75 return(GSS_S_COMPLETE);
76
77 /*
78 * The V2 API says the following!
79 *
80 * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
81 * and will silently ignore attempts to free these OIDs; for other OIDs
82 * it will call the C free() routine for both the OID data and the
83 * descriptor. This allows applications to freely mix their own heap-
84 * allocated OID values with OIDs returned by GSS-API.
85 */
86
87 /*
88 * We use the official OID definitions instead of the unofficial OID
89 * definitions. But we continue to support the unofficial OID
90 * gss_nt_service_name just in case if some gss applications use
91 * the old OID.
92 */
93
94 if ((*oid != GSS_C_NT_USER_NAME) &&
95 (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
96 (*oid != GSS_C_NT_STRING_UID_NAME) &&
97 (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
98 (*oid != GSS_C_NT_ANONYMOUS) &&
99 (*oid != GSS_C_NT_EXPORT_NAME) &&
100 (*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
101 (*oid != gss_nt_service_name)) {
102 free((*oid)->elements);
103 free(*oid);
104 }
105 *oid = GSS_C_NO_OID;
106 return(GSS_S_COMPLETE);
107 }
108
109 OM_uint32
generic_gss_copy_oid(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_OID * new_oid)110 generic_gss_copy_oid(OM_uint32 *minor_status,
111 const gss_OID_desc * const oid,
112 gss_OID *new_oid)
113 {
114 gss_OID p;
115
116 *minor_status = 0;
117
118 p = (gss_OID) malloc(sizeof(gss_OID_desc));
119 if (!p) {
120 *minor_status = ENOMEM;
121 return GSS_S_FAILURE;
122 }
123 p->length = oid->length;
124 p->elements = malloc(p->length);
125 if (!p->elements) {
126 free(p);
127 return GSS_S_FAILURE;
128 }
129 memcpy(p->elements, oid->elements, p->length);
130 *new_oid = p;
131 return(GSS_S_COMPLETE);
132 }
133
134
135 OM_uint32
generic_gss_create_empty_oid_set(OM_uint32 * minor_status,gss_OID_set * oid_set)136 generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
137 {
138 *minor_status = 0;
139
140 if (oid_set == NULL)
141 return GSS_S_CALL_INACCESSIBLE_WRITE;
142
143 if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
144 memset(*oid_set, 0, sizeof(gss_OID_set_desc));
145 return(GSS_S_COMPLETE);
146 }
147 else {
148 *minor_status = ENOMEM;
149 return(GSS_S_FAILURE);
150 }
151 }
152
153 OM_uint32
generic_gss_add_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member_oid,gss_OID_set * oid_set)154 generic_gss_add_oid_set_member(OM_uint32 *minor_status,
155 const gss_OID_desc * const member_oid,
156 gss_OID_set *oid_set)
157 {
158 gss_OID elist;
159 gss_OID lastel;
160
161 *minor_status = 0;
162
163 if (member_oid == NULL || member_oid->length == 0 ||
164 member_oid->elements == NULL)
165 return (GSS_S_CALL_INACCESSIBLE_READ);
166
167 if (oid_set == NULL)
168 return GSS_S_CALL_INACCESSIBLE_WRITE;
169
170 elist = (*oid_set)->elements;
171 /* Get an enlarged copy of the array */
172 if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
173 sizeof(gss_OID_desc)))) {
174 /* Copy in the old junk */
175 if (elist)
176 memcpy((*oid_set)->elements,
177 elist,
178 ((*oid_set)->count * sizeof(gss_OID_desc)));
179
180 /* Duplicate the input element */
181 lastel = &(*oid_set)->elements[(*oid_set)->count];
182 if ((lastel->elements =
183 (void *) gssalloc_malloc((size_t) member_oid->length))) {
184 /* Success - copy elements */
185 memcpy(lastel->elements, member_oid->elements,
186 (size_t) member_oid->length);
187 /* Set length */
188 lastel->length = member_oid->length;
189
190 /* Update count */
191 (*oid_set)->count++;
192 if (elist)
193 gssalloc_free(elist);
194 *minor_status = 0;
195 return(GSS_S_COMPLETE);
196 }
197 else
198 gssalloc_free((*oid_set)->elements);
199 }
200 /* Failure - restore old contents of list */
201 (*oid_set)->elements = elist;
202 *minor_status = ENOMEM;
203 return(GSS_S_FAILURE);
204 }
205
206 OM_uint32
generic_gss_test_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member,gss_OID_set set,int * present)207 generic_gss_test_oid_set_member(OM_uint32 *minor_status,
208 const gss_OID_desc * const member,
209 gss_OID_set set,
210 int * present)
211 {
212 OM_uint32 i;
213 int result;
214
215 *minor_status = 0;
216
217 if (member == NULL || set == NULL)
218 return (GSS_S_CALL_INACCESSIBLE_READ);
219
220 if (present == NULL)
221 return (GSS_S_CALL_INACCESSIBLE_WRITE);
222
223 result = 0;
224 for (i=0; i<set->count; i++) {
225 if ((set->elements[i].length == member->length) &&
226 !memcmp(set->elements[i].elements,
227 member->elements,
228 (size_t) member->length)) {
229 result = 1;
230 break;
231 }
232 }
233 *present = result;
234 return(GSS_S_COMPLETE);
235 }
236
237 OM_uint32
generic_gss_oid_to_str(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_buffer_t oid_str)238 generic_gss_oid_to_str(OM_uint32 *minor_status,
239 const gss_OID_desc * const oid,
240 gss_buffer_t oid_str)
241 {
242 unsigned long number, n;
243 OM_uint32 i;
244 int first;
245 unsigned char *cp;
246 struct k5buf buf;
247
248 if (minor_status != NULL)
249 *minor_status = 0;
250
251 if (oid_str != GSS_C_NO_BUFFER) {
252 oid_str->length = 0;
253 oid_str->value = NULL;
254 }
255
256 if (oid == NULL || oid->length == 0 || oid->elements == NULL)
257 return (GSS_S_CALL_INACCESSIBLE_READ);
258
259 if (oid_str == GSS_C_NO_BUFFER)
260 return (GSS_S_CALL_INACCESSIBLE_WRITE);
261
262 /* Decoded according to krb5/gssapi_krb5.c */
263
264 cp = (unsigned char *) oid->elements;
265 number = (unsigned long) cp[0];
266 k5_buf_init_dynamic(&buf);
267 k5_buf_add(&buf, "{ ");
268 number = 0;
269 cp = (unsigned char *) oid->elements;
270 first = 1;
271 for (i = 0; i < oid->length; i++) {
272 number = (number << 7) | (cp[i] & 0x7f);
273 if ((cp[i] & 0x80) == 0) {
274 if (first) {
275 n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
276 k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
277 first = 0;
278 } else {
279 k5_buf_add_fmt(&buf, "%lu ", number);
280 }
281 number = 0;
282 }
283 }
284 k5_buf_add_len(&buf, "}\0", 2);
285 return k5buf_to_gss(minor_status, &buf, oid_str);
286 }
287
288 /* Return the length of a DER OID subidentifier encoding. */
289 static size_t
arc_encoded_length(unsigned long arc)290 arc_encoded_length(unsigned long arc)
291 {
292 size_t len = 1;
293
294 for (arc >>= 7; arc; arc >>= 7)
295 len++;
296 return len;
297 }
298
299 /* Encode a subidentifier into *bufp and advance it to the encoding's end. */
300 static void
arc_encode(unsigned long arc,unsigned char ** bufp)301 arc_encode(unsigned long arc, unsigned char **bufp)
302 {
303 unsigned char *p;
304
305 /* Advance to the end and encode backwards. */
306 p = *bufp = *bufp + arc_encoded_length(arc);
307 *--p = arc & 0x7f;
308 for (arc >>= 7; arc; arc >>= 7)
309 *--p = (arc & 0x7f) | 0x80;
310 }
311
312 /* Fetch an arc value from *bufp and advance past it and any following spaces
313 * or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */
314 static int
get_arc(const unsigned char ** bufp,const unsigned char * end,unsigned long * arc_out)315 get_arc(const unsigned char **bufp, const unsigned char *end,
316 unsigned long *arc_out)
317 {
318 const unsigned char *p = *bufp;
319 unsigned long arc = 0, newval;
320
321 if (p == end || !isdigit(*p))
322 return 0;
323 for (; p < end && isdigit(*p); p++) {
324 newval = arc * 10 + (*p - '0');
325 if (newval < arc)
326 return 0;
327 arc = newval;
328 }
329 while (p < end && (isspace(*p) || *p == '.'))
330 p++;
331 *bufp = p;
332 *arc_out = arc;
333 return 1;
334 }
335
336 /*
337 * Convert a sequence of two or more decimal arc values into a DER-encoded OID.
338 * The values may be separated by any combination of whitespace and period
339 * characters, and may be optionally surrounded with braces. Leading
340 * whitespace and trailing garbage is allowed. The first arc value must be 0,
341 * 1, or 2, and the second value must be less than 40 if the first value is not
342 * 2.
343 */
344 OM_uint32
generic_gss_str_to_oid(OM_uint32 * minor_status,gss_buffer_t oid_str,gss_OID * oid_out)345 generic_gss_str_to_oid(OM_uint32 *minor_status,
346 gss_buffer_t oid_str,
347 gss_OID *oid_out)
348 {
349 const unsigned char *p, *end, *arc3_start;
350 unsigned char *out;
351 unsigned long arc, arc1, arc2;
352 size_t nbytes;
353 int brace = 0;
354 gss_OID oid;
355
356 if (minor_status != NULL)
357 *minor_status = 0;
358
359 if (oid_out != NULL)
360 *oid_out = GSS_C_NO_OID;
361
362 if (GSS_EMPTY_BUFFER(oid_str))
363 return (GSS_S_CALL_INACCESSIBLE_READ);
364
365 if (oid_out == NULL)
366 return (GSS_S_CALL_INACCESSIBLE_WRITE);
367
368 /* Skip past initial spaces and, optionally, an open brace. */
369 brace = 0;
370 p = oid_str->value;
371 end = p + oid_str->length;
372 while (p < end && isspace(*p))
373 p++;
374 if (p < end && *p == '{') {
375 brace = 1;
376 p++;
377 }
378 while (p < end && isspace(*p))
379 p++;
380
381 /* Get the first two arc values, to be encoded as one subidentifier. */
382 if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
383 return (GSS_S_FAILURE);
384 if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
385 return (GSS_S_FAILURE);
386 arc3_start = p;
387
388 /* Compute the total length of the encoding while checking syntax. */
389 nbytes = arc_encoded_length(arc1 * 40 + arc2);
390 while (get_arc(&p, end, &arc))
391 nbytes += arc_encoded_length(arc);
392 if (brace && (p == end || *p != '}'))
393 return (GSS_S_FAILURE);
394
395 /* Allocate an oid structure. */
396 oid = malloc(sizeof(*oid));
397 if (oid == NULL)
398 return (GSS_S_FAILURE);
399 oid->elements = malloc(nbytes);
400 if (oid->elements == NULL) {
401 free(oid);
402 return (GSS_S_FAILURE);
403 }
404 oid->length = nbytes;
405
406 out = oid->elements;
407 arc_encode(arc1 * 40 + arc2, &out);
408 p = arc3_start;
409 while (get_arc(&p, end, &arc))
410 arc_encode(arc, &out);
411 assert(out - nbytes == oid->elements);
412 *oid_out = oid;
413 return(GSS_S_COMPLETE);
414 }
415
416 /* Compose an OID of a prefix and an integer suffix */
417 OM_uint32
generic_gss_oid_compose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,int suffix,gss_OID_desc * oid)418 generic_gss_oid_compose(OM_uint32 *minor_status,
419 const char *prefix,
420 size_t prefix_len,
421 int suffix,
422 gss_OID_desc *oid)
423 {
424 int osuffix, i;
425 size_t nbytes;
426 unsigned char *op;
427
428 if (oid == GSS_C_NO_OID) {
429 *minor_status = EINVAL;
430 return GSS_S_FAILURE;
431 }
432 if (oid->length < prefix_len) {
433 *minor_status = ERANGE;
434 return GSS_S_FAILURE;
435 }
436
437 memcpy(oid->elements, prefix, prefix_len);
438
439 nbytes = 0;
440 osuffix = suffix;
441 while (suffix) {
442 nbytes++;
443 suffix >>= 7;
444 }
445 suffix = osuffix;
446
447 if (oid->length < prefix_len + nbytes) {
448 *minor_status = ERANGE;
449 return GSS_S_FAILURE;
450 }
451
452 op = (unsigned char *) oid->elements + prefix_len + nbytes;
453 i = -1;
454 while (suffix) {
455 op[i] = (unsigned char)suffix & 0x7f;
456 if (i != -1)
457 op[i] |= 0x80;
458 i--;
459 suffix >>= 7;
460 }
461
462 oid->length = prefix_len + nbytes;
463
464 *minor_status = 0;
465 return GSS_S_COMPLETE;
466 }
467
468 OM_uint32
generic_gss_oid_decompose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,gss_OID_desc * oid,int * suffix)469 generic_gss_oid_decompose(OM_uint32 *minor_status,
470 const char *prefix,
471 size_t prefix_len,
472 gss_OID_desc *oid,
473 int *suffix)
474 {
475 size_t i, slen;
476 unsigned char *op;
477
478 if (oid->length < prefix_len ||
479 memcmp(oid->elements, prefix, prefix_len) != 0) {
480 return GSS_S_BAD_MECH;
481 }
482
483 op = (unsigned char *) oid->elements + prefix_len;
484
485 *suffix = 0;
486
487 slen = oid->length - prefix_len;
488
489 for (i = 0; i < slen; i++) {
490 *suffix = (*suffix << 7) | (op[i] & 0x7f);
491 if (i + 1 != slen && (op[i] & 0x80) == 0) {
492 *minor_status = EINVAL;
493 return GSS_S_FAILURE;
494 }
495 }
496
497 return GSS_S_COMPLETE;
498 }
499
500 OM_uint32
generic_gss_copy_oid_set(OM_uint32 * minor_status,const gss_OID_set_desc * const oidset,gss_OID_set * new_oidset)501 generic_gss_copy_oid_set(OM_uint32 *minor_status,
502 const gss_OID_set_desc * const oidset,
503 gss_OID_set *new_oidset)
504 {
505 gss_OID_set_desc *copy;
506 OM_uint32 minor = 0;
507 OM_uint32 major = GSS_S_COMPLETE;
508 OM_uint32 i;
509
510 if (minor_status != NULL)
511 *minor_status = 0;
512
513 if (new_oidset != NULL)
514 *new_oidset = GSS_C_NO_OID_SET;
515
516 if (oidset == GSS_C_NO_OID_SET)
517 return (GSS_S_CALL_INACCESSIBLE_READ);
518
519 if (new_oidset == NULL)
520 return (GSS_S_CALL_INACCESSIBLE_WRITE);
521
522 if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
523 major = GSS_S_FAILURE;
524 goto done;
525 }
526
527 if ((copy->elements = (gss_OID_desc *)
528 gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
529 major = GSS_S_FAILURE;
530 goto done;
531 }
532 copy->count = oidset->count;
533
534 for (i = 0; i < copy->count; i++) {
535 gss_OID_desc *out = ©->elements[i];
536 gss_OID_desc *in = &oidset->elements[i];
537
538 if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
539 major = GSS_S_FAILURE;
540 goto done;
541 }
542 (void) memcpy(out->elements, in->elements, in->length);
543 out->length = in->length;
544 }
545
546 *new_oidset = copy;
547 done:
548 if (major != GSS_S_COMPLETE) {
549 (void) generic_gss_release_oid_set(&minor, ©);
550 }
551
552 return (major);
553 }
554