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