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 *minor_status = 0;
72
73 if (oid == NULL || *oid == GSS_C_NO_OID)
74 return(GSS_S_COMPLETE);
75
76 /*
77 * The V2 API says the following!
78 *
79 * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
80 * and will silently ignore attempts to free these OIDs; for other OIDs
81 * it will call the C free() routine for both the OID data and the
82 * descriptor. This allows applications to freely mix their own heap-
83 * allocated OID values with OIDs returned by GSS-API.
84 */
85
86 /*
87 * We use the official OID definitions instead of the unofficial OID
88 * definitions. But we continue to support the unofficial OID
89 * gss_nt_service_name just in case if some gss applications use
90 * the old OID.
91 */
92
93 if ((*oid != GSS_C_NT_USER_NAME) &&
94 (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
95 (*oid != GSS_C_NT_STRING_UID_NAME) &&
96 (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
97 (*oid != GSS_C_NT_ANONYMOUS) &&
98 (*oid != GSS_C_NT_EXPORT_NAME) &&
99 (*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
100 (*oid != gss_nt_service_name)) {
101 free((*oid)->elements);
102 free(*oid);
103 }
104 *oid = GSS_C_NO_OID;
105 return(GSS_S_COMPLETE);
106 }
107
108 OM_uint32
generic_gss_copy_oid(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_OID * new_oid)109 generic_gss_copy_oid(OM_uint32 *minor_status,
110 const gss_OID_desc * const oid,
111 gss_OID *new_oid)
112 {
113 gss_OID p;
114
115 *minor_status = 0;
116
117 p = (gss_OID) malloc(sizeof(gss_OID_desc));
118 if (!p) {
119 *minor_status = ENOMEM;
120 return GSS_S_FAILURE;
121 }
122 p->length = oid->length;
123 p->elements = malloc(p->length);
124 if (!p->elements) {
125 free(p);
126 return GSS_S_FAILURE;
127 }
128 memcpy(p->elements, oid->elements, p->length);
129 *new_oid = p;
130 return(GSS_S_COMPLETE);
131 }
132
133
134 OM_uint32
generic_gss_create_empty_oid_set(OM_uint32 * minor_status,gss_OID_set * oid_set)135 generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
136 {
137 *minor_status = 0;
138
139 if (oid_set == NULL)
140 return GSS_S_CALL_INACCESSIBLE_WRITE;
141
142 if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
143 memset(*oid_set, 0, sizeof(gss_OID_set_desc));
144 return(GSS_S_COMPLETE);
145 }
146 else {
147 *minor_status = ENOMEM;
148 return(GSS_S_FAILURE);
149 }
150 }
151
152 OM_uint32
generic_gss_add_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member_oid,gss_OID_set * oid_set)153 generic_gss_add_oid_set_member(OM_uint32 *minor_status,
154 const gss_OID_desc * const member_oid,
155 gss_OID_set *oid_set)
156 {
157 gss_OID elist;
158 gss_OID lastel;
159
160 *minor_status = 0;
161
162 if (member_oid == NULL || member_oid->length == 0 ||
163 member_oid->elements == NULL)
164 return (GSS_S_CALL_INACCESSIBLE_READ);
165
166 if (oid_set == NULL)
167 return GSS_S_CALL_INACCESSIBLE_WRITE;
168
169 elist = (*oid_set)->elements;
170 /* Get an enlarged copy of the array */
171 if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
172 sizeof(gss_OID_desc)))) {
173 /* Copy in the old junk */
174 if (elist)
175 memcpy((*oid_set)->elements,
176 elist,
177 ((*oid_set)->count * sizeof(gss_OID_desc)));
178
179 /* Duplicate the input element */
180 lastel = &(*oid_set)->elements[(*oid_set)->count];
181 if ((lastel->elements =
182 (void *) gssalloc_malloc((size_t) member_oid->length))) {
183 /* Success - copy elements */
184 memcpy(lastel->elements, member_oid->elements,
185 (size_t) member_oid->length);
186 /* Set length */
187 lastel->length = member_oid->length;
188
189 /* Update count */
190 (*oid_set)->count++;
191 if (elist)
192 gssalloc_free(elist);
193 *minor_status = 0;
194 return(GSS_S_COMPLETE);
195 }
196 else
197 gssalloc_free((*oid_set)->elements);
198 }
199 /* Failure - restore old contents of list */
200 (*oid_set)->elements = elist;
201 *minor_status = ENOMEM;
202 return(GSS_S_FAILURE);
203 }
204
205 OM_uint32
generic_gss_test_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member,gss_OID_set set,int * present)206 generic_gss_test_oid_set_member(OM_uint32 *minor_status,
207 const gss_OID_desc * const member,
208 gss_OID_set set,
209 int * present)
210 {
211 OM_uint32 i;
212 int result;
213
214 *minor_status = 0;
215
216 if (member == NULL || set == NULL)
217 return (GSS_S_CALL_INACCESSIBLE_READ);
218
219 if (present == NULL)
220 return (GSS_S_CALL_INACCESSIBLE_WRITE);
221
222 result = 0;
223 for (i=0; i<set->count; i++) {
224 if ((set->elements[i].length == member->length) &&
225 !memcmp(set->elements[i].elements,
226 member->elements,
227 (size_t) member->length)) {
228 result = 1;
229 break;
230 }
231 }
232 *present = result;
233 return(GSS_S_COMPLETE);
234 }
235
236 OM_uint32
generic_gss_oid_to_str(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_buffer_t oid_str)237 generic_gss_oid_to_str(OM_uint32 *minor_status,
238 const gss_OID_desc * const oid,
239 gss_buffer_t oid_str)
240 {
241 unsigned long number, n;
242 OM_uint32 i;
243 int first;
244 unsigned char *cp;
245 struct k5buf buf;
246
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 == NULL || 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 /* Decoded according to krb5/gssapi_krb5.c */
261
262 cp = (unsigned char *) oid->elements;
263 number = (unsigned long) cp[0];
264 k5_buf_init_dynamic(&buf);
265 k5_buf_add(&buf, "{ ");
266 number = 0;
267 cp = (unsigned char *) oid->elements;
268 first = 1;
269 for (i = 0; i < oid->length; i++) {
270 number = (number << 7) | (cp[i] & 0x7f);
271 if ((cp[i] & 0x80) == 0) {
272 if (first) {
273 n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
274 k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
275 first = 0;
276 } else {
277 k5_buf_add_fmt(&buf, "%lu ", number);
278 }
279 number = 0;
280 }
281 }
282 k5_buf_add_len(&buf, "}\0", 2);
283 return k5buf_to_gss(minor_status, &buf, oid_str);
284 }
285
286 /* Return the length of a DER OID subidentifier encoding. */
287 static size_t
arc_encoded_length(unsigned long arc)288 arc_encoded_length(unsigned long arc)
289 {
290 size_t len = 1;
291
292 for (arc >>= 7; arc; arc >>= 7)
293 len++;
294 return len;
295 }
296
297 /* Encode a subidentifier into *bufp and advance it to the encoding's end. */
298 static void
arc_encode(unsigned long arc,unsigned char ** bufp)299 arc_encode(unsigned long arc, unsigned char **bufp)
300 {
301 unsigned char *p;
302
303 /* Advance to the end and encode backwards. */
304 p = *bufp = *bufp + arc_encoded_length(arc);
305 *--p = arc & 0x7f;
306 for (arc >>= 7; arc; arc >>= 7)
307 *--p = (arc & 0x7f) | 0x80;
308 }
309
310 /* Fetch an arc value from *bufp and advance past it and any following spaces
311 * or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */
312 static int
get_arc(const unsigned char ** bufp,const unsigned char * end,unsigned long * arc_out)313 get_arc(const unsigned char **bufp, const unsigned char *end,
314 unsigned long *arc_out)
315 {
316 const unsigned char *p = *bufp;
317 unsigned long arc = 0, newval;
318
319 if (p == end || !isdigit(*p))
320 return 0;
321 for (; p < end && isdigit(*p); p++) {
322 newval = arc * 10 + (*p - '0');
323 if (newval < arc)
324 return 0;
325 arc = newval;
326 }
327 while (p < end && (isspace(*p) || *p == '.'))
328 p++;
329 *bufp = p;
330 *arc_out = arc;
331 return 1;
332 }
333
334 /*
335 * Convert a sequence of two or more decimal arc values into a DER-encoded OID.
336 * The values may be separated by any combination of whitespace and period
337 * characters, and may be optionally surrounded with braces. Leading
338 * whitespace and trailing garbage is allowed. The first arc value must be 0,
339 * 1, or 2, and the second value must be less than 40 if the first value is not
340 * 2.
341 */
342 OM_uint32
generic_gss_str_to_oid(OM_uint32 * minor_status,gss_buffer_t oid_str,gss_OID * oid_out)343 generic_gss_str_to_oid(OM_uint32 *minor_status,
344 gss_buffer_t oid_str,
345 gss_OID *oid_out)
346 {
347 const unsigned char *p, *end, *arc3_start;
348 unsigned char *out;
349 unsigned long arc, arc1, arc2;
350 size_t nbytes;
351 int brace = 0;
352 gss_OID oid;
353
354 *minor_status = 0;
355
356 if (oid_out != NULL)
357 *oid_out = GSS_C_NO_OID;
358
359 if (GSS_EMPTY_BUFFER(oid_str))
360 return (GSS_S_CALL_INACCESSIBLE_READ);
361
362 if (oid_out == NULL)
363 return (GSS_S_CALL_INACCESSIBLE_WRITE);
364
365 /* Skip past initial spaces and, optionally, an open brace. */
366 brace = 0;
367 p = oid_str->value;
368 end = p + oid_str->length;
369 while (p < end && isspace(*p))
370 p++;
371 if (p < end && *p == '{') {
372 brace = 1;
373 p++;
374 }
375 while (p < end && isspace(*p))
376 p++;
377
378 /* Get the first two arc values, to be encoded as one subidentifier. */
379 if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
380 return (GSS_S_FAILURE);
381 if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
382 return (GSS_S_FAILURE);
383 arc3_start = p;
384
385 /* Compute the total length of the encoding while checking syntax. */
386 nbytes = arc_encoded_length(arc1 * 40 + arc2);
387 while (get_arc(&p, end, &arc))
388 nbytes += arc_encoded_length(arc);
389 if (brace && (p == end || *p != '}'))
390 return (GSS_S_FAILURE);
391
392 /* Allocate an oid structure. */
393 oid = malloc(sizeof(*oid));
394 if (oid == NULL)
395 return (GSS_S_FAILURE);
396 oid->elements = malloc(nbytes);
397 if (oid->elements == NULL) {
398 free(oid);
399 return (GSS_S_FAILURE);
400 }
401 oid->length = nbytes;
402
403 out = oid->elements;
404 arc_encode(arc1 * 40 + arc2, &out);
405 p = arc3_start;
406 while (get_arc(&p, end, &arc))
407 arc_encode(arc, &out);
408 assert(out - nbytes == oid->elements);
409 *oid_out = oid;
410 return(GSS_S_COMPLETE);
411 }
412
413 /* Compose an OID of a prefix and an integer suffix */
414 OM_uint32
generic_gss_oid_compose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,int suffix,gss_OID_desc * oid)415 generic_gss_oid_compose(OM_uint32 *minor_status,
416 const char *prefix,
417 size_t prefix_len,
418 int suffix,
419 gss_OID_desc *oid)
420 {
421 int osuffix, i;
422 size_t nbytes;
423 unsigned char *op;
424
425 if (oid == GSS_C_NO_OID) {
426 *minor_status = EINVAL;
427 return GSS_S_FAILURE;
428 }
429 if (oid->length < prefix_len) {
430 *minor_status = ERANGE;
431 return GSS_S_FAILURE;
432 }
433
434 memcpy(oid->elements, prefix, prefix_len);
435
436 nbytes = 0;
437 osuffix = suffix;
438 while (suffix) {
439 nbytes++;
440 suffix >>= 7;
441 }
442 suffix = osuffix;
443
444 if (oid->length < prefix_len + nbytes) {
445 *minor_status = ERANGE;
446 return GSS_S_FAILURE;
447 }
448
449 op = (unsigned char *) oid->elements + prefix_len + nbytes;
450 i = -1;
451 while (suffix) {
452 op[i] = (unsigned char)suffix & 0x7f;
453 if (i != -1)
454 op[i] |= 0x80;
455 i--;
456 suffix >>= 7;
457 }
458
459 oid->length = prefix_len + nbytes;
460
461 *minor_status = 0;
462 return GSS_S_COMPLETE;
463 }
464
465 OM_uint32
generic_gss_oid_decompose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,gss_OID_desc * oid,int * suffix)466 generic_gss_oid_decompose(OM_uint32 *minor_status,
467 const char *prefix,
468 size_t prefix_len,
469 gss_OID_desc *oid,
470 int *suffix)
471 {
472 size_t i, slen;
473 unsigned char *op;
474
475 if (oid->length < prefix_len ||
476 memcmp(oid->elements, prefix, prefix_len) != 0) {
477 return GSS_S_BAD_MECH;
478 }
479
480 op = (unsigned char *) oid->elements + prefix_len;
481
482 *suffix = 0;
483
484 slen = oid->length - prefix_len;
485
486 for (i = 0; i < slen; i++) {
487 *suffix = (*suffix << 7) | (op[i] & 0x7f);
488 if (i + 1 != slen && (op[i] & 0x80) == 0) {
489 *minor_status = EINVAL;
490 return GSS_S_FAILURE;
491 }
492 }
493
494 return GSS_S_COMPLETE;
495 }
496
497 OM_uint32
generic_gss_copy_oid_set(OM_uint32 * minor_status,const gss_OID_set_desc * const oidset,gss_OID_set * new_oidset)498 generic_gss_copy_oid_set(OM_uint32 *minor_status,
499 const gss_OID_set_desc * const oidset,
500 gss_OID_set *new_oidset)
501 {
502 gss_OID_set_desc *copy;
503 OM_uint32 minor = 0;
504 OM_uint32 major = GSS_S_COMPLETE;
505 OM_uint32 i;
506
507 if (minor_status != NULL)
508 *minor_status = 0;
509
510 if (new_oidset != NULL)
511 *new_oidset = GSS_C_NO_OID_SET;
512
513 if (oidset == GSS_C_NO_OID_SET)
514 return (GSS_S_CALL_INACCESSIBLE_READ);
515
516 if (new_oidset == NULL)
517 return (GSS_S_CALL_INACCESSIBLE_WRITE);
518
519 if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
520 major = GSS_S_FAILURE;
521 goto done;
522 }
523
524 if ((copy->elements = (gss_OID_desc *)
525 gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
526 major = GSS_S_FAILURE;
527 goto done;
528 }
529 copy->count = oidset->count;
530
531 for (i = 0; i < copy->count; i++) {
532 gss_OID_desc *out = ©->elements[i];
533 gss_OID_desc *in = &oidset->elements[i];
534
535 if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
536 major = GSS_S_FAILURE;
537 goto done;
538 }
539 (void) memcpy(out->elements, in->elements, in->length);
540 out->length = in->length;
541 }
542
543 *new_oidset = copy;
544 done:
545 if (major != GSS_S_COMPLETE) {
546 (void) generic_gss_release_oid_set(&minor, ©);
547 }
548
549 return (major);
550 }
551