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