aboutsummaryrefslogtreecommitdiff
path: root/crypto/krb5/src/tests/gss-threads/gss-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/krb5/src/tests/gss-threads/gss-client.c')
-rw-r--r--crypto/krb5/src/tests/gss-threads/gss-client.c865
1 files changed, 0 insertions, 865 deletions
diff --git a/crypto/krb5/src/tests/gss-threads/gss-client.c b/crypto/krb5/src/tests/gss-threads/gss-client.c
deleted file mode 100644
index 8c006c291561..000000000000
--- a/crypto/krb5/src/tests/gss-threads/gss-client.c
+++ /dev/null
@@ -1,865 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright 1994 by OpenVision Technologies, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appears in all copies and
- * that both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of OpenVision not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. OpenVision makes no
- * representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied warranty.
- *
- * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * Copyright (C) 2003, 2004, 2008 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "k5-platform.h"
-#ifdef _WIN32
-#include <windows.h>
-#include <winsock.h>
-#else
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <pthread.h>
-#endif
-
-#include <gssapi/gssapi_generic.h>
-#include "gss-misc.h"
-#include "port-sockets.h"
-#include "fake-addrinfo.h"
-
-static int verbose = 1;
-
-static void
-usage(void)
-{
- fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
- fprintf(stderr, " [-seq] [-noreplay] [-nomutual]");
- fprintf(stderr, " [-threads num]");
- fprintf(stderr, "\n");
- fprintf(stderr, " [-f] [-q] [-ccount count] [-mcount count]\n");
- fprintf(stderr, " [-v1] [-na] [-nw] [-nx] [-nm] host service msg\n");
- exit(1);
-}
-
-/*
- * Function: get_server_info
- *
- * Purpose: Sets up a socket address for the named host and port.
- *
- * Arguments:
- *
- * host (r) the target host name
- * port (r) the target port, in host byte order
- *
- * Returns: 0 on success, or -1 on failure
- *
- * Effects:
- *
- * The host name is resolved with gethostbyname(), and "saddr" is set
- * to the desired socket address. If an error occurs, an error
- * message is displayed and -1 is returned.
- */
-struct sockaddr_in saddr;
-static int
-get_server_info(char *host, u_short port)
-{
- struct hostent *hp;
-
- hp = gethostbyname(host);
- if (hp == NULL) {
- fprintf(stderr, "Unknown host: %s\n", host);
- return -1;
- }
-
- saddr.sin_family = hp->h_addrtype;
- memcpy(&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr));
- saddr.sin_port = htons(port);
- return 0;
-}
-
-/*
- * Function: connect_to_server
- *
- * Purpose: Opens a TCP connection to the name host and port.
- *
- * Arguments:
- *
- * host (r) the target host name
- * port (r) the target port, in host byte order
- *
- * Returns: the established socket file descriptor, or -1 on failure
- *
- * Effects:
- *
- * The host name is resolved with gethostbyname(), and the socket is
- * opened and connected. If an error occurs, an error message is
- * displayed and -1 is returned.
- */
-static int
-connect_to_server(void)
-{
- int s;
-
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0) {
- perror("creating socket");
- return -1;
- }
- if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
- perror("connecting to server");
- (void)closesocket(s);
- return -1;
- }
- return s;
-}
-
-/*
- * Function: client_establish_context
- *
- * Purpose: establishes a GSS-API context with a specified service and
- * returns the context handle
- *
- * Arguments:
- *
- * s (r) an established TCP connection to the service
- * service_name (r) the ASCII service name of the service
- * gss_flags (r) GSS-API delegation flag (if any)
- * auth_flag (r) whether to actually do authentication
- * v1_format (r) whether the v1 sample protocol should be used
- * oid (r) OID of the mechanism to use
- * context (w) the established GSS-API context
- * ret_flags (w) the returned flags from init_sec_context
- *
- * Returns: 0 on success, -1 on failure
- *
- * Effects:
- *
- * service_name is imported as a GSS-API name and a GSS-API context is
- * established with the corresponding service; the service should be
- * listening on the TCP connection s. The default GSS-API mechanism
- * is used, and mutual authentication and replay detection are
- * requested.
- *
- * If successful, the context handle is returned in context. If
- * unsuccessful, the GSS-API error messages are displayed on stderr
- * and -1 is returned.
- */
-static int
-client_establish_context(int s, char *service_name, OM_uint32 gss_flags,
- int auth_flag, int v1_format, gss_OID oid,
- gss_ctx_id_t *gss_context, OM_uint32 *ret_flags)
-{
- if (auth_flag) {
- gss_buffer_desc send_tok, recv_tok, *token_ptr;
- gss_name_t target_name;
- OM_uint32 maj_stat, min_stat, init_sec_min_stat;
- int token_flags;
-
- /*
- * Import the name into target_name. Use send_tok to save
- * local variable space.
- */
- send_tok.value = service_name;
- send_tok.length = strlen(service_name);
- maj_stat = gss_import_name(&min_stat, &send_tok,
- (gss_OID)gss_nt_service_name, &target_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("parsing name", maj_stat, min_stat);
- return -1;
- }
-
- if (!v1_format) {
- if (send_token(s, TOKEN_NOOP | TOKEN_CONTEXT_NEXT,
- empty_token) < 0) {
- (void)gss_release_name(&min_stat, &target_name);
- return -1;
- }
- }
-
- /*
- * Perform the context-establishement loop.
- *
- * On each pass through the loop, token_ptr points to the token
- * to send to the server (or GSS_C_NO_BUFFER on the first pass).
- * Every generated token is stored in send_tok which is then
- * transmitted to the server; every received token is stored in
- * recv_tok, which token_ptr is then set to, to be processed by
- * the next call to gss_init_sec_context.
- *
- * GSS-API guarantees that send_tok's length will be non-zero
- * if and only if the server is expecting another token from us,
- * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
- * and only if the server has another token to send us.
- */
-
- token_ptr = GSS_C_NO_BUFFER;
- *gss_context = GSS_C_NO_CONTEXT;
-
- do {
- maj_stat = gss_init_sec_context(&init_sec_min_stat,
- GSS_C_NO_CREDENTIAL, gss_context,
- target_name, oid, gss_flags, 0,
- NULL, token_ptr, NULL, &send_tok,
- ret_flags, NULL);
-
- if (token_ptr != GSS_C_NO_BUFFER)
- free(recv_tok.value);
-
- if (send_tok.length != 0) {
- if (verbose) {
- printf("Sending init_sec_context token (size=%d)...",
- (int)send_tok.length);
- }
- if (send_token(s, v1_format ? 0 : TOKEN_CONTEXT,
- &send_tok) < 0) {
- (void)gss_release_buffer(&min_stat, &send_tok);
- (void)gss_release_name(&min_stat, &target_name);
- if (*gss_context != GSS_C_NO_CONTEXT) {
- gss_delete_sec_context(&min_stat, gss_context,
- GSS_C_NO_BUFFER);
- *gss_context = GSS_C_NO_CONTEXT;
- }
- return -1;
- }
- }
- (void)gss_release_buffer(&min_stat, &send_tok);
-
- if (maj_stat != GSS_S_COMPLETE &&
- maj_stat != GSS_S_CONTINUE_NEEDED) {
- display_status("initializing context", maj_stat,
- init_sec_min_stat);
- (void)gss_release_name(&min_stat, &target_name);
- if (*gss_context != GSS_C_NO_CONTEXT) {
- gss_delete_sec_context(&min_stat, gss_context,
- GSS_C_NO_BUFFER);
- }
- return -1;
- }
-
- if (maj_stat == GSS_S_CONTINUE_NEEDED) {
- if (verbose)
- printf("continue needed...");
- if (recv_token(s, &token_flags, &recv_tok) < 0) {
- (void)gss_release_name(&min_stat, &target_name);
- return -1;
- }
- token_ptr = &recv_tok;
- }
- if (verbose)
- printf("\n");
- } while (maj_stat == GSS_S_CONTINUE_NEEDED);
-
- (void)gss_release_name(&min_stat, &target_name);
- } else if (send_token(s, TOKEN_NOOP, empty_token) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-static void
-read_file(char *file_name, gss_buffer_t in_buf)
-{
- int fd, count;
- struct stat stat_buf;
-
- fd = open(file_name, O_RDONLY, 0);
- if (fd < 0) {
- perror("open");
- fprintf(stderr, "Couldn't open file %s\n", file_name);
- exit(2);
- }
- if (fstat(fd, &stat_buf) < 0) {
- perror("fstat");
- exit(3);
- }
- in_buf->length = stat_buf.st_size;
-
- if (in_buf->length == 0) {
- in_buf->value = NULL;
- return;
- }
-
- in_buf->value = malloc(in_buf->length);
- if (in_buf->value == NULL) {
- fprintf(stderr, "Couldn't allocate %d byte buffer for reading file\n",
- (int)in_buf->length);
- exit(4);
- }
-
- /* This code used to check for incomplete reads, but you can't get
- * an incomplete read on any file for which fstat() is meaningful. */
-
- count = read(fd, in_buf->value, in_buf->length);
- if (count < 0) {
- perror("read");
- exit(5);
- }
- if ((size_t)count < in_buf->length) {
- fprintf(stderr, "Warning, only read in %d bytes, expected %d\n",
- count, (int)in_buf->length);
- }
-}
-
-/*
- * Function: call_server
- *
- * Purpose: Call the "sign" service.
- *
- * Arguments:
- *
- * host (r) the host providing the service
- * port (r) the port to connect to on host
- * service_name (r) the GSS-API service name to authenticate to
- * gss_flags (r) GSS-API delegation flag (if any)
- * auth_flag (r) whether to do authentication
- * wrap_flag (r) whether to do message wrapping at all
- * encrypt_flag (r) whether to do encryption while wrapping
- * mic_flag (r) whether to request a MIC from the server
- * msg (r) the message to have "signed"
- * use_file (r) whether to treat msg as an input file name
- * mcount (r) the number of times to send the message
- *
- * Returns: 0 on success, -1 on failure
- *
- * Effects:
- *
- * call_server opens a TCP connection to <host:port> and establishes a
- * GSS-API context with service_name over the connection. It then
- * seals msg in a GSS-API token with gss_wrap, sends it to the server,
- * reads back a GSS-API signature block for msg from the server, and
- * verifies it with gss_verify. -1 is returned if any step fails,
- * otherwise 0 is returned.
- */
-static int
-call_server(char *host, u_short port, gss_OID oid, char *service_name,
- OM_uint32 gss_flags, int auth_flag, int wrap_flag,
- int encrypt_flag, int mic_flag, int v1_format, char *msg,
- int use_file, size_t mcount)
-{
- gss_ctx_id_t context;
- gss_buffer_desc in_buf, out_buf, sname, tname, oid_name;
- int s, state, is_local, is_open, flags, token_flags;
- OM_uint32 ret_flags, maj_stat, min_stat, lifetime, context_flags;
- gss_name_t src_name, targ_name;
- gss_OID mechanism, name_type;
- gss_qop_t qop_state;
- gss_OID_set mech_names;
- size_t i;
-
- /* Open connection. */
- s = connect_to_server();
- if (s < 0)
- return -1;
-
- /* Establish context. */
- if (client_establish_context(s, service_name, gss_flags, auth_flag,
- v1_format, oid, &context, &ret_flags) < 0) {
- (void)closesocket(s);
- return -1;
- }
-
- if (auth_flag && verbose) {
- /* Display the flags. */
- display_ctx_flags(ret_flags);
-
- /* Get context information. */
- maj_stat = gss_inquire_context(&min_stat, context, &src_name,
- &targ_name, &lifetime, &mechanism,
- &context_flags, &is_local, &is_open);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("inquiring context", maj_stat, min_stat);
- return -1;
- }
-
- maj_stat = gss_display_name(&min_stat, src_name, &sname, &name_type);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("displaying source name", maj_stat, min_stat);
- return -1;
- }
- maj_stat = gss_display_name(&min_stat, targ_name, &tname, NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("displaying target name", maj_stat, min_stat);
- return -1;
- }
- printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
- (int)sname.length, (char *)sname.value,
- (int)tname.length, (char *)tname.value, lifetime, context_flags,
- is_local ? "locally initiated" : "remotely initiated",
- is_open ? "open" : "closed");
-
- (void)gss_release_name(&min_stat, &src_name);
- (void)gss_release_name(&min_stat, &targ_name);
- (void)gss_release_buffer(&min_stat, &sname);
- (void)gss_release_buffer(&min_stat, &tname);
-
- maj_stat = gss_oid_to_str(&min_stat, name_type, &oid_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
- }
- printf("Name type of source name is %.*s.\n", (int)oid_name.length,
- (char *)oid_name.value);
- (void)gss_release_buffer(&min_stat, &oid_name);
-
- /* Now get the names supported by the mechanism. */
- maj_stat = gss_inquire_names_for_mech(&min_stat, mechanism,
- &mech_names);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("inquiring mech names", maj_stat, min_stat);
- return -1;
- }
-
- maj_stat = gss_oid_to_str(&min_stat, mechanism, &oid_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
- }
- printf("Mechanism %.*s supports %d names\n", (int)oid_name.length,
- (char *)oid_name.value, (int)mech_names->count);
- (void)gss_release_buffer(&min_stat, &oid_name);
-
- for (i = 0; i < mech_names->count; i++) {
- maj_stat = gss_oid_to_str(&min_stat, &mech_names->elements[i],
- &oid_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
- }
- printf(" %d: %.*s\n", (int)i, (int)oid_name.length,
- (char *)oid_name.value);
-
- (void)gss_release_buffer(&min_stat, &oid_name);
- }
- (void)gss_release_oid_set(&min_stat, &mech_names);
- }
-
- if (use_file) {
- read_file(msg, &in_buf);
- } else {
- /* Seal the message. */
- in_buf.value = msg;
- in_buf.length = strlen(msg);
- }
-
- for (i = 0; i < mcount; i++) {
- if (wrap_flag) {
- maj_stat = gss_wrap(&min_stat, context, encrypt_flag,
- GSS_C_QOP_DEFAULT, &in_buf, &state, &out_buf);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("wrapping message", maj_stat, min_stat);
- (void)closesocket(s);
- (void)gss_delete_sec_context(&min_stat, &context,
- GSS_C_NO_BUFFER);
- return -1;
- } else if (encrypt_flag && !state) {
- fprintf(stderr, "Warning! Message not encrypted.\n");
- }
- } else {
- out_buf = in_buf;
- }
-
- /* Send to server. */
- flags = 0;
- if (!v1_format) {
- flags = TOKEN_DATA | (wrap_flag ? TOKEN_WRAPPED : 0) |
- (encrypt_flag ? TOKEN_ENCRYPTED : 0) |
- (mic_flag ? TOKEN_SEND_MIC : 0);
- }
- if (send_token(s, flags, &out_buf) < 0) {
- (void)closesocket(s);
- (void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- }
- if (out_buf.value != in_buf.value)
- (void)gss_release_buffer(&min_stat, &out_buf);
-
- /* Read signature block into out_buf. */
- if (recv_token(s, &token_flags, &out_buf) < 0) {
- (void)closesocket(s);
- (void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- }
-
- if (mic_flag) {
- /* Verify signature block. */
- maj_stat = gss_verify_mic(&min_stat, context, &in_buf, &out_buf,
- &qop_state);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("verifying signature", maj_stat, min_stat);
- (void)closesocket(s);
- (void)gss_delete_sec_context(&min_stat, &context,
- GSS_C_NO_BUFFER);
- return -1;
- }
-
- if (verbose)
- printf("Signature verified.\n");
- } else if (verbose) {
- printf("Response received.\n");
- }
-
- free(out_buf.value);
- }
-
- if (use_file)
- free(in_buf.value);
-
- /* Send NOOP. */
- if (!v1_format)
- (void)send_token(s, TOKEN_NOOP, empty_token);
-
- if (auth_flag) {
- /* Delete context. */
- maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("deleting context", maj_stat, min_stat);
- (void)closesocket(s);
- (void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- }
-
- (void)gss_release_buffer(&min_stat, &out_buf);
- }
-
- (void)closesocket(s);
- return 0;
-}
-
-static void
-parse_oid(char *mechanism, gss_OID *oid)
-{
- char *mechstr = 0, *cp;
- gss_buffer_desc tok;
- OM_uint32 maj_stat, min_stat;
-
- if (isdigit((unsigned char)mechanism[0])) {
- if (asprintf(&mechstr, "{ %s }", mechanism) < 0) {
- fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
- return;
- }
- for (cp = mechstr; *cp; cp++) {
- if (*cp == '.')
- *cp = ' ';
- }
- tok.value = mechstr;
- } else {
- tok.value = mechanism;
- }
- tok.length = strlen(tok.value);
- maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("str_to_oid", maj_stat, min_stat);
- return;
- }
- if (mechstr)
- free(mechstr);
-}
-
-static int max_threads = 1;
-
-#ifdef _WIN32
-static thread_count = 0;
-static HANDLE hMutex = NULL;
-static HANDLE hEvent = NULL;
-
-void
-init_handles(void)
-{
- hMutex = CreateMutex(NULL, FALSE, NULL);
- hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-}
-
-void
-cleanup_handles(void)
-{
- CloseHandle(hMutex);
- CloseHandle(hEvent);
-}
-
-BOOL
-wait_and_increment_thread_counter(void)
-{
- for (;;) {
- if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
- if (thread_count < max_threads) {
- thread_count++;
- ReleaseMutex(hMutex);
- return TRUE;
- } else {
- ReleaseMutex(hMutex);
-
- if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
- continue;
- else
- return FALSE;
- }
- } else {
- return FALSE;
- }
- }
-}
-
-BOOL
-decrement_and_signal_thread_counter(void)
-{
- if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
- if (thread_count == max_threads)
- SetEvent(hEvent);
- thread_count--;
- ReleaseMutex(hMutex);
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-#else /* assume pthread */
-
-static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t counter_cond = PTHREAD_COND_INITIALIZER;
-int counter = 0;
-
-static int
-wait_and_increment_thread_counter(void)
-{
- int err;
-
- err = pthread_mutex_lock(&counter_mutex);
- if (err) {
- perror("pthread_mutex_lock");
- return 0;
- }
- if (counter == max_threads) {
- err = pthread_cond_wait(&counter_cond, &counter_mutex);
- if (err) {
- pthread_mutex_unlock(&counter_mutex);
- perror("pthread_cond_wait");
- return 0;
- }
- }
- counter++;
- pthread_mutex_unlock(&counter_mutex);
- return 1;
-}
-
-static void
-decrement_and_signal_thread_counter(void)
-{
- int err;
-
- sleep(1);
- err = pthread_mutex_lock(&counter_mutex);
- if (err) {
- perror("pthread_mutex_lock");
- return;
- }
- if (counter == max_threads)
- pthread_cond_broadcast(&counter_cond);
- counter--;
- pthread_mutex_unlock(&counter_mutex);
-}
-
-#endif
-
-static char *service_name, *server_host, *msg;
-static char *mechanism = 0;
-static u_short port = 4444;
-static int use_file = 0;
-static OM_uint32 gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
-static OM_uint32 min_stat;
-static gss_OID oid = GSS_C_NULL_OID;
-static int mcount = 1, ccount = 1;
-static int auth_flag, wrap_flag, encrypt_flag, mic_flag, v1_format;
-
-static void *
-worker_bee(void *unused)
-{
- printf("worker bee!\n");
- if (call_server(server_host, port, oid, service_name,
- gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
- v1_format, msg, use_file, mcount) < 0) {
- if (max_threads == 1)
- exit(6);
- }
-
- if (max_threads > 1)
- decrement_and_signal_thread_counter();
- free(unused);
- return NULL;
-}
-
-int
-main(int argc, char **argv)
-{
- int i;
-
- display_file = stdout;
- auth_flag = wrap_flag = encrypt_flag = mic_flag = 1;
- v1_format = 0;
-
- /* Parse arguments. */
- argc--;
- argv++;
- while (argc) {
- if (strcmp(*argv, "-port") == 0) {
- argc--;
- argv++;
- if (!argc)
- usage();
- port = atoi(*argv);
- } else if (strcmp(*argv, "-mech") == 0) {
- argc--;
- argv++;
- if (!argc)
- usage();
- mechanism = *argv;
- } else if (strcmp(*argv, "-threads") == 0) {
- argc--;
- argv++;
- if (!argc)
- usage();
- max_threads = atoi(*argv);
- } else if (strcmp(*argv, "-d") == 0) {
- gss_flags |= GSS_C_DELEG_FLAG;
- } else if (strcmp(*argv, "-seq") == 0) {
- gss_flags |= GSS_C_SEQUENCE_FLAG;
- } else if (strcmp(*argv, "-noreplay") == 0) {
- gss_flags &= ~GSS_C_REPLAY_FLAG;
- } else if (strcmp(*argv, "-nomutual") == 0) {
- gss_flags &= ~GSS_C_MUTUAL_FLAG;
- } else if (strcmp(*argv, "-f") == 0) {
- use_file = 1;
- } else if (strcmp(*argv, "-q") == 0) {
- verbose = 0;
- } else if (strcmp(*argv, "-ccount") == 0) {
- argc--;
- argv++;
- if (!argc)
- usage();
- ccount = atoi(*argv);
- if (ccount <= 0)
- usage();
- } else if (strcmp(*argv, "-mcount") == 0) {
- argc--;
- argv++;
- if (!argc)
- usage();
- mcount = atoi(*argv);
- if (mcount < 0)
- usage();
- } else if (strcmp(*argv, "-na") == 0) {
- auth_flag = wrap_flag = encrypt_flag = mic_flag = 0;
- } else if (strcmp(*argv, "-nw") == 0) {
- wrap_flag = 0;
- } else if (strcmp(*argv, "-nx") == 0) {
- encrypt_flag = 0;
- } else if (strcmp(*argv, "-nm") == 0) {
- mic_flag = 0;
- } else if (strcmp(*argv, "-v1") == 0) {
- v1_format = 1;
- } else {
- break;
- }
- argc--;
- argv++;
- }
- if (argc != 3)
- usage();
-
-#ifdef _WIN32
- if (max_threads < 1) {
- fprintf(stderr, "warning: there must be at least one thread\n");
- max_threads = 1;
- }
-
- init_handles();
- SetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", "1");
-#endif
-
- server_host = *argv++;
- service_name = *argv++;
- msg = *argv++;
-
- if (mechanism)
- parse_oid(mechanism, &oid);
-
- if (get_server_info(server_host, port) < 0)
- exit(1);
-
- if (max_threads == 1) {
- for (i = 0; i < ccount; i++)
- worker_bee(0);
- } else {
- for (i = 0; i < ccount; i++) {
- if (wait_and_increment_thread_counter()) {
-#ifdef _WIN32
- uintptr_t handle = _beginthread(worker_bee, 0, (void *)NULL);
- if (handle == (uintptr_t)-1)
- exit(7);
-#else
- int err;
- pthread_t thr;
- err = pthread_create(&thr, 0, worker_bee, malloc(12));
- if (err) {
- perror("pthread_create");
- exit(7);
- }
- (void)pthread_detach(thr);
-#endif
- } else {
- exit(8);
- }
- }
- }
-
- if (oid != GSS_C_NULL_OID)
- (void)gss_release_oid(&min_stat, &oid);
-
-#ifdef _WIN32
- cleanup_handles();
-#else
- if (max_threads > 1)
- sleep(10);
-#endif
-
- return 0;
-}