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 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 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 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 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 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 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 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 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 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 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 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 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 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