windows-afskfw-20080218
[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 int
2738 KFW_AFS_klog(
2739     krb5_context alt_ctx,
2740     krb5_ccache  alt_cc,
2741     char *service,
2742     char *cell,
2743     char *realm,
2744     int  lifetime,      /* unused parameter */
2745     char *smbname
2746     )
2747 {
2748     long        rc = 0;
2749     CREDENTIALS creds;
2750 #ifdef USE_KRB4
2751     KTEXT_ST    ticket;
2752 #endif /* USE_KRB4 */
2753     struct ktc_principal        aserver;
2754     struct ktc_principal        aclient;
2755     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2756     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2757     char        local_cell[MAXCELLCHARS+1];
2758     char        Dmycell[MAXCELLCHARS+1];
2759     struct ktc_token    atoken;
2760     struct ktc_token    btoken;
2761     struct afsconf_cell ak_cellconfig; /* General information about the cell */
2762     char        RealmName[128];
2763     char        CellName[128];
2764     char        ServiceName[128];
2765     DWORD       CurrentState;
2766     char        HostName[64];
2767     BOOL        try_krb5 = 0;
2768     krb5_context  ctx = NULL;
2769     krb5_ccache   cc = NULL;
2770     krb5_creds increds;
2771     krb5_creds * k5creds = NULL;
2772     krb5_error_code code;
2773     krb5_principal client_principal = NULL;
2774     krb5_data * k5data = NULL;
2775     int i, retry = 0;
2776
2777     CurrentState = 0;
2778     memset(HostName, '\0', sizeof(HostName));
2779     gethostname(HostName, sizeof(HostName));
2780     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2781         if ( IsDebuggerPresent() )
2782             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2783         return(-1);
2784     }
2785     if (CurrentState != SERVICE_RUNNING) {
2786         if ( IsDebuggerPresent() )
2787             OutputDebugString("AFSD Service NOT RUNNING\n");
2788         return(-2);
2789     }
2790
2791     if (!pkrb5_init_context)
2792         return 0;
2793
2794     memset(RealmName, '\0', sizeof(RealmName));
2795     memset(CellName, '\0', sizeof(CellName));
2796     memset(ServiceName, '\0', sizeof(ServiceName));
2797     memset(realm_of_user, '\0', sizeof(realm_of_user));
2798     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2799     if (cell && cell[0])
2800         strcpy(Dmycell, cell);
2801     else
2802         memset(Dmycell, '\0', sizeof(Dmycell));
2803
2804     // NULL or empty cell returns information on local cell
2805     if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2806     {
2807         // KFW_AFS_error(rc, "get_cellconfig()");
2808         return(rc);
2809     }
2810
2811     if ( alt_ctx ) {
2812         ctx = alt_ctx;
2813     } else {
2814         code = pkrb5_init_context(&ctx);
2815         if (code) goto cleanup;
2816     }
2817
2818     if ( alt_cc ) {
2819         cc = alt_cc;
2820     } else {
2821         code = pkrb5_cc_default(ctx, &cc);
2822         if (code) goto skip_krb5_init;
2823     }
2824
2825     memset((char *)&increds, 0, sizeof(increds));
2826
2827     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2828     if (code) {
2829         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
2830         {
2831             OutputDebugString("Principal Not Found for ccache\n");
2832         }
2833         goto skip_krb5_init;
2834     }
2835
2836     if (!KFW_accept_dotted_usernames()) {
2837         /* look for client principals which cannot be distinguished 
2838          * from Kerberos 4 multi-component principal names
2839          */
2840         k5data = krb5_princ_component(ctx,client_principal,0);
2841         for ( i=0; i<k5data->length; i++ ) {
2842             if ( k5data->data[i] == '.' )
2843                 break;
2844         }
2845         if (i != k5data->length)
2846         {
2847             OutputDebugString("Illegal Principal name contains dot in first component\n");
2848             rc = KRB5KRB_ERR_GENERIC;
2849             goto cleanup;
2850         }
2851     }
2852
2853     i = krb5_princ_realm(ctx, client_principal)->length;
2854     if (i > REALM_SZ-1) 
2855         i = REALM_SZ-1;
2856     strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2857     realm_of_user[i] = 0;
2858     try_krb5 = 1;
2859
2860   skip_krb5_init:
2861 #ifdef USE_KRB4
2862     if ( !try_krb5 || !realm_of_user[0] ) {
2863         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2864         {
2865             goto cleanup;
2866         }       
2867     }
2868 #else
2869     if (!try_krb5)
2870         goto cleanup;
2871 #endif
2872     strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2873
2874     if (strlen(service) == 0)
2875         strcpy(ServiceName, "afs");
2876     else
2877         strcpy(ServiceName, service);
2878
2879     if (strlen(cell) == 0)
2880         strcpy(CellName, local_cell);
2881     else
2882         strcpy(CellName, cell);
2883
2884     if (strlen(realm) == 0)
2885         strcpy(RealmName, realm_of_cell);
2886     else
2887         strcpy(RealmName, realm);
2888
2889     memset(&creds, '\0', sizeof(creds));
2890
2891     if ( try_krb5 ) {
2892         int len;
2893
2894         /* First try service/cell@REALM */
2895         if (code = pkrb5_build_principal(ctx, &increds.server,
2896                                           (int)strlen(RealmName),
2897                                           RealmName,
2898                                           ServiceName,
2899                                           CellName,
2900                                           0)) 
2901         {
2902             goto cleanup;
2903         }
2904
2905         increds.client = client_principal;
2906         increds.times.endtime = 0;
2907         /* Ask for DES since that is what V4 understands */
2908         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2909
2910
2911         if ( IsDebuggerPresent() ) {
2912             char * cname, *sname;
2913             pkrb5_unparse_name(ctx, increds.client, &cname);
2914             pkrb5_unparse_name(ctx, increds.server, &sname);
2915             OutputDebugString("Getting tickets for \"");
2916             OutputDebugString(cname);
2917             OutputDebugString("\" and service \"");
2918             OutputDebugString(sname);
2919             OutputDebugString("\"\n");
2920             pkrb5_free_unparsed_name(ctx,cname);
2921             pkrb5_free_unparsed_name(ctx,sname);
2922         }
2923
2924         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2925         if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2926              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2927              code == KRB5KRB_AP_ERR_MSG_TYPE) {
2928             /* Or service@REALM */
2929             pkrb5_free_principal(ctx,increds.server);
2930             increds.server = 0;
2931             code = pkrb5_build_principal(ctx, &increds.server,
2932                                           (int)strlen(RealmName),
2933                                           RealmName,
2934                                           ServiceName,
2935                                           0);
2936
2937             if ( IsDebuggerPresent() ) {
2938                 char * cname, *sname;
2939                 pkrb5_unparse_name(ctx, increds.client, &cname);
2940                 pkrb5_unparse_name(ctx, increds.server, &sname);
2941                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2942                 OutputDebugString("Trying again: getting tickets for \"");
2943                 OutputDebugString(cname);
2944                 OutputDebugString("\" and service \"");
2945                 OutputDebugString(sname);
2946                 OutputDebugString("\"\n");
2947                 pkrb5_free_unparsed_name(ctx,cname);
2948                 pkrb5_free_unparsed_name(ctx,sname);
2949             }
2950
2951             if (!code)
2952                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2953         }
2954
2955         if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2956               code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2957               code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2958              strcmp(RealmName, realm_of_cell)) {
2959             /* Or service/cell@REALM_OF_CELL */
2960             strcpy(RealmName, realm_of_cell);
2961             pkrb5_free_principal(ctx,increds.server);
2962             increds.server = 0;
2963             code = pkrb5_build_principal(ctx, &increds.server,
2964                                          (int)strlen(RealmName),
2965                                          RealmName,
2966                                          ServiceName,
2967                                          CellName,
2968                                          0);
2969
2970             if ( IsDebuggerPresent() ) {
2971                 char * cname, *sname;
2972                 pkrb5_unparse_name(ctx, increds.client, &cname);
2973                 pkrb5_unparse_name(ctx, increds.server, &sname);
2974                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2975                 OutputDebugString("Trying again: getting tickets for \"");
2976                 OutputDebugString(cname);
2977                 OutputDebugString("\" and service \"");
2978                 OutputDebugString(sname);
2979                 OutputDebugString("\"\n");
2980                 pkrb5_free_unparsed_name(ctx,cname);
2981                 pkrb5_free_unparsed_name(ctx,sname);
2982             }
2983
2984             if (!code)
2985                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2986
2987         
2988             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2989                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2990                                  code == KRB5KRB_AP_ERR_MSG_TYPE) {
2991                 /* Or service@REALM_OF_CELL */
2992                 pkrb5_free_principal(ctx,increds.server);
2993                 increds.server = 0;
2994                 code = pkrb5_build_principal(ctx, &increds.server,
2995                                               (int)strlen(RealmName),
2996                                               RealmName,
2997                                               ServiceName,
2998                                               0);
2999
3000                 if ( IsDebuggerPresent() ) {
3001                     char * cname, *sname;
3002                     pkrb5_unparse_name(ctx, increds.client, &cname);
3003                     pkrb5_unparse_name(ctx, increds.server, &sname);
3004                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
3005                     OutputDebugString("Trying again: getting tickets for \"");
3006                     OutputDebugString(cname);
3007                     OutputDebugString("\" and service \"");
3008                     OutputDebugString(sname);
3009                     OutputDebugString("\"\n");
3010                     pkrb5_free_unparsed_name(ctx,cname);
3011                     pkrb5_free_unparsed_name(ctx,sname);
3012                 }
3013
3014                 if (!code)
3015                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3016             }
3017         }
3018
3019         if (code) {
3020             if ( IsDebuggerPresent() ) {
3021                 char message[256];
3022                 sprintf(message,"krb5_get_credentials returns: %d\n",code);
3023                 OutputDebugString(message);
3024             }
3025             try_krb5 = 0;
3026             goto use_krb4;
3027         }
3028
3029         /* This code inserts the entire K5 ticket into the token
3030          * No need to perform a krb524 translation which is 
3031          * commented out in the code below
3032          */
3033         if (KFW_use_krb524() ||
3034             k5creds->ticket.length > MAXKTCTICKETLEN)
3035             goto try_krb524d;
3036
3037         memset(&aserver, '\0', sizeof(aserver));
3038         strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3039         strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3040
3041         memset(&atoken, '\0', sizeof(atoken));
3042         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
3043         atoken.startTime = k5creds->times.starttime;
3044         atoken.endTime = k5creds->times.endtime;
3045         memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
3046         atoken.ticketLen = k5creds->ticket.length;
3047         memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
3048
3049       retry_gettoken5:
3050         rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3051         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3052             if ( rc == KTC_NOCM && retry < 20 ) {
3053                 Sleep(500);
3054                 retry++;
3055                 goto retry_gettoken5;
3056             }
3057             goto try_krb524d;
3058         }
3059
3060         if (atoken.kvno == btoken.kvno &&
3061              atoken.ticketLen == btoken.ticketLen &&
3062              !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3063              !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
3064         {
3065             /* Success - Nothing to do */
3066             goto cleanup;
3067         }
3068
3069         // * Reset the "aclient" structure before we call ktc_SetToken.
3070         // * This structure was first set by the ktc_GetToken call when
3071         // * we were comparing whether identical tokens already existed.
3072
3073         len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
3074         strncpy(aclient.name, k5creds->client->data[0].data, len);
3075         aclient.name[len] = '\0';
3076
3077         if ( k5creds->client->length > 1 ) {
3078             char * p;
3079             strcat(aclient.name, ".");
3080             p = aclient.name + strlen(aclient.name);
3081             len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3082             strncpy(p, k5creds->client->data[1].data, len);
3083             p[len] = '\0';
3084         }
3085         aclient.instance[0] = '\0';
3086
3087         strcpy(aclient.cell, realm_of_cell);
3088
3089         len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3090         /* For Khimaira, always append the realm name */
3091         if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3092             char * p;
3093             strcat(aclient.name, "@");
3094             p = aclient.name + strlen(aclient.name);
3095             len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3096             strncpy(p, k5creds->client->realm.data, len);
3097             p[len] = '\0';
3098         }
3099
3100         GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3101         if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3102             ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
3103                              &aclient, &aserver, &atoken);
3104
3105         if ( smbname ) {
3106             strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3107             aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3108         } else {
3109             aclient.smbname[0] = '\0';
3110         }
3111
3112         rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3113         if (!rc)
3114             goto cleanup;   /* We have successfully inserted the token */
3115
3116       try_krb524d:
3117 #ifndef USE_KRB524
3118         goto cleanup;
3119 #else
3120         /* Otherwise, the ticket could have been too large so try to
3121          * convert using the krb524d running with the KDC 
3122          */
3123         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3124         pkrb5_free_creds(ctx, k5creds);
3125         if (code) {
3126             if ( IsDebuggerPresent() ) {
3127                 char message[256];
3128                 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3129                 OutputDebugString(message);
3130             }
3131             try_krb5 = 0;
3132             goto use_krb4;
3133         }
3134 #endif /* USE_KRB524 */
3135     } else {
3136       use_krb4:
3137 #ifdef USE_KRB4
3138         code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3139         if (code == NO_TKT_FIL) {
3140             // if the problem is that we have no krb4 tickets
3141             // do not attempt to continue
3142             goto cleanup;
3143         }
3144         if (code != KSUCCESS)
3145             code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3146
3147         if (code != KSUCCESS)
3148         {
3149             if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3150             {
3151                 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3152                 {
3153                     goto cleanup;
3154                 }
3155             }
3156             else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3157             {
3158                 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3159                 {
3160                     goto cleanup;
3161                 }
3162             }
3163             else
3164             {
3165                 goto cleanup;
3166             }
3167         }
3168 #else
3169         goto cleanup;
3170 #endif
3171     }
3172
3173     memset(&aserver, '\0', sizeof(aserver));
3174     strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3175     strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3176
3177     memset(&atoken, '\0', sizeof(atoken));
3178     atoken.kvno = creds.kvno;
3179     atoken.startTime = creds.issue_date;
3180     atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3181     memcpy(&atoken.sessionKey, creds.session, 8);
3182     atoken.ticketLen = creds.ticket_st.length;
3183     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3184
3185   retry_gettoken:
3186     rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3187     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3188         if ( rc == KTC_NOCM && retry < 20 ) {
3189             Sleep(500);
3190             retry++;
3191             goto retry_gettoken;
3192         }
3193         KFW_AFS_error(rc, "ktc_GetToken()");
3194         code = rc;
3195         goto cleanup;
3196     }
3197
3198     if (atoken.kvno == btoken.kvno &&
3199         atoken.ticketLen == btoken.ticketLen &&
3200         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3201         !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
3202     {
3203         goto cleanup;
3204     }
3205
3206     // * Reset the "aclient" structure before we call ktc_SetToken.
3207     // * This structure was first set by the ktc_GetToken call when
3208     // * we were comparing whether identical tokens already existed.
3209
3210     strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3211     if (creds.pinst[0])
3212     {
3213         strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3214         strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3215     }
3216     strcpy(aclient.instance, "");
3217
3218     strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3219     strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3220     aclient.name[MAXKTCREALMLEN-1] = '\0';
3221
3222     strcpy(aclient.cell, CellName);
3223
3224     GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3225     if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3226         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
3227                          &aclient, &aserver, &atoken);
3228
3229     if ( smbname ) {
3230         strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3231         aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3232     } else {
3233         aclient.smbname[0] = '\0';
3234     }
3235
3236     if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3237     {
3238         KFW_AFS_error(rc, "ktc_SetToken()");
3239         code = rc;
3240         goto cleanup;
3241     }
3242
3243   cleanup:
3244     if (client_principal)
3245         pkrb5_free_principal(ctx,client_principal);
3246     /* increds.client == client_principal */
3247     if (increds.server)
3248         pkrb5_free_principal(ctx,increds.server);
3249     if (cc && (cc != alt_cc))
3250         pkrb5_cc_close(ctx, cc);
3251     if (ctx && (ctx != alt_ctx))
3252         pkrb5_free_context(ctx);
3253
3254     return(rc? rc : code);
3255 }
3256
3257 /**************************************/
3258 /* afs_realm_of_cell():               */
3259 /**************************************/
3260 static char *
3261 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3262 {
3263     static char krbrlm[REALM_SZ+1]="";
3264     char ** realmlist=NULL;
3265     krb5_error_code r;
3266
3267     if (!cellconfig)
3268         return 0;
3269
3270     r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3271     if ( !r && realmlist && realmlist[0] ) {
3272         strcpy(krbrlm, realmlist[0]);
3273         pkrb5_free_host_realm(ctx, realmlist);
3274     }
3275
3276     if ( !krbrlm[0] )
3277     {
3278         char *s = krbrlm;
3279         char *t = cellconfig->name;
3280         int c;
3281
3282         while (c = *t++)
3283         {
3284             if (islower(c)) c=toupper(c);
3285             *s++ = c;
3286         }
3287         *s++ = 0;
3288     }
3289     return(krbrlm);
3290 }
3291
3292 /**************************************/
3293 /* KFW_AFS_get_cellconfig():          */
3294 /**************************************/
3295 int 
3296 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3297 {
3298     int rc;
3299     char newcell[MAXCELLCHARS+1];
3300
3301     local_cell[0] = (char)0;
3302     memset(cellconfig, 0, sizeof(*cellconfig));
3303
3304     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3305     if (rc = cm_GetRootCellName(local_cell))
3306     {
3307         return(rc);
3308     }
3309
3310     if (strlen(cell) == 0)
3311         strcpy(cell, local_cell);
3312
3313     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3314     strcpy(cellconfig->name, cell);
3315
3316     rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3317 #ifdef AFS_AFSDB_ENV
3318     if (rc != 0) {
3319         int ttl;
3320         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3321     }
3322 #endif
3323     return rc;
3324 }
3325
3326 /**************************************/
3327 /* get_cellconfig_callback():         */
3328 /**************************************/
3329 static long 
3330 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3331 {
3332     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3333
3334     cc->hostAddr[cc->numServers] = *addrp;
3335     strcpy(cc->hostName[cc->numServers], namep);
3336     cc->numServers++;
3337     return(0);
3338 }
3339
3340
3341 /**************************************/
3342 /* KFW_AFS_error():                  */
3343 /**************************************/
3344 void
3345 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3346 {
3347     char message[256];
3348     const char *errText; 
3349
3350     // Using AFS defines as error messages for now, until Transarc 
3351     // gets back to me with "string" translations of each of these 
3352     // const. defines. 
3353     if (rc == KTC_ERROR)
3354       errText = "KTC_ERROR";
3355     else if (rc == KTC_TOOBIG)
3356       errText = "KTC_TOOBIG";
3357     else if (rc == KTC_INVAL)
3358       errText = "KTC_INVAL";
3359     else if (rc == KTC_NOENT)
3360       errText = "KTC_NOENT";
3361     else if (rc == KTC_PIOCTLFAIL)
3362       errText = "KTC_PIOCTLFAIL";
3363     else if (rc == KTC_NOPIOCTL)
3364       errText = "KTC_NOPIOCTL";
3365     else if (rc == KTC_NOCELL)
3366       errText = "KTC_NOCELL";
3367     else if (rc == KTC_NOCM)
3368       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3369     else
3370       errText = "Unknown error!";
3371
3372     sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3373
3374     if ( IsDebuggerPresent() ) {
3375         OutputDebugString(message);
3376         OutputDebugString("\n");
3377     }
3378     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3379     return;
3380 }
3381
3382 static DWORD 
3383 GetServiceStatus(
3384     LPSTR lpszMachineName, 
3385     LPSTR lpszServiceName,
3386     DWORD *lpdwCurrentState) 
3387
3388     DWORD           hr               = NOERROR; 
3389     SC_HANDLE       schSCManager     = NULL; 
3390     SC_HANDLE       schService       = NULL; 
3391     DWORD           fdwDesiredAccess = 0; 
3392     SERVICE_STATUS  ssServiceStatus  = {0}; 
3393     BOOL            fRet             = FALSE; 
3394
3395     *lpdwCurrentState = 0; 
3396  
3397     fdwDesiredAccess = GENERIC_READ; 
3398  
3399     schSCManager = OpenSCManager(lpszMachineName,  
3400                                  NULL,
3401                                  fdwDesiredAccess); 
3402  
3403     if(schSCManager == NULL) 
3404     { 
3405         hr = GetLastError();
3406         goto cleanup; 
3407     } 
3408  
3409     schService = OpenService(schSCManager,
3410                              lpszServiceName,
3411                              fdwDesiredAccess); 
3412  
3413     if(schService == NULL) 
3414     { 
3415         hr = GetLastError();
3416         goto cleanup; 
3417     } 
3418  
3419     fRet = QueryServiceStatus(schService,
3420                               &ssServiceStatus); 
3421  
3422     if(fRet == FALSE) 
3423     { 
3424         hr = GetLastError(); 
3425         goto cleanup; 
3426     } 
3427  
3428     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
3429  
3430 cleanup: 
3431  
3432     CloseServiceHandle(schService); 
3433     CloseServiceHandle(schSCManager); 
3434  
3435     return(hr); 
3436
3437
3438 void
3439 UnloadFuncs(
3440     FUNC_INFO fi[], 
3441     HINSTANCE h
3442     )
3443 {
3444     int n;
3445     if (fi)
3446         for (n = 0; fi[n].func_ptr_var; n++)
3447             *(fi[n].func_ptr_var) = 0;
3448     if (h) FreeLibrary(h);
3449 }
3450
3451 int
3452 LoadFuncs(
3453     const char* dll_name, 
3454     FUNC_INFO fi[], 
3455     HINSTANCE* ph,  // [out, optional] - DLL handle
3456     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
3457     int cleanup,    // cleanup function pointers and unload on error
3458     int go_on,      // continue loading even if some functions cannot be loaded
3459     int silent      // do not pop-up a system dialog if DLL cannot be loaded
3460     )
3461 {
3462     HINSTANCE h;
3463     int i, n, last_i;
3464     int error = 0;
3465     UINT em;
3466
3467     if (ph) *ph = 0;
3468     if (pindex) *pindex = -1;
3469
3470     for (n = 0; fi[n].func_ptr_var; n++)
3471         *(fi[n].func_ptr_var) = 0;
3472
3473     if (silent)
3474         em = SetErrorMode(SEM_FAILCRITICALERRORS);
3475     h = LoadLibrary(dll_name);
3476     if (silent)
3477         SetErrorMode(em);
3478
3479     if (!h)
3480         return 0;
3481
3482     last_i = -1;
3483     for (i = 0; (go_on || !error) && (i < n); i++)
3484     {
3485         void* p = (void*)GetProcAddress(h, fi[i].func_name);
3486         if (!p)
3487             error = 1;
3488         else
3489         {
3490             last_i = i;
3491             *(fi[i].func_ptr_var) = p;
3492         }
3493     }
3494     if (pindex) *pindex = last_i;
3495     if (error && cleanup && !go_on) {
3496         for (i = 0; i < n; i++) {
3497             *(fi[i].func_ptr_var) = 0;
3498         }
3499         FreeLibrary(h);
3500         return 0;
3501     }
3502     if (ph) *ph = h;
3503     if (error) return 0;
3504     return 1;
3505 }
3506
3507 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3508 {
3509     krb5_context ctx = NULL;
3510     krb5_ccache cc = NULL;
3511     krb5_error_code code;
3512     krb5_data pwdata;
3513     const char * realm = NULL;
3514     krb5_principal principal = NULL;
3515     char * pname = NULL;
3516     char   password[PROBE_PASSWORD_LEN+1];
3517     BOOL serverReachable = 0;
3518
3519     if (!pkrb5_init_context)
3520         return 0;
3521
3522     code = pkrb5_init_context(&ctx);
3523     if (code) goto cleanup;
3524
3525
3526     realm = afs_realm_of_cell(ctx, cellconfig);  // do not free
3527
3528     code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3529                                   realm, PROBE_USERNAME, NULL, NULL);
3530     if ( code ) goto cleanup;
3531
3532     code = KFW_get_ccache(ctx, principal, &cc);
3533     if ( code ) goto cleanup;
3534
3535     code = pkrb5_unparse_name(ctx, principal, &pname);
3536     if ( code ) goto cleanup;
3537
3538     pwdata.data = password;
3539     pwdata.length = PROBE_PASSWORD_LEN;
3540     code = pkrb5_c_random_make_octets(ctx, &pwdata);
3541     if (code) {
3542         int i;
3543         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3544             password[i] = 'x';
3545     }
3546     password[PROBE_PASSWORD_LEN] = '\0';
3547
3548     code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
3549                       pname, 
3550                       password,
3551                       5,
3552                       0,
3553                       0,
3554                       0,
3555                       1,
3556                       0);
3557     switch ( code ) {
3558     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3559     case KRB5KDC_ERR_CLIENT_REVOKED:
3560     case KRB5KDC_ERR_CLIENT_NOTYET:
3561     case KRB5KDC_ERR_PREAUTH_FAILED:
3562     case KRB5KDC_ERR_PREAUTH_REQUIRED:
3563     case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3564         serverReachable = TRUE;
3565         break;
3566     default:
3567         serverReachable = FALSE;
3568     }
3569
3570   cleanup:
3571     if ( pname )
3572         pkrb5_free_unparsed_name(ctx,pname);
3573     if ( principal )
3574         pkrb5_free_principal(ctx,principal);
3575     if (cc)
3576         pkrb5_cc_close(ctx,cc);
3577     if (ctx)
3578         pkrb5_free_context(ctx);
3579
3580     return serverReachable;
3581 }
3582
3583 BOOL
3584 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3585 {
3586     krb5_context   ctx = NULL;
3587     krb5_error_code code;
3588     krb5_ccache mslsa_ccache=NULL;
3589     krb5_principal princ = NULL;
3590     char * pname = NULL;
3591     BOOL success = 0;
3592
3593     if (!KFW_is_available())
3594         return FALSE;
3595
3596     if (code = pkrb5_init_context(&ctx))
3597         goto cleanup;
3598
3599     if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3600         goto cleanup;
3601
3602     if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3603         goto cleanup;
3604
3605     if (code = pkrb5_unparse_name(ctx, princ, &pname))
3606         goto cleanup;
3607
3608     if ( strlen(pname) < *dwSize ) {
3609         strncpy(szUser, pname, *dwSize);
3610         szUser[*dwSize-1] = '\0';
3611         success = 1;
3612     }
3613     *dwSize = (DWORD)strlen(pname);
3614
3615   cleanup:
3616     if (pname)
3617         pkrb5_free_unparsed_name(ctx, pname);
3618
3619     if (princ)
3620         pkrb5_free_principal(ctx, princ);
3621
3622     if (mslsa_ccache)
3623         pkrb5_cc_close(ctx, mslsa_ccache);
3624
3625     if (ctx)
3626         pkrb5_free_context(ctx);
3627     return success;
3628 }
3629
3630 int 
3631 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3632 {
3633     // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3634     PSID pSystemSID = NULL;
3635     DWORD SystemSIDlength = 0, UserSIDlength = 0;
3636     PACL ccacheACL = NULL;
3637     DWORD ccacheACLlength = 0;
3638     PTOKEN_USER pTokenUser = NULL;
3639     DWORD retLen;
3640     DWORD gle;
3641     int ret = 0;  
3642
3643     if (!filename) {
3644         return 1;
3645     }
3646
3647     /* Get System SID */
3648     if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3649         ret = 1;
3650         goto cleanup;
3651     }
3652
3653     /* Create ACL */
3654     SystemSIDlength = GetLengthSid(pSystemSID);
3655     ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3656         + SystemSIDlength - sizeof(DWORD);
3657
3658     if (hUserToken) {
3659         if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3660         {
3661             if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3662                 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3663
3664                 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3665             }            
3666         }
3667
3668         if (pTokenUser) {
3669             UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3670
3671             ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength 
3672                 - sizeof(DWORD);
3673         }
3674     }
3675
3676     ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3677     if (!ccacheACL) {
3678         ret = 1;
3679         goto cleanup;
3680      }
3681     InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3682     AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3683                          STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3684                          pSystemSID);
3685     if (pTokenUser) {
3686         AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3687                              STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3688                              pTokenUser->User.Sid);
3689         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3690                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3691                                    NULL,
3692                                    NULL, 
3693                                    ccacheACL,
3694                                    NULL)) {
3695             gle = GetLastError();
3696             if (gle != ERROR_NO_TOKEN)
3697                 ret = 1;
3698         }
3699         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3700                                    OWNER_SECURITY_INFORMATION,
3701                                    pTokenUser->User.Sid,
3702                                    NULL, 
3703                                    NULL,
3704                                    NULL)) {
3705             gle = GetLastError();
3706             if (gle != ERROR_NO_TOKEN)
3707                 ret = 1;
3708         }
3709     } else {
3710         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3711                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3712                                    NULL,
3713                                    NULL, 
3714                                    ccacheACL,
3715                                    NULL)) {
3716             gle = GetLastError();
3717             if (gle != ERROR_NO_TOKEN)
3718                 ret = 1;
3719         }
3720     }
3721
3722   cleanup:
3723     if (pSystemSID)
3724         LocalFree(pSystemSID);
3725     if (pTokenUser)
3726         LocalFree(pTokenUser);
3727     if (ccacheACL)
3728         LocalFree(ccacheACL);
3729     return ret;
3730 }
3731
3732 int 
3733 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3734 {
3735     int  retval = 0;
3736     DWORD dwSize = size-1;      /* leave room for nul */
3737     DWORD dwLen  = 0;
3738  
3739     if (!hUserToken || !newfilename || size <= 0)
3740         return 1;
3741  
3742      *newfilename = '\0';
3743  
3744      dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3745      if ( !dwLen || dwLen > dwSize )
3746         dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3747      if ( !dwLen || dwLen > dwSize )
3748         return 1;
3749  
3750      newfilename[dwSize] = '\0';
3751     return 0;
3752 }
3753
3754 void
3755 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3756 {
3757     char filename[MAX_PATH] = "";
3758     DWORD count;
3759     char cachename[MAX_PATH + 8] = "FILE:";
3760     krb5_context                ctx = NULL;
3761     krb5_error_code             code;
3762     krb5_principal              princ = NULL;
3763     krb5_ccache                 cc  = NULL;
3764     krb5_ccache                 ncc = NULL;
3765
3766     if (!pkrb5_init_context || !user || !szLogonId)
3767         return;
3768
3769     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3770     if ( count > sizeof(filename) || count == 0 ) {
3771         GetWindowsDirectory(filename, sizeof(filename));
3772     }
3773
3774     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3775         return;
3776
3777     strcat(filename, "\\");
3778     strcat(filename, szLogonId);    
3779
3780     strcat(cachename, filename);
3781
3782     DeleteFile(filename);
3783
3784     code = pkrb5_init_context(&ctx);
3785     if (code) goto cleanup;
3786
3787     code = pkrb5_parse_name(ctx, user, &princ);
3788     if (code) goto cleanup;
3789
3790     code = KFW_get_ccache(ctx, princ, &cc);
3791     if (code) goto cleanup;
3792
3793     code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3794     if (code) goto cleanup;
3795
3796     code = pkrb5_cc_initialize(ctx, ncc, princ);
3797     if (code) goto cleanup;
3798
3799     code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3800     if (code) goto cleanup;
3801
3802     code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3803
3804   cleanup:
3805     if ( cc ) {
3806         pkrb5_cc_close(ctx, cc);
3807         cc = 0;
3808     }
3809     if ( ncc ) {
3810         pkrb5_cc_close(ctx, ncc);
3811         ncc = 0;
3812     }
3813     if ( princ ) {
3814         pkrb5_free_principal(ctx, princ);
3815         princ = 0;
3816     }
3817
3818     if (ctx)
3819         pkrb5_free_context(ctx);
3820 }
3821
3822 int
3823 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3824 {
3825     char cachename[MAX_PATH + 8] = "FILE:";
3826     krb5_context                ctx = NULL;
3827     krb5_error_code             code;
3828     krb5_principal              princ = NULL;
3829     krb5_ccache                 cc  = NULL;
3830     krb5_ccache                 ncc = NULL;
3831     int retval = 1;
3832
3833     if (!pkrb5_init_context || !filename)
3834         return 1;
3835
3836     if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3837         return 1;
3838
3839     code = pkrb5_init_context(&ctx);
3840     if (code) return 1;
3841
3842     strcat(cachename, filename);
3843
3844     code = pkrb5_cc_resolve(ctx, cachename, &cc);
3845     if (code) goto cleanup;
3846     
3847     code = pkrb5_cc_get_principal(ctx, cc, &princ);
3848
3849     code = pkrb5_cc_default(ctx, &ncc);
3850     if (!code) {
3851         code = pkrb5_cc_initialize(ctx, ncc, princ);
3852
3853         if (!code)
3854             code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3855     }
3856     if ( ncc ) {
3857         pkrb5_cc_close(ctx, ncc);
3858         ncc = 0;
3859     }
3860
3861     retval=0;   /* success */
3862
3863   cleanup:
3864     if ( cc ) {
3865         pkrb5_cc_close(ctx, cc);
3866         cc = 0;
3867     }
3868
3869     DeleteFile(filename);
3870
3871     if ( princ ) {
3872         pkrb5_free_principal(ctx, princ);
3873         princ = 0;
3874     }
3875
3876     if (ctx)
3877         pkrb5_free_context(ctx);
3878
3879     return 0;
3880 }
3881
3882 /* We are including this 
3883
3884 /* Ticket lifetime.  This defines the table used to lookup lifetime for the
3885    fixed part of rande of the one byte lifetime field.  Values less than 0x80
3886    are intrpreted as the number of 5 minute intervals.  Values from 0x80 to
3887    0xBF should be looked up in this table.  The value of 0x80 is the same using
3888    both methods: 10 and two-thirds hours .  The lifetime of 0xBF is 30 days.
3889    The intervening values of have a fixed ratio of roughly 1.06914.  The value
3890    oxFF is defined to mean a ticket has no expiration time.  This should be
3891    used advisedly since individual servers may impose defacto upperbounds on
3892    ticket lifetimes. */
3893
3894 #define TKTLIFENUMFIXED 64
3895 #define TKTLIFEMINFIXED 0x80
3896 #define TKTLIFEMAXFIXED 0xBF
3897 #define TKTLIFENOEXPIRE 0xFF
3898 #define MAXTKTLIFETIME  (30*24*3600)    /* 30 days */
3899
3900 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3901     38400,                      /* 10.67 hours, 0.44 days */
3902     41055,                      /* 11.40 hours, 0.48 days */
3903     43894,                      /* 12.19 hours, 0.51 days */
3904     46929,                      /* 13.04 hours, 0.54 days */
3905     50174,                      /* 13.94 hours, 0.58 days */
3906     53643,                      /* 14.90 hours, 0.62 days */
3907     57352,                      /* 15.93 hours, 0.66 days */
3908     61318,                      /* 17.03 hours, 0.71 days */
3909     65558,                      /* 18.21 hours, 0.76 days */
3910     70091,                      /* 19.47 hours, 0.81 days */
3911     74937,                      /* 20.82 hours, 0.87 days */
3912     80119,                      /* 22.26 hours, 0.93 days */
3913     85658,                      /* 23.79 hours, 0.99 days */
3914     91581,                      /* 25.44 hours, 1.06 days */
3915     97914,                      /* 27.20 hours, 1.13 days */
3916     104684,                     /* 29.08 hours, 1.21 days */
3917     111922,                     /* 31.09 hours, 1.30 days */
3918     119661,                     /* 33.24 hours, 1.38 days */
3919     127935,                     /* 35.54 hours, 1.48 days */
3920     136781,                     /* 37.99 hours, 1.58 days */
3921     146239,                     /* 40.62 hours, 1.69 days */
3922     156350,                     /* 43.43 hours, 1.81 days */
3923     167161,                     /* 46.43 hours, 1.93 days */
3924     178720,                     /* 49.64 hours, 2.07 days */
3925     191077,                     /* 53.08 hours, 2.21 days */
3926     204289,                     /* 56.75 hours, 2.36 days */
3927     218415,                     /* 60.67 hours, 2.53 days */
3928     233517,                     /* 64.87 hours, 2.70 days */
3929     249664,                     /* 69.35 hours, 2.89 days */
3930     266926,                     /* 74.15 hours, 3.09 days */
3931     285383,                     /* 79.27 hours, 3.30 days */
3932     305116,                     /* 84.75 hours, 3.53 days */
3933     326213,                     /* 90.61 hours, 3.78 days */
3934     348769,                     /* 96.88 hours, 4.04 days */
3935     372885,                     /* 103.58 hours, 4.32 days */
3936     398668,                     /* 110.74 hours, 4.61 days */
3937     426234,                     /* 118.40 hours, 4.93 days */
3938     455705,                     /* 126.58 hours, 5.27 days */
3939     487215,                     /* 135.34 hours, 5.64 days */
3940     520904,                     /* 144.70 hours, 6.03 days */
3941     556921,                     /* 154.70 hours, 6.45 days */
3942     595430,                     /* 165.40 hours, 6.89 days */
3943     636601,                     /* 176.83 hours, 7.37 days */
3944     680618,                     /* 189.06 hours, 7.88 days */
3945     727680,                     /* 202.13 hours, 8.42 days */
3946     777995,                     /* 216.11 hours, 9.00 days */
3947     831789,                     /* 231.05 hours, 9.63 days */
3948     889303,                     /* 247.03 hours, 10.29 days */
3949     950794,                     /* 264.11 hours, 11.00 days */
3950     1016537,                    /* 282.37 hours, 11.77 days */
3951     1086825,                    /* 301.90 hours, 12.58 days */
3952     1161973,                    /* 322.77 hours, 13.45 days */
3953     1242318,                    /* 345.09 hours, 14.38 days */
3954     1328218,                    /* 368.95 hours, 15.37 days */
3955     1420057,                    /* 394.46 hours, 16.44 days */
3956     1518247,                    /* 421.74 hours, 17.57 days */
3957     1623226,                    /* 450.90 hours, 18.79 days */
3958     1735464,                    /* 482.07 hours, 20.09 days */
3959     1855462,                    /* 515.41 hours, 21.48 days */
3960     1983758,                    /* 551.04 hours, 22.96 days */
3961     2120925,                    /* 589.15 hours, 24.55 days */
3962     2267576,                    /* 629.88 hours, 26.25 days */
3963     2424367,                    /* 673.44 hours, 28.06 days */
3964     2592000
3965 };                              /* 720.00 hours, 30.00 days */
3966
3967 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3968  * returns the corresponding end time.  There are four simple cases to be
3969  * handled.  The first is a life of 0xff, meaning no expiration, and results in
3970  * an end time of 0xffffffff.  The second is when life is less than the values
3971  * covered by the table.  In this case, the end time is the start time plus the
3972  * number of 5 minute intervals specified by life.  The third case returns
3973  * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED.  The
3974  * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3975  * table to extract the lifetime in seconds, which is added to start to produce
3976  * the end time. */
3977
3978 afs_uint32
3979 life_to_time(afs_uint32 start, unsigned char life)
3980 {
3981     int realLife;
3982
3983     if (life == TKTLIFENOEXPIRE)
3984         return NEVERDATE;
3985     if (life < TKTLIFEMINFIXED)
3986         return start + life * 5 * 60;
3987     if (life > TKTLIFEMAXFIXED)
3988         return start + MAXTKTLIFETIME;
3989     realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3990     return start + realLife;
3991 }
3992
3993 /* time_to_life - takes start and end times for the ticket and returns a
3994  * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3995  * lifetimes above 127*5minutes.  First, the special case of (end ==
3996  * 0xffffffff) is handled to mean no expiration.  Then negative lifetimes and
3997  * those greater than the maximum ticket lifetime are rejected.  Then lifetimes
3998  * less than the first table entry are handled by rounding the requested
3999  * lifetime *up* to the next 5 minute interval.  The final step is to search
4000  * the table for the smallest entry *greater than or equal* to the requested
4001  * entry.  The actual code is prepared to handle the case where the table is
4002  * unordered but that it an unnecessary frill. */
4003
4004 static unsigned char
4005 time_to_life(afs_uint32 start, afs_uint32 end)
4006 {
4007     int lifetime = end - start;
4008     int best, best_i;
4009     int i;
4010
4011     if (end == NEVERDATE)
4012         return TKTLIFENOEXPIRE;
4013     if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
4014         return 0;
4015     if (lifetime < tkt_lifetimes[0])
4016         return (lifetime + 5 * 60 - 1) / (5 * 60);
4017     best_i = -1;
4018     best = MAXKTCTICKETLIFETIME;
4019     for (i = 0; i < TKTLIFENUMFIXED; i++)
4020         if (tkt_lifetimes[i] >= lifetime) {
4021             int diff = tkt_lifetimes[i] - lifetime;
4022             if (diff < best) {
4023                 best = diff;
4024                 best_i = i;
4025             }
4026         }
4027     if (best_i < 0)
4028         return 0;
4029     return best_i + TKTLIFEMINFIXED;
4030 }
4031