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