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