Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/tests/gss-threads/gss-client.c
34914 views
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) 2003, 2004, 2008 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 "k5-platform.h"
48
#ifdef _WIN32
49
#include <windows.h>
50
#include <winsock.h>
51
#else
52
#include <unistd.h>
53
#include <ctype.h>
54
#include <sys/types.h>
55
#include <sys/socket.h>
56
#include <netinet/in.h>
57
#include <netdb.h>
58
#include <sys/stat.h>
59
#include <fcntl.h>
60
#include <pthread.h>
61
#endif
62
63
#include <gssapi/gssapi_generic.h>
64
#include "gss-misc.h"
65
#include "port-sockets.h"
66
#include "fake-addrinfo.h"
67
68
static int verbose = 1;
69
70
static void
71
usage(void)
72
{
73
fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
74
fprintf(stderr, " [-seq] [-noreplay] [-nomutual]");
75
fprintf(stderr, " [-threads num]");
76
fprintf(stderr, "\n");
77
fprintf(stderr, " [-f] [-q] [-ccount count] [-mcount count]\n");
78
fprintf(stderr, " [-v1] [-na] [-nw] [-nx] [-nm] host service msg\n");
79
exit(1);
80
}
81
82
/*
83
* Function: get_server_info
84
*
85
* Purpose: Sets up a socket address for the named host and port.
86
*
87
* Arguments:
88
*
89
* host (r) the target host name
90
* port (r) the target port, in host byte order
91
*
92
* Returns: 0 on success, or -1 on failure
93
*
94
* Effects:
95
*
96
* The host name is resolved with gethostbyname(), and "saddr" is set
97
* to the desired socket address. If an error occurs, an error
98
* message is displayed and -1 is returned.
99
*/
100
struct sockaddr_in saddr;
101
static int
102
get_server_info(char *host, u_short port)
103
{
104
struct hostent *hp;
105
106
hp = gethostbyname(host);
107
if (hp == NULL) {
108
fprintf(stderr, "Unknown host: %s\n", host);
109
return -1;
110
}
111
112
saddr.sin_family = hp->h_addrtype;
113
memcpy(&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr));
114
saddr.sin_port = htons(port);
115
return 0;
116
}
117
118
/*
119
* Function: connect_to_server
120
*
121
* Purpose: Opens a TCP connection to the name host and port.
122
*
123
* Arguments:
124
*
125
* host (r) the target host name
126
* port (r) the target port, in host byte order
127
*
128
* Returns: the established socket file descriptor, or -1 on failure
129
*
130
* Effects:
131
*
132
* The host name is resolved with gethostbyname(), and the socket is
133
* opened and connected. If an error occurs, an error message is
134
* displayed and -1 is returned.
135
*/
136
static int
137
connect_to_server(void)
138
{
139
int s;
140
141
s = socket(AF_INET, SOCK_STREAM, 0);
142
if (s < 0) {
143
perror("creating socket");
144
return -1;
145
}
146
if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
147
perror("connecting to server");
148
(void)closesocket(s);
149
return -1;
150
}
151
return s;
152
}
153
154
/*
155
* Function: client_establish_context
156
*
157
* Purpose: establishes a GSS-API context with a specified service and
158
* returns the context handle
159
*
160
* Arguments:
161
*
162
* s (r) an established TCP connection to the service
163
* service_name (r) the ASCII service name of the service
164
* gss_flags (r) GSS-API delegation flag (if any)
165
* auth_flag (r) whether to actually do authentication
166
* v1_format (r) whether the v1 sample protocol should be used
167
* oid (r) OID of the mechanism to use
168
* context (w) the established GSS-API context
169
* ret_flags (w) the returned flags from init_sec_context
170
*
171
* Returns: 0 on success, -1 on failure
172
*
173
* Effects:
174
*
175
* service_name is imported as a GSS-API name and a GSS-API context is
176
* established with the corresponding service; the service should be
177
* listening on the TCP connection s. The default GSS-API mechanism
178
* is used, and mutual authentication and replay detection are
179
* requested.
180
*
181
* If successful, the context handle is returned in context. If
182
* unsuccessful, the GSS-API error messages are displayed on stderr
183
* and -1 is returned.
184
*/
185
static int
186
client_establish_context(int s, char *service_name, OM_uint32 gss_flags,
187
int auth_flag, int v1_format, gss_OID oid,
188
gss_ctx_id_t *gss_context, OM_uint32 *ret_flags)
189
{
190
if (auth_flag) {
191
gss_buffer_desc send_tok, recv_tok, *token_ptr;
192
gss_name_t target_name;
193
OM_uint32 maj_stat, min_stat, init_sec_min_stat;
194
int token_flags;
195
196
/*
197
* Import the name into target_name. Use send_tok to save
198
* local variable space.
199
*/
200
send_tok.value = service_name;
201
send_tok.length = strlen(service_name);
202
maj_stat = gss_import_name(&min_stat, &send_tok,
203
(gss_OID)gss_nt_service_name, &target_name);
204
if (maj_stat != GSS_S_COMPLETE) {
205
display_status("parsing name", maj_stat, min_stat);
206
return -1;
207
}
208
209
if (!v1_format) {
210
if (send_token(s, TOKEN_NOOP | TOKEN_CONTEXT_NEXT,
211
empty_token) < 0) {
212
(void)gss_release_name(&min_stat, &target_name);
213
return -1;
214
}
215
}
216
217
/*
218
* Perform the context-establishement loop.
219
*
220
* On each pass through the loop, token_ptr points to the token
221
* to send to the server (or GSS_C_NO_BUFFER on the first pass).
222
* Every generated token is stored in send_tok which is then
223
* transmitted to the server; every received token is stored in
224
* recv_tok, which token_ptr is then set to, to be processed by
225
* the next call to gss_init_sec_context.
226
*
227
* GSS-API guarantees that send_tok's length will be non-zero
228
* if and only if the server is expecting another token from us,
229
* and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
230
* and only if the server has another token to send us.
231
*/
232
233
token_ptr = GSS_C_NO_BUFFER;
234
*gss_context = GSS_C_NO_CONTEXT;
235
236
do {
237
maj_stat = gss_init_sec_context(&init_sec_min_stat,
238
GSS_C_NO_CREDENTIAL, gss_context,
239
target_name, oid, gss_flags, 0,
240
NULL, token_ptr, NULL, &send_tok,
241
ret_flags, NULL);
242
243
if (token_ptr != GSS_C_NO_BUFFER)
244
free(recv_tok.value);
245
246
if (send_tok.length != 0) {
247
if (verbose) {
248
printf("Sending init_sec_context token (size=%d)...",
249
(int)send_tok.length);
250
}
251
if (send_token(s, v1_format ? 0 : TOKEN_CONTEXT,
252
&send_tok) < 0) {
253
(void)gss_release_buffer(&min_stat, &send_tok);
254
(void)gss_release_name(&min_stat, &target_name);
255
if (*gss_context != GSS_C_NO_CONTEXT) {
256
gss_delete_sec_context(&min_stat, gss_context,
257
GSS_C_NO_BUFFER);
258
*gss_context = GSS_C_NO_CONTEXT;
259
}
260
return -1;
261
}
262
}
263
(void)gss_release_buffer(&min_stat, &send_tok);
264
265
if (maj_stat != GSS_S_COMPLETE &&
266
maj_stat != GSS_S_CONTINUE_NEEDED) {
267
display_status("initializing context", maj_stat,
268
init_sec_min_stat);
269
(void)gss_release_name(&min_stat, &target_name);
270
if (*gss_context != GSS_C_NO_CONTEXT) {
271
gss_delete_sec_context(&min_stat, gss_context,
272
GSS_C_NO_BUFFER);
273
}
274
return -1;
275
}
276
277
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
278
if (verbose)
279
printf("continue needed...");
280
if (recv_token(s, &token_flags, &recv_tok) < 0) {
281
(void)gss_release_name(&min_stat, &target_name);
282
return -1;
283
}
284
token_ptr = &recv_tok;
285
}
286
if (verbose)
287
printf("\n");
288
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
289
290
(void)gss_release_name(&min_stat, &target_name);
291
} else if (send_token(s, TOKEN_NOOP, empty_token) < 0) {
292
return -1;
293
}
294
295
return 0;
296
}
297
298
static void
299
read_file(char *file_name, gss_buffer_t in_buf)
300
{
301
int fd, count;
302
struct stat stat_buf;
303
304
fd = open(file_name, O_RDONLY, 0);
305
if (fd < 0) {
306
perror("open");
307
fprintf(stderr, "Couldn't open file %s\n", file_name);
308
exit(2);
309
}
310
if (fstat(fd, &stat_buf) < 0) {
311
perror("fstat");
312
exit(3);
313
}
314
in_buf->length = stat_buf.st_size;
315
316
if (in_buf->length == 0) {
317
in_buf->value = NULL;
318
return;
319
}
320
321
in_buf->value = malloc(in_buf->length);
322
if (in_buf->value == NULL) {
323
fprintf(stderr, "Couldn't allocate %d byte buffer for reading file\n",
324
(int)in_buf->length);
325
exit(4);
326
}
327
328
/* This code used to check for incomplete reads, but you can't get
329
* an incomplete read on any file for which fstat() is meaningful. */
330
331
count = read(fd, in_buf->value, in_buf->length);
332
if (count < 0) {
333
perror("read");
334
exit(5);
335
}
336
if ((size_t)count < in_buf->length) {
337
fprintf(stderr, "Warning, only read in %d bytes, expected %d\n",
338
count, (int)in_buf->length);
339
}
340
}
341
342
/*
343
* Function: call_server
344
*
345
* Purpose: Call the "sign" service.
346
*
347
* Arguments:
348
*
349
* host (r) the host providing the service
350
* port (r) the port to connect to on host
351
* service_name (r) the GSS-API service name to authenticate to
352
* gss_flags (r) GSS-API delegation flag (if any)
353
* auth_flag (r) whether to do authentication
354
* wrap_flag (r) whether to do message wrapping at all
355
* encrypt_flag (r) whether to do encryption while wrapping
356
* mic_flag (r) whether to request a MIC from the server
357
* msg (r) the message to have "signed"
358
* use_file (r) whether to treat msg as an input file name
359
* mcount (r) the number of times to send the message
360
*
361
* Returns: 0 on success, -1 on failure
362
*
363
* Effects:
364
*
365
* call_server opens a TCP connection to <host:port> and establishes a
366
* GSS-API context with service_name over the connection. It then
367
* seals msg in a GSS-API token with gss_wrap, sends it to the server,
368
* reads back a GSS-API signature block for msg from the server, and
369
* verifies it with gss_verify. -1 is returned if any step fails,
370
* otherwise 0 is returned.
371
*/
372
static int
373
call_server(char *host, u_short port, gss_OID oid, char *service_name,
374
OM_uint32 gss_flags, int auth_flag, int wrap_flag,
375
int encrypt_flag, int mic_flag, int v1_format, char *msg,
376
int use_file, size_t mcount)
377
{
378
gss_ctx_id_t context;
379
gss_buffer_desc in_buf, out_buf, sname, tname, oid_name;
380
int s, state, is_local, is_open, flags, token_flags;
381
OM_uint32 ret_flags, maj_stat, min_stat, lifetime, context_flags;
382
gss_name_t src_name, targ_name;
383
gss_OID mechanism, name_type;
384
gss_qop_t qop_state;
385
gss_OID_set mech_names;
386
size_t i;
387
388
/* Open connection. */
389
s = connect_to_server();
390
if (s < 0)
391
return -1;
392
393
/* Establish context. */
394
if (client_establish_context(s, service_name, gss_flags, auth_flag,
395
v1_format, oid, &context, &ret_flags) < 0) {
396
(void)closesocket(s);
397
return -1;
398
}
399
400
if (auth_flag && verbose) {
401
/* Display the flags. */
402
display_ctx_flags(ret_flags);
403
404
/* Get context information. */
405
maj_stat = gss_inquire_context(&min_stat, context, &src_name,
406
&targ_name, &lifetime, &mechanism,
407
&context_flags, &is_local, &is_open);
408
if (maj_stat != GSS_S_COMPLETE) {
409
display_status("inquiring context", maj_stat, min_stat);
410
return -1;
411
}
412
413
maj_stat = gss_display_name(&min_stat, src_name, &sname, &name_type);
414
if (maj_stat != GSS_S_COMPLETE) {
415
display_status("displaying source name", maj_stat, min_stat);
416
return -1;
417
}
418
maj_stat = gss_display_name(&min_stat, targ_name, &tname, NULL);
419
if (maj_stat != GSS_S_COMPLETE) {
420
display_status("displaying target name", maj_stat, min_stat);
421
return -1;
422
}
423
printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
424
(int)sname.length, (char *)sname.value,
425
(int)tname.length, (char *)tname.value, lifetime, context_flags,
426
is_local ? "locally initiated" : "remotely initiated",
427
is_open ? "open" : "closed");
428
429
(void)gss_release_name(&min_stat, &src_name);
430
(void)gss_release_name(&min_stat, &targ_name);
431
(void)gss_release_buffer(&min_stat, &sname);
432
(void)gss_release_buffer(&min_stat, &tname);
433
434
maj_stat = gss_oid_to_str(&min_stat, name_type, &oid_name);
435
if (maj_stat != GSS_S_COMPLETE) {
436
display_status("converting oid->string", maj_stat, min_stat);
437
return -1;
438
}
439
printf("Name type of source name is %.*s.\n", (int)oid_name.length,
440
(char *)oid_name.value);
441
(void)gss_release_buffer(&min_stat, &oid_name);
442
443
/* Now get the names supported by the mechanism. */
444
maj_stat = gss_inquire_names_for_mech(&min_stat, mechanism,
445
&mech_names);
446
if (maj_stat != GSS_S_COMPLETE) {
447
display_status("inquiring mech names", maj_stat, min_stat);
448
return -1;
449
}
450
451
maj_stat = gss_oid_to_str(&min_stat, mechanism, &oid_name);
452
if (maj_stat != GSS_S_COMPLETE) {
453
display_status("converting oid->string", maj_stat, min_stat);
454
return -1;
455
}
456
printf("Mechanism %.*s supports %d names\n", (int)oid_name.length,
457
(char *)oid_name.value, (int)mech_names->count);
458
(void)gss_release_buffer(&min_stat, &oid_name);
459
460
for (i = 0; i < mech_names->count; i++) {
461
maj_stat = gss_oid_to_str(&min_stat, &mech_names->elements[i],
462
&oid_name);
463
if (maj_stat != GSS_S_COMPLETE) {
464
display_status("converting oid->string", maj_stat, min_stat);
465
return -1;
466
}
467
printf(" %d: %.*s\n", (int)i, (int)oid_name.length,
468
(char *)oid_name.value);
469
470
(void)gss_release_buffer(&min_stat, &oid_name);
471
}
472
(void)gss_release_oid_set(&min_stat, &mech_names);
473
}
474
475
if (use_file) {
476
read_file(msg, &in_buf);
477
} else {
478
/* Seal the message. */
479
in_buf.value = msg;
480
in_buf.length = strlen(msg);
481
}
482
483
for (i = 0; i < mcount; i++) {
484
if (wrap_flag) {
485
maj_stat = gss_wrap(&min_stat, context, encrypt_flag,
486
GSS_C_QOP_DEFAULT, &in_buf, &state, &out_buf);
487
if (maj_stat != GSS_S_COMPLETE) {
488
display_status("wrapping message", maj_stat, min_stat);
489
(void)closesocket(s);
490
(void)gss_delete_sec_context(&min_stat, &context,
491
GSS_C_NO_BUFFER);
492
return -1;
493
} else if (encrypt_flag && !state) {
494
fprintf(stderr, "Warning! Message not encrypted.\n");
495
}
496
} else {
497
out_buf = in_buf;
498
}
499
500
/* Send to server. */
501
flags = 0;
502
if (!v1_format) {
503
flags = TOKEN_DATA | (wrap_flag ? TOKEN_WRAPPED : 0) |
504
(encrypt_flag ? TOKEN_ENCRYPTED : 0) |
505
(mic_flag ? TOKEN_SEND_MIC : 0);
506
}
507
if (send_token(s, flags, &out_buf) < 0) {
508
(void)closesocket(s);
509
(void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
510
return -1;
511
}
512
if (out_buf.value != in_buf.value)
513
(void)gss_release_buffer(&min_stat, &out_buf);
514
515
/* Read signature block into out_buf. */
516
if (recv_token(s, &token_flags, &out_buf) < 0) {
517
(void)closesocket(s);
518
(void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
519
return -1;
520
}
521
522
if (mic_flag) {
523
/* Verify signature block. */
524
maj_stat = gss_verify_mic(&min_stat, context, &in_buf, &out_buf,
525
&qop_state);
526
if (maj_stat != GSS_S_COMPLETE) {
527
display_status("verifying signature", maj_stat, min_stat);
528
(void)closesocket(s);
529
(void)gss_delete_sec_context(&min_stat, &context,
530
GSS_C_NO_BUFFER);
531
return -1;
532
}
533
534
if (verbose)
535
printf("Signature verified.\n");
536
} else if (verbose) {
537
printf("Response received.\n");
538
}
539
540
free(out_buf.value);
541
}
542
543
if (use_file)
544
free(in_buf.value);
545
546
/* Send NOOP. */
547
if (!v1_format)
548
(void)send_token(s, TOKEN_NOOP, empty_token);
549
550
if (auth_flag) {
551
/* Delete context. */
552
maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
553
if (maj_stat != GSS_S_COMPLETE) {
554
display_status("deleting context", maj_stat, min_stat);
555
(void)closesocket(s);
556
(void)gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
557
return -1;
558
}
559
560
(void)gss_release_buffer(&min_stat, &out_buf);
561
}
562
563
(void)closesocket(s);
564
return 0;
565
}
566
567
static void
568
parse_oid(char *mechanism, gss_OID *oid)
569
{
570
char *mechstr = 0, *cp;
571
gss_buffer_desc tok;
572
OM_uint32 maj_stat, min_stat;
573
574
if (isdigit((unsigned char)mechanism[0])) {
575
if (asprintf(&mechstr, "{ %s }", mechanism) < 0) {
576
fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
577
return;
578
}
579
for (cp = mechstr; *cp; cp++) {
580
if (*cp == '.')
581
*cp = ' ';
582
}
583
tok.value = mechstr;
584
} else {
585
tok.value = mechanism;
586
}
587
tok.length = strlen(tok.value);
588
maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
589
if (maj_stat != GSS_S_COMPLETE) {
590
display_status("str_to_oid", maj_stat, min_stat);
591
return;
592
}
593
if (mechstr)
594
free(mechstr);
595
}
596
597
static int max_threads = 1;
598
599
#ifdef _WIN32
600
static thread_count = 0;
601
static HANDLE hMutex = NULL;
602
static HANDLE hEvent = NULL;
603
604
void
605
init_handles(void)
606
{
607
hMutex = CreateMutex(NULL, FALSE, NULL);
608
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
609
}
610
611
void
612
cleanup_handles(void)
613
{
614
CloseHandle(hMutex);
615
CloseHandle(hEvent);
616
}
617
618
BOOL
619
wait_and_increment_thread_counter(void)
620
{
621
for (;;) {
622
if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
623
if (thread_count < max_threads) {
624
thread_count++;
625
ReleaseMutex(hMutex);
626
return TRUE;
627
} else {
628
ReleaseMutex(hMutex);
629
630
if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
631
continue;
632
else
633
return FALSE;
634
}
635
} else {
636
return FALSE;
637
}
638
}
639
}
640
641
BOOL
642
decrement_and_signal_thread_counter(void)
643
{
644
if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
645
if (thread_count == max_threads)
646
SetEvent(hEvent);
647
thread_count--;
648
ReleaseMutex(hMutex);
649
return TRUE;
650
} else {
651
return FALSE;
652
}
653
}
654
655
#else /* assume pthread */
656
657
static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
658
static pthread_cond_t counter_cond = PTHREAD_COND_INITIALIZER;
659
int counter = 0;
660
661
static int
662
wait_and_increment_thread_counter(void)
663
{
664
int err;
665
666
err = pthread_mutex_lock(&counter_mutex);
667
if (err) {
668
perror("pthread_mutex_lock");
669
return 0;
670
}
671
if (counter == max_threads) {
672
err = pthread_cond_wait(&counter_cond, &counter_mutex);
673
if (err) {
674
pthread_mutex_unlock(&counter_mutex);
675
perror("pthread_cond_wait");
676
return 0;
677
}
678
}
679
counter++;
680
pthread_mutex_unlock(&counter_mutex);
681
return 1;
682
}
683
684
static void
685
decrement_and_signal_thread_counter(void)
686
{
687
int err;
688
689
sleep(1);
690
err = pthread_mutex_lock(&counter_mutex);
691
if (err) {
692
perror("pthread_mutex_lock");
693
return;
694
}
695
if (counter == max_threads)
696
pthread_cond_broadcast(&counter_cond);
697
counter--;
698
pthread_mutex_unlock(&counter_mutex);
699
}
700
701
#endif
702
703
static char *service_name, *server_host, *msg;
704
static char *mechanism = 0;
705
static u_short port = 4444;
706
static int use_file = 0;
707
static OM_uint32 gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
708
static OM_uint32 min_stat;
709
static gss_OID oid = GSS_C_NULL_OID;
710
static int mcount = 1, ccount = 1;
711
static int auth_flag, wrap_flag, encrypt_flag, mic_flag, v1_format;
712
713
static void *
714
worker_bee(void *unused)
715
{
716
printf("worker bee!\n");
717
if (call_server(server_host, port, oid, service_name,
718
gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
719
v1_format, msg, use_file, mcount) < 0) {
720
if (max_threads == 1)
721
exit(6);
722
}
723
724
if (max_threads > 1)
725
decrement_and_signal_thread_counter();
726
free(unused);
727
return NULL;
728
}
729
730
int
731
main(int argc, char **argv)
732
{
733
int i;
734
735
display_file = stdout;
736
auth_flag = wrap_flag = encrypt_flag = mic_flag = 1;
737
v1_format = 0;
738
739
/* Parse arguments. */
740
argc--;
741
argv++;
742
while (argc) {
743
if (strcmp(*argv, "-port") == 0) {
744
argc--;
745
argv++;
746
if (!argc)
747
usage();
748
port = atoi(*argv);
749
} else if (strcmp(*argv, "-mech") == 0) {
750
argc--;
751
argv++;
752
if (!argc)
753
usage();
754
mechanism = *argv;
755
} else if (strcmp(*argv, "-threads") == 0) {
756
argc--;
757
argv++;
758
if (!argc)
759
usage();
760
max_threads = atoi(*argv);
761
} else if (strcmp(*argv, "-d") == 0) {
762
gss_flags |= GSS_C_DELEG_FLAG;
763
} else if (strcmp(*argv, "-seq") == 0) {
764
gss_flags |= GSS_C_SEQUENCE_FLAG;
765
} else if (strcmp(*argv, "-noreplay") == 0) {
766
gss_flags &= ~GSS_C_REPLAY_FLAG;
767
} else if (strcmp(*argv, "-nomutual") == 0) {
768
gss_flags &= ~GSS_C_MUTUAL_FLAG;
769
} else if (strcmp(*argv, "-f") == 0) {
770
use_file = 1;
771
} else if (strcmp(*argv, "-q") == 0) {
772
verbose = 0;
773
} else if (strcmp(*argv, "-ccount") == 0) {
774
argc--;
775
argv++;
776
if (!argc)
777
usage();
778
ccount = atoi(*argv);
779
if (ccount <= 0)
780
usage();
781
} else if (strcmp(*argv, "-mcount") == 0) {
782
argc--;
783
argv++;
784
if (!argc)
785
usage();
786
mcount = atoi(*argv);
787
if (mcount < 0)
788
usage();
789
} else if (strcmp(*argv, "-na") == 0) {
790
auth_flag = wrap_flag = encrypt_flag = mic_flag = 0;
791
} else if (strcmp(*argv, "-nw") == 0) {
792
wrap_flag = 0;
793
} else if (strcmp(*argv, "-nx") == 0) {
794
encrypt_flag = 0;
795
} else if (strcmp(*argv, "-nm") == 0) {
796
mic_flag = 0;
797
} else if (strcmp(*argv, "-v1") == 0) {
798
v1_format = 1;
799
} else {
800
break;
801
}
802
argc--;
803
argv++;
804
}
805
if (argc != 3)
806
usage();
807
808
#ifdef _WIN32
809
if (max_threads < 1) {
810
fprintf(stderr, "warning: there must be at least one thread\n");
811
max_threads = 1;
812
}
813
814
init_handles();
815
SetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", "1");
816
#endif
817
818
server_host = *argv++;
819
service_name = *argv++;
820
msg = *argv++;
821
822
if (mechanism)
823
parse_oid(mechanism, &oid);
824
825
if (get_server_info(server_host, port) < 0)
826
exit(1);
827
828
if (max_threads == 1) {
829
for (i = 0; i < ccount; i++)
830
worker_bee(0);
831
} else {
832
for (i = 0; i < ccount; i++) {
833
if (wait_and_increment_thread_counter()) {
834
#ifdef _WIN32
835
uintptr_t handle = _beginthread(worker_bee, 0, (void *)NULL);
836
if (handle == (uintptr_t)-1)
837
exit(7);
838
#else
839
int err;
840
pthread_t thr;
841
err = pthread_create(&thr, 0, worker_bee, malloc(12));
842
if (err) {
843
perror("pthread_create");
844
exit(7);
845
}
846
(void)pthread_detach(thr);
847
#endif
848
} else {
849
exit(8);
850
}
851
}
852
}
853
854
if (oid != GSS_C_NULL_OID)
855
(void)gss_release_oid(&min_stat, &oid);
856
857
#ifdef _WIN32
858
cleanup_handles();
859
#else
860
if (max_threads > 1)
861
sleep(10);
862
#endif
863
864
return 0;
865
}
866
867