36#if HAVE_LDAP && HAVE_KRB5
41extern struct kstruct kparam;
44#define KT_PATH_MAX 256
50 for (
int i=0; i<MAX_DOMAINS; i++) {
52 krb5_cc_destroy(kparam.context, kparam.cc[i]);
55 krb5_free_context(kparam.context);
59k5_error2(
const char* msg,
char* msg2, krb5_error_code code)
62 errmsg = krb5_get_error_message(kparam.context, code);
64#if HAVE_KRB5_FREE_ERROR_MESSAGE
65 krb5_free_error_message(kparam.context, errmsg);
66#elif HAVE_KRB5_FREE_ERROR_STRING
67 krb5_free_error_string(kparam.context, (
char *)errmsg);
74k5_debug(
const char* msg, krb5_error_code code)
77 errmsg = krb5_get_error_message(kparam.context, code);
79#if HAVE_KRB5_FREE_ERROR_MESSAGE
80 krb5_free_error_message(kparam.context, errmsg);
81#elif HAVE_KRB5_FREE_ERROR_STRING
82 krb5_free_error_string(kparam.context, (
char *)errmsg);
89k5_error(
const char* msg, krb5_error_code code)
91 k5_error2(msg, (
char *)
"", code);
98krb5_create_cache(
char *domain,
char *service_principal_name)
101 krb5_keytab keytab =
nullptr;
102 krb5_keytab_entry entry;
103 krb5_kt_cursor cursor;
104 krb5_cc_cursor ccursor;
105 krb5_creds *creds =
nullptr;
106 krb5_principal *principal_list =
nullptr;
107 krb5_principal principal =
nullptr;
109 char *keytab_name =
nullptr, *principal_name =
nullptr, *mem_cache =
nullptr;
110 char buf[KT_PATH_MAX], *p;
113 krb5_error_code code = 0;
116 if (!domain || !strcmp(domain,
""))
122#if !HAVE_KRB5_MEMORY_CACHE || HAVE_SUN_LDAP_SDK
123 mem_cache = (
char *)
xmalloc(strlen(
"FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16);
124 snprintf(mem_cache, strlen(
"FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16,
"FILE:/tmp/squid_ldap_%s_%d", domain, (
int) getpid());
126 mem_cache = (
char *)
xmalloc(strlen(
"MEMORY:squid_ldap_") + strlen(domain) + 1 + 16);
127 snprintf(mem_cache, strlen(
"MEMORY:squid_ldap_") + strlen(domain) + 1 + 16,
"MEMORY:squid_ldap_%s_%d", domain, (
int) getpid());
130 setenv(
"KRB5CCNAME", mem_cache, 1);
131 debug((
char *)
"%s| %s: DEBUG: Set credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
132 for (
int i=0; i<MAX_DOMAINS; i++) {
133 if (kparam.mem_ccache[i] && !strcmp(mem_cache,kparam.mem_ccache[i])) {
138 if ( ccindex == -1 ) {
139 kparam.mem_ccache[kparam.ncache]=
xstrdup(mem_cache);
140 ccindex=kparam.ncache;
142 if ( kparam.ncache == MAX_DOMAINS ) {
143 error((
char *)
"%s| %s: ERROR: Too many domains to support: # domains %d\n",
LogTime(),
PROGRAM, kparam.ncache);
147 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
149 k5_error(
"Error while resolving memory ccache", code);
158 code = krb5_cc_get_principal(kparam.context, kparam.cc[ccindex], &principal);
161 krb5_free_principal(kparam.context, principal);
163 k5_debug(
"No default principal found in ccache", code);
168 code = krb5_cc_start_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
170 k5_error(
"Error while starting ccache scan", code);
171 code = krb5_cc_close (kparam.context, kparam.cc[ccindex]);
173 k5_error(
"Error while closing ccache", code);
175 if (kparam.cc[ccindex]) {
176 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
178 k5_error(
"Error while destroying ccache", code);
182 krb5_error_code code2 = 0;
183 creds =
static_cast<krb5_creds *
>(
xcalloc(1,
sizeof(*creds)));
184 while ((krb5_cc_next_cred(kparam.context, kparam.cc[ccindex], &ccursor, creds)) == 0) {
185 code2 = krb5_unparse_name(kparam.context, creds->server, &principal_name);
187 k5_error(
"Error while unparsing principal", code2);
188 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
190 k5_error(
"Error while destroying ccache", code);
193 krb5_free_creds(kparam.context, creds);
196 debug((
char *)
"%s| %s: DEBUG: Reset credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
197 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
199 k5_error(
"Error while resolving memory ccache", code);
206 if (!strncmp(KRB5_TGS_NAME,principal_name,KRB5_TGS_NAME_SIZE)) {
208 static krb5_deltat skew=MAX_SKEW;
210 debug((
char *)
"%s| %s: DEBUG: Found %s in cache : %s\n",
LogTime(),
PROGRAM,KRB5_TGS_NAME,principal_name);
215 debug((
char *)
"%s| %s: DEBUG: credential time diff %d\n",
LogTime(),
PROGRAM, (
int)(creds->times.endtime - now));
216 if (creds->times.endtime - now < 2*skew) {
217 debug((
char *)
"%s| %s: DEBUG: credential will soon expire %d\n",
LogTime(),
PROGRAM, (
int)(creds->times.endtime - now));
219 krb5_free_principal(kparam.context, principal);
221 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
223 k5_error(
"Error while destroying ccache", code);
226 krb5_free_creds(kparam.context, creds);
229 debug((
char *)
"%s| %s: DEBUG: Reset credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
230 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
232 k5_error(
"Error while resolving ccache", code);
243 krb5_free_creds(kparam.context, creds);
244 creds =
static_cast<krb5_creds *
>(
xcalloc(1,
sizeof(*creds)));
248 krb5_free_creds(kparam.context, creds);
250 code2 = krb5_cc_end_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
252 k5_error(
"Error while ending ccache scan", code2);
264 krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
265 p = strchr(buf,
':');
268 keytab_name =
xstrdup(p ? p : buf);
269 debug((
char *)
"%s| %s: DEBUG: Got default keytab file name %s\n",
LogTime(),
PROGRAM, keytab_name);
271 code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
273 k5_error2(
"Error while resolving keytab ", keytab_name,code);
277 code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
279 k5_error(
"Error while starting keytab scan", code);
283 debug((
char *)
"%s| %s: DEBUG: Get principal name from keytab %s\n",
LogTime(),
PROGRAM, keytab_name);
286 while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) {
289 principal_list = (krb5_principal *)
xrealloc(principal_list,
sizeof(krb5_principal) * (nprinc + 1));
290 krb5_copy_principal(kparam.context, entry.principal, &principal_list[nprinc++]);
291#if HAVE_LIBHEIMDAL_KRB5
292 debug((
char *)
"%s| %s: DEBUG: Keytab entry has realm name: %s\n",
LogTime(),
PROGRAM, entry.principal->realm);
294 debug((
char *)
"%s| %s: DEBUG: Keytab entry has realm name: %s\n",
LogTime(),
PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
296#if HAVE_LIBHEIMDAL_KRB5
297 if (!strcasecmp(domain, entry.principal->realm))
299 if (!strcasecmp(domain, krb5_princ_realm(kparam.context, entry.principal)->data))
302 code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
304 k5_error(
"Error while unparsing principal name", code);
306 debug((
char *)
"%s| %s: DEBUG: Found principal name: %s\n",
LogTime(),
PROGRAM, principal_name);
308 if (service_principal_name && strcasecmp(principal_name,service_principal_name) != 0 ) {
309 debug((
char *)
"%s| %s: DEBUG: principal name does not match parameter: %s\n",
LogTime(),
PROGRAM, service_principal_name);
315#if HAVE_LIBHEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
316 code = krb5_kt_free_entry(kparam.context, &entry);
318 code = krb5_free_keytab_entry_contents(kparam.context, &entry);
321 k5_error(
"Error while freeing keytab entry", code);
326 debug((
char *)
"%s| %s: DEBUG: Got principal name %s\n",
LogTime(),
PROGRAM, principal_name);
330 code = krb5_parse_name(kparam.context, principal_name, &principal);
332 k5_error2(
"Error while parsing name ", principal_name,code);
335 krb5_free_principal(kparam.context, principal);
339 creds = (krb5_creds *)
xcalloc(1,
sizeof(*creds));
344#if HAVE_GET_INIT_CREDS_KEYTAB
345 code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0,
nullptr,
nullptr);
347 service = (
char *)
xmalloc(strlen(
"krbtgt") + 2 * strlen(domain) + 3);
348 snprintf(service, strlen(
"krbtgt") + 2 * strlen(domain) + 3,
"krbtgt/%s@%s", domain, domain);
349 creds->client = principal;
350 code = krb5_parse_name(kparam.context, service, &creds->server);
352 code = krb5_get_in_tkt_with_keytab(kparam.context, 0,
nullptr,
nullptr,
nullptr, keytab,
nullptr, creds, 0);
356 k5_error(
"Error while initialising credentials from keytab", code);
359 krb5_free_principal(kparam.context, principal);
361 krb5_free_creds(kparam.context, creds);
366 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal);
368 k5_error(
"Error while initialising cache", code);
371 krb5_free_principal(kparam.context, principal);
373 krb5_free_creds(kparam.context, creds);
378 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
380 k5_error(
"Error while storing credentials", code);
382 krb5_free_principal(kparam.context, principal);
385 krb5_free_creds(kparam.context, creds);
395 if (code && code != KRB5_KT_END) {
396 k5_error(
"Error while scanning keytab", code);
400 code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
402 k5_error(
"Error while ending keytab scan", code);
410 if (!principal_name && !service_principal_name) {
412 debug((
char *)
"%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n",
LogTime(),
PROGRAM, domain);
413 debug((
char *)
"%s| %s: DEBUG: Try to get principal of trusted domain.\n",
LogTime(),
PROGRAM);
415 for (i = 0; i < nprinc; ++i) {
416 krb5_creds *tgt_creds =
nullptr;
417 creds = (krb5_creds *)
xmalloc(
sizeof(*creds));
418 memset(creds, 0,
sizeof(*creds));
422 code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
424 k5_error(
"Error while unparsing principal name", code);
427 debug((
char *)
"%s| %s: DEBUG: Keytab entry has principal: %s\n",
LogTime(),
PROGRAM, principal_name);
429#if HAVE_GET_INIT_CREDS_KEYTAB
430 code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0,
nullptr,
nullptr);
432 service = (
char *)
xmalloc(strlen(
"krbtgt") + 2 * strlen(domain) + 3);
433 snprintf(service, strlen(
"krbtgt") + 2 * strlen(domain) + 3,
"krbtgt/%s@%s", domain, domain);
434 creds->client = principal_list[i];
435 code = krb5_parse_name(kparam.context, service, &creds->server);
437 code = krb5_get_in_tkt_with_keytab(kparam.context, 0,
nullptr,
nullptr,
nullptr, keytab,
nullptr, creds, 0);
440 k5_error(
"Error while initialising credentials from keytab", code);
443 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal_list[i]);
445 k5_error(
"Error while initialising memory caches", code);
448 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
450 k5_error(
"Error while storing credentials", code);
454 krb5_free_principal(kparam.context, creds->server);
455#if HAVE_LIBHEIMDAL_KRB5
456 service = (
char *)
xmalloc(strlen(
"krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3);
457 snprintf(service, strlen(
"krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3,
"krbtgt/%s@%s", domain, principal_list[i]->realm);
459 service = (
char *)
xmalloc(strlen(
"krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3);
460 snprintf(service, strlen(
"krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3,
"krbtgt/%s@%s", domain, krb5_princ_realm(kparam.context, principal_list[i])->data);
462 code = krb5_parse_name(kparam.context, service, &creds->server);
465 k5_error(
"Error while initialising TGT credentials", code);
470#if HAVE_LIBHEIMDAL_KRB5
471 creds->session.keytype = 0;
472 if (creds->session.keyvalue.length > 0)
473 krb5_free_keyblock_contents(kparam.context, &creds->session);
475 creds->keyblock.enctype = 0;
476 if (creds->keyblock.contents)
477 krb5_free_keyblock_contents(kparam.context, &creds->keyblock);
479 code = krb5_get_credentials(kparam.context, 0, kparam.cc[ccindex], creds, &tgt_creds);
481 k5_error(
"Error while getting tgt", code);
484 debug((
char *)
"%s| %s: DEBUG: Found trusted principal name: %s\n",
LogTime(),
PROGRAM, principal_name);
486 krb5_free_creds(kparam.context, tgt_creds);
494 krb5_free_creds(kparam.context, tgt_creds);
497 krb5_free_creds(kparam.context, creds);
503 krb5_free_creds(kparam.context, creds);
511 code = krb5_unparse_name(kparam.context, principal, &principal_name);
513 k5_error(
"Error while unparsing principal name", code);
517 debug((
char *)
"%s| %s: DEBUG: ccache has principal: %s\n",
LogTime(),
PROGRAM, principal_name);
520 if (!principal_name) {
526 krb5_kt_close(kparam.context, keytab);
528 xfree(principal_name);
531 krb5_free_principal(kparam.context, principal);
532 for (j = 0; j < nprinc; ++j) {
533 if (principal_list[j])
534 krb5_free_principal(kparam.context, principal_list[j]);
536 xfree(principal_list);
538 krb5_free_creds(kparam.context, creds);
void error(char *format,...)
const char * LogTime(void)
void debug(const char *format,...)
void * xrealloc(void *s, size_t sz)
void * xcalloc(size_t n, size_t sz)