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