1603a3769604dc081315edc446d7bebdce5f7b5c
[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 )
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             krb5_ccache oldcc = 0;
1003             for ( j=0; pNCi[j]; j++ ) {
1004                 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1005                     found = 1;
1006                     break;
1007                 }
1008             }
1009             if (found)
1010                 continue;
1011
1012             if ( IsDebuggerPresent() )
1013                 OutputDebugString("copying ccache data to new ccache\n");
1014
1015             code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1016             if (code) goto loop_cleanup;
1017             code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1018             if (code) goto loop_cleanup;
1019             code = pkrb5_cc_initialize(ctx, cc, principal);
1020             if (code) goto loop_cleanup;
1021             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1022             if (code) goto loop_cleanup;
1023             code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1024                         if (code) {
1025                                 code = pkrb5_cc_close(ctx,cc);
1026                 cc = 0;
1027                 code = pkrb5_cc_close(ctx,oldcc);
1028                 cc = 0;
1029                                 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1030                                 continue;
1031                         }
1032             code = pkrb5_cc_close(ctx,oldcc);
1033         } else {
1034             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1035             if (code) goto loop_cleanup;
1036         }
1037
1038         flags = 0;  // turn off OPENCLOSE mode
1039         code = pkrb5_cc_set_flags(ctx, cc, flags);
1040         if ( code ) goto cleanup;
1041
1042         KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1043
1044         cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1045
1046         while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1047             krb5_data * sname = krb5_princ_name(ctx, creds.server);
1048             krb5_data * cell  = krb5_princ_component(ctx, creds.server, 1);
1049             krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1050             if ( sname && cell && !strcmp("afs",sname->data) ) {
1051                 struct ktc_principal    aserver;
1052                 struct ktc_principal    aclient;
1053                 struct ktc_token        atoken;
1054                 int active = TRUE;
1055
1056                 if ( IsDebuggerPresent() )  {
1057                     OutputDebugString("Found AFS ticket: ");
1058                     OutputDebugString(sname->data);
1059                     if ( cell->data ) {
1060                         OutputDebugString("/");
1061                         OutputDebugString(cell->data);
1062                     }
1063                     OutputDebugString("@");
1064                     OutputDebugString(realm->data);
1065                     OutputDebugString("\n");
1066                 }
1067
1068                 memset(&aserver, '\0', sizeof(aserver));
1069                 strcpy(aserver.name, sname->data);
1070                 strcpy(aserver.cell, cell->data);
1071
1072                 code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1073                 if (!code) {
1074                     // Found a token in AFS Client Server which matches
1075                     char pname[128], *p, *q;
1076                     for ( p=pname, q=aclient.name; *q; p++, q++)
1077                         *p = *q;
1078                     for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1079                         *p = toupper(*q);
1080                     *p = '\0';
1081
1082                     if ( IsDebuggerPresent() )  {
1083                         OutputDebugString("Found AFS token: ");
1084                         OutputDebugString(pname);
1085                         OutputDebugString("\n");
1086                     }
1087
1088                     if ( strcmp(pname,pNCi[i]->principal)  )
1089                         active = FALSE;
1090                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1091                 } else {
1092                     // Attempt to import it
1093                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1094
1095                     if ( IsDebuggerPresent() )  {
1096                         OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1097                     }
1098
1099                     code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime());
1100                     if ( IsDebuggerPresent() ) {
1101                         char message[256];
1102                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1103                         OutputDebugString(message);
1104                     }
1105                 }
1106             } else if ( IsDebuggerPresent() ) {
1107                 OutputDebugString("Found ticket: ");
1108                 OutputDebugString(sname->data);
1109                 if ( cell && cell->data ) {
1110                     OutputDebugString("/");
1111                     OutputDebugString(cell->data);
1112                 }
1113                 OutputDebugString("@");
1114                 OutputDebugString(realm->data);
1115                 OutputDebugString("\n");
1116             }
1117             pkrb5_free_cred_contents(ctx, &creds);
1118         }
1119
1120         if (cc_code == KRB5_CC_END) {
1121             cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1122             if (cc_code) goto loop_cleanup;
1123         }
1124
1125       loop_cleanup:
1126         flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
1127         code = pkrb5_cc_set_flags(ctx, cc, flags);
1128         if (cc) {
1129             pkrb5_cc_close(ctx,cc);
1130             cc = 0;
1131         }
1132     }
1133
1134   cleanup:
1135     if (principal)
1136         pkrb5_free_principal(ctx,principal);
1137     if (ctx)
1138         pkrb5_free_context(ctx);
1139     if (pNCi)
1140         pcc_free_NC_info(cc_ctx, &pNCi);
1141     if (cc_ctx)
1142         pcc_shutdown(&cc_ctx);
1143 }
1144
1145
1146 int
1147 KFW_AFS_get_cred(char * username, 
1148                   char * instance, 
1149                   char * cell,
1150                   char * password,
1151                   int lifetime,
1152                   char ** reasonP )
1153 {
1154     krb5_context ctx = 0;
1155     krb5_ccache cc = 0;
1156     char * realm = 0;
1157     char ** realmlist = 0;
1158     krb5_principal principal = 0;
1159     char * pname = 0;
1160     krb5_error_code code;
1161         char local_cell[MAXCELLCHARS+1];
1162     char **cells = NULL;
1163     int  cell_count=0;
1164     afsconf_cell cellconfig;
1165
1166     if (!pkrb5_init_context)
1167         return 0;
1168
1169     if ( IsDebuggerPresent() ) {
1170         OutputDebugString("KFW_AFS_get_cred for token ");
1171         OutputDebugString(username);
1172         if ( instance ) {
1173             OutputDebugString("/");
1174             OutputDebugString(instance);
1175         }
1176         OutputDebugString("@");
1177         OutputDebugString(cell);
1178         OutputDebugString("\n");
1179     }
1180
1181     code = pkrb5_init_context(&ctx);
1182     if ( code ) goto cleanup;
1183
1184     code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1185     if ( code ) goto cleanup;
1186
1187     realm = strchr(username,'@');
1188     if (realm) {
1189         *realm = '\0';
1190         realm++;
1191     }
1192     if ( !realm[0] )
1193         realm = afs_realm_of_cell(&cellconfig);  // do not free
1194
1195     if ( IsDebuggerPresent() ) {
1196         OutputDebugString("Realm: ");
1197         OutputDebugString(realm);
1198         OutputDebugString("\n");
1199     }
1200
1201     code = pkrb5_build_principal(ctx, &principal, strlen(realm),
1202                                  realm, username, 
1203                                  (instance && instance[0]) ? instance : NULL, 
1204                                  NULL);
1205
1206     code = KFW_get_ccache(ctx, principal, &cc);
1207     if ( code ) goto cleanup;
1208
1209     code = pkrb5_unparse_name(ctx, principal, &pname);
1210     if ( code ) goto cleanup;
1211
1212     if ( lifetime == 0 )
1213         lifetime = pLeash_get_default_lifetime();
1214
1215     code = KFW_kinit(ctx, cc, HWND_DESKTOP, 
1216                       pname, 
1217                       password,
1218                       lifetime,
1219                       pLeash_get_default_forwardable(),
1220                       pLeash_get_default_proxiable(),
1221                       pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1222                       pLeash_get_default_noaddresses(),
1223                       pLeash_get_default_publicip());
1224     if ( IsDebuggerPresent() ) {
1225         char message[256];
1226         sprintf(message,"KFW_kinit() returns: %d\n",code);
1227         OutputDebugString(message);
1228     }
1229     if ( code ) goto cleanup;
1230                    
1231     KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1232
1233     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime);
1234     if ( IsDebuggerPresent() ) {
1235         char message[256];
1236         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1237         OutputDebugString(message);
1238     }
1239     if ( code ) goto cleanup;
1240
1241     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1242
1243     // Attempt to obtain new tokens for other cells supported by the same 
1244     // principal
1245     cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1246     if ( cell_count > 1 ) {
1247         while ( cell_count-- ) {
1248             if ( strcmp(cells[cell_count],cell) ) {
1249                 if ( IsDebuggerPresent() ) {
1250                     char message[256];
1251                     sprintf(message,"found another cell for the same principal: %s\n",cell);
1252                     OutputDebugString(message);
1253                 }
1254                 code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1255                 if ( code ) continue;
1256     
1257                 realm = afs_realm_of_cell(&cellconfig);  // do not free
1258                 if ( IsDebuggerPresent() ) {
1259                     OutputDebugString("Realm: ");
1260                     OutputDebugString(realm);
1261                     OutputDebugString("\n");
1262                 }
1263                 
1264                 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime);
1265                 if ( IsDebuggerPresent() ) {
1266                     char message[256];
1267                     sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1268                     OutputDebugString(message);
1269                 }
1270             }
1271             free(cells[cell_count]);
1272         }
1273         free(cells);
1274     } else if ( cell_count == 1 ) {
1275         free(cells[0]);
1276         free(cells);
1277     }
1278
1279   cleanup:
1280     if ( pname )
1281         pkrb5_free_unparsed_name(ctx,pname);
1282     if ( cc )
1283         pkrb5_cc_close(ctx, cc);
1284
1285     if ( code && reasonP ) {
1286         *reasonP = (char *)perror_message(code);
1287     }
1288     return(code);
1289 }
1290
1291 int 
1292 KFW_AFS_destroy_tickets_for_cell(char * cell)
1293 {
1294     krb5_context                ctx = 0;
1295     krb5_error_code             code;
1296     int count;
1297     char ** principals = NULL;
1298
1299     if (!pkrb5_init_context)
1300         return 0;
1301
1302     if ( IsDebuggerPresent() ) {
1303         OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
1304         OutputDebugString(cell);
1305         OutputDebugString("\n");
1306     }
1307
1308     code = pkrb5_init_context(&ctx);
1309     if (code) ctx = 0;
1310
1311     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1312     if ( count > 0 ) {
1313         krb5_principal      princ = 0;
1314         krb5_ccache                     cc  = 0;
1315
1316         while ( count-- ) {
1317             int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1318             if ( cell_count > 1 ) {
1319                 // TODO - What we really should do here is verify whether or not any of the
1320                 // other cells which use this principal to obtain its credentials actually
1321                 // have valid tokens or not.  If they are currently using these credentials
1322                 // we will skip them.  For the time being we assume that if there is an active
1323                 // map in the table that they are actively being used.
1324                 goto loop_cleanup;
1325             }
1326
1327             code = pkrb5_parse_name(ctx, principals[count], &princ);
1328             if (code) goto loop_cleanup;
1329
1330             code = KFW_get_ccache(ctx, princ, &cc);
1331             if (code) goto loop_cleanup;
1332
1333             code = pkrb5_cc_destroy(ctx, cc);
1334             if (!code) cc = 0;
1335
1336           loop_cleanup:
1337             if ( cc ) {
1338                 pkrb5_cc_close(ctx, cc);
1339                 cc = 0;
1340             }
1341             if ( princ ) {
1342                 pkrb5_free_principal(ctx, princ);
1343                 princ = 0;
1344             }
1345
1346             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1347             free(principals[count]);
1348         }
1349         free(principals);
1350     }
1351     pkrb5_free_context(ctx);
1352     return 0;
1353 }
1354
1355 int
1356 KFW_AFS_renew_expiring_tokens(void)
1357 {
1358     krb5_error_code                     code = 0;
1359     krb5_context                        ctx = 0;
1360     krb5_ccache                         cc = 0;
1361     krb5_timestamp now;
1362     struct principal_ccache_data * pcc_next = princ_cc_data;
1363     int cell_count;
1364     char ** cells=NULL;
1365     const char * realm = NULL;
1366     char local_cell[MAXCELLCHARS+1]="";
1367     afsconf_cell cellconfig;
1368
1369     if (!pkrb5_init_context)
1370         return 0;
1371
1372     if ( pcc_next == NULL ) // nothing to do
1373         return 0;
1374
1375     if ( IsDebuggerPresent() ) {
1376         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1377     }
1378
1379     code = pkrb5_init_context(&ctx);
1380     if (code) goto cleanup;
1381
1382     code = pkrb5_timeofday(ctx, &now);
1383     if (code) goto cleanup; 
1384
1385     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1386         if ( pcc_next->expired ) 
1387             continue;
1388
1389         if ( now >= (pcc_next->expiration_time) ) {
1390             if ( !pcc_next->from_lsa ) {
1391                 pcc_next->expired = 1;
1392                 continue;
1393             }
1394         }
1395
1396         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1397             code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1398             if ( code ) 
1399                                 goto loop_cleanup;
1400             code = KFW_renew(ctx,cc);
1401 #ifdef USE_MS2MIT
1402             if ( code && pcc_next->from_lsa)
1403                 goto loop_cleanup;
1404 #endif /* USE_MS2MIT */
1405
1406
1407             KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1408             if (code) goto loop_cleanup;
1409
1410             // Attempt to obtain new tokens for other cells supported by the same 
1411             // principal
1412             cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1413             if ( cell_count > 0 ) {
1414                 while ( cell_count-- ) {
1415                     if ( IsDebuggerPresent() ) {
1416                         OutputDebugString("Cell: ");
1417                         OutputDebugString(cells[cell_count]);
1418                         OutputDebugString("\n");
1419                     }
1420                     code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1421                     if ( code ) continue;
1422                     realm = afs_realm_of_cell(&cellconfig);  // do not free
1423                     if ( IsDebuggerPresent() ) {
1424                         OutputDebugString("Realm: ");
1425                         OutputDebugString(realm);
1426                         OutputDebugString("\n");
1427                     }
1428                     code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime());
1429                     if ( IsDebuggerPresent() ) {
1430                         char message[256];
1431                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1432                         OutputDebugString(message);
1433                     }
1434                     free(cells[cell_count]);
1435                 }
1436                 free(cells);
1437             }
1438         }
1439
1440       loop_cleanup:
1441         if ( cc ) {
1442             pkrb5_cc_close(ctx,cc);
1443             cc = 0;
1444         }
1445     }
1446
1447   cleanup:
1448     if ( cc )
1449         pkrb5_cc_close(ctx,cc);
1450     if ( ctx )
1451         pkrb5_free_context(ctx);
1452
1453     return 0;
1454 }
1455
1456
1457 BOOL
1458 KFW_AFS_renew_token_for_cell(char * cell)
1459 {
1460     krb5_error_code                     code = 0;
1461     krb5_context                        ctx = 0;
1462     int count;
1463     char ** principals = NULL;
1464
1465     if (!pkrb5_init_context)
1466         return 0;
1467
1468     if ( IsDebuggerPresent() ) {
1469         OutputDebugString("KFW_AFS_renew_token_for_cell:");
1470         OutputDebugString(cell);
1471         OutputDebugString("\n");
1472     }
1473
1474     code = pkrb5_init_context(&ctx);
1475     if (code) goto cleanup;
1476
1477     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1478     if ( count > 0 ) {
1479         krb5_principal      princ = 0;
1480         krb5_principal      service = 0;
1481 #ifdef COMMENT
1482         krb5_creds          mcreds, creds;
1483 #endif /* COMMENT */
1484         krb5_ccache                     cc  = 0;
1485         const char * realm = NULL;
1486         afsconf_cell cellconfig;
1487         char local_cell[MAXCELLCHARS+1];
1488
1489         while ( count-- ) {
1490             code = pkrb5_parse_name(ctx, principals[count], &princ);
1491             if (code) goto loop_cleanup;
1492
1493             code = KFW_get_ccache(ctx, princ, &cc);
1494             if (code) goto loop_cleanup;
1495
1496             code = get_cellconfig( cell, (void*)&cellconfig, local_cell);
1497             if ( code ) goto loop_cleanup;
1498
1499             realm = afs_realm_of_cell(&cellconfig);  // do not free
1500             if ( IsDebuggerPresent() ) {
1501                 OutputDebugString("Realm: ");
1502                 OutputDebugString(realm);
1503                 OutputDebugString("\n");
1504             }
1505
1506 #ifdef COMMENT
1507             /* krb5_cc_remove_cred() is not implemented 
1508              * for a single cred 
1509              */
1510             code = pkrb5_build_principal(ctx, &service, strlen(realm),
1511                                           realm, "afs", cell, NULL);
1512             if (!code) {
1513                 memset(&mcreds, 0, sizeof(krb5_creds));
1514                 mcreds.client = princ;
1515                 mcreds.server = service;
1516
1517                 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1518                 if (!code) {
1519                     if ( IsDebuggerPresent() ) {
1520                         char * cname, *sname;
1521                         pkrb5_unparse_name(ctx, creds.client, &cname);
1522                         pkrb5_unparse_name(ctx, creds.server, &sname);
1523                         OutputDebugString("Removing credential for client \"");
1524                         OutputDebugString(cname);
1525                         OutputDebugString("\" and service \"");
1526                         OutputDebugString(sname);
1527                         OutputDebugString("\"\n");
1528                         pkrb5_free_unparsed_name(ctx,cname);
1529                         pkrb5_free_unparsed_name(ctx,sname);
1530                     }
1531
1532                     code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1533                     pkrb5_free_principal(ctx, creds.client);
1534                     pkrb5_free_principal(ctx, creds.server);
1535                 }
1536             }
1537 #endif /* COMMENT */
1538
1539             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime());
1540             if ( IsDebuggerPresent() ) {
1541                 char message[256];
1542                 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1543                 OutputDebugString(message);
1544             }
1545
1546           loop_cleanup:
1547             if (cc) {
1548                 pkrb5_cc_close(ctx, cc);
1549                 cc = 0;
1550             }
1551             if (princ) {
1552                 pkrb5_free_principal(ctx, princ);
1553                 princ = 0;
1554             }
1555             if (service) {
1556                 pkrb5_free_principal(ctx, service);
1557                 princ = 0;
1558             }
1559
1560             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1561             free(principals[count]);
1562         }
1563         free(principals);
1564     } else
1565         code = -1;      // we did not renew the tokens 
1566
1567   cleanup:
1568     pkrb5_free_context(ctx);
1569     return (code ? FALSE : TRUE);
1570
1571 }
1572
1573 int
1574 KFW_AFS_renew_tokens_for_all_cells(void)
1575 {
1576     struct cell_principal_map * next = cell_princ_map;
1577
1578     if ( IsDebuggerPresent() )
1579         OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1580
1581     if ( !next )
1582         return 0;
1583
1584     for ( ; next ; next = next->next ) {
1585         if ( next->active )
1586             KFW_AFS_renew_token_for_cell(next->cell);
1587     }
1588     return 0;
1589 }
1590
1591 int
1592 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1593 {
1594     krb5_error_code                     code = 0;
1595     krb5_context                        ctx = 0;
1596     krb5_ccache                         cc = 0;
1597     krb5_principal                      me = 0;
1598     krb5_principal              server = 0;
1599     krb5_creds                          my_creds;
1600     krb5_data                   *realm = 0;
1601
1602     if (!pkrb5_init_context)
1603         return 0;
1604
1605         memset(&my_creds, 0, sizeof(krb5_creds));
1606
1607     if ( alt_ctx ) {
1608         ctx = alt_ctx;
1609     } else {
1610         code = pkrb5_init_context(&ctx);
1611         if (code) goto cleanup;
1612     }
1613
1614     if ( alt_cc ) {
1615         cc = alt_cc;
1616     } else {
1617         code = pkrb5_cc_default(ctx, &cc);
1618         if (code) goto cleanup;
1619     }
1620
1621     code = pkrb5_cc_get_principal(ctx, cc, &me);
1622     if (code) goto cleanup;
1623
1624     realm = krb5_princ_realm(ctx, me);
1625
1626     code = pkrb5_build_principal_ext(ctx, &server,
1627                                     realm->length,realm->data,
1628                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1629                                     realm->length,realm->data,
1630                                     0);
1631     if ( code ) 
1632         goto cleanup;
1633
1634     if ( IsDebuggerPresent() ) {
1635         char * cname, *sname;
1636         pkrb5_unparse_name(ctx, me, &cname);
1637         pkrb5_unparse_name(ctx, server, &sname);
1638         OutputDebugString("Renewing credential for client \"");
1639         OutputDebugString(cname);
1640         OutputDebugString("\" and service \"");
1641         OutputDebugString(sname);
1642         OutputDebugString("\"\n");
1643         pkrb5_free_unparsed_name(ctx,cname);
1644         pkrb5_free_unparsed_name(ctx,sname);
1645     }
1646
1647     my_creds.client = me;
1648     my_creds.server = server;
1649
1650     code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1651     if (code) {
1652         if ( IsDebuggerPresent() ) {
1653             char message[256];
1654             sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1655             OutputDebugString(message);
1656         }
1657         goto cleanup;
1658     }
1659
1660     code = pkrb5_cc_initialize(ctx, cc, me);
1661     if (code) {
1662         if ( IsDebuggerPresent() ) {
1663             char message[256];
1664             sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1665             OutputDebugString(message);
1666         }
1667         goto cleanup;
1668     }
1669
1670     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1671     if (code) {
1672         if ( IsDebuggerPresent() ) {
1673             char message[256];
1674             sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1675             OutputDebugString(message);
1676         }
1677         goto cleanup;
1678     }
1679
1680   cleanup:
1681     if (my_creds.client == me)
1682         my_creds.client = 0;
1683     if (my_creds.server == server)
1684         my_creds.server = 0;
1685     pkrb5_free_cred_contents(ctx, &my_creds);
1686     if (me)
1687         pkrb5_free_principal(ctx, me);
1688     if (server)
1689         pkrb5_free_principal(ctx, server);
1690     if (cc && (cc != alt_cc))
1691         pkrb5_cc_close(ctx, cc);
1692     if (ctx && (ctx != alt_ctx))
1693         pkrb5_free_context(ctx);
1694     return(code);
1695 }
1696
1697 int
1698 KFW_kinit( krb5_context alt_ctx,
1699             krb5_ccache  alt_cc,
1700             HWND hParent,
1701             char *principal_name,
1702             char *password,
1703             krb5_deltat lifetime,
1704             DWORD                       forwardable,
1705             DWORD                       proxiable,
1706             krb5_deltat                 renew_life,
1707             DWORD                       addressless,
1708             DWORD                       publicIP
1709             )
1710 {
1711     krb5_error_code                     code = 0;
1712     krb5_context                        ctx = 0;
1713     krb5_ccache                         cc = 0;
1714     krb5_principal                      me = 0;
1715     char*                       name = 0;
1716     krb5_creds                          my_creds;
1717     krb5_get_init_creds_opt     options;
1718     krb5_address **             addrs = NULL;
1719     int                         i = 0, addr_count = 0;
1720
1721     if (!pkrb5_init_context)
1722         return 0;
1723
1724     pkrb5_get_init_creds_opt_init(&options);
1725     memset(&my_creds, 0, sizeof(my_creds));
1726
1727     if (alt_ctx)
1728     {
1729         ctx = alt_ctx;
1730     }
1731     else
1732     {
1733         code = pkrb5_init_context(&ctx);
1734         if (code) goto cleanup;
1735     }
1736
1737     if ( alt_cc ) {
1738         cc = alt_cc;
1739     } else {
1740         code = pkrb5_cc_default(ctx, &cc);  
1741         if (code) goto cleanup;
1742     }
1743
1744     code = pkrb5_parse_name(ctx, principal_name, &me);
1745     if (code) 
1746                 goto cleanup;
1747
1748     code = pkrb5_unparse_name(ctx, me, &name);
1749     if (code) 
1750                 goto cleanup;
1751
1752     if (lifetime == 0)
1753         lifetime = pLeash_get_default_lifetime();
1754     else
1755         lifetime *= 5*60;
1756
1757         if (renew_life > 0)
1758                 renew_life *= 5*60;
1759
1760     if (lifetime)
1761         pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1762         pkrb5_get_init_creds_opt_set_forwardable(&options,
1763                                                  forwardable ? 1 : 0);
1764         pkrb5_get_init_creds_opt_set_proxiable(&options,
1765                                                proxiable ? 1 : 0);
1766         pkrb5_get_init_creds_opt_set_renew_life(&options,
1767                                                renew_life);
1768     if (addressless)
1769         pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1770     else {
1771                 if (publicIP)
1772         {
1773             // we are going to add the public IP address specified by the user
1774             // to the list provided by the operating system
1775             krb5_address ** local_addrs=NULL;
1776             DWORD           netIPAddr;
1777
1778             pkrb5_os_localaddr(ctx, &local_addrs);
1779             while ( local_addrs[i++] );
1780             addr_count = i + 1;
1781
1782             addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1783             if ( !addrs ) {
1784                 pkrb5_free_addresses(ctx, local_addrs);
1785                 goto cleanup;
1786             }
1787             memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1788             i = 0;
1789             while ( local_addrs[i] ) {
1790                 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1791                 if (addrs[i] == NULL) {
1792                     pkrb5_free_addresses(ctx, local_addrs);
1793                     goto cleanup;
1794                 }
1795
1796                 addrs[i]->magic = local_addrs[i]->magic;
1797                 addrs[i]->addrtype = local_addrs[i]->addrtype;
1798                 addrs[i]->length = local_addrs[i]->length;
1799                 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1800                 if (!addrs[i]->contents) {
1801                     pkrb5_free_addresses(ctx, local_addrs);
1802                     goto cleanup;
1803                 }
1804
1805                 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1806                         local_addrs[i]->length);        /* safe */
1807                 i++;
1808             }
1809             pkrb5_free_addresses(ctx, local_addrs);
1810
1811             addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1812             if (addrs[i] == NULL)
1813                 goto cleanup;
1814
1815             addrs[i]->magic = KV5M_ADDRESS;
1816             addrs[i]->addrtype = AF_INET;
1817             addrs[i]->length = 4;
1818             addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1819             if (!addrs[i]->contents)
1820                 goto cleanup;
1821
1822             netIPAddr = htonl(publicIP);
1823             memcpy(addrs[i]->contents,&netIPAddr,4);
1824         
1825             pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1826
1827         }
1828     }
1829
1830     code = pkrb5_get_init_creds_password(ctx, 
1831                                        &my_creds, 
1832                                        me,
1833                                        password, // password
1834                                        KRB5_prompter, // prompter
1835                                        hParent, // prompter data
1836                                        0, // start time
1837                                        0, // service name
1838                                        &options);
1839     if (code) 
1840                 goto cleanup;
1841
1842     code = pkrb5_cc_initialize(ctx, cc, me);
1843     if (code) 
1844                 goto cleanup;
1845
1846     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1847     if (code) 
1848                 goto cleanup;
1849
1850  cleanup:
1851     if ( addrs ) {
1852         for ( i=0;i<addr_count;i++ ) {
1853             if ( addrs[i] ) {
1854                 if ( addrs[i]->contents )
1855                     free(addrs[i]->contents);
1856                 free(addrs[i]);
1857             }
1858         }
1859     }
1860     if (my_creds.client == me)
1861         my_creds.client = 0;
1862     pkrb5_free_cred_contents(ctx, &my_creds);
1863     if (name)
1864         pkrb5_free_unparsed_name(ctx, name);
1865     if (me)
1866         pkrb5_free_principal(ctx, me);
1867     if (cc && (cc != alt_cc))
1868         pkrb5_cc_close(ctx, cc);
1869     if (ctx && (ctx != alt_ctx))
1870         pkrb5_free_context(ctx);
1871     return(code);
1872 }
1873
1874
1875 int
1876 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
1877 {
1878     krb5_context                ctx;
1879     krb5_ccache                 cc;
1880     krb5_error_code             code;
1881
1882     if (!pkrb5_init_context)
1883         return 0;
1884
1885     if (alt_ctx)
1886     {
1887         ctx = alt_ctx;
1888     }
1889     else
1890     {
1891         code = pkrb5_init_context(&ctx);
1892         if (code) goto cleanup;
1893     }
1894
1895     if ( alt_cc ) {
1896         cc = alt_cc;
1897     } else {
1898         code = pkrb5_cc_default(ctx, &cc);  
1899         if (code) goto cleanup;
1900     }
1901
1902     code = pkrb5_cc_destroy(ctx, cc);
1903     if ( !code ) cc = 0;
1904
1905   cleanup:
1906     if (cc && (cc != alt_cc))
1907         pkrb5_cc_close(ctx, cc);
1908     if (ctx && (ctx != alt_ctx))
1909         pkrb5_free_context(ctx);
1910
1911     return(code);
1912 }
1913
1914
1915 #ifdef USE_MS2MIT
1916 static BOOL
1917 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1918 {
1919     NTSTATUS Status = 0;
1920     HANDLE  TokenHandle;
1921     TOKEN_STATISTICS Stats;
1922     DWORD   ReqLen;
1923     BOOL    Success;
1924
1925     if (!ppSessionData)
1926         return FALSE;
1927     *ppSessionData = NULL;
1928
1929     Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1930     if ( !Success )
1931         return FALSE;
1932
1933     Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1934     CloseHandle( TokenHandle );
1935     if ( !Success )
1936         return FALSE;
1937
1938     Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1939     if ( FAILED(Status) || !ppSessionData )
1940         return FALSE;
1941
1942     return TRUE;
1943 }
1944
1945 //
1946 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the 
1947 // cache.  It validates whether or not it is reasonable to assume that if we 
1948 // attempted to retrieve valid tickets we could do so.  Microsoft does not 
1949 // automatically renew expired tickets.  Therefore, the cache could contain
1950 // expired or invalid tickets.  Microsoft also caches the user's password 
1951 // and will use it to retrieve new TGTs if the cache is empty and tickets
1952 // are requested.
1953
1954 static BOOL
1955 MSLSA_IsKerberosLogon(VOID)
1956 {
1957     PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1958     BOOL    Success = FALSE;
1959
1960     if ( GetSecurityLogonSessionData(&pSessionData) ) {
1961         if ( pSessionData->AuthenticationPackage.Buffer ) {
1962             WCHAR buffer[256];
1963             WCHAR *usBuffer;
1964             int usLength;
1965
1966             Success = FALSE;
1967             usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1968             usLength = (pSessionData->AuthenticationPackage).Length;
1969             if (usLength < 256)
1970             {
1971                 lstrcpynW (buffer, usBuffer, usLength);
1972                 lstrcatW (buffer,L"");
1973                 if ( !lstrcmpW(L"Kerberos",buffer) )
1974                     Success = TRUE;
1975             }
1976         }
1977         pLsaFreeReturnBuffer(pSessionData);
1978     }
1979     return Success;
1980 }
1981 #endif /* USE_MS2MIT */
1982
1983 static BOOL CALLBACK 
1984 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1985 {
1986     int i;
1987
1988     switch ( message ) {
1989     case WM_INITDIALOG:
1990         if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1991         {
1992             SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1993             return FALSE;
1994         }
1995                 for ( i=0; i < mid_cnt ; i++ ) {
1996                         if (mid_tb[i].echo == 0)
1997                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1998                     else if (mid_tb[i].echo == 2) 
1999                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2000                 }
2001         return TRUE;
2002
2003     case WM_COMMAND:
2004         switch ( LOWORD(wParam) ) {
2005         case IDOK:
2006             for ( i=0; i < mid_cnt ; i++ ) {
2007                 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2008                     *mid_tb[i].buf = '\0';
2009             }
2010             /* fallthrough */
2011         case IDCANCEL:
2012             EndDialog(hDialog, LOWORD(wParam));
2013             return TRUE;
2014         }
2015     }
2016     return FALSE;
2017 }
2018
2019 static LPWORD 
2020 lpwAlign( LPWORD lpIn )
2021 {
2022     ULONG ul;
2023
2024     ul = (ULONG) lpIn;
2025     ul += 3;
2026     ul >>=2;
2027     ul <<=2;
2028     return (LPWORD) ul;;
2029 }
2030
2031 /*
2032  * dialog widths are measured in 1/4 character widths
2033  * dialog height are measured in 1/8 character heights
2034  */
2035
2036 static LRESULT
2037 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 
2038                   char * ptext[], int numlines, int width, 
2039                   int tb_cnt, struct textField * tb)
2040 {
2041     HGLOBAL hgbl;
2042     LPDLGTEMPLATE lpdt;
2043     LPDLGITEMTEMPLATE lpdit;
2044     LPWORD lpw;
2045     LPWSTR lpwsz;
2046     LRESULT ret;
2047     int nchar, i, pwid;
2048
2049     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2050     if (!hgbl)
2051         return -1;
2052  
2053     mid_cnt = tb_cnt;
2054     mid_tb = tb;
2055
2056     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2057  
2058     // Define a dialog box.
2059  
2060     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2061                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
2062                    | DS_SETFOREGROUND | DS_3DLOOK
2063                    | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2064     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
2065     lpdt->x  = 10;  
2066     lpdt->y  = 10;
2067     lpdt->cx = 20 + width * 4; 
2068     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2069
2070     lpw = (LPWORD) (lpdt + 1);
2071     *lpw++ = 0;   // no menu
2072     *lpw++ = 0;   // predefined dialog box class (by default)
2073
2074     lpwsz = (LPWSTR) lpw;
2075     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2076     lpw   += nchar;
2077     *lpw++ = 8;                        // font size (points)
2078     lpwsz = (LPWSTR) lpw;
2079     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
2080                                     -1, lpwsz, 128);
2081     lpw   += nchar;
2082
2083     //-----------------------
2084     // Define an OK button.
2085     //-----------------------
2086     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2087     lpdit = (LPDLGITEMTEMPLATE) lpw;
2088     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2089     lpdit->dwExtendedStyle = 0;
2090     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
2091     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2092     lpdit->cx = 40; 
2093     lpdit->cy = 14;
2094     lpdit->id = IDOK;  // OK button identifier
2095
2096     lpw = (LPWORD) (lpdit + 1);
2097     *lpw++ = 0xFFFF;
2098     *lpw++ = 0x0080;    // button class
2099
2100     lpwsz = (LPWSTR) lpw;
2101     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2102     lpw   += nchar;
2103     *lpw++ = 0;           // no creation data
2104
2105     //-----------------------
2106     // Define an Cancel button.
2107     //-----------------------
2108     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2109     lpdit = (LPDLGITEMTEMPLATE) lpw;
2110     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2111     lpdit->dwExtendedStyle = 0;
2112     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
2113     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2114     lpdit->cx = 40; 
2115     lpdit->cy = 14;
2116     lpdit->id = IDCANCEL;  // CANCEL button identifier
2117
2118     lpw = (LPWORD) (lpdit + 1);
2119     *lpw++ = 0xFFFF;
2120     *lpw++ = 0x0080;    // button class
2121
2122     lpwsz = (LPWSTR) lpw;
2123     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2124     lpw   += nchar;
2125     *lpw++ = 0;           // no creation data
2126
2127     /* Add controls for preface data */
2128     for ( i=0; i<numlines; i++) {
2129         /*-----------------------
2130          * Define a static text control.
2131          *-----------------------*/
2132         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2133         lpdit = (LPDLGITEMTEMPLATE) lpw;
2134         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2135         lpdit->dwExtendedStyle = 0;
2136         lpdit->x  = 10; 
2137         lpdit->y  = 10 + i * 14;
2138         lpdit->cx = strlen(ptext[i]) * 4 + 10; 
2139         lpdit->cy = 14;
2140         lpdit->id = ID_TEXT + i;  // text identifier
2141
2142         lpw = (LPWORD) (lpdit + 1);
2143         *lpw++ = 0xFFFF;
2144         *lpw++ = 0x0082;                         // static class
2145
2146         lpwsz = (LPWSTR) lpw;
2147         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
2148                                          -1, lpwsz, 2*width);
2149         lpw   += nchar;
2150         *lpw++ = 0;           // no creation data
2151     }
2152     
2153     for ( i=0, pwid = 0; i<tb_cnt; i++) {
2154         if ( pwid < strlen(tb[i].label) )
2155             pwid = strlen(tb[i].label);
2156     }
2157
2158     for ( i=0; i<tb_cnt; i++) {
2159         /* Prompt */
2160         /*-----------------------
2161          * Define a static text control.
2162          *-----------------------*/
2163         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2164         lpdit = (LPDLGITEMTEMPLATE) lpw;
2165         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2166         lpdit->dwExtendedStyle = 0;
2167         lpdit->x  = 10; 
2168         lpdit->y  = 10 + (numlines + i + 1) * 14;
2169         lpdit->cx = pwid * 4; 
2170         lpdit->cy = 14;
2171         lpdit->id = ID_TEXT + numlines + i;  // text identifier
2172
2173         lpw = (LPWORD) (lpdit + 1);
2174         *lpw++ = 0xFFFF;
2175         *lpw++ = 0x0082;                         // static class
2176
2177         lpwsz = (LPWSTR) lpw;
2178         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 
2179                                      -1, lpwsz, 128);
2180         lpw   += nchar;
2181         *lpw++ = 0;           // no creation data
2182
2183         /*-----------------------
2184          * Define an edit control.
2185          *-----------------------*/
2186         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2187         lpdit = (LPDLGITEMTEMPLATE) lpw;
2188         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2189         lpdit->dwExtendedStyle = 0;
2190         lpdit->x  = 10 + (pwid + 1) * 4; 
2191         lpdit->y  = 10 + (numlines + i + 1) * 14;
2192         lpdit->cx = (width - (pwid + 1)) * 4; 
2193         lpdit->cy = 14;
2194         lpdit->id = ID_MID_TEXT + i;             // identifier
2195
2196         lpw = (LPWORD) (lpdit + 1);
2197         *lpw++ = 0xFFFF;
2198         *lpw++ = 0x0081;                         // edit class
2199
2200         lpwsz = (LPWSTR) lpw;
2201         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 
2202                                      -1, lpwsz, 128);
2203         lpw   += nchar;
2204         *lpw++ = 0;           // no creation data
2205     }
2206
2207     GlobalUnlock(hgbl); 
2208     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
2209                                                         hwndOwner, (DLGPROC) MultiInputDialogProc); 
2210     GlobalFree(hgbl); 
2211
2212     switch ( ret ) {
2213     case 0:     /* Timeout */
2214         return -1;
2215     case IDOK:
2216         return 1;
2217     case IDCANCEL:
2218         return 0;
2219     default: {
2220         char buf[256];
2221         sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2222         MessageBox(hwndOwner,
2223                     buf,
2224                     "GetLastError()",
2225                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2226         return -1;
2227     }
2228     }
2229 }
2230
2231 static int
2232 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2233 {
2234         HINSTANCE hInst = 0;
2235     int maxwidth = 0;
2236     int numlines = 0;
2237     int len;
2238     char * plines[16], *p = preface ? preface : "";
2239     int i;
2240
2241     for ( i=0; i<16; i++ ) 
2242         plines[i] = NULL;
2243
2244     while (*p && numlines < 16) {
2245         plines[numlines++] = p;
2246         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2247         if ( *p == '\r' && *(p+1) == '\n' ) {
2248             *p++ = '\0';
2249             p++;
2250         } else if ( *p == '\n' ) {
2251             *p++ = '\0';
2252         } 
2253         if ( strlen(plines[numlines-1]) > maxwidth )
2254             maxwidth = strlen(plines[numlines-1]);
2255     }
2256
2257     for ( i=0;i<n;i++ ) {
2258         len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2259         if ( maxwidth < len )
2260             maxwidth = len;
2261     }
2262
2263     return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2264 }
2265
2266 static krb5_error_code KRB5_CALLCONV
2267 KRB5_prompter( krb5_context context,
2268                void *data,
2269                const char *name,
2270                const char *banner,
2271                int num_prompts,
2272                krb5_prompt prompts[])
2273 {
2274     krb5_error_code     errcode = 0;
2275     int                 i;
2276     struct textField * tb = NULL;
2277     int    len = 0, blen=0, nlen=0;
2278         HWND hParent = (HWND)data;
2279
2280     if (name)
2281         nlen = strlen(name)+2;
2282
2283     if (banner)
2284         blen = strlen(banner)+2;
2285
2286     tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2287     if ( tb != NULL ) {
2288         int ok;
2289         memset(tb,0,sizeof(struct textField) * num_prompts);
2290         for ( i=0; i < num_prompts; i++ ) {
2291             tb[i].buf = prompts[i].reply->data;
2292             tb[i].len = prompts[i].reply->length;
2293             tb[i].label = prompts[i].prompt;
2294             tb[i].def = NULL;
2295             tb[i].echo = (prompts[i].hidden ? 2 : 1);
2296         }   
2297
2298         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2299         if ( ok ) {
2300             for ( i=0; i < num_prompts; i++ )
2301                 prompts[i].reply->length = strlen(prompts[i].reply->data);
2302         } else
2303             errcode = -2;
2304     }
2305
2306     if ( tb )
2307         free(tb);
2308     if (errcode) {
2309         for (i = 0; i < num_prompts; i++) {
2310             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2311         }
2312     }
2313     return errcode;
2314 }
2315
2316 BOOL
2317 KFW_AFS_wait_for_service_start(void)
2318 {
2319     char    HostName[64];
2320     DWORD   CurrentState;
2321
2322     CurrentState = SERVICE_START_PENDING;
2323     memset(HostName, '\0', sizeof(HostName));
2324     gethostname(HostName, sizeof(HostName));
2325
2326     while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2327     {
2328         if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2329             return(0);
2330         if ( IsDebuggerPresent() ) {
2331             switch ( CurrentState ) {
2332             case SERVICE_STOPPED:
2333                 OutputDebugString("SERVICE_STOPPED\n");
2334                 break;
2335             case SERVICE_START_PENDING:
2336                 OutputDebugString("SERVICE_START_PENDING\n");
2337                 break;
2338             case SERVICE_STOP_PENDING:
2339                 OutputDebugString("SERVICE_STOP_PENDING\n");
2340                 break;
2341             case SERVICE_RUNNING:
2342                 OutputDebugString("SERVICE_RUNNING\n");
2343                 break;
2344             case SERVICE_CONTINUE_PENDING:
2345                 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2346                 break;
2347             case SERVICE_PAUSE_PENDING:
2348                 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2349                 break;
2350             case SERVICE_PAUSED:
2351                 OutputDebugString("SERVICE_PAUSED\n");
2352                 break;
2353             default:
2354                 OutputDebugString("UNKNOWN Service State\n");
2355             }
2356         }
2357         if (CurrentState == SERVICE_STOPPED)
2358             return(0);
2359         if (CurrentState == SERVICE_RUNNING)
2360             return(1);
2361         Sleep(500);
2362     }
2363     return(0);
2364 }
2365
2366
2367 int
2368 KFW_AFS_unlog(void)
2369 {
2370     long        rc;
2371     char    HostName[64];
2372     DWORD   CurrentState;
2373
2374     CurrentState = 0;
2375     memset(HostName, '\0', sizeof(HostName));
2376     gethostname(HostName, sizeof(HostName));
2377     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2378         return(0);
2379     if (CurrentState != SERVICE_RUNNING)
2380         return(0);
2381
2382     rc = pktc_ForgetAllTokens();
2383
2384     return(0);
2385 }
2386
2387
2388 #define TKTLIFENUMFIXED 64
2389 #define TKTLIFEMINFIXED 0x80
2390 #define TKTLIFEMAXFIXED 0xBF
2391 #define TKTLIFENOEXPIRE 0xFF
2392 #define MAXTKTLIFETIME  (30*24*3600)    /* 30 days */
2393 #ifndef NEVERDATE
2394 #define NEVERDATE ((unsigned long)0x7fffffffL)
2395 #endif
2396
2397 static int no_long_lifetimes = 0;
2398 typedef unsigned long u_int32_t;
2399
2400 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
2401     38400,                              /* 10.67 hours, 0.44 days */ 
2402     41055,                              /* 11.40 hours, 0.48 days */ 
2403     43894,                              /* 12.19 hours, 0.51 days */ 
2404     46929,                              /* 13.04 hours, 0.54 days */ 
2405     50174,                              /* 13.94 hours, 0.58 days */ 
2406     53643,                              /* 14.90 hours, 0.62 days */ 
2407     57352,                              /* 15.93 hours, 0.66 days */ 
2408     61318,                              /* 17.03 hours, 0.71 days */ 
2409     65558,                              /* 18.21 hours, 0.76 days */ 
2410     70091,                              /* 19.47 hours, 0.81 days */ 
2411     74937,                              /* 20.82 hours, 0.87 days */ 
2412     80119,                              /* 22.26 hours, 0.93 days */ 
2413     85658,                              /* 23.79 hours, 0.99 days */ 
2414     91581,                              /* 25.44 hours, 1.06 days */ 
2415     97914,                              /* 27.20 hours, 1.13 days */ 
2416     104684,                             /* 29.08 hours, 1.21 days */ 
2417     111922,                             /* 31.09 hours, 1.30 days */ 
2418     119661,                             /* 33.24 hours, 1.38 days */ 
2419     127935,                             /* 35.54 hours, 1.48 days */ 
2420     136781,                             /* 37.99 hours, 1.58 days */ 
2421     146239,                             /* 40.62 hours, 1.69 days */ 
2422     156350,                             /* 43.43 hours, 1.81 days */ 
2423     167161,                             /* 46.43 hours, 1.93 days */ 
2424     178720,                             /* 49.64 hours, 2.07 days */ 
2425     191077,                             /* 53.08 hours, 2.21 days */ 
2426     204289,                             /* 56.75 hours, 2.36 days */ 
2427     218415,                             /* 60.67 hours, 2.53 days */ 
2428     233517,                             /* 64.87 hours, 2.70 days */ 
2429     249664,                             /* 69.35 hours, 2.89 days */ 
2430     266926,                             /* 74.15 hours, 3.09 days */ 
2431     285383,                             /* 79.27 hours, 3.30 days */ 
2432     305116,                             /* 84.75 hours, 3.53 days */ 
2433     326213,                             /* 90.61 hours, 3.78 days */ 
2434     348769,                             /* 96.88 hours, 4.04 days */ 
2435     372885,                             /* 103.58 hours, 4.32 days */ 
2436     398668,                             /* 110.74 hours, 4.61 days */ 
2437     426234,                             /* 118.40 hours, 4.93 days */ 
2438     455705,                             /* 126.58 hours, 5.27 days */ 
2439     487215,                             /* 135.34 hours, 5.64 days */ 
2440     520904,                             /* 144.70 hours, 6.03 days */ 
2441     556921,                             /* 154.70 hours, 6.45 days */ 
2442     595430,                             /* 165.40 hours, 6.89 days */ 
2443     636601,                             /* 176.83 hours, 7.37 days */ 
2444     680618,                             /* 189.06 hours, 7.88 days */ 
2445     727680,                             /* 202.13 hours, 8.42 days */ 
2446     777995,                             /* 216.11 hours, 9.00 days */ 
2447     831789,                             /* 231.05 hours, 9.63 days */ 
2448     889303,                             /* 247.03 hours, 10.29 days */
2449
2450     950794,                             /* 264.11 hours, 11.00 days */
2451
2452     1016537,                            /* 282.37 hours, 11.77 days */
2453
2454     1086825,                            /* 301.90 hours, 12.58 days */
2455
2456     1161973,                            /* 322.77 hours, 13.45 days */
2457
2458     1242318,                            /* 345.09 hours, 14.38 days */
2459
2460     1328218,                            /* 368.95 hours, 15.37 days */
2461
2462     1420057,                            /* 394.46 hours, 16.44 days */
2463
2464     1518247,                            /* 421.74 hours, 17.57 days */
2465
2466     1623226,                            /* 450.90 hours, 18.79 days */
2467
2468     1735464,                            /* 482.07 hours, 20.09 days */
2469
2470     1855462,                            /* 515.41 hours, 21.48 days */
2471
2472     1983758,                            /* 551.04 hours, 22.96 days */
2473
2474     2120925,                            /* 589.15 hours, 24.55 days */
2475
2476     2267576,                            /* 629.88 hours, 26.25 days */
2477
2478     2424367,                            /* 673.44 hours, 28.06 days */
2479
2480     2592000};                           /* 720.00 hours, 30.00 days */
2481
2482
2483 int
2484 KFW_AFS_klog(
2485     krb5_context alt_ctx,
2486     krb5_ccache  alt_cc,
2487     char *service,
2488     char *cell,
2489     char *realm,
2490     int LifeTime
2491     )
2492 {
2493     long        rc = 0;
2494     CREDENTIALS creds;
2495     KTEXT_ST    ticket;
2496     struct ktc_principal        aserver;
2497     struct ktc_principal        aclient;
2498     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2499     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2500     char        local_cell[MAXCELLCHARS+1];
2501     char        Dmycell[MAXCELLCHARS+1];
2502     struct ktc_token    atoken;
2503     struct ktc_token    btoken;
2504     afsconf_cell        ak_cellconfig; /* General information about the cell */
2505     char        RealmName[128];
2506     char        CellName[128];
2507     char        ServiceName[128];
2508     DWORD       CurrentState;
2509     char        HostName[64];
2510     BOOL        try_krb5 = 0;
2511     krb5_context  ctx = 0;
2512     krb5_ccache   cc = 0;
2513     krb5_creds increds;
2514     krb5_creds * k5creds = 0;
2515     krb5_error_code code;
2516     krb5_principal client_principal = 0;
2517     char * cname = 0, *sname = 0;
2518     int i, retry = 0;
2519
2520     CurrentState = 0;
2521     memset(HostName, '\0', sizeof(HostName));
2522     gethostname(HostName, sizeof(HostName));
2523     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2524         if ( IsDebuggerPresent() )
2525             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2526         return(-1);
2527     }
2528     if (CurrentState != SERVICE_RUNNING) {
2529         if ( IsDebuggerPresent() )
2530             OutputDebugString("AFSD Service NOT RUNNING\n");
2531         return(-2);
2532     }
2533
2534     if (!pkrb5_init_context)
2535         return 0;
2536
2537     memset(RealmName, '\0', sizeof(RealmName));
2538     memset(CellName, '\0', sizeof(CellName));
2539     memset(ServiceName, '\0', sizeof(ServiceName));
2540     memset(realm_of_user, '\0', sizeof(realm_of_user));
2541     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2542         if (cell && cell[0])
2543                 strcpy(Dmycell, cell);
2544         else
2545                 memset(Dmycell, '\0', sizeof(Dmycell));
2546
2547     // NULL or empty cell returns information on local cell
2548     if (rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2549     {
2550         // KFW_AFS_error(rc, "get_cellconfig()");
2551         return(rc);
2552     }
2553
2554     if ( alt_ctx ) {
2555         ctx = alt_ctx;
2556     } else {
2557         code = pkrb5_init_context(&ctx);
2558         if (code) goto cleanup;
2559     }
2560
2561     if ( alt_cc ) {
2562         cc = alt_cc;
2563     } else {
2564         code = pkrb5_cc_default(ctx, &cc);
2565         if (code) goto skip_krb5_init;
2566     }
2567
2568     memset((char *)&increds, 0, sizeof(increds));
2569
2570     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2571         if (code) {
2572         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
2573         {
2574             OutputDebugString("Principal Not Found for ccache\n");
2575         }
2576         goto skip_krb5_init;
2577     }
2578     i = krb5_princ_realm(ctx, client_principal)->length;
2579     if (i > REALM_SZ-1) 
2580         i = REALM_SZ-1;
2581     strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2582     realm_of_user[i] = 0;
2583     try_krb5 = 1;
2584
2585   skip_krb5_init:
2586 #ifdef USE_KRB4
2587     if ( !try_krb5 || !realm_of_user[0] ) {
2588         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2589         {
2590             goto cleanup;
2591         }       
2592     }
2593 #else
2594     goto cleanup;
2595 #endif
2596     strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
2597
2598     if (strlen(service) == 0)
2599         strcpy(ServiceName, "afs");
2600     else
2601         strcpy(ServiceName, service);
2602
2603     if (strlen(cell) == 0)
2604         strcpy(CellName, local_cell);
2605     else
2606         strcpy(CellName, cell);
2607
2608     if (strlen(realm) == 0)
2609         strcpy(RealmName, realm_of_cell);
2610     else
2611         strcpy(RealmName, realm);
2612
2613     memset(&creds, '\0', sizeof(creds));
2614
2615     if ( try_krb5 ) {
2616         int i, len;
2617         char *p;
2618
2619         /* First try service/cell@REALM */
2620         if (code = pkrb5_build_principal(ctx, &increds.server,
2621                                           strlen(RealmName),
2622                                           RealmName,
2623                                           ServiceName,
2624                                           CellName,
2625                                           0)) 
2626         {
2627             goto cleanup;
2628         }
2629
2630         increds.client = client_principal;
2631         increds.times.endtime = 0;
2632         /* Ask for DES since that is what V4 understands */
2633         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2634
2635
2636         if ( IsDebuggerPresent() ) {
2637             pkrb5_unparse_name(ctx, increds.client, &cname);
2638             pkrb5_unparse_name(ctx, increds.server, &sname);
2639             OutputDebugString("Getting tickets for \"");
2640             OutputDebugString(cname);
2641             OutputDebugString("\" and service \"");
2642             OutputDebugString(sname);
2643             OutputDebugString("\"\n");
2644             cname = sname = 0;
2645         }
2646
2647         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2648         if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2649              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2650                          code == KRB5KRB_AP_ERR_MSG_TYPE) {
2651             /* Or service@REALM */
2652             pkrb5_free_principal(ctx,increds.server);
2653             increds.server = 0;
2654             code = pkrb5_build_principal(ctx, &increds.server,
2655                                           strlen(RealmName),
2656                                           RealmName,
2657                                           ServiceName,
2658                                           0);
2659
2660             if ( IsDebuggerPresent() ) {
2661                 char * cname, *sname;
2662                 pkrb5_unparse_name(ctx, increds.client, &cname);
2663                 pkrb5_unparse_name(ctx, increds.server, &sname);
2664                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2665                 OutputDebugString("Trying again: getting tickets for \"");
2666                 OutputDebugString(cname);
2667                 OutputDebugString("\" and service \"");
2668                 OutputDebugString(sname);
2669                 OutputDebugString("\"\n");
2670                 pkrb5_free_unparsed_name(ctx,cname);
2671                 pkrb5_free_unparsed_name(ctx,sname);
2672                 cname = sname = 0;
2673             }
2674
2675             if (!code)
2676                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2677         }
2678
2679         if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2680               code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2681                           code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2682              strcmp(RealmName, realm_of_cell)) {
2683             /* Or service/cell@REALM_OF_CELL */
2684             strcpy(RealmName, realm_of_cell);
2685             pkrb5_free_principal(ctx,increds.server);
2686             increds.server = 0;
2687             code = pkrb5_build_principal(ctx, &increds.server,
2688                                          strlen(RealmName),
2689                                          RealmName,
2690                                          ServiceName,
2691                                          CellName,
2692                                          0);
2693
2694             if ( IsDebuggerPresent() ) {
2695                 char * cname, *sname;
2696                 pkrb5_unparse_name(ctx, increds.client, &cname);
2697                 pkrb5_unparse_name(ctx, increds.server, &sname);
2698                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2699                 OutputDebugString("Trying again: getting tickets for \"");
2700                 OutputDebugString(cname);
2701                 OutputDebugString("\" and service \"");
2702                 OutputDebugString(sname);
2703                 OutputDebugString("\"\n");
2704                 pkrb5_free_unparsed_name(ctx,cname);
2705                 pkrb5_free_unparsed_name(ctx,sname);
2706                 cname = sname = 0;
2707             }
2708
2709             if (!code)
2710                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2711
2712         
2713             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2714                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2715                                  code == KRB5KRB_AP_ERR_MSG_TYPE) {
2716                 /* Or service@REALM_OF_CELL */
2717                 pkrb5_free_principal(ctx,increds.server);
2718                 increds.server = 0;
2719                 code = pkrb5_build_principal(ctx, &increds.server,
2720                                               strlen(RealmName),
2721                                               RealmName,
2722                                               ServiceName,
2723                                               0);
2724
2725                 if ( IsDebuggerPresent() ) {
2726                     char * cname, *sname;
2727                     pkrb5_unparse_name(ctx, increds.client, &cname);
2728                     pkrb5_unparse_name(ctx, increds.server, &sname);
2729                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2730                     OutputDebugString("Trying again: getting tickets for \"");
2731                     OutputDebugString(cname);
2732                     OutputDebugString("\" and service \"");
2733                     OutputDebugString(sname);
2734                     OutputDebugString("\"\n");
2735                     pkrb5_free_unparsed_name(ctx,cname);
2736                     pkrb5_free_unparsed_name(ctx,sname);
2737                     cname = sname = 0;
2738                 }
2739
2740                 if (!code)
2741                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2742             }
2743         }
2744
2745         if (code) {
2746             if ( IsDebuggerPresent() ) {
2747                 char message[256];
2748                 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2749                 OutputDebugString(message);
2750             }
2751             try_krb5 = 0;
2752             goto use_krb4;
2753         }
2754
2755         /* This code inserts the entire K5 ticket into the token
2756          * No need to perform a krb524 translation which is 
2757          * commented out in the code below
2758          */
2759         if (k5creds->ticket.length > MAXKTCTICKETLEN)
2760             goto try_krb524d;
2761
2762         memset(&aserver, '\0', sizeof(aserver));
2763         strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2764         strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2765
2766         memset(&atoken, '\0', sizeof(atoken));
2767         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2768         atoken.startTime = k5creds->times.starttime;
2769         atoken.endTime = k5creds->times.endtime;
2770         memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2771         atoken.ticketLen = k5creds->ticket.length;
2772         memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2773
2774       retry_gettoken5:
2775         rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2776         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2777             if ( rc == KTC_NOCM && retry < 20 ) {
2778                 Sleep(500);
2779                 retry++;
2780                 goto retry_gettoken5;
2781             }
2782             goto try_krb524d;
2783         }
2784
2785         if (atoken.kvno == btoken.kvno &&
2786              atoken.ticketLen == btoken.ticketLen &&
2787              !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2788              !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
2789         {
2790             /* Success - Nothing to do */
2791             goto cleanup;
2792         }
2793
2794         // * Reset the "aclient" structure before we call ktc_SetToken.
2795         // * This structure was first set by the ktc_GetToken call when
2796         // * we were comparing whether identical tokens already existed.
2797
2798         len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2799         strncpy(aclient.name, k5creds->client->data[0].data, len);
2800         aclient.name[len] = '\0';
2801
2802         if ( k5creds->client->length > 1 ) {
2803             len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - 1);
2804             strncpy(aclient.instance, k5creds->client->data[1].data, len);
2805             aclient.instance[len] = '\0';
2806         } else
2807             aclient.instance[0] = '\0';
2808         len = min(k5creds->client->realm.length,MAXKTCNAMELEN - 1);
2809             for ( i=0; i<len; i++ ) {
2810                         aclient.cell[i] = tolower(k5creds->client->realm.data[i]);
2811                 }
2812         aclient.cell[len] = '\0';
2813                 aclient.smbname[0] = '\0';
2814
2815         rc = pktc_SetToken(&aserver, &atoken, &aclient, 0);
2816         if (!rc)
2817             goto cleanup;   /* We have successfully inserted the token */
2818
2819       try_krb524d:
2820         /* Otherwise, the ticket could have been too large so try to
2821          * convert using the krb524d running with the KDC 
2822          */
2823         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2824         pkrb5_free_creds(ctx, k5creds);
2825         if (code) {
2826             if ( IsDebuggerPresent() ) {
2827                 char message[256];
2828                 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2829                 OutputDebugString(message);
2830             }
2831             try_krb5 = 0;
2832             goto use_krb4;
2833         }
2834     } else {
2835       use_krb4:
2836 #ifdef USE_KRB4
2837         code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
2838         if (code == NO_TKT_FIL) {
2839             // if the problem is that we have no krb4 tickets
2840             // do not attempt to continue
2841             goto cleanup;
2842         }
2843         if (code != KSUCCESS)
2844             code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
2845
2846         if (code != KSUCCESS)
2847         {
2848             if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
2849             {
2850                 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
2851                 {
2852                     goto cleanup;
2853                 }
2854             }
2855             else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
2856             {
2857                 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
2858                 {
2859                     goto cleanup;
2860                 }
2861             }
2862             else
2863             {
2864                 goto cleanup;
2865             }
2866         }
2867 #else
2868         goto cleanup;
2869 #endif
2870     }
2871
2872     memset(&aserver, '\0', sizeof(aserver));
2873     strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2874     strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2875
2876     memset(&atoken, '\0', sizeof(atoken));
2877     atoken.kvno = creds.kvno;
2878     atoken.startTime = creds.issue_date;
2879     atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
2880     memcpy(&atoken.sessionKey, creds.session, 8);
2881     atoken.ticketLen = creds.ticket_st.length;
2882     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
2883
2884   retry_gettoken:
2885     rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2886     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2887         if ( rc == KTC_NOCM && retry < 20 ) {
2888             Sleep(500);
2889             retry++;
2890             goto retry_gettoken;
2891         }
2892         KFW_AFS_error(rc, "ktc_GetToken()");
2893         code = rc;
2894         goto cleanup;
2895     }
2896
2897     if (atoken.kvno == btoken.kvno &&
2898         atoken.ticketLen == btoken.ticketLen &&
2899         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2900         !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
2901     {
2902         goto cleanup;
2903     }
2904
2905     // * Reset the "aclient" structure before we call ktc_SetToken.
2906     // * This structure was first set by the ktc_GetToken call when
2907     // * we were comparing whether identical tokens already existed.
2908
2909     strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
2910     strcpy(aclient.instance, creds.pinst);
2911     strncpy(aclient.cell, creds.realm, MAXKTCREALMLEN - 1);
2912
2913     if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0))
2914     {
2915         KFW_AFS_error(rc, "ktc_SetToken()");
2916         code = rc;
2917         goto cleanup;
2918     }
2919
2920   cleanup:
2921     if (cname)
2922         pkrb5_free_unparsed_name(ctx,cname);
2923     if (sname)
2924         pkrb5_free_unparsed_name(ctx,sname);
2925     if (client_principal)
2926         pkrb5_free_principal(ctx,client_principal);
2927     /* increds.client == client_principal */
2928     if (increds.server)
2929         pkrb5_free_principal(ctx,increds.server);
2930     if (cc && (cc != alt_cc))
2931         pkrb5_cc_close(ctx, cc);
2932     if (ctx && (ctx != alt_ctx))
2933         pkrb5_free_context(ctx);
2934
2935         return(rc? rc : code);
2936 }
2937
2938 /**************************************/
2939 /* afs_realm_of_cell():               */
2940 /**************************************/
2941 static char *
2942 afs_realm_of_cell(afsconf_cell *cellconfig)
2943 {
2944     static char krbrlm[REALM_SZ+1]="";
2945     krb5_context  ctx = 0;
2946     char ** realmlist=NULL;
2947     krb5_error_code r;
2948
2949     if (!cellconfig)
2950         return 0;
2951
2952     if (!pkrb5_init_context)
2953         return 0;
2954
2955     r = pkrb5_init_context(&ctx); 
2956     if ( !r )
2957         r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
2958     if ( !r && realmlist && realmlist[0] ) {
2959         strcpy(krbrlm, realmlist[0]);
2960         pkrb5_free_host_realm(ctx, realmlist);
2961     }
2962     if (ctx)
2963         pkrb5_free_context(ctx);
2964
2965     if ( !krbrlm[0] )
2966     {
2967         char *s = krbrlm;
2968         char *t = cellconfig->name;
2969         int c;
2970
2971         while (c = *t++)
2972         {
2973             if (islower(c)) c=toupper(c);
2974             *s++ = c;
2975         }
2976         *s++ = 0;
2977     }
2978     return(krbrlm);
2979 }
2980
2981 /**************************************/
2982 /* get_cellconfig():                  */
2983 /**************************************/
2984 static int 
2985 get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell)
2986 {
2987     int rc;
2988     char newcell[MAXCELLCHARS+1];
2989
2990     local_cell[0] = (char)0;
2991     memset(cellconfig, 0, sizeof(*cellconfig));
2992
2993     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2994     if (rc = pcm_GetRootCellName(local_cell))
2995     {
2996         return(rc);
2997     }
2998
2999     if (strlen(cell) == 0)
3000         strcpy(cell, local_cell);
3001
3002     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3003     strcpy(cellconfig->name, cell);
3004
3005     return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3006 }
3007
3008 /**************************************/
3009 /* get_cellconfig_callback():         */
3010 /**************************************/
3011 static long 
3012 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3013 {
3014     afsconf_cell *cc = (afsconf_cell *)cellconfig;
3015
3016     cc->hostAddr[cc->numServers] = *addrp;
3017     strcpy(cc->hostName[cc->numServers], namep);
3018     cc->numServers++;
3019     return(0);
3020 }
3021
3022
3023 /**************************************/
3024 /* KFW_AFS_error():                  */
3025 /**************************************/
3026 void
3027 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3028 {
3029     char message[256];
3030     const char *errText; 
3031
3032     // Using AFS defines as error messages for now, until Transarc 
3033     // gets back to me with "string" translations of each of these 
3034     // const. defines. 
3035     if (rc == KTC_ERROR)
3036       errText = "KTC_ERROR";
3037     else if (rc == KTC_TOOBIG)
3038       errText = "KTC_TOOBIG";
3039     else if (rc == KTC_INVAL)
3040       errText = "KTC_INVAL";
3041     else if (rc == KTC_NOENT)
3042       errText = "KTC_NOENT";
3043     else if (rc == KTC_PIOCTLFAIL)
3044       errText = "KTC_PIOCTLFAIL";
3045     else if (rc == KTC_NOPIOCTL)
3046       errText = "KTC_NOPIOCTL";
3047     else if (rc == KTC_NOCELL)
3048       errText = "KTC_NOCELL";
3049     else if (rc == KTC_NOCM)
3050       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3051     else
3052       errText = "Unknown error!";
3053
3054     sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3055
3056     if ( IsDebuggerPresent() ) {
3057         OutputDebugString(message);
3058         OutputDebugString("\n");
3059     }
3060     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3061     return;
3062 }
3063
3064 static DWORD 
3065 GetServiceStatus(
3066     LPSTR lpszMachineName, 
3067     LPSTR lpszServiceName,
3068     DWORD *lpdwCurrentState) 
3069
3070     DWORD           hr               = NOERROR; 
3071     SC_HANDLE       schSCManager     = NULL; 
3072     SC_HANDLE       schService       = NULL; 
3073     DWORD           fdwDesiredAccess = 0; 
3074     SERVICE_STATUS  ssServiceStatus  = {0}; 
3075     BOOL            fRet             = FALSE; 
3076
3077     *lpdwCurrentState = 0; 
3078  
3079     fdwDesiredAccess = GENERIC_READ; 
3080  
3081     schSCManager = OpenSCManager(lpszMachineName,  
3082                                  NULL,
3083                                  fdwDesiredAccess); 
3084  
3085     if(schSCManager == NULL) 
3086     { 
3087         hr = GetLastError();
3088         goto cleanup; 
3089     } 
3090  
3091     schService = OpenService(schSCManager,
3092                              lpszServiceName,
3093                              fdwDesiredAccess); 
3094  
3095     if(schService == NULL) 
3096     { 
3097         hr = GetLastError();
3098         goto cleanup; 
3099     } 
3100  
3101     fRet = QueryServiceStatus(schService,
3102                               &ssServiceStatus); 
3103  
3104     if(fRet == FALSE) 
3105     { 
3106         hr = GetLastError(); 
3107         goto cleanup; 
3108     } 
3109  
3110     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
3111  
3112 cleanup: 
3113  
3114     CloseServiceHandle(schService); 
3115     CloseServiceHandle(schSCManager); 
3116  
3117     return(hr); 
3118
3119
3120 void
3121 UnloadFuncs(
3122     FUNC_INFO fi[], 
3123     HINSTANCE h
3124     )
3125 {
3126     int n;
3127     if (fi)
3128         for (n = 0; fi[n].func_ptr_var; n++)
3129             *(fi[n].func_ptr_var) = 0;
3130     if (h) FreeLibrary(h);
3131 }
3132
3133 int
3134 LoadFuncs(
3135     const char* dll_name, 
3136     FUNC_INFO fi[], 
3137     HINSTANCE* ph,  // [out, optional] - DLL handle
3138     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
3139     int cleanup,    // cleanup function pointers and unload on error
3140     int go_on,      // continue loading even if some functions cannot be loaded
3141     int silent      // do not pop-up a system dialog if DLL cannot be loaded
3142     )
3143 {
3144     HINSTANCE h;
3145     int i, n, last_i;
3146     int error = 0;
3147     UINT em;
3148
3149     if (ph) *ph = 0;
3150     if (pindex) *pindex = -1;
3151
3152     for (n = 0; fi[n].func_ptr_var; n++)
3153         *(fi[n].func_ptr_var) = 0;
3154
3155     if (silent)
3156         em = SetErrorMode(SEM_FAILCRITICALERRORS);
3157     h = LoadLibrary(dll_name);
3158     if (silent)
3159         SetErrorMode(em);
3160
3161     if (!h)
3162         return 0;
3163
3164     last_i = -1;
3165     for (i = 0; (go_on || !error) && (i < n); i++)
3166     {
3167         void* p = (void*)GetProcAddress(h, fi[i].func_name);
3168         if (!p)
3169             error = 1;
3170         else
3171         {
3172             last_i = i;
3173             *(fi[i].func_ptr_var) = p;
3174         }
3175     }
3176     if (pindex) *pindex = last_i;
3177     if (error && cleanup && !go_on) {
3178         for (i = 0; i < n; i++) {
3179             *(fi[i].func_ptr_var) = 0;
3180         }
3181         FreeLibrary(h);
3182         return 0;
3183     }
3184     if (ph) *ph = h;
3185     if (error) return 0;
3186     return 1;
3187 }
3188
3189 #ifdef USE_FSPROBE
3190 // Cell Accessibility Functions
3191 // based on work originally submitted to the CMU Computer Club
3192 // by Jeffrey Hutzelman
3193 //
3194 // These would work great if the fsProbe interface had been 
3195 // ported to Windows
3196
3197 static 
3198 void probeComplete()
3199 {
3200     fsprobe_Cleanup(1);
3201     rx_Finalize();
3202 }
3203
3204 struct ping_params {
3205     unsigned short port;            // in
3206     int            retry_delay;     // in seconds
3207     int            verbose;         // in
3208     struct {
3209         int        wait;            // in seconds
3210         int        retry;           // in attempts
3211     }   host;
3212     int            max_hosts;       // in
3213     int            hosts_attempted; // out
3214 }
3215
3216 // the fsHandler is where we receive the answer to the probe
3217 static 
3218 int fsHandler(void)
3219 {
3220     ping_count = fsprobe_Results.probeNum;
3221     if (!*fsprobe_Results.probeOK)
3222     {
3223         ok_count++;
3224         if (waiting) complete();
3225     }
3226     if (ping_count == retry) 
3227         complete();
3228     return 0;
3229 }
3230
3231 // ping_fs is a callback routine meant to be called from within
3232 // cm_SearchCellFile() or cm_SearchCellDNS()
3233 static long 
3234 pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep)
3235 {
3236     int rc;
3237     struct ping_params * pp = (struct ping_params *) ping_params;
3238
3239     if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts )
3240         return 0;
3241
3242     pp->hosts_attempted++;
3243
3244     if (pp->port && addrp->sin_port != htons(pp->port))
3245         addrp->sin_port = htons(pp->port);
3246
3247     rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose);
3248     if (rc)
3249     {
3250         fprintf(stderr, "fsprobe_Init failed (%d)\n", rc);
3251         fsprobe_Cleanup(1);
3252         return 0;
3253     }
3254
3255     for (;;)
3256     {
3257         tv.tv_sec = pp->host.wait;
3258         tv.tv_usec = 0;
3259         if (IOMGR_Select(0, 0, 0, 0, &tv)) 
3260             break;
3261     }
3262     probeComplete();
3263     return(0);
3264 }
3265
3266
3267 static BOOL
3268 pingCell(char *cell)
3269 {
3270     int rc;
3271     char rootcell[MAXCELLCHARS+1];
3272     char newcell[MAXCELLCHARS+1];
3273     struct ping_params pp;
3274
3275     memset(&pp, 0, sizeof(struct ping_params));
3276
3277     if (!cell || strlen(cell) == 0) {
3278         /* WIN32 NOTE: no way to get max chars */
3279         if (rc = pcm_GetRootCellName(rootcell))
3280             return(FALSE);
3281         cell = rootcell;
3282     }
3283
3284     pp.port = 7000; // AFS FileServer
3285     pp.retry_delay = 10;
3286     pp.max_hosts = 3;
3287     pp.host.wait = 30;
3288     pp.host.retry = 0;
3289     pp.verbose = 1;
3290
3291     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3292     rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp);
3293 }
3294 #endif /* USE_FSPROBE */
3295  
3296 // These two items are imported from afscreds.h 
3297 // but it cannot be included without causing conflicts
3298 #define c100ns1SECOND        (LONGLONG)10000000
3299 static void 
3300 TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT)
3301 {
3302     struct tm *pTime;
3303     memset (pst, 0x00, sizeof(SYSTEMTIME));
3304
3305     if ((pTime = localtime (&TimeT)) != NULL)
3306     {
3307         pst->wYear = pTime->tm_year + 1900;
3308         pst->wMonth = pTime->tm_mon + 1;
3309         pst->wDayOfWeek = pTime->tm_wday;
3310         pst->wDay = pTime->tm_mday;
3311         pst->wHour = pTime->tm_hour;
3312         pst->wMinute = pTime->tm_min;
3313         pst->wSecond = pTime->tm_sec;
3314         pst->wMilliseconds = 0;
3315     }
3316 }
3317
3318 void
3319 ObtainTokensFromUserIfNeeded(HWND hWnd)
3320 {
3321     char * rootcell = NULL;
3322     char   cell[MAXCELLCHARS+1] = "";
3323     char   password[PROBE_PASSWORD_LEN+1];
3324     krb5_data pwdata;
3325     afsconf_cell cellconfig;
3326     struct ktc_principal    aserver;
3327     struct ktc_principal    aclient;
3328     struct ktc_token    atoken;
3329     krb5_context ctx = 0;
3330     krb5_timestamp now = 0;
3331     krb5_error_code code;
3332     int serverReachable = 0;
3333     int rc;
3334 #ifndef USE_FSPROBE
3335     krb5_ccache cc = 0;
3336     const char * realm = 0;
3337     krb5_principal principal = 0;
3338     char * pname = 0;
3339 #endif /* USE_FSPROBE */
3340     DWORD       CurrentState;
3341     char        HostName[64];
3342     int         use_kfw = KFW_is_available();
3343
3344     CurrentState = 0;
3345     memset(HostName, '\0', sizeof(HostName));
3346     gethostname(HostName, sizeof(HostName));
3347     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
3348         return;
3349     if (CurrentState != SERVICE_RUNNING) {
3350         SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L);
3351         return;
3352     }
3353
3354     if (!pkrb5_init_context)
3355         return;
3356
3357     if ( use_kfw ) {
3358         code = pkrb5_init_context(&ctx);
3359         if ( code ) goto cleanup;
3360     }
3361
3362     rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1);
3363     if ( !rootcell ) goto cleanup;
3364
3365     code = get_cellconfig(cell, (void*)&cellconfig, rootcell);
3366     if ( code ) goto cleanup;
3367
3368     memset(&aserver, '\0', sizeof(aserver));
3369     strcpy(aserver.name, "afs");
3370     strcpy(aserver.cell, rootcell);
3371
3372     rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3373
3374     if ( use_kfw ) {
3375         code = pkrb5_timeofday(ctx, &now);
3376         if ( code ) 
3377             now = 0;
3378
3379         if (!rc && (now < atoken.endTime))
3380             goto cleanup;
3381
3382         if ( IsDebuggerPresent() ) {
3383             char message[256];
3384             sprintf(message,"KFW_AFS_klog() returns: %d  now = %ul  endTime = %ul\n",
3385                      rc, now, atoken.endTime);
3386             OutputDebugString(message);
3387         }
3388     } else {
3389         SYSTEMTIME stNow;
3390         FILETIME ftNow;
3391         FILETIME ftExpires;
3392         LONGLONG llNow;
3393         LONGLONG llExpires;
3394         SYSTEMTIME stExpires;
3395
3396         TimeToSystemTime (&stExpires, atoken.endTime);
3397         GetLocalTime (&stNow);
3398         SystemTimeToFileTime (&stNow, &ftNow);
3399         SystemTimeToFileTime (&stExpires, &ftExpires);
3400
3401         llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime);
3402         llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime);
3403
3404         llNow /= c100ns1SECOND;
3405         llExpires /= c100ns1SECOND;
3406
3407         if (!rc && (llNow < llExpires))
3408             goto cleanup;
3409
3410         if ( IsDebuggerPresent() ) {
3411             char message[256];
3412             sprintf(message,"KFW_AFS_klog() returns: %d  now = %ul  endTime = %ul\n",
3413                      rc, llNow, llExpires);
3414             OutputDebugString(message);
3415         }
3416     }
3417
3418
3419 #ifdef USE_FSPROBE
3420     serverReachable = cellPing(NULL);
3421 #else
3422     if ( use_kfw ) {
3423         // If we can't use the FSProbe interface we can attempt to forge
3424         // a kinit and if we can back an invalid user error we know the
3425         // kdc is at least reachable
3426         realm = afs_realm_of_cell(&cellconfig);  // do not free
3427
3428         code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3429                                      realm, PROBE_USERNAME, NULL, NULL);
3430         if ( code ) goto cleanup;
3431
3432         code = KFW_get_ccache(ctx, principal, &cc);
3433         if ( code ) goto cleanup;
3434
3435         code = pkrb5_unparse_name(ctx, principal, &pname);
3436         if ( code ) goto cleanup;
3437
3438         pwdata.data = password;
3439         pwdata.length = PROBE_PASSWORD_LEN;
3440         code = pkrb5_c_random_make_octets(ctx, &pwdata);
3441         if (code) {
3442             int i;
3443             for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3444                 password[i] = 'x';
3445         }
3446         password[PROBE_PASSWORD_LEN] = '\0';
3447
3448         code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
3449                            pname, 
3450                            password,
3451                            5,
3452                            0,
3453                            0,
3454                            0,
3455                            1,
3456                            0);
3457         switch ( code ) {
3458         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3459         case KRB5KDC_ERR_CLIENT_REVOKED:
3460         case KRB5KDC_ERR_CLIENT_NOTYET:
3461         case KRB5KDC_ERR_PREAUTH_FAILED:
3462         case KRB5KDC_ERR_PREAUTH_REQUIRED:
3463         case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3464             serverReachable = TRUE;
3465             break;
3466         default:
3467             serverReachable = FALSE;
3468         }
3469     } else {
3470         int i;
3471
3472         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3473             password[i] = 'x';
3474
3475         code = ObtainNewCredentials(rootcell, PROBE_USERNAME, password, TRUE);
3476         switch ( code ) {
3477         case INTK_BADPW:
3478         case KERB_ERR_PRINCIPAL_UNKNOWN:
3479         case KERB_ERR_SERVICE_EXP:
3480         case RD_AP_TIME:
3481             serverReachable = TRUE;
3482             break;
3483         default:
3484             serverReachable = FALSE;
3485         }
3486     }
3487 #endif
3488     if ( !serverReachable ) {
3489         if ( IsDebuggerPresent() )
3490             OutputDebugString("Server Unreachable\n");
3491         goto cleanup;
3492     }
3493
3494     if ( IsDebuggerPresent() )
3495         OutputDebugString("Server Reachable\n");
3496
3497     if ( use_kfw ) {
3498 #ifdef USE_MS2MIT
3499         KFW_import_windows_lsa();
3500 #endif /* USE_MS2MIT */
3501         KFW_AFS_renew_expiring_tokens();
3502         KFW_AFS_renew_token_for_cell(rootcell);
3503
3504         rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
3505         if (!rc && (now < atoken.endTime))
3506             goto cleanup;
3507     }
3508
3509     SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
3510     rootcell = NULL;    // rootcell freed by message receiver
3511
3512   cleanup:
3513     if (rootcell)
3514         GlobalFree(rootcell);
3515
3516 #ifndef USE_FSPROBE
3517         if (KFW_is_available()) {
3518     if ( pname )
3519         pkrb5_free_unparsed_name(ctx,pname);
3520     if ( principal )
3521         pkrb5_free_principal(ctx,principal);
3522     if (cc)
3523         pkrb5_cc_close(ctx,cc);
3524 #endif /* USE_FSPROBE */
3525     if (ctx)
3526         pkrb5_free_context(ctx);
3527         }
3528     return;
3529 }
3530
3531 // IP Change Monitoring Functions
3532 #include <Iphlpapi.h>
3533
3534 DWORD
3535 GetNumOfIpAddrs(void)
3536 {
3537     PMIB_IPADDRTABLE pIpAddrTable = NULL;
3538     ULONG            dwSize;
3539     DWORD            code;
3540     DWORD            index;
3541     DWORD            validAddrs = 0;
3542
3543     dwSize = 0;
3544     code = GetIpAddrTable(NULL, &dwSize, 0);
3545     if (code == ERROR_INSUFFICIENT_BUFFER) {
3546         pIpAddrTable = malloc(dwSize);
3547         code = GetIpAddrTable(pIpAddrTable, &dwSize, 0);
3548         if ( code == NO_ERROR ) {
3549             for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
3550                 if (pIpAddrTable->table[index].dwAddr != 0)
3551                     validAddrs++;
3552             }
3553         }
3554         free(pIpAddrTable);
3555     }
3556     return validAddrs;
3557 }
3558
3559 void
3560 IpAddrChangeMonitor(void * hWnd)
3561 {
3562 #ifdef USE_OVERLAPPED
3563     HANDLE Handle = INVALID_HANDLE_VALUE;   /* Do Not Close This Handle */
3564     OVERLAPPED Ovlap;
3565 #endif /* USE_OVERLAPPED */
3566     DWORD Result;
3567     DWORD prevNumOfAddrs = GetNumOfIpAddrs();
3568     DWORD NumOfAddrs;
3569     char message[256];
3570
3571     if ( !hWnd )
3572         return;
3573
3574     while ( TRUE ) {
3575 #ifdef USE_OVERLAPPED
3576         ZeroMemory(&Ovlap, sizeof(OVERLAPPED));
3577
3578         Result = NotifyAddrChange(&Handle,&Ovlap);
3579         if (Result != ERROR_IO_PENDING)
3580         {        
3581             if ( IsDebuggerPresent() ) {
3582                 sprintf(message, "NotifyAddrChange() failed with error %d \n", Result);
3583                 OutputDebugString(message);
3584             }
3585             break;
3586         }
3587
3588         if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0)
3589         {
3590             if ( IsDebuggerPresent() ) {
3591                 sprintf(message, "WaitForSingleObject() failed with error %d\n",
3592                         GetLastError());
3593                 OutputDebugString(message);
3594             }
3595             continue;
3596         }
3597
3598         if (GetOverlappedResult(Handle, &Ovlap,
3599                                  &DataTransfered, TRUE) == 0)
3600         {
3601             if ( IsDebuggerPresent() ) {
3602                 sprintf(message, "GetOverlapped result failed %d \n",
3603                         GetLastError());
3604                 OutputDebugString(message);
3605             }
3606             break;
3607         }
3608 #else
3609         Result = NotifyAddrChange(NULL,NULL);
3610         if (Result != NO_ERROR)
3611         {        
3612             if ( IsDebuggerPresent() ) {
3613                 sprintf(message, "NotifyAddrChange() failed with error %d \n", Result);
3614                 OutputDebugString(message);
3615             }
3616             break;
3617         }
3618 #endif
3619         
3620         NumOfAddrs = GetNumOfIpAddrs();
3621
3622         if ( IsDebuggerPresent() ) {
3623             sprintf(message,"IPAddrChangeMonitor() NumOfAddrs: now %d was %d\n",
3624                     NumOfAddrs, prevNumOfAddrs);
3625             OutputDebugString(message);
3626         }
3627
3628         if ( NumOfAddrs != prevNumOfAddrs ) {
3629             // Give AFS Client Service a chance to notice and die
3630             // Or for network services to startup
3631             Sleep(2000);
3632             // this call should probably be mutex protected
3633             ObtainTokensFromUserIfNeeded(hWnd);
3634         }
3635         prevNumOfAddrs = NumOfAddrs;
3636     }
3637 }
3638
3639
3640 DWORD 
3641 IpAddrChangeMonitorInit(HWND hWnd)
3642 {
3643     DWORD status = ERROR_SUCCESS;
3644     HANDLE thread;
3645     ULONG  threadID = 0;
3646
3647     thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor,
3648                                     hWnd, 0, &threadID);
3649
3650     if (thread == NULL) {
3651         status = GetLastError();
3652     }
3653     CloseHandle(thread);
3654     return status;
3655 }
3656