2 * Copyright (c) 2003 SkyRope, LLC
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Skyrope, LLC nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission from Skyrope, LLC.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Portions of this code are derived from portions of the MIT
30 * Leash Ticket Manager and LoadFuncs utilities. For these portions the
31 * following copyright applies.
33 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
34 * All rights reserved.
36 * Export of this software from the United States of America may
37 * require a specific license from the United States Government.
38 * It is the responsibility of any person or organization contemplating
39 * export to obtain such a license before exporting.
41 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42 * distribute this software and its documentation for any purpose and
43 * without fee is hereby granted, provided that the above copyright
44 * notice appear in all copies and that both that copyright notice and
45 * this permission notice appear in supporting documentation, and that
46 * the name of M.I.T. not be used in advertising or publicity pertaining
47 * to distribution of the software without specific, written prior
48 * permission. Furthermore if you modify this software you must label
49 * your software as modified software and not distribute it in such a
50 * fashion that it might be confused with the original M.I.T. software.
51 * M.I.T. makes no representations about the suitability of
52 * this software for any purpose. It is provided "as is" without express
53 * or implied warranty.
60 #include "afskfw-int.h"
67 * TIMING _____________________________________________________________________
71 #define cminREMIND_TEST 1 // test every minute for expired creds
72 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
73 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
74 #define cminMINLIFE 30 // minimum life of Kerberos creds
76 #define c100ns1SECOND (LONGLONG)10000000
77 #define cmsec1SECOND 1000
78 #define cmsec1MINUTE 60000
79 #define csec1MINUTE 60
81 /* Function Pointer Declarations for Delayed Loading */
83 DECL_FUNC_PTR(cc_initialize);
84 DECL_FUNC_PTR(cc_shutdown);
85 DECL_FUNC_PTR(cc_get_NC_info);
86 DECL_FUNC_PTR(cc_free_NC_info);
89 DECL_FUNC_PTR(Leash_get_default_lifetime);
90 DECL_FUNC_PTR(Leash_get_default_forwardable);
91 DECL_FUNC_PTR(Leash_get_default_renew_till);
92 DECL_FUNC_PTR(Leash_get_default_noaddresses);
93 DECL_FUNC_PTR(Leash_get_default_proxiable);
94 DECL_FUNC_PTR(Leash_get_default_publicip);
95 DECL_FUNC_PTR(Leash_get_default_use_krb4);
96 DECL_FUNC_PTR(Leash_get_default_life_min);
97 DECL_FUNC_PTR(Leash_get_default_life_max);
98 DECL_FUNC_PTR(Leash_get_default_renew_min);
99 DECL_FUNC_PTR(Leash_get_default_renew_max);
100 DECL_FUNC_PTR(Leash_get_default_renewable);
103 DECL_FUNC_PTR(krb5_change_password);
104 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
105 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
106 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
107 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
108 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
109 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
110 DECL_FUNC_PTR(krb5_get_init_creds_password);
111 DECL_FUNC_PTR(krb5_build_principal_ext);
112 DECL_FUNC_PTR(krb5_cc_get_name);
113 DECL_FUNC_PTR(krb5_cc_resolve);
114 DECL_FUNC_PTR(krb5_cc_default);
115 DECL_FUNC_PTR(krb5_cc_default_name);
116 DECL_FUNC_PTR(krb5_cc_set_default_name);
117 DECL_FUNC_PTR(krb5_cc_initialize);
118 DECL_FUNC_PTR(krb5_cc_destroy);
119 DECL_FUNC_PTR(krb5_cc_close);
120 DECL_FUNC_PTR(krb5_cc_store_cred);
121 DECL_FUNC_PTR(krb5_cc_copy_creds);
122 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
123 DECL_FUNC_PTR(krb5_cc_get_principal);
124 DECL_FUNC_PTR(krb5_cc_start_seq_get);
125 DECL_FUNC_PTR(krb5_cc_next_cred);
126 DECL_FUNC_PTR(krb5_cc_end_seq_get);
127 DECL_FUNC_PTR(krb5_cc_remove_cred);
128 DECL_FUNC_PTR(krb5_cc_set_flags);
129 DECL_FUNC_PTR(krb5_cc_get_type);
130 DECL_FUNC_PTR(krb5_free_context);
131 DECL_FUNC_PTR(krb5_free_cred_contents);
132 DECL_FUNC_PTR(krb5_free_principal);
133 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
134 DECL_FUNC_PTR(krb5_init_context);
135 DECL_FUNC_PTR(krb5_parse_name);
136 DECL_FUNC_PTR(krb5_timeofday);
137 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
138 DECL_FUNC_PTR(krb5_unparse_name);
139 DECL_FUNC_PTR(krb5_get_credentials);
140 DECL_FUNC_PTR(krb5_mk_req);
141 DECL_FUNC_PTR(krb5_sname_to_principal);
142 DECL_FUNC_PTR(krb5_get_credentials_renew);
143 DECL_FUNC_PTR(krb5_free_data);
144 DECL_FUNC_PTR(krb5_free_data_contents);
145 DECL_FUNC_PTR(krb5_free_unparsed_name);
146 DECL_FUNC_PTR(krb5_os_localaddr);
147 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
148 DECL_FUNC_PTR(krb5_copy_data);
149 DECL_FUNC_PTR(krb5_free_creds);
150 DECL_FUNC_PTR(krb5_build_principal);
151 DECL_FUNC_PTR(krb5_get_renewed_creds);
152 DECL_FUNC_PTR(krb5_get_default_config_files);
153 DECL_FUNC_PTR(krb5_free_config_files);
154 DECL_FUNC_PTR(krb5_get_default_realm);
155 DECL_FUNC_PTR(krb5_free_ticket);
156 DECL_FUNC_PTR(krb5_decode_ticket);
157 DECL_FUNC_PTR(krb5_get_host_realm);
158 DECL_FUNC_PTR(krb5_free_host_realm);
159 DECL_FUNC_PTR(krb5_free_addresses);
160 DECL_FUNC_PTR(krb5_c_random_make_octets);
163 DECL_FUNC_PTR(krb524_init_ets);
164 DECL_FUNC_PTR(krb524_convert_creds_kdc);
167 DECL_FUNC_PTR(krb_get_cred);
168 DECL_FUNC_PTR(tkt_string);
169 DECL_FUNC_PTR(krb_get_tf_realm);
170 DECL_FUNC_PTR(krb_mk_req);
173 DECL_FUNC_PTR(com_err);
174 DECL_FUNC_PTR(error_message);
177 DECL_FUNC_PTR(profile_init);
178 DECL_FUNC_PTR(profile_release);
179 DECL_FUNC_PTR(profile_get_subsection_names);
180 DECL_FUNC_PTR(profile_free_list);
181 DECL_FUNC_PTR(profile_get_string);
182 DECL_FUNC_PTR(profile_release_string);
185 DECL_FUNC_PTR(OpenSCManagerA);
186 DECL_FUNC_PTR(OpenServiceA);
187 DECL_FUNC_PTR(QueryServiceStatus);
188 DECL_FUNC_PTR(CloseServiceHandle);
190 DECL_FUNC_PTR(LsaNtStatusToWinError);
191 #endif /* USE_MS2MIT */
195 DECL_FUNC_PTR(LsaConnectUntrusted);
196 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
197 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
198 DECL_FUNC_PTR(LsaFreeReturnBuffer);
199 DECL_FUNC_PTR(LsaGetLogonSessionData);
200 #endif /* USE_MS2MIT */
202 // AFS36 Token Functions
203 DECL_FUNC_PTR(ktc_ListTokens);
204 DECL_FUNC_PTR(ktc_GetToken);
205 DECL_FUNC_PTR(ktc_SetToken);
206 DECL_FUNC_PTR(ktc_ForgetAllTokens);
208 // AFS36 Config Functions
209 DECL_FUNC_PTR(cm_SearchCellFile);
210 DECL_FUNC_PTR(cm_GetRootCellName);
213 FUNC_INFO ccapi_fi[] = {
214 MAKE_FUNC_INFO(cc_initialize),
215 MAKE_FUNC_INFO(cc_shutdown),
216 MAKE_FUNC_INFO(cc_get_NC_info),
217 MAKE_FUNC_INFO(cc_free_NC_info),
221 FUNC_INFO leash_fi[] = {
222 MAKE_FUNC_INFO(Leash_get_default_lifetime),
223 MAKE_FUNC_INFO(Leash_get_default_renew_till),
224 MAKE_FUNC_INFO(Leash_get_default_forwardable),
225 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
226 MAKE_FUNC_INFO(Leash_get_default_proxiable),
227 MAKE_FUNC_INFO(Leash_get_default_publicip),
228 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
229 MAKE_FUNC_INFO(Leash_get_default_life_min),
230 MAKE_FUNC_INFO(Leash_get_default_life_max),
231 MAKE_FUNC_INFO(Leash_get_default_renew_min),
232 MAKE_FUNC_INFO(Leash_get_default_renew_max),
233 MAKE_FUNC_INFO(Leash_get_default_renewable),
237 FUNC_INFO k5_fi[] = {
238 MAKE_FUNC_INFO(krb5_change_password),
239 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
240 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
241 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
242 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
243 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
244 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
245 MAKE_FUNC_INFO(krb5_get_init_creds_password),
246 MAKE_FUNC_INFO(krb5_build_principal_ext),
247 MAKE_FUNC_INFO(krb5_cc_get_name),
248 MAKE_FUNC_INFO(krb5_cc_resolve),
249 MAKE_FUNC_INFO(krb5_cc_default),
250 MAKE_FUNC_INFO(krb5_cc_default_name),
251 MAKE_FUNC_INFO(krb5_cc_set_default_name),
252 MAKE_FUNC_INFO(krb5_cc_initialize),
253 MAKE_FUNC_INFO(krb5_cc_destroy),
254 MAKE_FUNC_INFO(krb5_cc_close),
255 MAKE_FUNC_INFO(krb5_cc_copy_creds),
256 MAKE_FUNC_INFO(krb5_cc_store_cred),
257 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
258 MAKE_FUNC_INFO(krb5_cc_get_principal),
259 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
260 MAKE_FUNC_INFO(krb5_cc_next_cred),
261 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
262 MAKE_FUNC_INFO(krb5_cc_remove_cred),
263 MAKE_FUNC_INFO(krb5_cc_set_flags),
264 MAKE_FUNC_INFO(krb5_cc_get_type),
265 MAKE_FUNC_INFO(krb5_free_context),
266 MAKE_FUNC_INFO(krb5_free_cred_contents),
267 MAKE_FUNC_INFO(krb5_free_principal),
268 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
269 MAKE_FUNC_INFO(krb5_init_context),
270 MAKE_FUNC_INFO(krb5_parse_name),
271 MAKE_FUNC_INFO(krb5_timeofday),
272 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
273 MAKE_FUNC_INFO(krb5_unparse_name),
274 MAKE_FUNC_INFO(krb5_get_credentials),
275 MAKE_FUNC_INFO(krb5_mk_req),
276 MAKE_FUNC_INFO(krb5_sname_to_principal),
277 MAKE_FUNC_INFO(krb5_get_credentials_renew),
278 MAKE_FUNC_INFO(krb5_free_data),
279 MAKE_FUNC_INFO(krb5_free_data_contents),
280 MAKE_FUNC_INFO(krb5_free_unparsed_name),
281 MAKE_FUNC_INFO(krb5_os_localaddr),
282 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
283 MAKE_FUNC_INFO(krb5_copy_data),
284 MAKE_FUNC_INFO(krb5_free_creds),
285 MAKE_FUNC_INFO(krb5_build_principal),
286 MAKE_FUNC_INFO(krb5_get_renewed_creds),
287 MAKE_FUNC_INFO(krb5_free_addresses),
288 MAKE_FUNC_INFO(krb5_get_default_config_files),
289 MAKE_FUNC_INFO(krb5_free_config_files),
290 MAKE_FUNC_INFO(krb5_get_default_realm),
291 MAKE_FUNC_INFO(krb5_free_ticket),
292 MAKE_FUNC_INFO(krb5_decode_ticket),
293 MAKE_FUNC_INFO(krb5_get_host_realm),
294 MAKE_FUNC_INFO(krb5_free_host_realm),
295 MAKE_FUNC_INFO(krb5_free_addresses),
296 MAKE_FUNC_INFO(krb5_c_random_make_octets),
300 FUNC_INFO k4_fi[] = {
301 MAKE_FUNC_INFO(krb_get_cred),
302 MAKE_FUNC_INFO(krb_get_tf_realm),
303 MAKE_FUNC_INFO(krb_mk_req),
304 MAKE_FUNC_INFO(tkt_string),
308 FUNC_INFO k524_fi[] = {
309 MAKE_FUNC_INFO(krb524_init_ets),
310 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
314 FUNC_INFO profile_fi[] = {
315 MAKE_FUNC_INFO(profile_init),
316 MAKE_FUNC_INFO(profile_release),
317 MAKE_FUNC_INFO(profile_get_subsection_names),
318 MAKE_FUNC_INFO(profile_free_list),
319 MAKE_FUNC_INFO(profile_get_string),
320 MAKE_FUNC_INFO(profile_release_string),
324 FUNC_INFO ce_fi[] = {
325 MAKE_FUNC_INFO(com_err),
326 MAKE_FUNC_INFO(error_message),
330 FUNC_INFO service_fi[] = {
331 MAKE_FUNC_INFO(OpenSCManagerA),
332 MAKE_FUNC_INFO(OpenServiceA),
333 MAKE_FUNC_INFO(QueryServiceStatus),
334 MAKE_FUNC_INFO(CloseServiceHandle),
336 MAKE_FUNC_INFO(LsaNtStatusToWinError),
337 #endif /* USE_MS2MIT */
342 FUNC_INFO lsa_fi[] = {
343 MAKE_FUNC_INFO(LsaConnectUntrusted),
344 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
345 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
346 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
347 MAKE_FUNC_INFO(LsaGetLogonSessionData),
350 #endif /* USE_MS2MIT */
352 FUNC_INFO afst_fi[] = {
353 MAKE_FUNC_INFO(ktc_ListTokens),
354 MAKE_FUNC_INFO(ktc_GetToken),
355 MAKE_FUNC_INFO(ktc_SetToken),
356 MAKE_FUNC_INFO(ktc_ForgetAllTokens),
360 FUNC_INFO afsc_fi[] = {
361 MAKE_FUNC_INFO(cm_SearchCellFile),
362 MAKE_FUNC_INFO(cm_GetRootCellName),
366 /* Static Prototypes */
367 static char *afs_realm_of_cell(afsconf_cell *);
368 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
369 static int get_cellconfig(char *, afsconf_cell *, char *);
370 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
371 void *data, const char *name, const char *banner, int num_prompts,
372 krb5_prompt prompts[]);
375 /* Static Declarations */
376 static int inited = 0;
377 static int mid_cnt = 0;
378 static struct textField * mid_tb = NULL;
379 static HINSTANCE hKrb5 = 0;
380 static HINSTANCE hKrb4 = 0;
381 static HINSTANCE hKrb524 = 0;
383 static HINSTANCE hSecur32 = 0;
384 #endif /* USE_MS2MIT */
385 static HINSTANCE hAdvApi32 = 0;
386 static HINSTANCE hAfsTokens = 0;
387 static HINSTANCE hAfsConf = 0;
388 static HINSTANCE hComErr = 0;
389 static HINSTANCE hService = 0;
390 static HINSTANCE hProfile = 0;
391 static HINSTANCE hLeash = 0;
392 static HINSTANCE hCCAPI = 0;
393 static struct principal_ccache_data * princ_cc_data = NULL;
394 static struct cell_principal_map * cell_princ_map = NULL;
399 static int inited = 0;
402 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
403 LoadFuncs(KRB4_DLL, k4_fi, &hKrb5, 0, 1, 0, 0);
404 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
405 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
407 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
408 #endif /* USE_MS2MIT */
409 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
410 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
411 LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0);
412 LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0);
413 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
414 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
416 if ( KFW_is_available() ) {
417 char rootcell[MAXCELLCHARS+1];
419 KFW_import_windows_lsa();
420 #endif /* USE_MS2MIT */
421 KFW_import_ccache_data();
422 KFW_AFS_renew_expiring_credentials();
424 /* WIN32 NOTE: no way to get max chars */
425 if (!pcm_GetRootCellName(rootcell))
426 KFW_AFS_renew_token_for_cell(rootcell);
439 FreeLibrary(hProfile);
441 FreeLibrary(hAfsTokens);
443 FreeLibrary(hAfsConf);
445 FreeLibrary(hComErr);
447 FreeLibrary(hService);
450 FreeLibrary(hSecur32);
451 #endif /* USE_MS2MIT */
453 FreeLibrary(hKrb524);
461 KFW_is_available(void)
464 if ( hKrb5 && hComErr && hService &&
467 #endif /* USE_MS2MIT */
469 hProfile && hAfsTokens && hAfsConf )
475 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
476 int FreeContextFlag, krb5_context * ctx,
481 int krb5Error = ((int)(rc & 255));
493 errText = perror_message(rc);
494 _snprintf(message, sizeof(message),
495 "%s\n(Kerberos error %ld)\n\n%s failed",
500 if ( IsDebuggerPresent() )
501 OutputDebugString(message);
503 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
506 if (FreeContextFlag == 1)
508 if (ctx && *ctx != NULL)
510 if (cache && *cache != NULL) {
511 pkrb5_cc_close(*ctx, *cache);
515 pkrb5_free_context(*ctx);
524 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
526 struct principal_ccache_data * next = princ_cc_data;
527 krb5_principal principal = 0;
529 const char * ccname = NULL;
530 krb5_error_code code = 0;
531 krb5_error_code cc_code = 0;
537 if (ctx == 0 || cc == 0)
540 code = pkrb5_cc_get_principal(ctx, cc, &principal);
543 code = pkrb5_unparse_name(ctx, principal, &pname);
544 if ( code ) goto cleanup;
546 ccname = pkrb5_cc_get_name(ctx, cc);
547 if (!ccname) goto cleanup;
549 // Search the existing list to see if we have a match
551 for ( ; next ; next = next->next ) {
552 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
557 // If not, match add a new node to the beginning of the list and assign init it
559 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
560 next->next = princ_cc_data;
561 princ_cc_data = next;
562 next->principal = _strdup(pname);
563 next->ccache_name = _strdup(ccname);
564 next->from_lsa = lsa;
566 next->expiration_time = 0;
570 flags = 0; // turn off OPENCLOSE mode
571 code = pkrb5_cc_set_flags(ctx, cc, flags);
572 if ( code ) goto cleanup;
574 code = pkrb5_timeofday(ctx, &now);
576 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
578 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
579 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
581 // we found the ticket we are looking for
582 // check validity of timestamp
583 // We add a 5 minutes fudge factor to compensate for potential
584 // clock skew errors between the KDC and client OS
586 valid = ((creds.times.starttime > 0) &&
587 now >= (creds.times.starttime - 300) &&
588 now < (creds.times.endtime + 300) &&
589 !(creds.ticket_flags & TKT_FLG_INVALID));
591 if ( next->from_lsa) {
593 next->expiration_time = creds.times.endtime;
595 } else if ( valid ) {
597 next->expiration_time = creds.times.endtime;
598 next->renew = (creds.times.renew_till > creds.times.endtime) &&
599 (creds.ticket_flags & TKT_FLG_RENEWABLE);
602 next->expiration_time = 0;
606 pkrb5_free_cred_contents(ctx, &creds);
607 cc_code = KRB5_CC_END;
610 pkrb5_free_cred_contents(ctx, &creds);
613 if (cc_code == KRB5_CC_END) {
614 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
615 if (code) goto cleanup;
619 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
620 code = pkrb5_cc_set_flags(ctx, cc, flags);
623 pkrb5_free_unparsed_name(ctx,pname);
625 pkrb5_free_principal(ctx,principal);
629 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
631 struct principal_ccache_data * next = princ_cc_data;
632 char * response = NULL;
634 if ( !principal || !ccache )
638 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
640 // we always want to prefer the MS Kerberos LSA cache or
641 // the cache afscreds created specifically for the principal
642 // if the current entry is either one, drop the previous find
643 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
646 response = _strdup(next->ccache_name);
647 // MS Kerberos LSA is our best option so use it and quit
648 if ( next->from_lsa )
662 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
664 struct principal_ccache_data ** next = &princ_cc_data;
666 if ( !pname && !ccname )
670 if ( !strcmp((*next)->principal,pname) ||
671 !strcmp((*next)->ccache_name,ccname) ) {
673 free((*next)->principal);
674 free((*next)->ccache_name);
676 (*next) = (*next)->next;
683 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
685 struct cell_principal_map * next = cell_princ_map;
687 // Search the existing list to see if we have a match
689 for ( ; next ; next = next->next ) {
690 if ( !strcmp(next->cell, cell) ) {
691 if ( !strcmp(next->principal,pname) ) {
692 next->active = active;
695 // OpenAFS currently has a restriction of one active token per cell
696 // Therefore, whenever we update the table with a new active cell we
697 // must mark all of the other principal to cell entries as inactive.
705 // If not, match add a new node to the beginning of the list and assign init it
707 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
708 next->next = cell_princ_map;
709 cell_princ_map = next;
710 next->principal = _strdup(pname);
711 next->cell = _strdup(cell);
712 next->active = active;
717 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
719 struct cell_principal_map ** next = &cell_princ_map;
721 if ( !pname && !cell )
725 if ( !strcmp((*next)->principal,pname) ||
726 !strcmp((*next)->cell,cell) ) {
728 free((*next)->principal);
731 (*next) = (*next)->next;
737 // Returns (if possible) a principal which has been known in
738 // the past to have been used to obtain tokens for the specified
740 // TODO: Attempt to return one which has not yet expired by checking
741 // the principal/ccache data
743 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
745 struct cell_principal_map * next_map = cell_princ_map;
746 const char * princ = NULL;
753 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
756 next_map = next_map->next;
762 *principals = (char **) malloc(sizeof(char *) * count);
763 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
765 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
766 (*principals)[i++] = _strdup(next_map->principal);
773 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
776 struct cell_principal_map * next_map = cell_princ_map;
777 const char * princ = NULL;
783 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
786 next_map = next_map->next;
792 *cells = (char **) malloc(sizeof(char *) * count);
793 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
795 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
796 (*cells)[i++] = _strdup(next_map->cell);
802 /* Given a principal return an existing ccache or create one and return */
804 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
809 krb5_error_code code;
814 code = pkrb5_init_context(&ctx);
815 if (code) goto cleanup;
819 code = pkrb5_unparse_name(ctx, principal, &pname);
820 if (code) goto cleanup;
822 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
823 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
824 ccname = (char *)malloc(strlen(pname) + 5);
825 sprintf(ccname,"API:%s",pname);
827 code = pkrb5_cc_resolve(ctx, ccname, cc);
829 code = pkrb5_cc_default(ctx, cc);
830 if (code) goto cleanup;
837 pkrb5_free_unparsed_name(ctx,pname);
838 if (ctx && (ctx != alt_ctx))
839 pkrb5_free_context(ctx);
844 // Import Microsoft Credentials into a new MIT ccache
846 KFW_import_windows_lsa(void)
848 krb5_context ctx = 0;
850 krb5_principal princ = 0;
853 krb5_error_code code;
857 if ( !MSLSA_IsKerberosLogon() )
860 code = pkrb5_init_context(&ctx);
861 if (code) goto cleanup;
863 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
864 if (code) goto cleanup;
866 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
868 code = pkrb5_cc_get_principal(ctx, cc, &princ);
869 if ( code ) goto cleanup;
871 code = pkrb5_unparse_name(ctx,princ,&pname);
872 if ( code ) goto cleanup;
874 realm = krb5_princ_realm(ctx, princ);
875 for ( i=0; i<realm->length; i++ ) {
876 cell[i] = tolower(realm->data[i]);
880 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime());
881 if ( IsDebuggerPresent() ) {
883 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
884 OutputDebugString(message);
886 if ( code ) goto cleanup;
888 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
892 pkrb5_free_unparsed_name(ctx,pname);
894 pkrb5_free_principal(ctx,princ);
896 pkrb5_cc_close(ctx,cc);
898 pkrb5_free_context(ctx);
900 #endif /* USE_MS2MIT */
902 // If there are existing MIT credentials, copy them to a new
903 // ccache named after the principal
905 // Enumerate all existing MIT ccaches and construct entries
906 // in the principal_ccache table
908 // Enumerate all existing AFS Tokens and construct entries
909 // in the cell_principal table
911 KFW_import_ccache_data(void)
913 krb5_context ctx = 0;
915 krb5_principal principal = 0;
917 krb5_error_code code;
918 krb5_error_code cc_code;
921 struct _infoNC ** pNCi = NULL;
924 if ( !pcc_initialize )
927 if ( IsDebuggerPresent() )
928 OutputDebugString("KFW_import_ccache_data()\n");
930 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
931 if (code) goto cleanup;
933 code = pcc_get_NC_info(cc_ctx, &pNCi);
934 if (code) goto cleanup;
936 code = pkrb5_init_context(&ctx);
937 if (code) goto cleanup;
939 for ( i=0; pNCi[i]; i++ ) {
940 if ( pNCi[i]->vers != CC_CRED_V5 )
942 if ( IsDebuggerPresent() ) {
943 OutputDebugString("Principal: ");
944 OutputDebugString(pNCi[i]->principal);
945 OutputDebugString(" in ccache ");
946 OutputDebugString(pNCi[i]->name);
947 OutputDebugString("\n");
949 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
950 && strcmp(pNCi[i]->name,LSA_CCNAME)
953 krb5_ccache oldcc = 0;
954 for ( j=0; pNCi[j]; j++ ) {
955 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
963 if ( IsDebuggerPresent() )
964 OutputDebugString("copying ccache data to new ccache\n");
966 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
967 if (code) goto loop_cleanup;
968 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
969 if (code) goto loop_cleanup;
970 code = pkrb5_cc_initialize(ctx, cc, principal);
971 if (code) goto loop_cleanup;
972 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
973 if (code) goto loop_cleanup;
974 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
976 code = pkrb5_cc_close(ctx,cc);
978 code = pkrb5_cc_close(ctx,oldcc);
980 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
983 code = pkrb5_cc_close(ctx,oldcc);
985 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
986 if (code) goto loop_cleanup;
989 flags = 0; // turn off OPENCLOSE mode
990 code = pkrb5_cc_set_flags(ctx, cc, flags);
991 if ( code ) goto cleanup;
993 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
995 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
997 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
998 krb5_data * sname = krb5_princ_name(ctx, creds.server);
999 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1000 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1001 if ( sname && cell && !strcmp("afs",sname->data) ) {
1002 struct ktc_principal aserver;
1003 struct ktc_principal aclient;
1004 struct ktc_token atoken;
1007 if ( IsDebuggerPresent() ) {
1008 OutputDebugString("Found AFS ticket: ");
1009 OutputDebugString(sname->data);
1011 OutputDebugString("/");
1012 OutputDebugString(cell->data);
1014 OutputDebugString("@");
1015 OutputDebugString(realm->data);
1016 OutputDebugString("\n");
1019 memset(&aserver, '\0', sizeof(aserver));
1020 strcpy(aserver.name, sname->data);
1021 strcpy(aserver.cell, cell->data);
1023 code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1025 // Found a token in AFS Client Server which matches
1026 char pname[128], *p, *q;
1027 for ( p=pname, q=aclient.name; *q; p++, q++)
1029 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1033 if ( IsDebuggerPresent() ) {
1034 OutputDebugString("Found AFS token: ");
1035 OutputDebugString(pname);
1036 OutputDebugString("\n");
1039 if ( strcmp(pname,pNCi[i]->principal) )
1041 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1043 // Attempt to import it
1044 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1046 if ( IsDebuggerPresent() ) {
1047 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1050 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime());
1051 if ( IsDebuggerPresent() ) {
1053 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1054 OutputDebugString(message);
1057 } else if ( IsDebuggerPresent() ) {
1058 OutputDebugString("Found ticket: ");
1059 OutputDebugString(sname->data);
1060 if ( cell && cell->data ) {
1061 OutputDebugString("/");
1062 OutputDebugString(cell->data);
1064 OutputDebugString("@");
1065 OutputDebugString(realm->data);
1066 OutputDebugString("\n");
1068 pkrb5_free_cred_contents(ctx, &creds);
1071 if (cc_code == KRB5_CC_END) {
1072 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1073 if (cc_code) goto loop_cleanup;
1077 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1078 code = pkrb5_cc_set_flags(ctx, cc, flags);
1080 pkrb5_cc_close(ctx,cc);
1087 pkrb5_free_principal(ctx,principal);
1089 pkrb5_free_context(ctx);
1091 pcc_free_NC_info(cc_ctx, &pNCi);
1093 pcc_shutdown(&cc_ctx);
1098 KFW_AFS_get_cred(char * username,
1105 krb5_context ctx = 0;
1108 char ** realmlist = 0;
1109 krb5_principal principal = 0;
1111 krb5_error_code code;
1112 char local_cell[MAXCELLCHARS+1];
1113 char **cells = NULL;
1115 afsconf_cell cellconfig;
1117 if ( IsDebuggerPresent() ) {
1118 OutputDebugString("KFW_AFS_get_cred for token ");
1119 OutputDebugString(username);
1121 OutputDebugString("/");
1122 OutputDebugString(instance);
1124 OutputDebugString("@");
1125 OutputDebugString(cell);
1126 OutputDebugString("\n");
1129 code = pkrb5_init_context(&ctx);
1130 if ( code ) goto cleanup;
1132 code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1133 if ( code ) goto cleanup;
1135 realm = afs_realm_of_cell(&cellconfig); // do not free
1137 if ( IsDebuggerPresent() ) {
1138 OutputDebugString("Realm: ");
1139 OutputDebugString(realm);
1140 OutputDebugString("\n");
1143 code = pkrb5_build_principal(ctx, &principal, strlen(realm),
1145 (instance && instance[0]) ? instance : NULL,
1148 code = KFW_get_ccache(ctx, principal, &cc);
1149 if ( code ) goto cleanup;
1151 code = pkrb5_unparse_name(ctx, principal, &pname);
1152 if ( code ) goto cleanup;
1154 if ( lifetime == 0 )
1155 lifetime = pLeash_get_default_lifetime();
1157 code = KFW_kinit(ctx, cc, HWND_DESKTOP,
1161 pLeash_get_default_forwardable(),
1162 pLeash_get_default_proxiable(),
1163 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1164 pLeash_get_default_noaddresses(),
1165 pLeash_get_default_publicip());
1166 if ( IsDebuggerPresent() ) {
1168 sprintf(message,"KFW_kinit() returns: %d\n",code);
1169 OutputDebugString(message);
1171 if ( code ) goto cleanup;
1173 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1175 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime);
1176 if ( IsDebuggerPresent() ) {
1178 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1179 OutputDebugString(message);
1181 if ( code ) goto cleanup;
1183 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1185 // Attempt to obtain new tokens for other cells supported by the same
1187 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1188 if ( cell_count > 1 ) {
1189 while ( cell_count-- ) {
1190 if ( strcmp(cells[cell_count],cell) ) {
1191 if ( IsDebuggerPresent() ) {
1193 sprintf(message,"found another cell for the same principal: %s\n",cell);
1194 OutputDebugString(message);
1196 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1197 if ( code ) continue;
1199 realm = afs_realm_of_cell(&cellconfig); // do not free
1200 if ( IsDebuggerPresent() ) {
1201 OutputDebugString("Realm: ");
1202 OutputDebugString(realm);
1203 OutputDebugString("\n");
1206 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime);
1207 if ( IsDebuggerPresent() ) {
1209 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1210 OutputDebugString(message);
1213 free(cells[cell_count]);
1216 } else if ( cell_count == 1 ) {
1223 pkrb5_free_unparsed_name(ctx,pname);
1225 pkrb5_cc_close(ctx, cc);
1227 if ( code && reasonP ) {
1228 *reasonP = (char *)perror_message(code);
1234 KFW_AFS_destroy_tickets_for_cell(char * cell)
1236 krb5_context ctx = 0;
1237 krb5_error_code code;
1239 char ** principals = NULL;
1241 if ( IsDebuggerPresent() ) {
1242 OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
1243 OutputDebugString(cell);
1244 OutputDebugString("\n");
1247 code = pkrb5_init_context(&ctx);
1250 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1252 krb5_principal princ = 0;
1256 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1257 if ( cell_count > 1 ) {
1258 // TODO - What we really should do here is verify whether or not any of the
1259 // other cells which use this principal to obtain its credentials actually
1260 // have valid tokens or not. If they are currently using these credentials
1261 // we will skip them. For the time being we assume that if there is an active
1262 // map in the table that they are actively being used.
1266 code = pkrb5_parse_name(ctx, principals[count], &princ);
1267 if (code) goto loop_cleanup;
1269 code = KFW_get_ccache(ctx, princ, &cc);
1270 if (code) goto loop_cleanup;
1272 code = pkrb5_cc_destroy(ctx, cc);
1277 pkrb5_cc_close(ctx, cc);
1281 pkrb5_free_principal(ctx, princ);
1285 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1286 free(principals[count]);
1290 pkrb5_free_context(ctx);
1295 KFW_AFS_renew_expiring_credentials(void)
1297 krb5_error_code code = 0;
1298 krb5_context ctx = 0;
1301 struct principal_ccache_data * pcc_next = princ_cc_data;
1304 const char * realm = NULL;
1305 char local_cell[MAXCELLCHARS+1]="";
1306 afsconf_cell cellconfig;
1308 if ( pcc_next == NULL ) // nothing to do
1311 if ( IsDebuggerPresent() ) {
1312 OutputDebugString("KFW_AFS_renew_expiring_credentials\n");
1315 code = pkrb5_init_context(&ctx);
1316 if (code) goto cleanup;
1318 code = pkrb5_timeofday(ctx, &now);
1319 if (code) goto cleanup;
1321 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1322 if ( pcc_next->expired )
1325 if ( now >= (pcc_next->expiration_time) ) {
1326 if ( !pcc_next->from_lsa ) {
1327 pcc_next->expired = 1;
1332 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1333 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1336 code = KFW_renew(ctx,cc);
1338 if ( code && pcc_next->from_lsa)
1340 #endif /* USE_MS2MIT */
1343 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1344 if (code) goto loop_cleanup;
1346 // Attempt to obtain new tokens for other cells supported by the same
1348 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1349 if ( cell_count > 0 ) {
1350 while ( cell_count-- ) {
1351 if ( IsDebuggerPresent() ) {
1352 OutputDebugString("Cell: ");
1353 OutputDebugString(cells[cell_count]);
1354 OutputDebugString("\n");
1356 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1357 if ( code ) continue;
1358 realm = afs_realm_of_cell(&cellconfig); // do not free
1359 if ( IsDebuggerPresent() ) {
1360 OutputDebugString("Realm: ");
1361 OutputDebugString(realm);
1362 OutputDebugString("\n");
1364 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime());
1365 if ( IsDebuggerPresent() ) {
1367 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1368 OutputDebugString(message);
1370 free(cells[cell_count]);
1378 pkrb5_cc_close(ctx,cc);
1385 pkrb5_cc_close(ctx,cc);
1387 pkrb5_free_context(ctx);
1394 KFW_AFS_renew_token_for_cell(char * cell)
1396 krb5_error_code code = 0;
1397 krb5_context ctx = 0;
1399 char ** principals = NULL;
1401 if ( IsDebuggerPresent() ) {
1402 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1403 OutputDebugString(cell);
1404 OutputDebugString("\n");
1407 code = pkrb5_init_context(&ctx);
1408 if (code) goto cleanup;
1410 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1412 krb5_principal princ = 0;
1413 krb5_principal service = 0;
1414 krb5_creds mcreds, creds;
1416 const char * realm = NULL;
1417 afsconf_cell cellconfig;
1418 char local_cell[MAXCELLCHARS+1];
1421 code = pkrb5_parse_name(ctx, principals[count], &princ);
1422 if (code) goto loop_cleanup;
1424 code = KFW_get_ccache(ctx, princ, &cc);
1425 if (code) goto loop_cleanup;
1427 code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1428 if ( code ) goto loop_cleanup;
1430 realm = afs_realm_of_cell(&cellconfig); // do not free
1431 if ( IsDebuggerPresent() ) {
1432 OutputDebugString("Realm: ");
1433 OutputDebugString(realm);
1434 OutputDebugString("\n");
1437 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1438 realm, "afs", cell, NULL);
1440 memset(&mcreds, 0, sizeof(krb5_creds));
1441 mcreds.client = princ;
1442 mcreds.server = service;
1444 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1446 if ( IsDebuggerPresent() ) {
1447 char * cname, *sname;
1448 pkrb5_unparse_name(ctx, creds.client, &cname);
1449 pkrb5_unparse_name(ctx, creds.server, &sname);
1450 OutputDebugString("Removing credential for client \"");
1451 OutputDebugString(cname);
1452 OutputDebugString("\" and service \"");
1453 OutputDebugString(sname);
1454 OutputDebugString("\"\n");
1455 pkrb5_free_unparsed_name(ctx,cname);
1456 pkrb5_free_unparsed_name(ctx,sname);
1459 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1460 pkrb5_free_principal(ctx, creds.client);
1461 pkrb5_free_principal(ctx, creds.server);
1464 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime());
1465 if ( IsDebuggerPresent() ) {
1467 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1468 OutputDebugString(message);
1473 pkrb5_cc_close(ctx, cc);
1477 pkrb5_free_principal(ctx, princ);
1481 pkrb5_free_principal(ctx, service);
1485 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1486 free(principals[count]);
1490 code = -1; // we did not renew the tokens
1493 pkrb5_free_context(ctx);
1494 return (code ? FALSE : TRUE);
1499 KFW_AFS_renew_tokens_for_all_cells(void)
1501 struct cell_principal_map * next = cell_princ_map;
1503 if ( IsDebuggerPresent() )
1504 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1509 for ( ; next ; next = next->next ) {
1511 KFW_AFS_renew_token_for_cell(next->cell);
1517 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1519 krb5_error_code code = 0;
1520 krb5_context ctx = 0;
1522 krb5_principal me = 0;
1523 krb5_principal server = 0;
1524 krb5_creds my_creds;
1525 krb5_data *realm = 0;
1527 memset(&my_creds, 0, sizeof(krb5_creds));
1532 code = pkrb5_init_context(&ctx);
1533 if (code) goto cleanup;
1539 code = pkrb5_cc_default(ctx, &cc);
1540 if (code) goto cleanup;
1543 code = pkrb5_cc_get_principal(ctx, cc, &me);
1544 if (code) goto cleanup;
1546 realm = krb5_princ_realm(ctx, me);
1548 code = pkrb5_build_principal_ext(ctx, &server,
1549 realm->length,realm->data,
1550 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1551 realm->length,realm->data,
1556 if ( IsDebuggerPresent() ) {
1557 char * cname, *sname;
1558 pkrb5_unparse_name(ctx, me, &cname);
1559 pkrb5_unparse_name(ctx, server, &sname);
1560 OutputDebugString("Renewing credential for client \"");
1561 OutputDebugString(cname);
1562 OutputDebugString("\" and service \"");
1563 OutputDebugString(sname);
1564 OutputDebugString("\"\n");
1565 pkrb5_free_unparsed_name(ctx,cname);
1566 pkrb5_free_unparsed_name(ctx,sname);
1569 my_creds.client = me;
1570 my_creds.server = server;
1572 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1574 if ( IsDebuggerPresent() ) {
1576 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1577 OutputDebugString(message);
1582 code = pkrb5_cc_initialize(ctx, cc, me);
1584 if ( IsDebuggerPresent() ) {
1586 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1587 OutputDebugString(message);
1592 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1594 if ( IsDebuggerPresent() ) {
1596 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1597 OutputDebugString(message);
1603 if (my_creds.client == me)
1604 my_creds.client = 0;
1605 if (my_creds.server == server)
1606 my_creds.server = 0;
1607 pkrb5_free_cred_contents(ctx, &my_creds);
1609 pkrb5_free_principal(ctx, me);
1611 pkrb5_free_principal(ctx, server);
1612 if (cc && (cc != alt_cc))
1613 pkrb5_cc_close(ctx, cc);
1614 if (ctx && (ctx != alt_ctx))
1615 pkrb5_free_context(ctx);
1620 KFW_kinit( krb5_context alt_ctx,
1623 char *principal_name,
1625 krb5_deltat lifetime,
1628 krb5_deltat renew_life,
1633 krb5_error_code code = 0;
1634 krb5_context ctx = 0;
1636 krb5_principal me = 0;
1638 krb5_creds my_creds;
1639 krb5_get_init_creds_opt options;
1640 krb5_address ** addrs = NULL;
1641 int i = 0, addr_count = 0;
1643 if (!pkrb5_init_context)
1646 pkrb5_get_init_creds_opt_init(&options);
1647 memset(&my_creds, 0, sizeof(my_creds));
1655 code = pkrb5_init_context(&ctx);
1656 if (code) goto cleanup;
1662 code = pkrb5_cc_default(ctx, &cc);
1663 if (code) goto cleanup;
1666 code = pkrb5_parse_name(ctx, principal_name, &me);
1670 code = pkrb5_unparse_name(ctx, me, &name);
1675 lifetime = pLeash_get_default_lifetime();
1683 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1684 pkrb5_get_init_creds_opt_set_forwardable(&options,
1685 forwardable ? 1 : 0);
1686 pkrb5_get_init_creds_opt_set_proxiable(&options,
1688 pkrb5_get_init_creds_opt_set_renew_life(&options,
1691 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1695 // we are going to add the public IP address specified by the user
1696 // to the list provided by the operating system
1697 krb5_address ** local_addrs=NULL;
1700 pkrb5_os_localaddr(ctx, &local_addrs);
1701 while ( local_addrs[i++] );
1704 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1706 pkrb5_free_addresses(ctx, local_addrs);
1709 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1711 while ( local_addrs[i] ) {
1712 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1713 if (addrs[i] == NULL) {
1714 pkrb5_free_addresses(ctx, local_addrs);
1718 addrs[i]->magic = local_addrs[i]->magic;
1719 addrs[i]->addrtype = local_addrs[i]->addrtype;
1720 addrs[i]->length = local_addrs[i]->length;
1721 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1722 if (!addrs[i]->contents) {
1723 pkrb5_free_addresses(ctx, local_addrs);
1727 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1728 local_addrs[i]->length); /* safe */
1731 pkrb5_free_addresses(ctx, local_addrs);
1733 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1734 if (addrs[i] == NULL)
1737 addrs[i]->magic = KV5M_ADDRESS;
1738 addrs[i]->addrtype = AF_INET;
1739 addrs[i]->length = 4;
1740 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1741 if (!addrs[i]->contents)
1744 netIPAddr = htonl(publicIP);
1745 memcpy(addrs[i]->contents,&netIPAddr,4);
1747 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1752 code = pkrb5_get_init_creds_password(ctx,
1755 password, // password
1756 KRB5_prompter, // prompter
1757 hParent, // prompter data
1764 code = pkrb5_cc_initialize(ctx, cc, me);
1768 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1774 for ( i=0;i<addr_count;i++ ) {
1776 if ( addrs[i]->contents )
1777 free(addrs[i]->contents);
1782 if (my_creds.client == me)
1783 my_creds.client = 0;
1784 pkrb5_free_cred_contents(ctx, &my_creds);
1786 pkrb5_free_unparsed_name(ctx, name);
1788 pkrb5_free_principal(ctx, me);
1789 if (cc && (cc != alt_cc))
1790 pkrb5_cc_close(ctx, cc);
1791 if (ctx && (ctx != alt_ctx))
1792 pkrb5_free_context(ctx);
1798 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
1802 krb5_error_code code;
1810 code = pkrb5_init_context(&ctx);
1811 if (code) goto cleanup;
1817 code = pkrb5_cc_default(ctx, &cc);
1818 if (code) goto cleanup;
1821 code = pkrb5_cc_destroy(ctx, cc);
1822 if ( !code ) cc = 0;
1825 if (cc && (cc != alt_cc))
1826 pkrb5_cc_close(ctx, cc);
1827 if (ctx && (ctx != alt_ctx))
1828 pkrb5_free_context(ctx);
1836 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1838 NTSTATUS Status = 0;
1840 TOKEN_STATISTICS Stats;
1846 *ppSessionData = NULL;
1848 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1852 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1853 CloseHandle( TokenHandle );
1857 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1858 if ( FAILED(Status) || !ppSessionData )
1865 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1866 // cache. It validates whether or not it is reasonable to assume that if we
1867 // attempted to retrieve valid tickets we could do so. Microsoft does not
1868 // automatically renew expired tickets. Therefore, the cache could contain
1869 // expired or invalid tickets. Microsoft also caches the user's password
1870 // and will use it to retrieve new TGTs if the cache is empty and tickets
1874 MSLSA_IsKerberosLogon(VOID)
1876 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1877 BOOL Success = FALSE;
1879 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1880 if ( pSessionData->AuthenticationPackage.Buffer ) {
1886 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1887 usLength = (pSessionData->AuthenticationPackage).Length;
1890 lstrcpynW (buffer, usBuffer, usLength);
1891 lstrcatW (buffer,L"");
1892 if ( !lstrcmpW(L"Kerberos",buffer) )
1896 pLsaFreeReturnBuffer(pSessionData);
1900 #endif /* USE_MS2MIT */
1902 static BOOL CALLBACK
1903 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1907 switch ( message ) {
1909 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1911 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1914 for ( i=0; i < mid_cnt ; i++ ) {
1915 if (mid_tb[i].echo == 0)
1916 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1917 else if (mid_tb[i].echo == 2)
1918 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1923 switch ( LOWORD(wParam) ) {
1925 for ( i=0; i < mid_cnt ; i++ ) {
1926 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1927 *mid_tb[i].buf = '\0';
1931 EndDialog(hDialog, LOWORD(wParam));
1939 lpwAlign( LPWORD lpIn )
1947 return (LPWORD) ul;;
1951 * dialog widths are measured in 1/4 character widths
1952 * dialog height are measured in 1/8 character heights
1956 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
1957 char * ptext[], int numlines, int width,
1958 int tb_cnt, struct textField * tb)
1962 LPDLGITEMTEMPLATE lpdit;
1968 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
1975 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
1977 // Define a dialog box.
1979 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
1980 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
1981 | DS_SETFOREGROUND | DS_3DLOOK
1982 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
1983 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
1986 lpdt->cx = 20 + width * 4;
1987 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
1989 lpw = (LPWORD) (lpdt + 1);
1990 *lpw++ = 0; // no menu
1991 *lpw++ = 0; // predefined dialog box class (by default)
1993 lpwsz = (LPWSTR) lpw;
1994 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
1996 *lpw++ = 8; // font size (points)
1997 lpwsz = (LPWSTR) lpw;
1998 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2002 //-----------------------
2003 // Define an OK button.
2004 //-----------------------
2005 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2006 lpdit = (LPDLGITEMTEMPLATE) lpw;
2007 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2008 lpdit->dwExtendedStyle = 0;
2009 lpdit->x = (lpdt->cx - 14)/4 - 20;
2010 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2013 lpdit->id = IDOK; // OK button identifier
2015 lpw = (LPWORD) (lpdit + 1);
2017 *lpw++ = 0x0080; // button class
2019 lpwsz = (LPWSTR) lpw;
2020 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2022 *lpw++ = 0; // no creation data
2024 //-----------------------
2025 // Define an Cancel button.
2026 //-----------------------
2027 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2028 lpdit = (LPDLGITEMTEMPLATE) lpw;
2029 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2030 lpdit->dwExtendedStyle = 0;
2031 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2032 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2035 lpdit->id = IDCANCEL; // CANCEL button identifier
2037 lpw = (LPWORD) (lpdit + 1);
2039 *lpw++ = 0x0080; // button class
2041 lpwsz = (LPWSTR) lpw;
2042 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2044 *lpw++ = 0; // no creation data
2046 /* Add controls for preface data */
2047 for ( i=0; i<numlines; i++) {
2048 /*-----------------------
2049 * Define a static text control.
2050 *-----------------------*/
2051 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2052 lpdit = (LPDLGITEMTEMPLATE) lpw;
2053 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2054 lpdit->dwExtendedStyle = 0;
2056 lpdit->y = 10 + i * 14;
2057 lpdit->cx = strlen(ptext[i]) * 4 + 10;
2059 lpdit->id = ID_TEXT + i; // text identifier
2061 lpw = (LPWORD) (lpdit + 1);
2063 *lpw++ = 0x0082; // static class
2065 lpwsz = (LPWSTR) lpw;
2066 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2067 -1, lpwsz, 2*width);
2069 *lpw++ = 0; // no creation data
2072 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2073 if ( pwid < strlen(tb[i].label) )
2074 pwid = strlen(tb[i].label);
2077 for ( i=0; i<tb_cnt; i++) {
2079 /*-----------------------
2080 * Define a static text control.
2081 *-----------------------*/
2082 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2083 lpdit = (LPDLGITEMTEMPLATE) lpw;
2084 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2085 lpdit->dwExtendedStyle = 0;
2087 lpdit->y = 10 + (numlines + i + 1) * 14;
2088 lpdit->cx = pwid * 4;
2090 lpdit->id = ID_TEXT + numlines + i; // text identifier
2092 lpw = (LPWORD) (lpdit + 1);
2094 *lpw++ = 0x0082; // static class
2096 lpwsz = (LPWSTR) lpw;
2097 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2100 *lpw++ = 0; // no creation data
2102 /*-----------------------
2103 * Define an edit control.
2104 *-----------------------*/
2105 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2106 lpdit = (LPDLGITEMTEMPLATE) lpw;
2107 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2108 lpdit->dwExtendedStyle = 0;
2109 lpdit->x = 10 + (pwid + 1) * 4;
2110 lpdit->y = 10 + (numlines + i + 1) * 14;
2111 lpdit->cx = (width - (pwid + 1)) * 4;
2113 lpdit->id = ID_MID_TEXT + i; // identifier
2115 lpw = (LPWORD) (lpdit + 1);
2117 *lpw++ = 0x0081; // edit class
2119 lpwsz = (LPWSTR) lpw;
2120 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2123 *lpw++ = 0; // no creation data
2127 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2128 hwndOwner, (DLGPROC) MultiInputDialogProc);
2132 case 0: /* Timeout */
2140 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2141 MessageBox(hwndOwner,
2144 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2151 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2153 HINSTANCE hInst = 0;
2157 char * plines[16], *p = preface ? preface : "";
2160 for ( i=0; i<16; i++ )
2163 while (*p && numlines < 16) {
2164 plines[numlines++] = p;
2165 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2166 if ( *p == '\r' && *(p+1) == '\n' ) {
2169 } else if ( *p == '\n' ) {
2172 if ( strlen(plines[numlines-1]) > maxwidth )
2173 maxwidth = strlen(plines[numlines-1]);
2176 for ( i=0;i<n;i++ ) {
2177 len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2178 if ( maxwidth < len )
2182 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2185 static krb5_error_code KRB5_CALLCONV
2186 KRB5_prompter( krb5_context context,
2191 krb5_prompt prompts[])
2193 krb5_error_code errcode = 0;
2195 struct textField * tb = NULL;
2196 int len = 0, blen=0, nlen=0;
2197 HWND hParent = (HWND)data;
2200 nlen = strlen(name)+2;
2203 blen = strlen(banner)+2;
2205 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2208 memset(tb,0,sizeof(struct textField) * num_prompts);
2209 for ( i=0; i < num_prompts; i++ ) {
2210 tb[i].buf = prompts[i].reply->data;
2211 tb[i].len = prompts[i].reply->length;
2212 tb[i].label = prompts[i].prompt;
2214 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2217 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2219 for ( i=0; i < num_prompts; i++ )
2220 prompts[i].reply->length = strlen(prompts[i].reply->data);
2228 for (i = 0; i < num_prompts; i++) {
2229 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2236 KFW_AFS_wait_for_service_start(void)
2241 CurrentState = SERVICE_START_PENDING;
2242 memset(HostName, '\0', sizeof(HostName));
2243 gethostname(HostName, sizeof(HostName));
2245 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2247 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2249 if ( IsDebuggerPresent() ) {
2250 switch ( CurrentState ) {
2251 case SERVICE_STOPPED:
2252 OutputDebugString("SERVICE_STOPPED\n");
2254 case SERVICE_START_PENDING:
2255 OutputDebugString("SERVICE_START_PENDING\n");
2257 case SERVICE_STOP_PENDING:
2258 OutputDebugString("SERVICE_STOP_PENDING\n");
2260 case SERVICE_RUNNING:
2261 OutputDebugString("SERVICE_RUNNING\n");
2263 case SERVICE_CONTINUE_PENDING:
2264 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2266 case SERVICE_PAUSE_PENDING:
2267 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2269 case SERVICE_PAUSED:
2270 OutputDebugString("SERVICE_PAUSED\n");
2273 OutputDebugString("UNKNOWN Service State\n");
2276 if (CurrentState == SERVICE_STOPPED)
2278 if (CurrentState == SERVICE_RUNNING)
2294 memset(HostName, '\0', sizeof(HostName));
2295 gethostname(HostName, sizeof(HostName));
2296 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2298 if (CurrentState != SERVICE_RUNNING)
2301 rc = pktc_ForgetAllTokens();
2308 krb5_context alt_ctx,
2319 struct ktc_principal aserver;
2320 struct ktc_principal aclient;
2321 char username[BUFSIZ]; /* To hold client username structure */
2322 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2323 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2324 char local_cell[MAXCELLCHARS+1];
2325 char Dmycell[MAXCELLCHARS+1];
2326 struct ktc_token atoken;
2327 struct ktc_token btoken;
2328 afsconf_cell ak_cellconfig; /* General information about the cell */
2329 char RealmName[128];
2331 char ServiceName[128];
2335 krb5_context ctx = 0;
2338 krb5_creds * k5creds = 0;
2339 krb5_error_code code;
2340 krb5_principal client_principal = 0;
2344 memset(HostName, '\0', sizeof(HostName));
2345 gethostname(HostName, sizeof(HostName));
2346 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2347 if ( IsDebuggerPresent() )
2348 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2351 if (CurrentState != SERVICE_RUNNING) {
2352 if ( IsDebuggerPresent() )
2353 OutputDebugString("AFSD Service NOT RUNNING\n");
2357 memset(RealmName, '\0', sizeof(RealmName));
2358 memset(CellName, '\0', sizeof(CellName));
2359 memset(ServiceName, '\0', sizeof(ServiceName));
2360 memset(realm_of_user, '\0', sizeof(realm_of_user));
2361 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2362 if (cell && cell[0])
2363 strcpy(Dmycell, cell);
2365 memset(Dmycell, '\0', sizeof(Dmycell));
2367 // NULL or empty cell returns information on local cell
2368 if (rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2370 KFW_AFS_error(rc, "get_cellconfig()");
2377 code = pkrb5_init_context(&ctx);
2378 if (code) goto cleanup;
2384 code = pkrb5_cc_default(ctx, &cc);
2385 if (code) goto skip_krb5_init;
2388 memset((char *)&increds, 0, sizeof(increds));
2390 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2392 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2394 OutputDebugString("Principal Not Found for ccache\n");
2396 goto skip_krb5_init;
2398 i = krb5_princ_realm(ctx, client_principal)->length;
2401 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2402 realm_of_user[i] = 0;
2407 if ( !try_krb5 || !realm_of_user[0] ) {
2408 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2416 strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
2418 if (strlen(service) == 0)
2419 strcpy(ServiceName, "afs");
2421 strcpy(ServiceName, service);
2423 if (strlen(cell) == 0)
2424 strcpy(CellName, local_cell);
2426 strcpy(CellName, cell);
2428 if (strlen(realm) == 0)
2429 strcpy(RealmName, realm_of_cell);
2431 strcpy(RealmName, realm);
2433 memset(&creds, '\0', sizeof(creds));
2436 /* First try service/cell@REALM */
2437 if (code = pkrb5_build_principal(ctx, &increds.server,
2447 increds.client = client_principal;
2448 increds.times.endtime = 0;
2449 /* Ask for DES since that is what V4 understands */
2450 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2452 if ( IsDebuggerPresent() ) {
2453 char * cname, *sname;
2454 pkrb5_unparse_name(ctx, increds.client, &cname);
2455 pkrb5_unparse_name(ctx, increds.server, &sname);
2456 OutputDebugString("Getting credentials for \"");
2457 OutputDebugString(cname);
2458 OutputDebugString("\" and service \"");
2459 OutputDebugString(sname);
2460 OutputDebugString("\"\n");
2461 pkrb5_free_unparsed_name(ctx,cname);
2462 pkrb5_free_unparsed_name(ctx,sname);
2465 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2466 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2467 code == KRB5KRB_ERR_GENERIC /* heimdal */) {
2468 /* Or service@REALM */
2469 pkrb5_free_principal(ctx,increds.server);
2471 code = pkrb5_build_principal(ctx, &increds.server,
2477 if ( IsDebuggerPresent() ) {
2478 char * cname, *sname;
2479 pkrb5_unparse_name(ctx, increds.client, &cname);
2480 pkrb5_unparse_name(ctx, increds.server, &sname);
2481 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2482 OutputDebugString("Trying again: getting credentials for \"");
2483 OutputDebugString(cname);
2484 OutputDebugString("\" and service \"");
2485 OutputDebugString(sname);
2486 OutputDebugString("\"\n");
2487 pkrb5_free_unparsed_name(ctx,cname);
2488 pkrb5_free_unparsed_name(ctx,sname);
2492 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2496 if ( IsDebuggerPresent() ) {
2498 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2499 OutputDebugString(message);
2504 /* This requires krb524d to be running with the KDC */
2505 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2506 pkrb5_free_creds(ctx, k5creds);
2508 if ( IsDebuggerPresent() ) {
2510 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2511 OutputDebugString(message);
2519 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
2520 if (rc == NO_TKT_FIL) {
2521 // if the problem is that we have no krb4 tickets
2522 // do not attempt to continue
2526 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
2530 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
2532 if ((rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
2537 else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
2539 if ((rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
2554 memset(&aserver, '\0', sizeof(aserver));
2555 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2556 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2558 strcpy(username, creds.pname);
2561 strcat(username, ".");
2562 strcat(username, creds.pinst);
2565 memset(&atoken, '\0', sizeof(atoken));
2566 atoken.kvno = creds.kvno;
2567 atoken.startTime = creds.issue_date;
2568 atoken.endTime = creds.issue_date + (creds.lifetime * 300);
2569 memcpy(&atoken.sessionKey, creds.session, 8);
2570 atoken.ticketLen = creds.ticket_st.length;
2571 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
2574 rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2575 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2576 if ( rc == KTC_NOCM && retry < 20 ) {
2579 goto retry_gettoken;
2581 KFW_AFS_error(rc, "ktc_GetToken()");
2586 if (atoken.kvno == btoken.kvno &&
2587 atoken.ticketLen == btoken.ticketLen &&
2588 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2589 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2594 // * Reset the "aclient" structure before we call ktc_SetToken.
2595 // * This structure was first set by the ktc_GetToken call when
2596 // * we were comparing whether identical tokens already existed.
2598 strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
2599 strcpy(aclient.instance, "");
2600 strncpy(aclient.cell, creds.realm, MAXKTCREALMLEN - 1);
2602 if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0))
2604 KFW_AFS_error(rc, "ktc_SetToken()");
2610 if (client_principal)
2611 pkrb5_free_principal(ctx,client_principal);
2612 /* increds.client == client_principal */
2614 pkrb5_free_principal(ctx,increds.server);
2615 if (cc && (cc != alt_cc))
2616 pkrb5_cc_close(ctx, cc);
2617 if (ctx && (ctx != alt_ctx))
2618 pkrb5_free_context(ctx);
2623 /**************************************/
2624 /* afs_realm_of_cell(): */
2625 /**************************************/
2627 afs_realm_of_cell(afsconf_cell *cellconfig)
2629 static char krbrlm[REALM_SZ+1]="";
2630 krb5_context ctx = 0;
2631 char ** realmlist=NULL;
2637 r = pkrb5_init_context(&ctx);
2639 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
2640 if ( !r && realmlist && realmlist[0] ) {
2641 strcpy(krbrlm, realmlist[0]);
2642 pkrb5_free_host_realm(ctx, realmlist);
2645 pkrb5_free_context(ctx);
2650 char *t = cellconfig->name;
2655 if (islower(c)) c=toupper(c);
2663 /**************************************/
2664 /* get_cellconfig(): */
2665 /**************************************/
2667 get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell)
2670 char newcell[MAXCELLCHARS+1];
2672 local_cell[0] = (char)0;
2673 memset(cellconfig, 0, sizeof(*cellconfig));
2675 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2676 if (rc = pcm_GetRootCellName(local_cell))
2681 if (strlen(cell) == 0)
2682 strcpy(cell, local_cell);
2684 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
2685 strcpy(cellconfig->name, cell);
2687 return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
2690 /**************************************/
2691 /* get_cellconfig_callback(): */
2692 /**************************************/
2694 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
2696 afsconf_cell *cc = (afsconf_cell *)cellconfig;
2698 cc->hostAddr[cc->numServers] = *addrp;
2699 strcpy(cc->hostName[cc->numServers], namep);
2705 /**************************************/
2706 /* KFW_AFS_error(): */
2707 /**************************************/
2709 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2712 const char *errText;
2714 // Using AFS defines as error messages for now, until Transarc
2715 // gets back to me with "string" translations of each of these
2717 if (rc == KTC_ERROR)
2718 errText = "KTC_ERROR";
2719 else if (rc == KTC_TOOBIG)
2720 errText = "KTC_TOOBIG";
2721 else if (rc == KTC_INVAL)
2722 errText = "KTC_INVAL";
2723 else if (rc == KTC_NOENT)
2724 errText = "KTC_NOENT";
2725 else if (rc == KTC_PIOCTLFAIL)
2726 errText = "KTC_PIOCTLFAIL";
2727 else if (rc == KTC_NOPIOCTL)
2728 errText = "KTC_NOPIOCTL";
2729 else if (rc == KTC_NOCELL)
2730 errText = "KTC_NOCELL";
2731 else if (rc == KTC_NOCM)
2732 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2734 errText = "Unknown error!";
2736 sprintf(message, "%s\n(%s failed)", errText, FailedFunctionName);
2738 if ( IsDebuggerPresent() ) {
2739 OutputDebugString(message);
2740 OutputDebugString("\n");
2742 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
2748 LPSTR lpszMachineName,
2749 LPSTR lpszServiceName,
2750 DWORD *lpdwCurrentState)
2753 SC_HANDLE schSCManager = NULL;
2754 SC_HANDLE schService = NULL;
2755 DWORD fdwDesiredAccess = 0;
2756 SERVICE_STATUS ssServiceStatus = {0};
2759 *lpdwCurrentState = 0;
2761 fdwDesiredAccess = GENERIC_READ;
2763 schSCManager = OpenSCManager(lpszMachineName,
2767 if(schSCManager == NULL)
2769 hr = GetLastError();
2773 schService = OpenService(schSCManager,
2777 if(schService == NULL)
2779 hr = GetLastError();
2783 fRet = QueryServiceStatus(schService,
2788 hr = GetLastError();
2792 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
2796 CloseServiceHandle(schService);
2797 CloseServiceHandle(schSCManager);
2810 for (n = 0; fi[n].func_ptr_var; n++)
2811 *(fi[n].func_ptr_var) = 0;
2812 if (h) FreeLibrary(h);
2817 const char* dll_name,
2819 HINSTANCE* ph, // [out, optional] - DLL handle
2820 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
2821 int cleanup, // cleanup function pointers and unload on error
2822 int go_on, // continue loading even if some functions cannot be loaded
2823 int silent // do not pop-up a system dialog if DLL cannot be loaded
2832 if (pindex) *pindex = -1;
2834 for (n = 0; fi[n].func_ptr_var; n++)
2835 *(fi[n].func_ptr_var) = 0;
2838 em = SetErrorMode(SEM_FAILCRITICALERRORS);
2839 h = LoadLibrary(dll_name);
2847 for (i = 0; (go_on || !error) && (i < n); i++)
2849 void* p = (void*)GetProcAddress(h, fi[i].func_name);
2855 *(fi[i].func_ptr_var) = p;
2858 if (pindex) *pindex = last_i;
2859 if (error && cleanup && !go_on) {
2860 for (i = 0; i < n; i++) {
2861 *(fi[i].func_ptr_var) = 0;
2867 if (error) return 0;
2872 // Cell Accessibility Functions
2873 // based on work originally submitted to the CMU Computer Club
2874 // by Jeffrey Hutzelman
2876 // These would work great if the fsProbe interface had been
2877 // ported to Windows
2880 void probeComplete()
2886 struct ping_params {
2887 unsigned short port; // in
2888 int retry_delay; // in seconds
2891 int wait; // in seconds
2892 int retry; // in attempts
2894 int max_hosts; // in
2895 int hosts_attempted; // out
2898 // the fsHandler is where we receive the answer to the probe
2902 ping_count = fsprobe_Results.probeNum;
2903 if (!*fsprobe_Results.probeOK)
2906 if (waiting) complete();
2908 if (ping_count == retry)
2913 // ping_fs is a callback routine meant to be called from within
2914 // cm_SearchCellFile() or cm_SearchCellDNS()
2916 pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep)
2919 struct ping_params * pp = (struct ping_params *) ping_params;
2921 if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts )
2924 pp->hosts_attempted++;
2926 if (pp->port && addrp->sin_port != htons(pp->port))
2927 addrp->sin_port = htons(pp->port);
2929 rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose);
2932 fprintf(stderr, "fsprobe_Init failed (%d)\n", rc);
2939 tv.tv_sec = pp->host.wait;
2941 if (IOMGR_Select(0, 0, 0, 0, &tv))
2950 pingCell(char *cell)
2953 char rootcell[MAXCELLCHARS+1];
2954 char newcell[MAXCELLCHARS+1];
2955 struct ping_params pp;
2957 memset(&pp, 0, sizeof(struct ping_params));
2959 if (!cell || strlen(cell) == 0) {
2960 /* WIN32 NOTE: no way to get max chars */
2961 if (rc = pcm_GetRootCellName(rootcell))
2966 pp.port = 7000; // AFS FileServer
2967 pp.retry_delay = 10;
2973 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
2974 rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp);
2976 #endif /* USE_FSPROBE */
2978 // These two items are imported from afscreds.h
2979 // but it cannot be included without causing conflicts
2980 #define c100ns1SECOND (LONGLONG)10000000
2982 TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT)
2985 memset (pst, 0x00, sizeof(SYSTEMTIME));
2987 if ((pTime = localtime (&TimeT)) != NULL)
2989 pst->wYear = pTime->tm_year + 1900;
2990 pst->wMonth = pTime->tm_mon + 1;
2991 pst->wDayOfWeek = pTime->tm_wday;
2992 pst->wDay = pTime->tm_mday;
2993 pst->wHour = pTime->tm_hour;
2994 pst->wMinute = pTime->tm_min;
2995 pst->wSecond = pTime->tm_sec;
2996 pst->wMilliseconds = 0;
3001 ObtainTokensFromUserIfNeeded(HWND hWnd)
3003 char * rootcell = NULL;
3004 char cell[MAXCELLCHARS+1] = "";
3005 char password[PROBE_PASSWORD_LEN+1];
3007 afsconf_cell cellconfig;
3008 struct ktc_principal aserver;
3009 struct ktc_principal aclient;
3010 struct ktc_token atoken;
3012 krb5_timestamp now = 0;
3013 krb5_error_code code;
3014 int serverReachable = 0;
3018 const char * realm = 0;
3019 krb5_principal principal = 0;
3021 #endif /* USE_FSPROBE */
3026 memset(HostName, '\0', sizeof(HostName));
3027 gethostname(HostName, sizeof(HostName));
3028 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
3030 if (CurrentState != SERVICE_RUNNING) {
3031 SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L);
3035 if ( KFW_is_available() ) {
3036 code = pkrb5_init_context(&ctx);
3037 if ( code ) goto cleanup;
3040 rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1);
3041 if ( !rootcell ) goto cleanup;
3043 code = get_cellconfig(cell, (void*)&cellconfig, rootcell);
3044 if ( code ) goto cleanup;
3046 memset(&aserver, '\0', sizeof(aserver));
3047 strcpy(aserver.name, "afs");
3048 strcpy(aserver.cell, rootcell);
3050 rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3052 if ( KFW_is_available() ) {
3053 code = pkrb5_timeofday(ctx, &now);
3057 if (!rc && (now < atoken.endTime))
3065 SYSTEMTIME stExpires;
3067 TimeToSystemTime (&stExpires, atoken.endTime);
3068 GetLocalTime (&stNow);
3069 SystemTimeToFileTime (&stNow, &ftNow);
3070 SystemTimeToFileTime (&stExpires, &ftExpires);
3072 llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime);
3073 llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime);
3075 llNow /= c100ns1SECOND;
3076 llExpires /= c100ns1SECOND;
3078 if (!rc && (llNow < llExpires))
3084 serverReachable = cellPing(NULL);
3086 if ( KFW_is_available() ) {
3087 // If we can't use the FSProbe interface we can attempt to forge
3088 // a kinit and if we can back an invalid user error we know the
3089 // kdc is at least reachable
3090 realm = afs_realm_of_cell(&cellconfig); // do not free
3092 code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3093 realm, PROBE_USERNAME, NULL, NULL);
3094 if ( code ) goto cleanup;
3096 code = KFW_get_ccache(ctx, principal, &cc);
3097 if ( code ) goto cleanup;
3099 code = pkrb5_unparse_name(ctx, principal, &pname);
3100 if ( code ) goto cleanup;
3102 pwdata.data = password;
3103 pwdata.length = PROBE_PASSWORD_LEN;
3104 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3107 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i )
3110 password[PROBE_PASSWORD_LEN] = '\0';
3112 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3122 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3123 case KRB5KDC_ERR_CLIENT_REVOKED:
3124 case KRB5KDC_ERR_CLIENT_NOTYET:
3125 case KRB5KDC_ERR_PREAUTH_FAILED:
3126 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3127 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3128 serverReachable = TRUE;
3131 serverReachable = FALSE;
3135 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i )
3138 code = ObtainNewCredentials(rootcell, PROBE_USERNAME, password);
3139 serverReachable = 1;
3142 if ( !serverReachable )
3145 if ( KFW_is_available() ) {
3147 KFW_import_windows_lsa();
3148 #endif /* USE_MS2MIT */
3149 KFW_AFS_renew_expiring_credentials();
3150 KFW_AFS_renew_token_for_cell(rootcell);
3152 rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3153 if (!rc && (now < atoken.endTime))
3157 SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
3158 rootcell = NULL; // rootcell freed by message receiver
3162 GlobalFree(rootcell);
3166 pkrb5_free_unparsed_name(ctx,pname);
3168 pkrb5_free_principal(ctx,principal);
3170 pkrb5_cc_close(ctx,cc);
3171 #endif /* USE_FSPROBE */
3173 pkrb5_free_context(ctx);
3177 // IP Change Monitoring Functions
3178 #include <Iphlpapi.h>
3181 GetNumOfIpAddrs(void)
3183 PMIB_IPADDRTABLE pIpAddrTable = NULL;
3187 DWORD validAddrs = 0;
3190 code = GetIpAddrTable(NULL, &dwSize, 0);
3191 if (code == ERROR_INSUFFICIENT_BUFFER) {
3192 pIpAddrTable = malloc(dwSize);
3193 code = GetIpAddrTable(pIpAddrTable, &dwSize, 0);
3194 for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
3195 if (pIpAddrTable->table[index].dwAddr != 0)
3204 IpAddrChangeMonitor(void * hWnd)
3206 #ifdef USE_OVERLAPPED
3207 HANDLE Handle = INVALID_HANDLE_VALUE;
3209 #endif /* USE_OVERLAPPED */
3211 DWORD prevNumOfAddrs = GetNumOfIpAddrs();
3218 #ifdef USE_OVERLAPPED
3219 ZeroMemory(&Ovlap, sizeof(OVERLAPPED));
3221 Result = NotifyAddrChange(&Handle,&Ovlap);
3222 if (Result != ERROR_IO_PENDING)
3224 printf("NotifyAddrChange() failed with error %d \n", Result);
3228 if ((Result = WaitForSingleObject(Handle,INFINITE)) == WAIT_FAILED)
3230 printf("WaitForSingleObject() failed with error %d\n",
3235 if (GetOverlappedResult(Handle, &Ovlap,
3236 &DataTransfered, TRUE) == 0)
3238 printf("GetOverlapped result failed %d \n",
3244 Result = NotifyAddrChange(NULL,NULL);
3247 NumOfAddrs = GetNumOfIpAddrs();
3248 if ( NumOfAddrs != prevNumOfAddrs ) {
3249 // Give AFS Client Service a chance to notice and die
3250 // Or for network services to startup
3252 // this call should probably be mutex protected
3253 ObtainTokensFromUserIfNeeded(hWnd);
3255 prevNumOfAddrs = NumOfAddrs;
3258 #ifdef USE_OVERLAPPED
3259 if (Handle != INVALID_HANDLE_VALUE)
3260 CloseHandle(Handle);
3266 IpAddrChangeMonitorInit(HWND hWnd)
3268 DWORD status = ERROR_SUCCESS;
3272 thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor,
3273 hWnd, 0, &threadID);
3275 if (thread == NULL) {
3276 status = GetLastError();
3278 CloseHandle(thread);