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