3e5c3ca453d08801d2c93b79d96bf076c025ba55
[openafs.git] / src / WINNT / client_creds / afskfw.c
1 /*
2  * Copyright (c) 2003 SkyRope, LLC
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without 
6  * modification, are permitted provided that the following conditions are met:
7  * 
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.
16  *
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.
28  *
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.
32  *
33  * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
34  * All rights reserved.
35  *
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.
40  *
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.
54  *
55  */
56
57
58 #define USE_MS2MIT
59 #define USE_KRB4
60 #include "afskfw-int.h"
61 #include "afskfw.h"
62 #include "creds.h"
63
64 #include <osilog.h>
65
66 /*
67  * TIMING _____________________________________________________________________
68  *
69  */
70
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
75
76 #define c100ns1SECOND        (LONGLONG)10000000
77 #define cmsec1SECOND         1000
78 #define cmsec1MINUTE         60000
79 #define csec1MINUTE          60
80
81 /* Function Pointer Declarations for Delayed Loading */
82 // CCAPI
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);
87
88 // leash functions
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);
101
102 // krb5 functions
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);
161
162 // Krb524 functions
163 DECL_FUNC_PTR(krb524_init_ets);
164 DECL_FUNC_PTR(krb524_convert_creds_kdc);
165
166 // krb4 functions
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);
171
172 // ComErr functions
173 DECL_FUNC_PTR(com_err);
174 DECL_FUNC_PTR(error_message);
175
176 // Profile functions
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);
183
184 // Service functions
185 DECL_FUNC_PTR(OpenSCManagerA);
186 DECL_FUNC_PTR(OpenServiceA);
187 DECL_FUNC_PTR(QueryServiceStatus);
188 DECL_FUNC_PTR(CloseServiceHandle);
189 #ifdef USE_MS2MIT
190 DECL_FUNC_PTR(LsaNtStatusToWinError);
191 #endif /* USE_MS2MIT */
192
193 #ifdef USE_MS2MIT
194 // LSA Functions
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 */
201
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);
207
208 // AFS36 Config Functions
209 DECL_FUNC_PTR(cm_SearchCellFile);
210 DECL_FUNC_PTR(cm_GetRootCellName);
211
212 // CCAPI
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),
218     END_FUNC_INFO
219 };
220
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),
234     END_FUNC_INFO
235 };
236
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),
297     END_FUNC_INFO
298 };
299
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),
305     END_FUNC_INFO
306 };
307
308 FUNC_INFO k524_fi[] = {
309     MAKE_FUNC_INFO(krb524_init_ets),
310     MAKE_FUNC_INFO(krb524_convert_creds_kdc),
311     END_FUNC_INFO
312 };
313
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),
321         END_FUNC_INFO
322 };
323
324 FUNC_INFO ce_fi[] = {
325     MAKE_FUNC_INFO(com_err),
326     MAKE_FUNC_INFO(error_message),
327     END_FUNC_INFO
328 };
329
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),
335 #ifdef USE_MS2MIT
336     MAKE_FUNC_INFO(LsaNtStatusToWinError),
337 #endif /* USE_MS2MIT */
338     END_FUNC_INFO
339 };
340
341 #ifdef 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),
348     END_FUNC_INFO
349 };
350 #endif /* USE_MS2MIT */
351
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),
357     END_FUNC_INFO
358 };
359
360 FUNC_INFO afsc_fi[] = {
361     MAKE_FUNC_INFO(cm_SearchCellFile),
362     MAKE_FUNC_INFO(cm_GetRootCellName),
363     END_FUNC_INFO
364 };
365
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[]);
373
374
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;
382 #ifdef USE_MS2MIT
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;
395
396 void
397 KFW_initialize(void)
398 {
399     static int inited = 0;
400     if ( !inited ) {
401         inited = 1;
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);
406 #ifdef USE_MS2MIT
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);
415
416         if ( KFW_is_available() ) {
417             char rootcell[MAXCELLCHARS+1];
418 #ifdef USE_MS2MIT
419             KFW_import_windows_lsa();
420 #endif /* USE_MS2MIT */
421             KFW_import_ccache_data();
422                     KFW_AFS_renew_expiring_credentials();
423
424             /* WIN32 NOTE: no way to get max chars */
425             if (!pcm_GetRootCellName(rootcell))
426                 KFW_AFS_renew_token_for_cell(rootcell);
427         }
428     }
429 }
430
431 void
432 KFW_cleanup(void)
433 {
434     if (hKrb5)
435         FreeLibrary(hKrb5);
436     if (hKrb4)
437         FreeLibrary(hKrb4);
438     if (hProfile)
439         FreeLibrary(hProfile);
440     if (hAfsTokens)
441         FreeLibrary(hAfsTokens);
442     if (hAfsConf)
443         FreeLibrary(hAfsConf);
444     if (hComErr)
445         FreeLibrary(hComErr);
446     if (hService)
447         FreeLibrary(hService);
448 #ifdef USE_MS2MIT
449     if (hSecur32)
450         FreeLibrary(hSecur32);
451 #endif /* USE_MS2MIT */
452     if (hKrb524)
453         FreeLibrary(hKrb524);
454     if (hLeash)
455         FreeLibrary(hLeash);
456     if (hCCAPI)
457         FreeLibrary(hCCAPI);
458 }
459
460 static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
461
462 int 
463 KFW_is_available(void)
464 {
465     HKEY parmKey;
466         DWORD code, len;
467     DWORD enableKFW = 1;
468
469     code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
470                          0, KEY_QUERY_VALUE, &parmKey);
471     if (code != ERROR_SUCCESS)
472         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
473                              0, KEY_QUERY_VALUE, &parmKey);
474         if (code == ERROR_SUCCESS) {
475         len = sizeof(enableKFW);
476         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
477                                 (BYTE *) &enableKFW, &len);
478         if (code != ERROR_SUCCESS) {
479             enableKFW = 1;
480         }
481         RegCloseKey (parmKey);
482         }
483
484     if ( !enableKFW )
485         return FALSE;
486
487     KFW_initialize();
488     if ( hKrb5 && hComErr && hService && 
489 #ifdef USE_MS2MIT
490          hSecur32 && 
491 #endif /* USE_MS2MIT */
492          hKrb524 &&
493          hProfile && hAfsTokens && hAfsConf )
494         return TRUE;
495     return FALSE;
496 }
497
498 int 
499 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, 
500                  int FreeContextFlag, krb5_context * ctx, 
501                  krb5_ccache * cache)
502 {
503     char message[256];
504     const char *errText;
505     int krb5Error = ((int)(rc & 255));  
506     
507     /*
508     switch (krb5Error)
509     {
510         // Wrong password
511         case 31:
512         case 8:
513             return;
514     }
515     */
516         
517     errText = perror_message(rc);   
518     _snprintf(message, sizeof(message), 
519               "%s\n(Kerberos error %ld)\n\n%s failed", 
520               errText, 
521               krb5Error, 
522               FailedFunctionName);
523
524     if ( IsDebuggerPresent() )
525         OutputDebugString(message);
526
527     MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 
528                MB_TASKMODAL | 
529                MB_SETFOREGROUND);
530     if (FreeContextFlag == 1)
531     {
532         if (ctx && *ctx != NULL)
533         {
534             if (cache && *cache != NULL) {
535                 pkrb5_cc_close(*ctx, *cache);
536                                 *cache = NULL;
537                         }
538         
539             pkrb5_free_context(*ctx);
540                         *ctx = NULL;
541         }
542     }
543
544     return rc;
545 }
546
547 void
548 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
549 {
550     struct principal_ccache_data * next = princ_cc_data;
551     krb5_principal principal = 0;
552     char * pname = NULL;
553     const char * ccname = NULL;
554     krb5_error_code code = 0;
555     krb5_error_code cc_code = 0;
556     krb5_cc_cursor cur;
557     krb5_creds creds;
558     krb5_flags flags=0;
559     krb5_timestamp now;
560
561     if (ctx == 0 || cc == 0)
562         return;
563
564     code = pkrb5_cc_get_principal(ctx, cc, &principal);
565     if ( code ) return;
566
567     code = pkrb5_unparse_name(ctx, principal, &pname);
568     if ( code ) goto cleanup;
569
570     ccname = pkrb5_cc_get_name(ctx, cc);
571     if (!ccname) goto cleanup;
572
573     // Search the existing list to see if we have a match 
574     if ( next ) {
575         for ( ; next ; next = next->next ) {
576             if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
577                 break;
578         }
579     } 
580
581     // If not, match add a new node to the beginning of the list and assign init it
582     if ( !next ) {
583         next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
584         next->next = princ_cc_data;
585         princ_cc_data = next;
586         next->principal = _strdup(pname);
587         next->ccache_name = _strdup(ccname);
588         next->from_lsa = lsa;
589         next->expired = 1;
590         next->expiration_time = 0;
591         next->renew = 0;
592     }
593
594     flags = 0;  // turn off OPENCLOSE mode
595     code = pkrb5_cc_set_flags(ctx, cc, flags);
596     if ( code ) goto cleanup;
597
598     code = pkrb5_timeofday(ctx, &now);
599
600     cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
601
602     while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
603         if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
604             int valid;
605             // we found the ticket we are looking for
606             // check validity of timestamp 
607             // We add a 5 minutes fudge factor to compensate for potential
608             // clock skew errors between the KDC and client OS
609
610             valid = ((creds.times.starttime > 0) &&
611                      now >= (creds.times.starttime - 300) &&
612                      now < (creds.times.endtime + 300) &&
613                      !(creds.ticket_flags & TKT_FLG_INVALID));
614
615             if ( next->from_lsa) {
616                 next->expired = 0;
617                 next->expiration_time = creds.times.endtime;
618                 next->renew = 1;
619             } else if ( valid ) {
620                 next->expired = 0;
621                 next->expiration_time = creds.times.endtime;
622                 next->renew = (creds.times.renew_till > creds.times.endtime) && 
623                                (creds.ticket_flags & TKT_FLG_RENEWABLE);
624             } else {
625                 next->expired = 1;
626                 next->expiration_time = 0;
627                 next->renew = 0;
628             }
629
630             pkrb5_free_cred_contents(ctx, &creds);
631             cc_code = KRB5_CC_END;
632             break;
633         }
634         pkrb5_free_cred_contents(ctx, &creds);
635     }
636
637     if (cc_code == KRB5_CC_END) {
638         code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
639         if (code) goto cleanup;
640     }
641
642   cleanup:
643     flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
644     code = pkrb5_cc_set_flags(ctx, cc, flags);
645
646     if ( pname )
647         pkrb5_free_unparsed_name(ctx,pname);
648     if ( principal )
649         pkrb5_free_principal(ctx,principal);
650 }   
651
652 int
653 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
654 {
655     struct principal_ccache_data * next = princ_cc_data;
656     char * response = NULL;
657
658     if ( !principal || !ccache )
659         return 0;
660
661     while ( next ) {
662         if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
663             if (response) {
664                 // we always want to prefer the MS Kerberos LSA cache or
665                 // the cache afscreds created specifically for the principal
666                 // if the current entry is either one, drop the previous find
667                 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
668                     free(response);
669             }
670             response = _strdup(next->ccache_name);
671             // MS Kerberos LSA is our best option so use it and quit
672             if ( next->from_lsa )   
673                 break;
674         }
675         next = next->next;
676     }
677
678     if ( response ) {
679         *ccache = response;
680         return 1;
681     }
682     return 0;
683 }
684
685 void 
686 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
687 {
688     struct principal_ccache_data ** next = &princ_cc_data;
689
690     if ( !pname && !ccname )
691         return;
692
693     while ( (*next) ) {
694         if ( !strcmp((*next)->principal,pname) || 
695              !strcmp((*next)->ccache_name,ccname) ) {
696             void * temp;
697             free((*next)->principal);
698             free((*next)->ccache_name);
699             temp = (*next);
700             (*next) = (*next)->next;
701             free(temp);
702         }
703     }
704 }
705
706 void 
707 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
708 {
709     struct cell_principal_map * next = cell_princ_map;
710
711     // Search the existing list to see if we have a match 
712     if ( next ) {
713         for ( ; next ; next = next->next ) {
714             if ( !strcmp(next->cell, cell) ) {
715                 if ( !strcmp(next->principal,pname) ) {
716                     next->active = active;
717                                         break;
718                 } else {
719                     // OpenAFS currently has a restriction of one active token per cell
720                     // Therefore, whenever we update the table with a new active cell we
721                     // must mark all of the other principal to cell entries as inactive.
722                     if (active)
723                         next->active = 0;
724                 }
725             }
726         }
727     } 
728
729     // If not, match add a new node to the beginning of the list and assign init it
730     if ( !next ) {
731         next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
732         next->next = cell_princ_map;
733         cell_princ_map = next;
734         next->principal = _strdup(pname);
735         next->cell = _strdup(cell);
736         next->active = active;
737     }
738 }
739
740 void 
741 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
742 {
743     struct cell_principal_map ** next = &cell_princ_map;
744
745     if ( !pname && !cell )
746         return;
747
748     while ( (*next) ) {
749         if ( !strcmp((*next)->principal,pname) || 
750              !strcmp((*next)->cell,cell) ) {
751             void * temp;
752             free((*next)->principal);
753             free((*next)->cell);
754             temp = (*next);
755             (*next) = (*next)->next;
756             free(temp);
757         }
758     }
759 }
760
761 // Returns (if possible) a principal which has been known in 
762 // the past to have been used to obtain tokens for the specified
763 // cell.  
764 // TODO: Attempt to return one which has not yet expired by checking
765 // the principal/ccache data
766 int
767 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
768 {
769     struct cell_principal_map * next_map = cell_princ_map;
770     const char * princ = NULL;
771     int count = 0, i;
772
773     if ( !cell )
774         return 0;
775
776     while ( next_map ) {
777         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
778             count++;
779         }
780         next_map = next_map->next;
781     }
782
783     if ( !principals )
784         return count;
785
786     *principals = (char **) malloc(sizeof(char *) * count);
787     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
788     {
789         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
790             (*principals)[i++] = _strdup(next_map->principal);
791         }
792     }
793     return count;
794 }
795
796 int
797 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
798 {
799     int     count = 0, i;
800     struct cell_principal_map * next_map = cell_princ_map;
801     const char * princ = NULL;
802     
803     if ( !pname )
804         return 0;
805
806     while ( next_map ) {
807         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
808             count++;
809         }
810         next_map = next_map->next;
811     }
812
813     if ( !cells )
814         return count;
815
816     *cells = (char **) malloc(sizeof(char *) * count);
817     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
818     {
819         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
820             (*cells)[i++] = _strdup(next_map->cell);
821         }
822     }
823     return count;
824 }
825
826 /* Given a principal return an existing ccache or create one and return */
827 int
828 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
829 {
830     krb5_context ctx;
831     char * pname = 0;
832     char * ccname = 0;
833     krb5_error_code code;
834
835     if ( alt_ctx ) {
836         ctx = alt_ctx;
837     } else {
838         code = pkrb5_init_context(&ctx);
839         if (code) goto cleanup;
840     }
841
842     if ( principal ) {
843         code = pkrb5_unparse_name(ctx, principal, &pname);
844         if (code) goto cleanup;
845
846         if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
847              !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
848             ccname = (char *)malloc(strlen(pname) + 5);
849             sprintf(ccname,"API:%s",pname);
850         }
851         code = pkrb5_cc_resolve(ctx, ccname, cc);
852     } else {
853         code = pkrb5_cc_default(ctx, cc);
854         if (code) goto cleanup;
855     }
856
857   cleanup:
858     if (ccname)
859         free(ccname);
860     if (pname)
861         pkrb5_free_unparsed_name(ctx,pname);
862     if (ctx && (ctx != alt_ctx))
863         pkrb5_free_context(ctx);
864     return(code);
865 }
866
867 #ifdef USE_MS2MIT
868 // Import Microsoft Credentials into a new MIT ccache
869 void
870 KFW_import_windows_lsa(void)
871 {
872     krb5_context ctx = 0;
873     krb5_ccache  cc = 0;
874     krb5_principal princ = 0;
875     char * pname = NULL;
876     krb5_data *  realm;
877     krb5_error_code code;
878     char cell[128]="";
879     int i;
880          
881     if ( !MSLSA_IsKerberosLogon() )
882         return;
883
884     code = pkrb5_init_context(&ctx);
885     if (code) goto cleanup;
886
887     code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
888     if (code) goto cleanup;
889
890     KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
891
892     code = pkrb5_cc_get_principal(ctx, cc, &princ);
893     if ( code ) goto cleanup;
894
895     code = pkrb5_unparse_name(ctx,princ,&pname);
896     if ( code ) goto cleanup;
897
898     realm = krb5_princ_realm(ctx, princ);
899     for ( i=0; i<realm->length; i++ ) {
900         cell[i] = tolower(realm->data[i]);
901     }
902         cell[i] = '\0';
903
904     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime());
905     if ( IsDebuggerPresent() ) {
906         char message[256];
907         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
908         OutputDebugString(message);
909     }
910     if ( code ) goto cleanup;
911
912     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
913
914   cleanup:
915     if (pname)
916         pkrb5_free_unparsed_name(ctx,pname);
917     if (princ)
918         pkrb5_free_principal(ctx,princ);
919     if (cc)
920         pkrb5_cc_close(ctx,cc);
921     if (ctx)
922         pkrb5_free_context(ctx);
923 }
924 #endif /* USE_MS2MIT */
925
926 // If there are existing MIT credentials, copy them to a new
927 // ccache named after the principal
928
929 // Enumerate all existing MIT ccaches and construct entries
930 // in the principal_ccache table
931
932 // Enumerate all existing AFS Tokens and construct entries
933 // in the cell_principal table
934 void
935 KFW_import_ccache_data(void)
936 {
937     krb5_context ctx = 0;
938     krb5_ccache  cc = 0;
939     krb5_principal principal = 0;
940     krb5_creds creds;
941     krb5_error_code code;
942     krb5_error_code cc_code;
943     krb5_cc_cursor cur;
944     apiCB * cc_ctx = 0;
945     struct _infoNC ** pNCi = NULL;
946     int i, j, flags;
947
948     if ( !pcc_initialize )
949         return;
950
951     if ( IsDebuggerPresent() )
952         OutputDebugString("KFW_import_ccache_data()\n");
953
954     code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
955     if (code) goto cleanup;
956
957     code = pcc_get_NC_info(cc_ctx, &pNCi);
958     if (code) goto cleanup;
959
960     code = pkrb5_init_context(&ctx);
961     if (code) goto cleanup;
962
963     for ( i=0; pNCi[i]; i++ ) {
964         if ( pNCi[i]->vers != CC_CRED_V5 )
965             continue;
966         if ( IsDebuggerPresent() ) {
967             OutputDebugString("Principal: ");
968             OutputDebugString(pNCi[i]->principal);
969             OutputDebugString(" in ccache ");
970             OutputDebugString(pNCi[i]->name);
971             OutputDebugString("\n");
972         }
973         if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
974              && strcmp(pNCi[i]->name,LSA_CCNAME) 
975              ) {
976             int found = 0;
977             krb5_ccache oldcc = 0;
978             for ( j=0; pNCi[j]; j++ ) {
979                 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
980                     found = 1;
981                     break;
982                 }
983             }
984             if (found)
985                 continue;
986
987             if ( IsDebuggerPresent() )
988                 OutputDebugString("copying ccache data to new ccache\n");
989
990             code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
991             if (code) goto loop_cleanup;
992             code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
993             if (code) goto loop_cleanup;
994             code = pkrb5_cc_initialize(ctx, cc, principal);
995             if (code) goto loop_cleanup;
996             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
997             if (code) goto loop_cleanup;
998             code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
999                         if (code) {
1000                                 code = pkrb5_cc_close(ctx,cc);
1001                 cc = 0;
1002                 code = pkrb5_cc_close(ctx,oldcc);
1003                 cc = 0;
1004                                 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1005                                 continue;
1006                         }
1007             code = pkrb5_cc_close(ctx,oldcc);
1008         } else {
1009             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1010             if (code) goto loop_cleanup;
1011         }
1012
1013         flags = 0;  // turn off OPENCLOSE mode
1014         code = pkrb5_cc_set_flags(ctx, cc, flags);
1015         if ( code ) goto cleanup;
1016
1017         KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1018
1019         cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1020
1021         while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1022             krb5_data * sname = krb5_princ_name(ctx, creds.server);
1023             krb5_data * cell  = krb5_princ_component(ctx, creds.server, 1);
1024             krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1025             if ( sname && cell && !strcmp("afs",sname->data) ) {
1026                 struct ktc_principal    aserver;
1027                 struct ktc_principal    aclient;
1028                 struct ktc_token        atoken;
1029                 int active = TRUE;
1030
1031                 if ( IsDebuggerPresent() )  {
1032                     OutputDebugString("Found AFS ticket: ");
1033                     OutputDebugString(sname->data);
1034                     if ( cell->data ) {
1035                         OutputDebugString("/");
1036                         OutputDebugString(cell->data);
1037                     }
1038                     OutputDebugString("@");
1039                     OutputDebugString(realm->data);
1040                     OutputDebugString("\n");
1041                 }
1042
1043                 memset(&aserver, '\0', sizeof(aserver));
1044                 strcpy(aserver.name, sname->data);
1045                 strcpy(aserver.cell, cell->data);
1046
1047                 code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1048                 if (!code) {
1049                     // Found a token in AFS Client Server which matches
1050                     char pname[128], *p, *q;
1051                     for ( p=pname, q=aclient.name; *q; p++, q++)
1052                         *p = *q;
1053                     for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1054                         *p = toupper(*q);
1055                     *p = '\0';
1056
1057                     if ( IsDebuggerPresent() )  {
1058                         OutputDebugString("Found AFS token: ");
1059                         OutputDebugString(pname);
1060                         OutputDebugString("\n");
1061                     }
1062
1063                     if ( strcmp(pname,pNCi[i]->principal)  )
1064                         active = FALSE;
1065                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1066                 } else {
1067                     // Attempt to import it
1068                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1069
1070                     if ( IsDebuggerPresent() )  {
1071                         OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1072                     }
1073
1074                     code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime());
1075                     if ( IsDebuggerPresent() ) {
1076                         char message[256];
1077                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1078                         OutputDebugString(message);
1079                     }
1080                 }
1081             } else if ( IsDebuggerPresent() ) {
1082                 OutputDebugString("Found ticket: ");
1083                 OutputDebugString(sname->data);
1084                 if ( cell && cell->data ) {
1085                     OutputDebugString("/");
1086                     OutputDebugString(cell->data);
1087                 }
1088                 OutputDebugString("@");
1089                 OutputDebugString(realm->data);
1090                 OutputDebugString("\n");
1091             }
1092             pkrb5_free_cred_contents(ctx, &creds);
1093         }
1094
1095         if (cc_code == KRB5_CC_END) {
1096             cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1097             if (cc_code) goto loop_cleanup;
1098         }
1099
1100       loop_cleanup:
1101         flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
1102         code = pkrb5_cc_set_flags(ctx, cc, flags);
1103         if (cc) {
1104             pkrb5_cc_close(ctx,cc);
1105             cc = 0;
1106         }
1107     }
1108
1109   cleanup:
1110     if (principal)
1111         pkrb5_free_principal(ctx,principal);
1112     if (ctx)
1113         pkrb5_free_context(ctx);
1114     if (pNCi)
1115         pcc_free_NC_info(cc_ctx, &pNCi);
1116     if (cc_ctx)
1117         pcc_shutdown(&cc_ctx);
1118 }
1119
1120
1121 int
1122 KFW_AFS_get_cred(char * username, 
1123                   char * instance, 
1124                   char * cell,
1125                   char * password,
1126                   int lifetime,
1127                   char ** reasonP )
1128 {
1129     krb5_context ctx = 0;
1130     krb5_ccache cc = 0;
1131     char * realm = 0;
1132     char ** realmlist = 0;
1133     krb5_principal principal = 0;
1134     char * pname = 0;
1135     krb5_error_code code;
1136         char local_cell[MAXCELLCHARS+1];
1137     char **cells = NULL;
1138     int  cell_count=0;
1139     afsconf_cell cellconfig;
1140
1141     if ( IsDebuggerPresent() ) {
1142         OutputDebugString("KFW_AFS_get_cred for token ");
1143         OutputDebugString(username);
1144         if ( instance ) {
1145             OutputDebugString("/");
1146             OutputDebugString(instance);
1147         }
1148         OutputDebugString("@");
1149         OutputDebugString(cell);
1150         OutputDebugString("\n");
1151     }
1152
1153     code = pkrb5_init_context(&ctx);
1154     if ( code ) goto cleanup;
1155
1156     code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1157     if ( code ) goto cleanup;
1158
1159     realm = afs_realm_of_cell(&cellconfig);  // do not free
1160
1161     if ( IsDebuggerPresent() ) {
1162         OutputDebugString("Realm: ");
1163         OutputDebugString(realm);
1164         OutputDebugString("\n");
1165     }
1166
1167     code = pkrb5_build_principal(ctx, &principal, strlen(realm),
1168                                  realm, username, 
1169                                  (instance && instance[0]) ? instance : NULL, 
1170                                  NULL);
1171
1172     code = KFW_get_ccache(ctx, principal, &cc);
1173     if ( code ) goto cleanup;
1174
1175     code = pkrb5_unparse_name(ctx, principal, &pname);
1176     if ( code ) goto cleanup;
1177
1178     if ( lifetime == 0 )
1179         lifetime = pLeash_get_default_lifetime();
1180
1181     code = KFW_kinit(ctx, cc, HWND_DESKTOP, 
1182                       pname, 
1183                       password,
1184                       lifetime,
1185                       pLeash_get_default_forwardable(),
1186                       pLeash_get_default_proxiable(),
1187                       pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1188                       pLeash_get_default_noaddresses(),
1189                       pLeash_get_default_publicip());
1190     if ( IsDebuggerPresent() ) {
1191         char message[256];
1192         sprintf(message,"KFW_kinit() returns: %d\n",code);
1193         OutputDebugString(message);
1194     }
1195     if ( code ) goto cleanup;
1196                    
1197     KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1198
1199     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime);
1200     if ( IsDebuggerPresent() ) {
1201         char message[256];
1202         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1203         OutputDebugString(message);
1204     }
1205     if ( code ) goto cleanup;
1206
1207     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1208
1209     // Attempt to obtain new tokens for other cells supported by the same 
1210     // principal
1211     cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1212     if ( cell_count > 1 ) {
1213         while ( cell_count-- ) {
1214             if ( strcmp(cells[cell_count],cell) ) {
1215                 if ( IsDebuggerPresent() ) {
1216                     char message[256];
1217                     sprintf(message,"found another cell for the same principal: %s\n",cell);
1218                     OutputDebugString(message);
1219                 }
1220                 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1221                 if ( code ) continue;
1222     
1223                 realm = afs_realm_of_cell(&cellconfig);  // do not free
1224                 if ( IsDebuggerPresent() ) {
1225                     OutputDebugString("Realm: ");
1226                     OutputDebugString(realm);
1227                     OutputDebugString("\n");
1228                 }
1229                 
1230                 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime);
1231                 if ( IsDebuggerPresent() ) {
1232                     char message[256];
1233                     sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1234                     OutputDebugString(message);
1235                 }
1236             }
1237             free(cells[cell_count]);
1238         }
1239         free(cells);
1240     } else if ( cell_count == 1 ) {
1241         free(cells[0]);
1242         free(cells);
1243     }
1244
1245   cleanup:
1246     if ( pname )
1247         pkrb5_free_unparsed_name(ctx,pname);
1248     if ( cc )
1249         pkrb5_cc_close(ctx, cc);
1250
1251     if ( code && reasonP ) {
1252         *reasonP = (char *)perror_message(code);
1253     }
1254     return(code);
1255 }
1256
1257 int 
1258 KFW_AFS_destroy_tickets_for_cell(char * cell)
1259 {
1260     krb5_context                ctx = 0;
1261     krb5_error_code             code;
1262     int count;
1263     char ** principals = NULL;
1264
1265     if ( IsDebuggerPresent() ) {
1266         OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
1267         OutputDebugString(cell);
1268         OutputDebugString("\n");
1269     }
1270
1271     code = pkrb5_init_context(&ctx);
1272     if (code) ctx = 0;
1273
1274     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1275     if ( count > 0 ) {
1276         krb5_principal      princ = 0;
1277         krb5_ccache                     cc  = 0;
1278
1279         while ( count-- ) {
1280             int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1281             if ( cell_count > 1 ) {
1282                 // TODO - What we really should do here is verify whether or not any of the
1283                 // other cells which use this principal to obtain its credentials actually
1284                 // have valid tokens or not.  If they are currently using these credentials
1285                 // we will skip them.  For the time being we assume that if there is an active
1286                 // map in the table that they are actively being used.
1287                 goto loop_cleanup;
1288             }
1289
1290             code = pkrb5_parse_name(ctx, principals[count], &princ);
1291             if (code) goto loop_cleanup;
1292
1293             code = KFW_get_ccache(ctx, princ, &cc);
1294             if (code) goto loop_cleanup;
1295
1296             code = pkrb5_cc_destroy(ctx, cc);
1297             if (!code) cc = 0;
1298
1299           loop_cleanup:
1300             if ( cc ) {
1301                 pkrb5_cc_close(ctx, cc);
1302                 cc = 0;
1303             }
1304             if ( princ ) {
1305                 pkrb5_free_principal(ctx, princ);
1306                 princ = 0;
1307             }
1308
1309             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1310             free(principals[count]);
1311         }
1312         free(principals);
1313     }
1314     pkrb5_free_context(ctx);
1315     return 0;
1316 }
1317
1318 int
1319 KFW_AFS_renew_expiring_credentials(void)
1320 {
1321     krb5_error_code                     code = 0;
1322     krb5_context                        ctx = 0;
1323     krb5_ccache                         cc = 0;
1324     krb5_timestamp now;
1325     struct principal_ccache_data * pcc_next = princ_cc_data;
1326     int cell_count;
1327     char ** cells=NULL;
1328     const char * realm = NULL;
1329     char local_cell[MAXCELLCHARS+1]="";
1330     afsconf_cell cellconfig;
1331
1332     if ( pcc_next == NULL ) // nothing to do
1333         return 0;
1334
1335     if ( IsDebuggerPresent() ) {
1336         OutputDebugString("KFW_AFS_renew_expiring_credentials\n");
1337     }
1338
1339     code = pkrb5_init_context(&ctx);
1340     if (code) goto cleanup;
1341
1342     code = pkrb5_timeofday(ctx, &now);
1343     if (code) goto cleanup; 
1344
1345     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1346         if ( pcc_next->expired ) 
1347             continue;
1348
1349         if ( now >= (pcc_next->expiration_time) ) {
1350             if ( !pcc_next->from_lsa ) {
1351                 pcc_next->expired = 1;
1352                 continue;
1353             }
1354         }
1355
1356         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1357             code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1358             if ( code ) 
1359                                 goto loop_cleanup;
1360             code = KFW_renew(ctx,cc);
1361 #ifdef USE_MS2MIT
1362             if ( code && pcc_next->from_lsa)
1363                 goto loop_cleanup;
1364 #endif /* USE_MS2MIT */
1365
1366
1367             KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1368             if (code) goto loop_cleanup;
1369
1370             // Attempt to obtain new tokens for other cells supported by the same 
1371             // principal
1372             cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1373             if ( cell_count > 0 ) {
1374                 while ( cell_count-- ) {
1375                     if ( IsDebuggerPresent() ) {
1376                         OutputDebugString("Cell: ");
1377                         OutputDebugString(cells[cell_count]);
1378                         OutputDebugString("\n");
1379                     }
1380                     code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1381                     if ( code ) continue;
1382                     realm = afs_realm_of_cell(&cellconfig);  // do not free
1383                     if ( IsDebuggerPresent() ) {
1384                         OutputDebugString("Realm: ");
1385                         OutputDebugString(realm);
1386                         OutputDebugString("\n");
1387                     }
1388                     code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime());
1389                     if ( IsDebuggerPresent() ) {
1390                         char message[256];
1391                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1392                         OutputDebugString(message);
1393                     }
1394                     free(cells[cell_count]);
1395                 }
1396                 free(cells);
1397             }
1398         }
1399
1400       loop_cleanup:
1401         if ( cc ) {
1402             pkrb5_cc_close(ctx,cc);
1403             cc = 0;
1404         }
1405     }
1406
1407   cleanup:
1408     if ( cc )
1409         pkrb5_cc_close(ctx,cc);
1410     if ( ctx )
1411         pkrb5_free_context(ctx);
1412
1413     return 0;
1414 }
1415
1416
1417 BOOL
1418 KFW_AFS_renew_token_for_cell(char * cell)
1419 {
1420     krb5_error_code                     code = 0;
1421     krb5_context                        ctx = 0;
1422     int count;
1423     char ** principals = NULL;
1424
1425     if ( IsDebuggerPresent() ) {
1426         OutputDebugString("KFW_AFS_renew_token_for_cell:");
1427         OutputDebugString(cell);
1428         OutputDebugString("\n");
1429     }
1430
1431     code = pkrb5_init_context(&ctx);
1432     if (code) goto cleanup;
1433
1434     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1435     if ( count > 0 ) {
1436         krb5_principal      princ = 0;
1437         krb5_principal      service = 0;
1438         krb5_creds          mcreds, creds;
1439         krb5_ccache                     cc  = 0;
1440         const char * realm = NULL;
1441         afsconf_cell cellconfig;
1442         char local_cell[MAXCELLCHARS+1];
1443
1444         while ( count-- ) {
1445             code = pkrb5_parse_name(ctx, principals[count], &princ);
1446             if (code) goto loop_cleanup;
1447
1448             code = KFW_get_ccache(ctx, princ, &cc);
1449             if (code) goto loop_cleanup;
1450
1451             code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1452             if ( code ) goto loop_cleanup;
1453
1454             realm = afs_realm_of_cell(&cellconfig);  // do not free
1455             if ( IsDebuggerPresent() ) {
1456                 OutputDebugString("Realm: ");
1457                 OutputDebugString(realm);
1458                 OutputDebugString("\n");
1459             }
1460
1461             code = pkrb5_build_principal(ctx, &service, strlen(realm),
1462                                           realm, "afs", cell, NULL);
1463             if (!code) {
1464                 memset(&mcreds, 0, sizeof(krb5_creds));
1465                 mcreds.client = princ;
1466                 mcreds.server = service;
1467
1468                 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1469                 if (!code) {
1470                     if ( IsDebuggerPresent() ) {
1471                         char * cname, *sname;
1472                         pkrb5_unparse_name(ctx, creds.client, &cname);
1473                         pkrb5_unparse_name(ctx, creds.server, &sname);
1474                         OutputDebugString("Removing credential for client \"");
1475                         OutputDebugString(cname);
1476                         OutputDebugString("\" and service \"");
1477                         OutputDebugString(sname);
1478                         OutputDebugString("\"\n");
1479                         pkrb5_free_unparsed_name(ctx,cname);
1480                         pkrb5_free_unparsed_name(ctx,sname);
1481                     }
1482
1483                     code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1484                     pkrb5_free_principal(ctx, creds.client);
1485                     pkrb5_free_principal(ctx, creds.server);
1486                 }
1487             }
1488             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime());
1489             if ( IsDebuggerPresent() ) {
1490                 char message[256];
1491                 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1492                 OutputDebugString(message);
1493             }
1494
1495           loop_cleanup:
1496             if (cc) {
1497                 pkrb5_cc_close(ctx, cc);
1498                 cc = 0;
1499             }
1500             if (princ) {
1501                 pkrb5_free_principal(ctx, princ);
1502                 princ = 0;
1503             }
1504             if (service) {
1505                 pkrb5_free_principal(ctx, service);
1506                 princ = 0;
1507             }
1508
1509             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1510             free(principals[count]);
1511         }
1512         free(principals);
1513     } else
1514         code = -1;      // we did not renew the tokens 
1515
1516   cleanup:
1517     pkrb5_free_context(ctx);
1518     return (code ? FALSE : TRUE);
1519
1520 }
1521
1522 int
1523 KFW_AFS_renew_tokens_for_all_cells(void)
1524 {
1525     struct cell_principal_map * next = cell_princ_map;
1526
1527     if ( IsDebuggerPresent() )
1528         OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1529
1530     if ( !next )
1531         return 0;
1532
1533     for ( ; next ; next = next->next ) {
1534         if ( next->active )
1535             KFW_AFS_renew_token_for_cell(next->cell);
1536     }
1537     return 0;
1538 }
1539
1540 int
1541 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1542 {
1543     krb5_error_code                     code = 0;
1544     krb5_context                        ctx = 0;
1545     krb5_ccache                         cc = 0;
1546     krb5_principal                      me = 0;
1547     krb5_principal              server = 0;
1548     krb5_creds                          my_creds;
1549     krb5_data                   *realm = 0;
1550
1551         memset(&my_creds, 0, sizeof(krb5_creds));
1552
1553     if ( alt_ctx ) {
1554         ctx = alt_ctx;
1555     } else {
1556         code = pkrb5_init_context(&ctx);
1557         if (code) goto cleanup;
1558     }
1559
1560     if ( alt_cc ) {
1561         cc = alt_cc;
1562     } else {
1563         code = pkrb5_cc_default(ctx, &cc);
1564         if (code) goto cleanup;
1565     }
1566
1567     code = pkrb5_cc_get_principal(ctx, cc, &me);
1568     if (code) goto cleanup;
1569
1570     realm = krb5_princ_realm(ctx, me);
1571
1572     code = pkrb5_build_principal_ext(ctx, &server,
1573                                     realm->length,realm->data,
1574                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1575                                     realm->length,realm->data,
1576                                     0);
1577     if ( code ) 
1578         goto cleanup;
1579
1580     if ( IsDebuggerPresent() ) {
1581         char * cname, *sname;
1582         pkrb5_unparse_name(ctx, me, &cname);
1583         pkrb5_unparse_name(ctx, server, &sname);
1584         OutputDebugString("Renewing credential for client \"");
1585         OutputDebugString(cname);
1586         OutputDebugString("\" and service \"");
1587         OutputDebugString(sname);
1588         OutputDebugString("\"\n");
1589         pkrb5_free_unparsed_name(ctx,cname);
1590         pkrb5_free_unparsed_name(ctx,sname);
1591     }
1592
1593     my_creds.client = me;
1594     my_creds.server = server;
1595
1596     code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1597     if (code) {
1598         if ( IsDebuggerPresent() ) {
1599             char message[256];
1600             sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1601             OutputDebugString(message);
1602         }
1603         goto cleanup;
1604     }
1605
1606     code = pkrb5_cc_initialize(ctx, cc, me);
1607     if (code) {
1608         if ( IsDebuggerPresent() ) {
1609             char message[256];
1610             sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1611             OutputDebugString(message);
1612         }
1613         goto cleanup;
1614     }
1615
1616     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1617     if (code) {
1618         if ( IsDebuggerPresent() ) {
1619             char message[256];
1620             sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1621             OutputDebugString(message);
1622         }
1623         goto cleanup;
1624     }
1625
1626   cleanup:
1627     if (my_creds.client == me)
1628         my_creds.client = 0;
1629     if (my_creds.server == server)
1630         my_creds.server = 0;
1631     pkrb5_free_cred_contents(ctx, &my_creds);
1632     if (me)
1633         pkrb5_free_principal(ctx, me);
1634     if (server)
1635         pkrb5_free_principal(ctx, server);
1636     if (cc && (cc != alt_cc))
1637         pkrb5_cc_close(ctx, cc);
1638     if (ctx && (ctx != alt_ctx))
1639         pkrb5_free_context(ctx);
1640     return(code);
1641 }
1642
1643 int
1644 KFW_kinit( krb5_context alt_ctx,
1645             krb5_ccache  alt_cc,
1646             HWND hParent,
1647             char *principal_name,
1648             char *password,
1649             krb5_deltat lifetime,
1650             DWORD                       forwardable,
1651             DWORD                       proxiable,
1652             krb5_deltat                 renew_life,
1653             DWORD                       addressless,
1654             DWORD                       publicIP
1655             )
1656 {
1657     krb5_error_code                     code = 0;
1658     krb5_context                        ctx = 0;
1659     krb5_ccache                         cc = 0;
1660     krb5_principal                      me = 0;
1661     char*                       name = 0;
1662     krb5_creds                          my_creds;
1663     krb5_get_init_creds_opt     options;
1664     krb5_address **             addrs = NULL;
1665     int                         i = 0, addr_count = 0;
1666
1667     if (!pkrb5_init_context)
1668         return 0;
1669
1670     pkrb5_get_init_creds_opt_init(&options);
1671     memset(&my_creds, 0, sizeof(my_creds));
1672
1673     if (alt_ctx)
1674     {
1675         ctx = alt_ctx;
1676     }
1677     else
1678     {
1679         code = pkrb5_init_context(&ctx);
1680         if (code) goto cleanup;
1681     }
1682
1683     if ( alt_cc ) {
1684         cc = alt_cc;
1685     } else {
1686         code = pkrb5_cc_default(ctx, &cc);  
1687         if (code) goto cleanup;
1688     }
1689
1690     code = pkrb5_parse_name(ctx, principal_name, &me);
1691     if (code) 
1692                 goto cleanup;
1693
1694     code = pkrb5_unparse_name(ctx, me, &name);
1695     if (code) 
1696                 goto cleanup;
1697
1698     if (lifetime == 0)
1699         lifetime = pLeash_get_default_lifetime();
1700     else
1701         lifetime *= 5*60;
1702
1703         if (renew_life > 0)
1704                 renew_life *= 5*60;
1705
1706     if (lifetime)
1707         pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1708         pkrb5_get_init_creds_opt_set_forwardable(&options,
1709                                                  forwardable ? 1 : 0);
1710         pkrb5_get_init_creds_opt_set_proxiable(&options,
1711                                                proxiable ? 1 : 0);
1712         pkrb5_get_init_creds_opt_set_renew_life(&options,
1713                                                renew_life);
1714     if (addressless)
1715         pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1716     else {
1717                 if (publicIP)
1718         {
1719             // we are going to add the public IP address specified by the user
1720             // to the list provided by the operating system
1721             krb5_address ** local_addrs=NULL;
1722             DWORD           netIPAddr;
1723
1724             pkrb5_os_localaddr(ctx, &local_addrs);
1725             while ( local_addrs[i++] );
1726             addr_count = i + 1;
1727
1728             addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1729             if ( !addrs ) {
1730                 pkrb5_free_addresses(ctx, local_addrs);
1731                 goto cleanup;
1732             }
1733             memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1734             i = 0;
1735             while ( local_addrs[i] ) {
1736                 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1737                 if (addrs[i] == NULL) {
1738                     pkrb5_free_addresses(ctx, local_addrs);
1739                     goto cleanup;
1740                 }
1741
1742                 addrs[i]->magic = local_addrs[i]->magic;
1743                 addrs[i]->addrtype = local_addrs[i]->addrtype;
1744                 addrs[i]->length = local_addrs[i]->length;
1745                 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1746                 if (!addrs[i]->contents) {
1747                     pkrb5_free_addresses(ctx, local_addrs);
1748                     goto cleanup;
1749                 }
1750
1751                 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1752                         local_addrs[i]->length);        /* safe */
1753                 i++;
1754             }
1755             pkrb5_free_addresses(ctx, local_addrs);
1756
1757             addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1758             if (addrs[i] == NULL)
1759                 goto cleanup;
1760
1761             addrs[i]->magic = KV5M_ADDRESS;
1762             addrs[i]->addrtype = AF_INET;
1763             addrs[i]->length = 4;
1764             addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1765             if (!addrs[i]->contents)
1766                 goto cleanup;
1767
1768             netIPAddr = htonl(publicIP);
1769             memcpy(addrs[i]->contents,&netIPAddr,4);
1770         
1771             pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1772
1773         }
1774     }
1775
1776     code = pkrb5_get_init_creds_password(ctx, 
1777                                        &my_creds, 
1778                                        me,
1779                                        password, // password
1780                                        KRB5_prompter, // prompter
1781                                        hParent, // prompter data
1782                                        0, // start time
1783                                        0, // service name
1784                                        &options);
1785     if (code) 
1786                 goto cleanup;
1787
1788     code = pkrb5_cc_initialize(ctx, cc, me);
1789     if (code) 
1790                 goto cleanup;
1791
1792     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1793     if (code) 
1794                 goto cleanup;
1795
1796  cleanup:
1797     if ( addrs ) {
1798         for ( i=0;i<addr_count;i++ ) {
1799             if ( addrs[i] ) {
1800                 if ( addrs[i]->contents )
1801                     free(addrs[i]->contents);
1802                 free(addrs[i]);
1803             }
1804         }
1805     }
1806     if (my_creds.client == me)
1807         my_creds.client = 0;
1808     pkrb5_free_cred_contents(ctx, &my_creds);
1809     if (name)
1810         pkrb5_free_unparsed_name(ctx, name);
1811     if (me)
1812         pkrb5_free_principal(ctx, me);
1813     if (cc && (cc != alt_cc))
1814         pkrb5_cc_close(ctx, cc);
1815     if (ctx && (ctx != alt_ctx))
1816         pkrb5_free_context(ctx);
1817     return(code);
1818 }
1819
1820
1821 int
1822 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
1823 {
1824     krb5_context                ctx;
1825     krb5_ccache                 cc;
1826     krb5_error_code             code;
1827
1828     if (alt_ctx)
1829     {
1830         ctx = alt_ctx;
1831     }
1832     else
1833     {
1834         code = pkrb5_init_context(&ctx);
1835         if (code) goto cleanup;
1836     }
1837
1838     if ( alt_cc ) {
1839         cc = alt_cc;
1840     } else {
1841         code = pkrb5_cc_default(ctx, &cc);  
1842         if (code) goto cleanup;
1843     }
1844
1845     code = pkrb5_cc_destroy(ctx, cc);
1846     if ( !code ) cc = 0;
1847
1848   cleanup:
1849     if (cc && (cc != alt_cc))
1850         pkrb5_cc_close(ctx, cc);
1851     if (ctx && (ctx != alt_ctx))
1852         pkrb5_free_context(ctx);
1853
1854     return(code);
1855 }
1856
1857
1858 #ifdef USE_MS2MIT
1859 static BOOL
1860 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1861 {
1862     NTSTATUS Status = 0;
1863     HANDLE  TokenHandle;
1864     TOKEN_STATISTICS Stats;
1865     DWORD   ReqLen;
1866     BOOL    Success;
1867
1868     if (!ppSessionData)
1869         return FALSE;
1870     *ppSessionData = NULL;
1871
1872     Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1873     if ( !Success )
1874         return FALSE;
1875
1876     Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1877     CloseHandle( TokenHandle );
1878     if ( !Success )
1879         return FALSE;
1880
1881     Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1882     if ( FAILED(Status) || !ppSessionData )
1883         return FALSE;
1884
1885     return TRUE;
1886 }
1887
1888 //
1889 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the 
1890 // cache.  It validates whether or not it is reasonable to assume that if we 
1891 // attempted to retrieve valid tickets we could do so.  Microsoft does not 
1892 // automatically renew expired tickets.  Therefore, the cache could contain
1893 // expired or invalid tickets.  Microsoft also caches the user's password 
1894 // and will use it to retrieve new TGTs if the cache is empty and tickets
1895 // are requested.
1896
1897 static BOOL
1898 MSLSA_IsKerberosLogon(VOID)
1899 {
1900     PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1901     BOOL    Success = FALSE;
1902
1903     if ( GetSecurityLogonSessionData(&pSessionData) ) {
1904         if ( pSessionData->AuthenticationPackage.Buffer ) {
1905             WCHAR buffer[256];
1906             WCHAR *usBuffer;
1907             int usLength;
1908
1909             Success = FALSE;
1910             usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1911             usLength = (pSessionData->AuthenticationPackage).Length;
1912             if (usLength < 256)
1913             {
1914                 lstrcpynW (buffer, usBuffer, usLength);
1915                 lstrcatW (buffer,L"");
1916                 if ( !lstrcmpW(L"Kerberos",buffer) )
1917                     Success = TRUE;
1918             }
1919         }
1920         pLsaFreeReturnBuffer(pSessionData);
1921     }
1922     return Success;
1923 }
1924 #endif /* USE_MS2MIT */
1925
1926 static BOOL CALLBACK 
1927 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1928 {
1929     int i;
1930
1931     switch ( message ) {
1932     case WM_INITDIALOG:
1933         if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1934         {
1935             SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1936             return FALSE;
1937         }
1938                 for ( i=0; i < mid_cnt ; i++ ) {
1939                         if (mid_tb[i].echo == 0)
1940                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1941                     else if (mid_tb[i].echo == 2) 
1942                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1943                 }
1944         return TRUE;
1945
1946     case WM_COMMAND:
1947         switch ( LOWORD(wParam) ) {
1948         case IDOK:
1949             for ( i=0; i < mid_cnt ; i++ ) {
1950                 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1951                     *mid_tb[i].buf = '\0';
1952             }
1953             /* fallthrough */
1954         case IDCANCEL:
1955             EndDialog(hDialog, LOWORD(wParam));
1956             return TRUE;
1957         }
1958     }
1959     return FALSE;
1960 }
1961
1962 static LPWORD 
1963 lpwAlign( LPWORD lpIn )
1964 {
1965     ULONG ul;
1966
1967     ul = (ULONG) lpIn;
1968     ul += 3;
1969     ul >>=2;
1970     ul <<=2;
1971     return (LPWORD) ul;;
1972 }
1973
1974 /*
1975  * dialog widths are measured in 1/4 character widths
1976  * dialog height are measured in 1/8 character heights
1977  */
1978
1979 static LRESULT
1980 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 
1981                   char * ptext[], int numlines, int width, 
1982                   int tb_cnt, struct textField * tb)
1983 {
1984     HGLOBAL hgbl;
1985     LPDLGTEMPLATE lpdt;
1986     LPDLGITEMTEMPLATE lpdit;
1987     LPWORD lpw;
1988     LPWSTR lpwsz;
1989     LRESULT ret;
1990     int nchar, i, pwid;
1991
1992     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
1993     if (!hgbl)
1994         return -1;
1995  
1996     mid_cnt = tb_cnt;
1997     mid_tb = tb;
1998
1999     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2000  
2001     // Define a dialog box.
2002  
2003     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2004                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
2005                    | DS_SETFOREGROUND | DS_3DLOOK
2006                    | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2007     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
2008     lpdt->x  = 10;  
2009     lpdt->y  = 10;
2010     lpdt->cx = 20 + width * 4; 
2011     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2012
2013     lpw = (LPWORD) (lpdt + 1);
2014     *lpw++ = 0;   // no menu
2015     *lpw++ = 0;   // predefined dialog box class (by default)
2016
2017     lpwsz = (LPWSTR) lpw;
2018     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2019     lpw   += nchar;
2020     *lpw++ = 8;                        // font size (points)
2021     lpwsz = (LPWSTR) lpw;
2022     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
2023                                     -1, lpwsz, 128);
2024     lpw   += nchar;
2025
2026     //-----------------------
2027     // Define an OK button.
2028     //-----------------------
2029     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2030     lpdit = (LPDLGITEMTEMPLATE) lpw;
2031     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2032     lpdit->dwExtendedStyle = 0;
2033     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
2034     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2035     lpdit->cx = 40; 
2036     lpdit->cy = 14;
2037     lpdit->id = IDOK;  // OK button identifier
2038
2039     lpw = (LPWORD) (lpdit + 1);
2040     *lpw++ = 0xFFFF;
2041     *lpw++ = 0x0080;    // button class
2042
2043     lpwsz = (LPWSTR) lpw;
2044     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2045     lpw   += nchar;
2046     *lpw++ = 0;           // no creation data
2047
2048     //-----------------------
2049     // Define an Cancel button.
2050     //-----------------------
2051     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2052     lpdit = (LPDLGITEMTEMPLATE) lpw;
2053     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2054     lpdit->dwExtendedStyle = 0;
2055     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
2056     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2057     lpdit->cx = 40; 
2058     lpdit->cy = 14;
2059     lpdit->id = IDCANCEL;  // CANCEL button identifier
2060
2061     lpw = (LPWORD) (lpdit + 1);
2062     *lpw++ = 0xFFFF;
2063     *lpw++ = 0x0080;    // button class
2064
2065     lpwsz = (LPWSTR) lpw;
2066     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2067     lpw   += nchar;
2068     *lpw++ = 0;           // no creation data
2069
2070     /* Add controls for preface data */
2071     for ( i=0; i<numlines; i++) {
2072         /*-----------------------
2073          * Define a static text control.
2074          *-----------------------*/
2075         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2076         lpdit = (LPDLGITEMTEMPLATE) lpw;
2077         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2078         lpdit->dwExtendedStyle = 0;
2079         lpdit->x  = 10; 
2080         lpdit->y  = 10 + i * 14;
2081         lpdit->cx = strlen(ptext[i]) * 4 + 10; 
2082         lpdit->cy = 14;
2083         lpdit->id = ID_TEXT + i;  // text identifier
2084
2085         lpw = (LPWORD) (lpdit + 1);
2086         *lpw++ = 0xFFFF;
2087         *lpw++ = 0x0082;                         // static class
2088
2089         lpwsz = (LPWSTR) lpw;
2090         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
2091                                          -1, lpwsz, 2*width);
2092         lpw   += nchar;
2093         *lpw++ = 0;           // no creation data
2094     }
2095     
2096     for ( i=0, pwid = 0; i<tb_cnt; i++) {
2097         if ( pwid < strlen(tb[i].label) )
2098             pwid = strlen(tb[i].label);
2099     }
2100
2101     for ( i=0; i<tb_cnt; i++) {
2102         /* Prompt */
2103         /*-----------------------
2104          * Define a static text control.
2105          *-----------------------*/
2106         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2107         lpdit = (LPDLGITEMTEMPLATE) lpw;
2108         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2109         lpdit->dwExtendedStyle = 0;
2110         lpdit->x  = 10; 
2111         lpdit->y  = 10 + (numlines + i + 1) * 14;
2112         lpdit->cx = pwid * 4; 
2113         lpdit->cy = 14;
2114         lpdit->id = ID_TEXT + numlines + i;  // text identifier
2115
2116         lpw = (LPWORD) (lpdit + 1);
2117         *lpw++ = 0xFFFF;
2118         *lpw++ = 0x0082;                         // static class
2119
2120         lpwsz = (LPWSTR) lpw;
2121         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 
2122                                      -1, lpwsz, 128);
2123         lpw   += nchar;
2124         *lpw++ = 0;           // no creation data
2125
2126         /*-----------------------
2127          * Define an edit control.
2128          *-----------------------*/
2129         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2130         lpdit = (LPDLGITEMTEMPLATE) lpw;
2131         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2132         lpdit->dwExtendedStyle = 0;
2133         lpdit->x  = 10 + (pwid + 1) * 4; 
2134         lpdit->y  = 10 + (numlines + i + 1) * 14;
2135         lpdit->cx = (width - (pwid + 1)) * 4; 
2136         lpdit->cy = 14;
2137         lpdit->id = ID_MID_TEXT + i;             // identifier
2138
2139         lpw = (LPWORD) (lpdit + 1);
2140         *lpw++ = 0xFFFF;
2141         *lpw++ = 0x0081;                         // edit class
2142
2143         lpwsz = (LPWSTR) lpw;
2144         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 
2145                                      -1, lpwsz, 128);
2146         lpw   += nchar;
2147         *lpw++ = 0;           // no creation data
2148     }
2149
2150     GlobalUnlock(hgbl); 
2151     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
2152                                                         hwndOwner, (DLGPROC) MultiInputDialogProc); 
2153     GlobalFree(hgbl); 
2154
2155     switch ( ret ) {
2156     case 0:     /* Timeout */
2157         return -1;
2158     case IDOK:
2159         return 1;
2160     case IDCANCEL:
2161         return 0;
2162     default: {
2163         char buf[256];
2164         sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2165         MessageBox(hwndOwner,
2166                     buf,
2167                     "GetLastError()",
2168                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2169         return -1;
2170     }
2171     }
2172 }
2173
2174 static int
2175 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2176 {
2177         HINSTANCE hInst = 0;
2178     int maxwidth = 0;
2179     int numlines = 0;
2180     int len;
2181     char * plines[16], *p = preface ? preface : "";
2182     int i;
2183
2184     for ( i=0; i<16; i++ ) 
2185         plines[i] = NULL;
2186
2187     while (*p && numlines < 16) {
2188         plines[numlines++] = p;
2189         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2190         if ( *p == '\r' && *(p+1) == '\n' ) {
2191             *p++ = '\0';
2192             p++;
2193         } else if ( *p == '\n' ) {
2194             *p++ = '\0';
2195         } 
2196         if ( strlen(plines[numlines-1]) > maxwidth )
2197             maxwidth = strlen(plines[numlines-1]);
2198     }
2199
2200     for ( i=0;i<n;i++ ) {
2201         len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2202         if ( maxwidth < len )
2203             maxwidth = len;
2204     }
2205
2206     return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2207 }
2208
2209 static krb5_error_code KRB5_CALLCONV
2210 KRB5_prompter( krb5_context context,
2211                void *data,
2212                const char *name,
2213                const char *banner,
2214                int num_prompts,
2215                krb5_prompt prompts[])
2216 {
2217     krb5_error_code     errcode = 0;
2218     int                 i;
2219     struct textField * tb = NULL;
2220     int    len = 0, blen=0, nlen=0;
2221         HWND hParent = (HWND)data;
2222
2223     if (name)
2224         nlen = strlen(name)+2;
2225
2226     if (banner)
2227         blen = strlen(banner)+2;
2228
2229     tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2230     if ( tb != NULL ) {
2231         int ok;
2232         memset(tb,0,sizeof(struct textField) * num_prompts);
2233         for ( i=0; i < num_prompts; i++ ) {
2234             tb[i].buf = prompts[i].reply->data;
2235             tb[i].len = prompts[i].reply->length;
2236             tb[i].label = prompts[i].prompt;
2237             tb[i].def = NULL;
2238             tb[i].echo = (prompts[i].hidden ? 2 : 1);
2239         }   
2240
2241         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2242         if ( ok ) {
2243             for ( i=0; i < num_prompts; i++ )
2244                 prompts[i].reply->length = strlen(prompts[i].reply->data);
2245         } else
2246             errcode = -2;
2247     }
2248
2249     if ( tb )
2250         free(tb);
2251     if (errcode) {
2252         for (i = 0; i < num_prompts; i++) {
2253             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2254         }
2255     }
2256     return errcode;
2257 }
2258
2259 BOOL
2260 KFW_AFS_wait_for_service_start(void)
2261 {
2262     char    HostName[64];
2263     DWORD   CurrentState;
2264
2265     CurrentState = SERVICE_START_PENDING;
2266     memset(HostName, '\0', sizeof(HostName));
2267     gethostname(HostName, sizeof(HostName));
2268
2269     while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2270     {
2271         if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2272             return(0);
2273         if ( IsDebuggerPresent() ) {
2274             switch ( CurrentState ) {
2275             case SERVICE_STOPPED:
2276                 OutputDebugString("SERVICE_STOPPED\n");
2277                 break;
2278             case SERVICE_START_PENDING:
2279                 OutputDebugString("SERVICE_START_PENDING\n");
2280                 break;
2281             case SERVICE_STOP_PENDING:
2282                 OutputDebugString("SERVICE_STOP_PENDING\n");
2283                 break;
2284             case SERVICE_RUNNING:
2285                 OutputDebugString("SERVICE_RUNNING\n");
2286                 break;
2287             case SERVICE_CONTINUE_PENDING:
2288                 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2289                 break;
2290             case SERVICE_PAUSE_PENDING:
2291                 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2292                 break;
2293             case SERVICE_PAUSED:
2294                 OutputDebugString("SERVICE_PAUSED\n");
2295                 break;
2296             default:
2297                 OutputDebugString("UNKNOWN Service State\n");
2298             }
2299         }
2300         if (CurrentState == SERVICE_STOPPED)
2301             return(0);
2302         if (CurrentState == SERVICE_RUNNING)
2303             return(1);
2304         Sleep(500);
2305     }
2306     return(0);
2307 }
2308
2309
2310 int
2311 KFW_AFS_unlog(void)
2312 {
2313     long        rc;
2314     char    HostName[64];
2315     DWORD   CurrentState;
2316
2317     CurrentState = 0;
2318     memset(HostName, '\0', sizeof(HostName));
2319     gethostname(HostName, sizeof(HostName));
2320     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2321         return(0);
2322     if (CurrentState != SERVICE_RUNNING)
2323         return(0);
2324
2325     rc = pktc_ForgetAllTokens();
2326
2327     return(0);
2328 }
2329
2330 int
2331 KFW_AFS_klog(
2332     krb5_context alt_ctx,
2333     krb5_ccache  alt_cc,
2334     char *service,
2335     char *cell,
2336     char *realm,
2337     int LifeTime
2338     )
2339 {
2340     long        rc = 0;
2341     CREDENTIALS creds;
2342     KTEXT_ST    ticket;
2343     struct ktc_principal        aserver;
2344     struct ktc_principal        aclient;
2345     char        username[BUFSIZ];       /* To hold client username structure */
2346     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2347     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2348     char        local_cell[MAXCELLCHARS+1];
2349     char        Dmycell[MAXCELLCHARS+1];
2350     struct ktc_token    atoken;
2351     struct ktc_token    btoken;
2352     afsconf_cell        ak_cellconfig; /* General information about the cell */
2353     char        RealmName[128];
2354     char        CellName[128];
2355     char        ServiceName[128];
2356     DWORD       CurrentState;
2357     char        HostName[64];
2358     BOOL        try_krb5 = 0;
2359     krb5_context  ctx = 0;
2360     krb5_ccache   cc = 0;
2361     krb5_creds increds;
2362     krb5_creds * k5creds = 0;
2363     krb5_error_code code;
2364     krb5_principal client_principal = 0;
2365     int i, retry = 0;
2366
2367     CurrentState = 0;
2368     memset(HostName, '\0', sizeof(HostName));
2369     gethostname(HostName, sizeof(HostName));
2370     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2371         if ( IsDebuggerPresent() )
2372             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2373         return(-1);
2374     }
2375     if (CurrentState != SERVICE_RUNNING) {
2376         if ( IsDebuggerPresent() )
2377             OutputDebugString("AFSD Service NOT RUNNING\n");
2378         return(-2);
2379     }
2380
2381     memset(RealmName, '\0', sizeof(RealmName));
2382     memset(CellName, '\0', sizeof(CellName));
2383     memset(ServiceName, '\0', sizeof(ServiceName));
2384     memset(realm_of_user, '\0', sizeof(realm_of_user));
2385     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2386         if (cell && cell[0])
2387                 strcpy(Dmycell, cell);
2388         else
2389                 memset(Dmycell, '\0', sizeof(Dmycell));
2390
2391     // NULL or empty cell returns information on local cell
2392     if (rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2393     {
2394                 KFW_AFS_error(rc, "get_cellconfig()");
2395         return(rc);
2396     }
2397
2398     if ( alt_ctx ) {
2399         ctx = alt_ctx;
2400     } else {
2401         code = pkrb5_init_context(&ctx);
2402         if (code) goto cleanup;
2403     }
2404
2405     if ( alt_cc ) {
2406         cc = alt_cc;
2407     } else {
2408         code = pkrb5_cc_default(ctx, &cc);
2409         if (code) goto skip_krb5_init;
2410     }
2411
2412     memset((char *)&increds, 0, sizeof(increds));
2413
2414     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2415         if (code) {
2416         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
2417         {
2418             OutputDebugString("Principal Not Found for ccache\n");
2419         }
2420         goto skip_krb5_init;
2421     }
2422     i = krb5_princ_realm(ctx, client_principal)->length;
2423     if (i > REALM_SZ-1) 
2424         i = REALM_SZ-1;
2425     strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2426     realm_of_user[i] = 0;
2427     try_krb5 = 1;
2428
2429   skip_krb5_init:
2430 #ifdef USE_KRB4
2431     if ( !try_krb5 || !realm_of_user[0] ) {
2432         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2433         {
2434             goto cleanup;
2435         }       
2436     }
2437 #else
2438     goto cleanup;
2439 #endif
2440     strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
2441
2442     if (strlen(service) == 0)
2443         strcpy(ServiceName, "afs");
2444     else
2445         strcpy(ServiceName, service);
2446
2447     if (strlen(cell) == 0)
2448         strcpy(CellName, local_cell);
2449     else
2450         strcpy(CellName, cell);
2451
2452     if (strlen(realm) == 0)
2453         strcpy(RealmName, realm_of_cell);
2454     else
2455         strcpy(RealmName, realm);
2456
2457     memset(&creds, '\0', sizeof(creds));
2458
2459     if ( try_krb5 ) {
2460         /* First try service/cell@REALM */
2461         if (code = pkrb5_build_principal(ctx, &increds.server,
2462                                           strlen(RealmName),
2463                                           RealmName,
2464                                           ServiceName,
2465                                           CellName,
2466                                           0)) 
2467         {
2468             goto cleanup;
2469         }
2470
2471         increds.client = client_principal;
2472         increds.times.endtime = 0;
2473         /* Ask for DES since that is what V4 understands */
2474         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2475
2476         if ( IsDebuggerPresent() ) {
2477             char * cname, *sname;
2478             pkrb5_unparse_name(ctx, increds.client, &cname);
2479             pkrb5_unparse_name(ctx, increds.server, &sname);
2480             OutputDebugString("Getting credentials for \"");
2481             OutputDebugString(cname);
2482             OutputDebugString("\" and service \"");
2483             OutputDebugString(sname);
2484             OutputDebugString("\"\n");
2485             pkrb5_free_unparsed_name(ctx,cname);
2486             pkrb5_free_unparsed_name(ctx,sname);
2487         }
2488
2489         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2490         if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2491              code == KRB5KRB_ERR_GENERIC /* heimdal */) {
2492             /* Or service@REALM */
2493             pkrb5_free_principal(ctx,increds.server);
2494             increds.server = 0;
2495             code = pkrb5_build_principal(ctx, &increds.server,
2496                                           strlen(RealmName),
2497                                           RealmName,
2498                                           ServiceName,
2499                                           0);
2500
2501             if ( IsDebuggerPresent() ) {
2502                 char * cname, *sname;
2503                 pkrb5_unparse_name(ctx, increds.client, &cname);
2504                 pkrb5_unparse_name(ctx, increds.server, &sname);
2505                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2506                 OutputDebugString("Trying again: getting credentials for \"");
2507                 OutputDebugString(cname);
2508                 OutputDebugString("\" and service \"");
2509                 OutputDebugString(sname);
2510                 OutputDebugString("\"\n");
2511                 pkrb5_free_unparsed_name(ctx,cname);
2512                 pkrb5_free_unparsed_name(ctx,sname);
2513             }
2514
2515             if (!code)
2516                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2517         }
2518
2519         if (code) {
2520             if ( IsDebuggerPresent() ) {
2521                 char message[256];
2522                 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2523                 OutputDebugString(message);
2524             }
2525             try_krb5 = 0;
2526             goto use_krb4;
2527         }
2528         /* This requires krb524d to be running with the KDC */
2529         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2530         pkrb5_free_creds(ctx, k5creds);
2531         if (code) {
2532             if ( IsDebuggerPresent() ) {
2533                 char message[256];
2534                 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2535                 OutputDebugString(message);
2536             }
2537             try_krb5 = 0;
2538             goto use_krb4;
2539         }
2540     } else {
2541       use_krb4:
2542 #ifdef USE_KRB4
2543         rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
2544         if (rc == NO_TKT_FIL) {
2545             // if the problem is that we have no krb4 tickets
2546             // do not attempt to continue
2547             goto cleanup;
2548         }
2549         if (rc != KSUCCESS)
2550             rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
2551
2552         if (rc != KSUCCESS)
2553         {
2554             if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
2555             {
2556                 if ((rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
2557                 {
2558                     goto cleanup;
2559                 }
2560             }
2561             else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
2562             {
2563                 if ((rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
2564                 {
2565                     goto cleanup;
2566                 }
2567             }
2568             else
2569             {
2570                 goto cleanup;
2571             }
2572         }
2573 #else
2574         goto cleanup;
2575 #endif
2576     }
2577
2578     memset(&aserver, '\0', sizeof(aserver));
2579     strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2580     strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2581
2582     strcpy(username, creds.pname);
2583     if (creds.pinst[0]) 
2584     {
2585         strcat(username, ".");
2586         strcat(username, creds.pinst);
2587     }
2588
2589     memset(&atoken, '\0', sizeof(atoken));
2590     atoken.kvno = creds.kvno;
2591     atoken.startTime = creds.issue_date;
2592     atoken.endTime = creds.issue_date + (creds.lifetime * 300);
2593     memcpy(&atoken.sessionKey, creds.session, 8);
2594     atoken.ticketLen = creds.ticket_st.length;
2595     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
2596
2597   retry_gettoken:
2598     rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2599     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2600         if ( rc == KTC_NOCM && retry < 20 ) {
2601             Sleep(500);
2602             retry++;
2603             goto retry_gettoken;
2604         }
2605         KFW_AFS_error(rc, "ktc_GetToken()");
2606         code = rc;
2607         goto cleanup;
2608     }
2609
2610     if (atoken.kvno == btoken.kvno &&
2611         atoken.ticketLen == btoken.ticketLen &&
2612         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2613         !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
2614     {
2615         goto cleanup;
2616     }
2617
2618     // * Reset the "aclient" structure before we call ktc_SetToken.
2619     // * This structure was first set by the ktc_GetToken call when
2620     // * we were comparing whether identical tokens already existed.
2621
2622     strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
2623     strcpy(aclient.instance, "");
2624     strncpy(aclient.cell, creds.realm, MAXKTCREALMLEN - 1);
2625
2626     if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0))
2627     {
2628         KFW_AFS_error(rc, "ktc_SetToken()");
2629         code = rc;
2630         goto cleanup;
2631     }
2632
2633   cleanup:
2634     if (client_principal)
2635         pkrb5_free_principal(ctx,client_principal);
2636     /* increds.client == client_principal */
2637     if (increds.server)
2638         pkrb5_free_principal(ctx,increds.server);
2639     if (cc && (cc != alt_cc))
2640         pkrb5_cc_close(ctx, cc);
2641     if (ctx && (ctx != alt_ctx))
2642         pkrb5_free_context(ctx);
2643
2644    return(code);
2645 }
2646
2647 /**************************************/
2648 /* afs_realm_of_cell():               */
2649 /**************************************/
2650 static char *
2651 afs_realm_of_cell(afsconf_cell *cellconfig)
2652 {
2653     static char krbrlm[REALM_SZ+1]="";
2654     krb5_context  ctx = 0;
2655     char ** realmlist=NULL;
2656     krb5_error_code r;
2657
2658     if (!cellconfig)
2659         return 0;
2660
2661     r = pkrb5_init_context(&ctx); 
2662     if ( !r )
2663         r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
2664     if ( !r && realmlist && realmlist[0] ) {
2665         strcpy(krbrlm, realmlist[0]);
2666         pkrb5_free_host_realm(ctx, realmlist);
2667     }
2668     if (ctx)
2669         pkrb5_free_context(ctx);
2670
2671     if ( !krbrlm[0] )
2672     {
2673         char *s = krbrlm;
2674         char *t = cellconfig->name;
2675         int c;
2676
2677         while (c = *t++)
2678         {
2679             if (islower(c)) c=toupper(c);
2680             *s++ = c;
2681         }
2682         *s++ = 0;
2683     }
2684     return(krbrlm);
2685 }
2686
2687 /**************************************/
2688 /* get_cellconfig():                  */
2689 /**************************************/
2690 static int 
2691 get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell)
2692 {
2693     int rc;
2694     char newcell[MAXCELLCHARS+1];
2695
2696     local_cell[0] = (char)0;
2697     memset(cellconfig, 0, sizeof(*cellconfig));
2698
2699     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2700     if (rc = pcm_GetRootCellName(local_cell))
2701     {
2702         return(rc);
2703     }
2704
2705     if (strlen(cell) == 0)
2706         strcpy(cell, local_cell);
2707
2708     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
2709     strcpy(cellconfig->name, cell);
2710
2711     return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
2712 }
2713
2714 /**************************************/
2715 /* get_cellconfig_callback():         */
2716 /**************************************/
2717 static long 
2718 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
2719 {
2720     afsconf_cell *cc = (afsconf_cell *)cellconfig;
2721
2722     cc->hostAddr[cc->numServers] = *addrp;
2723     strcpy(cc->hostName[cc->numServers], namep);
2724     cc->numServers++;
2725     return(0);
2726 }
2727
2728
2729 /**************************************/
2730 /* KFW_AFS_error():                  */
2731 /**************************************/
2732 void
2733 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2734 {
2735     char message[256];
2736     const char *errText; 
2737
2738     // Using AFS defines as error messages for now, until Transarc 
2739     // gets back to me with "string" translations of each of these 
2740     // const. defines. 
2741     if (rc == KTC_ERROR)
2742       errText = "KTC_ERROR";
2743     else if (rc == KTC_TOOBIG)
2744       errText = "KTC_TOOBIG";
2745     else if (rc == KTC_INVAL)
2746       errText = "KTC_INVAL";
2747     else if (rc == KTC_NOENT)
2748       errText = "KTC_NOENT";
2749     else if (rc == KTC_PIOCTLFAIL)
2750       errText = "KTC_PIOCTLFAIL";
2751     else if (rc == KTC_NOPIOCTL)
2752       errText = "KTC_NOPIOCTL";
2753     else if (rc == KTC_NOCELL)
2754       errText = "KTC_NOCELL";
2755     else if (rc == KTC_NOCM)
2756       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2757     else
2758       errText = "Unknown error!";
2759
2760     sprintf(message, "%s\n(%s failed)", errText, FailedFunctionName);
2761
2762     if ( IsDebuggerPresent() ) {
2763         OutputDebugString(message);
2764         OutputDebugString("\n");
2765     }
2766     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
2767     return;
2768 }
2769
2770 static DWORD 
2771 GetServiceStatus(
2772     LPSTR lpszMachineName, 
2773     LPSTR lpszServiceName,
2774     DWORD *lpdwCurrentState) 
2775
2776     DWORD           hr               = NOERROR; 
2777     SC_HANDLE       schSCManager     = NULL; 
2778     SC_HANDLE       schService       = NULL; 
2779     DWORD           fdwDesiredAccess = 0; 
2780     SERVICE_STATUS  ssServiceStatus  = {0}; 
2781     BOOL            fRet             = FALSE; 
2782
2783     *lpdwCurrentState = 0; 
2784  
2785     fdwDesiredAccess = GENERIC_READ; 
2786  
2787     schSCManager = OpenSCManager(lpszMachineName,  
2788                                  NULL,
2789                                  fdwDesiredAccess); 
2790  
2791     if(schSCManager == NULL) 
2792     { 
2793         hr = GetLastError();
2794         goto cleanup; 
2795     } 
2796  
2797     schService = OpenService(schSCManager,
2798                              lpszServiceName,
2799                              fdwDesiredAccess); 
2800  
2801     if(schService == NULL) 
2802     { 
2803         hr = GetLastError();
2804         goto cleanup; 
2805     } 
2806  
2807     fRet = QueryServiceStatus(schService,
2808                               &ssServiceStatus); 
2809  
2810     if(fRet == FALSE) 
2811     { 
2812         hr = GetLastError(); 
2813         goto cleanup; 
2814     } 
2815  
2816     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
2817  
2818 cleanup: 
2819  
2820     CloseServiceHandle(schService); 
2821     CloseServiceHandle(schSCManager); 
2822  
2823     return(hr); 
2824
2825
2826 void
2827 UnloadFuncs(
2828     FUNC_INFO fi[], 
2829     HINSTANCE h
2830     )
2831 {
2832     int n;
2833     if (fi)
2834         for (n = 0; fi[n].func_ptr_var; n++)
2835             *(fi[n].func_ptr_var) = 0;
2836     if (h) FreeLibrary(h);
2837 }
2838
2839 int
2840 LoadFuncs(
2841     const char* dll_name, 
2842     FUNC_INFO fi[], 
2843     HINSTANCE* ph,  // [out, optional] - DLL handle
2844     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
2845     int cleanup,    // cleanup function pointers and unload on error
2846     int go_on,      // continue loading even if some functions cannot be loaded
2847     int silent      // do not pop-up a system dialog if DLL cannot be loaded
2848     )
2849 {
2850     HINSTANCE h;
2851     int i, n, last_i;
2852     int error = 0;
2853     UINT em;
2854
2855     if (ph) *ph = 0;
2856     if (pindex) *pindex = -1;
2857
2858     for (n = 0; fi[n].func_ptr_var; n++)
2859         *(fi[n].func_ptr_var) = 0;
2860
2861     if (silent)
2862         em = SetErrorMode(SEM_FAILCRITICALERRORS);
2863     h = LoadLibrary(dll_name);
2864     if (silent)
2865         SetErrorMode(em);
2866
2867     if (!h)
2868         return 0;
2869
2870     last_i = -1;
2871     for (i = 0; (go_on || !error) && (i < n); i++)
2872     {
2873         void* p = (void*)GetProcAddress(h, fi[i].func_name);
2874         if (!p)
2875             error = 1;
2876         else
2877         {
2878             last_i = i;
2879             *(fi[i].func_ptr_var) = p;
2880         }
2881     }
2882     if (pindex) *pindex = last_i;
2883     if (error && cleanup && !go_on) {
2884         for (i = 0; i < n; i++) {
2885             *(fi[i].func_ptr_var) = 0;
2886         }
2887         FreeLibrary(h);
2888         return 0;
2889     }
2890     if (ph) *ph = h;
2891     if (error) return 0;
2892     return 1;
2893 }
2894
2895 #ifdef USE_FSPROBE
2896 // Cell Accessibility Functions
2897 // based on work originally submitted to the CMU Computer Club
2898 // by Jeffrey Hutzelman
2899 //
2900 // These would work great if the fsProbe interface had been 
2901 // ported to Windows
2902
2903 static 
2904 void probeComplete()
2905 {
2906     fsprobe_Cleanup(1);
2907     rx_Finalize();
2908 }
2909
2910 struct ping_params {
2911     unsigned short port;            // in
2912     int            retry_delay;     // in seconds
2913     int            verbose;         // in
2914     struct {
2915         int        wait;            // in seconds
2916         int        retry;           // in attempts
2917     }   host;
2918     int            max_hosts;       // in
2919     int            hosts_attempted; // out
2920 }
2921
2922 // the fsHandler is where we receive the answer to the probe
2923 static 
2924 int fsHandler(void)
2925 {
2926     ping_count = fsprobe_Results.probeNum;
2927     if (!*fsprobe_Results.probeOK)
2928     {
2929         ok_count++;
2930         if (waiting) complete();
2931     }
2932     if (ping_count == retry) 
2933         complete();
2934     return 0;
2935 }
2936
2937 // ping_fs is a callback routine meant to be called from within
2938 // cm_SearchCellFile() or cm_SearchCellDNS()
2939 static long 
2940 pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep)
2941 {
2942     int rc;
2943     struct ping_params * pp = (struct ping_params *) ping_params;
2944
2945     if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts )
2946         return 0;
2947
2948     pp->hosts_attempted++;
2949
2950     if (pp->port && addrp->sin_port != htons(pp->port))
2951         addrp->sin_port = htons(pp->port);
2952
2953     rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose);
2954     if (rc)
2955     {
2956         fprintf(stderr, "fsprobe_Init failed (%d)\n", rc);
2957         fsprobe_Cleanup(1);
2958         return 0;
2959     }
2960
2961     for (;;)
2962     {
2963         tv.tv_sec = pp->host.wait;
2964         tv.tv_usec = 0;
2965         if (IOMGR_Select(0, 0, 0, 0, &tv)) 
2966             break;
2967     }
2968     probeComplete();
2969     return(0);
2970 }
2971
2972
2973 static BOOL
2974 pingCell(char *cell)
2975 {
2976     int rc;
2977     char rootcell[MAXCELLCHARS+1];
2978     char newcell[MAXCELLCHARS+1];
2979     struct ping_params pp;
2980
2981     memset(&pp, 0, sizeof(struct ping_params));
2982
2983     if (!cell || strlen(cell) == 0) {
2984         /* WIN32 NOTE: no way to get max chars */
2985         if (rc = pcm_GetRootCellName(rootcell))
2986             return(FALSE);
2987         cell = rootcell;
2988     }
2989
2990     pp.port = 7000; // AFS FileServer
2991     pp.retry_delay = 10;
2992     pp.max_hosts = 3;
2993     pp.host.wait = 30;
2994     pp.host.retry = 0;
2995     pp.verbose = 1;
2996
2997     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
2998     rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp);
2999 }
3000 #endif /* USE_FSPROBE */
3001  
3002 // These two items are imported from afscreds.h 
3003 // but it cannot be included without causing conflicts
3004 #define c100ns1SECOND        (LONGLONG)10000000
3005 static void 
3006 TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT)
3007 {
3008     struct tm *pTime;
3009     memset (pst, 0x00, sizeof(SYSTEMTIME));
3010
3011     if ((pTime = localtime (&TimeT)) != NULL)
3012     {
3013         pst->wYear = pTime->tm_year + 1900;
3014         pst->wMonth = pTime->tm_mon + 1;
3015         pst->wDayOfWeek = pTime->tm_wday;
3016         pst->wDay = pTime->tm_mday;
3017         pst->wHour = pTime->tm_hour;
3018         pst->wMinute = pTime->tm_min;
3019         pst->wSecond = pTime->tm_sec;
3020         pst->wMilliseconds = 0;
3021     }
3022 }
3023
3024 void
3025 ObtainTokensFromUserIfNeeded(HWND hWnd)
3026 {
3027     char * rootcell = NULL;
3028     char   cell[MAXCELLCHARS+1] = "";
3029     char   password[PROBE_PASSWORD_LEN+1];
3030     krb5_data pwdata;
3031     afsconf_cell cellconfig;
3032     struct ktc_principal    aserver;
3033     struct ktc_principal    aclient;
3034     struct ktc_token    atoken;
3035     krb5_context ctx;
3036     krb5_timestamp now = 0;
3037     krb5_error_code code;
3038     int serverReachable = 0;
3039     int rc;
3040 #ifndef USE_FSPROBE
3041     krb5_ccache cc = 0;
3042     const char * realm = 0;
3043     krb5_principal principal = 0;
3044     char * pname = 0;
3045 #endif /* USE_FSPROBE */
3046     DWORD       CurrentState;
3047     char        HostName[64];
3048
3049     CurrentState = 0;
3050     memset(HostName, '\0', sizeof(HostName));
3051     gethostname(HostName, sizeof(HostName));
3052     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
3053         return;
3054     if (CurrentState != SERVICE_RUNNING) {
3055         SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L);
3056         return;
3057     }
3058
3059     if ( KFW_is_available() ) {
3060         code = pkrb5_init_context(&ctx);
3061         if ( code ) goto cleanup;
3062     }
3063
3064     rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1);
3065     if ( !rootcell ) goto cleanup;
3066
3067     code = get_cellconfig(cell, (void*)&cellconfig, rootcell);
3068     if ( code ) goto cleanup;
3069
3070     memset(&aserver, '\0', sizeof(aserver));
3071     strcpy(aserver.name, "afs");
3072     strcpy(aserver.cell, rootcell);
3073
3074     rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3075
3076     if ( KFW_is_available() ) {
3077         code = pkrb5_timeofday(ctx, &now);
3078         if ( code ) 
3079             now = 0;
3080
3081         if (!rc && (now < atoken.endTime))
3082             goto cleanup;
3083     } else {
3084         SYSTEMTIME stNow;
3085         FILETIME ftNow;
3086         FILETIME ftExpires;
3087         LONGLONG llNow;
3088         LONGLONG llExpires;
3089         SYSTEMTIME stExpires;
3090
3091         TimeToSystemTime (&stExpires, atoken.endTime);
3092         GetLocalTime (&stNow);
3093         SystemTimeToFileTime (&stNow, &ftNow);
3094         SystemTimeToFileTime (&stExpires, &ftExpires);
3095
3096         llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime);
3097         llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime);
3098
3099         llNow /= c100ns1SECOND;
3100         llExpires /= c100ns1SECOND;
3101
3102         if (!rc && (llNow < llExpires))
3103             goto cleanup;
3104     }
3105
3106
3107 #ifdef USE_FSPROBE
3108     serverReachable = cellPing(NULL);
3109 #else
3110     if ( KFW_is_available() ) {
3111         // If we can't use the FSProbe interface we can attempt to forge
3112         // a kinit and if we can back an invalid user error we know the
3113         // kdc is at least reachable
3114         realm = afs_realm_of_cell(&cellconfig);  // do not free
3115
3116         code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3117                                      realm, PROBE_USERNAME, NULL, NULL);
3118         if ( code ) goto cleanup;
3119
3120         code = KFW_get_ccache(ctx, principal, &cc);
3121         if ( code ) goto cleanup;
3122
3123         code = pkrb5_unparse_name(ctx, principal, &pname);
3124         if ( code ) goto cleanup;
3125
3126         pwdata.data = password;
3127         pwdata.length = PROBE_PASSWORD_LEN;
3128         code = pkrb5_c_random_make_octets(ctx, &pwdata);
3129         if (code) {
3130             int i;
3131             for ( i=0 ; i<PROBE_PASSWORD_LEN ; i )
3132                 password[i] = 'x';
3133         }
3134         password[PROBE_PASSWORD_LEN] = '\0';
3135
3136         code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
3137                            pname, 
3138                            password,
3139                            5,
3140                            0,
3141                            0,
3142                            0,
3143                            1,
3144                            0);
3145         switch ( code ) {
3146         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3147         case KRB5KDC_ERR_CLIENT_REVOKED:
3148         case KRB5KDC_ERR_CLIENT_NOTYET:
3149         case KRB5KDC_ERR_PREAUTH_FAILED:
3150         case KRB5KDC_ERR_PREAUTH_REQUIRED:
3151         case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3152             serverReachable = TRUE;
3153             break;
3154         default:
3155             serverReachable = FALSE;
3156         }
3157     } else {
3158         int i;
3159         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i )
3160             password[i] = 'x';
3161
3162         code = ObtainNewCredentials(rootcell, PROBE_USERNAME, password);
3163         serverReachable = 1;
3164     }
3165 #endif
3166     if ( !serverReachable )
3167         goto cleanup;
3168
3169     if ( KFW_is_available() ) {
3170 #ifdef USE_MS2MIT
3171         KFW_import_windows_lsa();
3172 #endif /* USE_MS2MIT */
3173         KFW_AFS_renew_expiring_credentials();
3174         KFW_AFS_renew_token_for_cell(rootcell);
3175
3176         rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3177         if (!rc && (now < atoken.endTime))
3178             goto cleanup;
3179     }
3180
3181     SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
3182     rootcell = NULL;    // rootcell freed by message receiver
3183
3184   cleanup:
3185     if (rootcell)
3186         GlobalFree(rootcell);
3187
3188 #ifndef USE_FSPROBE
3189     if ( pname )
3190         pkrb5_free_unparsed_name(ctx,pname);
3191     if ( principal )
3192         pkrb5_free_principal(ctx,principal);
3193     if (cc)
3194         pkrb5_cc_close(ctx,cc);
3195 #endif /* USE_FSPROBE */
3196     if (ctx)
3197         pkrb5_free_context(ctx);
3198     return;
3199 }
3200
3201 // IP Change Monitoring Functions
3202 #include <Iphlpapi.h>
3203
3204 DWORD
3205 GetNumOfIpAddrs(void)
3206 {
3207     PMIB_IPADDRTABLE pIpAddrTable = NULL;
3208     ULONG            dwSize;
3209     DWORD            code;
3210     DWORD            index;
3211     DWORD            validAddrs = 0;
3212
3213     dwSize = 0;
3214     code = GetIpAddrTable(NULL, &dwSize, 0);
3215     if (code == ERROR_INSUFFICIENT_BUFFER) {
3216         pIpAddrTable = malloc(dwSize);
3217         code = GetIpAddrTable(pIpAddrTable, &dwSize, 0);
3218         for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
3219             if (pIpAddrTable->table[index].dwAddr != 0)
3220                 validAddrs++;
3221         }
3222         free(pIpAddrTable);
3223     }
3224     return validAddrs;
3225 }
3226
3227 void
3228 IpAddrChangeMonitor(void * hWnd)
3229 {
3230 #ifdef USE_OVERLAPPED
3231     HANDLE Handle = INVALID_HANDLE_VALUE;
3232     OVERLAPPED Ovlap;
3233 #endif /* USE_OVERLAPPED */
3234     DWORD Result;
3235     DWORD prevNumOfAddrs = GetNumOfIpAddrs();
3236     DWORD NumOfAddrs;
3237
3238     if ( !hWnd )
3239         return;
3240
3241     while ( TRUE ) {
3242 #ifdef USE_OVERLAPPED
3243         ZeroMemory(&Ovlap, sizeof(OVERLAPPED));
3244
3245         Result = NotifyAddrChange(&Handle,&Ovlap);
3246         if (Result != ERROR_IO_PENDING)
3247         {        
3248             printf("NotifyAddrChange() failed with error %d \n", Result);
3249             break;
3250         }
3251
3252         if ((Result = WaitForSingleObject(Handle,INFINITE)) == WAIT_FAILED)
3253         {
3254             printf("WaitForSingleObject() failed with error %d\n",
3255                     GetLastError());
3256             continue;
3257         }
3258
3259         if (GetOverlappedResult(Handle, &Ovlap,
3260                                  &DataTransfered, TRUE) == 0)
3261         {
3262             printf("GetOverlapped result failed %d \n",
3263                     GetLastError());
3264             break;
3265         }
3266
3267 #else
3268         Result = NotifyAddrChange(NULL,NULL);
3269 #endif
3270         
3271         NumOfAddrs = GetNumOfIpAddrs();
3272         if ( NumOfAddrs != prevNumOfAddrs ) {
3273             // Give AFS Client Service a chance to notice and die
3274             // Or for network services to startup
3275             Sleep(2000);
3276             // this call should probably be mutex protected
3277             ObtainTokensFromUserIfNeeded(hWnd);
3278         }
3279         prevNumOfAddrs = NumOfAddrs;
3280     }
3281
3282 #ifdef USE_OVERLAPPED
3283     if (Handle != INVALID_HANDLE_VALUE)
3284         CloseHandle(Handle);
3285 #endif 
3286 }
3287
3288
3289 DWORD 
3290 IpAddrChangeMonitorInit(HWND hWnd)
3291 {
3292     DWORD status = ERROR_SUCCESS;
3293     HANDLE thread;
3294     ULONG  threadID = 0;
3295
3296     thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor,
3297                                     hWnd, 0, &threadID);
3298
3299     if (thread == NULL) {
3300         status = GetLastError();
3301     }
3302     CloseHandle(thread);
3303     return status;
3304 }
3305