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