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"
65 #include <rxkad_prototypes.h> /* for life_to_time */
68 * TIMING _____________________________________________________________________
72 #define cminREMIND_TEST 1 // test every minute for expired creds
73 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
74 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
75 #define cminMINLIFE 30 // minimum life of Kerberos creds
77 #define c100ns1SECOND (LONGLONG)10000000
78 #define cmsec1SECOND 1000
79 #define cmsec1MINUTE 60000
80 #define csec1MINUTE 60
82 /* Function Pointer Declarations for Delayed Loading */
84 DECL_FUNC_PTR(cc_initialize);
85 DECL_FUNC_PTR(cc_shutdown);
86 DECL_FUNC_PTR(cc_get_NC_info);
87 DECL_FUNC_PTR(cc_free_NC_info);
90 DECL_FUNC_PTR(Leash_get_default_lifetime);
91 DECL_FUNC_PTR(Leash_get_default_forwardable);
92 DECL_FUNC_PTR(Leash_get_default_renew_till);
93 DECL_FUNC_PTR(Leash_get_default_noaddresses);
94 DECL_FUNC_PTR(Leash_get_default_proxiable);
95 DECL_FUNC_PTR(Leash_get_default_publicip);
96 DECL_FUNC_PTR(Leash_get_default_use_krb4);
97 DECL_FUNC_PTR(Leash_get_default_life_min);
98 DECL_FUNC_PTR(Leash_get_default_life_max);
99 DECL_FUNC_PTR(Leash_get_default_renew_min);
100 DECL_FUNC_PTR(Leash_get_default_renew_max);
101 DECL_FUNC_PTR(Leash_get_default_renewable);
104 DECL_FUNC_PTR(krb5_change_password);
105 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
106 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
107 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
108 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
109 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
110 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
111 DECL_FUNC_PTR(krb5_get_init_creds_password);
112 DECL_FUNC_PTR(krb5_build_principal_ext);
113 DECL_FUNC_PTR(krb5_cc_get_name);
114 DECL_FUNC_PTR(krb5_cc_resolve);
115 DECL_FUNC_PTR(krb5_cc_default);
116 DECL_FUNC_PTR(krb5_cc_default_name);
117 DECL_FUNC_PTR(krb5_cc_set_default_name);
118 DECL_FUNC_PTR(krb5_cc_initialize);
119 DECL_FUNC_PTR(krb5_cc_destroy);
120 DECL_FUNC_PTR(krb5_cc_close);
121 DECL_FUNC_PTR(krb5_cc_store_cred);
122 DECL_FUNC_PTR(krb5_cc_copy_creds);
123 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
124 DECL_FUNC_PTR(krb5_cc_get_principal);
125 DECL_FUNC_PTR(krb5_cc_start_seq_get);
126 DECL_FUNC_PTR(krb5_cc_next_cred);
127 DECL_FUNC_PTR(krb5_cc_end_seq_get);
128 DECL_FUNC_PTR(krb5_cc_remove_cred);
129 DECL_FUNC_PTR(krb5_cc_set_flags);
130 DECL_FUNC_PTR(krb5_cc_get_type);
131 DECL_FUNC_PTR(krb5_free_context);
132 DECL_FUNC_PTR(krb5_free_cred_contents);
133 DECL_FUNC_PTR(krb5_free_principal);
134 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
135 DECL_FUNC_PTR(krb5_init_context);
136 DECL_FUNC_PTR(krb5_parse_name);
137 DECL_FUNC_PTR(krb5_timeofday);
138 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
139 DECL_FUNC_PTR(krb5_unparse_name);
140 DECL_FUNC_PTR(krb5_get_credentials);
141 DECL_FUNC_PTR(krb5_mk_req);
142 DECL_FUNC_PTR(krb5_sname_to_principal);
143 DECL_FUNC_PTR(krb5_get_credentials_renew);
144 DECL_FUNC_PTR(krb5_free_data);
145 DECL_FUNC_PTR(krb5_free_data_contents);
146 DECL_FUNC_PTR(krb5_free_unparsed_name);
147 DECL_FUNC_PTR(krb5_os_localaddr);
148 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
149 DECL_FUNC_PTR(krb5_copy_data);
150 DECL_FUNC_PTR(krb5_free_creds);
151 DECL_FUNC_PTR(krb5_build_principal);
152 DECL_FUNC_PTR(krb5_get_renewed_creds);
153 DECL_FUNC_PTR(krb5_get_default_config_files);
154 DECL_FUNC_PTR(krb5_free_config_files);
155 DECL_FUNC_PTR(krb5_get_default_realm);
156 DECL_FUNC_PTR(krb5_free_ticket);
157 DECL_FUNC_PTR(krb5_decode_ticket);
158 DECL_FUNC_PTR(krb5_get_host_realm);
159 DECL_FUNC_PTR(krb5_free_host_realm);
160 DECL_FUNC_PTR(krb5_free_addresses);
161 DECL_FUNC_PTR(krb5_c_random_make_octets);
164 DECL_FUNC_PTR(krb524_init_ets);
165 DECL_FUNC_PTR(krb524_convert_creds_kdc);
168 DECL_FUNC_PTR(krb_get_cred);
169 DECL_FUNC_PTR(tkt_string);
170 DECL_FUNC_PTR(krb_get_tf_realm);
171 DECL_FUNC_PTR(krb_mk_req);
174 DECL_FUNC_PTR(com_err);
175 DECL_FUNC_PTR(error_message);
178 DECL_FUNC_PTR(profile_init);
179 DECL_FUNC_PTR(profile_release);
180 DECL_FUNC_PTR(profile_get_subsection_names);
181 DECL_FUNC_PTR(profile_free_list);
182 DECL_FUNC_PTR(profile_get_string);
183 DECL_FUNC_PTR(profile_release_string);
186 DECL_FUNC_PTR(OpenSCManagerA);
187 DECL_FUNC_PTR(OpenServiceA);
188 DECL_FUNC_PTR(QueryServiceStatus);
189 DECL_FUNC_PTR(CloseServiceHandle);
191 DECL_FUNC_PTR(LsaNtStatusToWinError);
192 #endif /* USE_MS2MIT */
196 DECL_FUNC_PTR(LsaConnectUntrusted);
197 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
198 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
199 DECL_FUNC_PTR(LsaFreeReturnBuffer);
200 DECL_FUNC_PTR(LsaGetLogonSessionData);
201 #endif /* USE_MS2MIT */
203 // AFS36 Token Functions
204 DECL_FUNC_PTR(ktc_ListTokens);
205 DECL_FUNC_PTR(ktc_GetToken);
206 DECL_FUNC_PTR(ktc_SetToken);
207 DECL_FUNC_PTR(ktc_ForgetAllTokens);
209 // AFS36 Config Functions
210 DECL_FUNC_PTR(cm_SearchCellFile);
211 DECL_FUNC_PTR(cm_GetRootCellName);
214 FUNC_INFO ccapi_fi[] = {
215 MAKE_FUNC_INFO(cc_initialize),
216 MAKE_FUNC_INFO(cc_shutdown),
217 MAKE_FUNC_INFO(cc_get_NC_info),
218 MAKE_FUNC_INFO(cc_free_NC_info),
222 FUNC_INFO leash_fi[] = {
223 MAKE_FUNC_INFO(Leash_get_default_lifetime),
224 MAKE_FUNC_INFO(Leash_get_default_renew_till),
225 MAKE_FUNC_INFO(Leash_get_default_forwardable),
226 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
227 MAKE_FUNC_INFO(Leash_get_default_proxiable),
228 MAKE_FUNC_INFO(Leash_get_default_publicip),
229 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
230 MAKE_FUNC_INFO(Leash_get_default_life_min),
231 MAKE_FUNC_INFO(Leash_get_default_life_max),
232 MAKE_FUNC_INFO(Leash_get_default_renew_min),
233 MAKE_FUNC_INFO(Leash_get_default_renew_max),
234 MAKE_FUNC_INFO(Leash_get_default_renewable),
238 FUNC_INFO k5_fi[] = {
239 MAKE_FUNC_INFO(krb5_change_password),
240 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
241 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
242 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
243 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
244 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
245 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
246 MAKE_FUNC_INFO(krb5_get_init_creds_password),
247 MAKE_FUNC_INFO(krb5_build_principal_ext),
248 MAKE_FUNC_INFO(krb5_cc_get_name),
249 MAKE_FUNC_INFO(krb5_cc_resolve),
250 MAKE_FUNC_INFO(krb5_cc_default),
251 MAKE_FUNC_INFO(krb5_cc_default_name),
252 MAKE_FUNC_INFO(krb5_cc_set_default_name),
253 MAKE_FUNC_INFO(krb5_cc_initialize),
254 MAKE_FUNC_INFO(krb5_cc_destroy),
255 MAKE_FUNC_INFO(krb5_cc_close),
256 MAKE_FUNC_INFO(krb5_cc_copy_creds),
257 MAKE_FUNC_INFO(krb5_cc_store_cred),
258 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
259 MAKE_FUNC_INFO(krb5_cc_get_principal),
260 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
261 MAKE_FUNC_INFO(krb5_cc_next_cred),
262 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
263 MAKE_FUNC_INFO(krb5_cc_remove_cred),
264 MAKE_FUNC_INFO(krb5_cc_set_flags),
265 MAKE_FUNC_INFO(krb5_cc_get_type),
266 MAKE_FUNC_INFO(krb5_free_context),
267 MAKE_FUNC_INFO(krb5_free_cred_contents),
268 MAKE_FUNC_INFO(krb5_free_principal),
269 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
270 MAKE_FUNC_INFO(krb5_init_context),
271 MAKE_FUNC_INFO(krb5_parse_name),
272 MAKE_FUNC_INFO(krb5_timeofday),
273 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
274 MAKE_FUNC_INFO(krb5_unparse_name),
275 MAKE_FUNC_INFO(krb5_get_credentials),
276 MAKE_FUNC_INFO(krb5_mk_req),
277 MAKE_FUNC_INFO(krb5_sname_to_principal),
278 MAKE_FUNC_INFO(krb5_get_credentials_renew),
279 MAKE_FUNC_INFO(krb5_free_data),
280 MAKE_FUNC_INFO(krb5_free_data_contents),
281 MAKE_FUNC_INFO(krb5_free_unparsed_name),
282 MAKE_FUNC_INFO(krb5_os_localaddr),
283 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
284 MAKE_FUNC_INFO(krb5_copy_data),
285 MAKE_FUNC_INFO(krb5_free_creds),
286 MAKE_FUNC_INFO(krb5_build_principal),
287 MAKE_FUNC_INFO(krb5_get_renewed_creds),
288 MAKE_FUNC_INFO(krb5_free_addresses),
289 MAKE_FUNC_INFO(krb5_get_default_config_files),
290 MAKE_FUNC_INFO(krb5_free_config_files),
291 MAKE_FUNC_INFO(krb5_get_default_realm),
292 MAKE_FUNC_INFO(krb5_free_ticket),
293 MAKE_FUNC_INFO(krb5_decode_ticket),
294 MAKE_FUNC_INFO(krb5_get_host_realm),
295 MAKE_FUNC_INFO(krb5_free_host_realm),
296 MAKE_FUNC_INFO(krb5_free_addresses),
297 MAKE_FUNC_INFO(krb5_c_random_make_octets),
301 FUNC_INFO k4_fi[] = {
302 MAKE_FUNC_INFO(krb_get_cred),
303 MAKE_FUNC_INFO(krb_get_tf_realm),
304 MAKE_FUNC_INFO(krb_mk_req),
305 MAKE_FUNC_INFO(tkt_string),
309 FUNC_INFO k524_fi[] = {
310 MAKE_FUNC_INFO(krb524_init_ets),
311 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
315 FUNC_INFO profile_fi[] = {
316 MAKE_FUNC_INFO(profile_init),
317 MAKE_FUNC_INFO(profile_release),
318 MAKE_FUNC_INFO(profile_get_subsection_names),
319 MAKE_FUNC_INFO(profile_free_list),
320 MAKE_FUNC_INFO(profile_get_string),
321 MAKE_FUNC_INFO(profile_release_string),
325 FUNC_INFO ce_fi[] = {
326 MAKE_FUNC_INFO(com_err),
327 MAKE_FUNC_INFO(error_message),
331 FUNC_INFO service_fi[] = {
332 MAKE_FUNC_INFO(OpenSCManagerA),
333 MAKE_FUNC_INFO(OpenServiceA),
334 MAKE_FUNC_INFO(QueryServiceStatus),
335 MAKE_FUNC_INFO(CloseServiceHandle),
337 MAKE_FUNC_INFO(LsaNtStatusToWinError),
338 #endif /* USE_MS2MIT */
343 FUNC_INFO lsa_fi[] = {
344 MAKE_FUNC_INFO(LsaConnectUntrusted),
345 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
346 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
347 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
348 MAKE_FUNC_INFO(LsaGetLogonSessionData),
351 #endif /* USE_MS2MIT */
353 FUNC_INFO afst_fi[] = {
354 MAKE_FUNC_INFO(ktc_ListTokens),
355 MAKE_FUNC_INFO(ktc_GetToken),
356 MAKE_FUNC_INFO(ktc_SetToken),
357 MAKE_FUNC_INFO(ktc_ForgetAllTokens),
361 FUNC_INFO afsc_fi[] = {
362 MAKE_FUNC_INFO(cm_SearchCellFile),
363 MAKE_FUNC_INFO(cm_GetRootCellName),
367 /* Static Prototypes */
368 static char *afs_realm_of_cell(afsconf_cell *);
369 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
370 static int get_cellconfig(char *, afsconf_cell *, char *);
371 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
372 void *data, const char *name, const char *banner, int num_prompts,
373 krb5_prompt prompts[]);
376 /* Static Declarations */
377 static int inited = 0;
378 static int mid_cnt = 0;
379 static struct textField * mid_tb = NULL;
380 static HINSTANCE hKrb5 = 0;
381 static HINSTANCE hKrb4 = 0;
382 static HINSTANCE hKrb524 = 0;
384 static HINSTANCE hSecur32 = 0;
385 #endif /* USE_MS2MIT */
386 static HINSTANCE hAdvApi32 = 0;
387 static HINSTANCE hAfsTokens = 0;
388 static HINSTANCE hAfsConf = 0;
389 static HINSTANCE hComErr = 0;
390 static HINSTANCE hService = 0;
391 static HINSTANCE hProfile = 0;
392 static HINSTANCE hLeash = 0;
393 static HINSTANCE hCCAPI = 0;
394 static struct principal_ccache_data * princ_cc_data = NULL;
395 static struct cell_principal_map * cell_princ_map = NULL;
400 static int inited = 0;
403 char mutexName[MAX_PATH];
404 HANDLE hMutex = NULL;
406 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
408 hMutex = CreateMutex( NULL, TRUE, mutexName );
409 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
410 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
416 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
417 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
418 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
419 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
421 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
422 #endif /* USE_MS2MIT */
423 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
424 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
425 LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0);
426 LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0);
427 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
428 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
430 if ( KFW_is_available() ) {
431 char rootcell[MAXCELLCHARS+1];
433 KFW_import_windows_lsa();
434 #endif /* USE_MS2MIT */
435 KFW_import_ccache_data();
436 KFW_AFS_renew_expiring_tokens();
438 /* WIN32 NOTE: no way to get max chars */
439 if (!pcm_GetRootCellName(rootcell))
440 KFW_AFS_renew_token_for_cell(rootcell);
443 ReleaseMutex(hMutex);
456 FreeLibrary(hProfile);
458 FreeLibrary(hAfsTokens);
460 FreeLibrary(hAfsConf);
462 FreeLibrary(hComErr);
464 FreeLibrary(hService);
467 FreeLibrary(hSecur32);
468 #endif /* USE_MS2MIT */
470 FreeLibrary(hKrb524);
477 static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
480 KFW_is_available(void)
486 code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
487 0, KEY_QUERY_VALUE, &parmKey);
488 if (code != ERROR_SUCCESS)
489 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
490 0, KEY_QUERY_VALUE, &parmKey);
491 if (code == ERROR_SUCCESS) {
492 len = sizeof(enableKFW);
493 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
494 (BYTE *) &enableKFW, &len);
495 if (code != ERROR_SUCCESS) {
498 RegCloseKey (parmKey);
505 if ( hKrb5 && hComErr && hService &&
508 #endif /* USE_MS2MIT */
510 hProfile && hAfsTokens && hAfsConf && hLeash && hCCAPI )
516 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
517 int FreeContextFlag, krb5_context * ctx,
522 int krb5Error = ((int)(rc & 255));
534 errText = perror_message(rc);
535 _snprintf(message, sizeof(message),
536 "%s\n(Kerberos error %ld)\n\n%s failed",
541 if ( IsDebuggerPresent() )
542 OutputDebugString(message);
544 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
547 if (FreeContextFlag == 1)
549 if (ctx && *ctx != NULL)
551 if (cache && *cache != NULL) {
552 pkrb5_cc_close(*ctx, *cache);
556 pkrb5_free_context(*ctx);
565 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
567 struct principal_ccache_data * next = princ_cc_data;
568 krb5_principal principal = 0;
570 const char * ccname = NULL;
571 krb5_error_code code = 0;
572 krb5_error_code cc_code = 0;
578 if (ctx == 0 || cc == 0)
581 code = pkrb5_cc_get_principal(ctx, cc, &principal);
584 code = pkrb5_unparse_name(ctx, principal, &pname);
585 if ( code ) goto cleanup;
587 ccname = pkrb5_cc_get_name(ctx, cc);
588 if (!ccname) goto cleanup;
590 // Search the existing list to see if we have a match
592 for ( ; next ; next = next->next ) {
593 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
598 // If not, match add a new node to the beginning of the list and assign init it
600 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
601 next->next = princ_cc_data;
602 princ_cc_data = next;
603 next->principal = _strdup(pname);
604 next->ccache_name = _strdup(ccname);
605 next->from_lsa = lsa;
607 next->expiration_time = 0;
611 flags = 0; // turn off OPENCLOSE mode
612 code = pkrb5_cc_set_flags(ctx, cc, flags);
613 if ( code ) goto cleanup;
615 code = pkrb5_timeofday(ctx, &now);
617 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
619 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
620 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
622 // we found the ticket we are looking for
623 // check validity of timestamp
624 // We add a 5 minutes fudge factor to compensate for potential
625 // clock skew errors between the KDC and client OS
627 valid = ((creds.times.starttime > 0) &&
628 now >= (creds.times.starttime - 300) &&
629 now < (creds.times.endtime + 300) &&
630 !(creds.ticket_flags & TKT_FLG_INVALID));
632 if ( next->from_lsa) {
634 next->expiration_time = creds.times.endtime;
636 } else if ( valid ) {
638 next->expiration_time = creds.times.endtime;
639 next->renew = (creds.times.renew_till > creds.times.endtime) &&
640 (creds.ticket_flags & TKT_FLG_RENEWABLE);
643 next->expiration_time = 0;
647 pkrb5_free_cred_contents(ctx, &creds);
648 cc_code = KRB5_CC_END;
651 pkrb5_free_cred_contents(ctx, &creds);
654 if (cc_code == KRB5_CC_END) {
655 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
656 if (code) goto cleanup;
660 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
661 code = pkrb5_cc_set_flags(ctx, cc, flags);
664 pkrb5_free_unparsed_name(ctx,pname);
666 pkrb5_free_principal(ctx,principal);
670 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
672 struct principal_ccache_data * next = princ_cc_data;
673 char * response = NULL;
675 if ( !principal || !ccache )
679 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
681 // we always want to prefer the MS Kerberos LSA cache or
682 // the cache afscreds created specifically for the principal
683 // if the current entry is either one, drop the previous find
684 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
687 response = _strdup(next->ccache_name);
688 // MS Kerberos LSA is our best option so use it and quit
689 if ( next->from_lsa )
703 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
705 struct principal_ccache_data ** next = &princ_cc_data;
707 if ( !pname && !ccname )
711 if ( !strcmp((*next)->principal,pname) ||
712 !strcmp((*next)->ccache_name,ccname) ) {
714 free((*next)->principal);
715 free((*next)->ccache_name);
717 (*next) = (*next)->next;
724 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
726 struct cell_principal_map * next = cell_princ_map;
728 // Search the existing list to see if we have a match
730 for ( ; next ; next = next->next ) {
731 if ( !strcmp(next->cell, cell) ) {
732 if ( !strcmp(next->principal,pname) ) {
733 next->active = active;
736 // OpenAFS currently has a restriction of one active token per cell
737 // Therefore, whenever we update the table with a new active cell we
738 // must mark all of the other principal to cell entries as inactive.
746 // If not, match add a new node to the beginning of the list and assign init it
748 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
749 next->next = cell_princ_map;
750 cell_princ_map = next;
751 next->principal = _strdup(pname);
752 next->cell = _strdup(cell);
753 next->active = active;
758 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
760 struct cell_principal_map ** next = &cell_princ_map;
762 if ( !pname && !cell )
766 if ( !strcmp((*next)->principal,pname) ||
767 !strcmp((*next)->cell,cell) ) {
769 free((*next)->principal);
772 (*next) = (*next)->next;
778 // Returns (if possible) a principal which has been known in
779 // the past to have been used to obtain tokens for the specified
781 // TODO: Attempt to return one which has not yet expired by checking
782 // the principal/ccache data
784 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
786 struct cell_principal_map * next_map = cell_princ_map;
787 const char * princ = NULL;
794 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
797 next_map = next_map->next;
803 *principals = (char **) malloc(sizeof(char *) * count);
804 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
806 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
807 (*principals)[i++] = _strdup(next_map->principal);
814 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
817 struct cell_principal_map * next_map = cell_princ_map;
818 const char * princ = NULL;
824 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
827 next_map = next_map->next;
833 *cells = (char **) malloc(sizeof(char *) * count);
834 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
836 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
837 (*cells)[i++] = _strdup(next_map->cell);
843 /* Given a principal return an existing ccache or create one and return */
845 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
850 krb5_error_code code;
852 if (!pkrb5_init_context)
858 code = pkrb5_init_context(&ctx);
859 if (code) goto cleanup;
863 code = pkrb5_unparse_name(ctx, principal, &pname);
864 if (code) goto cleanup;
866 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
867 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
868 ccname = (char *)malloc(strlen(pname) + 5);
869 sprintf(ccname,"API:%s",pname);
871 code = pkrb5_cc_resolve(ctx, ccname, cc);
873 code = pkrb5_cc_default(ctx, cc);
874 if (code) goto cleanup;
881 pkrb5_free_unparsed_name(ctx,pname);
882 if (ctx && (ctx != alt_ctx))
883 pkrb5_free_context(ctx);
888 // Import Microsoft Credentials into a new MIT ccache
890 KFW_import_windows_lsa(void)
892 krb5_context ctx = 0;
894 krb5_principal princ = 0;
897 krb5_error_code code;
901 if (!pkrb5_init_context)
905 if ( !MSLSA_IsKerberosLogon() )
909 code = pkrb5_init_context(&ctx);
910 if (code) goto cleanup;
912 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
913 if (code) goto cleanup;
915 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
917 code = pkrb5_cc_get_principal(ctx, cc, &princ);
918 if ( code ) goto cleanup;
920 code = pkrb5_unparse_name(ctx,princ,&pname);
921 if ( code ) goto cleanup;
923 realm = krb5_princ_realm(ctx, princ);
924 for ( i=0; i<realm->length; i++ ) {
925 cell[i] = tolower(realm->data[i]);
929 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime());
930 if ( IsDebuggerPresent() ) {
932 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
933 OutputDebugString(message);
935 if ( code ) goto cleanup;
937 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
941 pkrb5_free_unparsed_name(ctx,pname);
943 pkrb5_free_principal(ctx,princ);
945 pkrb5_cc_close(ctx,cc);
947 pkrb5_free_context(ctx);
949 #endif /* USE_MS2MIT */
951 // If there are existing MIT credentials, copy them to a new
952 // ccache named after the principal
954 // Enumerate all existing MIT ccaches and construct entries
955 // in the principal_ccache table
957 // Enumerate all existing AFS Tokens and construct entries
958 // in the cell_principal table
960 KFW_import_ccache_data(void)
962 krb5_context ctx = 0;
964 krb5_principal principal = 0;
966 krb5_error_code code;
967 krb5_error_code cc_code;
970 struct _infoNC ** pNCi = NULL;
973 if ( !pcc_initialize )
976 if ( IsDebuggerPresent() )
977 OutputDebugString("KFW_import_ccache_data()\n");
979 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
980 if (code) goto cleanup;
982 code = pcc_get_NC_info(cc_ctx, &pNCi);
983 if (code) goto cleanup;
985 code = pkrb5_init_context(&ctx);
986 if (code) goto cleanup;
988 for ( i=0; pNCi[i]; i++ ) {
989 if ( pNCi[i]->vers != CC_CRED_V5 )
991 if ( IsDebuggerPresent() ) {
992 OutputDebugString("Principal: ");
993 OutputDebugString(pNCi[i]->principal);
994 OutputDebugString(" in ccache ");
995 OutputDebugString(pNCi[i]->name);
996 OutputDebugString("\n");
998 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
999 && strcmp(pNCi[i]->name,LSA_CCNAME)
1002 krb5_ccache oldcc = 0;
1003 for ( j=0; pNCi[j]; j++ ) {
1004 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1012 if ( IsDebuggerPresent() )
1013 OutputDebugString("copying ccache data to new ccache\n");
1015 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1016 if (code) goto loop_cleanup;
1017 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1018 if (code) goto loop_cleanup;
1019 code = pkrb5_cc_initialize(ctx, cc, principal);
1020 if (code) goto loop_cleanup;
1021 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1022 if (code) goto loop_cleanup;
1023 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1025 code = pkrb5_cc_close(ctx,cc);
1027 code = pkrb5_cc_close(ctx,oldcc);
1029 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1032 code = pkrb5_cc_close(ctx,oldcc);
1034 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1035 if (code) goto loop_cleanup;
1038 flags = 0; // turn off OPENCLOSE mode
1039 code = pkrb5_cc_set_flags(ctx, cc, flags);
1040 if ( code ) goto cleanup;
1042 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1044 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1046 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1047 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1048 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1049 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1050 if ( sname && cell && !strcmp("afs",sname->data) ) {
1051 struct ktc_principal aserver;
1052 struct ktc_principal aclient;
1053 struct ktc_token atoken;
1056 if ( IsDebuggerPresent() ) {
1057 OutputDebugString("Found AFS ticket: ");
1058 OutputDebugString(sname->data);
1060 OutputDebugString("/");
1061 OutputDebugString(cell->data);
1063 OutputDebugString("@");
1064 OutputDebugString(realm->data);
1065 OutputDebugString("\n");
1068 memset(&aserver, '\0', sizeof(aserver));
1069 strcpy(aserver.name, sname->data);
1070 strcpy(aserver.cell, cell->data);
1072 code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1074 // Found a token in AFS Client Server which matches
1075 char pname[128], *p, *q;
1076 for ( p=pname, q=aclient.name; *q; p++, q++)
1078 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1082 if ( IsDebuggerPresent() ) {
1083 OutputDebugString("Found AFS token: ");
1084 OutputDebugString(pname);
1085 OutputDebugString("\n");
1088 if ( strcmp(pname,pNCi[i]->principal) )
1090 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1092 // Attempt to import it
1093 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1095 if ( IsDebuggerPresent() ) {
1096 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1099 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime());
1100 if ( IsDebuggerPresent() ) {
1102 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1103 OutputDebugString(message);
1106 } else if ( IsDebuggerPresent() ) {
1107 OutputDebugString("Found ticket: ");
1108 OutputDebugString(sname->data);
1109 if ( cell && cell->data ) {
1110 OutputDebugString("/");
1111 OutputDebugString(cell->data);
1113 OutputDebugString("@");
1114 OutputDebugString(realm->data);
1115 OutputDebugString("\n");
1117 pkrb5_free_cred_contents(ctx, &creds);
1120 if (cc_code == KRB5_CC_END) {
1121 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1122 if (cc_code) goto loop_cleanup;
1126 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1127 code = pkrb5_cc_set_flags(ctx, cc, flags);
1129 pkrb5_cc_close(ctx,cc);
1136 pkrb5_free_principal(ctx,principal);
1138 pkrb5_free_context(ctx);
1140 pcc_free_NC_info(cc_ctx, &pNCi);
1142 pcc_shutdown(&cc_ctx);
1147 KFW_AFS_get_cred(char * username,
1154 krb5_context ctx = 0;
1157 char ** realmlist = 0;
1158 krb5_principal principal = 0;
1160 krb5_error_code code;
1161 char local_cell[MAXCELLCHARS+1];
1162 char **cells = NULL;
1164 afsconf_cell cellconfig;
1166 if (!pkrb5_init_context)
1169 if ( IsDebuggerPresent() ) {
1170 OutputDebugString("KFW_AFS_get_cred for token ");
1171 OutputDebugString(username);
1173 OutputDebugString("/");
1174 OutputDebugString(instance);
1176 OutputDebugString("@");
1177 OutputDebugString(cell);
1178 OutputDebugString("\n");
1181 code = pkrb5_init_context(&ctx);
1182 if ( code ) goto cleanup;
1184 code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1185 if ( code ) goto cleanup;
1187 realm = strchr(username,'@');
1193 realm = afs_realm_of_cell(&cellconfig); // do not free
1195 if ( IsDebuggerPresent() ) {
1196 OutputDebugString("Realm: ");
1197 OutputDebugString(realm);
1198 OutputDebugString("\n");
1201 code = pkrb5_build_principal(ctx, &principal, strlen(realm),
1203 (instance && instance[0]) ? instance : NULL,
1206 code = KFW_get_ccache(ctx, principal, &cc);
1207 if ( code ) goto cleanup;
1209 code = pkrb5_unparse_name(ctx, principal, &pname);
1210 if ( code ) goto cleanup;
1212 if ( lifetime == 0 )
1213 lifetime = pLeash_get_default_lifetime();
1215 code = KFW_kinit(ctx, cc, HWND_DESKTOP,
1219 pLeash_get_default_forwardable(),
1220 pLeash_get_default_proxiable(),
1221 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1222 pLeash_get_default_noaddresses(),
1223 pLeash_get_default_publicip());
1224 if ( IsDebuggerPresent() ) {
1226 sprintf(message,"KFW_kinit() returns: %d\n",code);
1227 OutputDebugString(message);
1229 if ( code ) goto cleanup;
1231 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1233 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime);
1234 if ( IsDebuggerPresent() ) {
1236 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1237 OutputDebugString(message);
1239 if ( code ) goto cleanup;
1241 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1243 // Attempt to obtain new tokens for other cells supported by the same
1245 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1246 if ( cell_count > 1 ) {
1247 while ( cell_count-- ) {
1248 if ( strcmp(cells[cell_count],cell) ) {
1249 if ( IsDebuggerPresent() ) {
1251 sprintf(message,"found another cell for the same principal: %s\n",cell);
1252 OutputDebugString(message);
1254 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1255 if ( code ) continue;
1257 realm = afs_realm_of_cell(&cellconfig); // do not free
1258 if ( IsDebuggerPresent() ) {
1259 OutputDebugString("Realm: ");
1260 OutputDebugString(realm);
1261 OutputDebugString("\n");
1264 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime);
1265 if ( IsDebuggerPresent() ) {
1267 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1268 OutputDebugString(message);
1271 free(cells[cell_count]);
1274 } else if ( cell_count == 1 ) {
1281 pkrb5_free_unparsed_name(ctx,pname);
1283 pkrb5_cc_close(ctx, cc);
1285 if ( code && reasonP ) {
1286 *reasonP = (char *)perror_message(code);
1292 KFW_AFS_destroy_tickets_for_cell(char * cell)
1294 krb5_context ctx = 0;
1295 krb5_error_code code;
1297 char ** principals = NULL;
1299 if (!pkrb5_init_context)
1302 if ( IsDebuggerPresent() ) {
1303 OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
1304 OutputDebugString(cell);
1305 OutputDebugString("\n");
1308 code = pkrb5_init_context(&ctx);
1311 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1313 krb5_principal princ = 0;
1317 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1318 if ( cell_count > 1 ) {
1319 // TODO - What we really should do here is verify whether or not any of the
1320 // other cells which use this principal to obtain its credentials actually
1321 // have valid tokens or not. If they are currently using these credentials
1322 // we will skip them. For the time being we assume that if there is an active
1323 // map in the table that they are actively being used.
1327 code = pkrb5_parse_name(ctx, principals[count], &princ);
1328 if (code) goto loop_cleanup;
1330 code = KFW_get_ccache(ctx, princ, &cc);
1331 if (code) goto loop_cleanup;
1333 code = pkrb5_cc_destroy(ctx, cc);
1338 pkrb5_cc_close(ctx, cc);
1342 pkrb5_free_principal(ctx, princ);
1346 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1347 free(principals[count]);
1351 pkrb5_free_context(ctx);
1356 KFW_AFS_renew_expiring_tokens(void)
1358 krb5_error_code code = 0;
1359 krb5_context ctx = 0;
1362 struct principal_ccache_data * pcc_next = princ_cc_data;
1365 const char * realm = NULL;
1366 char local_cell[MAXCELLCHARS+1]="";
1367 afsconf_cell cellconfig;
1369 if (!pkrb5_init_context)
1372 if ( pcc_next == NULL ) // nothing to do
1375 if ( IsDebuggerPresent() ) {
1376 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1379 code = pkrb5_init_context(&ctx);
1380 if (code) goto cleanup;
1382 code = pkrb5_timeofday(ctx, &now);
1383 if (code) goto cleanup;
1385 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1386 if ( pcc_next->expired )
1389 if ( now >= (pcc_next->expiration_time) ) {
1390 if ( !pcc_next->from_lsa ) {
1391 pcc_next->expired = 1;
1396 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1397 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1400 code = KFW_renew(ctx,cc);
1402 if ( code && pcc_next->from_lsa)
1404 #endif /* USE_MS2MIT */
1407 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1408 if (code) goto loop_cleanup;
1410 // Attempt to obtain new tokens for other cells supported by the same
1412 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1413 if ( cell_count > 0 ) {
1414 while ( cell_count-- ) {
1415 if ( IsDebuggerPresent() ) {
1416 OutputDebugString("Cell: ");
1417 OutputDebugString(cells[cell_count]);
1418 OutputDebugString("\n");
1420 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1421 if ( code ) continue;
1422 realm = afs_realm_of_cell(&cellconfig); // do not free
1423 if ( IsDebuggerPresent() ) {
1424 OutputDebugString("Realm: ");
1425 OutputDebugString(realm);
1426 OutputDebugString("\n");
1428 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime());
1429 if ( IsDebuggerPresent() ) {
1431 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1432 OutputDebugString(message);
1434 free(cells[cell_count]);
1442 pkrb5_cc_close(ctx,cc);
1449 pkrb5_cc_close(ctx,cc);
1451 pkrb5_free_context(ctx);
1458 KFW_AFS_renew_token_for_cell(char * cell)
1460 krb5_error_code code = 0;
1461 krb5_context ctx = 0;
1463 char ** principals = NULL;
1465 if (!pkrb5_init_context)
1468 if ( IsDebuggerPresent() ) {
1469 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1470 OutputDebugString(cell);
1471 OutputDebugString("\n");
1474 code = pkrb5_init_context(&ctx);
1475 if (code) goto cleanup;
1477 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1479 krb5_principal princ = 0;
1480 krb5_principal service = 0;
1482 krb5_creds mcreds, creds;
1483 #endif /* COMMENT */
1485 const char * realm = NULL;
1486 afsconf_cell cellconfig;
1487 char local_cell[MAXCELLCHARS+1];
1490 code = pkrb5_parse_name(ctx, principals[count], &princ);
1491 if (code) goto loop_cleanup;
1493 code = KFW_get_ccache(ctx, princ, &cc);
1494 if (code) goto loop_cleanup;
1496 code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1497 if ( code ) goto loop_cleanup;
1499 realm = afs_realm_of_cell(&cellconfig); // do not free
1500 if ( IsDebuggerPresent() ) {
1501 OutputDebugString("Realm: ");
1502 OutputDebugString(realm);
1503 OutputDebugString("\n");
1507 /* krb5_cc_remove_cred() is not implemented
1510 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1511 realm, "afs", cell, NULL);
1513 memset(&mcreds, 0, sizeof(krb5_creds));
1514 mcreds.client = princ;
1515 mcreds.server = service;
1517 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1519 if ( IsDebuggerPresent() ) {
1520 char * cname, *sname;
1521 pkrb5_unparse_name(ctx, creds.client, &cname);
1522 pkrb5_unparse_name(ctx, creds.server, &sname);
1523 OutputDebugString("Removing credential for client \"");
1524 OutputDebugString(cname);
1525 OutputDebugString("\" and service \"");
1526 OutputDebugString(sname);
1527 OutputDebugString("\"\n");
1528 pkrb5_free_unparsed_name(ctx,cname);
1529 pkrb5_free_unparsed_name(ctx,sname);
1532 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1533 pkrb5_free_principal(ctx, creds.client);
1534 pkrb5_free_principal(ctx, creds.server);
1537 #endif /* COMMENT */
1539 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime());
1540 if ( IsDebuggerPresent() ) {
1542 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1543 OutputDebugString(message);
1548 pkrb5_cc_close(ctx, cc);
1552 pkrb5_free_principal(ctx, princ);
1556 pkrb5_free_principal(ctx, service);
1560 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1561 free(principals[count]);
1565 code = -1; // we did not renew the tokens
1568 pkrb5_free_context(ctx);
1569 return (code ? FALSE : TRUE);
1574 KFW_AFS_renew_tokens_for_all_cells(void)
1576 struct cell_principal_map * next = cell_princ_map;
1578 if ( IsDebuggerPresent() )
1579 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1584 for ( ; next ; next = next->next ) {
1586 KFW_AFS_renew_token_for_cell(next->cell);
1592 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1594 krb5_error_code code = 0;
1595 krb5_context ctx = 0;
1597 krb5_principal me = 0;
1598 krb5_principal server = 0;
1599 krb5_creds my_creds;
1600 krb5_data *realm = 0;
1602 if (!pkrb5_init_context)
1605 memset(&my_creds, 0, sizeof(krb5_creds));
1610 code = pkrb5_init_context(&ctx);
1611 if (code) goto cleanup;
1617 code = pkrb5_cc_default(ctx, &cc);
1618 if (code) goto cleanup;
1621 code = pkrb5_cc_get_principal(ctx, cc, &me);
1622 if (code) goto cleanup;
1624 realm = krb5_princ_realm(ctx, me);
1626 code = pkrb5_build_principal_ext(ctx, &server,
1627 realm->length,realm->data,
1628 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1629 realm->length,realm->data,
1634 if ( IsDebuggerPresent() ) {
1635 char * cname, *sname;
1636 pkrb5_unparse_name(ctx, me, &cname);
1637 pkrb5_unparse_name(ctx, server, &sname);
1638 OutputDebugString("Renewing credential for client \"");
1639 OutputDebugString(cname);
1640 OutputDebugString("\" and service \"");
1641 OutputDebugString(sname);
1642 OutputDebugString("\"\n");
1643 pkrb5_free_unparsed_name(ctx,cname);
1644 pkrb5_free_unparsed_name(ctx,sname);
1647 my_creds.client = me;
1648 my_creds.server = server;
1650 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1652 if ( IsDebuggerPresent() ) {
1654 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1655 OutputDebugString(message);
1660 code = pkrb5_cc_initialize(ctx, cc, me);
1662 if ( IsDebuggerPresent() ) {
1664 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1665 OutputDebugString(message);
1670 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1672 if ( IsDebuggerPresent() ) {
1674 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1675 OutputDebugString(message);
1681 if (my_creds.client == me)
1682 my_creds.client = 0;
1683 if (my_creds.server == server)
1684 my_creds.server = 0;
1685 pkrb5_free_cred_contents(ctx, &my_creds);
1687 pkrb5_free_principal(ctx, me);
1689 pkrb5_free_principal(ctx, server);
1690 if (cc && (cc != alt_cc))
1691 pkrb5_cc_close(ctx, cc);
1692 if (ctx && (ctx != alt_ctx))
1693 pkrb5_free_context(ctx);
1698 KFW_kinit( krb5_context alt_ctx,
1701 char *principal_name,
1703 krb5_deltat lifetime,
1706 krb5_deltat renew_life,
1711 krb5_error_code code = 0;
1712 krb5_context ctx = 0;
1714 krb5_principal me = 0;
1716 krb5_creds my_creds;
1717 krb5_get_init_creds_opt options;
1718 krb5_address ** addrs = NULL;
1719 int i = 0, addr_count = 0;
1721 if (!pkrb5_init_context)
1724 pkrb5_get_init_creds_opt_init(&options);
1725 memset(&my_creds, 0, sizeof(my_creds));
1733 code = pkrb5_init_context(&ctx);
1734 if (code) goto cleanup;
1740 code = pkrb5_cc_default(ctx, &cc);
1741 if (code) goto cleanup;
1744 code = pkrb5_parse_name(ctx, principal_name, &me);
1748 code = pkrb5_unparse_name(ctx, me, &name);
1753 lifetime = pLeash_get_default_lifetime();
1761 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1762 pkrb5_get_init_creds_opt_set_forwardable(&options,
1763 forwardable ? 1 : 0);
1764 pkrb5_get_init_creds_opt_set_proxiable(&options,
1766 pkrb5_get_init_creds_opt_set_renew_life(&options,
1769 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1773 // we are going to add the public IP address specified by the user
1774 // to the list provided by the operating system
1775 krb5_address ** local_addrs=NULL;
1778 pkrb5_os_localaddr(ctx, &local_addrs);
1779 while ( local_addrs[i++] );
1782 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1784 pkrb5_free_addresses(ctx, local_addrs);
1787 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1789 while ( local_addrs[i] ) {
1790 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1791 if (addrs[i] == NULL) {
1792 pkrb5_free_addresses(ctx, local_addrs);
1796 addrs[i]->magic = local_addrs[i]->magic;
1797 addrs[i]->addrtype = local_addrs[i]->addrtype;
1798 addrs[i]->length = local_addrs[i]->length;
1799 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1800 if (!addrs[i]->contents) {
1801 pkrb5_free_addresses(ctx, local_addrs);
1805 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1806 local_addrs[i]->length); /* safe */
1809 pkrb5_free_addresses(ctx, local_addrs);
1811 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1812 if (addrs[i] == NULL)
1815 addrs[i]->magic = KV5M_ADDRESS;
1816 addrs[i]->addrtype = AF_INET;
1817 addrs[i]->length = 4;
1818 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1819 if (!addrs[i]->contents)
1822 netIPAddr = htonl(publicIP);
1823 memcpy(addrs[i]->contents,&netIPAddr,4);
1825 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1830 code = pkrb5_get_init_creds_password(ctx,
1833 password, // password
1834 KRB5_prompter, // prompter
1835 hParent, // prompter data
1842 code = pkrb5_cc_initialize(ctx, cc, me);
1846 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1852 for ( i=0;i<addr_count;i++ ) {
1854 if ( addrs[i]->contents )
1855 free(addrs[i]->contents);
1860 if (my_creds.client == me)
1861 my_creds.client = 0;
1862 pkrb5_free_cred_contents(ctx, &my_creds);
1864 pkrb5_free_unparsed_name(ctx, name);
1866 pkrb5_free_principal(ctx, me);
1867 if (cc && (cc != alt_cc))
1868 pkrb5_cc_close(ctx, cc);
1869 if (ctx && (ctx != alt_ctx))
1870 pkrb5_free_context(ctx);
1876 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
1880 krb5_error_code code;
1882 if (!pkrb5_init_context)
1891 code = pkrb5_init_context(&ctx);
1892 if (code) goto cleanup;
1898 code = pkrb5_cc_default(ctx, &cc);
1899 if (code) goto cleanup;
1902 code = pkrb5_cc_destroy(ctx, cc);
1903 if ( !code ) cc = 0;
1906 if (cc && (cc != alt_cc))
1907 pkrb5_cc_close(ctx, cc);
1908 if (ctx && (ctx != alt_ctx))
1909 pkrb5_free_context(ctx);
1917 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1919 NTSTATUS Status = 0;
1921 TOKEN_STATISTICS Stats;
1927 *ppSessionData = NULL;
1929 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1933 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1934 CloseHandle( TokenHandle );
1938 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1939 if ( FAILED(Status) || !ppSessionData )
1946 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1947 // cache. It validates whether or not it is reasonable to assume that if we
1948 // attempted to retrieve valid tickets we could do so. Microsoft does not
1949 // automatically renew expired tickets. Therefore, the cache could contain
1950 // expired or invalid tickets. Microsoft also caches the user's password
1951 // and will use it to retrieve new TGTs if the cache is empty and tickets
1955 MSLSA_IsKerberosLogon(VOID)
1957 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1958 BOOL Success = FALSE;
1960 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1961 if ( pSessionData->AuthenticationPackage.Buffer ) {
1967 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1968 usLength = (pSessionData->AuthenticationPackage).Length;
1971 lstrcpynW (buffer, usBuffer, usLength);
1972 lstrcatW (buffer,L"");
1973 if ( !lstrcmpW(L"Kerberos",buffer) )
1977 pLsaFreeReturnBuffer(pSessionData);
1981 #endif /* USE_MS2MIT */
1983 static BOOL CALLBACK
1984 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1988 switch ( message ) {
1990 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1992 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1995 for ( i=0; i < mid_cnt ; i++ ) {
1996 if (mid_tb[i].echo == 0)
1997 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1998 else if (mid_tb[i].echo == 2)
1999 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2004 switch ( LOWORD(wParam) ) {
2006 for ( i=0; i < mid_cnt ; i++ ) {
2007 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2008 *mid_tb[i].buf = '\0';
2012 EndDialog(hDialog, LOWORD(wParam));
2020 lpwAlign( LPWORD lpIn )
2028 return (LPWORD) ul;;
2032 * dialog widths are measured in 1/4 character widths
2033 * dialog height are measured in 1/8 character heights
2037 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2038 char * ptext[], int numlines, int width,
2039 int tb_cnt, struct textField * tb)
2043 LPDLGITEMTEMPLATE lpdit;
2049 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2056 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2058 // Define a dialog box.
2060 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2061 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2062 | DS_SETFOREGROUND | DS_3DLOOK
2063 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2064 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2067 lpdt->cx = 20 + width * 4;
2068 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2070 lpw = (LPWORD) (lpdt + 1);
2071 *lpw++ = 0; // no menu
2072 *lpw++ = 0; // predefined dialog box class (by default)
2074 lpwsz = (LPWSTR) lpw;
2075 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2077 *lpw++ = 8; // font size (points)
2078 lpwsz = (LPWSTR) lpw;
2079 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2083 //-----------------------
2084 // Define an OK button.
2085 //-----------------------
2086 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2087 lpdit = (LPDLGITEMTEMPLATE) lpw;
2088 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2089 lpdit->dwExtendedStyle = 0;
2090 lpdit->x = (lpdt->cx - 14)/4 - 20;
2091 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2094 lpdit->id = IDOK; // OK button identifier
2096 lpw = (LPWORD) (lpdit + 1);
2098 *lpw++ = 0x0080; // button class
2100 lpwsz = (LPWSTR) lpw;
2101 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2103 *lpw++ = 0; // no creation data
2105 //-----------------------
2106 // Define an Cancel button.
2107 //-----------------------
2108 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2109 lpdit = (LPDLGITEMTEMPLATE) lpw;
2110 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2111 lpdit->dwExtendedStyle = 0;
2112 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2113 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2116 lpdit->id = IDCANCEL; // CANCEL button identifier
2118 lpw = (LPWORD) (lpdit + 1);
2120 *lpw++ = 0x0080; // button class
2122 lpwsz = (LPWSTR) lpw;
2123 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2125 *lpw++ = 0; // no creation data
2127 /* Add controls for preface data */
2128 for ( i=0; i<numlines; i++) {
2129 /*-----------------------
2130 * Define a static text control.
2131 *-----------------------*/
2132 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2133 lpdit = (LPDLGITEMTEMPLATE) lpw;
2134 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2135 lpdit->dwExtendedStyle = 0;
2137 lpdit->y = 10 + i * 14;
2138 lpdit->cx = strlen(ptext[i]) * 4 + 10;
2140 lpdit->id = ID_TEXT + i; // text identifier
2142 lpw = (LPWORD) (lpdit + 1);
2144 *lpw++ = 0x0082; // static class
2146 lpwsz = (LPWSTR) lpw;
2147 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2148 -1, lpwsz, 2*width);
2150 *lpw++ = 0; // no creation data
2153 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2154 if ( pwid < strlen(tb[i].label) )
2155 pwid = strlen(tb[i].label);
2158 for ( i=0; i<tb_cnt; i++) {
2160 /*-----------------------
2161 * Define a static text control.
2162 *-----------------------*/
2163 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2164 lpdit = (LPDLGITEMTEMPLATE) lpw;
2165 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2166 lpdit->dwExtendedStyle = 0;
2168 lpdit->y = 10 + (numlines + i + 1) * 14;
2169 lpdit->cx = pwid * 4;
2171 lpdit->id = ID_TEXT + numlines + i; // text identifier
2173 lpw = (LPWORD) (lpdit + 1);
2175 *lpw++ = 0x0082; // static class
2177 lpwsz = (LPWSTR) lpw;
2178 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2181 *lpw++ = 0; // no creation data
2183 /*-----------------------
2184 * Define an edit control.
2185 *-----------------------*/
2186 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2187 lpdit = (LPDLGITEMTEMPLATE) lpw;
2188 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2189 lpdit->dwExtendedStyle = 0;
2190 lpdit->x = 10 + (pwid + 1) * 4;
2191 lpdit->y = 10 + (numlines + i + 1) * 14;
2192 lpdit->cx = (width - (pwid + 1)) * 4;
2194 lpdit->id = ID_MID_TEXT + i; // identifier
2196 lpw = (LPWORD) (lpdit + 1);
2198 *lpw++ = 0x0081; // edit class
2200 lpwsz = (LPWSTR) lpw;
2201 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2204 *lpw++ = 0; // no creation data
2208 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2209 hwndOwner, (DLGPROC) MultiInputDialogProc);
2213 case 0: /* Timeout */
2221 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2222 MessageBox(hwndOwner,
2225 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2232 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2234 HINSTANCE hInst = 0;
2238 char * plines[16], *p = preface ? preface : "";
2241 for ( i=0; i<16; i++ )
2244 while (*p && numlines < 16) {
2245 plines[numlines++] = p;
2246 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2247 if ( *p == '\r' && *(p+1) == '\n' ) {
2250 } else if ( *p == '\n' ) {
2253 if ( strlen(plines[numlines-1]) > maxwidth )
2254 maxwidth = strlen(plines[numlines-1]);
2257 for ( i=0;i<n;i++ ) {
2258 len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2259 if ( maxwidth < len )
2263 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2266 static krb5_error_code KRB5_CALLCONV
2267 KRB5_prompter( krb5_context context,
2272 krb5_prompt prompts[])
2274 krb5_error_code errcode = 0;
2276 struct textField * tb = NULL;
2277 int len = 0, blen=0, nlen=0;
2278 HWND hParent = (HWND)data;
2281 nlen = strlen(name)+2;
2284 blen = strlen(banner)+2;
2286 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2289 memset(tb,0,sizeof(struct textField) * num_prompts);
2290 for ( i=0; i < num_prompts; i++ ) {
2291 tb[i].buf = prompts[i].reply->data;
2292 tb[i].len = prompts[i].reply->length;
2293 tb[i].label = prompts[i].prompt;
2295 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2298 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2300 for ( i=0; i < num_prompts; i++ )
2301 prompts[i].reply->length = strlen(prompts[i].reply->data);
2309 for (i = 0; i < num_prompts; i++) {
2310 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2317 KFW_AFS_wait_for_service_start(void)
2322 CurrentState = SERVICE_START_PENDING;
2323 memset(HostName, '\0', sizeof(HostName));
2324 gethostname(HostName, sizeof(HostName));
2326 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2328 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2330 if ( IsDebuggerPresent() ) {
2331 switch ( CurrentState ) {
2332 case SERVICE_STOPPED:
2333 OutputDebugString("SERVICE_STOPPED\n");
2335 case SERVICE_START_PENDING:
2336 OutputDebugString("SERVICE_START_PENDING\n");
2338 case SERVICE_STOP_PENDING:
2339 OutputDebugString("SERVICE_STOP_PENDING\n");
2341 case SERVICE_RUNNING:
2342 OutputDebugString("SERVICE_RUNNING\n");
2344 case SERVICE_CONTINUE_PENDING:
2345 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2347 case SERVICE_PAUSE_PENDING:
2348 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2350 case SERVICE_PAUSED:
2351 OutputDebugString("SERVICE_PAUSED\n");
2354 OutputDebugString("UNKNOWN Service State\n");
2357 if (CurrentState == SERVICE_STOPPED)
2359 if (CurrentState == SERVICE_RUNNING)
2375 memset(HostName, '\0', sizeof(HostName));
2376 gethostname(HostName, sizeof(HostName));
2377 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2379 if (CurrentState != SERVICE_RUNNING)
2382 rc = pktc_ForgetAllTokens();
2388 #define TKTLIFENUMFIXED 64
2389 #define TKTLIFEMINFIXED 0x80
2390 #define TKTLIFEMAXFIXED 0xBF
2391 #define TKTLIFENOEXPIRE 0xFF
2392 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
2394 #define NEVERDATE ((unsigned long)0x7fffffffL)
2397 static int no_long_lifetimes = 0;
2398 typedef unsigned long u_int32_t;
2400 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
2401 38400, /* 10.67 hours, 0.44 days */
2402 41055, /* 11.40 hours, 0.48 days */
2403 43894, /* 12.19 hours, 0.51 days */
2404 46929, /* 13.04 hours, 0.54 days */
2405 50174, /* 13.94 hours, 0.58 days */
2406 53643, /* 14.90 hours, 0.62 days */
2407 57352, /* 15.93 hours, 0.66 days */
2408 61318, /* 17.03 hours, 0.71 days */
2409 65558, /* 18.21 hours, 0.76 days */
2410 70091, /* 19.47 hours, 0.81 days */
2411 74937, /* 20.82 hours, 0.87 days */
2412 80119, /* 22.26 hours, 0.93 days */
2413 85658, /* 23.79 hours, 0.99 days */
2414 91581, /* 25.44 hours, 1.06 days */
2415 97914, /* 27.20 hours, 1.13 days */
2416 104684, /* 29.08 hours, 1.21 days */
2417 111922, /* 31.09 hours, 1.30 days */
2418 119661, /* 33.24 hours, 1.38 days */
2419 127935, /* 35.54 hours, 1.48 days */
2420 136781, /* 37.99 hours, 1.58 days */
2421 146239, /* 40.62 hours, 1.69 days */
2422 156350, /* 43.43 hours, 1.81 days */
2423 167161, /* 46.43 hours, 1.93 days */
2424 178720, /* 49.64 hours, 2.07 days */
2425 191077, /* 53.08 hours, 2.21 days */
2426 204289, /* 56.75 hours, 2.36 days */
2427 218415, /* 60.67 hours, 2.53 days */
2428 233517, /* 64.87 hours, 2.70 days */
2429 249664, /* 69.35 hours, 2.89 days */
2430 266926, /* 74.15 hours, 3.09 days */
2431 285383, /* 79.27 hours, 3.30 days */
2432 305116, /* 84.75 hours, 3.53 days */
2433 326213, /* 90.61 hours, 3.78 days */
2434 348769, /* 96.88 hours, 4.04 days */
2435 372885, /* 103.58 hours, 4.32 days */
2436 398668, /* 110.74 hours, 4.61 days */
2437 426234, /* 118.40 hours, 4.93 days */
2438 455705, /* 126.58 hours, 5.27 days */
2439 487215, /* 135.34 hours, 5.64 days */
2440 520904, /* 144.70 hours, 6.03 days */
2441 556921, /* 154.70 hours, 6.45 days */
2442 595430, /* 165.40 hours, 6.89 days */
2443 636601, /* 176.83 hours, 7.37 days */
2444 680618, /* 189.06 hours, 7.88 days */
2445 727680, /* 202.13 hours, 8.42 days */
2446 777995, /* 216.11 hours, 9.00 days */
2447 831789, /* 231.05 hours, 9.63 days */
2448 889303, /* 247.03 hours, 10.29 days */
2450 950794, /* 264.11 hours, 11.00 days */
2452 1016537, /* 282.37 hours, 11.77 days */
2454 1086825, /* 301.90 hours, 12.58 days */
2456 1161973, /* 322.77 hours, 13.45 days */
2458 1242318, /* 345.09 hours, 14.38 days */
2460 1328218, /* 368.95 hours, 15.37 days */
2462 1420057, /* 394.46 hours, 16.44 days */
2464 1518247, /* 421.74 hours, 17.57 days */
2466 1623226, /* 450.90 hours, 18.79 days */
2468 1735464, /* 482.07 hours, 20.09 days */
2470 1855462, /* 515.41 hours, 21.48 days */
2472 1983758, /* 551.04 hours, 22.96 days */
2474 2120925, /* 589.15 hours, 24.55 days */
2476 2267576, /* 629.88 hours, 26.25 days */
2478 2424367, /* 673.44 hours, 28.06 days */
2480 2592000}; /* 720.00 hours, 30.00 days */
2485 krb5_context alt_ctx,
2496 struct ktc_principal aserver;
2497 struct ktc_principal aclient;
2498 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2499 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2500 char local_cell[MAXCELLCHARS+1];
2501 char Dmycell[MAXCELLCHARS+1];
2502 struct ktc_token atoken;
2503 struct ktc_token btoken;
2504 afsconf_cell ak_cellconfig; /* General information about the cell */
2505 char RealmName[128];
2507 char ServiceName[128];
2511 krb5_context ctx = 0;
2514 krb5_creds * k5creds = 0;
2515 krb5_error_code code;
2516 krb5_principal client_principal = 0;
2517 char * cname = 0, *sname = 0;
2521 memset(HostName, '\0', sizeof(HostName));
2522 gethostname(HostName, sizeof(HostName));
2523 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2524 if ( IsDebuggerPresent() )
2525 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2528 if (CurrentState != SERVICE_RUNNING) {
2529 if ( IsDebuggerPresent() )
2530 OutputDebugString("AFSD Service NOT RUNNING\n");
2534 if (!pkrb5_init_context)
2537 memset(RealmName, '\0', sizeof(RealmName));
2538 memset(CellName, '\0', sizeof(CellName));
2539 memset(ServiceName, '\0', sizeof(ServiceName));
2540 memset(realm_of_user, '\0', sizeof(realm_of_user));
2541 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2542 if (cell && cell[0])
2543 strcpy(Dmycell, cell);
2545 memset(Dmycell, '\0', sizeof(Dmycell));
2547 // NULL or empty cell returns information on local cell
2548 if (rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2550 // KFW_AFS_error(rc, "get_cellconfig()");
2557 code = pkrb5_init_context(&ctx);
2558 if (code) goto cleanup;
2564 code = pkrb5_cc_default(ctx, &cc);
2565 if (code) goto skip_krb5_init;
2568 memset((char *)&increds, 0, sizeof(increds));
2570 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2572 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2574 OutputDebugString("Principal Not Found for ccache\n");
2576 goto skip_krb5_init;
2578 i = krb5_princ_realm(ctx, client_principal)->length;
2581 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2582 realm_of_user[i] = 0;
2587 if ( !try_krb5 || !realm_of_user[0] ) {
2588 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2596 strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
2598 if (strlen(service) == 0)
2599 strcpy(ServiceName, "afs");
2601 strcpy(ServiceName, service);
2603 if (strlen(cell) == 0)
2604 strcpy(CellName, local_cell);
2606 strcpy(CellName, cell);
2608 if (strlen(realm) == 0)
2609 strcpy(RealmName, realm_of_cell);
2611 strcpy(RealmName, realm);
2613 memset(&creds, '\0', sizeof(creds));
2619 /* First try service/cell@REALM */
2620 if (code = pkrb5_build_principal(ctx, &increds.server,
2630 increds.client = client_principal;
2631 increds.times.endtime = 0;
2632 /* Ask for DES since that is what V4 understands */
2633 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2636 if ( IsDebuggerPresent() ) {
2637 pkrb5_unparse_name(ctx, increds.client, &cname);
2638 pkrb5_unparse_name(ctx, increds.server, &sname);
2639 OutputDebugString("Getting tickets for \"");
2640 OutputDebugString(cname);
2641 OutputDebugString("\" and service \"");
2642 OutputDebugString(sname);
2643 OutputDebugString("\"\n");
2647 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2648 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2649 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2650 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2651 /* Or service@REALM */
2652 pkrb5_free_principal(ctx,increds.server);
2654 code = pkrb5_build_principal(ctx, &increds.server,
2660 if ( IsDebuggerPresent() ) {
2661 char * cname, *sname;
2662 pkrb5_unparse_name(ctx, increds.client, &cname);
2663 pkrb5_unparse_name(ctx, increds.server, &sname);
2664 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2665 OutputDebugString("Trying again: getting tickets for \"");
2666 OutputDebugString(cname);
2667 OutputDebugString("\" and service \"");
2668 OutputDebugString(sname);
2669 OutputDebugString("\"\n");
2670 pkrb5_free_unparsed_name(ctx,cname);
2671 pkrb5_free_unparsed_name(ctx,sname);
2676 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2679 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2680 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2681 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2682 strcmp(RealmName, realm_of_cell)) {
2683 /* Or service/cell@REALM_OF_CELL */
2684 strcpy(RealmName, realm_of_cell);
2685 pkrb5_free_principal(ctx,increds.server);
2687 code = pkrb5_build_principal(ctx, &increds.server,
2694 if ( IsDebuggerPresent() ) {
2695 char * cname, *sname;
2696 pkrb5_unparse_name(ctx, increds.client, &cname);
2697 pkrb5_unparse_name(ctx, increds.server, &sname);
2698 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2699 OutputDebugString("Trying again: getting tickets for \"");
2700 OutputDebugString(cname);
2701 OutputDebugString("\" and service \"");
2702 OutputDebugString(sname);
2703 OutputDebugString("\"\n");
2704 pkrb5_free_unparsed_name(ctx,cname);
2705 pkrb5_free_unparsed_name(ctx,sname);
2710 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2713 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2714 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2715 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2716 /* Or service@REALM_OF_CELL */
2717 pkrb5_free_principal(ctx,increds.server);
2719 code = pkrb5_build_principal(ctx, &increds.server,
2725 if ( IsDebuggerPresent() ) {
2726 char * cname, *sname;
2727 pkrb5_unparse_name(ctx, increds.client, &cname);
2728 pkrb5_unparse_name(ctx, increds.server, &sname);
2729 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2730 OutputDebugString("Trying again: getting tickets for \"");
2731 OutputDebugString(cname);
2732 OutputDebugString("\" and service \"");
2733 OutputDebugString(sname);
2734 OutputDebugString("\"\n");
2735 pkrb5_free_unparsed_name(ctx,cname);
2736 pkrb5_free_unparsed_name(ctx,sname);
2741 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2746 if ( IsDebuggerPresent() ) {
2748 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2749 OutputDebugString(message);
2755 /* This code inserts the entire K5 ticket into the token
2756 * No need to perform a krb524 translation which is
2757 * commented out in the code below
2759 if (k5creds->ticket.length > MAXKTCTICKETLEN)
2762 memset(&aserver, '\0', sizeof(aserver));
2763 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2764 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2766 memset(&atoken, '\0', sizeof(atoken));
2767 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2768 atoken.startTime = k5creds->times.starttime;
2769 atoken.endTime = k5creds->times.endtime;
2770 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2771 atoken.ticketLen = k5creds->ticket.length;
2772 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2775 rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2776 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2777 if ( rc == KTC_NOCM && retry < 20 ) {
2780 goto retry_gettoken5;
2785 if (atoken.kvno == btoken.kvno &&
2786 atoken.ticketLen == btoken.ticketLen &&
2787 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2788 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2790 /* Success - Nothing to do */
2794 // * Reset the "aclient" structure before we call ktc_SetToken.
2795 // * This structure was first set by the ktc_GetToken call when
2796 // * we were comparing whether identical tokens already existed.
2798 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2799 strncpy(aclient.name, k5creds->client->data[0].data, len);
2800 aclient.name[len] = '\0';
2802 if ( k5creds->client->length > 1 ) {
2803 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - 1);
2804 strncpy(aclient.instance, k5creds->client->data[1].data, len);
2805 aclient.instance[len] = '\0';
2807 aclient.instance[0] = '\0';
2808 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - 1);
2809 for ( i=0; i<len; i++ ) {
2810 aclient.cell[i] = tolower(k5creds->client->realm.data[i]);
2812 aclient.cell[len] = '\0';
2813 aclient.smbname[0] = '\0';
2815 rc = pktc_SetToken(&aserver, &atoken, &aclient, 0);
2817 goto cleanup; /* We have successfully inserted the token */
2820 /* Otherwise, the ticket could have been too large so try to
2821 * convert using the krb524d running with the KDC
2823 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2824 pkrb5_free_creds(ctx, k5creds);
2826 if ( IsDebuggerPresent() ) {
2828 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2829 OutputDebugString(message);
2837 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
2838 if (code == NO_TKT_FIL) {
2839 // if the problem is that we have no krb4 tickets
2840 // do not attempt to continue
2843 if (code != KSUCCESS)
2844 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
2846 if (code != KSUCCESS)
2848 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
2850 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
2855 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
2857 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
2872 memset(&aserver, '\0', sizeof(aserver));
2873 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2874 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2876 memset(&atoken, '\0', sizeof(atoken));
2877 atoken.kvno = creds.kvno;
2878 atoken.startTime = creds.issue_date;
2879 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
2880 memcpy(&atoken.sessionKey, creds.session, 8);
2881 atoken.ticketLen = creds.ticket_st.length;
2882 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
2885 rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2886 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2887 if ( rc == KTC_NOCM && retry < 20 ) {
2890 goto retry_gettoken;
2892 KFW_AFS_error(rc, "ktc_GetToken()");
2897 if (atoken.kvno == btoken.kvno &&
2898 atoken.ticketLen == btoken.ticketLen &&
2899 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2900 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2905 // * Reset the "aclient" structure before we call ktc_SetToken.
2906 // * This structure was first set by the ktc_GetToken call when
2907 // * we were comparing whether identical tokens already existed.
2909 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
2910 strcpy(aclient.instance, creds.pinst);
2911 strncpy(aclient.cell, creds.realm, MAXKTCREALMLEN - 1);
2913 if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0))
2915 KFW_AFS_error(rc, "ktc_SetToken()");
2922 pkrb5_free_unparsed_name(ctx,cname);
2924 pkrb5_free_unparsed_name(ctx,sname);
2925 if (client_principal)
2926 pkrb5_free_principal(ctx,client_principal);
2927 /* increds.client == client_principal */
2929 pkrb5_free_principal(ctx,increds.server);
2930 if (cc && (cc != alt_cc))
2931 pkrb5_cc_close(ctx, cc);
2932 if (ctx && (ctx != alt_ctx))
2933 pkrb5_free_context(ctx);
2935 return(rc? rc : code);
2938 /**************************************/
2939 /* afs_realm_of_cell(): */
2940 /**************************************/
2942 afs_realm_of_cell(afsconf_cell *cellconfig)
2944 static char krbrlm[REALM_SZ+1]="";
2945 krb5_context ctx = 0;
2946 char ** realmlist=NULL;
2952 if (!pkrb5_init_context)
2955 r = pkrb5_init_context(&ctx);
2957 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
2958 if ( !r && realmlist && realmlist[0] ) {
2959 strcpy(krbrlm, realmlist[0]);
2960 pkrb5_free_host_realm(ctx, realmlist);
2963 pkrb5_free_context(ctx);
2968 char *t = cellconfig->name;
2973 if (islower(c)) c=toupper(c);
2981 /**************************************/
2982 /* get_cellconfig(): */
2983 /**************************************/
2985 get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell)
2988 char newcell[MAXCELLCHARS+1];
2990 local_cell[0] = (char)0;
2991 memset(cellconfig, 0, sizeof(*cellconfig));
2993 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2994 if (rc = pcm_GetRootCellName(local_cell))
2999 if (strlen(cell) == 0)
3000 strcpy(cell, local_cell);
3002 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3003 strcpy(cellconfig->name, cell);
3005 return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3008 /**************************************/
3009 /* get_cellconfig_callback(): */
3010 /**************************************/
3012 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3014 afsconf_cell *cc = (afsconf_cell *)cellconfig;
3016 cc->hostAddr[cc->numServers] = *addrp;
3017 strcpy(cc->hostName[cc->numServers], namep);
3023 /**************************************/
3024 /* KFW_AFS_error(): */
3025 /**************************************/
3027 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3030 const char *errText;
3032 // Using AFS defines as error messages for now, until Transarc
3033 // gets back to me with "string" translations of each of these
3035 if (rc == KTC_ERROR)
3036 errText = "KTC_ERROR";
3037 else if (rc == KTC_TOOBIG)
3038 errText = "KTC_TOOBIG";
3039 else if (rc == KTC_INVAL)
3040 errText = "KTC_INVAL";
3041 else if (rc == KTC_NOENT)
3042 errText = "KTC_NOENT";
3043 else if (rc == KTC_PIOCTLFAIL)
3044 errText = "KTC_PIOCTLFAIL";
3045 else if (rc == KTC_NOPIOCTL)
3046 errText = "KTC_NOPIOCTL";
3047 else if (rc == KTC_NOCELL)
3048 errText = "KTC_NOCELL";
3049 else if (rc == KTC_NOCM)
3050 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3052 errText = "Unknown error!";
3054 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3056 if ( IsDebuggerPresent() ) {
3057 OutputDebugString(message);
3058 OutputDebugString("\n");
3060 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3066 LPSTR lpszMachineName,
3067 LPSTR lpszServiceName,
3068 DWORD *lpdwCurrentState)
3071 SC_HANDLE schSCManager = NULL;
3072 SC_HANDLE schService = NULL;
3073 DWORD fdwDesiredAccess = 0;
3074 SERVICE_STATUS ssServiceStatus = {0};
3077 *lpdwCurrentState = 0;
3079 fdwDesiredAccess = GENERIC_READ;
3081 schSCManager = OpenSCManager(lpszMachineName,
3085 if(schSCManager == NULL)
3087 hr = GetLastError();
3091 schService = OpenService(schSCManager,
3095 if(schService == NULL)
3097 hr = GetLastError();
3101 fRet = QueryServiceStatus(schService,
3106 hr = GetLastError();
3110 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3114 CloseServiceHandle(schService);
3115 CloseServiceHandle(schSCManager);
3128 for (n = 0; fi[n].func_ptr_var; n++)
3129 *(fi[n].func_ptr_var) = 0;
3130 if (h) FreeLibrary(h);
3135 const char* dll_name,
3137 HINSTANCE* ph, // [out, optional] - DLL handle
3138 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3139 int cleanup, // cleanup function pointers and unload on error
3140 int go_on, // continue loading even if some functions cannot be loaded
3141 int silent // do not pop-up a system dialog if DLL cannot be loaded
3150 if (pindex) *pindex = -1;
3152 for (n = 0; fi[n].func_ptr_var; n++)
3153 *(fi[n].func_ptr_var) = 0;
3156 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3157 h = LoadLibrary(dll_name);
3165 for (i = 0; (go_on || !error) && (i < n); i++)
3167 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3173 *(fi[i].func_ptr_var) = p;
3176 if (pindex) *pindex = last_i;
3177 if (error && cleanup && !go_on) {
3178 for (i = 0; i < n; i++) {
3179 *(fi[i].func_ptr_var) = 0;
3185 if (error) return 0;
3190 // Cell Accessibility Functions
3191 // based on work originally submitted to the CMU Computer Club
3192 // by Jeffrey Hutzelman
3194 // These would work great if the fsProbe interface had been
3195 // ported to Windows
3198 void probeComplete()
3204 struct ping_params {
3205 unsigned short port; // in
3206 int retry_delay; // in seconds
3209 int wait; // in seconds
3210 int retry; // in attempts
3212 int max_hosts; // in
3213 int hosts_attempted; // out
3216 // the fsHandler is where we receive the answer to the probe
3220 ping_count = fsprobe_Results.probeNum;
3221 if (!*fsprobe_Results.probeOK)
3224 if (waiting) complete();
3226 if (ping_count == retry)
3231 // ping_fs is a callback routine meant to be called from within
3232 // cm_SearchCellFile() or cm_SearchCellDNS()
3234 pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep)
3237 struct ping_params * pp = (struct ping_params *) ping_params;
3239 if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts )
3242 pp->hosts_attempted++;
3244 if (pp->port && addrp->sin_port != htons(pp->port))
3245 addrp->sin_port = htons(pp->port);
3247 rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose);
3250 fprintf(stderr, "fsprobe_Init failed (%d)\n", rc);
3257 tv.tv_sec = pp->host.wait;
3259 if (IOMGR_Select(0, 0, 0, 0, &tv))
3268 pingCell(char *cell)
3271 char rootcell[MAXCELLCHARS+1];
3272 char newcell[MAXCELLCHARS+1];
3273 struct ping_params pp;
3275 memset(&pp, 0, sizeof(struct ping_params));
3277 if (!cell || strlen(cell) == 0) {
3278 /* WIN32 NOTE: no way to get max chars */
3279 if (rc = pcm_GetRootCellName(rootcell))
3284 pp.port = 7000; // AFS FileServer
3285 pp.retry_delay = 10;
3291 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3292 rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp);
3294 #endif /* USE_FSPROBE */
3296 // These two items are imported from afscreds.h
3297 // but it cannot be included without causing conflicts
3298 #define c100ns1SECOND (LONGLONG)10000000
3300 TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT)
3303 memset (pst, 0x00, sizeof(SYSTEMTIME));
3305 if ((pTime = localtime (&TimeT)) != NULL)
3307 pst->wYear = pTime->tm_year + 1900;
3308 pst->wMonth = pTime->tm_mon + 1;
3309 pst->wDayOfWeek = pTime->tm_wday;
3310 pst->wDay = pTime->tm_mday;
3311 pst->wHour = pTime->tm_hour;
3312 pst->wMinute = pTime->tm_min;
3313 pst->wSecond = pTime->tm_sec;
3314 pst->wMilliseconds = 0;
3319 ObtainTokensFromUserIfNeeded(HWND hWnd)
3321 char * rootcell = NULL;
3322 char cell[MAXCELLCHARS+1] = "";
3323 char password[PROBE_PASSWORD_LEN+1];
3325 afsconf_cell cellconfig;
3326 struct ktc_principal aserver;
3327 struct ktc_principal aclient;
3328 struct ktc_token atoken;
3329 krb5_context ctx = 0;
3330 krb5_timestamp now = 0;
3331 krb5_error_code code;
3332 int serverReachable = 0;
3336 const char * realm = 0;
3337 krb5_principal principal = 0;
3339 #endif /* USE_FSPROBE */
3342 int use_kfw = KFW_is_available();
3345 memset(HostName, '\0', sizeof(HostName));
3346 gethostname(HostName, sizeof(HostName));
3347 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
3349 if (CurrentState != SERVICE_RUNNING) {
3350 SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L);
3354 if (!pkrb5_init_context)
3358 code = pkrb5_init_context(&ctx);
3359 if ( code ) goto cleanup;
3362 rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1);
3363 if ( !rootcell ) goto cleanup;
3365 code = get_cellconfig(cell, (void*)&cellconfig, rootcell);
3366 if ( code ) goto cleanup;
3368 memset(&aserver, '\0', sizeof(aserver));
3369 strcpy(aserver.name, "afs");
3370 strcpy(aserver.cell, rootcell);
3372 rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3375 code = pkrb5_timeofday(ctx, &now);
3379 if (!rc && (now < atoken.endTime))
3382 if ( IsDebuggerPresent() ) {
3384 sprintf(message,"KFW_AFS_klog() returns: %d now = %ul endTime = %ul\n",
3385 rc, now, atoken.endTime);
3386 OutputDebugString(message);
3394 SYSTEMTIME stExpires;
3396 TimeToSystemTime (&stExpires, atoken.endTime);
3397 GetLocalTime (&stNow);
3398 SystemTimeToFileTime (&stNow, &ftNow);
3399 SystemTimeToFileTime (&stExpires, &ftExpires);
3401 llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime);
3402 llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime);
3404 llNow /= c100ns1SECOND;
3405 llExpires /= c100ns1SECOND;
3407 if (!rc && (llNow < llExpires))
3410 if ( IsDebuggerPresent() ) {
3412 sprintf(message,"KFW_AFS_klog() returns: %d now = %ul endTime = %ul\n",
3413 rc, llNow, llExpires);
3414 OutputDebugString(message);
3420 serverReachable = cellPing(NULL);
3423 // If we can't use the FSProbe interface we can attempt to forge
3424 // a kinit and if we can back an invalid user error we know the
3425 // kdc is at least reachable
3426 realm = afs_realm_of_cell(&cellconfig); // do not free
3428 code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3429 realm, PROBE_USERNAME, NULL, NULL);
3430 if ( code ) goto cleanup;
3432 code = KFW_get_ccache(ctx, principal, &cc);
3433 if ( code ) goto cleanup;
3435 code = pkrb5_unparse_name(ctx, principal, &pname);
3436 if ( code ) goto cleanup;
3438 pwdata.data = password;
3439 pwdata.length = PROBE_PASSWORD_LEN;
3440 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3443 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3446 password[PROBE_PASSWORD_LEN] = '\0';
3448 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3458 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3459 case KRB5KDC_ERR_CLIENT_REVOKED:
3460 case KRB5KDC_ERR_CLIENT_NOTYET:
3461 case KRB5KDC_ERR_PREAUTH_FAILED:
3462 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3463 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3464 serverReachable = TRUE;
3467 serverReachable = FALSE;
3472 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3475 code = ObtainNewCredentials(rootcell, PROBE_USERNAME, password, TRUE);
3478 case KERB_ERR_PRINCIPAL_UNKNOWN:
3479 case KERB_ERR_SERVICE_EXP:
3481 serverReachable = TRUE;
3484 serverReachable = FALSE;
3488 if ( !serverReachable ) {
3489 if ( IsDebuggerPresent() )
3490 OutputDebugString("Server Unreachable\n");
3494 if ( IsDebuggerPresent() )
3495 OutputDebugString("Server Reachable\n");
3499 KFW_import_windows_lsa();
3500 #endif /* USE_MS2MIT */
3501 KFW_AFS_renew_expiring_tokens();
3502 KFW_AFS_renew_token_for_cell(rootcell);
3504 rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3505 if (!rc && (now < atoken.endTime))
3509 SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
3510 rootcell = NULL; // rootcell freed by message receiver
3514 GlobalFree(rootcell);
3517 if (KFW_is_available()) {
3519 pkrb5_free_unparsed_name(ctx,pname);
3521 pkrb5_free_principal(ctx,principal);
3523 pkrb5_cc_close(ctx,cc);
3524 #endif /* USE_FSPROBE */
3526 pkrb5_free_context(ctx);
3531 // IP Change Monitoring Functions
3532 #include <Iphlpapi.h>
3535 GetNumOfIpAddrs(void)
3537 PMIB_IPADDRTABLE pIpAddrTable = NULL;
3541 DWORD validAddrs = 0;
3544 code = GetIpAddrTable(NULL, &dwSize, 0);
3545 if (code == ERROR_INSUFFICIENT_BUFFER) {
3546 pIpAddrTable = malloc(dwSize);
3547 code = GetIpAddrTable(pIpAddrTable, &dwSize, 0);
3548 if ( code == NO_ERROR ) {
3549 for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
3550 if (pIpAddrTable->table[index].dwAddr != 0)
3560 IpAddrChangeMonitor(void * hWnd)
3562 #ifdef USE_OVERLAPPED
3563 HANDLE Handle = INVALID_HANDLE_VALUE; /* Do Not Close This Handle */
3565 #endif /* USE_OVERLAPPED */
3567 DWORD prevNumOfAddrs = GetNumOfIpAddrs();
3575 #ifdef USE_OVERLAPPED
3576 ZeroMemory(&Ovlap, sizeof(OVERLAPPED));
3578 Result = NotifyAddrChange(&Handle,&Ovlap);
3579 if (Result != ERROR_IO_PENDING)
3581 if ( IsDebuggerPresent() ) {
3582 sprintf(message, "NotifyAddrChange() failed with error %d \n", Result);
3583 OutputDebugString(message);
3588 if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0)
3590 if ( IsDebuggerPresent() ) {
3591 sprintf(message, "WaitForSingleObject() failed with error %d\n",
3593 OutputDebugString(message);
3598 if (GetOverlappedResult(Handle, &Ovlap,
3599 &DataTransfered, TRUE) == 0)
3601 if ( IsDebuggerPresent() ) {
3602 sprintf(message, "GetOverlapped result failed %d \n",
3604 OutputDebugString(message);
3609 Result = NotifyAddrChange(NULL,NULL);
3610 if (Result != NO_ERROR)
3612 if ( IsDebuggerPresent() ) {
3613 sprintf(message, "NotifyAddrChange() failed with error %d \n", Result);
3614 OutputDebugString(message);
3620 NumOfAddrs = GetNumOfIpAddrs();
3622 if ( IsDebuggerPresent() ) {
3623 sprintf(message,"IPAddrChangeMonitor() NumOfAddrs: now %d was %d\n",
3624 NumOfAddrs, prevNumOfAddrs);
3625 OutputDebugString(message);
3628 if ( NumOfAddrs != prevNumOfAddrs ) {
3629 // Give AFS Client Service a chance to notice and die
3630 // Or for network services to startup
3632 // this call should probably be mutex protected
3633 ObtainTokensFromUserIfNeeded(hWnd);
3635 prevNumOfAddrs = NumOfAddrs;
3641 IpAddrChangeMonitorInit(HWND hWnd)
3643 DWORD status = ERROR_SUCCESS;
3647 thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor,
3648 hWnd, 0, &threadID);
3650 if (thread == NULL) {
3651 status = GetLastError();
3653 CloseHandle(thread);