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