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