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