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