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