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