2 * Copyright (c) 2005 Massachusetts Institute of Technology
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 #include <afsconfig.h>
28 #include <afs/param.h>
35 #include<krb5common.h>
41 /**************************************/
42 /* khm_krb5_error(): */
43 /**************************************/
45 khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
46 int FreeContextFlag, krb5_context * ctx,
53 #ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY
56 int krb5Error = ((int)(rc & 255));
58 if (pkrb5_get_error_message)
59 errText = pkrb5_get_error_message(rc);
61 errText = perror_message(rc);
62 _snprintf(message, sizeof(message),
63 "%s\n(Kerberos error %ld)\n\n%s failed",
67 if (pkrb5_free_error_message)
68 pkrb5_free_error_message(errText);
70 MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
75 if (FreeContextFlag == 1)
80 pkrb5_cc_close(*ctx, *cache);
84 pkrb5_free_context(*ctx);
95 khm_krb5_initialize(khm_handle ident,
105 krb5_error_code rc = 0;
106 krb5_flags flags = KRB5_TC_OPENCLOSE;
108 if (pkrb5_init_context == NULL)
111 if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) {
112 functionName = "krb5_init_context()";
118 wchar_t wccname[MAX_PATH];
122 cbwccname = sizeof(wccname);
126 if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName",
129 cbwccname = sizeof(wccname);
131 (khm_krb5_find_ccache_for_identity(ident,
135 #ifdef DEBUG_LIKE_A_MADMAN
142 if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0)
145 if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) {
146 functionName = "krb5_cc_resolve()";
153 #ifndef FAILOVER_TO_DEFAULT_CCACHE
157 #ifdef FAILOVER_TO_DEFAULT_CCACHE
158 && (rc = (*pkrb5_cc_default)(*ctx, cache))
161 functionName = "krb5_cc_default()";
167 #ifdef KRB5_TC_NOTICKET
168 flags = KRB5_TC_NOTICKET;
171 if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags)))
173 if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND)
174 khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx,
176 else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) {
178 (*pkrb5_cc_close)(*ctx, *cache);
185 return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache);
189 #define TIMET_TOLERANCE (60*5)
192 khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc,
194 krb5_timestamp * pexpiration)
196 krb5_principal principal = 0;
197 char * princ_name = NULL;
199 krb5_error_code code;
200 krb5_error_code cc_code;
202 krb5_timestamp now, expiration = 0;
204 wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME];
205 char ident_name[KCDB_IDENT_MAXCCH_NAME];
208 khm_int32 rv = KHM_ERROR_NOT_FOUND;
210 if (!ctx || !cc || !ident || !pexpiration)
211 return KHM_ERROR_GENERAL;
213 code = pkrb5_cc_get_principal(ctx, cc, &principal);
216 return KHM_ERROR_INVALID_PARAM;
218 cb = sizeof(w_ident_name);
219 kcdb_identity_get_name(ident, w_ident_name, &cb);
220 UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name);
222 code = pkrb5_unparse_name(ctx, principal, &princ_name);
224 /* compare principal to ident. */
226 if ( code || !princ_name ||
227 strcmp(princ_name, ident_name) ) {
229 pkrb5_free_unparsed_name(ctx, princ_name);
230 pkrb5_free_principal(ctx, principal);
231 return KHM_ERROR_UNKNOWN;
234 pkrb5_free_unparsed_name(ctx, princ_name);
235 pkrb5_free_principal(ctx, principal);
237 code = pkrb5_timeofday(ctx, &now);
240 return KHM_ERROR_UNKNOWN;
242 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
244 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
245 krb5_data * c0 = krb5_princ_name(ctx, creds.server);
246 krb5_data * c1 = krb5_princ_component(ctx, creds.server, 1);
247 krb5_data * r = krb5_princ_realm(ctx, creds.server);
249 if ( c0 && c1 && r && c1->length == r->length &&
250 !strncmp(c1->data,r->data,r->length) &&
251 !strncmp("krbtgt",c0->data,c0->length) ) {
253 /* we have a TGT, check for the expiration time.
254 * if it is valid and renewable, use the renew time
257 if (!(creds.ticket_flags & TKT_FLG_INVALID) &&
258 creds.times.starttime < (now + TIMET_TOLERANCE) &&
259 (creds.times.endtime + TIMET_TOLERANCE) > now) {
260 expiration = creds.times.endtime;
262 if ((creds.ticket_flags & TKT_FLG_RENEWABLE) &&
263 (creds.times.renew_till > creds.times.endtime)) {
264 expiration = creds.times.renew_till;
270 if (cc_code == KRB5_CC_END) {
271 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
272 rv = KHM_ERROR_SUCCESS;
273 *pexpiration = expiration;
280 khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx,
281 void * buffer, khm_size * pcbbuf)
283 krb5_context ctx = 0;
284 krb5_ccache cache = 0;
285 krb5_error_code code;
287 struct _infoNC ** pNCi = NULL;
292 krb5_timestamp expiration = 0;
293 krb5_timestamp best_match_expiration = 0;
294 char best_match_ccname[256] = "";
295 khm_handle csp_params = NULL;
296 khm_handle csp_plugins = NULL;
298 if (!buffer || !pcbbuf)
299 return KHM_ERROR_GENERAL;
303 if (!pcc_initialize ||
309 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
313 code = pcc_get_NC_info(cc_ctx, &pNCi);
318 for(i=0; pNCi[i]; i++) {
319 if (pNCi[i]->vers != CC_CRED_V5)
322 code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache);
326 /* need a function to check the cache for the identity
327 * and determine if it has valid tickets. If it has
328 * the right identity and valid tickets, store the
329 * expiration time and the cache name. If it has the
330 * right identity but no valid tickets, store the ccache
331 * name and an expiration time of zero. if it does not
332 * have the right identity don't save the name.
334 * Keep searching to find the best cache available.
337 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache,
340 if ( expiration > best_match_expiration ) {
341 best_match_expiration = expiration;
342 StringCbCopyA(best_match_ccname,
343 sizeof(best_match_ccname),
345 StringCbCatA(best_match_ccname,
346 sizeof(best_match_ccname),
352 if(ctx != NULL && cache != NULL)
353 (*pkrb5_cc_close)(ctx, cache);
359 if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) {
360 khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params);
361 khc_close_space(csp_plugins);
366 if (csp_params == NULL) {
372 KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) {
373 code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache);
374 if (code == 0 && cache) {
375 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache,
378 if ( expiration > best_match_expiration ) {
379 best_match_expiration = expiration;
380 StringCbCopyA(best_match_ccname, sizeof(best_match_ccname),
387 if (ctx != NULL && cache != NULL)
388 (*pkrb5_cc_close)(ctx, cache);
394 khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb)
395 == KHM_ERROR_TOO_LONG &&
396 cb > sizeof(wchar_t) * 2) {
399 char ccname[MAX_PATH + 6];
407 khc_read_multi_string(csp_params, L"FileCCList", ms, &cb);
408 for(t = ms; t && *t; t = multi_string_next(t)) {
409 StringCchPrintfA(ccname, ARRAYLENGTH(ccname),
412 code = (*pkrb5_cc_resolve)(ctx, ccname, &cache);
416 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache,
419 if ( expiration > best_match_expiration ) {
420 best_match_expiration = expiration;
421 StringCbCopyA(best_match_ccname,
422 sizeof(best_match_ccname),
428 if (ctx != NULL && cache != NULL)
429 (*pkrb5_cc_close)(ctx, cache);
437 khc_close_space(csp_params);
440 (*pcc_free_NC_info)(cc_ctx, &pNCi);
443 (*pcc_shutdown)(&cc_ctx);
445 if (best_match_ccname[0]) {
447 if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer,
449 best_match_ccname)) {
451 *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t);
453 return KHM_ERROR_SUCCESS;
458 return KHM_ERROR_GENERAL;