]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
Merge from trunk
[thirdparty/squid.git] / helpers / negotiate_auth / kerberos / negotiate_kerberos_auth.cc
1 /*
2 * -----------------------------------------------------------------------------
3 *
4 * Author: Markus Moeller (markus_moeller at compuserve.com)
5 *
6 * Copyright (C) 2007 Markus Moeller. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * As a special exemption, M Moeller gives permission to link this program
23 * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute
24 * the resulting executable, without including the source code for
25 * the Libraries in the source distribution.
26 *
27 * -----------------------------------------------------------------------------
28 */
29 /*
30 * Hosted at http://sourceforge.net/projects/squidkerbauth
31 */
32 #include "config.h"
33
34 #if HAVE_GSSAPI
35
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #if HAVE_STDOI_H
40 #include <stdio.h>
41 #endif
42 #if HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 #if HAVE_NETDB_H
46 #include <netdb.h>
47 #endif
48 #if HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #if HAVE_TIME_H
52 #include <time.h>
53 #endif
54 #if HAVE_SYS_TIME_H
55 #include <sys/time.h>
56 #endif
57
58 #include "util.h"
59 #include "base64.h"
60 #include "getaddrinfo.h"
61 #include "getnameinfo.h"
62 #if !HAVE_SPNEGO
63 #include "spnegohelp.h"
64 #endif
65
66 #if HAVE_HEIMDAL_KERBEROS
67 #if HAVE_GSSAPI_GSSAPI_H
68 #include <gssapi/gssapi.h>
69 #elif HAVE_GSSAPI_H
70 #include <gssapi.h>
71 #endif /* HAVE_GSSAPI_GSSAPI_H */
72 #else /* HAVE_HEIMDAL_KERBEROS */
73 #if HAVE_GSSAPI_GSSAPI_H
74 #include <gssapi/gssapi.h>
75 #elif HAVE_GSSAPI_H
76 #include <gssapi.h>
77 #endif /* HAVE_GSSAPI_GSSAPI_H */
78 #if HAVE_GSSAPI_GSSAPI_KRB5_H
79 #include <gssapi/gssapi_krb5.h>
80 #endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */
81 #if HAVE_GSSAPI_GSSAPI_GENERIC_H
82 #include <gssapi/gssapi_generic.h>
83 #endif /* HAVE_GSSAPI_GSSAPI_GENERIC_H */
84 #endif /* HAVE_HEIMDAL_KERBEROS */
85 #ifndef gss_nt_service_name
86 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
87 #endif
88
89 #define PROGRAM "negotiate_kerberos_auth"
90
91 #ifndef MAX_AUTHTOKEN_LEN
92 #define MAX_AUTHTOKEN_LEN 65535
93 #endif
94 #ifndef SQUID_KERB_AUTH_VERSION
95 #define SQUID_KERB_AUTH_VERSION "3.0.1sq"
96 #endif
97
98 int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
99 const char *function, int debug, int log);
100 char *gethost_name(void);
101 static const char *LogTime(void);
102
103 static const unsigned char ntlmProtocol[] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0 };
104
105 static const char *
106 LogTime()
107 {
108 struct tm *tm;
109 struct timeval now;
110 static time_t last_t = 0;
111 static char buf[128];
112
113 gettimeofday(&now, NULL);
114 if (now.tv_sec != last_t) {
115 tm = localtime((time_t *) & now.tv_sec);
116 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
117 last_t = now.tv_sec;
118 }
119 return buf;
120 }
121
122 char *
123 gethost_name(void)
124 {
125 char hostname[sysconf(_SC_HOST_NAME_MAX)];
126 struct addrinfo *hres = NULL, *hres_list;
127 int rc, count;
128
129 rc = gethostname(hostname, sysconf(_SC_HOST_NAME_MAX));
130 if (rc) {
131 fprintf(stderr, "%s| %s: error while resolving hostname '%s'\n",
132 LogTime(), PROGRAM, hostname);
133 return NULL;
134 }
135 rc = xgetaddrinfo(hostname, NULL, NULL, &hres);
136 if (rc != 0) {
137 fprintf(stderr,
138 "%s| %s: error while resolving hostname with getaddrinfo: %s\n",
139 LogTime(), PROGRAM, xgai_strerror(rc));
140 return NULL;
141 }
142 hres_list = hres;
143 count = 0;
144 while (hres_list) {
145 count++;
146 hres_list = hres_list->ai_next;
147 }
148 rc = xgetnameinfo(hres->ai_addr, hres->ai_addrlen, hostname,
149 sizeof(hostname), NULL, 0, 0);
150 if (rc != 0) {
151 fprintf(stderr,
152 "%s| %s: error while resolving ip address with getnameinfo: %s\n",
153 LogTime(), PROGRAM, xgai_strerror(rc));
154 xfreeaddrinfo(hres);
155 return NULL;
156 }
157
158 xfreeaddrinfo(hres);
159 hostname[sysconf(_SC_HOST_NAME_MAX) - 1] = '\0';
160 return (xstrdup(hostname));
161 }
162
163 int
164 check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
165 const char *function, int debug, int log)
166 {
167 if (GSS_ERROR(major_status)) {
168 OM_uint32 maj_stat, min_stat;
169 OM_uint32 msg_ctx = 0;
170 gss_buffer_desc status_string;
171 char buf[1024];
172 size_t len;
173
174 len = 0;
175 msg_ctx = 0;
176 while (!msg_ctx) {
177 /* convert major status code (GSS-API error) to text */
178 maj_stat = gss_display_status(&min_stat, major_status,
179 GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
180 if (maj_stat == GSS_S_COMPLETE) {
181 if (sizeof(buf) > len + status_string.length + 1) {
182 sprintf(buf + len, "%s", (char *) status_string.value);
183 len += status_string.length;
184 }
185 gss_release_buffer(&min_stat, &status_string);
186 break;
187 }
188 gss_release_buffer(&min_stat, &status_string);
189 }
190 if (sizeof(buf) > len + 2) {
191 sprintf(buf + len, "%s", ". ");
192 len += 2;
193 }
194 msg_ctx = 0;
195 while (!msg_ctx) {
196 /* convert minor status code (underlying routine error) to text */
197 maj_stat = gss_display_status(&min_stat, minor_status,
198 GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
199 if (maj_stat == GSS_S_COMPLETE) {
200 if (sizeof(buf) > len + status_string.length) {
201 sprintf(buf + len, "%s", (char *) status_string.value);
202 len += status_string.length;
203 }
204 gss_release_buffer(&min_stat, &status_string);
205 break;
206 }
207 gss_release_buffer(&min_stat, &status_string);
208 }
209 if (debug)
210 fprintf(stderr, "%s| %s: %s failed: %s\n", LogTime(), PROGRAM,
211 function, buf);
212 fprintf(stdout, "BH %s failed: %s\n", function, buf);
213 if (log)
214 fprintf(stderr, "%s| %s: User not authenticated\n", LogTime(),
215 PROGRAM);
216 return (1);
217 }
218 return (0);
219 }
220
221
222
223 int
224 main(int argc, char *const argv[])
225 {
226 char buf[MAX_AUTHTOKEN_LEN];
227 char *c, *p;
228 char *user = NULL;
229 int length = 0;
230 static int err = 0;
231 int opt, debug = 0, log = 0, norealm = 0;
232 #if !HAVE_SPNEGO
233 int rc;
234 #endif
235 OM_uint32 ret_flags = 0, spnego_flag = 0;
236 char *service_name = (char *) "HTTP", *host_name = NULL;
237 char *token = NULL;
238 char *service_principal = NULL;
239 OM_uint32 major_status, minor_status;
240 gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
241 gss_name_t client_name = GSS_C_NO_NAME;
242 gss_name_t server_name = GSS_C_NO_NAME;
243 gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
244 gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
245 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
246 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
247 const unsigned char *kerberosToken = NULL;
248 #if !HAVE_SPNEGO
249 size_t kerberosTokenLength = 0;
250 #endif
251 const unsigned char *spnegoToken = NULL;
252 size_t spnegoTokenLength = 0;
253
254 setbuf(stdout, NULL);
255 setbuf(stdin, NULL);
256
257 while (-1 != (opt = getopt(argc, argv, "dirs:h"))) {
258 switch (opt) {
259 case 'd':
260 debug = 1;
261 break;
262 case 'i':
263 log = 1;
264 break;
265 case 'r':
266 norealm = 1;
267 break;
268 case 's':
269 service_principal = xstrdup(optarg);
270 break;
271 case 'h':
272 fprintf(stderr, "Usage: \n");
273 fprintf(stderr, "squid_kerb_auth [-d] [-i] [-s SPN] [-h]\n");
274 fprintf(stderr, "-d full debug\n");
275 fprintf(stderr, "-i informational messages\n");
276 fprintf(stderr, "-r remove realm from username\n");
277 fprintf(stderr, "-s service principal name\n");
278 fprintf(stderr, "-h help\n");
279 fprintf(stderr,
280 "The SPN can be set to GSS_C_NO_NAME to allow any entry from keytab\n");
281 fprintf(stderr, "default SPN is HTTP/fqdn@DEFAULT_REALM\n");
282 exit(0);
283 default:
284 fprintf(stderr, "%s| %s: unknown option: -%c.\n", LogTime(),
285 PROGRAM, opt);
286 }
287 }
288
289 if (debug)
290 fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM,
291 SQUID_KERB_AUTH_VERSION);
292 if (service_principal && strcasecmp(service_principal, "GSS_C_NO_NAME")) {
293 service.value = service_principal;
294 service.length = strlen((char *) service.value);
295 } else {
296 host_name = gethost_name();
297 if (!host_name) {
298 fprintf(stderr,
299 "%s| %s: Local hostname could not be determined. Please specify the service principal\n",
300 LogTime(), PROGRAM);
301 fprintf(stdout, "BH hostname error\n");
302 exit(-1);
303 }
304 service.value = xmalloc(strlen(service_name) + strlen(host_name) + 2);
305 snprintf((char*)service.value, strlen(service_name) + strlen(host_name) + 2,
306 "%s@%s", service_name, host_name);
307 service.length = strlen((char *) service.value);
308 }
309
310 while (1) {
311 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
312 if (ferror(stdin)) {
313 if (debug)
314 fprintf(stderr,
315 "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
316 LogTime(), PROGRAM, ferror(stdin),
317 strerror(ferror(stdin)));
318
319 fprintf(stdout, "BH input error\n");
320 exit(1); /* BIIG buffer */
321 }
322 fprintf(stdout, "BH input error\n");
323 exit(0);
324 }
325
326 c = (char*)memchr(buf, '\n', sizeof(buf) - 1);
327 if (c) {
328 *c = '\0';
329 length = c - buf;
330 } else {
331 err = 1;
332 }
333 if (err) {
334 if (debug)
335 fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
336 PROGRAM);
337 fprintf(stdout, "BH Oversized message\n");
338 err = 0;
339 continue;
340 }
341
342 if (debug)
343 fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n",
344 LogTime(), PROGRAM, buf, length);
345
346 if (buf[0] == '\0') {
347 if (debug)
348 fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
349 PROGRAM);
350 fprintf(stdout, "BH Invalid request\n");
351 continue;
352 }
353
354 if (strlen(buf) < 2) {
355 if (debug)
356 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
357 PROGRAM, buf);
358 fprintf(stdout, "BH Invalid request\n");
359 continue;
360 }
361
362 if (!strncmp(buf, "QQ", 2)) {
363 gss_release_buffer(&minor_status, &input_token);
364 gss_release_buffer(&minor_status, &output_token);
365 gss_release_buffer(&minor_status, &service);
366 gss_release_cred(&minor_status, &server_creds);
367 if (server_name)
368 gss_release_name(&minor_status, &server_name);
369 if (client_name)
370 gss_release_name(&minor_status, &client_name);
371 if (gss_context != GSS_C_NO_CONTEXT)
372 gss_delete_sec_context(&minor_status, &gss_context, NULL);
373 if (kerberosToken) {
374 /* Allocated by parseNegTokenInit, but no matching free function exists.. */
375 if (!spnego_flag)
376 xfree((char *) kerberosToken);
377 kerberosToken = NULL;
378 }
379 if (spnego_flag) {
380 /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
381 if (spnegoToken)
382 xfree((char *) spnegoToken);
383 spnegoToken = NULL;
384 }
385 if (token) {
386 xfree(token);
387 token = NULL;
388 }
389 if (host_name) {
390 xfree(host_name);
391 host_name = NULL;
392 }
393 fprintf(stdout, "BH quit command\n");
394 exit(0);
395 }
396
397 if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
398 if (debug)
399 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
400 PROGRAM, buf);
401 fprintf(stdout, "BH Invalid request\n");
402 continue;
403 }
404 if (!strncmp(buf, "YR", 2)) {
405 if (gss_context != GSS_C_NO_CONTEXT)
406 gss_delete_sec_context(&minor_status, &gss_context, NULL);
407 gss_context = GSS_C_NO_CONTEXT;
408 }
409
410 if (strlen(buf) <= 3) {
411 if (debug)
412 fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
413 LogTime(), PROGRAM, buf);
414 fprintf(stdout, "BH Invalid negotiate request\n");
415 continue;
416 }
417
418 input_token.length = ska_base64_decode_len(buf + 3);
419 if (debug)
420 fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
421 LogTime(), PROGRAM, buf + 3, (int) input_token.length);
422 input_token.value = xmalloc(input_token.length);
423
424 ska_base64_decode((char*)input_token.value, buf + 3, input_token.length);
425
426
427 #if !HAVE_SPNEGO
428 if ((rc = parseNegTokenInit(input_token.value,
429 input_token.length,
430 &kerberosToken, &kerberosTokenLength)) != 0) {
431 if (debug)
432 fprintf(stderr, "%s| %s: parseNegTokenInit failed with rc=%d\n",
433 LogTime(), PROGRAM, rc);
434
435 /* if between 100 and 200 it might be a GSSAPI token and not a SPNEGO token */
436 if (rc < 100 || rc > 199) {
437 if (debug)
438 fprintf(stderr, "%s| %s: Invalid GSS-SPNEGO query [%s]\n",
439 LogTime(), PROGRAM, buf);
440 fprintf(stdout, "BH Invalid GSS-SPNEGO query\n");
441 goto cleanup;
442 }
443 if ((input_token.length >= sizeof ntlmProtocol + 1) &&
444 (!memcmp(input_token.value, ntlmProtocol,
445 sizeof ntlmProtocol))) {
446 if (debug)
447 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
448 LogTime(), PROGRAM,
449 (int) *((unsigned char *) input_token.value +
450 sizeof ntlmProtocol));
451 fprintf(stdout, "BH received type %d NTLM token\n",
452 (int) *((unsigned char *) input_token.value +
453 sizeof ntlmProtocol));
454 goto cleanup;
455 }
456 if (debug)
457 fprintf(stderr, "%s| %s: Token is possibly a GSSAPI token\n",
458 LogTime(), PROGRAM);
459 spnego_flag = 0;
460 } else {
461 gss_release_buffer(&minor_status, &input_token);
462 input_token.length = kerberosTokenLength;
463 input_token.value = (void *) kerberosToken;
464 spnego_flag = 1;
465 }
466 #else
467 if ((input_token.length >= sizeof ntlmProtocol + 1) &&
468 (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
469 if (debug)
470 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
471 LogTime(), PROGRAM,
472 (int) *((unsigned char *) input_token.value +
473 sizeof ntlmProtocol));
474 fprintf(stdout, "BH received type %d NTLM token\n",
475 (int) *((unsigned char *) input_token.value +
476 sizeof ntlmProtocol));
477 goto cleanup;
478 }
479 #endif
480
481 if (service_principal) {
482 if (strcasecmp(service_principal, "GSS_C_NO_NAME")) {
483 major_status = gss_import_name(&minor_status, &service,
484 (gss_OID) GSS_C_NULL_OID, &server_name);
485
486 } else {
487 server_name = GSS_C_NO_NAME;
488 major_status = GSS_S_COMPLETE;
489 }
490 } else {
491 major_status = gss_import_name(&minor_status, &service,
492 gss_nt_service_name, &server_name);
493 }
494
495 if (check_gss_err(major_status, minor_status, "gss_import_name()",
496 debug, log))
497 goto cleanup;
498
499 major_status =
500 gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
501 GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
502 if (check_gss_err(major_status, minor_status, "gss_acquire_cred()",
503 debug, log))
504 goto cleanup;
505
506 major_status = gss_accept_sec_context(&minor_status,
507 &gss_context,
508 server_creds,
509 &input_token,
510 GSS_C_NO_CHANNEL_BINDINGS,
511 &client_name, NULL, &output_token, &ret_flags, NULL, NULL);
512
513
514 if (output_token.length) {
515 #if !HAVE_SPNEGO
516 if (spnego_flag) {
517 if ((rc = makeNegTokenTarg(output_token.value,
518 output_token.length,
519 &spnegoToken, &spnegoTokenLength)) != 0) {
520 if (debug)
521 fprintf(stderr,
522 "%s| %s: makeNegTokenTarg failed with rc=%d\n",
523 LogTime(), PROGRAM, rc);
524 fprintf(stdout, "BH makeNegTokenTarg failed with rc=%d\n",
525 rc);
526 goto cleanup;
527 }
528 } else {
529 spnegoToken = output_token.value;
530 spnegoTokenLength = output_token.length;
531 }
532 #else
533 spnegoToken = (unsigned char *)output_token.value;
534 spnegoTokenLength = output_token.length;
535 #endif
536 token = (char*)xmalloc(ska_base64_encode_len(spnegoTokenLength));
537 if (token == NULL) {
538 if (debug)
539 fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
540 PROGRAM);
541 fprintf(stdout, "BH Not enough memory\n");
542 goto cleanup;
543 }
544
545 ska_base64_encode(token, (const char *) spnegoToken,
546 ska_base64_encode_len(spnegoTokenLength), spnegoTokenLength);
547
548 if (check_gss_err(major_status, minor_status,
549 "gss_accept_sec_context()", debug, log))
550 goto cleanup;
551 if (major_status & GSS_S_CONTINUE_NEEDED) {
552 if (debug)
553 fprintf(stderr, "%s| %s: continuation needed\n", LogTime(),
554 PROGRAM);
555 fprintf(stdout, "TT %s\n", token);
556 goto cleanup;
557 }
558 gss_release_buffer(&minor_status, &output_token);
559 major_status =
560 gss_display_name(&minor_status, client_name, &output_token,
561 NULL);
562
563 if (check_gss_err(major_status, minor_status, "gss_display_name()",
564 debug, log))
565 goto cleanup;
566 user = (char*)xmalloc(output_token.length + 1);
567 if (user == NULL) {
568 if (debug)
569 fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
570 PROGRAM);
571 fprintf(stdout, "BH Not enough memory\n");
572 goto cleanup;
573 }
574 memcpy(user, output_token.value, output_token.length);
575 user[output_token.length] = '\0';
576 if (norealm && (p = strchr(user, '@')) != NULL) {
577 *p = '\0';
578 }
579 fprintf(stdout, "AF %s %s\n", token, user);
580 if (debug)
581 fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, token,
582 user);
583 if (log)
584 fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(),
585 PROGRAM, user);
586 goto cleanup;
587 } else {
588 if (check_gss_err(major_status, minor_status,
589 "gss_accept_sec_context()", debug, log))
590 goto cleanup;
591 if (major_status & GSS_S_CONTINUE_NEEDED) {
592 if (debug)
593 fprintf(stderr, "%s| %s: continuation needed\n", LogTime(),
594 PROGRAM);
595 fprintf(stdout, "NA %s\n", token);
596 goto cleanup;
597 }
598 gss_release_buffer(&minor_status, &output_token);
599 major_status =
600 gss_display_name(&minor_status, client_name, &output_token,
601 NULL);
602
603 if (check_gss_err(major_status, minor_status, "gss_display_name()",
604 debug, log))
605 goto cleanup;
606 /*
607 * Return dummy token AA. May need an extra return tag then AF
608 */
609 user = (char*)xmalloc(output_token.length + 1);
610 if (user == NULL) {
611 if (debug)
612 fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(),
613 PROGRAM);
614 fprintf(stdout, "BH Not enough memory\n");
615 goto cleanup;
616 }
617 memcpy(user, output_token.value, output_token.length);
618 user[output_token.length] = '\0';
619 if (norealm && (p = strchr(user, '@')) != NULL) {
620 *p = '\0';
621 }
622 fprintf(stdout, "AF %s %s\n", "AA==", user);
623 if (debug)
624 fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM,
625 "AA==", user);
626 if (log)
627 fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(),
628 PROGRAM, user);
629
630 }
631 cleanup:
632 gss_release_buffer(&minor_status, &input_token);
633 gss_release_buffer(&minor_status, &output_token);
634 gss_release_cred(&minor_status, &server_creds);
635 if (server_name)
636 gss_release_name(&minor_status, &server_name);
637 if (client_name)
638 gss_release_name(&minor_status, &client_name);
639 if (kerberosToken) {
640 /* Allocated by parseNegTokenInit, but no matching free function exists.. */
641 if (!spnego_flag)
642 xfree((char *) kerberosToken);
643 kerberosToken = NULL;
644 }
645 if (spnego_flag) {
646 /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
647 if (spnegoToken)
648 xfree((char *) spnegoToken);
649 spnegoToken = NULL;
650 }
651 if (token) {
652 xfree(token);
653 token = NULL;
654 }
655 if (user) {
656 xfree(user);
657 user = NULL;
658 }
659 continue;
660 }
661 }
662 #else
663 #include <stdio.h>
664 #include <stdlib.h>
665 #ifndef MAX_AUTHTOKEN_LEN
666 #define MAX_AUTHTOKEN_LEN 65535
667 #endif
668 int
669 main(int argc, char *const argv[])
670 {
671 setbuf(stdout, NULL);
672 setbuf(stdin, NULL);
673 char buf[MAX_AUTHTOKEN_LEN];
674 while (1) {
675 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
676 fprintf(stdout, "BH input error\n");
677 exit(0);
678 }
679 fprintf(stdout, "BH Kerberos authentication not supported\n");
680 }
681 }
682 #endif /* HAVE_GSSAPI */