1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 1994 by OpenVision Technologies, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software 6 * and its documentation for any purpose is hereby granted without fee, 7 * provided that the above copyright notice appears in all copies and 8 * that both that copyright notice and this permission notice appear in 9 * supporting documentation, and that the name of OpenVision not be used 10 * in advertising or publicity pertaining to distribution of the software 11 * without specific, written prior permission. OpenVision makes no 12 * representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied warranty. 14 * 15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 /* 24 * Copyright (C) 2004,2005 by the Massachusetts Institute of Technology. 25 * All rights reserved. 26 * 27 * Export of this software from the United States of America may 28 * require a specific license from the United States Government. 29 * It is the responsibility of any person or organization contemplating 30 * export to obtain such a license before exporting. 31 * 32 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 33 * distribute this software and its documentation for any purpose and 34 * without fee is hereby granted, provided that the above copyright 35 * notice appear in all copies and that both that copyright notice and 36 * this permission notice appear in supporting documentation, and that 37 * the name of M.I.T. not be used in advertising or publicity pertaining 38 * to distribution of the software without specific, written prior 39 * permission. Furthermore if you modify this software you must label 40 * your software as modified software and not distribute it in such a 41 * fashion that it might be confused with the original M.I.T. software. 42 * M.I.T. makes no representations about the suitability of 43 * this software for any purpose. It is provided "as is" without express 44 * or implied warranty. 45 */ 46 47 #include <stdio.h> 48 #ifdef _WIN32 49 #include <windows.h> 50 #include <winsock.h> 51 #else 52 #include "port-sockets.h" 53 #endif 54 #ifdef HAVE_UNISTD_H 55 #include <unistd.h> 56 #endif 57 #include <stdlib.h> 58 #include <ctype.h> 59 60 #include <gssapi/gssapi_generic.h> 61 #include <gssapi/gssapi_krb5.h> 62 #include "gss-misc.h" 63 64 #ifdef HAVE_STRING_H 65 #include <string.h> 66 #else 67 #include <strings.h> 68 #endif 69 70 static OM_uint32 71 enumerateAttributes(OM_uint32 *minor, gss_name_t name, int noisy); 72 static OM_uint32 73 showLocalIdentity(OM_uint32 *minor, gss_name_t name); 74 75 static void 76 usage(void) 77 { 78 fprintf(stderr, "Usage: gss-server [-port port] [-verbose] [-once]"); 79 #ifdef _WIN32 80 fprintf(stderr, " [-threads num]"); 81 #endif 82 fprintf(stderr, "\n"); 83 fprintf(stderr, 84 " [-inetd] [-export] [-logfile file] [-keytab keytab]\n" 85 " service_name\n"); 86 exit(1); 87 } 88 89 static FILE *logfile; 90 91 int verbose = 0; 92 93 /* 94 * Function: server_acquire_creds 95 * 96 * Purpose: imports a service name and acquires credentials for it 97 * 98 * Arguments: 99 * 100 * service_name (r) the ASCII service name 101 * mech (r) the desired mechanism (or GSS_C_NO_OID) 102 * server_creds (w) the GSS-API service credentials 103 * 104 * Returns: 0 on success, -1 on failure 105 * 106 * Effects: 107 * 108 * The service name is imported with gss_import_name, and service 109 * credentials are acquired with gss_acquire_cred. If either operation 110 * fails, an error message is displayed and -1 is returned; otherwise, 111 * 0 is returned. If mech is given, credentials are acquired for the 112 * specified mechanism. 113 */ 114 115 static int 116 server_acquire_creds(char *service_name, gss_OID mech, 117 gss_cred_id_t *server_creds) 118 { 119 gss_buffer_desc name_buf; 120 gss_name_t server_name; 121 OM_uint32 maj_stat, min_stat; 122 gss_OID_set_desc mechlist; 123 gss_OID_set mechs = GSS_C_NO_OID_SET; 124 125 name_buf.value = service_name; 126 name_buf.length = strlen(name_buf.value) + 1; 127 maj_stat = gss_import_name(&min_stat, &name_buf, 128 (gss_OID) gss_nt_service_name, &server_name); 129 if (maj_stat != GSS_S_COMPLETE) { 130 display_status("importing name", maj_stat, min_stat); 131 return -1; 132 } 133 134 if (mech != GSS_C_NO_OID) { 135 mechlist.count = 1; 136 mechlist.elements = mech; 137 mechs = &mechlist; 138 } 139 maj_stat = gss_acquire_cred(&min_stat, server_name, 0, mechs, GSS_C_ACCEPT, 140 server_creds, NULL, NULL); 141 (void) gss_release_name(&min_stat, &server_name); 142 if (maj_stat != GSS_S_COMPLETE) { 143 display_status("acquiring credentials", maj_stat, min_stat); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 /* 151 * Function: server_establish_context 152 * 153 * Purpose: establishses a GSS-API context as a specified service with 154 * an incoming client, and returns the context handle and associated 155 * client name 156 * 157 * Arguments: 158 * 159 * s (r) an established TCP connection to the client 160 * service_creds (r) server credentials, from gss_acquire_cred 161 * context (w) the established GSS-API context 162 * client_name (w) the client's ASCII name 163 * 164 * Returns: 0 on success, -1 on failure 165 * 166 * Effects: 167 * 168 * Any valid client request is accepted. If a context is established, 169 * its handle is returned in context and the client name is returned 170 * in client_name and 0 is returned. If unsuccessful, an error 171 * message is displayed and -1 is returned. 172 */ 173 static int 174 server_establish_context(int s, gss_cred_id_t server_creds, 175 gss_ctx_id_t *context, gss_buffer_t client_name, 176 OM_uint32 *ret_flags) 177 { 178 gss_buffer_desc send_tok, recv_tok; 179 gss_name_t client; 180 gss_OID doid; 181 OM_uint32 maj_stat, min_stat, acc_sec_min_stat; 182 gss_buffer_desc oid_name; 183 int token_flags; 184 185 if (recv_token(s, &token_flags, &recv_tok) < 0) 186 return -1; 187 188 if (recv_tok.value) { 189 free(recv_tok.value); 190 recv_tok.value = NULL; 191 } 192 193 if (!(token_flags & TOKEN_NOOP)) { 194 if (logfile) 195 fprintf(logfile, "Expected NOOP token, got %d token instead\n", 196 token_flags); 197 return -1; 198 } 199 200 *context = GSS_C_NO_CONTEXT; 201 202 if (token_flags & TOKEN_CONTEXT_NEXT) { 203 do { 204 if (recv_token(s, &token_flags, &recv_tok) < 0) 205 return -1; 206 207 if (verbose && logfile) { 208 fprintf(logfile, "Received token (size=%d): \n", 209 (int) recv_tok.length); 210 print_token(&recv_tok); 211 } 212 213 maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, 214 server_creds, &recv_tok, 215 GSS_C_NO_CHANNEL_BINDINGS, 216 &client, &doid, &send_tok, 217 ret_flags, 218 NULL, /* time_rec */ 219 NULL); /* del_cred_handle */ 220 221 if (recv_tok.value) { 222 free(recv_tok.value); 223 recv_tok.value = NULL; 224 } 225 226 if (send_tok.length != 0) { 227 if (verbose && logfile) { 228 fprintf(logfile, 229 "Sending accept_sec_context token (size=%d):\n", 230 (int) send_tok.length); 231 print_token(&send_tok); 232 } 233 if (send_token(s, TOKEN_CONTEXT, &send_tok) < 0) { 234 if (logfile) 235 fprintf(logfile, "failure sending token\n"); 236 return -1; 237 } 238 239 (void) gss_release_buffer(&min_stat, &send_tok); 240 } 241 if (maj_stat != GSS_S_COMPLETE 242 && maj_stat != GSS_S_CONTINUE_NEEDED) { 243 display_status("accepting context", maj_stat, 244 acc_sec_min_stat); 245 if (*context != GSS_C_NO_CONTEXT) 246 gss_delete_sec_context(&min_stat, context, 247 GSS_C_NO_BUFFER); 248 return -1; 249 } 250 251 if (verbose && logfile) { 252 if (maj_stat == GSS_S_CONTINUE_NEEDED) 253 fprintf(logfile, "continue needed...\n"); 254 else 255 fprintf(logfile, "\n"); 256 fflush(logfile); 257 } 258 } while (maj_stat == GSS_S_CONTINUE_NEEDED); 259 260 /* display the flags */ 261 display_ctx_flags(*ret_flags); 262 263 if (verbose && logfile) { 264 maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name); 265 if (maj_stat != GSS_S_COMPLETE) { 266 display_status("converting oid->string", maj_stat, min_stat); 267 return -1; 268 } 269 fprintf(logfile, "Accepted connection using mechanism OID %.*s.\n", 270 (int) oid_name.length, (char *) oid_name.value); 271 (void) gss_release_buffer(&min_stat, &oid_name); 272 } 273 274 maj_stat = gss_display_name(&min_stat, client, client_name, &doid); 275 if (maj_stat != GSS_S_COMPLETE) { 276 display_status("displaying name", maj_stat, min_stat); 277 return -1; 278 } 279 enumerateAttributes(&min_stat, client, TRUE); 280 showLocalIdentity(&min_stat, client); 281 maj_stat = gss_release_name(&min_stat, &client); 282 if (maj_stat != GSS_S_COMPLETE) { 283 display_status("releasing name", maj_stat, min_stat); 284 return -1; 285 } 286 } else { 287 client_name->length = *ret_flags = 0; 288 289 if (logfile) 290 fprintf(logfile, "Accepted unauthenticated connection.\n"); 291 } 292 293 return 0; 294 } 295 296 /* 297 * Function: create_socket 298 * 299 * Purpose: Opens a listening TCP socket. 300 * 301 * Arguments: 302 * 303 * port (r) the port number on which to listen 304 * 305 * Returns: the listening socket file descriptor, or -1 on failure 306 * 307 * Effects: 308 * 309 * A listening socket on the specified port and created and returned. 310 * On error, an error message is displayed and -1 is returned. 311 */ 312 static int 313 create_socket(u_short port) 314 { 315 struct sockaddr_in saddr; 316 int s; 317 int on = 1; 318 319 saddr.sin_family = AF_INET; 320 saddr.sin_port = htons(port); 321 saddr.sin_addr.s_addr = INADDR_ANY; 322 323 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 324 perror("creating socket"); 325 return -1; 326 } 327 /* Let the socket be reused right away */ 328 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); 329 if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { 330 perror("binding socket"); 331 (void) closesocket(s); 332 return -1; 333 } 334 if (listen(s, 5) < 0) { 335 perror("listening on socket"); 336 (void) closesocket(s); 337 return -1; 338 } 339 return s; 340 } 341 342 static float 343 timeval_subtract(struct timeval *tv1, struct timeval *tv2) 344 { 345 return ((tv1->tv_sec - tv2->tv_sec) + 346 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); 347 } 348 349 /* 350 * Yes, yes, this isn't the best place for doing this test. 351 * DO NOT REMOVE THIS UNTIL A BETTER TEST HAS BEEN WRITTEN, THOUGH. 352 * -TYT 353 */ 354 static int 355 test_import_export_context(gss_ctx_id_t *context) 356 { 357 OM_uint32 min_stat, maj_stat; 358 gss_buffer_desc context_token, copied_token; 359 struct timeval tm1, tm2; 360 361 /* 362 * Attempt to save and then restore the context. 363 */ 364 gettimeofday(&tm1, (struct timezone *) 0); 365 maj_stat = gss_export_sec_context(&min_stat, context, &context_token); 366 if (maj_stat != GSS_S_COMPLETE) { 367 display_status("exporting context", maj_stat, min_stat); 368 return 1; 369 } 370 gettimeofday(&tm2, (struct timezone *) 0); 371 if (verbose && logfile) 372 fprintf(logfile, "Exported context: %d bytes, %7.4f seconds\n", 373 (int) context_token.length, timeval_subtract(&tm2, &tm1)); 374 copied_token.length = context_token.length; 375 copied_token.value = malloc(context_token.length); 376 if (copied_token.value == 0) { 377 if (logfile) 378 fprintf(logfile, 379 "Couldn't allocate memory to copy context token.\n"); 380 return 1; 381 } 382 memcpy(copied_token.value, context_token.value, copied_token.length); 383 maj_stat = gss_import_sec_context(&min_stat, &copied_token, context); 384 if (maj_stat != GSS_S_COMPLETE) { 385 display_status("importing context", maj_stat, min_stat); 386 return 1; 387 } 388 free(copied_token.value); 389 gettimeofday(&tm1, (struct timezone *) 0); 390 if (verbose && logfile) 391 fprintf(logfile, "Importing context: %7.4f seconds\n", 392 timeval_subtract(&tm1, &tm2)); 393 (void) gss_release_buffer(&min_stat, &context_token); 394 return 0; 395 } 396 397 /* 398 * Function: sign_server 399 * 400 * Purpose: Performs the "sign" service. 401 * 402 * Arguments: 403 * 404 * s (r) a TCP socket on which a connection has been 405 * accept()ed 406 * service_name (r) the ASCII name of the GSS-API service to 407 * establish a context as 408 * export (r) whether to test context exporting 409 * 410 * Returns: -1 on error 411 * 412 * Effects: 413 * 414 * sign_server establishes a context, and performs a single sign request. 415 * 416 * A sign request is a single GSS-API sealed token. The token is 417 * unsealed and a signature block, produced with gss_sign, is returned 418 * to the sender. The context is the destroyed and the connection 419 * closed. 420 * 421 * If any error occurs, -1 is returned. 422 */ 423 static int 424 sign_server(int s, gss_cred_id_t server_creds, int export) 425 { 426 gss_buffer_desc client_name, recv_buf, unwrap_buf, mic_buf, *msg_buf, *send_buf; 427 gss_ctx_id_t context; 428 OM_uint32 maj_stat, min_stat; 429 int i, conf_state; 430 OM_uint32 ret_flags; 431 char *cp; 432 int token_flags; 433 int send_flags; 434 435 /* Establish a context with the client */ 436 if (server_establish_context(s, server_creds, &context, 437 &client_name, &ret_flags) < 0) 438 return (-1); 439 440 if (context == GSS_C_NO_CONTEXT) { 441 printf("Accepted unauthenticated connection.\n"); 442 } else { 443 printf("Accepted connection: \"%.*s\"\n", 444 (int) client_name.length, (char *) client_name.value); 445 (void) gss_release_buffer(&min_stat, &client_name); 446 447 if (export) { 448 for (i = 0; i < 3; i++) 449 if (test_import_export_context(&context)) 450 return -1; 451 } 452 } 453 454 do { 455 /* Receive the message token */ 456 if (recv_token(s, &token_flags, &recv_buf) < 0) 457 return (-1); 458 459 if (token_flags & TOKEN_NOOP) { 460 if (logfile) 461 fprintf(logfile, "NOOP token\n"); 462 if (recv_buf.value) { 463 free(recv_buf.value); 464 recv_buf.value = 0; 465 } 466 break; 467 } 468 469 if (verbose && logfile) { 470 fprintf(logfile, "Message token (flags=%d):\n", token_flags); 471 print_token(&recv_buf); 472 } 473 474 if ((context == GSS_C_NO_CONTEXT) && 475 (token_flags & (TOKEN_WRAPPED | TOKEN_ENCRYPTED | TOKEN_SEND_MIC))) 476 { 477 if (logfile) 478 fprintf(logfile, 479 "Unauthenticated client requested authenticated services!\n"); 480 if (recv_buf.value) { 481 free(recv_buf.value); 482 recv_buf.value = 0; 483 } 484 return (-1); 485 } 486 487 if (token_flags & TOKEN_WRAPPED) { 488 maj_stat = gss_unwrap(&min_stat, context, &recv_buf, &unwrap_buf, 489 &conf_state, (gss_qop_t *) NULL); 490 if (maj_stat != GSS_S_COMPLETE) { 491 display_status("unsealing message", maj_stat, min_stat); 492 if (recv_buf.value) { 493 free(recv_buf.value); 494 recv_buf.value = 0; 495 } 496 return (-1); 497 } else if (!conf_state && (token_flags & TOKEN_ENCRYPTED)) { 498 fprintf(stderr, "Warning! Message not encrypted.\n"); 499 } 500 501 if (recv_buf.value) { 502 free(recv_buf.value); 503 recv_buf.value = 0; 504 } 505 msg_buf = &unwrap_buf; 506 } else { 507 unwrap_buf.value = NULL; 508 unwrap_buf.length = 0; 509 msg_buf = &recv_buf; 510 } 511 512 if (logfile) { 513 fprintf(logfile, "Received message: "); 514 cp = msg_buf->value; 515 if ((isprint((int) cp[0]) || isspace((int) cp[0])) && 516 (isprint((int) cp[1]) || isspace((int) cp[1]))) { 517 fprintf(logfile, "\"%.*s\"\n", (int) msg_buf->length, 518 (char *) msg_buf->value); 519 } else { 520 fprintf(logfile, "\n"); 521 print_token(msg_buf); 522 } 523 } 524 525 if (token_flags & TOKEN_SEND_MIC) { 526 /* Produce a signature block for the message */ 527 maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT, 528 msg_buf, &mic_buf); 529 if (maj_stat != GSS_S_COMPLETE) { 530 display_status("signing message", maj_stat, min_stat); 531 return (-1); 532 } 533 send_flags = TOKEN_MIC; 534 send_buf = &mic_buf; 535 } else { 536 mic_buf.value = NULL; 537 mic_buf.length = 0; 538 send_flags = TOKEN_NOOP; 539 send_buf = empty_token; 540 } 541 if (recv_buf.value) { 542 free(recv_buf.value); 543 recv_buf.value = NULL; 544 } 545 if (unwrap_buf.value) { 546 gss_release_buffer(&min_stat, &unwrap_buf); 547 } 548 549 /* Send the signature block or NOOP to the client */ 550 if (send_token(s, send_flags, send_buf) < 0) 551 return (-1); 552 553 if (mic_buf.value) { 554 gss_release_buffer(&min_stat, &mic_buf); 555 } 556 } while (1 /* loop will break if NOOP received */ ); 557 558 if (context != GSS_C_NO_CONTEXT) { 559 /* Delete context */ 560 maj_stat = gss_delete_sec_context(&min_stat, &context, NULL); 561 if (maj_stat != GSS_S_COMPLETE) { 562 display_status("deleting context", maj_stat, min_stat); 563 return (-1); 564 } 565 } 566 567 if (logfile) 568 fflush(logfile); 569 570 return (0); 571 } 572 573 static int max_threads = 1; 574 575 #ifdef _WIN32 576 static thread_count = 0; 577 static HANDLE hMutex = NULL; 578 static HANDLE hEvent = NULL; 579 580 void 581 InitHandles(void) 582 { 583 hMutex = CreateMutex(NULL, FALSE, NULL); 584 hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 585 } 586 587 void 588 CleanupHandles(void) 589 { 590 CloseHandle(hMutex); 591 CloseHandle(hEvent); 592 } 593 594 BOOL 595 WaitAndIncrementThreadCounter(void) 596 { 597 for (;;) { 598 if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) { 599 if (thread_count < max_threads) { 600 thread_count++; 601 ReleaseMutex(hMutex); 602 return TRUE; 603 } else { 604 ReleaseMutex(hMutex); 605 606 if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) { 607 continue; 608 } else { 609 return FALSE; 610 } 611 } 612 } else { 613 return FALSE; 614 } 615 } 616 } 617 618 BOOL 619 DecrementAndSignalThreadCounter(void) 620 { 621 if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) { 622 if (thread_count == max_threads) 623 ResetEvent(hEvent); 624 thread_count--; 625 ReleaseMutex(hMutex); 626 return TRUE; 627 } else { 628 return FALSE; 629 } 630 } 631 #endif 632 633 struct _work_plan 634 { 635 int s; 636 gss_cred_id_t server_creds; 637 int export; 638 }; 639 640 static void 641 worker_bee(void *param) 642 { 643 struct _work_plan *work = (struct _work_plan *) param; 644 645 /* this return value is not checked, because there's 646 * not really anything to do if it fails 647 */ 648 sign_server(work->s, work->server_creds, work->export); 649 closesocket(work->s); 650 free(work); 651 652 #ifdef _WIN32 653 if (max_threads > 1) 654 DecrementAndSignalThreadCounter(); 655 #endif 656 } 657 658 int 659 main(int argc, char **argv) 660 { 661 char *service_name; 662 gss_cred_id_t server_creds; 663 gss_OID mech = GSS_C_NO_OID; 664 OM_uint32 min_stat; 665 u_short port = 4444; 666 int once = 0; 667 int do_inetd = 0; 668 int export = 0; 669 670 logfile = stdout; 671 display_file = stdout; 672 argc--; 673 argv++; 674 while (argc) { 675 if (strcmp(*argv, "-port") == 0) { 676 argc--; 677 argv++; 678 if (!argc) 679 usage(); 680 port = atoi(*argv); 681 } 682 #ifdef _WIN32 683 else if (strcmp(*argv, "-threads") == 0) { 684 argc--; 685 argv++; 686 if (!argc) 687 usage(); 688 max_threads = atoi(*argv); 689 } 690 #endif 691 else if (strcmp(*argv, "-verbose") == 0) { 692 verbose = 1; 693 } else if (strcmp(*argv, "-once") == 0) { 694 once = 1; 695 } else if (strcmp(*argv, "-inetd") == 0) { 696 do_inetd = 1; 697 } else if (strcmp(*argv, "-export") == 0) { 698 export = 1; 699 } else if (strcmp(*argv, "-logfile") == 0) { 700 argc--; 701 argv++; 702 if (!argc) 703 usage(); 704 /* Gross hack, but it makes it unnecessary to add an 705 * extra argument to disable logging, and makes the code 706 * more efficient because it doesn't actually write data 707 * to /dev/null. */ 708 if (!strcmp(*argv, "/dev/null")) { 709 logfile = display_file = NULL; 710 } else { 711 logfile = fopen(*argv, "a"); 712 display_file = logfile; 713 if (!logfile) { 714 perror(*argv); 715 exit(1); 716 } 717 } 718 } else if (strcmp(*argv, "-keytab") == 0) { 719 argc--; 720 argv++; 721 if (!argc) 722 usage(); 723 if (krb5_gss_register_acceptor_identity(*argv)) { 724 fprintf(stderr, "failed to register keytab\n"); 725 exit(1); 726 } 727 } else if (strcmp(*argv, "-iakerb") == 0) { 728 mech = (gss_OID)gss_mech_iakerb; 729 } else 730 break; 731 argc--; 732 argv++; 733 } 734 if (argc != 1) 735 usage(); 736 737 if ((*argv)[0] == '-') 738 usage(); 739 740 #ifdef _WIN32 741 if (max_threads < 1) { 742 fprintf(stderr, "warning: there must be at least one thread\n"); 743 max_threads = 1; 744 } 745 746 if (max_threads > 1 && do_inetd) 747 fprintf(stderr, 748 "warning: one thread may be used in conjunction with inetd\n"); 749 750 InitHandles(); 751 #endif 752 753 service_name = *argv; 754 755 if (server_acquire_creds(service_name, mech, &server_creds) < 0) 756 return -1; 757 758 if (do_inetd) { 759 close(1); 760 close(2); 761 762 sign_server(0, server_creds, export); 763 close(0); 764 } else { 765 int stmp; 766 767 if ((stmp = create_socket(port)) >= 0) { 768 fprintf(stderr, "starting...\n"); 769 770 do { 771 struct _work_plan *work = malloc(sizeof(struct _work_plan)); 772 773 if (work == NULL) { 774 fprintf(stderr, "fatal error: out of memory"); 775 break; 776 } 777 778 /* Accept a TCP connection */ 779 if ((work->s = accept(stmp, NULL, 0)) < 0) { 780 perror("accepting connection"); 781 free(work); 782 continue; 783 } 784 785 work->server_creds = server_creds; 786 work->export = export; 787 788 if (max_threads == 1) { 789 worker_bee((void *) work); 790 } 791 #ifdef _WIN32 792 else { 793 if (WaitAndIncrementThreadCounter()) { 794 uintptr_t handle = 795 _beginthread(worker_bee, 0, (void *) work); 796 if (handle == (uintptr_t) - 1) { 797 closesocket(work->s); 798 free(work); 799 } 800 } else { 801 fprintf(stderr, 802 "fatal error incrementing thread counter"); 803 closesocket(work->s); 804 free(work); 805 break; 806 } 807 } 808 #endif 809 } while (!once); 810 811 closesocket(stmp); 812 } 813 } 814 815 (void) gss_release_cred(&min_stat, &server_creds); 816 817 #ifdef _WIN32 818 CleanupHandles(); 819 #endif 820 821 return 0; 822 } 823 824 static void 825 dumpAttribute(OM_uint32 *minor, 826 gss_name_t name, 827 gss_buffer_t attribute, 828 int noisy) 829 { 830 OM_uint32 major, tmp; 831 gss_buffer_desc value; 832 gss_buffer_desc display_value; 833 int authenticated = 0; 834 int complete = 0; 835 int more = -1; 836 unsigned int i; 837 838 while (more != 0) { 839 value.value = NULL; 840 display_value.value = NULL; 841 842 major = gss_get_name_attribute(minor, name, attribute, &authenticated, 843 &complete, &value, &display_value, 844 &more); 845 if (GSS_ERROR(major)) { 846 display_status("gss_get_name_attribute", major, *minor); 847 break; 848 } 849 850 printf("Attribute %.*s %s %s\n\n%.*s\n", 851 (int)attribute->length, (char *)attribute->value, 852 authenticated ? "Authenticated" : "", 853 complete ? "Complete" : "", 854 (int)display_value.length, (char *)display_value.value); 855 856 if (noisy) { 857 for (i = 0; i < value.length; i++) { 858 if ((i % 32) == 0) 859 printf("\n"); 860 printf("%02x", ((char *)value.value)[i] & 0xFF); 861 } 862 printf("\n\n"); 863 } 864 865 gss_release_buffer(&tmp, &value); 866 gss_release_buffer(&tmp, &display_value); 867 } 868 } 869 870 static OM_uint32 871 enumerateAttributes(OM_uint32 *minor, 872 gss_name_t name, 873 int noisy) 874 { 875 OM_uint32 major, tmp; 876 int name_is_MN; 877 gss_OID mech = GSS_C_NO_OID; 878 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; 879 unsigned int i; 880 881 major = gss_inquire_name(minor, name, &name_is_MN, &mech, &attrs); 882 if (GSS_ERROR(major)) { 883 display_status("gss_inquire_name", major, *minor); 884 return major; 885 } 886 887 if (attrs != GSS_C_NO_BUFFER_SET) { 888 for (i = 0; i < attrs->count; i++) 889 dumpAttribute(minor, name, &attrs->elements[i], noisy); 890 } 891 892 gss_release_oid(&tmp, &mech); 893 gss_release_buffer_set(&tmp, &attrs); 894 895 return major; 896 } 897 898 static OM_uint32 899 showLocalIdentity(OM_uint32 *minor, gss_name_t name) 900 { 901 OM_uint32 major; 902 gss_buffer_desc buf; 903 904 major = gss_localname(minor, name, GSS_C_NO_OID, &buf); 905 if (major == GSS_S_COMPLETE) 906 printf("localname: %-*s\n", (int)buf.length, (char *)buf.value); 907 else if (major != GSS_S_UNAVAILABLE) 908 display_status("gss_localname", major, *minor); 909 gss_release_buffer(minor, &buf); 910 return major; 911 } 912