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