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