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 (*ctx
&& krb5_get_error_message
)
59 errText
= krb5_get_error_message(*ctx
, rc
);
61 errText
= perror_message(rc
);
62 _snprintf(message
, sizeof(message
),
63 "%s\n(Kerberos error %ld)\n\n%s failed",
67 if (*ctx
&& krb5_free_error_message
)
68 krb5_free_error_message(*ctx
, errText
);
70 MessageBoxA(NULL
, message
, "Kerberos Five", MB_OK
| MB_ICONERROR
|
75 if (FreeContextFlag
== 1)
80 krb5_cc_close(*ctx
, *cache
);
84 krb5_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 (krb5_init_context
== NULL
)
111 if (*ctx
== 0 && (rc
= krb5_init_context(ctx
))) {
112 functionName
= "krb5_init_context()";
117 if (krb5_enctype_valid(*ctx
, ETYPE_DES_CBC_CRC
))
118 krb5_enctype_enable(*ctx
, ETYPE_DES_CBC_CRC
);
121 wchar_t wccname
[MAX_PATH
];
125 cbwccname
= sizeof(wccname
);
129 if(KHM_FAILED(kcdb_identity_get_attrib(ident
, L
"Krb5CCName",
132 cbwccname
= sizeof(wccname
);
134 (khm_krb5_find_ccache_for_identity(ident
,
138 #ifdef DEBUG_LIKE_A_MADMAN
145 if(UnicodeStrToAnsi(ccname
, sizeof(ccname
), wccname
) == 0)
148 if((rc
= krb5_cc_resolve(*ctx
, ccname
, cache
)) != 0) {
149 functionName
= "krb5_cc_resolve()";
156 #ifndef FAILOVER_TO_DEFAULT_CCACHE
160 #ifdef FAILOVER_TO_DEFAULT_CCACHE
161 && (rc
= krb5_cc_default(*ctx
, cache
))
164 functionName
= "krb5_cc_default()";
170 #ifdef KRB5_TC_NOTICKET
171 flags
= KRB5_TC_NOTICKET
;
174 if ((rc
= krb5_cc_set_flags(*ctx
, *cache
, flags
)))
176 if (rc
!= KRB5_FCC_NOFILE
&& rc
!= KRB5_CC_NOTFOUND
)
177 khm_krb5_error(rc
, "krb5_cc_set_flags()", 0, ctx
, cache
);
178 else if ((rc
== KRB5_FCC_NOFILE
|| rc
== KRB5_CC_NOTFOUND
) && *ctx
!= NULL
) {
180 krb5_cc_close(*ctx
, *cache
);
187 return khm_krb5_error(rc
, functionName
, freeContextFlag
, ctx
, cache
);
191 #define TIMET_TOLERANCE (60*5)
194 khm_get_identity_expiration_time(krb5_context ctx
, krb5_ccache cc
,
196 krb5_timestamp
* pexpiration
)
198 krb5_principal principal
= 0;
199 char * princ_name
= NULL
;
201 krb5_error_code code
;
202 krb5_error_code cc_code
;
204 krb5_timestamp now
, expiration
= 0;
206 wchar_t w_ident_name
[KCDB_IDENT_MAXCCH_NAME
];
207 char ident_name
[KCDB_IDENT_MAXCCH_NAME
];
210 khm_int32 rv
= KHM_ERROR_NOT_FOUND
;
212 if (!ctx
|| !cc
|| !ident
|| !pexpiration
)
213 return KHM_ERROR_GENERAL
;
215 code
= krb5_cc_get_principal(ctx
, cc
, &principal
);
218 return KHM_ERROR_INVALID_PARAM
;
220 cb
= sizeof(w_ident_name
);
221 kcdb_identity_get_name(ident
, w_ident_name
, &cb
);
222 UnicodeStrToAnsi(ident_name
, sizeof(ident_name
), w_ident_name
);
224 code
= krb5_unparse_name(ctx
, principal
, &princ_name
);
226 /* compare principal to ident. */
228 if ( code
|| !princ_name
||
229 strcmp(princ_name
, ident_name
) ) {
231 krb5_free_unparsed_name(ctx
, princ_name
);
232 krb5_free_principal(ctx
, principal
);
233 return KHM_ERROR_UNKNOWN
;
236 krb5_free_unparsed_name(ctx
, princ_name
);
237 krb5_free_principal(ctx
, principal
);
239 code
= krb5_timeofday(ctx
, &now
);
242 return KHM_ERROR_UNKNOWN
;
244 cc_code
= krb5_cc_start_seq_get(ctx
, cc
, &cur
);
246 while (!(cc_code
= krb5_cc_next_cred(ctx
, cc
, &cur
, &creds
))) {
247 const char * c0
= krb5_principal_get_comp_string(ctx
, creds
.server
, 0);
248 const char * c1
= krb5_principal_get_comp_string(ctx
, creds
.server
, 1);
249 const char * r
= krb5_principal_get_realm(ctx
, creds
.server
);
251 if ( c0
&& c1
&& r
&& !strcmp(c1
, r
) &&
252 !strcmp("krbtgt",c0
) ) {
254 /* we have a TGT, check for the expiration time.
255 * if it is valid and renewable, use the renew time
258 if (!creds
.flags
.b
.invalid
&&
259 creds
.times
.starttime
< (now
+ TIMET_TOLERANCE
) &&
260 (creds
.times
.endtime
+ TIMET_TOLERANCE
) > now
) {
261 expiration
= creds
.times
.endtime
;
263 if (creds
.flags
.b
.renewable
&&
264 (creds
.times
.renew_till
> creds
.times
.endtime
)) {
265 expiration
= creds
.times
.renew_till
;
271 if (cc_code
== KRB5_CC_END
) {
272 cc_code
= krb5_cc_end_seq_get(ctx
, cc
, &cur
);
273 rv
= KHM_ERROR_SUCCESS
;
274 *pexpiration
= expiration
;
281 khm_krb5_find_ccache_for_identity(khm_handle ident
, krb5_context
*pctx
,
282 void * buffer
, khm_size
* pcbbuf
)
284 krb5_context context
= 0;
285 krb5_ccache cache
= 0;
286 krb5_error_code code
;
290 krb5_timestamp expiration
= 0;
291 krb5_timestamp best_match_expiration
= 0;
292 char best_match_ccname
[256] = "";
293 khm_handle csp_params
= NULL
;
294 khm_handle csp_plugins
= NULL
;
296 if (!buffer
|| !pcbbuf
)
297 return KHM_ERROR_GENERAL
;
302 krb5_cccol_cursor cciter
= 0;
304 code
= krb5_cccol_cursor_new(context
, &cciter
);
308 while (krb5_cccol_cursor_next(context
, cciter
, &cache
) == 0) {
310 /* need a function to check the cache for the identity and
311 * determine if it has valid tickets. If it has the right
312 * identity and valid tickets, store the expiration time
313 * and the cache name. If it has the right identity but
314 * no valid tickets, store the ccache name and an
315 * expiration time of zero. if it does not have the right
316 * identity don't save the name.
318 * Keep searching to find the best cache available.
321 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context
, cache
,
324 if ( expiration
> best_match_expiration
) {
325 best_match_expiration
= expiration
;
326 StringCbPrintfA(best_match_ccname
, sizeof(best_match_ccname
),
328 krb5_cc_get_type(context
, cache
),
329 krb5_cc_get_name(context
, cache
));
334 krb5_cc_close(context
, cache
);
338 krb5_cccol_cursor_free(context
, &cciter
);
341 if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins
))) {
342 khc_open_space(csp_plugins
, L
"Krb5Cred\\Parameters", 0, &csp_params
);
343 khc_close_space(csp_plugins
);
348 if (csp_params
== NULL
) {
354 KHM_SUCCEEDED(khc_read_int32(csp_params
, L
"MsLsaList", &t
)) && t
) {
355 code
= krb5_cc_resolve(context
, "MSLSA:", &cache
);
356 if (code
== 0 && cache
) {
357 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context
, cache
,
360 if ( expiration
> best_match_expiration
) {
361 best_match_expiration
= expiration
;
362 StringCbCopyA(best_match_ccname
, sizeof(best_match_ccname
),
369 if (context
!= NULL
&& cache
!= NULL
)
370 krb5_cc_close(context
, cache
);
376 khc_read_multi_string(csp_params
, L
"FileCCList", NULL
, &cb
)
377 == KHM_ERROR_TOO_LONG
&&
378 cb
> sizeof(wchar_t) * 2) {
381 char ccname
[MAX_PATH
+ 6];
389 khc_read_multi_string(csp_params
, L
"FileCCList", ms
, &cb
);
390 for(t
= ms
; t
&& *t
; t
= multi_string_next(t
)) {
391 StringCchPrintfA(ccname
, ARRAYLENGTH(ccname
),
394 code
= krb5_cc_resolve(context
, ccname
, &cache
);
398 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context
, cache
,
401 if ( expiration
> best_match_expiration
) {
402 best_match_expiration
= expiration
;
403 StringCbCopyA(best_match_ccname
,
404 sizeof(best_match_ccname
),
410 if (context
!= NULL
&& cache
!= NULL
)
411 krb5_cc_close(context
, cache
);
419 khc_close_space(csp_params
);
421 if (best_match_ccname
[0]) {
423 if (*pcbbuf
= AnsiStrToUnicode((wchar_t *)buffer
,
425 best_match_ccname
)) {
427 *pcbbuf
= (*pcbbuf
+ 1) * sizeof(wchar_t);
429 return KHM_ERROR_SUCCESS
;
434 return KHM_ERROR_GENERAL
;