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