]> git.ipfire.org Git - thirdparty/squid.git/blame - src/peer_proxy_negotiate_auth.cc
Bug 5498: cachemgr documentation improvements (#2109)
[thirdparty/squid.git] / src / peer_proxy_negotiate_auth.cc
CommitLineData
9ca29d23 1/*
1f7b830e 2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
9ca29d23 3 *
282b7328
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9ca29d23 7 */
282b7328 8
9ca29d23 9/*
282b7328 10 * DEBUG: 11 Hypertext Transfer Protocol (HTTP)
9ca29d23
AJ
11 */
12
f7f3304a 13#include "squid.h"
6ff204fc 14
8b082ed9 15#if HAVE_AUTH_MODULE_NEGOTIATE && HAVE_KRB5 && HAVE_GSSAPI
a1fe225c 16#include "base64.h"
42557148 17#include "compat/krb5.h"
675b8408 18#include "debug/Stream.h"
6ff204fc 19#include "peer_proxy_negotiate_auth.h"
9ca29d23 20
9ca29d23
AJ
21#if HAVE_PROFILE_H
22#include <profile.h>
f53969cc 23#endif /* HAVE_PROFILE_H */
42557148 24#if HAVE_ET_COM_ERR_H && !HAVE_KRB5_H
cf99ae25
AJ
25#include <et/com_err.h>
26#endif /* HAVE_COM_ERR_H */
9ca29d23
AJ
27#if HAVE_COM_ERR_H
28#include <com_err.h>
f53969cc 29#endif /* HAVE_COM_ERR_H */
adcdd245
AJ
30#if HAVE_GSS_H
31#include <gss.h>
32#endif
33#if USE_APPLE_KRB5
34#define GSSKRB_APPLE_DEPRECATED(x)
35#endif
9ca29d23
AJ
36#if HAVE_GSSAPI_GSSAPI_H
37#include <gssapi/gssapi.h>
38#elif HAVE_GSSAPI_H
39#include <gssapi.h>
f53969cc 40#endif /* HAVE_GSSAPI_H */
9ca29d23
AJ
41#if HAVE_GSSAPI_GSSAPI_EXT_H
42#include <gssapi/gssapi_ext.h>
f53969cc 43#endif /* HAVE_GSSAPI_GSSAPI_EXT_H */
9ca29d23
AJ
44#if HAVE_GSSAPI_GSSAPI_KRB5_H
45#include <gssapi/gssapi_krb5.h>
f53969cc 46#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */
9ca29d23
AJ
47#if HAVE_GSSAPI_GSSAPI_GENERIC_H
48#include <gssapi/gssapi_generic.h>
f53969cc 49#endif /* HAVE_GSSAPI_GSSAPI_GENERIC_H */
9ca29d23
AJ
50
51#ifndef gss_nt_service_name
52#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
53#endif
54
b2bdde72 55#if !HAVE_ERROR_MESSAGE && HAVE_KRB5_GET_ERROR_MESSAGE
cf99ae25 56#define error_message(code) krb5_get_error_message(kparam.context,code)
b2bdde72 57#elif !HAVE_ERROR_MESSAGE && HAVE_KRB5_GET_ERR_TEXT
1a22a39e 58#define error_message(code) krb5_get_err_text(kparam.context,code)
cf99ae25 59#elif !HAVE_ERROR_MESSAGE
f53969cc
SM
60static char err_code[17];
61const char *KRB5_CALLCONV
62error_message(long code) {
63 snprintf(err_code,16,"%ld",code);
64 return err_code;
65}
9ca29d23
AJ
66#endif
67
68#ifndef gss_mech_spnego
f53969cc
SM
69static gss_OID_desc _gss_mech_spnego =
70{ 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
71gss_OID gss_mech_spnego = &_gss_mech_spnego;
9ca29d23
AJ
72#endif
73
1a22a39e 74#if USE_IBM_KERBEROS
9ca29d23 75#include <ibm_svc/krb5_svc.h>
f53969cc 76const char *KRB5_CALLCONV error_message(long code) {
a1b1756c 77 char *msg = nullptr;
f53969cc
SM
78 krb5_svc_get_msg(code, &msg);
79 return msg;
80}
9ca29d23
AJ
81#endif
82
f53969cc
SM
83/*
84 * Kerberos context and cache structure
85 * Caches authentication details to reduce
86 * number of authentication requests to kdc
87 */
88static struct kstruct {
89 krb5_context context;
90 krb5_ccache cc;
91} kparam = {
aee3523a 92 nullptr, nullptr
f53969cc 93};
f54f527e 94
f53969cc
SM
95/*
96 * krb5_create_cache creates a Kerberos file credential cache or a memory
97 * credential cache if supported. The initial key for the principal
98 * principal_name is extracted from the keytab keytab_filename.
99 *
100 * If keytab_filename is NULL the default will be used.
101 * If principal_name is NULL the first working entry of the keytab will be used.
102 */
103int krb5_create_cache(char *keytab_filename, char *principal_name);
9ca29d23 104
f53969cc
SM
105/*
106 * krb5_cleanup clears used Keberos memory
107 */
108void krb5_cleanup(void);
9ca29d23 109
f53969cc
SM
110/*
111 * check_gss_err checks for gssapi error codes, extracts the error message
112 * and prints it.
113 */
114int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
115 const char *function);
116
117int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
118 const char *function) {
119 if (GSS_ERROR(major_status)) {
120 OM_uint32 maj_stat, min_stat;
121 OM_uint32 msg_ctx = 0;
122 gss_buffer_desc status_string;
123 char buf[1024];
124 size_t len;
125
126 len = 0;
127 msg_ctx = 0;
128 while (!msg_ctx) {
129 /* convert major status code (GSS-API error) to text */
130 maj_stat = gss_display_status(&min_stat, major_status,
131 GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
132 if (maj_stat == GSS_S_COMPLETE) {
133 if (sizeof(buf) > len + status_string.length + 1) {
134 memcpy(buf + len, status_string.value,
135 status_string.length);
136 len += status_string.length;
f54f527e
AJ
137 }
138 gss_release_buffer(&min_stat, &status_string);
f53969cc 139 break;
f54f527e 140 }
f53969cc
SM
141 gss_release_buffer(&min_stat, &status_string);
142 }
143 if (sizeof(buf) > len + 2) {
144 strcpy(buf + len, ". ");
145 len += 2;
146 }
147 msg_ctx = 0;
148 while (!msg_ctx) {
149 /* convert minor status code (underlying routine error) to text */
150 maj_stat = gss_display_status(&min_stat, minor_status,
151 GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
152 if (maj_stat == GSS_S_COMPLETE) {
153 if (sizeof(buf) > len + status_string.length) {
154 memcpy(buf + len, status_string.value,
155 status_string.length);
156 len += status_string.length;
f54f527e
AJ
157 }
158 gss_release_buffer(&min_stat, &status_string);
f53969cc 159 break;
f54f527e 160 }
f53969cc 161 gss_release_buffer(&min_stat, &status_string);
f54f527e 162 }
bf95c10a 163 debugs(11, 5, function << "failed: " << buf);
f53969cc 164 return (1);
9ca29d23 165 }
f53969cc
SM
166 return (0);
167}
9ca29d23 168
f53969cc 169void krb5_cleanup() {
bf95c10a 170 debugs(11, 5, "Cleanup kerberos context");
f53969cc
SM
171 if (kparam.context) {
172 if (kparam.cc)
173 krb5_cc_destroy(kparam.context, kparam.cc);
aee3523a 174 kparam.cc = nullptr;
f53969cc 175 krb5_free_context(kparam.context);
aee3523a 176 kparam.context = nullptr;
9ca29d23 177 }
f53969cc 178}
9ca29d23 179
f53969cc 180int krb5_create_cache(char *kf, char *pn) {
9ca29d23
AJ
181
182#define KT_PATH_MAX 256
183#define MAX_RENEW_TIME "365d"
184#define DEFAULT_SKEW (krb5_deltat) 600
185
aee3523a
AR
186 static char *keytab_filename = nullptr, *principal_name = nullptr;
187 static krb5_keytab keytab = nullptr;
f53969cc
SM
188 static krb5_keytab_entry entry;
189 static krb5_kt_cursor cursor;
aee3523a 190 static krb5_creds *creds = nullptr;
adcdd245 191#if HAVE_LIBHEIMDAL_KRB5 && !HAVE_KRB5_GET_RENEWED_CREDS
f53969cc 192 static krb5_creds creds2;
9ca29d23 193#endif
aee3523a 194 static krb5_principal principal = nullptr;
f53969cc 195 static krb5_deltat skew;
f54f527e 196
4ebcf1ce 197#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
f53969cc 198 krb5_get_init_creds_opt *options;
4ebcf1ce 199#else
f53969cc 200 krb5_get_init_creds_opt options;
4ebcf1ce 201#endif
f53969cc
SM
202 krb5_error_code code = 0;
203 krb5_deltat rlife;
f54f527e 204#if HAVE_PROFILE_H && HAVE_KRB5_GET_PROFILE && HAVE_PROFILE_GET_INTEGER && HAVE_PROFILE_RELEASE
f53969cc 205 profile_t profile;
9ca29d23 206#endif
adcdd245 207#if HAVE_LIBHEIMDAL_KRB5 && !HAVE_KRB5_GET_RENEWED_CREDS
f53969cc 208 krb5_kdc_flags flags;
4ebcf1ce 209#if HAVE_KRB5_PRINCIPAL_GET_REALM
f53969cc 210 const char *client_realm;
4ebcf1ce 211#else
f53969cc 212 krb5_realm client_realm;
4ebcf1ce 213#endif
9ca29d23 214#endif
f53969cc 215 char *mem_cache;
f54f527e
AJ
216
217restart:
f53969cc
SM
218 /*
219 * Check if credentials need to be renewed
220 */
221 if (creds &&
aee3523a
AR
222 (creds->times.endtime - time(nullptr) > skew) &&
223 (creds->times.renew_till - time(nullptr) > 2 * skew)) {
224 if (creds->times.endtime - time(nullptr) < 2 * skew) {
4ebcf1ce 225#if HAVE_KRB5_GET_RENEWED_CREDS
f53969cc
SM
226 /* renew ticket */
227 code =
228 krb5_get_renewed_creds(kparam.context, creds, principal,
aee3523a 229 kparam.cc, nullptr);
9ca29d23 230#else
f53969cc
SM
231 /* renew ticket */
232 flags.i = 0;
233 flags.b.renewable = flags.b.renew = 1;
234
235 code =
236 krb5_cc_get_principal(kparam.context, kparam.cc,
237 &creds2.client);
238 if (code) {
239 debugs(11, 5,
bf95c10a 240
f53969cc
SM
241 "Error while getting principal from credential cache : "
242 << error_message(code));
243 return (1);
244 }
4ebcf1ce 245#if HAVE_KRB5_PRINCIPAL_GET_REALM
f53969cc 246 client_realm = krb5_principal_get_realm(kparam.context, principal);
4ebcf1ce 247#else
f53969cc 248 client_realm = krb5_princ_realm(kparam.context, creds2.client);
9ca29d23 249#endif
f53969cc
SM
250 code =
251 krb5_make_principal(kparam.context, &creds2.server,
252 (krb5_const_realm)&client_realm, KRB5_TGS_NAME,
a1b1756c 253 (krb5_const_realm)&client_realm, nullptr);
f54f527e 254 if (code) {
f54f527e 255 debugs(11, 5,
bf95c10a 256 "Error while getting krbtgt principal : " <<
f54f527e
AJ
257 error_message(code));
258 return (1);
259 }
260 code =
a1b1756c
AJ
261 krb5_get_kdc_cred(kparam.context, kparam.cc, flags, nullptr,
262 nullptr, &creds2, &creds);
f53969cc
SM
263 krb5_free_creds(kparam.context, &creds2);
264#endif
f54f527e 265 if (code) {
f53969cc
SM
266 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) {
267 krb5_free_creds(kparam.context, creds);
aee3523a 268 creds = nullptr;
f53969cc
SM
269 /* this can happen because of clock skew */
270 goto restart;
271 }
f54f527e 272 debugs(11, 5,
bf95c10a 273 "Error while get credentials : " <<
f54f527e
AJ
274 error_message(code));
275 return (1);
276 }
f53969cc
SM
277 }
278 } else {
279 /* reinit */
280 if (!kparam.context) {
281 code = krb5_init_context(&kparam.context);
f54f527e
AJ
282 if (code) {
283 debugs(11, 5,
bf95c10a 284 "Error while initialising Kerberos library : "
f53969cc 285 << error_message(code));
f54f527e
AJ
286 return (1);
287 }
f53969cc
SM
288 }
289#if HAVE_PROFILE_H && HAVE_KRB5_GET_PROFILE && HAVE_PROFILE_GET_INTEGER && HAVE_PROFILE_RELEASE
290 code = krb5_get_profile(kparam.context, &profile);
291 if (code) {
292 if (profile)
293 profile_release(profile);
294 debugs(11, 5,
bf95c10a 295 "Error while getting profile : " <<
f53969cc
SM
296 error_message(code));
297 return (1);
298 }
299 code =
aee3523a 300 profile_get_integer(profile, "libdefaults", "clockskew", nullptr,
f53969cc
SM
301 5 * 60, &skew);
302 if (profile)
303 profile_release(profile);
304 if (code) {
305 debugs(11, 5,
bf95c10a 306 "Error while getting clockskew : " <<
f53969cc
SM
307 error_message(code));
308 return (1);
309 }
202d3a22 310#elif HAVE_LIBHEIMDAL_KRB5
f53969cc 311 skew = krb5_get_max_time_skew(kparam.context);
9ca29d23 312#else
f53969cc 313 skew = DEFAULT_SKEW;
9ca29d23 314#endif
f54f527e 315
f53969cc
SM
316 if (!kf) {
317 char buf[KT_PATH_MAX], *p;
f54f527e 318
f53969cc
SM
319 krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
320 p = strchr(buf, ':');
321 if (p)
322 ++p;
323 xfree(keytab_filename);
324 keytab_filename = xstrdup(p ? p : buf);
325 } else {
326 keytab_filename = xstrdup(kf);
327 }
f54f527e 328
f53969cc
SM
329 code = krb5_kt_resolve(kparam.context, keytab_filename, &keytab);
330 if (code) {
331 debugs(11, 5,
bf95c10a 332 "Error while resolving keytab filename " <<
f53969cc
SM
333 keytab_filename << " : " << error_message(code));
334 return (1);
335 }
336
337 if (!pn) {
338 code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
339 if (code) {
f54f527e 340 debugs(11, 5,
bf95c10a 341 "Error while starting keytab scan : " <<
f53969cc 342 error_message(code));
f54f527e
AJ
343 return (1);
344 }
f54f527e 345 code =
f53969cc
SM
346 krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor);
347 krb5_copy_principal(kparam.context, entry.principal,
348 &principal);
349 if (code && code != KRB5_KT_END) {
f54f527e 350 debugs(11, 5,
bf95c10a 351 "Error while scanning keytab : " <<
f54f527e
AJ
352 error_message(code));
353 return (1);
354 }
9ca29d23 355
f53969cc 356 code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
f54f527e
AJ
357 if (code) {
358 debugs(11, 5,
bf95c10a 359 "Error while ending keytab scan : " <<
f53969cc 360 error_message(code));
f54f527e
AJ
361 return (1);
362 }
adcdd245 363#if HAVE_LIBHEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY)
f53969cc
SM
364 code = krb5_kt_free_entry(kparam.context, &entry);
365#else
366 code = krb5_free_keytab_entry_contents(kparam.context, &entry);
367#endif
f54f527e
AJ
368 if (code) {
369 debugs(11, 5,
bf95c10a 370 "Error while freeing keytab entry : " <<
f54f527e
AJ
371 error_message(code));
372 return (1);
373 }
f53969cc
SM
374
375 } else {
376 principal_name = xstrdup(pn);
377 }
378
379 if (!principal) {
380 code =
381 krb5_parse_name(kparam.context, principal_name, &principal);
f54f527e
AJ
382 if (code) {
383 debugs(11, 5,
bf95c10a 384 "Error while parsing principal name " <<
f53969cc 385 principal_name << " : " << error_message(code));
f54f527e
AJ
386 return (1);
387 }
f54f527e 388 }
9ca29d23 389
f53969cc
SM
390 creds = (krb5_creds *) xmalloc(sizeof(*creds));
391 memset(creds, 0, sizeof(*creds));
392#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
393 krb5_get_init_creds_opt_alloc(kparam.context, &options);
394#else
395 krb5_get_init_creds_opt_init(&options);
396#endif
397 code = krb5_string_to_deltat((char *) MAX_RENEW_TIME, &rlife);
398 if (code != 0 || rlife == 0) {
399 debugs(11, 5,
bf95c10a 400 "Error bad lifetime value " << MAX_RENEW_TIME <<
f53969cc
SM
401 " : " << error_message(code));
402 return (1);
f54f527e 403 }
f53969cc
SM
404#if HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
405 krb5_get_init_creds_opt_set_renew_life(options, rlife);
406 code =
407 krb5_get_init_creds_keytab(kparam.context, creds, principal,
aee3523a 408 keytab, 0, nullptr, options);
f53969cc
SM
409#if HAVE_KRB5_GET_INIT_CREDS_FREE_CONTEXT
410 krb5_get_init_creds_opt_free(kparam.context, options);
411#else
412 krb5_get_init_creds_opt_free(options);
413#endif
414#else
415 krb5_get_init_creds_opt_set_renew_life(&options, rlife);
416 code =
417 krb5_get_init_creds_keytab(kparam.context, creds, principal,
a1b1756c 418 keytab, 0, nullptr, &options);
f53969cc
SM
419#endif
420 if (code) {
f54f527e 421 debugs(11, 5,
bf95c10a 422
f53969cc
SM
423 "Error while initializing credentials from keytab : " <<
424 error_message(code));
425 return (1);
426 }
427#if !HAVE_KRB5_MEMORY_CACHE
428 mem_cache =
429 (char *) xmalloc(strlen("FILE:/tmp/peer_proxy_negotiate_auth_")
430 + 16);
431 if (!mem_cache) {
432 debugs(11, 5, "Error while allocating memory");
433 return(1);
f54f527e 434 }
f53969cc
SM
435 snprintf(mem_cache,
436 strlen("FILE:/tmp/peer_proxy_negotiate_auth_") + 16,
437 "FILE:/tmp/peer_proxy_negotiate_auth_%d", (int) getpid());
438#else
439 mem_cache =
440 (char *) xmalloc(strlen("MEMORY:peer_proxy_negotiate_auth_") +
441 16);
442 if (!mem_cache) {
443 debugs(11, 5, "Error while allocating memory");
444 return(1);
445 }
446 snprintf(mem_cache,
447 strlen("MEMORY:peer_proxy_negotiate_auth_") + 16,
448 "MEMORY:peer_proxy_negotiate_auth_%d", (int) getpid());
449#endif
f54f527e 450
f53969cc
SM
451 setenv("KRB5CCNAME", mem_cache, 1);
452 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc);
453 xfree(mem_cache);
454 if (code) {
455 debugs(11, 5,
bf95c10a 456 "Error while resolving memory credential cache : "
f53969cc
SM
457 << error_message(code));
458 return (1);
459 }
460 code = krb5_cc_initialize(kparam.context, kparam.cc, principal);
461 if (code) {
462 debugs(11, 5,
bf95c10a 463
f53969cc
SM
464 "Error while initializing memory credential cache : " <<
465 error_message(code));
466 return (1);
467 }
468 code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
469 if (code) {
470 debugs(11, 5,
bf95c10a 471 "Error while storing credentials : " <<
f53969cc
SM
472 error_message(code));
473 return (1);
f54f527e
AJ
474 }
475
f53969cc
SM
476 if (!creds->times.starttime)
477 creds->times.starttime = creds->times.authtime;
478 }
479 return (0);
480}
481
482/*
483 * peer_proxy_negotiate_auth gets a GSSAPI token for principal_name
484 * and base64 encodes it.
485 */
16b17ba9 486char *peer_proxy_negotiate_auth(char *principal_name, const char * const proxy, int flags) {
f53969cc
SM
487 int rc = 0;
488 OM_uint32 major_status, minor_status;
489 gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
490 gss_name_t server_name = GSS_C_NO_NAME;
491 gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
492 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
493 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
aee3523a 494 char *token = nullptr;
f53969cc 495
aee3523a
AR
496 setbuf(stdout, nullptr);
497 setbuf(stdin, nullptr);
f53969cc
SM
498
499 if (!proxy) {
bf95c10a 500 debugs(11, 5, "Error : No proxy server name");
aee3523a 501 return nullptr;
f53969cc
SM
502 }
503
9825b398
AJ
504 if (!(flags & PEER_PROXY_NEGOTIATE_NOKEYTAB)) {
505 if (principal_name)
506 debugs(11, 5,
bf95c10a 507 "Creating credential cache for " << principal_name);
9825b398 508 else
bf95c10a 509 debugs(11, 5, "Creating credential cache");
aee3523a 510 rc = krb5_create_cache(nullptr, principal_name);
9825b398 511 if (rc) {
bf95c10a 512 debugs(11, 5, "Error : Failed to create Kerberos cache");
9825b398 513 krb5_cleanup();
aee3523a 514 return nullptr;
9825b398 515 }
f53969cc 516 }
f54f527e 517
f53969cc
SM
518 service.value = (void *) xmalloc(strlen("HTTP") + strlen(proxy) + 2);
519 snprintf((char *) service.value, strlen("HTTP") + strlen(proxy) + 2,
520 "%s@%s", "HTTP", proxy);
521 service.length = strlen((char *) service.value);
522
bf95c10a 523 debugs(11, 5, "Import gss name");
f53969cc
SM
524 major_status = gss_import_name(&minor_status, &service,
525 gss_nt_service_name, &server_name);
526
527 if (check_gss_err(major_status, minor_status, "gss_import_name()"))
528 goto cleanup;
529
bf95c10a 530 debugs(11, 5, "Initialize gss security context");
f53969cc
SM
531 major_status = gss_init_sec_context(&minor_status,
532 GSS_C_NO_CREDENTIAL,
533 &gss_context,
534 server_name,
535 gss_mech_spnego,
536 0,
537 0,
538 GSS_C_NO_CHANNEL_BINDINGS,
aee3523a 539 &input_token, nullptr, &output_token, nullptr, nullptr);
f53969cc
SM
540
541 if (check_gss_err(major_status, minor_status, "gss_init_sec_context()"))
542 goto cleanup;
543
bf95c10a 544 debugs(11, 5, "Got token with length " << output_token.length);
f53969cc 545 if (output_token.length) {
1d11e9b3 546 static char b64buf[8192]; // XXX: 8KB only because base64_encode_bin() used to.
aadbbd7d
AJ
547 struct base64_encode_ctx ctx;
548 base64_encode_init(&ctx);
549 size_t blen = base64_encode_update(&ctx, b64buf, output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
550 blen += base64_encode_final(&ctx, b64buf+blen);
551 b64buf[blen] = '\0';
552
553 token = reinterpret_cast<char*>(b64buf);
9ca29d23
AJ
554 }
555
f53969cc 556cleanup:
aee3523a 557 gss_delete_sec_context(&minor_status, &gss_context, nullptr);
f53969cc
SM
558 gss_release_buffer(&minor_status, &service);
559 gss_release_buffer(&minor_status, &input_token);
560 gss_release_buffer(&minor_status, &output_token);
561 gss_release_name(&minor_status, &server_name);
562
563 return token;
564}
565
8b082ed9 566#endif /* HAVE_AUTH_MODULE_NEGOTIATE && HAVE_KRB5 && HAVE_GSSAPI */
f53969cc 567