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