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