1/* 2 * Copyright (c) 2006-2010 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <libkern/OSAtomic.h> 24#include <mach/mach.h> 25#include <mach/mach_error.h> 26 27#include <servers/bootstrap.h> 28#include <GSS/gssapi.h> 29#include <GSS/gssapi_krb5.h> 30#include <GSS/gssapi_ntlm.h> 31#include <GSS/gssapi_spnego.h> 32 33#include <asl.h> 34#include <bsm/audit.h> 35#include <bsm/audit_session.h> 36#include <limits.h> 37#include <pthread.h> 38#include <pwd.h> 39#include <stdbool.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <unistd.h> 44 45#include "gssd.h" 46#include "gssd_mach.h" 47 48/* 49 * OID table for supported mechs. This is index by the enumeration type mechtype 50 * found in gss_mach_types.h. 51 */ 52static gss_OID mechtab[] = { 53 NULL, /* Place holder for GSS_KRB5_MECHANISM */ 54 NULL, /* Place holder for GSS_SPNEGO_MECHANISM */ 55 NULL, /* Place holder for GSS_NTLM_MECHANISM */ 56 NULL 57}; 58 59int debug = 0; 60 61#define MAXHOSTNAME 256 62#define MAXRETRIES 3 63#define TIMEOUT 100 // 100 microseconds. 64 65volatile int32_t gss_init_errors; 66volatile int32_t gss_accept_errors; 67volatile int32_t server_errors; 68volatile int32_t server_deaths; 69volatile int32_t key_mismatches; 70volatile int32_t successes; 71 72static void waittime(void); 73void *server(void *); 74void *client(void *); 75static void deallocate(void *, uint32_t); 76static void server_done(); 77static void waitall(void); 78static void report_errors(void); 79 80typedef struct s_channel { 81 int client; 82 int failure; 83 pthread_mutex_t lock[1]; 84 pthread_cond_t cv[1]; 85 gssd_byte_buffer ctoken; 86 mach_msg_type_number_t ctokenCnt; 87 gssd_byte_buffer stoken; 88 mach_msg_type_number_t stokenCnt; 89 gssd_byte_buffer clnt_skey; 90 mach_msg_type_number_t clnt_skeyCnt; 91} *channel_t; 92 93#define CHANNEL_CLOSED 0x1000000 94#define CHANNEL_FAILED(c) ((c)->failure & (~CHANNEL_CLOSED)) 95 96int read_channel(int d, channel_t chan); 97int write_channel(int d, channel_t chan); 98int close_channel(int d, channel_t chan); 99 100static char *optstrs[] = { 101 " if no host is specified, use the local host", 102 "[-b bootstrap label] client bootstrap name", 103 "[-B bootstrap label] server bootstrap name", 104 "[-C] don't canonicalize the host name", 105 "[-d] debugging", 106 "[-D] don't use the default credential", 107 "[-e] exit on mach rpc errors", 108 "[-f flags] flags for init sec context", 109 "[-h] print this usage message", 110 "[-H] don't access home directory", 111 "[-i] run interactively", 112 "[-k] use kerberos service principal name, otherwise", 113 " use host base service name", 114 "[-M retries] max retries before giving up on server death", 115 "[-m krb5 | spnego |ntlm] mech to use, defaults to krb5", 116 "[-n n] number of experiments to run", 117 "[-N uid | user | krb5 | ntlm] name type for client principal", 118 "[-p principal] use principal for client", 119 "[-R] exercise credential refcounting and exit", 120 "[-r realm] use realm for kerberos", 121 "[-s n] number of concurrent servers (and clients) to run", 122 "[-S Service principal] Service principal to use", 123 "[-t usecs] average time to wait in the client", 124 " This is a random time between 0 and 2*usecs", 125 "[-u user] credentials to run as", 126 "[-V] verbose flag. May be repeated", 127 "[-v version] use version of the protocol", 128}; 129 130 131static void 132Usage(void) 133{ 134 unsigned int i; 135 136 Log("Usage: %s [options] [host]\n", getprogname()); 137 for (i = 0; i < sizeof(optstrs)/sizeof(char *); i++) 138 Log("\t%s\n", optstrs[i]); 139 140 exit(EXIT_FAILURE); 141} 142 143int timeout = TIMEOUT; 144int verbose = 0; 145int max_retries = MAXRETRIES; 146int exitonerror = 0; 147int interactive = 0; 148int version = 0; 149uint32_t uid; 150uint32_t flags; 151uint32_t gssd_flags = GSSD_HOME_ACCESS_OK; 152char *principal=""; 153char svcname[1024]; 154mach_port_t server_mp = MACH_PORT_NULL; 155mach_port_t client_mp = MACH_PORT_NULL; 156pthread_cond_t num_servers_cv[1]; 157pthread_mutex_t num_servers_lock[1]; 158int num_servers; 159gssd_mechtype mech = GSSD_KRB5_MECH; 160gssd_nametype name_type = GSSD_MACHINE_UID; 161 162struct gss_name { 163 gssd_nametype nt; 164 gssd_byte_buffer name; 165 uint32_t len; 166} clientp, targetp; 167 168static mach_port_t 169get_gssd_port(void) 170{ 171 mach_port_t mp, hgssdp; 172 kern_return_t kr; 173 auditinfo_addr_t ai; 174 au_asid_t asid; 175 176 if (getaudit_addr(&ai, sizeof(auditinfo_addr_t))) { 177 perror("getaudit_addr"); 178 exit(EXIT_FAILURE); 179 } 180 asid = ai.ai_asid; 181 182 if (seteuid(0)) { 183 Log("Could not get privilege"); 184 exit(EXIT_FAILURE); 185 } 186 kr = host_get_gssd_port(mach_host_self(), &hgssdp); 187 if (kr != KERN_SUCCESS) { 188 Log("host_get_gssd_port(): %s\n", mach_error_string(kr)); 189 exit(EXIT_FAILURE); 190 } 191 if (seteuid(uid)) { 192 Log("Could not drop privilege"); 193 exit(EXIT_FAILURE); 194 } 195 kr = mach_gss_lookup(hgssdp, uid, asid, &mp); 196 if (kr != KERN_SUCCESS) { 197 Log("Could not lookup port for asid = %d, uid = %d: %s\n", 198 asid, uid, mach_error_string(kr)); 199 } 200 201 mach_port_deallocate(mach_host_self(), hgssdp); 202 return (mp); 203 204} 205 206static int 207do_refcount(gssd_mechtype mt, gssd_nametype nt, char *princ) 208{ 209 kern_return_t kret; 210 uint32_t M = 0, m = 0; 211 212 printf("trying to hold credential for %s\n", princ); 213 kret = mach_gss_hold_cred(client_mp, mt, nt, (uint8_t *)princ, (uint32_t)strlen(princ), &M, &m); 214 if (kret == KERN_SUCCESS && M == GSS_S_COMPLETE) { 215 printf("Held credential for %s\n", principal); 216 if (interactive) { 217 printf("Press return to release ..."); 218 (void)getchar(); 219 } 220 kret = mach_gss_unhold_cred(client_mp, mt, nt, (uint8_t *)princ, (uint32_t)strlen(princ), &M, &m); 221 if (kret == KERN_SUCCESS && M == GSS_S_COMPLETE) 222 printf("Unheld credential for %s\n", principal); 223 else { 224 Log("mach_gss_unhold_cred: kret = %d: %#K %#k", kret, M, mechtab[mt], m); 225 return 1; 226 } 227 } else { 228 Log("mach_gss_hold_cred: kret = %d: %#K %#k", kret, M, mechtab[mt], m); 229 return 1; 230 } 231 return 0; 232} 233 234int main(int argc, char *argv[]) 235{ 236 char *bname_server = NULL, *bname_client = NULL; 237 int i, j, ch; 238 int error; 239 int num = 1; 240 int Servers = 1; 241 int use_kerberos = 0; 242 int refcnt = 0; 243 pthread_t thread; 244 pthread_attr_t attr[1]; 245 char hostbuf[MAXHOSTNAME]; 246 char *host = hostbuf; 247 char *realm = NULL; 248 char *ServicePrincipal = NULL; 249 struct passwd *pent = NULL; 250 kern_return_t kr; 251 252 uid = getuid(); 253 if (seteuid(uid)) { 254 Log("Could not drop privilege"); 255 exit(EXIT_FAILURE); 256 } 257 258 setprogname(argv[0]); 259 260 /* Set up mech table */ 261 mechtab[GSSD_KRB5_MECH] = GSS_KRB5_MECHANISM; 262 mechtab[GSSD_SPNEGO_MECH] = GSS_SPNEGO_MECHANISM; 263 mechtab[GSSD_NTLM_MECH] = GSS_NTLM_MECHANISM; 264 265 while ((ch = getopt(argc, argv, "b:B:CdDef:hHikN:n:M:m:p:r:Rs:S:t:u:v:V")) != -1) { 266 switch (ch) { 267 case 'b': 268 bname_client = optarg; 269 break; 270 case 'B': 271 bname_server = optarg; 272 break; 273 case 'C': 274 gssd_flags |= GSSD_NO_CANON; 275 break; 276 case 'd': 277 debug++; 278 break; 279 case 'D': 280 gssd_flags |= GSSD_NO_DEFAULT; 281 break; 282 case 'e': 283 exitonerror = 1; 284 break; 285 case 'f': 286 flags |= atoi(optarg); 287 break; 288 case 'H': 289 gssd_flags &= ~GSSD_HOME_ACCESS_OK; 290 break; 291 case 'i': 292 interactive = 1; 293 break; 294 case 'k': 295 use_kerberos = 1; 296 break; 297 case 'M': 298 max_retries = atoi(optarg); 299 break; 300 case 'm': 301 if (strcmp(optarg, "krb5") == 0) 302 mech = GSSD_KRB5_MECH; 303 else if (strcmp(optarg, "spnego") == 0) 304 mech = GSSD_SPNEGO_MECH; 305 else if (strcmp(optarg, "ntlm") == 0) 306 mech = GSSD_NTLM_MECH; 307 else { 308 Log("Unavailable gss mechanism %s\n", optarg); 309 exit(EXIT_FAILURE); 310 } 311 break; 312 case 'n': 313 num = atoi(optarg); 314 break; 315 316 case 'N': 317 if (strcmp(optarg, "uid") == 0) 318 name_type = GSSD_MACHINE_UID; 319 else if (strcmp(optarg, "suid") == 0) 320 name_type = GSSD_STRING_UID; 321 else if (strcmp(optarg, "user") == 0) 322 name_type = GSSD_USER; 323 else if (strcmp(optarg, "krb5") == 0) 324 name_type = GSSD_KRB5_PRINCIPAL; 325 else if (strcmp(optarg, "ntlm") == 0) 326 name_type = GSSD_NTLM_PRINCIPAL; 327 else { 328 Log("Unsupported name type %s\n", optarg); 329 exit(EXIT_FAILURE); 330 } 331 break; 332 case 'p': 333 principal = optarg; 334 break; 335 case 'r': 336 realm = optarg; 337 break; 338 case 'R': 339 refcnt = 1; 340 break; 341 case 's': 342 Servers = atoi(optarg); 343 break; 344 case 'S': 345 ServicePrincipal = optarg; 346 break; 347 case 't': 348 timeout = atoi(optarg); 349 break; 350 case 'u': 351 pent = getpwnam(optarg); 352 if (pent) 353 uid = pent->pw_uid; 354 else 355 Log("Could no find user %s\n", optarg); 356 break; 357 case 'V': 358 verbose++; 359 break; 360 case 'v': 361 version = atoi(optarg); 362 break; 363 default: 364 Usage(); 365 break; 366 } 367 } 368 argc -= optind; 369 argv += optind; 370 371 if (argc == 0) { 372 gethostname(hostbuf, MAXHOSTNAME); 373 } else if (argc == 1) { 374 host = argv[0]; 375 } else { 376 Usage(); 377 } 378 379 380 if (principal == NULL || *principal == '\0') { 381 if (pent == NULL) 382 pent = getpwuid(uid); 383 principal = pent->pw_name; 384 name_type = GSSD_USER; 385 } 386 387 clientp.nt = name_type; 388 switch (name_type) { 389 case GSSD_USER: 390 case GSSD_STRING_UID: 391 case GSSD_KRB5_PRINCIPAL: 392 case GSSD_NTLM_PRINCIPAL: 393 clientp.name = (gssd_byte_buffer) principal; 394 clientp.len = (uint32_t) strlen(principal); 395 break; 396 default: 397 Log("Unsupported name type for principal %s\n", principal); 398 exit(EXIT_FAILURE); 399 break; 400 } 401 printf("Using creds for %s host=%s\n", principal, host); 402 403 if (bname_client) { 404 kr = bootstrap_look_up(bootstrap_port, bname_client, &client_mp); 405 if (kr != KERN_SUCCESS) { 406 Log("bootstrap_look_up(): %s\n", bootstrap_strerror(kr)); 407 exit(EXIT_FAILURE); 408 } 409 } else { 410 client_mp = get_gssd_port(); 411 } 412 413 if (!MACH_PORT_VALID(client_mp)) { 414 Log("Could not get a valid client port (%d)\n", client_mp); 415 exit(EXIT_FAILURE); 416 } 417 418 if (refcnt) 419 return do_refcount(mech, name_type, principal); 420 421 if (ServicePrincipal) 422 strlcpy(svcname, ServicePrincipal, sizeof(svcname)); 423 else if (use_kerberos) { 424 strlcpy(svcname, "nfs/", sizeof(svcname)); 425 strlcat(svcname, host, sizeof(svcname)); 426 if (realm) { 427 strlcat(svcname, "@", sizeof(svcname)); 428 strlcat(svcname, realm, sizeof(svcname)); 429 } 430 } else { 431 strlcpy(svcname, "nfs@", sizeof(svcname)); 432 strlcat(svcname, host, sizeof(svcname)); 433 } 434 435 if (!use_kerberos) { 436 targetp.nt = GSSD_HOSTBASED; 437 targetp.name = (gssd_byte_buffer)svcname; 438 targetp.len = (uint32_t) strlen(svcname); 439 } 440 printf("Service name = %s\n", svcname); 441 442 if (bname_server) { 443 kr = bootstrap_look_up(bootstrap_port, bname_server, &server_mp); 444 if (kr != KERN_SUCCESS) { 445 Log("bootstrap_look_up(): %s\n", bootstrap_strerror(kr)); 446 exit(EXIT_FAILURE); 447 } 448 } else { 449 server_mp = get_gssd_port(); 450 } 451 452 if (!MACH_PORT_VALID(server_mp)) { 453 Log("Could not get a valid server port (%d)\n", server_mp); 454 exit(EXIT_FAILURE); 455 } 456 457 if (interactive) { 458 printf("Hit enter to start "); 459 (void) getchar(); 460 } 461 462 pthread_attr_init(attr); 463 pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); 464 465 pthread_mutex_init(num_servers_lock, NULL); 466 pthread_cond_init(num_servers_cv, NULL); 467 468 for (i = 0; i < num; i++) { 469 num_servers = Servers; 470 for (j = 0; j < num_servers; j++) { 471 error = pthread_create(&thread, attr, server, NULL); 472 if (error) 473 Log("Could not start server: %s\n", 474 strerror(error)); 475 } 476 waitall(); 477 } 478 report_errors(); 479 480 pthread_attr_destroy(attr); 481 482 kr = mach_port_deallocate(mach_task_self(), client_mp); 483 if (kr != KERN_SUCCESS) { 484 Log("Could not delete send right!\n"); 485 } 486 487 kr = mach_port_deallocate(mach_task_self(), server_mp); 488 if (kr != KERN_SUCCESS) { 489 Log("Could not delete send right!\n"); 490 } 491 492 if (interactive) { 493 printf("Hit enter to stop\n"); 494 (void) getchar(); 495 } 496 497 return (0); 498} 499 500static void 501waittime(void) 502{ 503 struct timespec to; 504 505 if (timeout == 0) 506 return; 507 508 to.tv_sec = 0; 509 to.tv_nsec = (random() % (2*1000*timeout)); 510 511 nanosleep(&to, NULL); 512} 513 514 515static void 516report_errors(void) 517{ 518 printf("gss_init_errors %d\n", gss_init_errors); 519 printf("gss_accept_errors %d\n", gss_accept_errors); 520 printf("server_errors %d\n", server_errors); 521 printf("server_deaths %d\n", server_deaths); 522} 523 524static void 525server_done(void) 526{ 527 pthread_mutex_lock(num_servers_lock); 528 num_servers-- ; 529 if (num_servers == 0) 530 pthread_cond_signal(num_servers_cv); 531 pthread_mutex_unlock(num_servers_lock); 532} 533 534static void 535waitall(void) 536{ 537 pthread_mutex_lock(num_servers_lock); 538 while (num_servers > 0) 539 pthread_cond_wait(num_servers_cv, num_servers_lock); 540 pthread_mutex_unlock(num_servers_lock); 541} 542 543static void 544deallocate(void *addr, uint32_t size) 545{ 546 if (addr == NULL || size == 0) 547 return; 548 549 (void) vm_deallocate(mach_task_self(), (vm_address_t)addr, (vm_size_t)size); 550} 551 552int read_channel(int d, channel_t chan) 553{ 554 pthread_mutex_lock(chan->lock); 555 while (chan->client != d && !chan->failure) 556 pthread_cond_wait(chan->cv, chan->lock); 557 558 waittime(); 559 560 if (chan->failure) { 561 pthread_mutex_unlock(chan->lock); 562 return (-1); 563 } 564 565 return (0); 566} 567 568int write_channel(int d, channel_t chan) 569{ 570 if (chan->client != d) 571 Log("Writing out of turn\n"); 572 573 chan->client = !d; 574 pthread_cond_signal(chan->cv); 575 pthread_mutex_unlock(chan->lock); 576 577 return (0); 578} 579 580int close_channel(int d, channel_t chan) 581{ 582 int rc; 583 584 pthread_mutex_lock(chan->lock); 585 while (chan->client != d && !chan->failure) 586 pthread_cond_wait(chan->cv, chan->lock); 587 588 rc = chan->failure; 589 590 chan->failure |= CHANNEL_CLOSED; 591 chan->client = d; 592 pthread_cond_signal(chan->cv); 593 pthread_mutex_unlock(chan->lock); 594 595 return (rc); 596} 597 598void *client(void *arg) 599{ 600 channel_t channel = (channel_t)arg; 601 uint32_t major_stat; 602 uint32_t minor_stat; 603 uint32_t rflags; 604 uint32_t inout_gssd_flags; 605 gssd_cred cred_handle = (gssd_cred) (uintptr_t)GSS_C_NO_CREDENTIAL; 606 gssd_ctx gss_context = (gssd_ctx) (uintptr_t)GSS_C_NO_CONTEXT; 607 kern_return_t kr; 608 int gss_error = 0; 609 int retry_count = 0; 610 char display_name[128]; 611 612 do { 613 if (read_channel(1, channel)) { 614 Log("Bad read from server\n"); 615 return (NULL); 616 } 617 618 if (verbose) 619 Debug("Calling mach_gss_init_sec_context from %p\n", 620 (void *) pthread_self()); 621 622 deallocate(channel->ctoken, channel->ctokenCnt); 623 channel->ctoken = (gssd_byte_buffer)GSS_C_NO_BUFFER; 624 channel->ctokenCnt = 0; 625retry: 626 switch (version) { 627 case 0: 628 case 1: 629 kr = mach_gss_init_sec_context( 630 client_mp, 631 mech, 632 channel->stoken, channel->stokenCnt, 633 uid, 634 principal, 635 svcname, 636 flags, 637 gssd_flags, 638 &gss_context, 639 &cred_handle, 640 &rflags, 641 &channel->clnt_skey, &channel->clnt_skeyCnt, 642 &channel->ctoken, &channel->ctokenCnt, 643 &major_stat, 644 &minor_stat); 645 break; 646 case 2: 647 inout_gssd_flags = gssd_flags; 648 kr = mach_gss_init_sec_context_v2( 649 client_mp, 650 mech, 651 channel->stoken, channel->stokenCnt, 652 uid, 653 clientp.nt, 654 clientp.name, 655 clientp.len, 656 targetp.nt, 657 targetp.name, 658 targetp.len, 659 flags, 660 &inout_gssd_flags, 661 &gss_context, 662 &cred_handle, 663 &rflags, 664 &channel->clnt_skey, &channel->clnt_skeyCnt, 665 &channel->ctoken, &channel->ctokenCnt, 666 display_name, 667 &major_stat, 668 &minor_stat); 669 if (verbose && kr == KERN_SUCCESS && major_stat == GSS_S_COMPLETE) 670 Debug("Got client identity of '%s'\n", display_name); 671 break; 672 default: 673 Log("Unsupported version %d\n", version); 674 exit(1); 675 break; 676 } 677 678 if (kr != KERN_SUCCESS) { 679 OSAtomicIncrement32(&server_errors); 680 Log("gsstest client: %s\n", mach_error_string(kr)); 681 if (exitonerror) 682 exit(1); 683 if (kr == MIG_SERVER_DIED) { 684 OSAtomicIncrement32(&server_deaths); 685 if (gss_context == (uint32_t)(uintptr_t)GSS_C_NO_CONTEXT && 686 retry_count < max_retries) { 687 retry_count++; 688 goto retry; 689 } 690 } 691 692 channel->failure = 1; 693 write_channel(1, channel); 694 return (NULL); 695 } 696 697 gss_error = (major_stat != GSS_S_COMPLETE && 698 major_stat != GSS_S_CONTINUE_NEEDED); 699 if (verbose > 1) { 700 Debug("\tcred = 0x%0x\n", (int) cred_handle); 701 Debug("\tclnt_gss_context = 0x%0x\n", 702 (int) gss_context); 703 Debug("\ttokenCnt = %d\n", (int) channel->ctokenCnt); 704 if (verbose > 2) 705 HexDump((char *) channel->ctoken, 706 (uint32_t) channel->ctokenCnt); 707 } 708 709 channel->failure = gss_error; 710 write_channel(1, channel); 711 } while (major_stat == GSS_S_CONTINUE_NEEDED); 712 713 714 if (gss_error) { 715 OSAtomicIncrement32(&gss_init_errors); 716 Log("mach_gss_int_sec_context: %#K %#k\n", major_stat, mechtab[mech], minor_stat); 717 } 718 719 close_channel(1, channel); 720 return (NULL); 721} 722 723void *server(void *arg __attribute__((unused))) 724{ 725 struct s_channel args; 726 channel_t channel = &args; 727 pthread_t client_thr; 728 int error; 729 uint32_t major_stat = GSS_S_FAILURE; 730 uint32_t minor_stat; 731 uint32_t rflags; 732 uint32_t inout_gssd_flags; 733 gssd_cred cred_handle = (gssd_cred) (uintptr_t)GSS_C_NO_CREDENTIAL; 734 gssd_ctx gss_context = (gssd_ctx) (uintptr_t)GSS_C_NO_CONTEXT; 735 uint32_t clnt_uid; 736 uint32_t clnt_gids[NGROUPS_MAX]; 737 uint32_t clnt_ngroups; 738 gssd_byte_buffer svc_skey = NULL; 739 mach_msg_type_number_t svc_skeyCnt = 0; 740 kern_return_t kr; 741 int retry_count = 0; 742 743 channel->client = 1; 744 channel->failure = 0; 745 pthread_mutex_init(channel->lock, NULL); 746 pthread_cond_init(channel->cv, NULL); 747 channel->ctoken = (gssd_byte_buffer) GSS_C_NO_BUFFER; 748 channel->ctokenCnt = 0; 749 channel->stoken = (gssd_byte_buffer) GSS_C_NO_BUFFER; 750 channel->stokenCnt = 0; 751 channel->clnt_skey = (gssd_byte_buffer) GSS_C_NO_BUFFER; 752 channel->clnt_skeyCnt = 0; 753 754 // Kick off a client; 755 error = pthread_create(&client_thr, NULL, client, channel); 756 if (error) { 757 Log("Could not start client: %s\n", strerror(error)); 758 return NULL; 759 } 760 761 762 do { 763 if (read_channel(0, channel) == -1) { 764 Log("Bad read from client\n"); 765 goto out; 766 } 767 768 deallocate(channel->stoken, channel->stokenCnt); 769 channel->stoken = (gssd_byte_buffer)GSS_C_NO_BUFFER; 770 channel->stokenCnt = 0; 771 772 if (verbose) 773 Debug("Calling mach_gss_accept_sec_contex %p\n", 774 (void *) pthread_self()); 775 776retry: switch (version) { 777 case 0: 778 case 1: 779 kr = mach_gss_accept_sec_context( 780 server_mp, 781 channel->ctoken, channel->ctokenCnt, 782 svcname, 783 gssd_flags, 784 &gss_context, 785 &cred_handle, 786 &rflags, 787 &clnt_uid, 788 clnt_gids, 789 &clnt_ngroups, 790 &svc_skey, &svc_skeyCnt, 791 &channel->stoken, &channel->stokenCnt, 792 &major_stat, 793 &minor_stat); 794 break; 795 case 2: 796 inout_gssd_flags = gssd_flags; 797 kr = mach_gss_accept_sec_context_v2( 798 server_mp, 799 channel->ctoken, channel->ctokenCnt, 800 GSSD_STRING_NAME, 801 (uint8_t *)svcname, 802 (uint32_t) strlen(svcname)+1, 803 &inout_gssd_flags, 804 &gss_context, 805 &cred_handle, 806 &rflags, 807 &clnt_uid, 808 clnt_gids, 809 &clnt_ngroups, 810 &svc_skey, &svc_skeyCnt, 811 &channel->stoken, &channel->stokenCnt, 812 &major_stat, 813 &minor_stat); 814 break; 815 default: 816 Log("Unsupported version %d\n", version); 817 exit(1); 818 break; 819 } 820 821 if (kr != KERN_SUCCESS) { 822 OSAtomicIncrement32(&server_errors); 823 Log("gsstest server: %s\n", mach_error_string(kr)); 824 if (exitonerror) 825 exit(1); 826 if (kr == MIG_SERVER_DIED) { 827 OSAtomicIncrement32(&server_deaths); 828 if (gss_context == (uint32_t)(uintptr_t)GSS_C_NO_CONTEXT && 829 retry_count < max_retries) { 830 retry_count++; 831 goto retry; 832 } 833 } 834 835 channel->failure = 1; 836 write_channel(0, channel); 837 goto out; 838 } 839 840 error = (major_stat != GSS_S_COMPLETE && 841 major_stat != GSS_S_CONTINUE_NEEDED); 842 843 channel->failure = error; 844 write_channel(0, channel); 845 } while (major_stat == GSS_S_CONTINUE_NEEDED); 846 847 if (error) { 848 OSAtomicIncrement32(&gss_accept_errors); 849 Log("mach_gss_accept_sec_context: %#K %#k", major_stat, mechtab[mech], minor_stat); 850 } 851out: 852 close_channel(0, channel); 853 854 pthread_join(client_thr, NULL); 855 856 if (major_stat == GSS_S_COMPLETE && !CHANNEL_FAILED(channel)) { 857 if (svc_skeyCnt != channel->clnt_skeyCnt || 858 memcmp(svc_skey, channel->clnt_skey, svc_skeyCnt)) { 859 Log("Session keys don't match!\n"); 860 Log("\tClient key length = %d\n", 861 channel->clnt_skeyCnt); 862 HexDump((char *) channel->clnt_skey, 863 (uint32_t) channel->clnt_skeyCnt); 864 Log("\tServer key length = %d\n", svc_skeyCnt); 865 HexDump((char *) svc_skey, (uint32_t) svc_skeyCnt); 866 if (uid != clnt_uid) 867 Log("Wrong uid. got %d expected %d\n", 868 clnt_uid, uid); 869 } 870 else if (verbose) { 871 Debug("\tSession key length = %d\n", svc_skeyCnt); 872 HexDump((char *) svc_skey, (uint32_t) svc_skeyCnt); 873 Debug("\tReturned uid = %d\n", uid); 874 } 875 } else if (verbose > 1) { 876 Debug("Failed major status = %d\n", major_stat); 877 Debug("Channel failure = %x\n", channel->failure); 878 } 879 880 deallocate(svc_skey, svc_skeyCnt); 881 deallocate(channel->ctoken, channel->ctokenCnt); 882 deallocate(channel->stoken, channel->stokenCnt); 883 deallocate(channel->clnt_skey, channel->clnt_skeyCnt); 884 pthread_mutex_destroy(channel->lock); 885 pthread_cond_destroy(channel->cv); 886 887 server_done(); 888 889 return (NULL); 890} 891