37#if HAVE_LDAP && HAVE_KRB5
42extern struct kstruct kparam;
45#define KT_PATH_MAX 256
51 for (
int i=0; i<MAX_DOMAINS; i++) {
53 krb5_cc_destroy(kparam.context, kparam.cc[i]);
56 krb5_free_context(kparam.context);
60k5_error2(
const char* msg,
char* msg2, krb5_error_code
code)
63 errmsg = krb5_get_error_message(kparam.context,
code);
65#if HAVE_KRB5_FREE_ERROR_MESSAGE
66 krb5_free_error_message(kparam.context, errmsg);
67#elif HAVE_KRB5_FREE_ERROR_STRING
68 krb5_free_error_string(kparam.context, (
char *)errmsg);
75k5_debug(
const char* msg, krb5_error_code
code)
78 errmsg = krb5_get_error_message(kparam.context,
code);
80#if HAVE_KRB5_FREE_ERROR_MESSAGE
81 krb5_free_error_message(kparam.context, errmsg);
82#elif HAVE_KRB5_FREE_ERROR_STRING
83 krb5_free_error_string(kparam.context, (
char *)errmsg);
90k5_error(
const char* msg, krb5_error_code
code)
92 k5_error2(msg, (
char *)
"",
code);
99krb5_create_cache(
char *domain,
char *service_principal_name)
102 krb5_keytab keytab =
nullptr;
103 krb5_keytab_entry entry;
104 krb5_kt_cursor cursor;
105 krb5_cc_cursor ccursor;
106 krb5_creds *creds =
nullptr;
107 krb5_principal *principal_list =
nullptr;
108 krb5_principal principal =
nullptr;
110 char *keytab_name =
nullptr, *principal_name =
nullptr, *mem_cache =
nullptr;
111 char buf[KT_PATH_MAX], *p;
114 krb5_error_code
code = 0;
117 if (!domain || !strcmp(domain,
""))
123#if !HAVE_KRB5_MEMORY_CACHE || HAVE_SUN_LDAP_SDK
124 mem_cache = (
char *)
xmalloc(strlen(
"FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16);
125 snprintf(mem_cache, strlen(
"FILE:/tmp/squid_ldap_") + strlen(domain) + 1 + 16,
"FILE:/tmp/squid_ldap_%s_%d", domain, (
int) getpid());
127 mem_cache = (
char *)
xmalloc(strlen(
"MEMORY:squid_ldap_") + strlen(domain) + 1 + 16);
128 snprintf(mem_cache, strlen(
"MEMORY:squid_ldap_") + strlen(domain) + 1 + 16,
"MEMORY:squid_ldap_%s_%d", domain, (
int) getpid());
131 setenv(
"KRB5CCNAME", mem_cache, 1);
132 debug((
char *)
"%s| %s: DEBUG: Set credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
133 for (
int i=0; i<MAX_DOMAINS; i++) {
134 if (kparam.mem_ccache[i] && !strcmp(mem_cache,kparam.mem_ccache[i])) {
139 if ( ccindex == -1 ) {
140 kparam.mem_ccache[kparam.ncache]=
xstrdup(mem_cache);
141 ccindex=kparam.ncache;
143 if ( kparam.ncache == MAX_DOMAINS ) {
144 error((
char *)
"%s| %s: ERROR: Too many domains to support: # domains %d\n",
LogTime(),
PROGRAM, kparam.ncache);
148 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
150 k5_error(
"Error while resolving memory ccache",
code);
159 code = krb5_cc_get_principal(kparam.context, kparam.cc[ccindex], &principal);
162 krb5_free_principal(kparam.context, principal);
164 k5_debug(
"No default principal found in ccache",
code);
169 code = krb5_cc_start_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
171 k5_error(
"Error while starting ccache scan",
code);
172 code = krb5_cc_close (kparam.context, kparam.cc[ccindex]);
174 k5_error(
"Error while closing ccache",
code);
176 if (kparam.cc[ccindex]) {
177 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
179 k5_error(
"Error while destroying ccache",
code);
183 krb5_error_code code2 = 0;
184 creds =
static_cast<krb5_creds *
>(
xcalloc(1,
sizeof(*creds)));
185 while ((krb5_cc_next_cred(kparam.context, kparam.cc[ccindex], &ccursor, creds)) == 0) {
186 code2 = krb5_unparse_name(kparam.context, creds->server, &principal_name);
188 k5_error(
"Error while unparsing principal", code2);
189 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
191 k5_error(
"Error while destroying ccache",
code);
194 krb5_free_creds(kparam.context, creds);
197 debug((
char *)
"%s| %s: DEBUG: Reset credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
198 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
200 k5_error(
"Error while resolving memory ccache",
code);
207 if (!strncmp(KRB5_TGS_NAME,principal_name,KRB5_TGS_NAME_SIZE)) {
209 static krb5_deltat skew=MAX_SKEW;
211 debug((
char *)
"%s| %s: DEBUG: Found %s in cache : %s\n",
LogTime(),
PROGRAM,KRB5_TGS_NAME,principal_name);
216 debug((
char *)
"%s| %s: DEBUG: credential time diff %d\n",
LogTime(),
PROGRAM, (
int)(creds->times.endtime -
now));
217 if (creds->times.endtime -
now < 2*skew) {
218 debug((
char *)
"%s| %s: DEBUG: credential will soon expire %d\n",
LogTime(),
PROGRAM, (
int)(creds->times.endtime -
now));
220 krb5_free_principal(kparam.context, principal);
222 code = krb5_cc_destroy(kparam.context, kparam.cc[ccindex]);
224 k5_error(
"Error while destroying ccache",
code);
227 krb5_free_creds(kparam.context, creds);
230 debug((
char *)
"%s| %s: DEBUG: Reset credential cache to %s\n",
LogTime(),
PROGRAM, mem_cache);
231 code = krb5_cc_resolve(kparam.context, mem_cache, &kparam.cc[ccindex]);
233 k5_error(
"Error while resolving ccache",
code);
244 krb5_free_creds(kparam.context, creds);
245 creds =
static_cast<krb5_creds *
>(
xcalloc(1,
sizeof(*creds)));
249 krb5_free_creds(kparam.context, creds);
251 code2 = krb5_cc_end_seq_get(kparam.context, kparam.cc[ccindex], &ccursor);
253 k5_error(
"Error while ending ccache scan", code2);
265 krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
266 p = strchr(buf,
':');
269 keytab_name =
xstrdup(p ? p : buf);
270 debug((
char *)
"%s| %s: DEBUG: Got default keytab file name %s\n",
LogTime(),
PROGRAM, keytab_name);
272 code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
274 k5_error2(
"Error while resolving keytab ", keytab_name,
code);
278 code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
280 k5_error(
"Error while starting keytab scan",
code);
284 debug((
char *)
"%s| %s: DEBUG: Get principal name from keytab %s\n",
LogTime(),
PROGRAM, keytab_name);
287 while ((
code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) {
290 principal_list = (krb5_principal *)
xrealloc(principal_list,
sizeof(krb5_principal) * (nprinc + 1));
291 krb5_copy_principal(kparam.context, entry.principal, &principal_list[nprinc++]);
293 debug((
char *)
"%s| %s: DEBUG: Keytab entry has realm name: %s\n",
LogTime(),
PROGRAM, entry.principal->realm);
295 debug((
char *)
"%s| %s: DEBUG: Keytab entry has realm name: %s\n",
LogTime(),
PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
298 if (!strcasecmp(domain, entry.principal->realm))
300 if (!strcasecmp(domain, krb5_princ_realm(kparam.context, entry.principal)->data))
303 code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
305 k5_error(
"Error while unparsing principal name",
code);
307 debug((
char *)
"%s| %s: DEBUG: Found principal name: %s\n",
LogTime(),
PROGRAM, principal_name);
309 if (service_principal_name && strcasecmp(principal_name,service_principal_name) != 0 ) {
310 debug((
char *)
"%s| %s: DEBUG: principal name does not match parameter: %s\n",
LogTime(),
PROGRAM, service_principal_name);
316#if USE_HEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
317 code = krb5_kt_free_entry(kparam.context, &entry);
319 code = krb5_free_keytab_entry_contents(kparam.context, &entry);
322 k5_error(
"Error while freeing keytab entry",
code);
327 debug((
char *)
"%s| %s: DEBUG: Got principal name %s\n",
LogTime(),
PROGRAM, principal_name);
331 code = krb5_parse_name(kparam.context, principal_name, &principal);
333 k5_error2(
"Error while parsing name ", principal_name,
code);
336 krb5_free_principal(kparam.context, principal);
340 creds = (krb5_creds *)
xcalloc(1,
sizeof(*creds));
345#if HAVE_GET_INIT_CREDS_KEYTAB
346 code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0,
nullptr,
nullptr);
348 service = (
char *)
xmalloc(strlen(
"krbtgt") + 2 * strlen(domain) + 3);
349 snprintf(service, strlen(
"krbtgt") + 2 * strlen(domain) + 3,
"krbtgt/%s@%s", domain, domain);
350 creds->client = principal;
351 code = krb5_parse_name(kparam.context, service, &creds->server);
353 code = krb5_get_in_tkt_with_keytab(kparam.context, 0,
nullptr,
nullptr,
nullptr, keytab,
nullptr, creds, 0);
357 k5_error(
"Error while initialising credentials from keytab",
code);
360 krb5_free_principal(kparam.context, principal);
362 krb5_free_creds(kparam.context, creds);
367 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal);
369 k5_error(
"Error while initialising cache",
code);
372 krb5_free_principal(kparam.context, principal);
374 krb5_free_creds(kparam.context, creds);
379 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
381 k5_error(
"Error while storing credentials",
code);
383 krb5_free_principal(kparam.context, principal);
386 krb5_free_creds(kparam.context, creds);
397 k5_error(
"Error while scanning keytab",
code);
401 code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
403 k5_error(
"Error while ending keytab scan",
code);
411 if (!principal_name && !service_principal_name) {
413 debug((
char *)
"%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n",
LogTime(),
PROGRAM, domain);
414 debug((
char *)
"%s| %s: DEBUG: Try to get principal of trusted domain.\n",
LogTime(),
PROGRAM);
416 for (i = 0; i < nprinc; ++i) {
417 krb5_creds *tgt_creds =
nullptr;
418 creds = (krb5_creds *)
xmalloc(
sizeof(*creds));
419 memset(creds, 0,
sizeof(*creds));
423 code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
425 k5_error(
"Error while unparsing principal name",
code);
428 debug((
char *)
"%s| %s: DEBUG: Keytab entry has principal: %s\n",
LogTime(),
PROGRAM, principal_name);
430#if HAVE_GET_INIT_CREDS_KEYTAB
431 code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0,
nullptr,
nullptr);
433 service = (
char *)
xmalloc(strlen(
"krbtgt") + 2 * strlen(domain) + 3);
434 snprintf(service, strlen(
"krbtgt") + 2 * strlen(domain) + 3,
"krbtgt/%s@%s", domain, domain);
435 creds->client = principal_list[i];
436 code = krb5_parse_name(kparam.context, service, &creds->server);
438 code = krb5_get_in_tkt_with_keytab(kparam.context, 0,
nullptr,
nullptr,
nullptr, keytab,
nullptr, creds, 0);
441 k5_error(
"Error while initialising credentials from keytab",
code);
444 code = krb5_cc_initialize(kparam.context, kparam.cc[ccindex], principal_list[i]);
446 k5_error(
"Error while initialising memory caches",
code);
449 code = krb5_cc_store_cred(kparam.context, kparam.cc[ccindex], creds);
451 k5_error(
"Error while storing credentials",
code);
455 krb5_free_principal(kparam.context, creds->server);
457 service = (
char *)
xmalloc(strlen(
"krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3);
458 snprintf(service, strlen(
"krbtgt") + strlen(domain) + strlen(principal_list[i]->realm) + 3,
"krbtgt/%s@%s", domain, principal_list[i]->realm);
460 service = (
char *)
xmalloc(strlen(
"krbtgt") + strlen(domain) + strlen(krb5_princ_realm(kparam.context, principal_list[i])->data) + 3);
461 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);
463 code = krb5_parse_name(kparam.context, service, &creds->server);
466 k5_error(
"Error while initialising TGT credentials",
code);
472 creds->session.keytype = 0;
473 if (creds->session.keyvalue.length > 0)
474 krb5_free_keyblock_contents(kparam.context, &creds->session);
476 creds->keyblock.enctype = 0;
477 if (creds->keyblock.contents)
478 krb5_free_keyblock_contents(kparam.context, &creds->keyblock);
480 code = krb5_get_credentials(kparam.context, 0, kparam.cc[ccindex], creds, &tgt_creds);
482 k5_error(
"Error while getting tgt",
code);
485 debug((
char *)
"%s| %s: DEBUG: Found trusted principal name: %s\n",
LogTime(),
PROGRAM, principal_name);
487 krb5_free_creds(kparam.context, tgt_creds);
495 krb5_free_creds(kparam.context, tgt_creds);
498 krb5_free_creds(kparam.context, creds);
504 krb5_free_creds(kparam.context, creds);
512 code = krb5_unparse_name(kparam.context, principal, &principal_name);
514 k5_error(
"Error while unparsing principal name",
code);
518 debug((
char *)
"%s| %s: DEBUG: ccache has principal: %s\n",
LogTime(),
PROGRAM, principal_name);
521 if (!principal_name) {
527 krb5_kt_close(kparam.context, keytab);
529 xfree(principal_name);
532 krb5_free_principal(kparam.context, principal);
533 for (j = 0; j < nprinc; ++j) {
534 if (principal_list[j])
535 krb5_free_principal(kparam.context, principal_list[j]);
537 xfree(principal_list);
539 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)