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