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