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