1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * name.c 24 * 25 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 * 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include "dh_gssapi.h" 33 #include <pwd.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/note.h> 39 #include <thread.h> 40 41 extern int 42 get_der_length(unsigned char **, unsigned int, unsigned int *); 43 44 extern unsigned int 45 der_length_size(unsigned int); 46 47 extern int 48 put_der_length(unsigned int, unsigned char **, unsigned int); 49 50 /* Diffie-Hellman ONC RPC netname name type */ 51 static gss_OID_desc __DH_GSS_C_NT_NETNAME_desc = 52 { 9, "\053\006\004\001\052\002\032\001\001" }; 53 54 const gss_OID_desc * const __DH_GSS_C_NT_NETNAME = &__DH_GSS_C_NT_NETNAME_desc; 55 56 #define OID_MAX_NAME_ENTRIES 32 57 58 /* 59 * __dh_gss_compare_name: Diffie-Hellman machanism support for 60 * gss_compare_name. Given two gss_name_ts that are presumed to 61 * be rpc netnames set the *equal parameter to true if they are 62 * the same, else set it to false. 63 */ 64 65 OM_uint32 66 __dh_gss_compare_name(void *ctx, /* Per mechanism context (not used) */ 67 OM_uint32 *minor, /* Mechanism status */ 68 gss_name_t name1, /* First name to compare */ 69 gss_name_t name2, /* Second name to compare */ 70 int *equal /* The result */) 71 { 72 _NOTE(ARGUNUSED(ctx)) 73 74 if (minor == 0 || equal == 0) 75 return (GSS_S_CALL_INACCESSIBLE_WRITE); 76 77 *minor = DH_SUCCESS; 78 79 if (name1 == 0 || name2 == 0) { 80 *minor = DH_BADARG_FAILURE; 81 return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ); 82 } 83 84 *equal = (strcmp((char *)name1, (char *)name2) == 0); 85 86 return (GSS_S_COMPLETE); 87 } 88 89 /* 90 * __dh_gss_display_name: Supports gss_display_name for Diffie-Hellman 91 * mechanism. This takes a gss internal name and converts it to 92 * a counted string suitable for display. 93 */ 94 OM_uint32 95 __dh_gss_display_name(void * ctx, /* Per mechanism context (not used) */ 96 OM_uint32* minor, /* Mechanism status */ 97 gss_name_t name, /* Diffie-Hellman internal name */ 98 gss_buffer_t output, /* Were the printable name goes */ 99 gss_OID *name_type /* Name type of the internal name */) 100 { 101 _NOTE(ARGUNUSED(ctx)) 102 103 if (minor == 0 || output == 0) 104 return (GSS_S_CALL_INACCESSIBLE_WRITE); 105 106 if (name == 0) 107 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); 108 109 *minor = DH_SUCCESS; 110 111 output->length = 0; 112 output->value = (void *)strdup((char *)name); 113 if (output->value == NULL) { 114 *minor = DH_NOMEM_FAILURE; 115 return (GSS_S_FAILURE); 116 } 117 output->length = strlen((char *)name) + 1; 118 119 /* 120 * Note: we no longer copy the name type OID. The current draft of 121 * the standard specifies: 122 * 123 * "The returned gss_OID will be a pointer into static stoarge 124 * and should be treated as read-only by the caller (in particular, 125 * it does not need to be freed)." 126 * 127 * if (name_type) { 128 * if ((*minor = __OID_copy(name_type, __DH_GSS_C_NT_NETNAME)) 129 * != DH_SUCCESS) { 130 * free(output->value); 131 * output->value = NULL; 132 * return (GSS_S_FAILURE); 133 * } 134 * } 135 */ 136 137 if (name_type) 138 *name_type = (gss_OID) __DH_GSS_C_NT_NETNAME; 139 140 return (GSS_S_COMPLETE); 141 } 142 143 /* 144 * Routine that takes a netname as a character string and assigns it 145 * to a an gss_name_t pointed to by output. 146 */ 147 static OM_uint32 148 do_netname_nametype(OM_uint32 *minor, char *input, gss_name_t *output) 149 { 150 if (__dh_validate_principal(input) != DH_SUCCESS) 151 return (GSS_S_BAD_NAME); 152 153 *minor = DH_SUCCESS; 154 *output = (gss_name_t)strdup((char *)input); 155 156 if (*output == NULL) { 157 *minor = DH_NOMEM_FAILURE; 158 return (GSS_S_FAILURE); 159 } 160 161 return (GSS_S_COMPLETE); 162 } 163 164 /* 165 * do_uid_nametype converts a uid to a gss_name_t pointed to by output 166 */ 167 static OM_uint32 168 do_uid_nametype(OM_uint32 *minor, uid_t uid, gss_name_t *output) 169 { 170 char netname[MAXNETNAMELEN+1]; 171 172 if (!user2netname(netname, uid, NULL)) { 173 *minor = DH_NETNAME_FAILURE; 174 return (GSS_S_FAILURE); 175 } 176 return (do_netname_nametype(minor, netname, output)); 177 } 178 179 /* 180 * do_username_nametype converts a username to a gss_name_t pointed to by 181 * output. 182 * 183 * A username will be represented by the following: 184 * name[/node][@security-domain] 185 * 186 * Then optional security-domain will represent secure rpc domain if 187 * present. If not present the local domain will be used. name is the 188 * user name as found in the unix password file. If name is root and 189 * node is present, then node will represent the host. If the host is 190 * a qualified name we assume that it is a DNS name and will only return 191 * the first commponnet since we want host name that are relative to 192 * the security domain (secure rpc domain). 193 */ 194 195 static OM_uint32 196 do_username_nametype(OM_uint32 *minor, char *uname, gss_name_t *output) 197 { 198 char netname[MAXNETNAMELEN+1]; 199 char *user, *node, *domain; 200 struct passwd pwd; 201 char buff[1024]; 202 203 /* Set outputs to sane values */ 204 205 *output = 0; 206 *minor = DH_SUCCESS; 207 208 /* See if we have a name */ 209 if (uname == 0) { 210 *minor = DH_NO_SUCH_USER; 211 return (GSS_S_FAILURE); 212 } 213 214 /* copy the name so that we can do surgery on it */ 215 user = strdup(uname); 216 if (user == 0) { 217 *minor = DH_NOMEM_FAILURE; 218 return (GSS_S_FAILURE); 219 } 220 221 222 /* Look for optional node part */ 223 node = strchr(user, '/'); 224 if (node) { 225 /* 226 * user is now just the user portion and node 227 * points to the start of the node part. 228 */ 229 *node++ = '\0'; 230 231 /* Now see if there is a domain */ 232 domain = strchr(node, '@'); 233 } 234 else 235 /* Check for a domain */ 236 domain = strchr(user, '@'); 237 238 /* Set domain to the beginning of the domain part if pressent */ 239 if (domain) 240 *domain++ = '\0'; 241 242 /* 243 * See if the node part is important. If the user is root get 244 * the host from the node. If node is not present we assume 245 * we're the local host. 246 */ 247 if (strcmp(user, "root") == 0) { 248 char *dot; 249 250 /* 251 * We only want the host part of a qualfied host name. We 252 * assume the domain part of a hostname is a DNS domain, 253 * not an rpc domain. The rpc domain can be specified 254 * in the optional security domain part. 255 */ 256 if (node) { 257 dot = strchr(node, '.'); 258 if (dot) 259 *dot = '\0'; 260 } 261 /* 262 * If node is null, assume local host. If domain is 263 * null assume local domain. See host2netname(3N) 264 */ 265 if (!host2netname(netname, node, domain)) { 266 *minor = DH_NETNAME_FAILURE; 267 free(user); 268 return (GSS_S_FAILURE); 269 } 270 free(user); 271 return (do_netname_nametype(minor, netname, output)); 272 } 273 274 /* 275 * We use getpwnam_r to convert the name to uid. Note it is 276 * important to use getpwnam_r to preserve MT safty. 277 */ 278 if (getpwnam_r(user, &pwd, buff, sizeof (buff)) == NULL) { 279 *minor = DH_NO_SUCH_USER; 280 free(user); 281 return (GSS_S_FAILURE); 282 } 283 284 /* If domain is null assume local domain. See user2netname(3N) */ 285 if (!user2netname(netname, pwd.pw_uid, domain)) { 286 *minor = DH_NETNAME_FAILURE; 287 free(user); 288 return (GSS_S_FAILURE); 289 } 290 free(user); 291 return (do_netname_nametype(minor, netname, output)); 292 } 293 294 /* 295 * do_hostbase_nametype convert a hostbase service name of the form 296 * service@hostname. 297 * 298 * For Diffie-Hellman we assume that the service is running with the 299 * credtials of the machine, i.e., as root. 300 */ 301 static OM_uint32 302 do_hostbase_nametype(OM_uint32 *minor, char *input, gss_name_t *output) 303 { 304 /* Get the nostname */ 305 char *host = strchr(input, '@'); 306 char netname[MAXNETNAMELEN+1]; 307 308 309 /* If no host return bad name */ 310 if (host == NULL) 311 return (GSS_S_BAD_NAME); 312 313 /* Advance pass the "@" sign */ 314 host += 1; 315 316 /* Convert the hostname to its netname */ 317 if (!host2netname(netname, host, NULL)) { 318 *minor = DH_NETNAME_FAILURE; 319 return (GSS_S_FAILURE); 320 } 321 322 /* Internalize the netname to output */ 323 return (do_netname_nametype(minor, netname, output)); 324 } 325 326 /* 327 * do_exported_netname: Convert an exported Diffie-Hellman name 328 * to a Diffie-Hellman internal name. 329 */ 330 static OM_uint32 331 do_exported_netname(dh_context_t ctx, /* Diffie-Hellman mech context */ 332 OM_uint32 *minor, /* Mech status */ 333 gss_buffer_t input, /* The export name to convert */ 334 gss_name_t *output /* The converted internal name */) 335 { 336 /* All export names must start with this */ 337 const char tokid[] = "\x04\x01"; 338 const int tokid_len = 2; 339 const int OIDlen_len = 2; 340 const int namelen_len = 4; 341 unsigned char *p = (unsigned char *)input->value; 342 OM_uint32 len = input->length; 343 int mechoidlen; 344 OM_uint32 oidlen; /* includes object tag len & DER len bytes */ 345 OM_uint32 namelen; 346 OM_uint32 currlen; 347 OM_uint32 bytes; 348 349 *minor = DH_BADARG_FAILURE; 350 351 /* The len must be at least this big */ 352 if (len < tokid_len + OIDlen_len + namelen_len) 353 return (GSS_S_DEFECTIVE_TOKEN); 354 355 /* Export names must start with the token id of 0x04 0x01 */ 356 if (memcmp(p, tokid, tokid_len) != 0) 357 return (GSS_S_DEFECTIVE_TOKEN); 358 p += tokid_len; 359 360 /* Decode the Mechanism oid */ 361 oidlen = (*p++ << 8) & 0xff00; 362 oidlen |= *p++ & 0xff; 363 364 /* Check that we actually have the mechanism oid elements */ 365 if (len < tokid_len + OIDlen_len + oidlen + namelen_len) 366 return (GSS_S_DEFECTIVE_TOKEN); 367 368 /* Compare that the input is for this mechanism */ 369 if (*p++ != 0x06) 370 return (GSS_S_DEFECTIVE_TOKEN); 371 currlen = len - (tokid_len + OIDlen_len + oidlen + namelen_len); 372 if ((mechoidlen = get_der_length(&p, currlen, &bytes)) < 0) 373 return (GSS_S_DEFECTIVE_TOKEN); 374 if (mechoidlen != ctx->mech->length) 375 return (GSS_S_DEFECTIVE_TOKEN); 376 if (memcmp(p, ctx->mech->elements, mechoidlen) != 0) 377 return (GSS_S_DEFECTIVE_TOKEN); 378 p += mechoidlen; 379 380 /* Grab the length of the mechanism specific name per RFC 2078 */ 381 namelen = (*p++ << 24) & 0xff000000; 382 namelen |= (*p++ << 16) & 0xff0000; 383 namelen |= (*p++ << 8) & 0xff00; 384 namelen |= *p++ & 0xff; 385 386 /* This should alway be false */ 387 if (len < tokid_len + OIDlen_len + oidlen + namelen_len + namelen) 388 return (GSS_S_DEFECTIVE_TOKEN); 389 390 /* Make sure the bytes for the netname oid length are available */ 391 if (namelen < OIDlen_len) 392 return (GSS_S_DEFECTIVE_TOKEN); 393 394 /* Get the netname oid length */ 395 oidlen = (*p++ << 8) & 0xff00; 396 oidlen = *p++ & 0xff; 397 398 /* See if we have the elements of the netname oid */ 399 if (namelen < OIDlen_len + oidlen) 400 return (GSS_S_DEFECTIVE_TOKEN); 401 402 /* Check that the oid is really a netname */ 403 if (oidlen != __DH_GSS_C_NT_NETNAME->length) 404 return (GSS_S_DEFECTIVE_TOKEN); 405 if (memcmp(p, __DH_GSS_C_NT_NETNAME->elements, 406 __DH_GSS_C_NT_NETNAME->length) != 0) 407 return (GSS_S_DEFECTIVE_TOKEN); 408 409 /* p now points to the netname wich is null terminated */ 410 p += oidlen; 411 412 /* 413 * How the netname is encoded in an export name type for 414 * this mechanism. See _dh_gss_export_name below. 415 */ 416 417 if (namelen != OIDlen_len + oidlen + strlen((char *)p) + 1) 418 return (GSS_S_DEFECTIVE_TOKEN); 419 420 /* Grab the netname */ 421 *output = (gss_name_t)strdup((char *)p); 422 if (*output) { 423 *minor = 0; 424 return (GSS_S_COMPLETE); 425 } 426 427 *minor = DH_NOMEM_FAILURE; 428 return (GSS_S_FAILURE); 429 } 430 431 /* 432 * __dh_gss_import_name: Diffie-Hellman entry point for gss_import_name. 433 * Given an input name of a specified name type, convert this to a 434 * Diffie-Hellman internal name (netname). 435 * 436 * The idea here is simply compare the name_type supplied with each 437 * name type that we know how to deal with. If we have a match we call 438 * the appropriate support routine form above. If we done't have a match 439 * we return GSS_S_BAD_NAMETYPE 440 */ 441 OM_uint32 442 __dh_gss_import_name(void *ctx, /* Per mechanism context */ 443 OM_uint32 *minor, /* Mechanism status */ 444 gss_buffer_t input, /* The name to convert */ 445 gss_OID name_type, /* of this name_type */ 446 gss_name_t *output /* The converted name */) 447 { 448 char *name; 449 OM_uint32 stat; 450 451 if (minor == NULL || output == NULL) 452 return (GSS_S_CALL_INACCESSIBLE_WRITE); 453 454 if (input == NULL || input->value == NULL) 455 return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ); 456 if (name_type == GSS_C_NO_OID) 457 return (GSS_S_BAD_NAMETYPE); 458 459 /* Set sane state */ 460 *minor = DH_SUCCESS; 461 *output = GSS_C_NO_NAME; 462 463 /* UID in machine format */ 464 if (__OID_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)) { 465 uid_t uid; 466 if (input->length != sizeof (uid_t)) 467 return (GSS_S_BAD_NAME); 468 uid = *(uid_t *)input->value; 469 /* Should we assume that the id is network byte order ??? */ 470 /* uid = htonl(uid); No, this should be the local orfering */ 471 return (do_uid_nametype(minor, uid, output)); 472 473 /* Name that was exported with __dh_gss_export_name */ 474 } else if (__OID_equal(name_type, GSS_C_NT_EXPORT_NAME)) { 475 stat = do_exported_netname((dh_context_t)ctx, minor, 476 input, output); 477 return (stat); 478 } 479 480 /* Null ternamte name so we can manipulate as a c-style string */ 481 name = malloc(input->length+1); 482 if (name == NULL) { 483 *minor = DH_NOMEM_FAILURE; 484 return (GSS_S_FAILURE); 485 } 486 memcpy(name, input->value, input->length); 487 name[input->length] = '\0'; 488 489 490 /* Diffie-Hellman (ONC RPC netname) */ 491 if (__OID_equal(name_type, __DH_GSS_C_NT_NETNAME)) { 492 stat = do_netname_nametype(minor, name, output); 493 free(name); 494 return (stat); 495 /* Host based service name (service@hostname) */ 496 } else if (__OID_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) { 497 stat = do_hostbase_nametype(minor, name, output); 498 free(name); 499 return (stat); 500 /* Thus local OS user name */ 501 } else if (__OID_equal(name_type, GSS_C_NT_USER_NAME)) { 502 stat = do_username_nametype(minor, name, output); 503 free(name); 504 return (stat); 505 /* The os user id writen as a string */ 506 } else if (__OID_equal(name_type, GSS_C_NT_STRING_UID_NAME)) { 507 char *p; 508 /* Convert the name to a uid */ 509 uid_t uid = (uid_t)strtol(name, &p, 0); 510 free(name); 511 if (*p != '\0') 512 return (GSS_S_BAD_NAME); 513 return (do_uid_nametype(minor, uid, output)); 514 } else { 515 /* Any thing else */ 516 free(name); 517 return (GSS_S_BAD_NAMETYPE); 518 } 519 } 520 521 /* 522 * __dh_gss_release_name: DH entry point for gss_release_name. 523 * Release an internal DH name. 524 */ 525 OM_uint32 526 __dh_gss_release_name(void *ctx, OM_uint32 *minor, gss_name_t *name) 527 { 528 _NOTE(ARGUNUSED(ctx)) 529 530 if (minor == 0 || name == 0) 531 return (GSS_S_CALL_INACCESSIBLE_WRITE); 532 533 *minor = DH_SUCCESS; 534 535 free(*name); 536 *name = GSS_C_NO_NAME; 537 538 return (GSS_S_COMPLETE); 539 } 540 541 /* Lock for initializing oid_name_tab */ 542 static mutex_t name_tab_lock = DEFAULTMUTEX; 543 544 /* Table of name types that this mechanism understands */ 545 static const gss_OID_desc * oid_name_tab[OID_MAX_NAME_ENTRIES]; 546 547 /* 548 * __dh_gss_inquire_names_for_mech: DH entry point for 549 * gss_inquire_names_for_mech. 550 * 551 * Return a set of OID name types that a mechanism can understand 552 */ 553 OM_uint32 554 __dh_gss_inquire_names_for_mech(void *ctx, OM_uint32 *minor, 555 gss_OID mech, gss_OID_set *names) 556 { 557 _NOTE(ARGUNUSED(ctx,mech)) 558 559 /* See if we need to initialize the table */ 560 if (oid_name_tab[0] == 0) { 561 mutex_lock(&name_tab_lock); 562 /* If nobody sneaked in, initialize the table */ 563 if (oid_name_tab[0] == 0) { 564 oid_name_tab[0] = __DH_GSS_C_NT_NETNAME; 565 oid_name_tab[1] = GSS_C_NT_HOSTBASED_SERVICE; 566 oid_name_tab[2] = GSS_C_NT_USER_NAME; 567 oid_name_tab[3] = GSS_C_NT_MACHINE_UID_NAME; 568 oid_name_tab[4] = GSS_C_NT_STRING_UID_NAME; 569 oid_name_tab[5] = GSS_C_NT_EXPORT_NAME; 570 /* oid_name_tab[6] = GSS_C_NT_ANONYMOUS_NAME; */ 571 } 572 mutex_unlock(&name_tab_lock); 573 } 574 575 /* Return the set of OIDS from the table */ 576 if ((*minor = __OID_copy_set_from_array(names, 577 oid_name_tab, 6)) != DH_SUCCESS) 578 return (GSS_S_FAILURE); 579 580 return (GSS_S_COMPLETE); 581 } 582 583 584 /* 585 * Private libgss entry point to convert a principal name to uid. 586 */ 587 OM_uint32 588 __dh_pname_to_uid(void *ctx, /* DH mech context (not used) */ 589 OM_uint32 *minor, /* Mech status */ 590 const gss_name_t pname, /* principal */ 591 uid_t *uid /* where to put the uid */) 592 { 593 _NOTE(ARGUNUSED(ctx)) 594 595 gid_t gid; 596 gid_t glist[NGRPS]; 597 int glen; 598 /* Convert the principal name to a netname */ 599 char *netname = (char *)pname; 600 char host_netname[MAXNETNAMELEN+1]; 601 602 if (pname == 0) 603 return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ); 604 if (minor == 0 || uid == 0) 605 return (GSS_S_CALL_INACCESSIBLE_WRITE); 606 607 *minor = DH_SUCCESS; 608 *uid = UID_NOBODY; 609 610 /* First try to convert as a user */ 611 if (netname2user(netname, uid, &gid, &glen, glist)) 612 return (GSS_S_COMPLETE); 613 /* Get this hosts netname */ 614 else if (host2netname(host_netname, NULL, NULL)) { 615 /* 616 * If the netname is this host's netname then we're root 617 * else we're nobody. 618 */ 619 if (strncmp(netname, host_netname, MAXNETNAMELEN) == 0) 620 *uid = 0; 621 return (GSS_S_COMPLETE); 622 } 623 624 /* We could not get a netname */ 625 *minor = DH_NETNAME_FAILURE; 626 return (GSS_S_FAILURE); 627 } 628 629 /* 630 * __dh_gss_export_name: Diffie-Hellman support for gss_export_name. 631 * Given a Diffie-Hellman internal name return the GSS exported format. 632 */ 633 OM_uint32 634 __dh_gss_export_name(void *ctx, /* Per mechanism context */ 635 OM_uint32 *minor, /* Mechanism status */ 636 const gss_name_t input_name, /* The name to export */ 637 gss_buffer_t exported_name /* Exported name goes here */) 638 { 639 /* input_name is dh principal name */ 640 dh_principal pname = (dh_principal)input_name; 641 dh_context_t dc = (dh_context_t)ctx; 642 /* Magic for exported blobs */ 643 const char tokid[] = "\x04\x01"; 644 const int tokid_len = 2; 645 const int OIDlen_len = 2; /* Why did they do this? */ 646 const int namelen_len = 4; 647 const int mechoid_tag_len = 1; 648 unsigned char *p; 649 OM_uint32 len; 650 OM_uint32 namelen; 651 OM_uint32 currlen; 652 OM_uint32 oid_der_len = 0; 653 654 if (minor == 0 || exported_name == GSS_C_NO_BUFFER) 655 return (GSS_S_CALL_INACCESSIBLE_WRITE); 656 if (input_name == GSS_C_NO_NAME) 657 return (GSS_S_CALL_INACCESSIBLE_READ); 658 659 /* Set sane outputs */ 660 *minor = DH_SUCCESS; 661 exported_name->length = 0; 662 exported_name->value = NULL; 663 664 /* Determine the length of the name */ 665 namelen = OIDlen_len + __DH_GSS_C_NT_NETNAME->length 666 + strlen(pname)+1; 667 oid_der_len = der_length_size(dc->mech->length); 668 /* Find the total length */ 669 len = tokid_len + OIDlen_len + mechoid_tag_len + oid_der_len 670 + dc->mech->length + namelen_len + namelen; 671 672 /* Allocate the blob */ 673 p = New(unsigned char, len); 674 if (p == NULL) { 675 *minor = DH_NOMEM_FAILURE; 676 return (GSS_S_FAILURE); 677 } 678 /* Set the blob to the exported name */ 679 exported_name->length = len; 680 exported_name->value = p; 681 682 /* Start with some magic */ 683 memcpy(p, tokid, tokid_len); 684 p += tokid_len; 685 686 /* 687 * The spec only allows two bytes for the oid length. 688 * We are assuming here that the correct encodeing is MSB first as 689 * was done in libgss. 690 */ 691 692 *p++ = ((mechoid_tag_len + oid_der_len + dc->mech->length) 693 & 0xff00) >> 8; 694 *p++ = ((mechoid_tag_len + oid_der_len + dc->mech->length) 695 & 0x00ff); 696 697 /* Now the mechanism OID DER Encoding */ 698 *p++ = 0x06; /* Universal Tag for OID */ 699 currlen = len - tokid_len - OIDlen_len - mechoid_tag_len; 700 if (!put_der_length(dc->mech->length, &p, currlen) == 0) { 701 return (GSS_S_FAILURE); 702 } 703 704 /* Now the mechanism OID elements */ 705 memcpy(p, dc->mech->elements, dc->mech->length); 706 p += dc->mech->length; 707 708 /* The name length most MSB first */ 709 *p++ = (namelen & 0xff000000) >> 24; 710 *p++ = (namelen & 0x00ff0000) >> 16; 711 *p++ = (namelen & 0x0000ff00) >> 8; 712 *p++ = (namelen & 0x000000ff); 713 714 /* 715 * We'll now encode the netname oid. Again we'll just use 2 bytes. 716 * This is the same encoding that the libgss implementor uses, so 717 * we'll just follow along. 718 */ 719 720 *p++ = (__DH_GSS_C_NT_NETNAME->length & 0xff00) >> 8; 721 *p++ = (__DH_GSS_C_NT_NETNAME->length &0x00ff); 722 723 /* The netname oid values */ 724 memcpy(p, __DH_GSS_C_NT_NETNAME->elements, 725 __DH_GSS_C_NT_NETNAME->length); 726 727 p += __DH_GSS_C_NT_NETNAME->length; 728 729 /* Now we copy the netname including the null byte to be safe */ 730 memcpy(p, pname, strlen(pname) + 1); 731 732 return (GSS_S_COMPLETE); 733 } 734 735 /* 736 * Support routine for __dh_internal_release_oid. Return True if 737 * the supplied OID points to the reference OID or if the elements 738 * of the reference OID are the same as the supplied OID. In the 739 * latter case, just free the OID container and set the pointer to it 740 * to GSS_C_NO_OID. Otherwise return false 741 */ 742 static int 743 release_oid(const gss_OID_desc * const ref, gss_OID *oid) 744 { 745 gss_OID id = *oid; 746 747 if (id == ref) 748 return (TRUE); 749 750 /* 751 * If some on create a shallow copy free, the structure point to 752 * id and set the pointer to it to GSS_C_NO_OID 753 */ 754 if (id->elements == ref->elements) { 755 Free(id); 756 *oid = GSS_C_NO_OID; 757 return (TRUE); 758 } 759 760 return (FALSE); 761 } 762 763 /* 764 * __dh_gss_internal_release_oid: DH support for the gss_internal_relaese_oid 765 * entry. Check that the refence to an oid is one of our mechanisms static 766 * OIDS. If it is return true indicating to libgss that we have handled the 767 * release of that OID. Otherwise we return false and let libgss deal with it. 768 * 769 * The only OIDS we know are the calling mechanism found in the context 770 * and the shared DH_GSS_C_NT_NETNAME name type 771 */ 772 OM_uint32 773 __dh_gss_internal_release_oid(void *ctx, OM_uint32 *minor, gss_OID *oid) 774 { 775 dh_context_t dhcxt = (dh_context_t)ctx; 776 777 if (minor == 0) 778 return (GSS_S_CALL_INACCESSIBLE_WRITE); 779 780 *minor = DH_SUCCESS; 781 782 if (oid == NULL || *oid == NULL) 783 return (GSS_S_COMPLETE); 784 785 if (release_oid(dhcxt->mech, oid)) 786 return (GSS_S_COMPLETE); 787 788 if (release_oid(__DH_GSS_C_NT_NETNAME, oid)) 789 return (GSS_S_COMPLETE); 790 791 return (GSS_S_FAILURE); 792 } 793