]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/external/kerberos_ldap_group/support_krb5.cc
2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
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.
10 * ----------------------------------------------------------------------------
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
30 * -----------------------------------------------------------------------------
36 #if HAVE_LDAP && HAVE_KRB5
41 extern 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
]);
53 safe_free(kparam
.mem_ccache
[i
]);
55 krb5_free_context(kparam
.context
);
59 k5_error2(const char* msg
, char* msg2
, krb5_error_code code
)
62 errmsg
= krb5_get_error_message(kparam
.context
, code
);
63 error((char *) "%s| %s: ERROR: %s%s : %s\n", LogTime(), PROGRAM
, msg
, msg2
, errmsg
);
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
);
74 k5_error(const char* msg
, krb5_error_code code
)
76 k5_error2(msg
, (char *)"", code
);
80 * create Kerberos memory cache
83 krb5_create_cache(char *domain
)
86 krb5_keytab keytab
= NULL
;
87 krb5_keytab_entry entry
;
88 krb5_kt_cursor cursor
;
89 krb5_cc_cursor ccursor
;
90 krb5_creds
*creds
= NULL
;
91 krb5_principal
*principal_list
= NULL
;
92 krb5_principal principal
= NULL
;
94 char *keytab_name
= NULL
, *principal_name
= NULL
, *mem_cache
= NULL
;
95 char buf
[KT_PATH_MAX
], *p
;
98 krb5_error_code code
= 0;
101 if (!domain
|| !strcmp(domain
, ""))
105 * prepare memory credential cache
107 #if !HAVE_KRB5_MEMORY_CACHE || HAVE_SUN_LDAP_SDK
108 mem_cache
= (char *) xmalloc(strlen("FILE:/tmp/squid_ldap_") + strlen(domain
) + 1 + 16);
109 snprintf(mem_cache
, strlen("FILE:/tmp/squid_ldap_") + strlen(domain
) + 1 + 16, "FILE:/tmp/squid_ldap_%s_%d", domain
, (int) getpid());
111 mem_cache
= (char *) xmalloc(strlen("MEMORY:squid_ldap_") + strlen(domain
) + 1 + 16);
112 snprintf(mem_cache
, strlen("MEMORY:squid_ldap_") + strlen(domain
) + 1 + 16, "MEMORY:squid_ldap_%s_%d", domain
, (int) getpid());
115 setenv("KRB5CCNAME", mem_cache
, 1);
116 debug((char *) "%s| %s: DEBUG: Set credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
117 for (int i
=0; i
<MAX_DOMAINS
; i
++) {
118 if (kparam
.mem_ccache
[i
] && !strcmp(mem_cache
,kparam
.mem_ccache
[i
])) {
123 if ( ccindex
== -1 ) {
124 kparam
.mem_ccache
[kparam
.ncache
]=xstrdup(mem_cache
);
125 ccindex
=kparam
.ncache
;
127 if ( kparam
.ncache
== MAX_DOMAINS
) {
128 error((char *) "%s| %s: ERROR: Too many domains to support: # domains %d\n", LogTime(), PROGRAM
, kparam
.ncache
);
132 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
134 k5_error("Error while resolving memory ccache",code
);
140 * getting default principal from cache
143 code
= krb5_cc_get_principal(kparam
.context
, kparam
.cc
[ccindex
], &principal
);
146 krb5_free_principal(kparam
.context
, principal
);
148 k5_error("No default principal found in ccache",code
);
151 * Look for krbtgt and check if it is expired (or soon to be expired)
153 code
= krb5_cc_start_seq_get(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
);
155 k5_error("Error while starting ccache scan",code
);
156 code
= krb5_cc_close (kparam
.context
, kparam
.cc
[ccindex
]);
158 k5_error("Error while closing ccache",code
);
160 if (kparam
.cc
[ccindex
]) {
161 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
163 k5_error("Error while destroying ccache",code
);
167 krb5_error_code code2
= 0;
168 creds
= static_cast<krb5_creds
*>(xcalloc(1,sizeof(*creds
)));
169 while ((krb5_cc_next_cred(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
, creds
)) == 0) {
170 code2
= krb5_unparse_name(kparam
.context
, creds
->server
, &principal_name
);
172 k5_error("Error while unparsing principal",code2
);
173 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
175 k5_error("Error while destroying ccache",code
);
177 assert(creds
!= NULL
);
178 krb5_free_creds(kparam
.context
, creds
);
180 safe_free(principal_name
);
181 debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
182 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
184 k5_error("Error while resolving memory ccache",code
);
191 if (!strncmp(KRB5_TGS_NAME
,principal_name
,KRB5_TGS_NAME_SIZE
)) {
193 static krb5_deltat skew
=MAX_SKEW
;
195 debug((char *) "%s| %s: DEBUG: Found %s in cache : %s\n", LogTime(), PROGRAM
,KRB5_TGS_NAME
,principal_name
);
200 debug((char *) "%s| %s: DEBUG: credential time diff %d\n", LogTime(), PROGRAM
, (int)(creds
->times
.endtime
- now
));
201 if (creds
->times
.endtime
- now
< 2*skew
) {
202 debug((char *) "%s| %s: DEBUG: credential will soon expire %d\n", LogTime(), PROGRAM
, (int)(creds
->times
.endtime
- now
));
204 krb5_free_principal(kparam
.context
, principal
);
206 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
208 k5_error("Error while destroying ccache",code
);
210 assert(creds
!= NULL
);
211 krb5_free_creds(kparam
.context
, creds
);
213 safe_free(principal_name
);
214 debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
215 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
217 k5_error("Error while resolving ccache",code
);
223 safe_free(principal_name
);
227 assert(creds
!= NULL
);
228 krb5_free_creds(kparam
.context
, creds
);
229 creds
= static_cast<krb5_creds
*>(xcalloc(1, sizeof(*creds
)));
230 safe_free(principal_name
);
233 krb5_free_creds(kparam
.context
, creds
);
235 code2
= krb5_cc_end_seq_get(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
);
237 k5_error("Error while ending ccache scan",code2
);
245 * getting default keytab name
248 debug((char *) "%s| %s: DEBUG: Get default keytab file name\n", LogTime(), PROGRAM
);
249 krb5_kt_default_name(kparam
.context
, buf
, KT_PATH_MAX
);
250 p
= strchr(buf
, ':'); /* Find the end if "FILE:" */
252 ++p
; /* step past : */
253 keytab_name
= xstrdup(p
? p
: buf
);
254 debug((char *) "%s| %s: DEBUG: Got default keytab file name %s\n", LogTime(), PROGRAM
, keytab_name
);
256 code
= krb5_kt_resolve(kparam
.context
, keytab_name
, &keytab
);
258 k5_error2("Error while resolving keytab ",keytab_name
,code
);
262 code
= krb5_kt_start_seq_get(kparam
.context
, keytab
, &cursor
);
264 k5_error("Error while starting keytab scan",code
);
268 debug((char *) "%s| %s: DEBUG: Get principal name from keytab %s\n", LogTime(), PROGRAM
, keytab_name
);
271 while ((code
= krb5_kt_next_entry(kparam
.context
, keytab
, &entry
, &cursor
)) == 0) {
274 principal_list
= (krb5_principal
*) xrealloc(principal_list
, sizeof(krb5_principal
) * (nprinc
+ 1));
275 krb5_copy_principal(kparam
.context
, entry
.principal
, &principal_list
[nprinc
++]);
277 debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM
, entry
.principal
->realm
);
279 debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM
, krb5_princ_realm(kparam
.context
, entry
.principal
)->data
);
282 if (!strcasecmp(domain
, entry
.principal
->realm
))
284 if (!strcasecmp(domain
, krb5_princ_realm(kparam
.context
, entry
.principal
)->data
))
287 code
= krb5_unparse_name(kparam
.context
, entry
.principal
, &principal_name
);
289 k5_error("Error while unparsing principal name",code
);
291 debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM
, principal_name
);
295 #if USE_HEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
296 code
= krb5_kt_free_entry(kparam
.context
, &entry
);
298 code
= krb5_free_keytab_entry_contents(kparam
.context
, &entry
);
301 k5_error("Error while freeing keytab entry",code
);
306 debug((char *) "%s| %s: DEBUG: Got principal name %s\n", LogTime(), PROGRAM
, principal_name
);
310 code
= krb5_parse_name(kparam
.context
, principal_name
, &principal
);
312 k5_error2("Error while parsing name ", principal_name
,code
);
313 safe_free(principal_name
);
315 krb5_free_principal(kparam
.context
, principal
);
319 creds
= (krb5_creds
*) xcalloc(1,sizeof(*creds
));
324 #if HAVE_GET_INIT_CREDS_KEYTAB
325 code
= krb5_get_init_creds_keytab(kparam
.context
, creds
, principal
, keytab
, 0, NULL
, NULL
);
327 service
= (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain
) + 3);
328 snprintf(service
, strlen("krbtgt") + 2 * strlen(domain
) + 3, "krbtgt/%s@%s", domain
, domain
);
329 creds
->client
= principal
;
330 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
332 code
= krb5_get_in_tkt_with_keytab(kparam
.context
, 0, NULL
, NULL
, NULL
, keytab
, NULL
, creds
, 0);
336 k5_error("Error while initialising credentials from keytab" ,code
);
337 safe_free(principal_name
);
339 krb5_free_principal(kparam
.context
, principal
);
341 krb5_free_creds(kparam
.context
, creds
);
346 code
= krb5_cc_initialize(kparam
.context
, kparam
.cc
[ccindex
], principal
);
348 k5_error("Error while initialising memory caches" ,code
);
349 safe_free(principal_name
);
351 krb5_free_principal(kparam
.context
, principal
);
353 krb5_free_creds(kparam
.context
, creds
);
358 code
= krb5_cc_store_cred(kparam
.context
, kparam
.cc
[ccindex
], creds
);
360 k5_error("Error while storing credentials" ,code
);
362 krb5_free_principal(kparam
.context
, principal
);
363 safe_free(principal_name
);
365 krb5_free_creds(kparam
.context
, creds
);
370 debug((char *) "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM
);
375 if (code
&& code
!= KRB5_KT_END
) {
376 k5_error("Error while scanning keytab" ,code
);
380 code
= krb5_kt_end_seq_get(kparam
.context
, keytab
, &cursor
);
382 k5_error("Error while ending keytab scan" ,code
);
388 * if no principal name found in keytab for domain use the prinipal name which can get a TGT
390 if (!principal_name
) {
392 debug((char *) "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM
, domain
);
393 debug((char *) "%s| %s: DEBUG: Try to get principal of trusted domain.\n", LogTime(), PROGRAM
);
395 for (i
= 0; i
< nprinc
; ++i
) {
396 krb5_creds
*tgt_creds
= NULL
;
397 creds
= (krb5_creds
*) xmalloc(sizeof(*creds
));
398 memset(creds
, 0, sizeof(*creds
));
402 code
= krb5_unparse_name(kparam
.context
, principal_list
[i
], &principal_name
);
404 k5_error("Error while unparsing principal name" ,code
);
407 debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM
, principal_name
);
409 #if HAVE_GET_INIT_CREDS_KEYTAB
410 code
= krb5_get_init_creds_keytab(kparam
.context
, creds
, principal_list
[i
], keytab
, 0, NULL
, NULL
);
412 service
= (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain
) + 3);
413 snprintf(service
, strlen("krbtgt") + 2 * strlen(domain
) + 3, "krbtgt/%s@%s", domain
, domain
);
414 creds
->client
= principal_list
[i
];
415 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
417 code
= krb5_get_in_tkt_with_keytab(kparam
.context
, 0, NULL
, NULL
, NULL
, keytab
, NULL
, creds
, 0);
420 k5_error("Error while initialising credentials from keytab" ,code
);
423 code
= krb5_cc_initialize(kparam
.context
, kparam
.cc
[ccindex
], principal_list
[i
]);
425 k5_error("Error while initialising memory caches" ,code
);
428 code
= krb5_cc_store_cred(kparam
.context
, kparam
.cc
[ccindex
], creds
);
430 k5_error("Error while storing credentials" ,code
);
434 krb5_free_principal(kparam
.context
, creds
->server
);
436 service
= (char *) xmalloc(strlen("krbtgt") + strlen(domain
) + strlen(principal_list
[i
]->realm
) + 3);
437 snprintf(service
, strlen("krbtgt") + strlen(domain
) + strlen(principal_list
[i
]->realm
) + 3, "krbtgt/%s@%s", domain
, principal_list
[i
]->realm
);
439 service
= (char *) xmalloc(strlen("krbtgt") + strlen(domain
) + strlen(krb5_princ_realm(kparam
.context
, principal_list
[i
])->data
) + 3);
440 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
);
442 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
445 k5_error("Error while initialising TGT credentials" ,code
);
448 code
= krb5_get_credentials(kparam
.context
, 0, kparam
.cc
[ccindex
], creds
, &tgt_creds
);
450 k5_error("Error while getting tgt" ,code
);
453 debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM
, principal_name
);
455 krb5_free_creds(kparam
.context
, tgt_creds
);
461 safe_free(principal_name
);
463 krb5_free_creds(kparam
.context
, tgt_creds
);
466 krb5_free_creds(kparam
.context
, creds
);
472 krb5_free_creds(kparam
.context
, creds
);
476 debug((char *) "%s| %s: DEBUG: Got principal from ccache\n", LogTime(), PROGRAM
);
480 code
= krb5_unparse_name(kparam
.context
, principal
, &principal_name
);
482 k5_error("Error while unparsing principal name" ,code
);
486 debug((char *) "%s| %s: DEBUG: ccache has principal: %s\n", LogTime(), PROGRAM
, principal_name
);
489 if (!principal_name
) {
490 debug((char *) "%s| %s: DEBUG: Got no principal name\n", LogTime(), PROGRAM
);
495 krb5_kt_close(kparam
.context
, keytab
);
497 xfree(principal_name
);
500 krb5_free_principal(kparam
.context
, principal
);
501 for (j
= 0; j
< nprinc
; ++j
) {
502 if (principal_list
[j
])
503 krb5_free_principal(kparam
.context
, principal_list
[j
]);
505 xfree(principal_list
);
507 krb5_free_creds(kparam
.context
, creds
);