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>
33 #include<krb5common.h>
39 /**************************************/
40 /* khm_krb5_error(): */
41 /**************************************/
43 khm_krb5_error(krb5_error_code rc
, LPCSTR FailedFunctionName
,
44 int FreeContextFlag
, krb5_context
* ctx
,
51 #ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY
54 int krb5Error
= ((int)(rc
& 255));
56 if (*ctx
&& pkrb5_get_error_message
)
57 errText
= pkrb5_get_error_message(*ctx
, rc
);
59 errText
= perror_message(rc
);
60 _snprintf(message
, sizeof(message
),
61 "%s\n(Kerberos error %ld)\n\n%s failed",
65 if (*ctx
&& pkrb5_free_error_message
)
66 pkrb5_free_error_message(*ctx
, errText
);
68 MessageBoxA(NULL
, message
, "Kerberos Five", MB_OK
| MB_ICONERROR
|
73 if (FreeContextFlag
== 1)
78 pkrb5_cc_close(*ctx
, *cache
);
82 pkrb5_free_context(*ctx
);
93 khm_krb5_initialize(khm_handle ident
,
103 krb5_error_code rc
= 0;
104 krb5_flags flags
= KRB5_TC_OPENCLOSE
;
106 if (pkrb5_init_context
== NULL
)
109 if (*ctx
== 0 && (rc
= (*pkrb5_init_context
)(ctx
))) {
110 functionName
= "krb5_init_context()";
116 wchar_t wccname
[MAX_PATH
];
120 cbwccname
= sizeof(wccname
);
124 if(KHM_FAILED(kcdb_identity_get_attrib(ident
, L
"Krb5CCName",
127 cbwccname
= sizeof(wccname
);
129 (khm_krb5_find_ccache_for_identity(ident
,
133 #ifdef DEBUG_LIKE_A_MADMAN
140 if(UnicodeStrToAnsi(ccname
, sizeof(ccname
), wccname
) == 0)
143 if((*pkrb5_cc_resolve
)(*ctx
, ccname
, cache
)) {
144 functionName
= "krb5_cc_resolve()";
151 #ifndef FAILOVER_TO_DEFAULT_CCACHE
155 #ifdef FAILOVER_TO_DEFAULT_CCACHE
156 && (rc
= (*pkrb5_cc_default
)(*ctx
, cache
))
159 functionName
= "krb5_cc_default()";
165 #ifdef KRB5_TC_NOTICKET
166 flags
= KRB5_TC_NOTICKET
;
169 if ((rc
= (*pkrb5_cc_set_flags
)(*ctx
, *cache
, flags
)))
171 if (rc
!= KRB5_FCC_NOFILE
&& rc
!= KRB5_CC_NOTFOUND
)
172 khm_krb5_error(rc
, "krb5_cc_set_flags()", 0, ctx
,
174 else if ((rc
== KRB5_FCC_NOFILE
|| rc
== KRB5_CC_NOTFOUND
) && *ctx
!= NULL
) {
176 (*pkrb5_cc_close
)(*ctx
, *cache
);
183 return khm_krb5_error(rc
, functionName
, freeContextFlag
, ctx
, cache
);
187 #define TIMET_TOLERANCE (60*5)
190 khm_get_identity_expiration_time(krb5_context ctx
, krb5_ccache cc
,
192 krb5_timestamp
* pexpiration
)
194 krb5_principal principal
= 0;
195 char * princ_name
= NULL
;
197 krb5_error_code code
;
198 krb5_error_code cc_code
;
200 krb5_timestamp now
, expiration
= 0;
202 wchar_t w_ident_name
[KCDB_IDENT_MAXCCH_NAME
];
203 char ident_name
[KCDB_IDENT_MAXCCH_NAME
];
206 khm_int32 rv
= KHM_ERROR_NOT_FOUND
;
208 if (!ctx
|| !cc
|| !ident
|| !pexpiration
)
209 return KHM_ERROR_GENERAL
;
211 code
= pkrb5_cc_get_principal(ctx
, cc
, &principal
);
214 return KHM_ERROR_INVALID_PARAM
;
216 cb
= sizeof(w_ident_name
);
217 kcdb_identity_get_name(ident
, w_ident_name
, &cb
);
218 UnicodeStrToAnsi(ident_name
, sizeof(ident_name
), w_ident_name
);
220 code
= pkrb5_unparse_name(ctx
, principal
, &princ_name
);
222 /* compare principal to ident. */
224 if ( code
|| !princ_name
||
225 strcmp(princ_name
, ident_name
) ) {
227 pkrb5_free_unparsed_name(ctx
, princ_name
);
228 pkrb5_free_principal(ctx
, principal
);
229 return KHM_ERROR_UNKNOWN
;
232 pkrb5_free_unparsed_name(ctx
, princ_name
);
233 pkrb5_free_principal(ctx
, principal
);
235 code
= pkrb5_timeofday(ctx
, &now
);
238 return KHM_ERROR_UNKNOWN
;
240 cc_code
= pkrb5_cc_start_seq_get(ctx
, cc
, &cur
);
242 while (!(cc_code
= pkrb5_cc_next_cred(ctx
, cc
, &cur
, &creds
))) {
243 krb5_data
* c0
= krb5_princ_name(ctx
, creds
.server
);
244 krb5_data
* c1
= krb5_princ_component(ctx
, creds
.server
, 1);
245 krb5_data
* r
= krb5_princ_realm(ctx
, creds
.server
);
247 if ( c0
&& c1
&& r
&& c1
->length
== r
->length
&&
248 !strncmp(c1
->data
,r
->data
,r
->length
) &&
249 !strncmp("krbtgt",c0
->data
,c0
->length
) ) {
251 /* we have a TGT, check for the expiration time.
252 * if it is valid and renewable, use the renew time
255 if (!(creds
.ticket_flags
& TKT_FLG_INVALID
) &&
256 creds
.times
.starttime
< (now
+ TIMET_TOLERANCE
) &&
257 (creds
.times
.endtime
+ TIMET_TOLERANCE
) > now
) {
258 expiration
= creds
.times
.endtime
;
260 if ((creds
.ticket_flags
& TKT_FLG_RENEWABLE
) &&
261 (creds
.times
.renew_till
> creds
.times
.endtime
)) {
262 expiration
= creds
.times
.renew_till
;
268 if (cc_code
== KRB5_CC_END
) {
269 cc_code
= pkrb5_cc_end_seq_get(ctx
, cc
, &cur
);
270 rv
= KHM_ERROR_SUCCESS
;
271 *pexpiration
= expiration
;
278 khm_krb5_find_ccache_for_identity(khm_handle ident
, krb5_context
*pctx
,
279 void * buffer
, khm_size
* pcbbuf
)
281 krb5_context ctx
= 0;
282 krb5_ccache cache
= 0;
283 krb5_error_code code
;
285 struct _infoNC
** pNCi
= NULL
;
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
;
301 if (!pcc_initialize
||
307 code
= pcc_initialize(&cc_ctx
, CC_API_VER_2
, NULL
, NULL
);
311 code
= pcc_get_NC_info(cc_ctx
, &pNCi
);
316 for(i
=0; pNCi
[i
]; i
++) {
317 if (pNCi
[i
]->vers
!= CC_CRED_V5
)
320 code
= (*pkrb5_cc_resolve
)(ctx
, pNCi
[i
]->name
, &cache
);
324 /* need a function to check the cache for the identity
325 * and determine if it has valid tickets. If it has
326 * the right identity and valid tickets, store the
327 * expiration time and the cache name. If it has the
328 * right identity but no valid tickets, store the ccache
329 * name and an expiration time of zero. if it does not
330 * have the right identity don't save the name.
332 * Keep searching to find the best cache available.
335 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx
, cache
,
338 if ( expiration
> best_match_expiration
) {
339 best_match_expiration
= expiration
;
340 StringCbCopyA(best_match_ccname
,
341 sizeof(best_match_ccname
),
343 StringCbCatA(best_match_ccname
,
344 sizeof(best_match_ccname
),
350 if(ctx
!= NULL
&& cache
!= NULL
)
351 (*pkrb5_cc_close
)(ctx
, cache
);
357 if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins
))) {
358 khc_open_space(csp_plugins
, L
"Krb5Cred\\Parameters", 0, &csp_params
);
359 khc_close_space(csp_plugins
);
364 if (csp_params
== NULL
) {
370 KHM_SUCCEEDED(khc_read_int32(csp_params
, L
"MsLsaList", &t
)) && t
) {
371 code
= (*pkrb5_cc_resolve
)(ctx
, "MSLSA:", &cache
);
372 if (code
== 0 && cache
) {
373 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx
, cache
,
376 if ( expiration
> best_match_expiration
) {
377 best_match_expiration
= expiration
;
378 StringCbCopyA(best_match_ccname
, sizeof(best_match_ccname
),
385 if (ctx
!= NULL
&& cache
!= NULL
)
386 (*pkrb5_cc_close
)(ctx
, cache
);
392 khc_read_multi_string(csp_params
, L
"FileCCList", NULL
, &cb
)
393 == KHM_ERROR_TOO_LONG
&&
394 cb
> sizeof(wchar_t) * 2) {
397 char ccname
[MAX_PATH
+ 6];
405 khc_read_multi_string(csp_params
, L
"FileCCList", ms
, &cb
);
406 for(t
= ms
; t
&& *t
; t
= multi_string_next(t
)) {
407 StringCchPrintfA(ccname
, ARRAYLENGTH(ccname
),
410 code
= (*pkrb5_cc_resolve
)(ctx
, ccname
, &cache
);
414 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx
, cache
,
417 if ( expiration
> best_match_expiration
) {
418 best_match_expiration
= expiration
;
419 StringCbCopyA(best_match_ccname
,
420 sizeof(best_match_ccname
),
426 if (ctx
!= NULL
&& cache
!= NULL
)
427 (*pkrb5_cc_close
)(ctx
, cache
);
435 khc_close_space(csp_params
);
438 (*pcc_free_NC_info
)(cc_ctx
, &pNCi
);
441 (*pcc_shutdown
)(&cc_ctx
);
443 if (best_match_ccname
[0]) {
445 if (*pcbbuf
= AnsiStrToUnicode((wchar_t *)buffer
,
447 best_match_ccname
)) {
449 *pcbbuf
= (*pcbbuf
+ 1) * sizeof(wchar_t);
451 return KHM_ERROR_SUCCESS
;
456 return KHM_ERROR_GENERAL
;