Windows: avoid race when writing mountPointString
[openafs.git] / src / WINNT / afsd / afskfw.c
1 /*
2  * Copyright (c) 2004, 2005, 2006, 2007, 2008 Secure Endpoints Inc.
3  * Copyright (c) 2003 SkyRope, LLC
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met:
8  * 
9  * - Redistributions of source code must retain the above copyright notice, 
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  *   this list of conditions and the following disclaimer in the documentation 
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Skyrope, LLC nor the names of its contributors may be 
15  *   used to endorse or promote products derived from this software without 
16  *   specific prior written permission from Skyrope, LLC.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Portions of this code are derived from portions of the MIT
31  * Leash Ticket Manager and LoadFuncs utilities.  For these portions the
32  * following copyright applies.
33  *
34  * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
35  * All rights reserved.
36  *
37  * Export of this software from the United States of America may
38  *   require a specific license from the United States Government.
39  *   It is the responsibility of any person or organization contemplating
40  *   export to obtain such a license before exporting.
41  *
42  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43  * distribute this software and its documentation for any purpose and
44  * without fee is hereby granted, provided that the above copyright
45  * notice appear in all copies and that both that copyright notice and
46  * this permission notice appear in supporting documentation, and that
47  * the name of M.I.T. not be used in advertising or publicity pertaining
48  * to distribution of the software without specific, written prior
49  * permission.  Furthermore if you modify this software you must label
50  * your software as modified software and not distribute it in such a
51  * fashion that it might be confused with the original M.I.T. software.
52  * M.I.T. makes no representations about the suitability of
53  * this software for any purpose.  It is provided "as is" without express
54  * or implied warranty.
55  *
56  */
57
58
59 #undef  USE_KRB4
60 #ifndef _WIN64
61 #define USE_KRB524 1
62 #endif
63 #define USE_MS2MIT 1
64 #define USE_LEASH 1
65
66 #include <afsconfig.h>
67 #include <afs/param.h>
68 #include <roken.h>
69
70 #include <osilog.h>
71 #include <afs/ptserver.h>
72 #include <afs/ptuser.h>
73 #include <rx/rxkad.h>
74 #include <WINNT\afsreg.h>
75 #include "cm.h"
76
77 #include "afskfw.h"
78 #include "afskfw-int.h"
79 #include <userenv.h>
80 #include "strsafe.h"
81
82 #include <Sddl.h>
83 #include <Aclapi.h>
84
85 /*
86  * TIMING _____________________________________________________________________
87  *
88  */
89
90 #define cminREMIND_TEST      1    // test every minute for expired creds
91 #define cminREMIND_WARN      15   // warn if creds expire in 15 minutes
92 #define cminRENEW            20   // renew creds when there are 20 minutes remaining
93 #define cminMINLIFE          30   // minimum life of Kerberos creds
94
95 #define c100ns1SECOND        (LONGLONG)10000000
96 #define cmsec1SECOND         1000
97 #define cmsec1MINUTE         60000
98 #define csec1MINUTE          60
99
100 /* Function Pointer Declarations for Delayed Loading */
101 // CCAPI
102 DECL_FUNC_PTR(cc_initialize);
103 DECL_FUNC_PTR(cc_shutdown);
104 DECL_FUNC_PTR(cc_get_NC_info);
105 DECL_FUNC_PTR(cc_free_NC_info);
106
107 #ifdef USE_LEASH
108 // leash functions
109 DECL_FUNC_PTR(Leash_get_default_lifetime);
110 DECL_FUNC_PTR(Leash_get_default_forwardable);
111 DECL_FUNC_PTR(Leash_get_default_renew_till);
112 DECL_FUNC_PTR(Leash_get_default_noaddresses);
113 DECL_FUNC_PTR(Leash_get_default_proxiable);
114 DECL_FUNC_PTR(Leash_get_default_publicip);
115 DECL_FUNC_PTR(Leash_get_default_use_krb4);
116 DECL_FUNC_PTR(Leash_get_default_life_min);
117 DECL_FUNC_PTR(Leash_get_default_life_max);
118 DECL_FUNC_PTR(Leash_get_default_renew_min);
119 DECL_FUNC_PTR(Leash_get_default_renew_max);
120 DECL_FUNC_PTR(Leash_get_default_renewable);
121 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
122 #endif 
123
124 // krb5 functions
125 DECL_FUNC_PTR(krb5_change_password);
126 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
127 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
128 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
129 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
130 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
131 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
132 DECL_FUNC_PTR(krb5_get_init_creds_password);
133 DECL_FUNC_PTR(krb5_build_principal_ext);
134 DECL_FUNC_PTR(krb5_cc_get_name);
135 DECL_FUNC_PTR(krb5_cc_resolve);
136 DECL_FUNC_PTR(krb5_cc_default);
137 DECL_FUNC_PTR(krb5_cc_default_name);
138 DECL_FUNC_PTR(krb5_cc_set_default_name);
139 DECL_FUNC_PTR(krb5_cc_initialize);
140 DECL_FUNC_PTR(krb5_cc_destroy);
141 DECL_FUNC_PTR(krb5_cc_close);
142 DECL_FUNC_PTR(krb5_cc_store_cred);
143 DECL_FUNC_PTR(krb5_cc_copy_creds);
144 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
145 DECL_FUNC_PTR(krb5_cc_get_principal);
146 DECL_FUNC_PTR(krb5_cc_start_seq_get);
147 DECL_FUNC_PTR(krb5_cc_next_cred);
148 DECL_FUNC_PTR(krb5_cc_end_seq_get);
149 DECL_FUNC_PTR(krb5_cc_remove_cred);
150 DECL_FUNC_PTR(krb5_cc_set_flags);
151 DECL_FUNC_PTR(krb5_cc_get_type);
152 DECL_FUNC_PTR(krb5_free_context);
153 DECL_FUNC_PTR(krb5_free_cred_contents);
154 DECL_FUNC_PTR(krb5_free_principal);
155 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
156 DECL_FUNC_PTR(krb5_init_context);
157 DECL_FUNC_PTR(krb5_parse_name);
158 DECL_FUNC_PTR(krb5_timeofday);
159 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
160 DECL_FUNC_PTR(krb5_unparse_name);
161 DECL_FUNC_PTR(krb5_get_credentials);
162 DECL_FUNC_PTR(krb5_mk_req);
163 DECL_FUNC_PTR(krb5_sname_to_principal);
164 DECL_FUNC_PTR(krb5_get_credentials_renew);
165 DECL_FUNC_PTR(krb5_free_data);
166 DECL_FUNC_PTR(krb5_free_data_contents);
167 DECL_FUNC_PTR(krb5_free_unparsed_name);
168 DECL_FUNC_PTR(krb5_os_localaddr);
169 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
170 DECL_FUNC_PTR(krb5_copy_data);
171 DECL_FUNC_PTR(krb5_free_creds);
172 DECL_FUNC_PTR(krb5_build_principal);
173 DECL_FUNC_PTR(krb5_get_renewed_creds);
174 DECL_FUNC_PTR(krb5_get_default_config_files);
175 DECL_FUNC_PTR(krb5_free_config_files);
176 DECL_FUNC_PTR(krb5_get_default_realm);
177 DECL_FUNC_PTR(krb5_free_default_realm);
178 DECL_FUNC_PTR(krb5_free_ticket);
179 DECL_FUNC_PTR(krb5_decode_ticket);
180 DECL_FUNC_PTR(krb5_get_host_realm);
181 DECL_FUNC_PTR(krb5_free_host_realm);
182 DECL_FUNC_PTR(krb5_free_addresses);
183 DECL_FUNC_PTR(krb5_c_random_make_octets);
184
185 // Krb5 KFW 3.2 functions
186 DECL_FUNC_PTR(krb5_get_error_message);
187 DECL_FUNC_PTR(krb5_free_error_message);
188
189 #ifdef USE_KRB524
190 // Krb524 functions
191 DECL_FUNC_PTR(krb524_init_ets);
192 DECL_FUNC_PTR(krb524_convert_creds_kdc);
193 #endif
194
195 #ifdef USE_KRB4
196 // krb4 functions
197 DECL_FUNC_PTR(krb_get_cred);
198 DECL_FUNC_PTR(tkt_string);
199 DECL_FUNC_PTR(krb_get_tf_realm);
200 DECL_FUNC_PTR(krb_mk_req);
201 #endif
202
203 // ComErr functions
204 DECL_FUNC_PTR(com_err);
205 DECL_FUNC_PTR(error_message);
206
207 // Profile functions
208 DECL_FUNC_PTR(profile_init);
209 DECL_FUNC_PTR(profile_release);
210 DECL_FUNC_PTR(profile_get_subsection_names);
211 DECL_FUNC_PTR(profile_free_list);
212 DECL_FUNC_PTR(profile_get_string);
213 DECL_FUNC_PTR(profile_release_string);
214
215 // Service functions
216 DECL_FUNC_PTR(OpenSCManagerA);
217 DECL_FUNC_PTR(OpenServiceA);
218 DECL_FUNC_PTR(QueryServiceStatus);
219 DECL_FUNC_PTR(CloseServiceHandle);
220 #ifdef USE_MS2MIT
221 DECL_FUNC_PTR(LsaNtStatusToWinError);
222 #endif /* USE_MS2MIT */
223
224 #ifdef USE_MS2MIT
225 // LSA Functions
226 DECL_FUNC_PTR(LsaConnectUntrusted);
227 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
228 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
229 DECL_FUNC_PTR(LsaFreeReturnBuffer);
230 DECL_FUNC_PTR(LsaGetLogonSessionData);
231 #endif /* USE_MS2MIT */
232
233 // CCAPI
234 FUNC_INFO ccapi_fi[] = {
235     MAKE_FUNC_INFO(cc_initialize),
236     MAKE_FUNC_INFO(cc_shutdown),
237     MAKE_FUNC_INFO(cc_get_NC_info),
238     MAKE_FUNC_INFO(cc_free_NC_info),
239     END_FUNC_INFO
240 };
241
242 #ifdef USE_LEASH
243 FUNC_INFO leash_fi[] = {
244     MAKE_FUNC_INFO(Leash_get_default_lifetime),
245     MAKE_FUNC_INFO(Leash_get_default_renew_till),
246     MAKE_FUNC_INFO(Leash_get_default_forwardable),
247     MAKE_FUNC_INFO(Leash_get_default_noaddresses),
248     MAKE_FUNC_INFO(Leash_get_default_proxiable),
249     MAKE_FUNC_INFO(Leash_get_default_publicip),
250     MAKE_FUNC_INFO(Leash_get_default_use_krb4),
251     MAKE_FUNC_INFO(Leash_get_default_life_min),
252     MAKE_FUNC_INFO(Leash_get_default_life_max),
253     MAKE_FUNC_INFO(Leash_get_default_renew_min),
254     MAKE_FUNC_INFO(Leash_get_default_renew_max),
255     MAKE_FUNC_INFO(Leash_get_default_renewable),
256     END_FUNC_INFO
257 };
258
259 FUNC_INFO leash_opt_fi[] = {
260     MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
261     END_FUNC_INFO
262 };
263 #endif
264
265 FUNC_INFO k5_fi[] = {
266     MAKE_FUNC_INFO(krb5_change_password),
267     MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
268     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
269     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
270     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
271     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
272     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
273     MAKE_FUNC_INFO(krb5_get_init_creds_password),
274     MAKE_FUNC_INFO(krb5_build_principal_ext),
275     MAKE_FUNC_INFO(krb5_cc_get_name),
276     MAKE_FUNC_INFO(krb5_cc_resolve),
277     MAKE_FUNC_INFO(krb5_cc_default),
278     MAKE_FUNC_INFO(krb5_cc_default_name),
279     MAKE_FUNC_INFO(krb5_cc_set_default_name),
280     MAKE_FUNC_INFO(krb5_cc_initialize),
281     MAKE_FUNC_INFO(krb5_cc_destroy),
282     MAKE_FUNC_INFO(krb5_cc_close),
283     MAKE_FUNC_INFO(krb5_cc_copy_creds),
284     MAKE_FUNC_INFO(krb5_cc_store_cred),
285     MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
286     MAKE_FUNC_INFO(krb5_cc_get_principal),
287     MAKE_FUNC_INFO(krb5_cc_start_seq_get),
288     MAKE_FUNC_INFO(krb5_cc_next_cred),
289     MAKE_FUNC_INFO(krb5_cc_end_seq_get),
290     MAKE_FUNC_INFO(krb5_cc_remove_cred),
291     MAKE_FUNC_INFO(krb5_cc_set_flags),
292     MAKE_FUNC_INFO(krb5_cc_get_type),
293     MAKE_FUNC_INFO(krb5_free_context),
294     MAKE_FUNC_INFO(krb5_free_cred_contents),
295     MAKE_FUNC_INFO(krb5_free_principal),
296     MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
297     MAKE_FUNC_INFO(krb5_init_context),
298     MAKE_FUNC_INFO(krb5_parse_name),
299     MAKE_FUNC_INFO(krb5_timeofday),
300     MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
301     MAKE_FUNC_INFO(krb5_unparse_name),
302     MAKE_FUNC_INFO(krb5_get_credentials),
303     MAKE_FUNC_INFO(krb5_mk_req),
304     MAKE_FUNC_INFO(krb5_sname_to_principal),
305     MAKE_FUNC_INFO(krb5_get_credentials_renew),
306     MAKE_FUNC_INFO(krb5_free_data),
307     MAKE_FUNC_INFO(krb5_free_data_contents),
308     MAKE_FUNC_INFO(krb5_free_unparsed_name),
309     MAKE_FUNC_INFO(krb5_os_localaddr),
310     MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
311     MAKE_FUNC_INFO(krb5_copy_data),
312     MAKE_FUNC_INFO(krb5_free_creds),
313     MAKE_FUNC_INFO(krb5_build_principal),
314     MAKE_FUNC_INFO(krb5_get_renewed_creds),
315     MAKE_FUNC_INFO(krb5_free_addresses),
316     MAKE_FUNC_INFO(krb5_get_default_config_files),
317     MAKE_FUNC_INFO(krb5_free_config_files),
318     MAKE_FUNC_INFO(krb5_get_default_realm),
319     MAKE_FUNC_INFO(krb5_free_default_realm),
320     MAKE_FUNC_INFO(krb5_free_ticket),
321     MAKE_FUNC_INFO(krb5_decode_ticket),
322     MAKE_FUNC_INFO(krb5_get_host_realm),
323     MAKE_FUNC_INFO(krb5_free_host_realm),
324     MAKE_FUNC_INFO(krb5_free_addresses),
325     MAKE_FUNC_INFO(krb5_c_random_make_octets),
326     END_FUNC_INFO
327 };
328
329 FUNC_INFO k5_kfw_32_fi[] = {
330     MAKE_FUNC_INFO(krb5_get_error_message),
331     MAKE_FUNC_INFO(krb5_free_error_message),
332     END_FUNC_INFO
333 };
334
335 #ifdef USE_KRB4
336 FUNC_INFO k4_fi[] = {
337     MAKE_FUNC_INFO(krb_get_cred),
338     MAKE_FUNC_INFO(krb_get_tf_realm),
339     MAKE_FUNC_INFO(krb_mk_req),
340     MAKE_FUNC_INFO(tkt_string),
341     END_FUNC_INFO
342 };
343 #endif
344
345 #ifdef USE_KRB524
346 FUNC_INFO k524_fi[] = {
347     MAKE_FUNC_INFO(krb524_init_ets),
348     MAKE_FUNC_INFO(krb524_convert_creds_kdc),
349     END_FUNC_INFO
350 };
351 #endif
352
353 FUNC_INFO profile_fi[] = {
354         MAKE_FUNC_INFO(profile_init),
355         MAKE_FUNC_INFO(profile_release),
356         MAKE_FUNC_INFO(profile_get_subsection_names),
357         MAKE_FUNC_INFO(profile_free_list),
358         MAKE_FUNC_INFO(profile_get_string),
359         MAKE_FUNC_INFO(profile_release_string),
360         END_FUNC_INFO
361 };
362
363 FUNC_INFO ce_fi[] = {
364     MAKE_FUNC_INFO(com_err),
365     MAKE_FUNC_INFO(error_message),
366     END_FUNC_INFO
367 };
368
369 FUNC_INFO service_fi[] = {
370     MAKE_FUNC_INFO(OpenSCManagerA),
371     MAKE_FUNC_INFO(OpenServiceA),
372     MAKE_FUNC_INFO(QueryServiceStatus),
373     MAKE_FUNC_INFO(CloseServiceHandle),
374 #ifdef USE_MS2MIT
375     MAKE_FUNC_INFO(LsaNtStatusToWinError),
376 #endif /* USE_MS2MIT */
377     END_FUNC_INFO
378 };
379
380 #ifdef USE_MS2MIT
381 FUNC_INFO lsa_fi[] = {
382     MAKE_FUNC_INFO(LsaConnectUntrusted),
383     MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
384     MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
385     MAKE_FUNC_INFO(LsaFreeReturnBuffer),
386     MAKE_FUNC_INFO(LsaGetLogonSessionData),
387     END_FUNC_INFO
388 };
389 #endif /* USE_MS2MIT */
390
391 /* Static Prototypes */
392 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
393 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short);
394 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
395 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
396            void *data, const char *name, const char *banner, int num_prompts,
397            krb5_prompt prompts[]);
398
399
400 /* Static Declarations */
401 static int                inited = 0;
402 static int                mid_cnt = 0;
403 static struct textField * mid_tb = NULL;
404 static HINSTANCE hKrb5 = 0;
405 static HINSTANCE hKrb5_kfw_32 = 0;
406 #ifdef USE_KRB4
407 static HINSTANCE hKrb4 = 0;
408 #endif /* USE_KRB4 */
409 #ifdef USE_KRB524
410 static HINSTANCE hKrb524 = 0;
411 #endif
412 #ifdef USE_MS2MIT
413 static HINSTANCE hSecur32 = 0;
414 #endif /* USE_MS2MIT */
415 static HINSTANCE hAdvApi32 = 0;
416 static HINSTANCE hComErr = 0;
417 static HINSTANCE hService = 0;
418 static HINSTANCE hProfile = 0;
419 #ifdef USE_LEASH
420 static HINSTANCE hLeash = 0;
421 static HINSTANCE hLeashOpt = 0;
422 #endif
423 static HINSTANCE hCCAPI = 0;
424 static struct principal_ccache_data * princ_cc_data = NULL;
425 static struct cell_principal_map    * cell_princ_map = NULL;
426
427 void
428 KFW_initialize(void)
429 {
430     static int inited = 0;
431
432     if ( !inited ) {
433         char mutexName[MAX_PATH];
434         HANDLE hMutex = NULL;
435
436         StringCbPrintf( mutexName, sizeof(mutexName), "AFS KFW Init pid=%d", getpid());
437         
438         hMutex = CreateMutex( NULL, TRUE, mutexName );
439         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
440             if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
441                 return;
442             }
443         }
444         if ( !inited ) {
445             inited = 1;
446             LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
447             LoadFuncs(KRB5_DLL, k5_kfw_32_fi, &hKrb5_kfw_32, 0, 1, 0, 0);
448             LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
449             LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
450 #ifdef USE_KRB4
451             LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
452 #endif /* USE_KRB4 */
453             LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
454 #ifdef USE_MS2MIT
455             LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
456 #endif /* USE_MS2MIT */
457 #ifdef USE_KRB524
458             LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
459 #endif
460 #ifdef USE_LEASH
461             LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
462             LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
463 #endif
464             LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
465
466             if ( KFW_is_available() ) {
467                 char rootcell[CELL_MAXNAMELEN+1];
468 #ifdef USE_MS2MIT
469                 KFW_import_windows_lsa();
470 #endif /* USE_MS2MIT */
471                 KFW_import_ccache_data();
472                 KFW_AFS_renew_expiring_tokens();
473
474                 /* WIN32 NOTE: no way to get max chars */
475                 if (!cm_GetRootCellName(rootcell))
476                     KFW_AFS_renew_token_for_cell(rootcell);
477             }
478         }
479         ReleaseMutex(hMutex);
480         CloseHandle(hMutex);
481     }
482 }
483
484 void
485 KFW_cleanup(void)
486 {
487 #ifdef USE_LEASH
488     if (hLeashOpt)
489         FreeLibrary(hLeashOpt);
490     if (hLeash)
491         FreeLibrary(hLeash);
492 #endif
493 #ifdef USE_KRB524
494     if (hKrb524)
495         FreeLibrary(hKrb524);
496 #endif
497     if (hCCAPI)
498         FreeLibrary(hCCAPI);
499 #ifdef USE_MS2MIT
500     if (hSecur32)
501         FreeLibrary(hSecur32);
502 #endif /* USE_MS2MIT */
503     if (hService)
504         FreeLibrary(hService);
505     if (hComErr)
506         FreeLibrary(hComErr);
507     if (hProfile)
508         FreeLibrary(hProfile);
509 #ifdef USE_KRB4
510     if (hKrb4)
511         FreeLibrary(hKrb4);
512 #endif /* USE_KRB4 */
513     if (hKrb5)
514         FreeLibrary(hKrb5);
515     if (hKrb5_kfw_32)
516         FreeLibrary(hKrb5_kfw_32);
517 }
518
519 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
520 static int IsWow64()
521 {
522     static int init = TRUE;
523     static int bIsWow64 = FALSE;
524
525     if (init) {
526         HMODULE hModule;
527         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
528
529         hModule = GetModuleHandle(TEXT("kernel32"));
530         if (hModule) {
531             fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
532   
533             if (NULL != fnIsWow64Process)
534             {
535                 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
536                 {
537                     // on error, assume FALSE.
538                     // in other words, do nothing.
539                 }
540             }
541             FreeLibrary(hModule);
542         }
543         init = FALSE;
544     }
545     return bIsWow64;
546 }
547
548 int
549 KFW_accept_dotted_usernames(void)
550 {
551     HKEY parmKey;
552     DWORD code, len;
553     DWORD value = 1;
554
555     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
556                          0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
557     if (code == ERROR_SUCCESS) {
558         len = sizeof(value);
559         code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
560                                 (BYTE *) &value, &len);
561         RegCloseKey(parmKey);
562     }
563     if (code != ERROR_SUCCESS) {
564         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
565                              0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
566         if (code == ERROR_SUCCESS) {
567             len = sizeof(value);
568             code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
569                                     (BYTE *) &value, &len);
570             RegCloseKey (parmKey);
571         }
572     }
573     return value;
574 }
575
576
577 int
578 KFW_use_krb524(void)
579 {
580     HKEY parmKey;
581     DWORD code, len;
582     DWORD use524 = 0;
583
584     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
585                          0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
586     if (code == ERROR_SUCCESS) {
587         len = sizeof(use524);
588         code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
589                                 (BYTE *) &use524, &len);
590         RegCloseKey(parmKey);
591     }
592     if (code != ERROR_SUCCESS) {
593         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
594                              0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
595         if (code == ERROR_SUCCESS) {
596             len = sizeof(use524);
597             code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
598                                     (BYTE *) &use524, &len);
599             RegCloseKey (parmKey);
600         }
601     }
602     return use524;
603 }
604
605 int 
606 KFW_is_available(void)
607 {
608     HKEY parmKey;
609     DWORD code, len;
610     DWORD enableKFW = 1;
611
612     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
613                          0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
614     if (code == ERROR_SUCCESS) {
615         len = sizeof(enableKFW);
616         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
617                                 (BYTE *) &enableKFW, &len);
618         RegCloseKey (parmKey);
619     }
620     
621     if (code != ERROR_SUCCESS) {
622         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
623                              0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
624         if (code == ERROR_SUCCESS) {
625             len = sizeof(enableKFW);
626             code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
627                                     (BYTE *) &enableKFW, &len);
628             RegCloseKey (parmKey);
629         }
630     } 
631
632     if ( !enableKFW )
633         return FALSE;
634
635     KFW_initialize();
636     if ( hKrb5 && hComErr && hService && 
637 #ifdef USE_MS2MIT
638          hSecur32 && 
639 #endif /* USE_MS2MIT */
640 #ifdef USE_KRB524
641          hKrb524 &&
642 #endif
643 #ifdef USE_LEASH
644          hLeash &&
645 #endif
646          hProfile && hCCAPI )
647         return TRUE;
648     return FALSE;
649 }
650
651 int 
652 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, 
653                  int FreeContextFlag, krb5_context * ctx, 
654                  krb5_ccache * cache)
655 {
656     char message[256];
657     const char *errText;
658     int krb5Error = ((int)(rc & 255));  
659     
660     /*
661     switch (krb5Error)
662     {
663         // Wrong password
664         case 31:
665         case 8:
666             return;
667     }
668     */
669         
670     if (pkrb5_get_error_message)
671         errText = pkrb5_get_error_message(ctx, rc);
672     else
673         errText = perror_message(rc);
674     StringCbPrintf(message, sizeof(message), 
675               "%s\n(Kerberos error %ld)\n\n%s failed",
676               errText, 
677               krb5Error, 
678               FailedFunctionName);
679     if (pkrb5_free_error_message)
680         pkrb5_free_error_message(ctx, (char *)errText);
681
682     if ( IsDebuggerPresent() )
683         OutputDebugString(message);
684
685     MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 
686                MB_TASKMODAL | 
687                MB_SETFOREGROUND);
688     if (FreeContextFlag == 1)
689     {
690         if (ctx && *ctx != NULL)
691         {
692             if (cache && *cache != NULL) {
693                 pkrb5_cc_close(*ctx, *cache);
694                 *cache = NULL;
695             }
696         
697             pkrb5_free_context(*ctx);
698             *ctx = NULL;
699         }
700     }
701
702     return rc;
703 }
704
705 void
706 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
707 {
708     struct principal_ccache_data * next = princ_cc_data;
709     krb5_principal principal = 0;
710     char * pname = NULL;
711     const char * ccname = NULL;
712     const char * cctype = NULL;
713     char * ccfullname = NULL;
714     krb5_error_code code = 0;
715     krb5_error_code cc_code = 0;
716     krb5_cc_cursor cur;
717     krb5_creds creds;
718     krb5_flags flags=0;
719     krb5_timestamp now;
720
721     if (ctx == 0 || cc == 0)
722         return;
723
724     code = pkrb5_cc_get_principal(ctx, cc, &principal);
725     if ( code ) return;
726
727     code = pkrb5_unparse_name(ctx, principal, &pname);
728     if ( code ) goto cleanup;
729
730     ccname = pkrb5_cc_get_name(ctx, cc);
731     if (!ccname) goto cleanup;
732
733     cctype = pkrb5_cc_get_type(ctx, cc);
734     if (!cctype) goto cleanup;
735
736     ccfullname = malloc(strlen(ccname) + strlen(cctype) + 2);
737     if (!ccfullname) goto cleanup;
738         
739     StringCbPrintf(ccfullname, sizeof(ccfullname), "%s:%s", cctype, ccname);
740
741     // Search the existing list to see if we have a match 
742     if ( next ) {
743         for ( ; next ; next = next->next ) {
744             if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
745                 break;
746         }
747     } 
748
749     // If not, match add a new node to the beginning of the list and assign init it
750     if ( !next ) {
751         next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
752         next->next = princ_cc_data;
753         princ_cc_data = next;
754         next->principal = _strdup(pname);
755         next->ccache_name = ccfullname;
756         ccfullname = NULL;
757         next->from_lsa = lsa;
758         next->expired = 1;
759         next->expiration_time = 0;
760         next->renew = 0;
761     }
762
763     flags = 0;  // turn off OPENCLOSE mode
764     code = pkrb5_cc_set_flags(ctx, cc, flags);
765     if ( code ) goto cleanup;
766
767     code = pkrb5_timeofday(ctx, &now);
768
769     cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
770
771     while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
772         if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
773             int valid;
774             // we found the ticket we are looking for
775             // check validity of timestamp 
776             // We add a 5 minutes fudge factor to compensate for potential
777             // clock skew errors between the KDC and client OS
778
779             valid = ((creds.times.starttime > 0) &&
780                      now >= (creds.times.starttime - 300) &&
781                      now < (creds.times.endtime + 300) &&
782                      !(creds.ticket_flags & TKT_FLG_INVALID));
783
784             if ( next->from_lsa) {
785                 next->expired = 0;
786                 next->expiration_time = creds.times.endtime;
787                 next->renew = 1;
788             } else if ( valid ) {
789                 next->expired = 0;
790                 next->expiration_time = creds.times.endtime;
791                 next->renew = (creds.times.renew_till > creds.times.endtime) && 
792                                (creds.ticket_flags & TKT_FLG_RENEWABLE);
793             } else {
794                 next->expired = 1;
795                 next->expiration_time = 0;
796                 next->renew = 0;
797             }
798
799             pkrb5_free_cred_contents(ctx, &creds);
800             cc_code = KRB5_CC_END;
801             break;
802         }
803         pkrb5_free_cred_contents(ctx, &creds);
804     }
805
806     if (cc_code == KRB5_CC_END) {
807         code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
808         if (code) goto cleanup;
809     }
810
811   cleanup:
812     flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
813     code = pkrb5_cc_set_flags(ctx, cc, flags);
814
815     if ( ccfullname)
816         free(ccfullname);
817     if ( pname )
818         pkrb5_free_unparsed_name(ctx,pname);
819     if ( principal )
820         pkrb5_free_principal(ctx,principal);
821 }   
822
823 int
824 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
825 {
826     struct principal_ccache_data * next = princ_cc_data;
827     char * response = NULL;
828
829     if ( !principal || !ccache )
830         return 0;
831
832     while ( next ) {
833         if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
834             if (response) {
835                 // we always want to prefer the MS Kerberos LSA cache or
836                 // the cache afscreds created specifically for the principal
837                 // if the current entry is either one, drop the previous find
838                 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
839                     free(response);
840             }
841             response = _strdup(next->ccache_name);
842             // MS Kerberos LSA is our best option so use it and quit
843             if ( next->from_lsa )   
844                 break;
845         }
846         next = next->next;
847     }
848
849     if ( response ) {
850         *ccache = response;
851         return 1;
852     }
853     return 0;
854 }
855
856 void 
857 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
858 {
859     struct principal_ccache_data ** next = &princ_cc_data;
860
861     if ( !pname && !ccname )
862         return;
863
864     while ( (*next) ) {
865         if ( !strcmp((*next)->principal,pname) || 
866              !strcmp((*next)->ccache_name,ccname) ) {
867             void * temp;
868             free((*next)->principal);
869             free((*next)->ccache_name);
870             temp = (*next);
871             (*next) = (*next)->next;
872             free(temp);
873         }
874     }
875 }
876
877 void 
878 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
879 {
880     struct cell_principal_map * next = cell_princ_map;
881
882     // Search the existing list to see if we have a match 
883     if ( next ) {
884         for ( ; next ; next = next->next ) {
885             if ( !strcmp(next->cell, cell) ) {
886                 if ( !strcmp(next->principal,pname) ) {
887                     next->active = active;
888                                         break;
889                 } else {
890                     // OpenAFS currently has a restriction of one active token per cell
891                     // Therefore, whenever we update the table with a new active cell we
892                     // must mark all of the other principal to cell entries as inactive.
893                     if (active)
894                         next->active = 0;
895                 }
896             }
897         }
898     } 
899
900     // If not, match add a new node to the beginning of the list and assign init it
901     if ( !next ) {
902         next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
903         next->next = cell_princ_map;
904         cell_princ_map = next;
905         next->principal = _strdup(pname);
906         next->cell = _strdup(cell);
907         next->active = active;
908     }
909 }
910
911 void 
912 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
913 {
914     struct cell_principal_map ** next = &cell_princ_map;
915
916     if ( !pname && !cell )
917         return;
918
919     while ( (*next) ) {
920         if ( !strcmp((*next)->principal,pname) || 
921              !strcmp((*next)->cell,cell) ) {
922             void * temp;
923             free((*next)->principal);
924             free((*next)->cell);
925             temp = (*next);
926             (*next) = (*next)->next;
927             free(temp);
928         }
929     }
930 }
931
932 // Returns (if possible) a principal which has been known in 
933 // the past to have been used to obtain tokens for the specified
934 // cell.  
935 // TODO: Attempt to return one which has not yet expired by checking
936 // the principal/ccache data
937 int
938 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
939 {
940     struct cell_principal_map * next_map = cell_princ_map;
941     const char * princ = NULL;
942     int count = 0, i;
943
944     if ( !cell )
945         return 0;
946
947     while ( next_map ) {
948         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
949             count++;
950         }
951         next_map = next_map->next;
952     }
953
954     if ( !principals || !count )
955         return count;
956
957     *principals = (char **) malloc(sizeof(char *) * count);
958     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
959     {
960         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
961             (*principals)[i++] = _strdup(next_map->principal);
962         }
963     }
964     return count;
965 }
966
967 int
968 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
969 {
970     int     count = 0, i;
971     struct cell_principal_map * next_map = cell_princ_map;
972     const char * princ = NULL;
973     
974     if ( !pname )
975         return 0;
976
977     while ( next_map ) {
978         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
979             count++;
980         }
981         next_map = next_map->next;
982     }
983
984     if ( !cells )
985         return count;
986
987     *cells = (char **) malloc(sizeof(char *) * count);
988     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
989     {
990         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
991             (*cells)[i++] = _strdup(next_map->cell);
992         }
993     }
994     return count;
995 }
996
997 /* Given a principal return an existing ccache or create one and return */
998 int
999 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
1000 {
1001     krb5_context ctx = NULL;
1002     char * pname = NULL;
1003     char * ccname = NULL;
1004     krb5_error_code code;
1005
1006     if (!pkrb5_init_context)
1007         return 0;
1008
1009     if ( alt_ctx ) {
1010         ctx = alt_ctx;
1011     } else {
1012         code = pkrb5_init_context(&ctx);
1013         if (code) goto cleanup;
1014     }
1015
1016     if ( principal ) {
1017         code = pkrb5_unparse_name(ctx, principal, &pname);
1018         if (code) goto cleanup;
1019
1020         if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
1021              !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
1022             size_t len = strlen(pname) + 5;
1023             ccname = (char *)malloc(len);
1024             StringCbPrintf(ccname, len, "API:%s", pname);
1025         }
1026         code = pkrb5_cc_resolve(ctx, ccname, cc);
1027     } else {
1028         code = pkrb5_cc_default(ctx, cc);
1029         if (code) goto cleanup;
1030     }
1031
1032   cleanup:
1033     if (ccname)
1034         free(ccname);
1035     if (pname)
1036         pkrb5_free_unparsed_name(ctx,pname);
1037     if (ctx && (ctx != alt_ctx))
1038         pkrb5_free_context(ctx);
1039     return(code);
1040 }
1041
1042 #ifdef USE_MS2MIT
1043 // Import Microsoft Credentials into a new MIT ccache
1044 void
1045 KFW_import_windows_lsa(void)
1046 {
1047     krb5_context ctx = NULL;
1048     krb5_ccache  cc = NULL;
1049     krb5_principal princ = NULL;
1050     char * pname = NULL;
1051     krb5_data *  princ_realm;
1052     krb5_error_code code;
1053     char cell[128]="", realm[128]="", *def_realm = 0;
1054     unsigned int i;
1055     DWORD dwMsLsaImport;
1056          
1057     if (!pkrb5_init_context)
1058         return;
1059
1060     code = pkrb5_init_context(&ctx);
1061     if (code) goto cleanup;
1062
1063     code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
1064     if (code) goto cleanup;
1065
1066     KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
1067
1068     code = pkrb5_cc_get_principal(ctx, cc, &princ);
1069     if ( code ) goto cleanup;
1070
1071     dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
1072     switch ( dwMsLsaImport ) {
1073     case 0: /* do not import */
1074         goto cleanup;
1075     case 1: /* always import */
1076         break;
1077     case 2: { /* matching realm */
1078         char ms_realm[128] = "", *r;
1079         unsigned int j;
1080
1081         for ( r=ms_realm, j=0; j<krb5_princ_realm(ctx, princ)->length; r++, j++ ) {
1082             *r = krb5_princ_realm(ctx, princ)->data[j];
1083         }
1084         *r = '\0';
1085
1086         if (code = pkrb5_get_default_realm(ctx, &def_realm))
1087             goto cleanup;
1088
1089         if (strcmp(def_realm, ms_realm))
1090             goto cleanup;
1091         break;
1092     }
1093     default:
1094         break;
1095     }
1096
1097     code = pkrb5_unparse_name(ctx,princ,&pname);
1098     if ( code ) goto cleanup;
1099
1100     princ_realm = krb5_princ_realm(ctx, princ);
1101     for ( i=0; i<princ_realm->length; i++ ) {
1102         realm[i] = princ_realm->data[i];
1103         cell[i] = tolower(princ_realm->data[i]);
1104     }
1105     cell[i] = '\0';
1106     realm[i] = '\0';
1107
1108     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
1109     if ( IsDebuggerPresent() ) {
1110         char message[256];
1111         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1112         OutputDebugString(message);
1113     }
1114     if ( code ) goto cleanup;
1115
1116     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1117
1118   cleanup:
1119     if (pname)
1120         pkrb5_free_unparsed_name(ctx,pname);
1121     if (princ)
1122         pkrb5_free_principal(ctx,princ);
1123     if (def_realm)
1124         pkrb5_free_default_realm(ctx, def_realm);
1125     if (cc)
1126         pkrb5_cc_close(ctx,cc);
1127     if (ctx)
1128         pkrb5_free_context(ctx);
1129 }
1130 #endif /* USE_MS2MIT */
1131
1132 // If there are existing MIT credentials, copy them to a new
1133 // ccache named after the principal
1134
1135 // Enumerate all existing MIT ccaches and construct entries
1136 // in the principal_ccache table
1137
1138 // Enumerate all existing AFS Tokens and construct entries
1139 // in the cell_principal table
1140 void
1141 KFW_import_ccache_data(void)
1142 {
1143     krb5_context ctx = NULL;
1144     krb5_ccache  cc = NULL;
1145     krb5_principal principal = NULL;
1146     krb5_creds creds;
1147     krb5_error_code code;
1148     krb5_error_code cc_code;
1149     krb5_cc_cursor cur;
1150     apiCB * cc_ctx = NULL;
1151     struct _infoNC ** pNCi = NULL;
1152     int i, j, flags;
1153
1154     if ( !pcc_initialize )
1155         return;
1156
1157     if ( IsDebuggerPresent() )
1158         OutputDebugString("KFW_import_ccache_data()\n");
1159
1160     code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1161     if (code) goto cleanup;
1162
1163     code = pcc_get_NC_info(cc_ctx, &pNCi);
1164     if (code) goto cleanup;
1165
1166     code = pkrb5_init_context(&ctx);
1167     if (code) goto cleanup;
1168
1169     for ( i=0; pNCi[i]; i++ ) {
1170         if ( pNCi[i]->vers != CC_CRED_V5 )
1171             continue;
1172         if ( IsDebuggerPresent() ) {
1173             OutputDebugString("Principal: ");
1174             OutputDebugString(pNCi[i]->principal);
1175             OutputDebugString(" in ccache ");
1176             OutputDebugString(pNCi[i]->name);
1177             OutputDebugString("\n");
1178         }
1179         if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1180              && strcmp(pNCi[i]->name,LSA_CCNAME) 
1181              ) {
1182             int found = 0;
1183             for ( j=0; pNCi[j]; j++ ) {
1184                 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1185                     found = 1;
1186                     break;
1187                 }
1188             }
1189             
1190             code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1191             if (code) goto loop_cleanup;
1192
1193             if (!found) {
1194                 krb5_ccache oldcc = 0;
1195
1196                 if ( IsDebuggerPresent() )
1197                     OutputDebugString("copying ccache data to new ccache\n");
1198
1199                 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1200                 if (code) goto loop_cleanup;
1201                 code = pkrb5_cc_initialize(ctx, cc, principal);
1202                 if (code) goto loop_cleanup;
1203
1204                 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1205                 if (code) goto loop_cleanup;
1206                 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1207                 if (code) {
1208                     code = pkrb5_cc_close(ctx,cc);
1209                     cc = 0;
1210                     code = pkrb5_cc_close(ctx,oldcc);
1211                     oldcc = 0;
1212                     KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1213                     continue;
1214                 }
1215                 code = pkrb5_cc_close(ctx,oldcc);
1216             }
1217         } else {
1218             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1219             if (code) goto loop_cleanup;
1220         }
1221
1222         flags = 0;  // turn off OPENCLOSE mode
1223         code = pkrb5_cc_set_flags(ctx, cc, flags);
1224         if ( code ) goto cleanup;
1225
1226         KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1227
1228         cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1229
1230         while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1231             krb5_data * sname = krb5_princ_name(ctx, creds.server);
1232             krb5_data * cell  = krb5_princ_component(ctx, creds.server, 1);
1233             krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1234             if ( sname && cell && !strcmp("afs",sname->data) ) {
1235                 struct ktc_principal    aserver;
1236                 struct ktc_principal    aclient;
1237                 struct ktc_token        atoken;
1238                 int active = TRUE;
1239
1240                 if ( IsDebuggerPresent() )  {
1241                     OutputDebugString("Found AFS ticket: ");
1242                     OutputDebugString(sname->data);
1243                     if ( cell->data ) {
1244                         OutputDebugString("/");
1245                         OutputDebugString(cell->data);
1246                     }
1247                     OutputDebugString("@");
1248                     OutputDebugString(realm->data);
1249                     OutputDebugString("\n");
1250                 }
1251
1252                 memset(&aserver, '\0', sizeof(aserver));
1253                 StringCbCopyN( aserver.name, sizeof(aserver.name),
1254                                sname->data, sizeof(aserver.name) - 1);
1255                 StringCbCopyN( aserver.cell, sizeof(aserver.cell),
1256                                cell->data, sizeof(aserver.cell) - 1);
1257
1258                 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1259                 if (!code) {
1260                     // Found a token in AFS Client Server which matches
1261                     char pname[128], *p, *q;
1262                     for ( p=pname, q=aclient.name; *q; p++, q++)
1263                         *p = *q;
1264                     for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1265                         *p = toupper(*q);
1266                     *p = '\0';
1267
1268                     if ( IsDebuggerPresent() )  {
1269                         OutputDebugString("Found AFS token: ");
1270                         OutputDebugString(pname);
1271                         OutputDebugString("\n");
1272                     }
1273
1274                     if ( strcmp(pname,pNCi[i]->principal)  )
1275                         active = FALSE;
1276                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1277                 } else {
1278                     // Attempt to import it
1279                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1280
1281                     if ( IsDebuggerPresent() )  {
1282                         OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1283                     }
1284
1285                     code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, 
1286 #ifndef USE_LEASH
1287                                         600,
1288 #else
1289                                         pLeash_get_default_lifetime(),
1290 #endif /* USE_LEASH */
1291                                         NULL);
1292                     if ( IsDebuggerPresent() ) {
1293                         char message[256];
1294                         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1295                         OutputDebugString(message);
1296                     }
1297                 }
1298             } else if ( IsDebuggerPresent() ) {
1299                 OutputDebugString("Found ticket: ");
1300                 OutputDebugString(sname->data);
1301                 if ( cell && cell->data ) {
1302                     OutputDebugString("/");
1303                     OutputDebugString(cell->data);
1304                 }
1305                 OutputDebugString("@");
1306                 OutputDebugString(realm->data);
1307                 OutputDebugString("\n");
1308             }
1309             pkrb5_free_cred_contents(ctx, &creds);
1310         }
1311
1312         if (cc_code == KRB5_CC_END) {
1313             cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1314             if (cc_code) goto loop_cleanup;
1315         }
1316
1317       loop_cleanup:
1318         flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
1319         code = pkrb5_cc_set_flags(ctx, cc, flags);
1320         if (cc) {
1321             pkrb5_cc_close(ctx,cc);
1322             cc = 0;
1323         }
1324         if (principal) {
1325             pkrb5_free_principal(ctx,principal);
1326             principal = 0;
1327         }
1328     }
1329
1330   cleanup:
1331     if (ctx)
1332         pkrb5_free_context(ctx);
1333     if (pNCi)
1334         pcc_free_NC_info(cc_ctx, &pNCi);
1335     if (cc_ctx)
1336         pcc_shutdown(&cc_ctx);
1337 }
1338
1339
1340 int
1341 KFW_AFS_get_cred( char * username, 
1342                   char * cell,
1343                   char * password,
1344                   int lifetime,
1345                   char * smbname,
1346                   char ** reasonP )
1347 {
1348     static char reason[1024]="";
1349     krb5_context ctx = NULL;
1350     krb5_ccache cc = NULL;
1351     char * realm = NULL, * userrealm = NULL;
1352     krb5_principal principal = NULL;
1353     char * pname = NULL;
1354     krb5_error_code code;
1355     char local_cell[CELL_MAXNAMELEN+1];
1356     char **cells = NULL;
1357     int  cell_count=0;
1358     struct afsconf_cell cellconfig;
1359     char * dot;
1360
1361     if (!pkrb5_init_context)
1362         return 0;
1363
1364     if ( IsDebuggerPresent() ) {
1365         OutputDebugString("KFW_AFS_get_cred for token ");
1366         OutputDebugString(username);
1367         OutputDebugString(" in cell ");
1368         OutputDebugString(cell);
1369         OutputDebugString("\n");
1370     }
1371
1372     memset(&cellconfig, 0, sizeof(cellconfig));
1373
1374     code = pkrb5_init_context(&ctx);
1375     if ( code ) goto cleanup;
1376
1377     code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1378     if ( code ) goto cleanup;
1379
1380     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1381
1382     userrealm = strchr(username,'@');
1383     if ( userrealm ) {
1384         pname = strdup(username);
1385         if (!KFW_accept_dotted_usernames()) {
1386             userrealm = strchr(pname, '@');
1387             *userrealm = '\0';
1388
1389             /* handle kerberos iv notation */
1390             while ( dot = strchr(pname,'.') ) {
1391                 *dot = '/';
1392             }
1393             *userrealm++ = '@';
1394         }
1395     } else {
1396         size_t len = strlen(username) + strlen(realm) + 2;
1397         pname = malloc(len);
1398         if (pname == NULL) {
1399             code = KRB5KRB_ERR_GENERIC;
1400             goto cleanup;
1401         }
1402         StringCbCopy(pname, len, username);
1403
1404         if (!KFW_accept_dotted_usernames()) {
1405             /* handle kerberos iv notation */
1406             while ( dot = strchr(pname,'.') ) {
1407                 *dot = '/';
1408             }
1409         }
1410         StringCbCat( pname, len, "@");
1411         StringCbCat( pname, len, realm);
1412     }
1413     if ( IsDebuggerPresent() ) {
1414         OutputDebugString("Realm: ");
1415         OutputDebugString(realm);
1416         OutputDebugString("\n");
1417     }
1418
1419     code = pkrb5_parse_name(ctx, pname, &principal);
1420     if ( code ) goto cleanup;
1421
1422     code = KFW_get_ccache(ctx, principal, &cc);
1423     if ( code ) goto cleanup;
1424
1425     if ( lifetime == 0 )
1426 #ifndef USE_LEASH
1427         lifetime = 600;
1428 #else
1429         lifetime = pLeash_get_default_lifetime();
1430 #endif
1431
1432     if ( password && password[0] ) {
1433         code = KFW_kinit( ctx, cc, HWND_DESKTOP, 
1434                           pname, 
1435                           password,
1436                           lifetime,
1437 #ifndef USE_LEASH
1438                           1, /* forwardable */
1439                           0, /* not proxiable */
1440                           1, /* renewable */
1441                           1, /* noaddresses */
1442                           0  /* no public ip */
1443 #else
1444                           pLeash_get_default_forwardable(),
1445                           pLeash_get_default_proxiable(),
1446                           pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1447                           pLeash_get_default_noaddresses(),
1448                           pLeash_get_default_publicip()
1449 #endif /* USE_LEASH */
1450                           );
1451
1452         if ( IsDebuggerPresent() ) {
1453             char message[256];
1454             StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1455             OutputDebugString(message);
1456         }
1457         if ( code ) goto cleanup;
1458
1459         KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1460     }
1461
1462     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1463     if ( IsDebuggerPresent() ) {
1464         char message[256];
1465         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1466         OutputDebugString(message);
1467     }
1468     if ( code ) goto cleanup;
1469
1470     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1471
1472     // Attempt to obtain new tokens for other cells supported by the same 
1473     // principal
1474     cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1475     if ( cell_count > 1 ) {
1476         while ( cell_count-- ) {
1477             if ( strcmp(cells[cell_count],cell) ) {
1478                 if ( IsDebuggerPresent() ) {
1479                     char message[256];
1480                     StringCbPrintf(message, sizeof(message),
1481                                    "found another cell for the same principal: %s\n", cell);
1482                     OutputDebugString(message);
1483                 }
1484
1485                 if (cellconfig.linkedCell) {
1486                     free(cellconfig.linkedCell);
1487                     cellconfig.linkedCell = NULL;
1488                 }
1489                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1490                 if ( code ) continue;
1491     
1492                 realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1493                 if ( IsDebuggerPresent() ) {
1494                     OutputDebugString("Realm: ");
1495                     OutputDebugString(realm);
1496                     OutputDebugString("\n");
1497                 }
1498                 
1499                 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1500                 if ( IsDebuggerPresent() ) {
1501                     char message[256];
1502                     StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1503                     OutputDebugString(message);
1504                 }
1505             }
1506             free(cells[cell_count]);
1507         }
1508         free(cells);
1509     } else if ( cell_count == 1 ) {
1510         free(cells[0]);
1511         free(cells);
1512     }
1513
1514   cleanup:
1515     if ( pname )
1516         free(pname);
1517     if ( cc )
1518         pkrb5_cc_close(ctx, cc);
1519     if ( cellconfig.linkedCell )
1520         free(cellconfig.linkedCell);
1521
1522     if ( code && reasonP ) {
1523         if (pkrb5_get_error_message) {
1524             char *msg = pkrb5_get_error_message(ctx, code);
1525             StringCbCopyN( reason, sizeof(reason),
1526                            msg, sizeof(reason) - 1);
1527             *reasonP = reason;
1528             pkrb5_free_error_message(ctx, msg);
1529         } else {
1530             *reasonP = perror_message(code);
1531         }
1532     }
1533     return(code);
1534 }
1535
1536 int 
1537 KFW_AFS_destroy_tickets_for_cell(char * cell)
1538 {
1539     krb5_context        ctx = NULL;
1540     krb5_error_code     code;
1541     int count;
1542     char ** principals = NULL;
1543
1544     if (!pkrb5_init_context)
1545         return 0;
1546
1547     if ( IsDebuggerPresent() ) {
1548         OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1549         OutputDebugString(cell);
1550         OutputDebugString("\n");
1551     }
1552
1553     code = pkrb5_init_context(&ctx);
1554     if (code) ctx = 0;
1555
1556     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1557     if ( count > 0 ) {
1558         krb5_principal      princ = 0;
1559         krb5_ccache                     cc  = 0;
1560
1561         while ( count-- ) {
1562             int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1563             if ( cell_count > 1 ) {
1564                 // TODO - What we really should do here is verify whether or not any of the
1565                 // other cells which use this principal to obtain its credentials actually
1566                 // have valid tokens or not.  If they are currently using these credentials
1567                 // we will skip them.  For the time being we assume that if there is an active
1568                 // map in the table that they are actively being used.
1569                 goto loop_cleanup;
1570             }
1571
1572             code = pkrb5_parse_name(ctx, principals[count], &princ);
1573             if (code) goto loop_cleanup;
1574
1575             code = KFW_get_ccache(ctx, princ, &cc);
1576             if (code) goto loop_cleanup;
1577
1578             code = pkrb5_cc_destroy(ctx, cc);
1579             if (!code) cc = 0;
1580
1581           loop_cleanup:
1582             if ( cc ) {
1583                 pkrb5_cc_close(ctx, cc);
1584                 cc = 0;
1585             }
1586             if ( princ ) {
1587                 pkrb5_free_principal(ctx, princ);
1588                 princ = 0;
1589             }
1590
1591             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1592             free(principals[count]);
1593         }
1594         free(principals);
1595     }
1596     if (ctx)
1597                 pkrb5_free_context(ctx);
1598     return 0;
1599 }
1600
1601 int 
1602 KFW_AFS_destroy_tickets_for_principal(char * user)
1603 {
1604     krb5_context        ctx = NULL;
1605     krb5_error_code     code;
1606     int count;
1607     char ** cells = NULL;
1608     krb5_principal      princ = NULL;
1609     krb5_ccache         cc  = NULL;
1610
1611     if (!pkrb5_init_context)
1612         return 0;
1613
1614     if ( IsDebuggerPresent() ) {
1615         OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1616         OutputDebugString(user);
1617         OutputDebugString("\n");
1618     }
1619
1620     code = pkrb5_init_context(&ctx);
1621     if (code) return 0;
1622
1623     code = pkrb5_parse_name(ctx, user, &princ);
1624     if (code) goto loop_cleanup;
1625
1626     code = KFW_get_ccache(ctx, princ, &cc);
1627     if (code) goto loop_cleanup;
1628
1629     code = pkrb5_cc_destroy(ctx, cc);
1630     if (!code) cc = 0;
1631
1632   loop_cleanup:
1633     if ( cc ) {
1634         pkrb5_cc_close(ctx, cc);
1635         cc = 0;
1636     }
1637     if ( princ ) {
1638         pkrb5_free_principal(ctx, princ);
1639         princ = 0;
1640     }
1641
1642     count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1643     if ( count >= 1 ) {
1644         while ( count-- ) {
1645             KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1646             free(cells[count]);
1647         }
1648         free(cells);
1649     }
1650
1651     if (ctx)
1652                 pkrb5_free_context(ctx);
1653     return 0;
1654 }
1655
1656 int
1657 KFW_AFS_renew_expiring_tokens(void)
1658 {
1659     krb5_error_code     code = 0;
1660     krb5_context        ctx = NULL;
1661     krb5_ccache         cc = NULL;
1662     krb5_timestamp now;
1663     struct principal_ccache_data * pcc_next = princ_cc_data;
1664     int cell_count;
1665     char ** cells=NULL;
1666     const char * realm = NULL;
1667     char local_cell[CELL_MAXNAMELEN+1]="";
1668     struct afsconf_cell cellconfig;
1669
1670     if (!pkrb5_init_context)
1671         return 0;
1672
1673     if ( pcc_next == NULL ) // nothing to do
1674         return 0;
1675
1676     if ( IsDebuggerPresent() ) {
1677         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1678     }
1679
1680     memset(&cellconfig, 0, sizeof(cellconfig));
1681
1682     code = pkrb5_init_context(&ctx);
1683     if (code) goto cleanup;
1684
1685     code = pkrb5_timeofday(ctx, &now);
1686     if (code) goto cleanup; 
1687
1688     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1689         if ( pcc_next->expired ) 
1690             continue;
1691
1692         if ( now >= (pcc_next->expiration_time) ) {
1693             if ( !pcc_next->from_lsa ) {
1694                 pcc_next->expired = 1;
1695                 continue;
1696             }
1697         }
1698
1699         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1700             code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1701             if ( code ) 
1702                                 goto loop_cleanup;
1703             code = KFW_renew(ctx,cc);
1704 #ifdef USE_MS2MIT
1705             if ( code && pcc_next->from_lsa)
1706                 goto loop_cleanup;
1707 #endif /* USE_MS2MIT */
1708
1709
1710             KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1711             if (code) goto loop_cleanup;
1712
1713             // Attempt to obtain new tokens for other cells supported by the same 
1714             // principal
1715             cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1716             if ( cell_count > 0 ) {
1717                 while ( cell_count-- ) {
1718                     if ( IsDebuggerPresent() ) {
1719                         OutputDebugString("Cell: ");
1720                         OutputDebugString(cells[cell_count]);
1721                         OutputDebugString("\n");
1722                     }
1723                     if (cellconfig.linkedCell) {
1724                         free(cellconfig.linkedCell);
1725                         cellconfig.linkedCell = NULL;
1726                     }
1727                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1728                     if ( code ) continue;
1729                     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1730                     if ( IsDebuggerPresent() ) {
1731                         OutputDebugString("Realm: ");
1732                         OutputDebugString(realm);
1733                         OutputDebugString("\n");
1734                     }
1735                     code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1736                     if ( IsDebuggerPresent() ) {
1737                         char message[256];
1738                         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1739                         OutputDebugString(message);
1740                     }
1741                     free(cells[cell_count]);
1742                 }
1743                 free(cells);
1744             }
1745         }
1746
1747       loop_cleanup:
1748         if ( cc ) {
1749             pkrb5_cc_close(ctx,cc);
1750             cc = 0;
1751         }
1752     }
1753
1754   cleanup:
1755     if ( cc )
1756         pkrb5_cc_close(ctx,cc);
1757     if ( ctx )
1758         pkrb5_free_context(ctx);
1759     if (cellconfig.linkedCell)
1760         free(cellconfig.linkedCell);
1761
1762     return 0;
1763 }
1764
1765
1766 BOOL
1767 KFW_AFS_renew_token_for_cell(char * cell)
1768 {
1769     krb5_error_code     code = 0;
1770     krb5_context        ctx = NULL;
1771     int count;
1772     char ** principals = NULL;
1773
1774     if (!pkrb5_init_context)
1775         return 0;
1776
1777     if ( IsDebuggerPresent() ) {
1778         OutputDebugString("KFW_AFS_renew_token_for_cell:");
1779         OutputDebugString(cell);
1780         OutputDebugString("\n");
1781     }
1782
1783     code = pkrb5_init_context(&ctx);
1784     if (code) goto cleanup;
1785
1786     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1787     if ( count == 0 ) {
1788         // We know we must have a credential somewhere since we are
1789         // trying to renew a token
1790
1791         KFW_import_ccache_data();
1792         count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1793     }
1794     if ( count > 0 ) {
1795         krb5_principal      princ = 0;
1796         krb5_principal      service = 0;
1797 #ifdef COMMENT
1798         krb5_creds          mcreds, creds;
1799 #endif /* COMMENT */
1800         krb5_ccache                     cc  = 0;
1801         const char * realm = NULL;
1802         struct afsconf_cell cellconfig;
1803         char local_cell[CELL_MAXNAMELEN+1];
1804
1805         memset(&cellconfig, 0, sizeof(cellconfig));
1806
1807         while ( count-- ) {
1808             code = pkrb5_parse_name(ctx, principals[count], &princ);
1809             if (code) goto loop_cleanup;
1810
1811             code = KFW_get_ccache(ctx, princ, &cc);
1812             if (code) goto loop_cleanup;
1813
1814             if (cellconfig.linkedCell) {
1815                 free(cellconfig.linkedCell);
1816                 cellconfig.linkedCell = NULL;
1817             }
1818             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1819             if ( code ) goto loop_cleanup;
1820
1821             realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1822             if ( IsDebuggerPresent() ) {
1823                 OutputDebugString("Realm: ");
1824                 OutputDebugString(realm);
1825                 OutputDebugString("\n");
1826             }
1827
1828 #ifdef COMMENT
1829             /* krb5_cc_remove_cred() is not implemented 
1830              * for a single cred 
1831              */
1832             code = pkrb5_build_principal(ctx, &service, strlen(realm),
1833                                           realm, "afs", cell, NULL);
1834             if (!code) {
1835                 memset(&mcreds, 0, sizeof(krb5_creds));
1836                 mcreds.client = princ;
1837                 mcreds.server = service;
1838
1839                 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1840                 if (!code) {
1841                     if ( IsDebuggerPresent() ) {
1842                         char * cname, *sname;
1843                         pkrb5_unparse_name(ctx, creds.client, &cname);
1844                         pkrb5_unparse_name(ctx, creds.server, &sname);
1845                         OutputDebugString("Removing credential for client \"");
1846                         OutputDebugString(cname);
1847                         OutputDebugString("\" and service \"");
1848                         OutputDebugString(sname);
1849                         OutputDebugString("\"\n");
1850                         pkrb5_free_unparsed_name(ctx,cname);
1851                         pkrb5_free_unparsed_name(ctx,sname);
1852                     }
1853
1854                     code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1855                     pkrb5_free_principal(ctx, creds.client);
1856                     pkrb5_free_principal(ctx, creds.server);
1857                 }
1858             }
1859 #endif /* COMMENT */
1860
1861             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1862             if ( IsDebuggerPresent() ) {
1863                 char message[256];
1864                 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1865                 OutputDebugString(message);
1866             }
1867
1868           loop_cleanup:
1869             if (cc) {
1870                 pkrb5_cc_close(ctx, cc);
1871                 cc = 0;
1872             }
1873             if (princ) {
1874                 pkrb5_free_principal(ctx, princ);
1875                 princ = 0;
1876             }
1877             if (service) {
1878                 pkrb5_free_principal(ctx, service);
1879                 princ = 0;
1880             }
1881             if (cellconfig.linkedCell) {
1882                 free(cellconfig.linkedCell);
1883                 cellconfig.linkedCell = NULL;
1884             }
1885
1886             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1887             free(principals[count]);
1888         }
1889         free(principals);
1890     } else
1891         code = -1;      // we did not renew the tokens 
1892
1893   cleanup:
1894     if (ctx) 
1895         pkrb5_free_context(ctx);
1896     return (code ? FALSE : TRUE);
1897
1898 }
1899
1900 int
1901 KFW_AFS_renew_tokens_for_all_cells(void)
1902 {
1903     struct cell_principal_map * next = cell_princ_map;
1904
1905     if ( IsDebuggerPresent() )
1906         OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1907
1908     if ( !next )
1909         return 0;
1910
1911     for ( ; next ; next = next->next ) {
1912         if ( next->active )
1913             KFW_AFS_renew_token_for_cell(next->cell);
1914     }
1915     return 0;
1916 }
1917
1918 int
1919 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1920 {
1921     krb5_error_code     code = 0;
1922     krb5_context        ctx = NULL;
1923     krb5_ccache         cc = NULL;
1924     krb5_principal      me = NULL;
1925     krb5_principal      server = NULL;
1926     krb5_creds          my_creds;
1927     krb5_data           *realm = NULL;
1928
1929     if (!pkrb5_init_context)
1930         return 0;
1931
1932         memset(&my_creds, 0, sizeof(krb5_creds));
1933
1934     if ( alt_ctx ) {
1935         ctx = alt_ctx;
1936     } else {
1937         code = pkrb5_init_context(&ctx);
1938         if (code) goto cleanup;
1939     }
1940
1941     if ( alt_cc ) {
1942         cc = alt_cc;
1943     } else {
1944         code = pkrb5_cc_default(ctx, &cc);
1945         if (code) goto cleanup;
1946     }
1947
1948     code = pkrb5_cc_get_principal(ctx, cc, &me);
1949     if (code) goto cleanup;
1950
1951     realm = krb5_princ_realm(ctx, me);
1952
1953     code = pkrb5_build_principal_ext(ctx, &server,
1954                                     realm->length,realm->data,
1955                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1956                                     realm->length,realm->data,
1957                                     0);
1958     if ( code ) 
1959         goto cleanup;
1960
1961     if ( IsDebuggerPresent() ) {
1962         char * cname, *sname;
1963         pkrb5_unparse_name(ctx, me, &cname);
1964         pkrb5_unparse_name(ctx, server, &sname);
1965         OutputDebugString("Renewing credential for client \"");
1966         OutputDebugString(cname);
1967         OutputDebugString("\" and service \"");
1968         OutputDebugString(sname);
1969         OutputDebugString("\"\n");
1970         pkrb5_free_unparsed_name(ctx,cname);
1971         pkrb5_free_unparsed_name(ctx,sname);
1972     }
1973
1974     my_creds.client = me;
1975     my_creds.server = server;
1976
1977     code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1978     if (code) {
1979         if ( IsDebuggerPresent() ) {
1980             char message[256];
1981             StringCbPrintf(message, sizeof(message), "krb5_get_renewed_creds() failed: %d\n", code);
1982             OutputDebugString(message);
1983         }
1984         goto cleanup;
1985     }
1986
1987     code = pkrb5_cc_initialize(ctx, cc, me);
1988     if (code) {
1989         if ( IsDebuggerPresent() ) {
1990             char message[256];
1991             StringCbPrintf(message, sizeof(message), "krb5_cc_initialize() failed: %d\n", code);
1992             OutputDebugString(message);
1993         }
1994         goto cleanup;
1995     }
1996
1997     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1998     if (code) {
1999         if ( IsDebuggerPresent() ) {
2000             char message[256];
2001             StringCbPrintf(message, sizeof(message), "krb5_cc_store_cred() failed: %d\n", code);
2002             OutputDebugString(message);
2003         }
2004         goto cleanup;
2005     }
2006
2007   cleanup:
2008     if (my_creds.client == me)
2009         my_creds.client = 0;
2010     if (my_creds.server == server)
2011         my_creds.server = 0;
2012     pkrb5_free_cred_contents(ctx, &my_creds);
2013     if (me)
2014         pkrb5_free_principal(ctx, me);
2015     if (server)
2016         pkrb5_free_principal(ctx, server);
2017     if (cc && (cc != alt_cc))
2018         pkrb5_cc_close(ctx, cc);
2019     if (ctx && (ctx != alt_ctx))
2020         pkrb5_free_context(ctx);
2021     return(code);
2022 }
2023
2024 int
2025 KFW_kinit( krb5_context alt_ctx,
2026             krb5_ccache  alt_cc,
2027             HWND hParent,
2028             char *principal_name,
2029             char *password,
2030             krb5_deltat lifetime,
2031             DWORD                       forwardable,
2032             DWORD                       proxiable,
2033             krb5_deltat                 renew_life,
2034             DWORD                       addressless,
2035             DWORD                       publicIP
2036             )
2037 {
2038     krb5_error_code             code = 0;
2039     krb5_context                ctx = NULL;
2040     krb5_ccache                 cc = NULL;
2041     krb5_principal              me = NULL;
2042     char*                       name = NULL;
2043     krb5_creds                  my_creds;
2044     krb5_get_init_creds_opt     options;
2045     krb5_address **             addrs = NULL;
2046     int                         i = 0, addr_count = 0;
2047
2048     if (!pkrb5_init_context)
2049         return 0;
2050
2051     pkrb5_get_init_creds_opt_init(&options);
2052     memset(&my_creds, 0, sizeof(my_creds));
2053
2054     if (alt_ctx)
2055     {
2056         ctx = alt_ctx;
2057     }
2058     else
2059     {
2060         code = pkrb5_init_context(&ctx);
2061         if (code) goto cleanup;
2062     }
2063
2064     if ( alt_cc ) {
2065         cc = alt_cc;
2066     } else {
2067         code = pkrb5_cc_default(ctx, &cc);  
2068         if (code) goto cleanup;
2069     }
2070
2071     code = pkrb5_parse_name(ctx, principal_name, &me);
2072     if (code) 
2073         goto cleanup;
2074
2075     code = pkrb5_unparse_name(ctx, me, &name);
2076     if (code) 
2077         goto cleanup;
2078
2079     if (lifetime == 0)
2080 #ifndef USE_LEASH
2081         lifetime = 600;
2082 #else
2083         lifetime = pLeash_get_default_lifetime();
2084 #endif /* USE_LEASH */
2085     lifetime *= 60;
2086
2087     if (renew_life > 0)
2088         renew_life *= 60;
2089
2090     if (lifetime)
2091         pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
2092         pkrb5_get_init_creds_opt_set_forwardable(&options,
2093                                                  forwardable ? 1 : 0);
2094         pkrb5_get_init_creds_opt_set_proxiable(&options,
2095                                                proxiable ? 1 : 0);
2096         pkrb5_get_init_creds_opt_set_renew_life(&options,
2097                                                renew_life);
2098     if (addressless)
2099         pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
2100     else {
2101         if (publicIP)
2102         {
2103             // we are going to add the public IP address specified by the user
2104             // to the list provided by the operating system
2105             krb5_address ** local_addrs=NULL;
2106             DWORD           netIPAddr;
2107
2108             pkrb5_os_localaddr(ctx, &local_addrs);
2109             while ( local_addrs[i++] );
2110             addr_count = i + 1;
2111
2112             addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
2113             if ( !addrs ) {
2114                 pkrb5_free_addresses(ctx, local_addrs);
2115                 goto cleanup;
2116             }
2117             memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
2118             i = 0;
2119             while ( local_addrs[i] ) {
2120                 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2121                 if (addrs[i] == NULL) {
2122                     pkrb5_free_addresses(ctx, local_addrs);
2123                     goto cleanup;
2124                 }
2125
2126                 addrs[i]->magic = local_addrs[i]->magic;
2127                 addrs[i]->addrtype = local_addrs[i]->addrtype;
2128                 addrs[i]->length = local_addrs[i]->length;
2129                 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2130                 if (!addrs[i]->contents) {
2131                     pkrb5_free_addresses(ctx, local_addrs);
2132                     goto cleanup;
2133                 }
2134
2135                 memcpy(addrs[i]->contents,local_addrs[i]->contents,
2136                         local_addrs[i]->length);        /* safe */
2137                 i++;
2138             }
2139             pkrb5_free_addresses(ctx, local_addrs);
2140
2141             addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2142             if (addrs[i] == NULL)
2143                 goto cleanup;
2144
2145             addrs[i]->magic = KV5M_ADDRESS;
2146             addrs[i]->addrtype = AF_INET;
2147             addrs[i]->length = 4;
2148             addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2149             if (!addrs[i]->contents)
2150                 goto cleanup;
2151
2152             netIPAddr = htonl(publicIP);
2153             memcpy(addrs[i]->contents,&netIPAddr,4);
2154         
2155             pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
2156
2157         }
2158     }
2159
2160     code = pkrb5_get_init_creds_password(ctx, 
2161                                        &my_creds, 
2162                                        me,
2163                                        password, // password
2164                                        KRB5_prompter, // prompter
2165                                        hParent, // prompter data
2166                                        0, // start time
2167                                        0, // service name
2168                                        &options);
2169     if (code) 
2170         goto cleanup;
2171
2172     code = pkrb5_cc_initialize(ctx, cc, me);
2173     if (code) 
2174         goto cleanup;
2175
2176     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
2177     if (code) 
2178         goto cleanup;
2179
2180  cleanup:
2181     if ( addrs ) {
2182         for ( i=0;i<addr_count;i++ ) {
2183             if ( addrs[i] ) {
2184                 if ( addrs[i]->contents )
2185                     free(addrs[i]->contents);
2186                 free(addrs[i]);
2187             }
2188         }
2189     }
2190     if (my_creds.client == me)
2191         my_creds.client = 0;
2192     pkrb5_free_cred_contents(ctx, &my_creds);
2193     if (name)
2194         pkrb5_free_unparsed_name(ctx, name);
2195     if (me)
2196         pkrb5_free_principal(ctx, me);
2197     if (cc && (cc != alt_cc))
2198         pkrb5_cc_close(ctx, cc);
2199     if (ctx && (ctx != alt_ctx))
2200         pkrb5_free_context(ctx);
2201     return(code);
2202 }
2203
2204
2205 int
2206 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2207 {
2208     krb5_context                ctx = NULL;
2209     krb5_ccache                 cc = NULL;
2210     krb5_error_code             code;
2211
2212     if (!pkrb5_init_context)
2213         return 0;
2214
2215     if (alt_ctx)
2216     {
2217         ctx = alt_ctx;
2218     }
2219     else
2220     {
2221         code = pkrb5_init_context(&ctx);
2222         if (code) goto cleanup;
2223     }
2224
2225     if ( alt_cc ) {
2226         cc = alt_cc;
2227     } else {
2228         code = pkrb5_cc_default(ctx, &cc);  
2229         if (code) goto cleanup;
2230     }
2231
2232     code = pkrb5_cc_destroy(ctx, cc);
2233     if ( !code ) cc = 0;
2234
2235   cleanup:
2236     if (cc && (cc != alt_cc))
2237         pkrb5_cc_close(ctx, cc);
2238     if (ctx && (ctx != alt_ctx))
2239         pkrb5_free_context(ctx);
2240
2241     return(code);
2242 }
2243
2244
2245 #ifdef USE_MS2MIT
2246 static BOOL
2247 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2248 {
2249     NTSTATUS Status = 0;
2250     HANDLE  TokenHandle;
2251     TOKEN_STATISTICS Stats;
2252     DWORD   ReqLen;
2253     BOOL    Success;
2254
2255     if (!ppSessionData)
2256         return FALSE;
2257     *ppSessionData = NULL;
2258
2259     Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2260     if ( !Success )
2261         return FALSE;
2262
2263     Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2264     CloseHandle( TokenHandle );
2265     if ( !Success )
2266         return FALSE;
2267
2268     Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2269     if ( FAILED(Status) || !ppSessionData )
2270         return FALSE;
2271
2272     return TRUE;
2273 }
2274
2275 //
2276 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the 
2277 // cache.  It validates whether or not it is reasonable to assume that if we 
2278 // attempted to retrieve valid tickets we could do so.  Microsoft does not 
2279 // automatically renew expired tickets.  Therefore, the cache could contain
2280 // expired or invalid tickets.  Microsoft also caches the user's password 
2281 // and will use it to retrieve new TGTs if the cache is empty and tickets
2282 // are requested.
2283
2284 static BOOL
2285 MSLSA_IsKerberosLogon(VOID)
2286 {
2287     PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2288     BOOL    Success = FALSE;
2289
2290     if ( GetSecurityLogonSessionData(&pSessionData) ) {
2291         if ( pSessionData->AuthenticationPackage.Buffer ) {
2292             WCHAR buffer[256];
2293             WCHAR *usBuffer;
2294             int usLength;
2295
2296             Success = FALSE;
2297             usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2298             usLength = (pSessionData->AuthenticationPackage).Length;
2299             if (usLength < 256)
2300             {
2301                 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
2302                                 usBuffer, usLength);
2303                 if ( !lstrcmpW(L"Kerberos",buffer) )
2304                     Success = TRUE;
2305             }
2306         }
2307         pLsaFreeReturnBuffer(pSessionData);
2308     }
2309     return Success;
2310 }
2311 #endif /* USE_MS2MIT */
2312
2313 static BOOL CALLBACK 
2314 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2315 {
2316     int i;
2317
2318     switch ( message ) {
2319     case WM_INITDIALOG:
2320         if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2321         {
2322             SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2323             return FALSE;
2324         }
2325                 for ( i=0; i < mid_cnt ; i++ ) {
2326                         if (mid_tb[i].echo == 0)
2327                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2328                     else if (mid_tb[i].echo == 2) 
2329                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2330                 }
2331         return TRUE;
2332
2333     case WM_COMMAND:
2334         switch ( LOWORD(wParam) ) {
2335         case IDOK:
2336             for ( i=0; i < mid_cnt ; i++ ) {
2337                 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2338                     *mid_tb[i].buf = '\0';
2339             }
2340             /* fallthrough */
2341         case IDCANCEL:
2342             EndDialog(hDialog, LOWORD(wParam));
2343             return TRUE;
2344         }
2345     }
2346     return FALSE;
2347 }
2348
2349 static LPWORD 
2350 lpwAlign( LPWORD lpIn )
2351 {
2352     ULONG_PTR ul;
2353
2354     ul = (ULONG_PTR) lpIn;
2355     ul += 3;
2356     ul >>=2;
2357     ul <<=2;
2358     return (LPWORD) ul;;
2359 }
2360
2361 /*
2362  * dialog widths are measured in 1/4 character widths
2363  * dialog height are measured in 1/8 character heights
2364  */
2365
2366 static LRESULT
2367 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 
2368                   char * ptext[], int numlines, int width, 
2369                   int tb_cnt, struct textField * tb)
2370 {
2371     HGLOBAL hgbl;
2372     LPDLGTEMPLATE lpdt;
2373     LPDLGITEMTEMPLATE lpdit;
2374     LPWORD lpw;
2375     LPWSTR lpwsz;
2376     LRESULT ret;
2377     int nchar, i, pwid;
2378
2379     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2380     if (!hgbl)
2381         return -1;
2382  
2383     mid_cnt = tb_cnt;
2384     mid_tb = tb;
2385
2386     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2387  
2388     // Define a dialog box.
2389  
2390     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2391                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
2392                    | DS_SETFOREGROUND | DS_3DLOOK
2393                    | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2394     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
2395     lpdt->x  = 10;  
2396     lpdt->y  = 10;
2397     lpdt->cx = 20 + width * 4; 
2398     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2399
2400     lpw = (LPWORD) (lpdt + 1);
2401     *lpw++ = 0;   // no menu
2402     *lpw++ = 0;   // predefined dialog box class (by default)
2403
2404     lpwsz = (LPWSTR) lpw;
2405     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2406     lpw   += nchar;
2407     *lpw++ = 8;                        // font size (points)
2408     lpwsz = (LPWSTR) lpw;
2409     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
2410                                     -1, lpwsz, 128);
2411     lpw   += nchar;
2412
2413     //-----------------------
2414     // Define an OK button.
2415     //-----------------------
2416     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2417     lpdit = (LPDLGITEMTEMPLATE) lpw;
2418     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2419     lpdit->dwExtendedStyle = 0;
2420     lpdit->x  = (lpdt->cx - 14)/4 - 20; 
2421     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2422     lpdit->cx = 40; 
2423     lpdit->cy = 14;
2424     lpdit->id = IDOK;  // OK button identifier
2425
2426     lpw = (LPWORD) (lpdit + 1);
2427     *lpw++ = 0xFFFF;
2428     *lpw++ = 0x0080;    // button class
2429
2430     lpwsz = (LPWSTR) lpw;
2431     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2432     lpw   += nchar;
2433     *lpw++ = 0;           // no creation data
2434
2435     //-----------------------
2436     // Define an Cancel button.
2437     //-----------------------
2438     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2439     lpdit = (LPDLGITEMTEMPLATE) lpw;
2440     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2441     lpdit->dwExtendedStyle = 0;
2442     lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
2443     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2444     lpdit->cx = 40; 
2445     lpdit->cy = 14;
2446     lpdit->id = IDCANCEL;  // CANCEL button identifier
2447
2448     lpw = (LPWORD) (lpdit + 1);
2449     *lpw++ = 0xFFFF;
2450     *lpw++ = 0x0080;    // button class
2451
2452     lpwsz = (LPWSTR) lpw;
2453     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2454     lpw   += nchar;
2455     *lpw++ = 0;           // no creation data
2456
2457     /* Add controls for preface data */
2458     for ( i=0; i<numlines; i++) {
2459         /*-----------------------
2460          * Define a static text control.
2461          *-----------------------*/
2462         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2463         lpdit = (LPDLGITEMTEMPLATE) lpw;
2464         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2465         lpdit->dwExtendedStyle = 0;
2466         lpdit->x  = 10; 
2467         lpdit->y  = 10 + i * 14;
2468         lpdit->cx = (short)strlen(ptext[i]) * 4 + 10; 
2469         lpdit->cy = 14;
2470         lpdit->id = ID_TEXT + i;  // text identifier
2471
2472         lpw = (LPWORD) (lpdit + 1);
2473         *lpw++ = 0xFFFF;
2474         *lpw++ = 0x0082;                         // static class
2475
2476         lpwsz = (LPWSTR) lpw;
2477         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
2478                                          -1, lpwsz, 2*width);
2479         lpw   += nchar;
2480         *lpw++ = 0;           // no creation data
2481     }
2482     
2483     for ( i=0, pwid = 0; i<tb_cnt; i++) {
2484         int len = (int)strlen(tb[i].label);
2485         if ( pwid < len )
2486             pwid = len;
2487     }
2488
2489     for ( i=0; i<tb_cnt; i++) {
2490         /* Prompt */
2491         /*-----------------------
2492          * Define a static text control.
2493          *-----------------------*/
2494         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2495         lpdit = (LPDLGITEMTEMPLATE) lpw;
2496         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2497         lpdit->dwExtendedStyle = 0;
2498         lpdit->x  = 10; 
2499         lpdit->y  = 10 + (numlines + i + 1) * 14;
2500         lpdit->cx = pwid * 4; 
2501         lpdit->cy = 14;
2502         lpdit->id = ID_TEXT + numlines + i;  // text identifier
2503
2504         lpw = (LPWORD) (lpdit + 1);
2505         *lpw++ = 0xFFFF;
2506         *lpw++ = 0x0082;                         // static class
2507
2508         lpwsz = (LPWSTR) lpw;
2509         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 
2510                                      -1, lpwsz, 128);
2511         lpw   += nchar;
2512         *lpw++ = 0;           // no creation data
2513
2514         /*-----------------------
2515          * Define an edit control.
2516          *-----------------------*/
2517         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2518         lpdit = (LPDLGITEMTEMPLATE) lpw;
2519         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2520         lpdit->dwExtendedStyle = 0;
2521         lpdit->x  = 10 + (pwid + 1) * 4; 
2522         lpdit->y  = 10 + (numlines + i + 1) * 14;
2523         lpdit->cx = (width - (pwid + 1)) * 4; 
2524         lpdit->cy = 14;
2525         lpdit->id = ID_MID_TEXT + i;             // identifier
2526
2527         lpw = (LPWORD) (lpdit + 1);
2528         *lpw++ = 0xFFFF;
2529         *lpw++ = 0x0081;                         // edit class
2530
2531         lpwsz = (LPWSTR) lpw;
2532         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 
2533                                      -1, lpwsz, 128);
2534         lpw   += nchar;
2535         *lpw++ = 0;           // no creation data
2536     }
2537
2538     GlobalUnlock(hgbl); 
2539     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
2540                                                         hwndOwner, (DLGPROC) MultiInputDialogProc); 
2541     GlobalFree(hgbl); 
2542
2543     switch ( ret ) {
2544     case 0:     /* Timeout */
2545         return -1;
2546     case IDOK:
2547         return 1;
2548     case IDCANCEL:
2549         return 0;
2550     default: {
2551         char buf[256];
2552         StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2553         MessageBox(hwndOwner,
2554                     buf,
2555                     "GetLastError()",
2556                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2557         return -1;
2558     }
2559     }
2560 }
2561
2562 static int
2563 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2564 {
2565     HINSTANCE hInst = 0;
2566     int maxwidth = 0;
2567     int numlines = 0;
2568     int len;
2569     char * plines[16], *p = preface ? preface : "";
2570     int i;
2571
2572     for ( i=0; i<16; i++ ) 
2573         plines[i] = NULL;
2574
2575     while (*p && numlines < 16) {
2576         plines[numlines++] = p;
2577         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2578         if ( *p == '\r' && *(p+1) == '\n' ) {
2579             *p++ = '\0';
2580             p++;
2581         } else if ( *p == '\n' ) {
2582             *p++ = '\0';
2583         } 
2584         if ( strlen(plines[numlines-1]) > maxwidth )
2585             maxwidth = (int)strlen(plines[numlines-1]);
2586     }
2587
2588     for ( i=0;i<n;i++ ) {
2589         len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2590         if ( maxwidth < len )
2591             maxwidth = len;
2592     }
2593
2594     return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2595 }
2596
2597 static krb5_error_code KRB5_CALLCONV
2598 KRB5_prompter( krb5_context context,
2599                void *data,
2600                const char *name,
2601                const char *banner,
2602                int num_prompts,
2603                krb5_prompt prompts[])
2604 {
2605     krb5_error_code     errcode = 0;
2606     int                 i;
2607     struct textField * tb = NULL;
2608     int    len = 0, blen=0, nlen=0;
2609         HWND hParent = (HWND)data;
2610
2611     if (name)
2612         nlen = (int)strlen(name)+2;
2613
2614     if (banner)
2615         blen = (int)strlen(banner)+2;
2616
2617     tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2618     if ( tb != NULL ) {
2619         int ok;
2620         memset(tb,0,sizeof(struct textField) * num_prompts);
2621         for ( i=0; i < num_prompts; i++ ) {
2622             tb[i].buf = prompts[i].reply->data;
2623             tb[i].len = prompts[i].reply->length;
2624             tb[i].label = prompts[i].prompt;
2625             tb[i].def = NULL;
2626             tb[i].echo = (prompts[i].hidden ? 2 : 1);
2627         }   
2628
2629         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2630         if ( ok ) {
2631             for ( i=0; i < num_prompts; i++ )
2632                 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2633         } else
2634             errcode = -2;
2635     }
2636
2637     if ( tb )
2638         free(tb);
2639     if (errcode) {
2640         for (i = 0; i < num_prompts; i++) {
2641             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2642         }
2643     }
2644     return errcode;
2645 }
2646
2647 BOOL
2648 KFW_AFS_wait_for_service_start(void)
2649 {
2650     char    HostName[64];
2651     DWORD   CurrentState;
2652
2653     CurrentState = SERVICE_START_PENDING;
2654     memset(HostName, '\0', sizeof(HostName));
2655     gethostname(HostName, sizeof(HostName));
2656
2657     while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2658     {
2659         if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2660             return(0);
2661         if ( IsDebuggerPresent() ) {
2662             switch ( CurrentState ) {
2663             case SERVICE_STOPPED:
2664                 OutputDebugString("SERVICE_STOPPED\n");
2665                 break;
2666             case SERVICE_START_PENDING:
2667                 OutputDebugString("SERVICE_START_PENDING\n");
2668                 break;
2669             case SERVICE_STOP_PENDING:
2670                 OutputDebugString("SERVICE_STOP_PENDING\n");
2671                 break;
2672             case SERVICE_RUNNING:
2673                 OutputDebugString("SERVICE_RUNNING\n");
2674                 break;
2675             case SERVICE_CONTINUE_PENDING:
2676                 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2677                 break;
2678             case SERVICE_PAUSE_PENDING:
2679                 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2680                 break;
2681             case SERVICE_PAUSED:
2682                 OutputDebugString("SERVICE_PAUSED\n");
2683                 break;
2684             default:
2685                 OutputDebugString("UNKNOWN Service State\n");
2686             }
2687         }
2688         if (CurrentState == SERVICE_STOPPED)
2689             return(0);
2690         if (CurrentState == SERVICE_RUNNING)
2691             return(1);
2692         Sleep(500);
2693     }
2694     return(0);
2695 }
2696
2697
2698 int
2699 KFW_AFS_unlog(void)
2700 {
2701     long        rc;
2702     char    HostName[64];
2703     DWORD   CurrentState;
2704
2705     CurrentState = 0;
2706     memset(HostName, '\0', sizeof(HostName));
2707     gethostname(HostName, sizeof(HostName));
2708     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2709         return(0);
2710     if (CurrentState != SERVICE_RUNNING)
2711         return(0);
2712
2713     rc = ktc_ForgetAllTokens();
2714
2715     return(0);
2716 }
2717
2718
2719 #define ALLOW_REGISTER 1
2720 static int
2721 ViceIDToUsername(char *username, 
2722                  char *realm_of_user, 
2723                  char *realm_of_cell,
2724                  char * cell_to_use,
2725                  struct ktc_principal *aclient, 
2726                  struct ktc_principal *aserver, 
2727                  struct ktc_token *atoken)
2728 {
2729     static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2730     static char confdir[512] = { 0 };
2731 #ifdef AFS_ID_TO_NAME
2732     char username_copy[BUFSIZ];
2733 #endif /* AFS_ID_TO_NAME */
2734     long viceId = ANONYMOUSID;          /* AFS uid of user */
2735     int  status = 0;
2736 #ifdef ALLOW_REGISTER
2737     afs_int32 id;
2738 #endif /* ALLOW_REGISTER */
2739
2740     if (confdir[0] == '\0')
2741         cm_GetConfigDir(confdir, sizeof(confdir));
2742
2743     StringCbCopyN( lastcell, sizeof(lastcell),
2744                    aserver->cell, sizeof(lastcell) - 1);
2745
2746     if (!pr_Initialize (0, confdir, aserver->cell)) {
2747         char sname[PR_MAXNAMELEN];
2748         StringCbCopyN( sname, sizeof(sname),
2749                        username, sizeof(sname) - 1);
2750         status = pr_SNameToId (sname, &viceId);
2751         pr_End();
2752     }
2753
2754     /*
2755      * This is a crock, but it is Transarc's crock, so
2756      * we have to play along in order to get the
2757      * functionality.  The way the afs id is stored is
2758      * as a string in the username field of the token.
2759      * Contrary to what you may think by looking at
2760      * the code for tokens, this hack (AFS ID %d) will
2761      * not work if you change %d to something else.
2762      */
2763
2764     /*
2765      * This code is taken from cklog -- it lets people
2766      * automatically register with the ptserver in foreign cells
2767      */
2768
2769 #ifdef ALLOW_REGISTER
2770     if (status == 0) {
2771         if (viceId != ANONYMOUSID) {
2772 #else /* ALLOW_REGISTER */
2773             if ((status == 0) && (viceId != ANONYMOUSID))
2774 #endif /* ALLOW_REGISTER */
2775             {
2776 #ifdef AFS_ID_TO_NAME
2777                 StringCbCopyN( username_copy, sizeof(username_copy),
2778                                username, sizeof(username_copy) - 1);
2779                 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2780 #endif /* AFS_ID_TO_NAME */
2781             }
2782 #ifdef ALLOW_REGISTER
2783         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2784             id = 0;
2785             StringCbCopyN( aclient->name, sizeof(aclient->name),
2786                            username, sizeof(aclient->name) - 1);
2787             aclient->instance[0] = '\0';
2788             StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2789                            realm_of_user, sizeof(aclient->cell) - 1);
2790             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2791                 return status;
2792             if (status = pr_Initialize(1L, confdir, aserver->cell))
2793                 return status;
2794             status = pr_CreateUser(username, &id);
2795             pr_End();
2796             if (status)
2797                 return status;
2798 #ifdef AFS_ID_TO_NAME
2799             StringCbCopyN( username_copy, sizeof(username_copy),
2800                            username, sizeof(username_copy) - 1);
2801             snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2802 #endif /* AFS_ID_TO_NAME */
2803         }
2804     }
2805 #endif /* ALLOW_REGISTER */
2806     return status;
2807 }
2808
2809
2810 static void
2811 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2812     krb5_error_code code;
2813     krb5_ticket *ticket;
2814     size_t len;
2815
2816     code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
2817     if (code == 0) {
2818         len = krb5_princ_realm(context, ticket->server)->length;
2819         if (len > destlen - 1)
2820             len = destlen - 1;
2821
2822         StringCbCopyN(dest, destlen, krb5_princ_realm(context, ticket->server)->data, len);
2823
2824         pkrb5_free_ticket(context, ticket);
2825     }
2826 }
2827
2828 int
2829 KFW_AFS_klog(
2830     krb5_context alt_ctx,
2831     krb5_ccache  alt_cc,
2832     char *service,
2833     char *cell,
2834     char *realm,
2835     int  lifetime,      /* unused parameter */
2836     char *smbname
2837     )
2838 {
2839     long        rc = 0;
2840     CREDENTIALS creds;
2841 #ifdef USE_KRB4
2842     KTEXT_ST    ticket;
2843 #endif /* USE_KRB4 */
2844     struct ktc_principal        aserver;
2845     struct ktc_principal        aclient;
2846     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2847     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2848     char        local_cell[CELL_MAXNAMELEN+1];
2849     char        Dmycell[CELL_MAXNAMELEN+1];
2850     struct ktc_token    atoken;
2851     struct ktc_token    btoken;
2852     struct afsconf_cell ak_cellconfig; /* General information about the cell */
2853     char        RealmName[128];
2854     char        CellName[128];
2855     char        ServiceName[128];
2856     DWORD       CurrentState;
2857     char        HostName[64];
2858     BOOL        try_krb5 = 0;
2859     krb5_context  ctx = NULL;
2860     krb5_ccache   cc = NULL;
2861     krb5_creds increds;
2862     krb5_creds * k5creds = NULL;
2863     krb5_error_code code;
2864     krb5_principal client_principal = NULL;
2865     krb5_data * k5data = NULL;
2866     unsigned int i, retry = 0;
2867
2868     CurrentState = 0;
2869     memset(HostName, '\0', sizeof(HostName));
2870     gethostname(HostName, sizeof(HostName));
2871     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2872         if ( IsDebuggerPresent() )
2873             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2874         return(-1);
2875     }
2876     if (CurrentState != SERVICE_RUNNING) {
2877         if ( IsDebuggerPresent() )
2878             OutputDebugString("AFSD Service NOT RUNNING\n");
2879         return(-2);
2880     }
2881
2882     if (!pkrb5_init_context)
2883         return 0;
2884
2885     memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2886     memset(RealmName, '\0', sizeof(RealmName));
2887     memset(CellName, '\0', sizeof(CellName));
2888     memset(ServiceName, '\0', sizeof(ServiceName));
2889     memset(realm_of_user, '\0', sizeof(realm_of_user));
2890     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2891     if (cell && cell[0])
2892         StringCbCopyN( Dmycell, sizeof(Dmycell),
2893                        cell, sizeof(Dmycell) - 1);
2894     else
2895         memset(Dmycell, '\0', sizeof(Dmycell));
2896
2897     // NULL or empty cell returns information on local cell
2898     if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2899     {
2900         // KFW_AFS_error(rc, "get_cellconfig()");
2901         return(rc);
2902     }
2903
2904     if ( alt_ctx ) {
2905         ctx = alt_ctx;
2906     } else {
2907         code = pkrb5_init_context(&ctx);
2908         if (code) goto cleanup;
2909     }
2910
2911     if ( alt_cc ) {
2912         cc = alt_cc;
2913     } else {
2914         code = pkrb5_cc_default(ctx, &cc);
2915         if (code) goto skip_krb5_init;
2916     }
2917
2918     memset(&increds, 0, sizeof(increds));
2919
2920     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2921     if (code) {
2922         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
2923         {
2924             OutputDebugString("Principal Not Found for ccache\n");
2925         }
2926         goto skip_krb5_init;
2927     }
2928
2929     if (!KFW_accept_dotted_usernames()) {
2930         /* look for client principals which cannot be distinguished 
2931          * from Kerberos 4 multi-component principal names
2932          */
2933         k5data = krb5_princ_component(ctx,client_principal,0);
2934         for ( i=0; i<k5data->length; i++ ) {
2935             if ( k5data->data[i] == '.' )
2936                 break;
2937         }
2938         if (i != k5data->length)
2939         {
2940             OutputDebugString("Illegal Principal name contains dot in first component\n");
2941             rc = KRB5KRB_ERR_GENERIC;
2942             goto cleanup;
2943         }
2944     }
2945
2946     i = krb5_princ_realm(ctx, client_principal)->length;
2947     if (i > REALM_SZ-1) 
2948         i = REALM_SZ-1;
2949     StringCbCopyN( realm_of_user, sizeof(realm_of_user),
2950                    krb5_princ_realm(ctx, client_principal)->data, i);
2951     try_krb5 = 1;
2952
2953   skip_krb5_init:
2954 #ifdef USE_KRB4
2955     if ( !try_krb5 || !realm_of_user[0] ) {
2956         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2957         {
2958             goto cleanup;
2959         }       
2960     }
2961 #else
2962     if (!try_krb5)
2963         goto cleanup;
2964 #endif
2965     StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2966                    afs_realm_of_cell(ctx, &ak_cellconfig),
2967                    sizeof(realm_of_cell) - 1);
2968
2969     if (strlen(service) == 0)
2970         StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2971     else
2972         StringCbCopyN( ServiceName, sizeof(ServiceName),
2973                        service, sizeof(ServiceName) - 1);
2974
2975     if (strlen(cell) == 0)
2976         StringCbCopyN( CellName, sizeof(CellName),
2977                        local_cell, sizeof(CellName) - 1);
2978     else
2979         StringCbCopyN( CellName, sizeof(CellName),
2980                        cell, sizeof(CellName) - 1);
2981
2982     /* This is for Kerberos v4 only */
2983     if (strlen(realm) == 0)
2984         StringCbCopyN( RealmName, sizeof(RealmName),
2985                        realm_of_cell, sizeof(RealmName) - 1);
2986     else
2987         StringCbCopyN( RealmName, sizeof(RealmName),
2988                        realm, sizeof(RealmName) - 1);
2989
2990     memset(&creds, '\0', sizeof(creds));
2991
2992     if ( try_krb5 ) {
2993         int len;
2994         code = KRB5KRB_ERR_GENERIC;
2995
2996
2997         increds.client = client_principal;
2998         increds.times.endtime = 0;
2999         /* Ask for DES since that is what V4 understands */
3000         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
3001
3002         /* If there was a specific realm we are supposed to try
3003          * then use it 
3004          */
3005         if (strlen(realm) != 0) {
3006             /* service/cell@REALM */
3007             increds.server = 0;
3008             code = pkrb5_build_principal(ctx, &increds.server,
3009                                          (int)strlen(realm),
3010                                          realm,
3011                                          ServiceName,
3012                                          CellName,
3013                                          0);
3014             if ( IsDebuggerPresent() ) {
3015                 char * cname, *sname;
3016                 pkrb5_unparse_name(ctx, increds.client, &cname);
3017                 pkrb5_unparse_name(ctx, increds.server, &sname);
3018                 OutputDebugString("Getting tickets for \"");
3019                 OutputDebugString(cname);
3020                 OutputDebugString("\" and service \"");
3021                 OutputDebugString(sname);
3022                 OutputDebugString("\"\n");
3023                 pkrb5_free_unparsed_name(ctx,cname);
3024                 pkrb5_free_unparsed_name(ctx,sname);
3025             }
3026
3027             if (!code)
3028                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3029
3030             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
3031                 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
3032                 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
3033                 code == KRB5KRB_AP_ERR_MSG_TYPE) {
3034                 /* Or service@REALM */
3035                 pkrb5_free_principal(ctx,increds.server);
3036                 increds.server = 0;
3037                 code = pkrb5_build_principal(ctx, &increds.server,
3038                                               (int)strlen(realm),
3039                                               realm,
3040                                               ServiceName,
3041                                               0);
3042
3043                 if ( IsDebuggerPresent() ) {
3044                     char * cname, *sname;
3045                     pkrb5_unparse_name(ctx, increds.client, &cname);
3046                     pkrb5_unparse_name(ctx, increds.server, &sname);
3047                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
3048                     OutputDebugString("Trying again: getting tickets for \"");
3049                     OutputDebugString(cname);
3050                     OutputDebugString("\" and service \"");
3051                     OutputDebugString(sname);
3052                     OutputDebugString("\"\n");
3053                     pkrb5_free_unparsed_name(ctx,cname);
3054                     pkrb5_free_unparsed_name(ctx,sname);
3055                 }
3056
3057                 if (!code)
3058                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3059             }
3060
3061             if (code == 0) {
3062                 /* we have a local realm for the cell */
3063                 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
3064                                realm, sizeof(realm_of_cell) - 1);
3065             }
3066         } else {
3067             /* Otherwise, first try service/cell@CLIENT_REALM */
3068             if (code = pkrb5_build_principal(ctx, &increds.server,
3069                                               (int)strlen(realm_of_user),
3070                                               realm_of_user,
3071                                               ServiceName,
3072                                               CellName,
3073                                               0)) 
3074             {
3075                 goto cleanup;
3076             }
3077
3078             if ( IsDebuggerPresent() ) {
3079                 char * cname, *sname;
3080                 pkrb5_unparse_name(ctx, increds.client, &cname);
3081                 pkrb5_unparse_name(ctx, increds.server, &sname);
3082                 OutputDebugString("Getting tickets for \"");
3083                 OutputDebugString(cname);
3084                 OutputDebugString("\" and service \"");
3085                 OutputDebugString(sname);
3086                 OutputDebugString("\"\n");
3087                 pkrb5_free_unparsed_name(ctx,cname);
3088                 pkrb5_free_unparsed_name(ctx,sname);
3089             }
3090
3091             code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3092             if (code == 0) {
3093                 /* The client's realm is a local realm for the cell.
3094                  * Save it so that later the pts registration will not
3095                  * be performed.
3096                  */
3097                 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
3098                                realm_of_user, sizeof(realm_of_cell) - 1);
3099             }
3100
3101             if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
3102                  code == KRB5_ERR_HOST_REALM_UNKNOWN ||
3103                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
3104                  code == KRB5KRB_AP_ERR_MSG_TYPE) && 
3105                  strcmp(realm_of_user, realm_of_cell)) {
3106                 /* Then service/cell@CELL_REALM */
3107                 pkrb5_free_principal(ctx,increds.server);
3108                 increds.server = 0;
3109                 code = pkrb5_build_principal(ctx, &increds.server,
3110                                               (int)strlen(realm_of_cell),
3111                                               realm_of_cell,
3112                                               ServiceName,
3113                                               CellName,
3114                                               0);
3115                 if ( IsDebuggerPresent() ) {
3116                     char * cname, *sname;
3117                     pkrb5_unparse_name(ctx, increds.client, &cname);
3118                     pkrb5_unparse_name(ctx, increds.server, &sname);
3119                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
3120                     OutputDebugString("Trying again: getting tickets for \"");
3121                     OutputDebugString(cname);
3122                     OutputDebugString("\" and service \"");
3123                     OutputDebugString(sname);
3124                     OutputDebugString("\"\n");
3125                     pkrb5_free_unparsed_name(ctx,cname);
3126                     pkrb5_free_unparsed_name(ctx,sname);
3127                 }
3128
3129                 if (!code)
3130                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3131
3132                 if (!code && !strlen(realm_of_cell)) 
3133                     copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
3134             }
3135
3136             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
3137                 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
3138                 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
3139                 code == KRB5KRB_AP_ERR_MSG_TYPE) {
3140                 /* Finally service@CELL_REALM */
3141                 pkrb5_free_principal(ctx,increds.server);
3142                 increds.server = 0;
3143                 code = pkrb5_build_principal(ctx, &increds.server,
3144                                               (int)strlen(realm_of_cell),
3145                                               realm_of_cell,
3146                                               ServiceName,
3147                                               0);
3148
3149                 if ( IsDebuggerPresent() ) {
3150                     char * cname, *sname;
3151                     pkrb5_unparse_name(ctx, increds.client, &cname);
3152                     pkrb5_unparse_name(ctx, increds.server, &sname);
3153                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
3154                     OutputDebugString("Trying again: getting tickets for \"");
3155                     OutputDebugString(cname);
3156                     OutputDebugString("\" and service \"");
3157                     OutputDebugString(sname);
3158                     OutputDebugString("\"\n");
3159                     pkrb5_free_unparsed_name(ctx,cname);
3160                     pkrb5_free_unparsed_name(ctx,sname);
3161                 }
3162
3163                 if (!code)
3164                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3165                 if (!code && !strlen(realm_of_cell)) 
3166                     copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
3167             }
3168         }
3169
3170         if (code) {
3171             if ( IsDebuggerPresent() ) {
3172                 char message[256];
3173                 StringCbPrintf(message, sizeof(message), "krb5_get_credentials returns: %d\n", code);
3174                 OutputDebugString(message);
3175             }
3176             try_krb5 = 0;
3177             goto use_krb4;
3178         }
3179
3180         /* This code inserts the entire K5 ticket into the token
3181          * No need to perform a krb524 translation which is 
3182          * commented out in the code below
3183          */
3184         if (KFW_use_krb524() ||
3185             k5creds->ticket.length > MAXKTCTICKETLEN)
3186             goto try_krb524d;
3187
3188         memset(&aserver, '\0', sizeof(aserver));
3189         StringCbCopyN( aserver.name, sizeof(aserver.name),
3190                        ServiceName, sizeof(aserver.name) - 1);
3191         StringCbCopyN( aserver.cell, sizeof(aserver.cell),
3192                        CellName, sizeof(aserver.cell) - 1);
3193
3194         memset(&atoken, '\0', sizeof(atoken));
3195         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
3196         atoken.startTime = k5creds->times.starttime;
3197         atoken.endTime = k5creds->times.endtime;
3198         memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
3199         atoken.ticketLen = k5creds->ticket.length;
3200         memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
3201
3202       retry_gettoken5:
3203         rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3204         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3205             if ( rc == KTC_NOCM && retry < 20 ) {
3206                 Sleep(500);
3207                 retry++;
3208                 goto retry_gettoken5;
3209             }
3210             goto cleanup;
3211         }
3212
3213         if (atoken.kvno == btoken.kvno &&
3214              atoken.ticketLen == btoken.ticketLen &&
3215              !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3216              !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
3217         {
3218             /* Success - Nothing to do */
3219             goto cleanup;
3220         }
3221
3222         // * Reset the "aclient" structure before we call ktc_SetToken.
3223         // * This structure was first set by the ktc_GetToken call when
3224         // * we were comparing whether identical tokens already existed.
3225
3226         len = min(k5creds->client->data[0].length, sizeof(aclient.name) - 1);
3227         StringCbCopyN( aclient.name, sizeof(aclient.name),
3228                        k5creds->client->data[0].data, len);
3229
3230         if ( k5creds->client->length > 1 ) {
3231             StringCbCat( aclient.name, sizeof(aclient.name), ".");
3232             len = min(k5creds->client->data[1].length, (int)(sizeof(aclient.name) - strlen(aclient.name) - 1));
3233             StringCbCatN( aclient.name, sizeof(aclient.name),
3234                           k5creds->client->data[1].data, len);
3235         }
3236         aclient.instance[0] = '\0';
3237
3238         StringCbCopyN( aclient.cell, sizeof(aclient.cell),
3239                        realm_of_cell, sizeof(aclient.cell) - 1);
3240
3241         len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3242         /* For Khimaira, always append the realm name */
3243         if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3244             StringCbCat( aclient.name, sizeof(aclient.name), "@");
3245             len = min(k5creds->client->realm.length, (int)(sizeof(aclient.name) - strlen(aclient.name) - 1));
3246             StringCbCatN( aclient.name, sizeof(aclient.name), k5creds->client->realm.data, len);
3247         }
3248
3249         GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3250         if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3251             ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
3252                              &aclient, &aserver, &atoken);
3253
3254         if ( smbname ) {
3255             StringCbCopyN( aclient.smbname, sizeof(aclient.smbname),
3256                            smbname, sizeof(aclient.smbname) - 1);
3257         } else {
3258             aclient.smbname[0] = '\0';
3259         }
3260
3261         rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3262         if (!rc)
3263             goto cleanup;   /* We have successfully inserted the token */
3264
3265       try_krb524d:
3266 #ifndef USE_KRB524
3267         goto cleanup;
3268 #else
3269         /* Otherwise, the ticket could have been too large so try to
3270          * convert using the krb524d running with the KDC 
3271          */
3272         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3273         pkrb5_free_creds(ctx, k5creds);
3274         if (code) {
3275             if ( IsDebuggerPresent() ) {
3276                 char message[256];
3277                 StringCbPrintf(message, sizeof(message), "krb524_convert_creds_kdc returns: %d\n", code);
3278                 OutputDebugString(message);
3279             }
3280             try_krb5 = 0;
3281             goto use_krb4;
3282         }
3283 #endif /* USE_KRB524 */
3284     } else {
3285       use_krb4:
3286 #ifdef USE_KRB4
3287         code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3288         if (code == NO_TKT_FIL) {
3289             // if the problem is that we have no krb4 tickets
3290             // do not attempt to continue
3291             goto cleanup;
3292         }
3293         if (code != KSUCCESS)
3294             code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3295
3296         if (code != KSUCCESS)
3297         {
3298             if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3299             {
3300                 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3301                 {
3302                     goto cleanup;
3303                 }
3304             }
3305             else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3306             {
3307                 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3308                 {
3309                     goto cleanup;
3310                 }
3311             }
3312             else
3313             {
3314                 goto cleanup;
3315             }
3316         }
3317 #else
3318         goto cleanup;
3319 #endif
3320     }
3321
3322     memset(&aserver, '\0', sizeof(aserver));
3323     StringCbCopyN( aserver.name, sizeof(aserver.name), ServiceName, sizeof(aserver.name) - 1);
3324     StringCbCopyN( aserver.cell, sizeof(aserver.cell), CellName, sizeof(aserver.cell) - 1);
3325
3326     memset(&atoken, '\0', sizeof(atoken));
3327     atoken.kvno = creds.kvno;
3328     atoken.startTime = creds.issue_date;
3329     atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3330     memcpy(&atoken.sessionKey, creds.session, 8);
3331     atoken.ticketLen = creds.ticket_st.length;
3332     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3333
3334   retry_gettoken:
3335     rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3336     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3337         if ( rc == KTC_NOCM && retry < 20 ) {
3338             Sleep(500);
3339             retry++;
3340             goto retry_gettoken;
3341         }
3342         KFW_AFS_error(rc, "ktc_GetToken()");
3343         code = rc;
3344         goto cleanup;
3345     }
3346
3347     if (atoken.kvno == btoken.kvno &&
3348         atoken.ticketLen == btoken.ticketLen &&
3349         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3350         !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
3351     {
3352         goto cleanup;
3353     }
3354
3355     // * Reset the "aclient" structure before we call ktc_SetToken.
3356     // * This structure was first set by the ktc_GetToken call when
3357     // * we were comparing whether identical tokens already existed.
3358
3359     StringCbCopyN( aclient.name, sizeof(aclient.name), creds.pname, sizeof(aclient.name) - 1);
3360     if (creds.pinst[0])
3361     {
3362         strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3363         strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3364     }
3365     aclient.instance[0] = '\0';
3366
3367     strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3368     strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3369     aclient.name[MAXKTCREALMLEN-1] = '\0';
3370
3371     StringCbCopyN( aclient.cell, sizeof(aclient.cell),
3372                    CellName, sizeof(aclient.cell) - 1);
3373
3374     GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3375     if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3376         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
3377                          &aclient, &aserver, &atoken);
3378
3379     if ( smbname ) {
3380         StringCbCopyN( aclient.smbname, sizeof(aclient.smbname),
3381                        smbname, sizeof(aclient.smbname) - 1);
3382     } else {
3383         aclient.smbname[0] = '\0';
3384     }
3385
3386     if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3387     {
3388         KFW_AFS_error(rc, "ktc_SetToken()");
3389         code = rc;
3390         goto cleanup;
3391     }
3392
3393   cleanup:
3394     if (client_principal)
3395         pkrb5_free_principal(ctx,client_principal);
3396     /* increds.client == client_principal */
3397     if (increds.server)
3398         pkrb5_free_principal(ctx,increds.server);
3399     if (cc && (cc != alt_cc))
3400         pkrb5_cc_close(ctx, cc);
3401     if (ctx && (ctx != alt_ctx))
3402         pkrb5_free_context(ctx);
3403     if (ak_cellconfig.linkedCell)
3404         free(ak_cellconfig.linkedCell);
3405
3406     return(rc? rc : code);
3407 }
3408
3409 /**************************************/
3410 /* afs_realm_of_cell():               */
3411 /**************************************/
3412 static char *
3413 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3414 {
3415     static char krbrlm[REALM_SZ+1]="";
3416     char ** realmlist=NULL;
3417     krb5_error_code r;
3418
3419     if (!cellconfig)
3420         return 0;
3421
3422     r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3423     if ( !r && realmlist && realmlist[0] ) {
3424         StringCbCopyN( krbrlm, sizeof(krbrlm),
3425                        realmlist[0], sizeof(krbrlm) - 1);
3426         pkrb5_free_host_realm(ctx, realmlist);
3427     }
3428
3429     if ( !krbrlm[0] )
3430     {
3431         char *s = krbrlm;
3432         char *t = cellconfig->name;
3433         int c;
3434
3435         while (c = *t++)
3436         {
3437             if (islower(c)) c=toupper(c);
3438             *s++ = c;
3439         }
3440         *s++ = 0;
3441     }
3442     return(krbrlm);
3443 }
3444
3445 /**************************************/
3446 /* KFW_AFS_get_cellconfig():          */
3447 /**************************************/
3448 int
3449 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3450 {
3451     int rc;
3452     char newcell[CELL_MAXNAMELEN+1];
3453     char linkedcell[CELL_MAXNAMELEN+1]="";
3454
3455     local_cell[0] = (char)0;
3456     memset(cellconfig, 0, sizeof(*cellconfig));
3457
3458     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3459     if (rc = cm_GetRootCellName(local_cell))
3460     {
3461         return(rc);
3462     }
3463
3464     if (strlen(cell) == 0)
3465         strcpy(cell, local_cell);
3466
3467     rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
3468     if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
3469         rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
3470     if (rc != 0) {
3471         int ttl;
3472         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3473     }
3474
3475     if (rc == 0) {
3476         StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
3477                        newcell, sizeof(cellconfig->name) - 1);
3478         if (linkedcell[0])
3479             cellconfig->linkedCell = strdup(linkedcell);
3480     }
3481     return rc;
3482 }
3483
3484 /**************************************/
3485 /* get_cellconfig_callback():         */
3486 /**************************************/
3487 static long 
3488 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
3489 {
3490     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3491
3492     cc->hostAddr[cc->numServers] = *addrp;
3493     StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
3494                    namep, sizeof(cc->hostName[cc->numServers]) - 1);
3495     cc->numServers++;
3496     return(0);
3497 }
3498
3499
3500 /**************************************/
3501 /* KFW_AFS_error():                  */
3502 /**************************************/
3503 void
3504 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3505 {
3506     char message[256];
3507     const char *errText; 
3508
3509     // Using AFS defines as error messages for now, until Transarc 
3510     // gets back to me with "string" translations of each of these 
3511     // const. defines. 
3512     if (rc == KTC_ERROR)
3513       errText = "KTC_ERROR";
3514     else if (rc == KTC_TOOBIG)
3515       errText = "KTC_TOOBIG";
3516     else if (rc == KTC_INVAL)
3517       errText = "KTC_INVAL";
3518     else if (rc == KTC_NOENT)
3519       errText = "KTC_NOENT";
3520     else if (rc == KTC_PIOCTLFAIL)
3521       errText = "KTC_PIOCTLFAIL";
3522     else if (rc == KTC_NOPIOCTL)
3523       errText = "KTC_NOPIOCTL";
3524     else if (rc == KTC_NOCELL)
3525       errText = "KTC_NOCELL";
3526     else if (rc == KTC_NOCM)
3527       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3528     else
3529       errText = "Unknown error!";
3530
3531     StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3532
3533     if ( IsDebuggerPresent() ) {
3534         OutputDebugString(message);
3535         OutputDebugString("\n");
3536     }
3537     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3538     return;
3539 }
3540
3541 static DWORD 
3542 GetServiceStatus(
3543     LPSTR lpszMachineName, 
3544     LPSTR lpszServiceName,
3545     DWORD *lpdwCurrentState) 
3546
3547     DWORD           hr               = NOERROR; 
3548     SC_HANDLE       schSCManager     = NULL; 
3549     SC_HANDLE       schService       = NULL; 
3550     DWORD           fdwDesiredAccess = 0; 
3551     SERVICE_STATUS  ssServiceStatus  = {0}; 
3552     BOOL            fRet             = FALSE; 
3553
3554     *lpdwCurrentState = 0; 
3555  
3556     fdwDesiredAccess = GENERIC_READ; 
3557  
3558     schSCManager = OpenSCManager(lpszMachineName,  
3559                                  NULL,
3560                                  fdwDesiredAccess); 
3561  
3562     if(schSCManager == NULL) 
3563     { 
3564         hr = GetLastError();
3565         goto cleanup; 
3566     } 
3567  
3568     schService = OpenService(schSCManager,
3569                              lpszServiceName,
3570                              fdwDesiredAccess); 
3571  
3572     if(schService == NULL) 
3573     { 
3574         hr = GetLastError();
3575         goto cleanup; 
3576     } 
3577  
3578     fRet = QueryServiceStatus(schService,
3579                               &ssServiceStatus); 
3580  
3581     if(fRet == FALSE) 
3582     { 
3583         hr = GetLastError(); 
3584         goto cleanup; 
3585     } 
3586  
3587     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
3588  
3589 cleanup: 
3590  
3591     CloseServiceHandle(schService); 
3592     CloseServiceHandle(schSCManager); 
3593  
3594     return(hr); 
3595
3596
3597 void
3598 UnloadFuncs(
3599     FUNC_INFO fi[], 
3600     HINSTANCE h
3601     )
3602 {
3603     int n;
3604     if (fi)
3605         for (n = 0; fi[n].func_ptr_var; n++)
3606             *(fi[n].func_ptr_var) = 0;
3607     if (h) FreeLibrary(h);
3608 }
3609
3610 int
3611 LoadFuncs(
3612     const char* dll_name, 
3613     FUNC_INFO fi[], 
3614     HINSTANCE* ph,  // [out, optional] - DLL handle
3615     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
3616     int cleanup,    // cleanup function pointers and unload on error
3617     int go_on,      // continue loading even if some functions cannot be loaded
3618     int silent      // do not pop-up a system dialog if DLL cannot be loaded
3619     )
3620 {
3621     HINSTANCE h;
3622     int i, n, last_i;
3623     int error = 0;
3624     UINT em;
3625
3626     if (ph) *ph = 0;
3627     if (pindex) *pindex = -1;
3628
3629     for (n = 0; fi[n].func_ptr_var; n++)
3630         *(fi[n].func_ptr_var) = 0;
3631
3632     if (silent)
3633         em = SetErrorMode(SEM_FAILCRITICALERRORS);
3634     h = LoadLibrary(dll_name);
3635     if (silent)
3636         SetErrorMode(em);
3637
3638     if (!h)
3639         return 0;
3640
3641     last_i = -1;
3642     for (i = 0; (go_on || !error) && (i < n); i++)
3643     {
3644         void* p = (void*)GetProcAddress(h, fi[i].func_name);
3645         if (!p)
3646             error = 1;
3647         else
3648         {
3649             last_i = i;
3650             *(fi[i].func_ptr_var) = p;
3651         }
3652     }
3653     if (pindex) *pindex = last_i;
3654     if (error && cleanup && !go_on) {
3655         for (i = 0; i < n; i++) {
3656             *(fi[i].func_ptr_var) = 0;
3657         }
3658         FreeLibrary(h);
3659         return 0;
3660     }
3661     if (ph) *ph = h;
3662     if (error) return 0;
3663     return 1;
3664 }
3665
3666 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3667 {
3668     krb5_context ctx = NULL;
3669     krb5_ccache cc = NULL;
3670     krb5_error_code code;
3671     krb5_data pwdata;
3672     const char * realm = NULL;
3673     krb5_principal principal = NULL;
3674     char * pname = NULL;
3675     char   password[PROBE_PASSWORD_LEN+1];
3676     BOOL serverReachable = 0;
3677
3678     if (!pkrb5_init_context)
3679         return 0;
3680
3681     code = pkrb5_init_context(&ctx);
3682     if (code) goto cleanup;
3683
3684
3685     realm = afs_realm_of_cell(ctx, cellconfig);  // do not free
3686
3687     code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3688                                   realm, PROBE_USERNAME, NULL, NULL);
3689     if ( code ) goto cleanup;
3690
3691     code = KFW_get_ccache(ctx, principal, &cc);
3692     if ( code ) goto cleanup;
3693
3694     code = pkrb5_unparse_name(ctx, principal, &pname);
3695     if ( code ) goto cleanup;
3696
3697     pwdata.data = password;
3698     pwdata.length = PROBE_PASSWORD_LEN;
3699     code = pkrb5_c_random_make_octets(ctx, &pwdata);
3700     if (code) {
3701         int i;
3702         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3703             password[i] = 'x';
3704     }
3705     password[PROBE_PASSWORD_LEN] = '\0';
3706
3707     code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
3708                       pname, 
3709                       password,
3710                       5,
3711                       0,
3712                       0,
3713                       0,
3714                       1,
3715                       0);
3716     switch ( code ) {
3717     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3718     case KRB5KDC_ERR_CLIENT_REVOKED:
3719     case KRB5KDC_ERR_CLIENT_NOTYET:
3720     case KRB5KDC_ERR_PREAUTH_FAILED:
3721     case KRB5KDC_ERR_PREAUTH_REQUIRED:
3722     case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3723         serverReachable = TRUE;
3724         break;
3725     default:
3726         serverReachable = FALSE;
3727     }
3728
3729   cleanup:
3730     if ( pname )
3731         pkrb5_free_unparsed_name(ctx,pname);
3732     if ( principal )
3733         pkrb5_free_principal(ctx,principal);
3734     if (cc)
3735         pkrb5_cc_close(ctx,cc);
3736     if (ctx)
3737         pkrb5_free_context(ctx);
3738
3739     return serverReachable;
3740 }
3741
3742 BOOL
3743 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3744 {
3745     krb5_context   ctx = NULL;
3746     krb5_error_code code;
3747     krb5_ccache mslsa_ccache=NULL;
3748     krb5_principal princ = NULL;
3749     char * pname = NULL;
3750     BOOL success = 0;
3751
3752     if (!KFW_is_available())
3753         return FALSE;
3754
3755     if (code = pkrb5_init_context(&ctx))
3756         goto cleanup;
3757
3758     if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3759         goto cleanup;
3760
3761     if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3762         goto cleanup;
3763
3764     if (code = pkrb5_unparse_name(ctx, princ, &pname))
3765         goto cleanup;
3766
3767     if ( strlen(pname) < *dwSize ) {
3768         StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3769         success = 1;
3770     }
3771     *dwSize = (DWORD)strlen(pname);
3772
3773   cleanup:
3774     if (pname)
3775         pkrb5_free_unparsed_name(ctx, pname);
3776
3777     if (princ)
3778         pkrb5_free_principal(ctx, princ);
3779
3780     if (mslsa_ccache)
3781         pkrb5_cc_close(ctx, mslsa_ccache);
3782
3783     if (ctx)
3784         pkrb5_free_context(ctx);
3785     return success;
3786 }
3787
3788 int 
3789 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3790 {
3791     // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3792     PSID pSystemSID = NULL;
3793     DWORD SystemSIDlength = 0, UserSIDlength = 0;
3794     PACL ccacheACL = NULL;
3795     DWORD ccacheACLlength = 0;
3796     PTOKEN_USER pTokenUser = NULL;
3797     DWORD retLen;
3798     DWORD gle;
3799     int ret = 0;  
3800
3801     if (!filename) {
3802         return 1;
3803     }
3804
3805     /* Get System SID */
3806     if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3807         ret = 1;
3808         goto cleanup;
3809     }
3810
3811     /* Create ACL */
3812     SystemSIDlength = GetLengthSid(pSystemSID);
3813     ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3814         + SystemSIDlength - sizeof(DWORD);
3815
3816     if (hUserToken) {
3817         if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3818         {
3819             if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3820                 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3821
3822                 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3823             }            
3824         }
3825
3826         if (pTokenUser) {
3827             UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3828
3829             ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength 
3830                 - sizeof(DWORD);
3831         }
3832     }
3833
3834     ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3835     if (!ccacheACL) {
3836         ret = 1;
3837         goto cleanup;
3838      }
3839     InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3840     AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3841                          STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3842                          pSystemSID);
3843     if (pTokenUser) {
3844         AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3845                              STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3846                              pTokenUser->User.Sid);
3847         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3848                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3849                                    NULL,
3850                                    NULL, 
3851                                    ccacheACL,
3852                                    NULL)) {
3853             gle = GetLastError();
3854             if (gle != ERROR_NO_TOKEN)
3855                 ret = 1;
3856         }
3857         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3858                                    OWNER_SECURITY_INFORMATION,
3859                                    pTokenUser->User.Sid,
3860                                    NULL, 
3861                                    NULL,
3862                                    NULL)) {
3863             gle = GetLastError();
3864             if (gle != ERROR_NO_TOKEN)
3865                 ret = 1;
3866         }
3867     } else {
3868         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3869                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3870                                    NULL,
3871                                    NULL, 
3872                                    ccacheACL,
3873                                    NULL)) {
3874             gle = GetLastError();
3875             if (gle != ERROR_NO_TOKEN)
3876                 ret = 1;
3877         }
3878     }
3879
3880   cleanup:
3881     if (pSystemSID)
3882         LocalFree(pSystemSID);
3883     if (pTokenUser)
3884         LocalFree(pTokenUser);
3885     if (ccacheACL)
3886         LocalFree(ccacheACL);
3887     return ret;
3888 }
3889
3890 int 
3891 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3892 {
3893     int  retval = 0;
3894     DWORD dwSize = size-1;      /* leave room for nul */
3895     DWORD dwLen  = 0;
3896  
3897     if (!hUserToken || !newfilename || size <= 0)
3898         return 1;
3899  
3900      *newfilename = '\0';
3901  
3902      dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3903      if ( !dwLen || dwLen > dwSize )
3904         dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3905      if ( !dwLen || dwLen > dwSize )
3906         return 1;
3907  
3908      newfilename[dwSize] = '\0';
3909     return 0;
3910 }
3911
3912 void
3913 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3914 {
3915     char filename[MAX_PATH] = "";
3916     DWORD count;
3917     char cachename[MAX_PATH + 8] = "FILE:";
3918     krb5_context                ctx = NULL;
3919     krb5_error_code             code;
3920     krb5_principal              princ = NULL;
3921     krb5_ccache                 cc  = NULL;
3922     krb5_ccache                 ncc = NULL;
3923
3924     if (!pkrb5_init_context || !user || !szLogonId)
3925         return;
3926
3927     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3928     if ( count > sizeof(filename) || count == 0 ) {
3929         GetWindowsDirectory(filename, sizeof(filename));
3930     }
3931
3932     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3933         return;
3934
3935     StringCbCat( filename, sizeof(filename), "\\");
3936     StringCbCat( filename, sizeof(filename), szLogonId);
3937
3938     StringCbCat( cachename, sizeof(cachename), filename);
3939
3940     DeleteFile(filename);
3941
3942     code = pkrb5_init_context(&ctx);
3943     if (code) goto cleanup;
3944
3945     code = pkrb5_parse_name(ctx, user, &princ);
3946     if (code) goto cleanup;
3947
3948     code = KFW_get_ccache(ctx, princ, &cc);
3949     if (code) goto cleanup;
3950
3951     code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3952     if (code) goto cleanup;
3953
3954     code = pkrb5_cc_initialize(ctx, ncc, princ);
3955     if (code) goto cleanup;
3956
3957     code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3958     if (code) goto cleanup;
3959
3960     code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3961
3962   cleanup:
3963     if ( cc ) {
3964         pkrb5_cc_close(ctx, cc);
3965         cc = 0;
3966     }
3967     if ( ncc ) {
3968         pkrb5_cc_close(ctx, ncc);
3969         ncc = 0;
3970     }
3971     if ( princ ) {
3972         pkrb5_free_principal(ctx, princ);
3973         princ = 0;
3974     }
3975
3976     if (ctx)
3977         pkrb5_free_context(ctx);
3978 }
3979
3980 int
3981 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3982 {
3983     char cachename[MAX_PATH + 8] = "FILE:";
3984     krb5_context                ctx = NULL;
3985     krb5_error_code             code;
3986     krb5_principal              princ = NULL;
3987     krb5_ccache                 cc  = NULL;
3988     krb5_ccache                 ncc = NULL;
3989     int retval = 1;
3990
3991     if (!pkrb5_init_context || !filename)
3992         return 1;
3993
3994     if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3995         return 1;
3996
3997     code = pkrb5_init_context(&ctx);
3998     if (code) return 1;
3999
4000     StringCbCat( cachename, sizeof(cachename), filename);
4001
4002     code = pkrb5_cc_resolve(ctx, cachename, &cc);
4003     if (code) goto cleanup;
4004     
4005     code = pkrb5_cc_get_principal(ctx, cc, &princ);
4006
4007     code = pkrb5_cc_default(ctx, &ncc);
4008     if (!code) {
4009         code = pkrb5_cc_initialize(ctx, ncc, princ);
4010
4011         if (!code)
4012             code = pkrb5_cc_copy_creds(ctx,cc,ncc);
4013     }
4014     if ( ncc ) {
4015         pkrb5_cc_close(ctx, ncc);
4016         ncc = 0;
4017     }
4018
4019     retval=0;   /* success */
4020
4021   cleanup:
4022     if ( cc ) {
4023         pkrb5_cc_close(ctx, cc);
4024         cc = 0;
4025     }
4026
4027     DeleteFile(filename);
4028
4029     if ( princ ) {
4030         pkrb5_free_principal(ctx, princ);
4031         princ = 0;
4032     }
4033
4034     if (ctx)
4035         pkrb5_free_context(ctx);
4036
4037     return 0;
4038 }
4039
4040 /* We are including this 
4041
4042 /* Ticket lifetime.  This defines the table used to lookup lifetime for the
4043    fixed part of rande of the one byte lifetime field.  Values less than 0x80
4044    are intrpreted as the number of 5 minute intervals.  Values from 0x80 to
4045    0xBF should be looked up in this table.  The value of 0x80 is the same using
4046    both methods: 10 and two-thirds hours .  The lifetime of 0xBF is 30 days.
4047    The intervening values of have a fixed ratio of roughly 1.06914.  The value
4048    oxFF is defined to mean a ticket has no expiration time.  This should be
4049    used advisedly since individual servers may impose defacto upperbounds on
4050    ticket lifetimes. */
4051
4052 #define TKTLIFENUMFIXED 64
4053 #define TKTLIFEMINFIXED 0x80
4054 #define TKTLIFEMAXFIXED 0xBF
4055 #define TKTLIFENOEXPIRE 0xFF
4056 #define MAXTKTLIFETIME  (30*24*3600)    /* 30 days */
4057
4058 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
4059     38400,                      /* 10.67 hours, 0.44 days */
4060     41055,                      /* 11.40 hours, 0.48 days */
4061     43894,                      /* 12.19 hours, 0.51 days */
4062     46929,                      /* 13.04 hours, 0.54 days */
4063     50174,                      /* 13.94 hours, 0.58 days */
4064     53643,                      /* 14.90 hours, 0.62 days */
4065     57352,                      /* 15.93 hours, 0.66 days */
4066     61318,                      /* 17.03 hours, 0.71 days */
4067     65558,                      /* 18.21 hours, 0.76 days */
4068     70091,                      /* 19.47 hours, 0.81 days */
4069     74937,                      /* 20.82 hours, 0.87 days */
4070     80119,                      /* 22.26 hours, 0.93 days */
4071     85658,                      /* 23.79 hours, 0.99 days */
4072     91581,                      /* 25.44 hours, 1.06 days */
4073     97914,                      /* 27.20 hours, 1.13 days */
4074     104684,                     /* 29.08 hours, 1.21 days */
4075     111922,                     /* 31.09 hours, 1.30 days */
4076     119661,                     /* 33.24 hours, 1.38 days */
4077     127935,                     /* 35.54 hours, 1.48 days */
4078     136781,                     /* 37.99 hours, 1.58 days */
4079     146239,                     /* 40.62 hours, 1.69 days */
4080     156350,                     /* 43.43 hours, 1.81 days */
4081     167161,                     /* 46.43 hours, 1.93 days */
4082     178720,                     /* 49.64 hours, 2.07 days */
4083     191077,                     /* 53.08 hours, 2.21 days */
4084     204289,                     /* 56.75 hours, 2.36 days */
4085     218415,                     /* 60.67 hours, 2.53 days */
4086     233517,                     /* 64.87 hours, 2.70 days */
4087     249664,                     /* 69.35 hours, 2.89 days */
4088     266926,                     /* 74.15 hours, 3.09 days */
4089     285383,                     /* 79.27 hours, 3.30 days */
4090     305116,                     /* 84.75 hours, 3.53 days */
4091     326213,                     /* 90.61 hours, 3.78 days */
4092     348769,                     /* 96.88 hours, 4.04 days */
4093     372885,                     /* 103.58 hours, 4.32 days */
4094     398668,                     /* 110.74 hours, 4.61 days */
4095     426234,                     /* 118.40 hours, 4.93 days */
4096     455705,                     /* 126.58 hours, 5.27 days */
4097     487215,                     /* 135.34 hours, 5.64 days */
4098     520904,                     /* 144.70 hours, 6.03 days */
4099     556921,                     /* 154.70 hours, 6.45 days */
4100     595430,                     /* 165.40 hours, 6.89 days */
4101     636601,                     /* 176.83 hours, 7.37 days */
4102     680618,                     /* 189.06 hours, 7.88 days */
4103     727680,                     /* 202.13 hours, 8.42 days */
4104     777995,                     /* 216.11 hours, 9.00 days */
4105     831789,                     /* 231.05 hours, 9.63 days */
4106     889303,                     /* 247.03 hours, 10.29 days */
4107     950794,                     /* 264.11 hours, 11.00 days */
4108     1016537,                    /* 282.37 hours, 11.77 days */
4109     1086825,                    /* 301.90 hours, 12.58 days */
4110     1161973,                    /* 322.77 hours, 13.45 days */
4111     1242318,                    /* 345.09 hours, 14.38 days */
4112     1328218,                    /* 368.95 hours, 15.37 days */
4113     1420057,                    /* 394.46 hours, 16.44 days */
4114     1518247,                    /* 421.74 hours, 17.57 days */
4115     1623226,                    /* 450.90 hours, 18.79 days */
4116     1735464,                    /* 482.07 hours, 20.09 days */
4117     1855462,                    /* 515.41 hours, 21.48 days */
4118     1983758,                    /* 551.04 hours, 22.96 days */
4119     2120925,                    /* 589.15 hours, 24.55 days */
4120     2267576,                    /* 629.88 hours, 26.25 days */
4121     2424367,                    /* 673.44 hours, 28.06 days */
4122     2592000
4123 };                              /* 720.00 hours, 30.00 days */
4124
4125 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
4126  * returns the corresponding end time.  There are four simple cases to be
4127  * handled.  The first is a life of 0xff, meaning no expiration, and results in
4128  * an end time of 0xffffffff.  The second is when life is less than the values
4129  * covered by the table.  In this case, the end time is the start time plus the
4130  * number of 5 minute intervals specified by life.  The third case returns
4131  * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED.  The
4132  * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
4133  * table to extract the lifetime in seconds, which is added to start to produce
4134  * the end time. */
4135
4136 afs_uint32
4137 life_to_time(afs_uint32 start, unsigned char life)
4138 {
4139     int realLife;
4140
4141     if (life == TKTLIFENOEXPIRE)
4142         return NEVERDATE;
4143     if (life < TKTLIFEMINFIXED)
4144         return start + life * 5 * 60;
4145     if (life > TKTLIFEMAXFIXED)
4146         return start + MAXTKTLIFETIME;
4147     realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
4148     return start + realLife;
4149 }
4150
4151 /* time_to_life - takes start and end times for the ticket and returns a
4152  * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
4153  * lifetimes above 127*5minutes.  First, the special case of (end ==
4154  * 0xffffffff) is handled to mean no expiration.  Then negative lifetimes and
4155  * those greater than the maximum ticket lifetime are rejected.  Then lifetimes
4156  * less than the first table entry are handled by rounding the requested
4157  * lifetime *up* to the next 5 minute interval.  The final step is to search
4158  * the table for the smallest entry *greater than or equal* to the requested
4159  * entry.  The actual code is prepared to handle the case where the table is
4160  * unordered but that it an unnecessary frill. */
4161
4162 static unsigned char
4163 time_to_life(afs_uint32 start, afs_uint32 end)
4164 {
4165     int lifetime = end - start;
4166     int best, best_i;
4167     int i;
4168
4169     if (end == NEVERDATE)
4170         return TKTLIFENOEXPIRE;
4171     if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
4172         return 0;
4173     if (lifetime < tkt_lifetimes[0])
4174         return (lifetime + 5 * 60 - 1) / (5 * 60);
4175     best_i = -1;
4176     best = MAXKTCTICKETLIFETIME;
4177     for (i = 0; i < TKTLIFENUMFIXED; i++)
4178         if (tkt_lifetimes[i] >= lifetime) {
4179             int diff = tkt_lifetimes[i] - lifetime;
4180             if (diff < best) {
4181                 best = diff;
4182                 best_i = i;
4183             }
4184         }
4185     if (best_i < 0)
4186         return 0;
4187     return best_i + TKTLIFEMINFIXED;
4188 }
4189