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