]>
git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/kerberos_ldap_group/support_krb5.cc
2 * Copyright (C) 1996-2015 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
);
58 * create Kerberos memory cache
61 krb5_create_cache(char *domain
)
64 krb5_keytab keytab
= NULL
;
65 krb5_keytab_entry entry
;
66 krb5_kt_cursor cursor
;
67 krb5_cc_cursor ccursor
;
68 krb5_creds
*creds
= NULL
;
69 krb5_principal
*principal_list
= NULL
;
70 krb5_principal principal
= NULL
;
72 char *keytab_name
= NULL
, *principal_name
= NULL
, *mem_cache
= NULL
;
73 char buf
[KT_PATH_MAX
], *p
;
76 krb5_error_code code
= 0;
79 if (!domain
|| !strcmp(domain
, ""))
83 * prepare memory credential cache
85 #if !HAVE_KRB5_MEMORY_CACHE || HAVE_SUN_LDAP_SDK
86 mem_cache
= (char *) xmalloc(strlen("FILE:/tmp/squid_ldap_") + strlen(domain
) + 1 + 16);
87 snprintf(mem_cache
, strlen("FILE:/tmp/squid_ldap_") + strlen(domain
) + 1 + 16, "FILE:/tmp/squid_ldap_%s_%d", domain
, (int) getpid());
89 mem_cache
= (char *) xmalloc(strlen("MEMORY:squid_ldap_") + strlen(domain
) + 1 + 16);
90 snprintf(mem_cache
, strlen("MEMORY:squid_ldap_") + strlen(domain
) + 1 + 16, "MEMORY:squid_ldap_%s_%d", domain
, (int) getpid());
93 setenv("KRB5CCNAME", mem_cache
, 1);
94 debug((char *) "%s| %s: DEBUG: Set credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
95 for (int i
=0; i
<MAX_DOMAINS
; i
++) {
96 if (kparam
.mem_ccache
[i
] && !strcmp(mem_cache
,kparam
.mem_ccache
[i
])) {
101 if ( ccindex
== -1 ) {
102 kparam
.mem_ccache
[kparam
.ncache
]=xstrdup(mem_cache
);
103 ccindex
=kparam
.ncache
;
105 if ( kparam
.ncache
== MAX_DOMAINS
) {
106 error((char *) "%s| %s: ERROR: Too many domains to support: # domains %d\n", LogTime(), PROGRAM
, kparam
.ncache
);
110 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
112 error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
118 * getting default principal from cache
121 code
= krb5_cc_get_principal(kparam
.context
, kparam
.cc
[ccindex
], &principal
);
124 krb5_free_principal(kparam
.context
, principal
);
126 debug((char *) "%s| %s: DEBUG: No default principal found in ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
130 * Look for krbtgt and check if it is expired (or soon to be expired)
132 code
= krb5_cc_start_seq_get(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
);
134 error((char *) "%s| %s: ERROR: Error while starting ccache scan : %s\n", LogTime(), PROGRAM
, error_message(code
));
135 code
= krb5_cc_close (kparam
.context
, kparam
.cc
[ccindex
]);
137 error((char *) "%s| %s: ERROR: while closing ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
139 if (kparam
.cc
[ccindex
]) {
140 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
142 error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
146 krb5_error_code code2
= 0;
147 creds
= (krb5_creds
*) xcalloc(1,sizeof(*creds
));
148 while ((krb5_cc_next_cred(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
, creds
)) == 0) {
149 code2
= krb5_unparse_name(kparam
.context
, creds
->server
, &principal_name
);
151 error((char *) "%s| %s: ERROR: Error while unparsing principal : %s\n", LogTime(), PROGRAM
, error_message(code2
));
152 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
154 error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
157 krb5_free_creds(kparam
.context
, creds
);
159 safe_free(principal_name
);
160 debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
161 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
163 error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
170 if (!strncmp(KRB5_TGS_NAME
,principal_name
,KRB5_TGS_NAME_SIZE
)) {
172 static krb5_deltat skew
=MAX_SKEW
;
174 debug((char *) "%s| %s: DEBUG: Found %s in cache : %s\n", LogTime(), PROGRAM
,KRB5_TGS_NAME
,principal_name
);
179 debug((char *) "%s| %s: DEBUG: credential time diff %d\n", LogTime(), PROGRAM
, (int)(creds
->times
.endtime
- now
));
180 if (creds
->times
.endtime
- now
< 2*skew
) {
181 debug((char *) "%s| %s: DEBUG: credential will soon expire %d\n", LogTime(), PROGRAM
, (int)(creds
->times
.endtime
- now
));
183 krb5_free_principal(kparam
.context
, principal
);
185 code
= krb5_cc_destroy(kparam
.context
, kparam
.cc
[ccindex
]);
187 error((char *) "%s| %s: ERROR: while destroying ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
190 krb5_free_creds(kparam
.context
, creds
);
192 safe_free(principal_name
);
193 debug((char *) "%s| %s: DEBUG: Reset credential cache to %s\n", LogTime(), PROGRAM
, mem_cache
);
194 code
= krb5_cc_resolve(kparam
.context
, mem_cache
, &kparam
.cc
[ccindex
]);
196 error((char *) "%s| %s: ERROR: Error while resolving memory ccache : %s\n", LogTime(), PROGRAM
, error_message(code
));
202 safe_free(principal_name
);
207 krb5_free_creds(kparam
.context
, creds
);
208 creds
= (krb5_creds
*) xcalloc(1,sizeof(*creds
));
209 safe_free(principal_name
);
212 krb5_free_creds(kparam
.context
, creds
);
214 code2
= krb5_cc_end_seq_get(kparam
.context
, kparam
.cc
[ccindex
], &ccursor
);
216 error((char *) "%s| %s: ERROR: Error while ending ccache scan : %s\n", LogTime(), PROGRAM
, error_message(code
));
224 * getting default keytab name
227 debug((char *) "%s| %s: DEBUG: Get default keytab file name\n", LogTime(), PROGRAM
);
228 krb5_kt_default_name(kparam
.context
, buf
, KT_PATH_MAX
);
229 p
= strchr(buf
, ':'); /* Find the end if "FILE:" */
231 ++p
; /* step past : */
232 keytab_name
= xstrdup(p
? p
: buf
);
233 debug((char *) "%s| %s: DEBUG: Got default keytab file name %s\n", LogTime(), PROGRAM
, keytab_name
);
235 code
= krb5_kt_resolve(kparam
.context
, keytab_name
, &keytab
);
237 error((char *) "%s| %s: ERROR: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM
, keytab_name
, error_message(code
));
241 code
= krb5_kt_start_seq_get(kparam
.context
, keytab
, &cursor
);
243 error((char *) "%s| %s: ERROR: Error while starting keytab scan : %s\n", LogTime(), PROGRAM
, error_message(code
));
247 debug((char *) "%s| %s: DEBUG: Get principal name from keytab %s\n", LogTime(), PROGRAM
, keytab_name
);
250 while ((code
= krb5_kt_next_entry(kparam
.context
, keytab
, &entry
, &cursor
)) == 0) {
253 principal_list
= (krb5_principal
*) xrealloc(principal_list
, sizeof(krb5_principal
) * (nprinc
+ 1));
254 krb5_copy_principal(kparam
.context
, entry
.principal
, &principal_list
[nprinc
++]);
256 debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM
, entry
.principal
->realm
);
258 debug((char *) "%s| %s: DEBUG: Keytab entry has realm name: %s\n", LogTime(), PROGRAM
, krb5_princ_realm(kparam
.context
, entry
.principal
)->data
);
261 if (!strcasecmp(domain
, entry
.principal
->realm
))
263 if (!strcasecmp(domain
, krb5_princ_realm(kparam
.context
, entry
.principal
)->data
))
266 code
= krb5_unparse_name(kparam
.context
, entry
.principal
, &principal_name
);
268 error((char *) "%s| %s: ERROR: Error while unparsing principal name : %s\n", LogTime(), PROGRAM
, error_message(code
));
270 debug((char *) "%s| %s: DEBUG: Found principal name: %s\n", LogTime(), PROGRAM
, principal_name
);
274 #if USE_HEIMDAL_KRB5 || ( HAVE_KRB5_KT_FREE_ENTRY && HAVE_DECL_KRB5_KT_FREE_ENTRY )
275 code
= krb5_kt_free_entry(kparam
.context
, &entry
);
277 code
= krb5_free_keytab_entry_contents(kparam
.context
, &entry
);
280 error((char *) "%s| %s: ERROR: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM
, error_message(code
));
285 debug((char *) "%s| %s: DEBUG: Got principal name %s\n", LogTime(), PROGRAM
, principal_name
);
289 code
= krb5_parse_name(kparam
.context
, principal_name
, &principal
);
291 error((char *) "%s| %s: ERROR: Error while parsing name %s : %s\n", LogTime(), PROGRAM
, principal_name
, error_message(code
));
292 safe_free(principal_name
);
294 krb5_free_principal(kparam
.context
, principal
);
298 creds
= (krb5_creds
*) xcalloc(1,sizeof(*creds
));
303 #if HAVE_GET_INIT_CREDS_KEYTAB
304 code
= krb5_get_init_creds_keytab(kparam
.context
, creds
, principal
, keytab
, 0, NULL
, NULL
);
306 service
= (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain
) + 3);
307 snprintf(service
, strlen("krbtgt") + 2 * strlen(domain
) + 3, "krbtgt/%s@%s", domain
, domain
);
308 creds
->client
= principal
;
309 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
311 code
= krb5_get_in_tkt_with_keytab(kparam
.context
, 0, NULL
, NULL
, NULL
, keytab
, NULL
, creds
, 0);
315 error((char *) "%s| %s: ERROR: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM
, error_message(code
));
316 safe_free(principal_name
);
318 krb5_free_principal(kparam
.context
, principal
);
320 krb5_free_creds(kparam
.context
, creds
);
325 code
= krb5_cc_initialize(kparam
.context
, kparam
.cc
[ccindex
], principal
);
327 error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM
, error_message(code
));
328 safe_free(principal_name
);
330 krb5_free_principal(kparam
.context
, principal
);
332 krb5_free_creds(kparam
.context
, creds
);
337 code
= krb5_cc_store_cred(kparam
.context
, kparam
.cc
[ccindex
], creds
);
339 error((char *) "%s| %s: ERROR: Error while storing credentials : %s\n", LogTime(), PROGRAM
, error_message(code
));
341 krb5_free_principal(kparam
.context
, principal
);
342 safe_free(principal_name
);
344 krb5_free_creds(kparam
.context
, creds
);
349 debug((char *) "%s| %s: DEBUG: Stored credentials\n", LogTime(), PROGRAM
);
354 if (code
&& code
!= KRB5_KT_END
) {
355 error((char *) "%s| %s: ERROR: Error while scanning keytab : %s\n", LogTime(), PROGRAM
, error_message(code
));
359 code
= krb5_kt_end_seq_get(kparam
.context
, keytab
, &cursor
);
361 error((char *) "%s| %s: ERROR: Error while ending keytab scan : %s\n", LogTime(), PROGRAM
, error_message(code
));
367 * if no principal name found in keytab for domain use the prinipal name which can get a TGT
369 if (!principal_name
) {
371 debug((char *) "%s| %s: DEBUG: Did not find a principal in keytab for domain %s.\n", LogTime(), PROGRAM
, domain
);
372 debug((char *) "%s| %s: DEBUG: Try to get principal of trusted domain.\n", LogTime(), PROGRAM
);
374 for (i
= 0; i
< nprinc
; ++i
) {
375 krb5_creds
*tgt_creds
= NULL
;
376 creds
= (krb5_creds
*) xmalloc(sizeof(*creds
));
377 memset(creds
, 0, sizeof(*creds
));
381 code
= krb5_unparse_name(kparam
.context
, principal_list
[i
], &principal_name
);
383 debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM
, error_message(code
));
386 debug((char *) "%s| %s: DEBUG: Keytab entry has principal: %s\n", LogTime(), PROGRAM
, principal_name
);
388 #if HAVE_GET_INIT_CREDS_KEYTAB
389 code
= krb5_get_init_creds_keytab(kparam
.context
, creds
, principal_list
[i
], keytab
, 0, NULL
, NULL
);
391 service
= (char *) xmalloc(strlen("krbtgt") + 2 * strlen(domain
) + 3);
392 snprintf(service
, strlen("krbtgt") + 2 * strlen(domain
) + 3, "krbtgt/%s@%s", domain
, domain
);
393 creds
->client
= principal_list
[i
];
394 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
396 code
= krb5_get_in_tkt_with_keytab(kparam
.context
, 0, NULL
, NULL
, NULL
, keytab
, NULL
, creds
, 0);
399 debug((char *) "%s| %s: DEBUG: Error while initialising credentials from keytab : %s\n", LogTime(), PROGRAM
, error_message(code
));
402 code
= krb5_cc_initialize(kparam
.context
, kparam
.cc
[ccindex
], principal_list
[i
]);
404 error((char *) "%s| %s: ERROR: Error while initializing memory caches : %s\n", LogTime(), PROGRAM
, error_message(code
));
407 code
= krb5_cc_store_cred(kparam
.context
, kparam
.cc
[ccindex
], creds
);
409 debug((char *) "%s| %s: DEBUG: Error while storing credentials : %s\n", LogTime(), PROGRAM
, error_message(code
));
413 krb5_free_principal(kparam
.context
, creds
->server
);
415 service
= (char *) xmalloc(strlen("krbtgt") + strlen(domain
) + strlen(principal_list
[i
]->realm
) + 3);
416 snprintf(service
, strlen("krbtgt") + strlen(domain
) + strlen(principal_list
[i
]->realm
) + 3, "krbtgt/%s@%s", domain
, principal_list
[i
]->realm
);
418 service
= (char *) xmalloc(strlen("krbtgt") + strlen(domain
) + strlen(krb5_princ_realm(kparam
.context
, principal_list
[i
])->data
) + 3);
419 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
);
421 code
= krb5_parse_name(kparam
.context
, service
, &creds
->server
);
424 error((char *) "%s| %s: ERROR: Error while initialising TGT credentials : %s\n", LogTime(), PROGRAM
, error_message(code
));
427 code
= krb5_get_credentials(kparam
.context
, 0, kparam
.cc
[ccindex
], creds
, &tgt_creds
);
429 debug((char *) "%s| %s: DEBUG: Error while getting tgt : %s\n", LogTime(), PROGRAM
, error_message(code
));
432 debug((char *) "%s| %s: DEBUG: Found trusted principal name: %s\n", LogTime(), PROGRAM
, principal_name
);
434 krb5_free_creds(kparam
.context
, tgt_creds
);
440 safe_free(principal_name
);
442 krb5_free_creds(kparam
.context
, tgt_creds
);
445 krb5_free_creds(kparam
.context
, creds
);
451 krb5_free_creds(kparam
.context
, creds
);
455 debug((char *) "%s| %s: DEBUG: Got principal from ccache\n", LogTime(), PROGRAM
);
459 code
= krb5_unparse_name(kparam
.context
, principal
, &principal_name
);
461 debug((char *) "%s| %s: DEBUG: Error while unparsing principal name : %s\n", LogTime(), PROGRAM
, error_message(code
));
465 debug((char *) "%s| %s: DEBUG: ccache has principal: %s\n", LogTime(), PROGRAM
, principal_name
);
468 if (!principal_name
) {
469 debug((char *) "%s| %s: DEBUG: Got no principal name\n", LogTime(), PROGRAM
);
474 krb5_kt_close(kparam
.context
, keytab
);
476 xfree(principal_name
);
479 krb5_free_principal(kparam
.context
, principal
);
480 for (j
= 0; j
< nprinc
; ++j
) {
481 if (principal_list
[j
])
482 krb5_free_principal(kparam
.context
, principal_list
[j
]);
484 xfree(principal_list
);
486 krb5_free_creds(kparam
.context
, creds
);