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