xref: /freebsd/crypto/heimdal/appl/test/http_client.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1c19800e8SDoug Rabson /*
2*ae771770SStanislav Sedov  * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34c19800e8SDoug Rabson #include "test_locl.h"
35*ae771770SStanislav Sedov #include <gssapi/gssapi.h>
36*ae771770SStanislav Sedov #include <gssapi/gssapi_krb5.h>
37*ae771770SStanislav Sedov #include <gssapi/gssapi_spnego.h>
38c19800e8SDoug Rabson #include "gss_common.h"
39c19800e8SDoug Rabson #include <base64.h>
40c19800e8SDoug Rabson 
41*ae771770SStanislav Sedov RCSID("$Id$");
42c19800e8SDoug Rabson 
43c19800e8SDoug Rabson /*
44c19800e8SDoug Rabson  * A simplistic client implementing draft-brezak-spnego-http-04.txt
45c19800e8SDoug Rabson  */
46c19800e8SDoug Rabson 
47c19800e8SDoug Rabson static int
do_connect(const char * hostname,const char * port)48c19800e8SDoug Rabson do_connect (const char *hostname, const char *port)
49c19800e8SDoug Rabson {
50c19800e8SDoug Rabson     struct addrinfo *ai, *a;
51c19800e8SDoug Rabson     struct addrinfo hints;
52c19800e8SDoug Rabson     int error;
53c19800e8SDoug Rabson     int s = -1;
54c19800e8SDoug Rabson 
55c19800e8SDoug Rabson     memset (&hints, 0, sizeof(hints));
56c19800e8SDoug Rabson     hints.ai_family = PF_UNSPEC;
57c19800e8SDoug Rabson     hints.ai_socktype = SOCK_STREAM;
58c19800e8SDoug Rabson     hints.ai_protocol = 0;
59c19800e8SDoug Rabson 
60c19800e8SDoug Rabson     error = getaddrinfo (hostname, port, &hints, &ai);
61c19800e8SDoug Rabson     if (error)
62c19800e8SDoug Rabson 	errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error));
63c19800e8SDoug Rabson 
64c19800e8SDoug Rabson     for (a = ai; a != NULL; a = a->ai_next) {
65c19800e8SDoug Rabson 	s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
66c19800e8SDoug Rabson 	if (s < 0)
67c19800e8SDoug Rabson 	    continue;
68c19800e8SDoug Rabson 	if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
69c19800e8SDoug Rabson 	    warn ("connect(%s)", hostname);
70c19800e8SDoug Rabson  	    close (s);
71c19800e8SDoug Rabson  	    continue;
72c19800e8SDoug Rabson 	}
73c19800e8SDoug Rabson 	break;
74c19800e8SDoug Rabson     }
75c19800e8SDoug Rabson     freeaddrinfo (ai);
76c19800e8SDoug Rabson     if (a == NULL)
77c19800e8SDoug Rabson 	errx (1, "failed to contact %s", hostname);
78c19800e8SDoug Rabson 
79c19800e8SDoug Rabson     return s;
80c19800e8SDoug Rabson }
81c19800e8SDoug Rabson 
82c19800e8SDoug Rabson static void
fdprintf(int s,const char * fmt,...)83c19800e8SDoug Rabson fdprintf(int s, const char *fmt, ...)
84c19800e8SDoug Rabson {
85c19800e8SDoug Rabson     size_t len;
86c19800e8SDoug Rabson     ssize_t ret;
87c19800e8SDoug Rabson     va_list ap;
88c19800e8SDoug Rabson     char *str, *buf;
89c19800e8SDoug Rabson 
90c19800e8SDoug Rabson     va_start(ap, fmt);
91c19800e8SDoug Rabson     vasprintf(&str, fmt, ap);
92c19800e8SDoug Rabson     va_end(ap);
93c19800e8SDoug Rabson 
94c19800e8SDoug Rabson     if (str == NULL)
95c19800e8SDoug Rabson 	errx(1, "vasprintf");
96c19800e8SDoug Rabson 
97c19800e8SDoug Rabson     buf = str;
98c19800e8SDoug Rabson     len = strlen(buf);
99c19800e8SDoug Rabson     while (len) {
100c19800e8SDoug Rabson 	ret = write(s, buf, len);
101c19800e8SDoug Rabson 	if (ret == 0)
102c19800e8SDoug Rabson 	    err(1, "connection closed");
103c19800e8SDoug Rabson 	else if (ret < 0)
104c19800e8SDoug Rabson 	    err(1, "error");
105c19800e8SDoug Rabson 	len -= ret;
106c19800e8SDoug Rabson 	buf += ret;
107c19800e8SDoug Rabson     }
108c19800e8SDoug Rabson     free(str);
109c19800e8SDoug Rabson }
110c19800e8SDoug Rabson 
111c19800e8SDoug Rabson static int help_flag;
112c19800e8SDoug Rabson static int version_flag;
113c19800e8SDoug Rabson static int verbose_flag;
114c19800e8SDoug Rabson static int mutual_flag = 1;
115c19800e8SDoug Rabson static int delegate_flag;
116c19800e8SDoug Rabson static char *port_str = "http";
117c19800e8SDoug Rabson static char *gss_service = "HTTP";
118c19800e8SDoug Rabson 
119c19800e8SDoug Rabson static struct getargs http_args[] = {
120c19800e8SDoug Rabson     { "verbose", 'v', arg_flag, &verbose_flag, "verbose logging", },
121c19800e8SDoug Rabson     { "port", 'p', arg_string, &port_str, "port to connect to", "port" },
122c19800e8SDoug Rabson     { "delegate", 0, arg_flag, &delegate_flag, "gssapi delegate credential" },
123c19800e8SDoug Rabson     { "gss-service", 's', arg_string, &gss_service, "gssapi service to use",
124c19800e8SDoug Rabson       "service" },
125c19800e8SDoug Rabson     { "mech", 'm', arg_string, &mech, "gssapi mech to use", "mech" },
126c19800e8SDoug Rabson     { "mutual", 0, arg_negative_flag, &mutual_flag, "no gssapi mutual auth" },
127c19800e8SDoug Rabson     { "help", 'h', arg_flag, &help_flag },
128c19800e8SDoug Rabson     { "version", 0, arg_flag, &version_flag }
129c19800e8SDoug Rabson };
130c19800e8SDoug Rabson 
131c19800e8SDoug Rabson static int num_http_args = sizeof(http_args) / sizeof(http_args[0]);
132c19800e8SDoug Rabson 
133c19800e8SDoug Rabson static void
usage(int code)134c19800e8SDoug Rabson usage(int code)
135c19800e8SDoug Rabson {
136c19800e8SDoug Rabson     arg_printusage(http_args, num_http_args, NULL, "host [page]");
137c19800e8SDoug Rabson     exit(code);
138c19800e8SDoug Rabson }
139c19800e8SDoug Rabson 
140c19800e8SDoug Rabson /*
141c19800e8SDoug Rabson  *
142c19800e8SDoug Rabson  */
143c19800e8SDoug Rabson 
144c19800e8SDoug Rabson struct http_req {
145c19800e8SDoug Rabson     char *response;
146c19800e8SDoug Rabson     char **headers;
147c19800e8SDoug Rabson     int num_headers;
148c19800e8SDoug Rabson     void *body;
149c19800e8SDoug Rabson     size_t body_size;
150c19800e8SDoug Rabson };
151c19800e8SDoug Rabson 
152c19800e8SDoug Rabson 
153c19800e8SDoug Rabson static void
http_req_zero(struct http_req * req)154c19800e8SDoug Rabson http_req_zero(struct http_req *req)
155c19800e8SDoug Rabson {
156c19800e8SDoug Rabson     req->response = NULL;
157c19800e8SDoug Rabson     req->headers = NULL;
158c19800e8SDoug Rabson     req->num_headers = 0;
159c19800e8SDoug Rabson     req->body = NULL;
160c19800e8SDoug Rabson     req->body_size = 0;
161c19800e8SDoug Rabson }
162c19800e8SDoug Rabson 
163c19800e8SDoug Rabson static void
http_req_free(struct http_req * req)164c19800e8SDoug Rabson http_req_free(struct http_req *req)
165c19800e8SDoug Rabson {
166c19800e8SDoug Rabson     int i;
167c19800e8SDoug Rabson 
168c19800e8SDoug Rabson     free(req->response);
169c19800e8SDoug Rabson     for (i = 0; i < req->num_headers; i++)
170c19800e8SDoug Rabson 	free(req->headers[i]);
171c19800e8SDoug Rabson     free(req->headers);
172c19800e8SDoug Rabson     free(req->body);
173c19800e8SDoug Rabson     http_req_zero(req);
174c19800e8SDoug Rabson }
175c19800e8SDoug Rabson 
176c19800e8SDoug Rabson static const char *
http_find_header(struct http_req * req,const char * header)177c19800e8SDoug Rabson http_find_header(struct http_req *req, const char *header)
178c19800e8SDoug Rabson {
179c19800e8SDoug Rabson     int i, len = strlen(header);
180c19800e8SDoug Rabson 
181c19800e8SDoug Rabson     for (i = 0; i < req->num_headers; i++) {
182c19800e8SDoug Rabson 	if (strncasecmp(header, req->headers[i], len) == 0) {
183c19800e8SDoug Rabson 	    return req->headers[i] + len + 1;
184c19800e8SDoug Rabson 	}
185c19800e8SDoug Rabson     }
186c19800e8SDoug Rabson     return NULL;
187c19800e8SDoug Rabson }
188c19800e8SDoug Rabson 
189c19800e8SDoug Rabson 
190c19800e8SDoug Rabson static int
http_query(const char * host,const char * page,char ** headers,int num_headers,struct http_req * req)191c19800e8SDoug Rabson http_query(const char *host, const char *page,
192c19800e8SDoug Rabson 	   char **headers, int num_headers, struct http_req *req)
193c19800e8SDoug Rabson {
194c19800e8SDoug Rabson     enum { RESPONSE, HEADER, BODY } state;
195c19800e8SDoug Rabson     ssize_t ret;
196c19800e8SDoug Rabson     char in_buf[1024], *in_ptr = in_buf;
197c19800e8SDoug Rabson     size_t in_len = 0;
198c19800e8SDoug Rabson     int s, i;
199c19800e8SDoug Rabson 
200c19800e8SDoug Rabson     http_req_zero(req);
201c19800e8SDoug Rabson 
202c19800e8SDoug Rabson     s = do_connect(host, port_str);
203c19800e8SDoug Rabson     if (s < 0)
204c19800e8SDoug Rabson 	errx(1, "connection failed");
205c19800e8SDoug Rabson 
206c19800e8SDoug Rabson     fdprintf(s, "GET %s HTTP/1.0\r\n", page);
207c19800e8SDoug Rabson     for (i = 0; i < num_headers; i++)
208c19800e8SDoug Rabson 	fdprintf(s, "%s\r\n", headers[i]);
209c19800e8SDoug Rabson     fdprintf(s, "Host: %s\r\n\r\n", host);
210c19800e8SDoug Rabson 
211c19800e8SDoug Rabson     state = RESPONSE;
212c19800e8SDoug Rabson 
213c19800e8SDoug Rabson     while (1) {
214c19800e8SDoug Rabson 	ret = read (s, in_ptr, sizeof(in_buf) - in_len - 1);
215c19800e8SDoug Rabson 	if (ret == 0)
216c19800e8SDoug Rabson 	    break;
217c19800e8SDoug Rabson 	else if (ret < 0)
218c19800e8SDoug Rabson 	    err (1, "read: %lu", (unsigned long)ret);
219c19800e8SDoug Rabson 
220c19800e8SDoug Rabson 	in_buf[ret + in_len] = '\0';
221c19800e8SDoug Rabson 
222c19800e8SDoug Rabson 	if (state == HEADER || state == RESPONSE) {
223c19800e8SDoug Rabson 	    char *p;
224c19800e8SDoug Rabson 
225c19800e8SDoug Rabson 	    in_len += ret;
226c19800e8SDoug Rabson 	    in_ptr += ret;
227c19800e8SDoug Rabson 
228c19800e8SDoug Rabson 	    while (1) {
229c19800e8SDoug Rabson 		p = strstr(in_buf, "\r\n");
230c19800e8SDoug Rabson 
231c19800e8SDoug Rabson 		if (p == NULL) {
232c19800e8SDoug Rabson 		    break;
233c19800e8SDoug Rabson 		} else if (p == in_buf) {
234c19800e8SDoug Rabson 		    memmove(in_buf, in_buf + 2, sizeof(in_buf) - 2);
235c19800e8SDoug Rabson 		    state = BODY;
236c19800e8SDoug Rabson 		    in_len -= 2;
237c19800e8SDoug Rabson 		    in_ptr -= 2;
238c19800e8SDoug Rabson 		    break;
239c19800e8SDoug Rabson 		} else if (state == RESPONSE) {
240*ae771770SStanislav Sedov 		    req->response = emalloc(p - in_buf + 1);
241*ae771770SStanislav Sedov 		    memcpy(req->response, in_buf, p - in_buf);
242*ae771770SStanislav Sedov 		    req->response[p - in_buf] = '\0';
243c19800e8SDoug Rabson 		    state = HEADER;
244c19800e8SDoug Rabson 		} else {
245c19800e8SDoug Rabson 		    req->headers = realloc(req->headers,
246c19800e8SDoug Rabson 					   (req->num_headers + 1) * sizeof(req->headers[0]));
247*ae771770SStanislav Sedov 		    req->headers[req->num_headers] = emalloc(p - in_buf + 1);
248*ae771770SStanislav Sedov 		    memcpy(req->headers[req->num_headers], in_buf, p - in_buf);
249*ae771770SStanislav Sedov 		    req->headers[req->num_headers][p - in_buf] = '\0';
250c19800e8SDoug Rabson 		    if (req->headers[req->num_headers] == NULL)
251c19800e8SDoug Rabson 			errx(1, "strdup");
252c19800e8SDoug Rabson 		    req->num_headers++;
253c19800e8SDoug Rabson 		}
254c19800e8SDoug Rabson 		memmove(in_buf, p + 2, sizeof(in_buf) - (p - in_buf) - 2);
255c19800e8SDoug Rabson 		in_len -= (p - in_buf) + 2;
256c19800e8SDoug Rabson 		in_ptr -= (p - in_buf) + 2;
257c19800e8SDoug Rabson 	    }
258c19800e8SDoug Rabson 	}
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson 	if (state == BODY) {
261c19800e8SDoug Rabson 
262c19800e8SDoug Rabson 	    req->body = erealloc(req->body, req->body_size + ret + 1);
263c19800e8SDoug Rabson 
264c19800e8SDoug Rabson 	    memcpy((char *)req->body + req->body_size, in_buf, ret);
265c19800e8SDoug Rabson 	    req->body_size += ret;
266c19800e8SDoug Rabson 	    ((char *)req->body)[req->body_size] = '\0';
267c19800e8SDoug Rabson 
268c19800e8SDoug Rabson 	    in_ptr = in_buf;
269c19800e8SDoug Rabson 	    in_len = 0;
270c19800e8SDoug Rabson 	} else
271c19800e8SDoug Rabson 	    abort();
272c19800e8SDoug Rabson     }
273c19800e8SDoug Rabson 
274c19800e8SDoug Rabson     if (verbose_flag) {
275c19800e8SDoug Rabson 	int i;
276c19800e8SDoug Rabson 	printf("response: %s\n", req->response);
277c19800e8SDoug Rabson 	for (i = 0; i < req->num_headers; i++)
278c19800e8SDoug Rabson 	    printf("header[%d] %s\n", i, req->headers[i]);
279c19800e8SDoug Rabson 	printf("body: %.*s\n", (int)req->body_size, (char *)req->body);
280c19800e8SDoug Rabson     }
281c19800e8SDoug Rabson 
282c19800e8SDoug Rabson     close(s);
283c19800e8SDoug Rabson     return 0;
284c19800e8SDoug Rabson }
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson 
287c19800e8SDoug Rabson int
main(int argc,char ** argv)288c19800e8SDoug Rabson main(int argc, char **argv)
289c19800e8SDoug Rabson {
290c19800e8SDoug Rabson     struct http_req req;
291c19800e8SDoug Rabson     const char *host, *page;
292c19800e8SDoug Rabson     int i, done, print_body, gssapi_done, gssapi_started;
293c19800e8SDoug Rabson     char *headers[10]; /* XXX */
294c19800e8SDoug Rabson     int num_headers;
295c19800e8SDoug Rabson     gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
296c19800e8SDoug Rabson     gss_name_t server = GSS_C_NO_NAME;
297c19800e8SDoug Rabson     int optind = 0;
298c19800e8SDoug Rabson     gss_OID mech_oid;
299c19800e8SDoug Rabson     OM_uint32 flags;
300c19800e8SDoug Rabson 
301c19800e8SDoug Rabson     setprogname(argv[0]);
302c19800e8SDoug Rabson 
303c19800e8SDoug Rabson     if(getarg(http_args, num_http_args, argc, argv, &optind))
304c19800e8SDoug Rabson 	usage(1);
305c19800e8SDoug Rabson 
306c19800e8SDoug Rabson     if (help_flag)
307c19800e8SDoug Rabson 	usage (0);
308c19800e8SDoug Rabson 
309c19800e8SDoug Rabson     if(version_flag) {
310c19800e8SDoug Rabson 	print_version(NULL);
311c19800e8SDoug Rabson 	exit(0);
312c19800e8SDoug Rabson     }
313c19800e8SDoug Rabson 
314c19800e8SDoug Rabson     argc -= optind;
315c19800e8SDoug Rabson     argv += optind;
316c19800e8SDoug Rabson 
317c19800e8SDoug Rabson     mech_oid = select_mech(mech);
318c19800e8SDoug Rabson 
319c19800e8SDoug Rabson     if (argc != 1 && argc != 2)
320c19800e8SDoug Rabson 	errx(1, "usage: %s host [page]", getprogname());
321c19800e8SDoug Rabson     host = argv[0];
322c19800e8SDoug Rabson     if (argc == 2)
323c19800e8SDoug Rabson 	page = argv[1];
324c19800e8SDoug Rabson     else
325c19800e8SDoug Rabson 	page = "/";
326c19800e8SDoug Rabson 
327c19800e8SDoug Rabson     flags = 0;
328c19800e8SDoug Rabson     if (delegate_flag)
329c19800e8SDoug Rabson 	flags |= GSS_C_DELEG_FLAG;
330c19800e8SDoug Rabson     if (mutual_flag)
331c19800e8SDoug Rabson 	flags |= GSS_C_MUTUAL_FLAG;
332c19800e8SDoug Rabson 
333c19800e8SDoug Rabson     done = 0;
334c19800e8SDoug Rabson     num_headers = 0;
335c19800e8SDoug Rabson     gssapi_done = 1;
336c19800e8SDoug Rabson     gssapi_started = 0;
337c19800e8SDoug Rabson     do {
338c19800e8SDoug Rabson 	print_body = 0;
339c19800e8SDoug Rabson 
340c19800e8SDoug Rabson 	http_query(host, page, headers, num_headers, &req);
341c19800e8SDoug Rabson 	for (i = 0 ; i < num_headers; i++)
342c19800e8SDoug Rabson 	    free(headers[i]);
343c19800e8SDoug Rabson 	num_headers = 0;
344c19800e8SDoug Rabson 
345c19800e8SDoug Rabson 	if (strstr(req.response, " 200 ") != NULL) {
346c19800e8SDoug Rabson 	    print_body = 1;
347c19800e8SDoug Rabson 	    done = 1;
348c19800e8SDoug Rabson 	} else if (strstr(req.response, " 401 ") != NULL) {
349c19800e8SDoug Rabson 	    if (http_find_header(&req, "WWW-Authenticate:") == NULL)
350c19800e8SDoug Rabson 		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
351c19800e8SDoug Rabson 	    gssapi_done = 0;
352c19800e8SDoug Rabson 	}
353c19800e8SDoug Rabson 
354c19800e8SDoug Rabson 	if (!gssapi_done) {
355c19800e8SDoug Rabson 	    const char *h = http_find_header(&req, "WWW-Authenticate:");
356c19800e8SDoug Rabson 	    if (h == NULL)
357c19800e8SDoug Rabson 		errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
358c19800e8SDoug Rabson 
359c19800e8SDoug Rabson 	    if (strncasecmp(h, "Negotiate", 9) == 0) {
360c19800e8SDoug Rabson 		OM_uint32 maj_stat, min_stat;
361c19800e8SDoug Rabson 		gss_buffer_desc input_token, output_token;
362c19800e8SDoug Rabson 
363c19800e8SDoug Rabson 		if (verbose_flag)
364c19800e8SDoug Rabson 		    printf("Negotiate found\n");
365c19800e8SDoug Rabson 
366c19800e8SDoug Rabson 		if (server == GSS_C_NO_NAME) {
367c19800e8SDoug Rabson 		    char *name;
368c19800e8SDoug Rabson 		    asprintf(&name, "%s@%s", gss_service, host);
369c19800e8SDoug Rabson 		    input_token.length = strlen(name);
370c19800e8SDoug Rabson 		    input_token.value = name;
371c19800e8SDoug Rabson 
372c19800e8SDoug Rabson 		    maj_stat = gss_import_name(&min_stat,
373c19800e8SDoug Rabson 					       &input_token,
374c19800e8SDoug Rabson 					       GSS_C_NT_HOSTBASED_SERVICE,
375c19800e8SDoug Rabson 					       &server);
376c19800e8SDoug Rabson 		    if (GSS_ERROR(maj_stat))
377c19800e8SDoug Rabson 			gss_err (1, min_stat, "gss_inport_name");
378c19800e8SDoug Rabson 		    free(name);
379c19800e8SDoug Rabson 		    input_token.length = 0;
380c19800e8SDoug Rabson 		    input_token.value = NULL;
381c19800e8SDoug Rabson 		}
382c19800e8SDoug Rabson 
383c19800e8SDoug Rabson 		i = 9;
384c19800e8SDoug Rabson 		while(h[i] && isspace((unsigned char)h[i]))
385c19800e8SDoug Rabson 		    i++;
386c19800e8SDoug Rabson 		if (h[i] != '\0') {
387c19800e8SDoug Rabson 		    int len = strlen(&h[i]);
388c19800e8SDoug Rabson 		    if (len == 0)
389c19800e8SDoug Rabson 			errx(1, "invalid Negotiate token");
390c19800e8SDoug Rabson 		    input_token.value = emalloc(len);
391c19800e8SDoug Rabson 		    len = base64_decode(&h[i], input_token.value);
392c19800e8SDoug Rabson 		    if (len < 0)
393c19800e8SDoug Rabson 			errx(1, "invalid base64 Negotiate token %s", &h[i]);
394c19800e8SDoug Rabson 		    input_token.length = len;
395c19800e8SDoug Rabson 		} else {
396c19800e8SDoug Rabson 		    if (gssapi_started)
397c19800e8SDoug Rabson 			errx(1, "Negotiate already started");
398c19800e8SDoug Rabson 		    gssapi_started = 1;
399c19800e8SDoug Rabson 
400c19800e8SDoug Rabson 		    input_token.length = 0;
401c19800e8SDoug Rabson 		    input_token.value = NULL;
402c19800e8SDoug Rabson 		}
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson 		maj_stat =
405c19800e8SDoug Rabson 		    gss_init_sec_context(&min_stat,
406c19800e8SDoug Rabson 					 GSS_C_NO_CREDENTIAL,
407c19800e8SDoug Rabson 					 &context_hdl,
408c19800e8SDoug Rabson 					 server,
409c19800e8SDoug Rabson 					 mech_oid,
410c19800e8SDoug Rabson 					 flags,
411c19800e8SDoug Rabson 					 0,
412c19800e8SDoug Rabson 					 GSS_C_NO_CHANNEL_BINDINGS,
413c19800e8SDoug Rabson 					 &input_token,
414c19800e8SDoug Rabson 					 NULL,
415c19800e8SDoug Rabson 					 &output_token,
416c19800e8SDoug Rabson 					 NULL,
417c19800e8SDoug Rabson 					 NULL);
418c19800e8SDoug Rabson 		if (GSS_ERROR(maj_stat))
419c19800e8SDoug Rabson 		    gss_err (1, min_stat, "gss_init_sec_context");
420c19800e8SDoug Rabson 		else if (maj_stat & GSS_S_CONTINUE_NEEDED)
421c19800e8SDoug Rabson 		    gssapi_done = 0;
422c19800e8SDoug Rabson 		else {
423c19800e8SDoug Rabson 		    gss_name_t targ_name, src_name;
424c19800e8SDoug Rabson 		    gss_buffer_desc name_buffer;
425c19800e8SDoug Rabson 		    gss_OID mech_type;
426c19800e8SDoug Rabson 
427c19800e8SDoug Rabson 		    gssapi_done = 1;
428c19800e8SDoug Rabson 
429c19800e8SDoug Rabson 		    printf("Negotiate done: %s\n", mech);
430c19800e8SDoug Rabson 
431c19800e8SDoug Rabson 		    maj_stat = gss_inquire_context(&min_stat,
432c19800e8SDoug Rabson 						   context_hdl,
433c19800e8SDoug Rabson 						   &src_name,
434c19800e8SDoug Rabson 						   &targ_name,
435c19800e8SDoug Rabson 						   NULL,
436c19800e8SDoug Rabson 						   &mech_type,
437c19800e8SDoug Rabson 						   NULL,
438c19800e8SDoug Rabson 						   NULL,
439c19800e8SDoug Rabson 						   NULL);
440c19800e8SDoug Rabson 		    if (GSS_ERROR(maj_stat))
441c19800e8SDoug Rabson 			gss_err (1, min_stat, "gss_inquire_context");
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson 		    maj_stat = gss_display_name(&min_stat,
444c19800e8SDoug Rabson 						src_name,
445c19800e8SDoug Rabson 						&name_buffer,
446c19800e8SDoug Rabson 						NULL);
447c19800e8SDoug Rabson 		    if (GSS_ERROR(maj_stat))
448c19800e8SDoug Rabson 			gss_err (1, min_stat, "gss_display_name");
449c19800e8SDoug Rabson 
450c19800e8SDoug Rabson 		    printf("Source: %.*s\n",
451c19800e8SDoug Rabson 			   (int)name_buffer.length,
452c19800e8SDoug Rabson 			   (char *)name_buffer.value);
453c19800e8SDoug Rabson 
454c19800e8SDoug Rabson 		    gss_release_buffer(&min_stat, &name_buffer);
455c19800e8SDoug Rabson 
456c19800e8SDoug Rabson 		    maj_stat = gss_display_name(&min_stat,
457c19800e8SDoug Rabson 						targ_name,
458c19800e8SDoug Rabson 						&name_buffer,
459c19800e8SDoug Rabson 						NULL);
460c19800e8SDoug Rabson 		    if (GSS_ERROR(maj_stat))
461c19800e8SDoug Rabson 			gss_err (1, min_stat, "gss_display_name");
462c19800e8SDoug Rabson 
463c19800e8SDoug Rabson 		    printf("Target: %.*s\n",
464c19800e8SDoug Rabson 			   (int)name_buffer.length,
465c19800e8SDoug Rabson 			   (char *)name_buffer.value);
466c19800e8SDoug Rabson 
467c19800e8SDoug Rabson 		    gss_release_name(&min_stat, &targ_name);
468c19800e8SDoug Rabson 		    gss_release_buffer(&min_stat, &name_buffer);
469c19800e8SDoug Rabson 		}
470c19800e8SDoug Rabson 
471c19800e8SDoug Rabson 		if (output_token.length) {
472c19800e8SDoug Rabson 		    char *neg_token;
473c19800e8SDoug Rabson 
474c19800e8SDoug Rabson 		    base64_encode(output_token.value,
475c19800e8SDoug Rabson 				  output_token.length,
476c19800e8SDoug Rabson 				  &neg_token);
477c19800e8SDoug Rabson 
478c19800e8SDoug Rabson 		    asprintf(&headers[0], "Authorization: Negotiate %s",
479c19800e8SDoug Rabson 			     neg_token);
480c19800e8SDoug Rabson 
481c19800e8SDoug Rabson 		    num_headers = 1;
482c19800e8SDoug Rabson 		    free(neg_token);
483c19800e8SDoug Rabson 		    gss_release_buffer(&min_stat, &output_token);
484c19800e8SDoug Rabson 		}
485c19800e8SDoug Rabson 		if (input_token.length)
486c19800e8SDoug Rabson 		    free(input_token.value);
487c19800e8SDoug Rabson 
488c19800e8SDoug Rabson 	    } else
489c19800e8SDoug Rabson 		done = 1;
490c19800e8SDoug Rabson 	} else
491c19800e8SDoug Rabson 	    done = 1;
492c19800e8SDoug Rabson 
493c19800e8SDoug Rabson 	if (verbose_flag) {
494c19800e8SDoug Rabson 	    printf("%s\n\n", req.response);
495c19800e8SDoug Rabson 
496c19800e8SDoug Rabson 	    for (i = 0; i < req.num_headers; i++)
497c19800e8SDoug Rabson 		printf("%s\n", req.headers[i]);
498c19800e8SDoug Rabson 	    printf("\n");
499c19800e8SDoug Rabson 	}
500c19800e8SDoug Rabson 	if (print_body || verbose_flag)
501c19800e8SDoug Rabson 	    printf("%.*s\n", (int)req.body_size, (char *)req.body);
502c19800e8SDoug Rabson 
503c19800e8SDoug Rabson 	http_req_free(&req);
504c19800e8SDoug Rabson     } while (!done);
505c19800e8SDoug Rabson 
506c19800e8SDoug Rabson     if (gssapi_done == 0)
507c19800e8SDoug Rabson 	errx(1, "gssapi not done but http dance done");
508c19800e8SDoug Rabson 
509c19800e8SDoug Rabson     return 0;
510c19800e8SDoug Rabson }
511