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