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