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