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() 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 if (maj_stat != GSS_S_COMPLETE) { 142 display_status("acquiring credentials", maj_stat, min_stat); 143 return -1; 144 } 145 146 (void) gss_release_name(&min_stat, &server_name); 147 148 return 0; 149 } 150 151 /* 152 * Function: server_establish_context 153 * 154 * Purpose: establishses a GSS-API context as a specified service with 155 * an incoming client, and returns the context handle and associated 156 * client name 157 * 158 * Arguments: 159 * 160 * s (r) an established TCP connection to the client 161 * service_creds (r) server credentials, from gss_acquire_cred 162 * context (w) the established GSS-API context 163 * client_name (w) the client's ASCII name 164 * 165 * Returns: 0 on success, -1 on failure 166 * 167 * Effects: 168 * 169 * Any valid client request is accepted. If a context is established, 170 * its handle is returned in context and the client name is returned 171 * in client_name and 0 is returned. If unsuccessful, an error 172 * message is displayed and -1 is returned. 173 */ 174 static int 175 server_establish_context(int s, gss_cred_id_t server_creds, 176 gss_ctx_id_t *context, gss_buffer_t client_name, 177 OM_uint32 *ret_flags) 178 { 179 gss_buffer_desc send_tok, recv_tok; 180 gss_name_t client; 181 gss_OID doid; 182 OM_uint32 maj_stat, min_stat, acc_sec_min_stat; 183 gss_buffer_desc oid_name; 184 int token_flags; 185 186 if (recv_token(s, &token_flags, &recv_tok) < 0) 187 return -1; 188 189 if (recv_tok.value) { 190 free(recv_tok.value); 191 recv_tok.value = NULL; 192 } 193 194 if (!(token_flags & TOKEN_NOOP)) { 195 if (logfile) 196 fprintf(logfile, "Expected NOOP token, got %d token instead\n", 197 token_flags); 198 return -1; 199 } 200 201 *context = GSS_C_NO_CONTEXT; 202 203 if (token_flags & TOKEN_CONTEXT_NEXT) { 204 do { 205 if (recv_token(s, &token_flags, &recv_tok) < 0) 206 return -1; 207 208 if (verbose && logfile) { 209 fprintf(logfile, "Received token (size=%d): \n", 210 (int) recv_tok.length); 211 print_token(&recv_tok); 212 } 213 214 maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, 215 server_creds, &recv_tok, 216 GSS_C_NO_CHANNEL_BINDINGS, 217 &client, &doid, &send_tok, 218 ret_flags, 219 NULL, /* time_rec */ 220 NULL); /* del_cred_handle */ 221 222 if (recv_tok.value) { 223 free(recv_tok.value); 224 recv_tok.value = NULL; 225 } 226 227 if (send_tok.length != 0) { 228 if (verbose && logfile) { 229 fprintf(logfile, 230 "Sending accept_sec_context token (size=%d):\n", 231 (int) send_tok.length); 232 print_token(&send_tok); 233 } 234 if (send_token(s, TOKEN_CONTEXT, &send_tok) < 0) { 235 if (logfile) 236 fprintf(logfile, "failure sending token\n"); 237 return -1; 238 } 239 240 (void) gss_release_buffer(&min_stat, &send_tok); 241 } 242 if (maj_stat != GSS_S_COMPLETE 243 && maj_stat != GSS_S_CONTINUE_NEEDED) { 244 display_status("accepting context", maj_stat, 245 acc_sec_min_stat); 246 if (*context != GSS_C_NO_CONTEXT) 247 gss_delete_sec_context(&min_stat, context, 248 GSS_C_NO_BUFFER); 249 return -1; 250 } 251 252 if (verbose && logfile) { 253 if (maj_stat == GSS_S_CONTINUE_NEEDED) 254 fprintf(logfile, "continue needed...\n"); 255 else 256 fprintf(logfile, "\n"); 257 fflush(logfile); 258 } 259 } while (maj_stat == GSS_S_CONTINUE_NEEDED); 260 261 /* display the flags */ 262 display_ctx_flags(*ret_flags); 263 264 if (verbose && logfile) { 265 maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name); 266 if (maj_stat != GSS_S_COMPLETE) { 267 display_status("converting oid->string", maj_stat, min_stat); 268 return -1; 269 } 270 fprintf(logfile, "Accepted connection using mechanism OID %.*s.\n", 271 (int) oid_name.length, (char *) oid_name.value); 272 (void) gss_release_buffer(&min_stat, &oid_name); 273 } 274 275 maj_stat = gss_display_name(&min_stat, client, client_name, &doid); 276 if (maj_stat != GSS_S_COMPLETE) { 277 display_status("displaying name", maj_stat, min_stat); 278 return -1; 279 } 280 enumerateAttributes(&min_stat, client, TRUE); 281 showLocalIdentity(&min_stat, client); 282 maj_stat = gss_release_name(&min_stat, &client); 283 if (maj_stat != GSS_S_COMPLETE) { 284 display_status("releasing name", maj_stat, min_stat); 285 return -1; 286 } 287 } else { 288 client_name->length = *ret_flags = 0; 289 290 if (logfile) 291 fprintf(logfile, "Accepted unauthenticated connection.\n"); 292 } 293 294 return 0; 295 } 296 297 /* 298 * Function: create_socket 299 * 300 * Purpose: Opens a listening TCP socket. 301 * 302 * Arguments: 303 * 304 * port (r) the port number on which to listen 305 * 306 * Returns: the listening socket file descriptor, or -1 on failure 307 * 308 * Effects: 309 * 310 * A listening socket on the specified port and created and returned. 311 * On error, an error message is displayed and -1 is returned. 312 */ 313 static int 314 create_socket(u_short port) 315 { 316 struct sockaddr_in saddr; 317 int s; 318 int on = 1; 319 320 saddr.sin_family = AF_INET; 321 saddr.sin_port = htons(port); 322 saddr.sin_addr.s_addr = INADDR_ANY; 323 324 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 325 perror("creating socket"); 326 return -1; 327 } 328 /* Let the socket be reused right away */ 329 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); 330 if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { 331 perror("binding socket"); 332 (void) closesocket(s); 333 return -1; 334 } 335 if (listen(s, 5) < 0) { 336 perror("listening on socket"); 337 (void) closesocket(s); 338 return -1; 339 } 340 return s; 341 } 342 343 static float 344 timeval_subtract(struct timeval *tv1, struct timeval *tv2) 345 { 346 return ((tv1->tv_sec - tv2->tv_sec) + 347 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); 348 } 349 350 /* 351 * Yes, yes, this isn't the best place for doing this test. 352 * DO NOT REMOVE THIS UNTIL A BETTER TEST HAS BEEN WRITTEN, THOUGH. 353 * -TYT 354 */ 355 static int 356 test_import_export_context(gss_ctx_id_t *context) 357 { 358 OM_uint32 min_stat, maj_stat; 359 gss_buffer_desc context_token, copied_token; 360 struct timeval tm1, tm2; 361 362 /* 363 * Attempt to save and then restore the context. 364 */ 365 gettimeofday(&tm1, (struct timezone *) 0); 366 maj_stat = gss_export_sec_context(&min_stat, context, &context_token); 367 if (maj_stat != GSS_S_COMPLETE) { 368 display_status("exporting context", maj_stat, min_stat); 369 return 1; 370 } 371 gettimeofday(&tm2, (struct timezone *) 0); 372 if (verbose && logfile) 373 fprintf(logfile, "Exported context: %d bytes, %7.4f seconds\n", 374 (int) context_token.length, timeval_subtract(&tm2, &tm1)); 375 copied_token.length = context_token.length; 376 copied_token.value = malloc(context_token.length); 377 if (copied_token.value == 0) { 378 if (logfile) 379 fprintf(logfile, 380 "Couldn't allocate memory to copy context token.\n"); 381 return 1; 382 } 383 memcpy(copied_token.value, context_token.value, copied_token.length); 384 maj_stat = gss_import_sec_context(&min_stat, &copied_token, context); 385 if (maj_stat != GSS_S_COMPLETE) { 386 display_status("importing context", maj_stat, min_stat); 387 return 1; 388 } 389 free(copied_token.value); 390 gettimeofday(&tm1, (struct timezone *) 0); 391 if (verbose && logfile) 392 fprintf(logfile, "Importing context: %7.4f seconds\n", 393 timeval_subtract(&tm1, &tm2)); 394 (void) gss_release_buffer(&min_stat, &context_token); 395 return 0; 396 } 397 398 /* 399 * Function: sign_server 400 * 401 * Purpose: Performs the "sign" service. 402 * 403 * Arguments: 404 * 405 * s (r) a TCP socket on which a connection has been 406 * accept()ed 407 * service_name (r) the ASCII name of the GSS-API service to 408 * establish a context as 409 * export (r) whether to test context exporting 410 * 411 * Returns: -1 on error 412 * 413 * Effects: 414 * 415 * sign_server establishes a context, and performs a single sign request. 416 * 417 * A sign request is a single GSS-API sealed token. The token is 418 * unsealed and a signature block, produced with gss_sign, is returned 419 * to the sender. The context is the destroyed and the connection 420 * closed. 421 * 422 * If any error occurs, -1 is returned. 423 */ 424 static int 425 sign_server(int s, gss_cred_id_t server_creds, int export) 426 { 427 gss_buffer_desc client_name, recv_buf, unwrap_buf, mic_buf, *msg_buf, *send_buf; 428 gss_ctx_id_t context; 429 OM_uint32 maj_stat, min_stat; 430 int i, conf_state; 431 OM_uint32 ret_flags; 432 char *cp; 433 int token_flags; 434 int send_flags; 435 436 /* Establish a context with the client */ 437 if (server_establish_context(s, server_creds, &context, 438 &client_name, &ret_flags) < 0) 439 return (-1); 440 441 if (context == GSS_C_NO_CONTEXT) { 442 printf("Accepted unauthenticated connection.\n"); 443 } else { 444 printf("Accepted connection: \"%.*s\"\n", 445 (int) client_name.length, (char *) client_name.value); 446 (void) gss_release_buffer(&min_stat, &client_name); 447 448 if (export) { 449 for (i = 0; i < 3; i++) 450 if (test_import_export_context(&context)) 451 return -1; 452 } 453 } 454 455 do { 456 /* Receive the message token */ 457 if (recv_token(s, &token_flags, &recv_buf) < 0) 458 return (-1); 459 460 if (token_flags & TOKEN_NOOP) { 461 if (logfile) 462 fprintf(logfile, "NOOP token\n"); 463 if (recv_buf.value) { 464 free(recv_buf.value); 465 recv_buf.value = 0; 466 } 467 break; 468 } 469 470 if (verbose && logfile) { 471 fprintf(logfile, "Message token (flags=%d):\n", token_flags); 472 print_token(&recv_buf); 473 } 474 475 if ((context == GSS_C_NO_CONTEXT) && 476 (token_flags & (TOKEN_WRAPPED | TOKEN_ENCRYPTED | TOKEN_SEND_MIC))) 477 { 478 if (logfile) 479 fprintf(logfile, 480 "Unauthenticated client requested authenticated services!\n"); 481 if (recv_buf.value) { 482 free(recv_buf.value); 483 recv_buf.value = 0; 484 } 485 return (-1); 486 } 487 488 if (token_flags & TOKEN_WRAPPED) { 489 maj_stat = gss_unwrap(&min_stat, context, &recv_buf, &unwrap_buf, 490 &conf_state, (gss_qop_t *) NULL); 491 if (maj_stat != GSS_S_COMPLETE) { 492 display_status("unsealing message", maj_stat, min_stat); 493 if (recv_buf.value) { 494 free(recv_buf.value); 495 recv_buf.value = 0; 496 } 497 return (-1); 498 } else if (!conf_state && (token_flags & TOKEN_ENCRYPTED)) { 499 fprintf(stderr, "Warning! Message not encrypted.\n"); 500 } 501 502 if (recv_buf.value) { 503 free(recv_buf.value); 504 recv_buf.value = 0; 505 } 506 msg_buf = &unwrap_buf; 507 } else { 508 unwrap_buf.value = NULL; 509 unwrap_buf.length = 0; 510 msg_buf = &recv_buf; 511 } 512 513 if (logfile) { 514 fprintf(logfile, "Received message: "); 515 cp = msg_buf->value; 516 if ((isprint((int) cp[0]) || isspace((int) cp[0])) && 517 (isprint((int) cp[1]) || isspace((int) cp[1]))) { 518 fprintf(logfile, "\"%.*s\"\n", (int) msg_buf->length, 519 (char *) msg_buf->value); 520 } else { 521 fprintf(logfile, "\n"); 522 print_token(msg_buf); 523 } 524 } 525 526 if (token_flags & TOKEN_SEND_MIC) { 527 /* Produce a signature block for the message */ 528 maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT, 529 msg_buf, &mic_buf); 530 if (maj_stat != GSS_S_COMPLETE) { 531 display_status("signing message", maj_stat, min_stat); 532 return (-1); 533 } 534 send_flags = TOKEN_MIC; 535 send_buf = &mic_buf; 536 } else { 537 mic_buf.value = NULL; 538 mic_buf.length = 0; 539 send_flags = TOKEN_NOOP; 540 send_buf = empty_token; 541 } 542 if (recv_buf.value) { 543 free(recv_buf.value); 544 recv_buf.value = NULL; 545 } 546 if (unwrap_buf.value) { 547 gss_release_buffer(&min_stat, &unwrap_buf); 548 } 549 550 /* Send the signature block or NOOP to the client */ 551 if (send_token(s, send_flags, send_buf) < 0) 552 return (-1); 553 554 if (mic_buf.value) { 555 gss_release_buffer(&min_stat, &mic_buf); 556 } 557 } while (1 /* loop will break if NOOP received */ ); 558 559 if (context != GSS_C_NO_CONTEXT) { 560 /* Delete context */ 561 maj_stat = gss_delete_sec_context(&min_stat, &context, NULL); 562 if (maj_stat != GSS_S_COMPLETE) { 563 display_status("deleting context", maj_stat, min_stat); 564 return (-1); 565 } 566 } 567 568 if (logfile) 569 fflush(logfile); 570 571 return (0); 572 } 573 574 static int max_threads = 1; 575 576 #ifdef _WIN32 577 static thread_count = 0; 578 static HANDLE hMutex = NULL; 579 static HANDLE hEvent = NULL; 580 581 void 582 InitHandles(void) 583 { 584 hMutex = CreateMutex(NULL, FALSE, NULL); 585 hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 586 } 587 588 void 589 CleanupHandles(void) 590 { 591 CloseHandle(hMutex); 592 CloseHandle(hEvent); 593 } 594 595 BOOL 596 WaitAndIncrementThreadCounter(void) 597 { 598 for (;;) { 599 if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) { 600 if (thread_count < max_threads) { 601 thread_count++; 602 ReleaseMutex(hMutex); 603 return TRUE; 604 } else { 605 ReleaseMutex(hMutex); 606 607 if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) { 608 continue; 609 } else { 610 return FALSE; 611 } 612 } 613 } else { 614 return FALSE; 615 } 616 } 617 } 618 619 BOOL 620 DecrementAndSignalThreadCounter(void) 621 { 622 if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) { 623 if (thread_count == max_threads) 624 ResetEvent(hEvent); 625 thread_count--; 626 ReleaseMutex(hMutex); 627 return TRUE; 628 } else { 629 return FALSE; 630 } 631 } 632 #endif 633 634 struct _work_plan 635 { 636 int s; 637 gss_cred_id_t server_creds; 638 int export; 639 }; 640 641 static void 642 worker_bee(void *param) 643 { 644 struct _work_plan *work = (struct _work_plan *) param; 645 646 /* this return value is not checked, because there's 647 * not really anything to do if it fails 648 */ 649 sign_server(work->s, work->server_creds, work->export); 650 closesocket(work->s); 651 free(work); 652 653 #ifdef _WIN32 654 if (max_threads > 1) 655 DecrementAndSignalThreadCounter(); 656 #endif 657 } 658 659 int 660 main(int argc, char **argv) 661 { 662 char *service_name; 663 gss_cred_id_t server_creds; 664 gss_OID mech = GSS_C_NO_OID; 665 OM_uint32 min_stat; 666 u_short port = 4444; 667 int once = 0; 668 int do_inetd = 0; 669 int export = 0; 670 671 logfile = stdout; 672 display_file = stdout; 673 argc--; 674 argv++; 675 while (argc) { 676 if (strcmp(*argv, "-port") == 0) { 677 argc--; 678 argv++; 679 if (!argc) 680 usage(); 681 port = atoi(*argv); 682 } 683 #ifdef _WIN32 684 else if (strcmp(*argv, "-threads") == 0) { 685 argc--; 686 argv++; 687 if (!argc) 688 usage(); 689 max_threads = atoi(*argv); 690 } 691 #endif 692 else if (strcmp(*argv, "-verbose") == 0) { 693 verbose = 1; 694 } else if (strcmp(*argv, "-once") == 0) { 695 once = 1; 696 } else if (strcmp(*argv, "-inetd") == 0) { 697 do_inetd = 1; 698 } else if (strcmp(*argv, "-export") == 0) { 699 export = 1; 700 } else if (strcmp(*argv, "-logfile") == 0) { 701 argc--; 702 argv++; 703 if (!argc) 704 usage(); 705 /* Gross hack, but it makes it unnecessary to add an 706 * extra argument to disable logging, and makes the code 707 * more efficient because it doesn't actually write data 708 * to /dev/null. */ 709 if (!strcmp(*argv, "/dev/null")) { 710 logfile = display_file = NULL; 711 } else { 712 logfile = fopen(*argv, "a"); 713 display_file = logfile; 714 if (!logfile) { 715 perror(*argv); 716 exit(1); 717 } 718 } 719 } else if (strcmp(*argv, "-keytab") == 0) { 720 argc--; 721 argv++; 722 if (!argc) 723 usage(); 724 if (krb5_gss_register_acceptor_identity(*argv)) { 725 fprintf(stderr, "failed to register keytab\n"); 726 exit(1); 727 } 728 } else if (strcmp(*argv, "-iakerb") == 0) { 729 mech = (gss_OID)gss_mech_iakerb; 730 } else 731 break; 732 argc--; 733 argv++; 734 } 735 if (argc != 1) 736 usage(); 737 738 if ((*argv)[0] == '-') 739 usage(); 740 741 #ifdef _WIN32 742 if (max_threads < 1) { 743 fprintf(stderr, "warning: there must be at least one thread\n"); 744 max_threads = 1; 745 } 746 747 if (max_threads > 1 && do_inetd) 748 fprintf(stderr, 749 "warning: one thread may be used in conjunction with inetd\n"); 750 751 InitHandles(); 752 #endif 753 754 service_name = *argv; 755 756 if (server_acquire_creds(service_name, mech, &server_creds) < 0) 757 return -1; 758 759 if (do_inetd) { 760 close(1); 761 close(2); 762 763 sign_server(0, server_creds, export); 764 close(0); 765 } else { 766 int stmp; 767 768 if ((stmp = create_socket(port)) >= 0) { 769 fprintf(stderr, "starting...\n"); 770 771 do { 772 struct _work_plan *work = malloc(sizeof(struct _work_plan)); 773 774 if (work == NULL) { 775 fprintf(stderr, "fatal error: out of memory"); 776 break; 777 } 778 779 /* Accept a TCP connection */ 780 if ((work->s = accept(stmp, NULL, 0)) < 0) { 781 perror("accepting connection"); 782 free(work); 783 continue; 784 } 785 786 work->server_creds = server_creds; 787 work->export = export; 788 789 if (max_threads == 1) { 790 worker_bee((void *) work); 791 } 792 #ifdef _WIN32 793 else { 794 if (WaitAndIncrementThreadCounter()) { 795 uintptr_t handle = 796 _beginthread(worker_bee, 0, (void *) work); 797 if (handle == (uintptr_t) - 1) { 798 closesocket(work->s); 799 free(work); 800 } 801 } else { 802 fprintf(stderr, 803 "fatal error incrementing thread counter"); 804 closesocket(work->s); 805 free(work); 806 break; 807 } 808 } 809 #endif 810 } while (!once); 811 812 closesocket(stmp); 813 } 814 } 815 816 (void) gss_release_cred(&min_stat, &server_creds); 817 818 #ifdef _WIN32 819 CleanupHandles(); 820 #endif 821 822 return 0; 823 } 824 825 static void 826 dumpAttribute(OM_uint32 *minor, 827 gss_name_t name, 828 gss_buffer_t attribute, 829 int noisy) 830 { 831 OM_uint32 major, tmp; 832 gss_buffer_desc value; 833 gss_buffer_desc display_value; 834 int authenticated = 0; 835 int complete = 0; 836 int more = -1; 837 unsigned int i; 838 839 while (more != 0) { 840 value.value = NULL; 841 display_value.value = NULL; 842 843 major = gss_get_name_attribute(minor, name, attribute, &authenticated, 844 &complete, &value, &display_value, 845 &more); 846 if (GSS_ERROR(major)) { 847 display_status("gss_get_name_attribute", major, *minor); 848 break; 849 } 850 851 printf("Attribute %.*s %s %s\n\n%.*s\n", 852 (int)attribute->length, (char *)attribute->value, 853 authenticated ? "Authenticated" : "", 854 complete ? "Complete" : "", 855 (int)display_value.length, (char *)display_value.value); 856 857 if (noisy) { 858 for (i = 0; i < value.length; i++) { 859 if ((i % 32) == 0) 860 printf("\n"); 861 printf("%02x", ((char *)value.value)[i] & 0xFF); 862 } 863 printf("\n\n"); 864 } 865 866 gss_release_buffer(&tmp, &value); 867 gss_release_buffer(&tmp, &display_value); 868 } 869 } 870 871 static OM_uint32 872 enumerateAttributes(OM_uint32 *minor, 873 gss_name_t name, 874 int noisy) 875 { 876 OM_uint32 major, tmp; 877 int name_is_MN; 878 gss_OID mech = GSS_C_NO_OID; 879 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; 880 unsigned int i; 881 882 major = gss_inquire_name(minor, name, &name_is_MN, &mech, &attrs); 883 if (GSS_ERROR(major)) { 884 display_status("gss_inquire_name", major, *minor); 885 return major; 886 } 887 888 if (attrs != GSS_C_NO_BUFFER_SET) { 889 for (i = 0; i < attrs->count; i++) 890 dumpAttribute(minor, name, &attrs->elements[i], noisy); 891 } 892 893 gss_release_oid(&tmp, &mech); 894 gss_release_buffer_set(&tmp, &attrs); 895 896 return major; 897 } 898 899 static OM_uint32 900 showLocalIdentity(OM_uint32 *minor, gss_name_t name) 901 { 902 OM_uint32 major; 903 gss_buffer_desc buf; 904 905 major = gss_localname(minor, name, GSS_C_NO_OID, &buf); 906 if (major == GSS_S_COMPLETE) 907 printf("localname: %-*s\n", (int)buf.length, (char *)buf.value); 908 else if (major != GSS_S_UNAVAILABLE) 909 display_status("gss_localname", major, *minor); 910 gss_release_buffer(minor, &buf); 911 return major; 912 } 913