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