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