d86ad7a9f143dbc8db0ee601eca6c6eb464f432b
[openafs.git] / src / WINNT / afsd / afskfw.c
1 /*
2  * Copyright (c) 2003 SkyRope, LLC
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without 
6  * modification, are permitted provided that the following conditions are met:
7  * 
8  * - Redistributions of source code must retain the above copyright notice, 
9  *   this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright notice, 
11  *   this list of conditions and the following disclaimer in the documentation 
12  *   and/or other materials provided with the distribution.
13  * - Neither the name of Skyrope, LLC nor the names of its contributors may be 
14  *   used to endorse or promote products derived from this software without 
15  *   specific prior written permission from Skyrope, LLC.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Portions of this code are derived from portions of the MIT
30  * Leash Ticket Manager and LoadFuncs utilities.  For these portions the
31  * following copyright applies.
32  *
33  * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
34  * All rights reserved.
35  *
36  * Export of this software from the United States of America may
37  *   require a specific license from the United States Government.
38  *   It is the responsibility of any person or organization contemplating
39  *   export to obtain such a license before exporting.
40  *
41  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42  * distribute this software and its documentation for any purpose and
43  * without fee is hereby granted, provided that the above copyright
44  * notice appear in all copies and that both that copyright notice and
45  * this permission notice appear in supporting documentation, and that
46  * the name of M.I.T. not be used in advertising or publicity pertaining
47  * to distribution of the software without specific, written prior
48  * permission.  Furthermore if you modify this software you must label
49  * your software as modified software and not distribute it in such a
50  * fashion that it might be confused with the original M.I.T. software.
51  * M.I.T. makes no representations about the suitability of
52  * this software for any purpose.  It is provided "as is" without express
53  * or implied warranty.
54  *
55  */
56
57
58 #define USE_MS2MIT
59 #undef  USE_KRB4
60 #include "afskfw-int.h"
61 #include "afskfw.h"
62
63 #include <osilog.h>
64 #include <rxkad_prototypes.h>   /* for life_to_time */
65 #include <afs/ptserver.h>
66 #include <afs/ptuser.h>
67
68 #include <WINNT\afsreg.h>
69
70 /*
71  * TIMING _____________________________________________________________________
72  *
73  */
74
75 #define cminREMIND_TEST      1    // test every minute for expired creds
76 #define cminREMIND_WARN      15   // warn if creds expire in 15 minutes
77 #define cminRENEW            20   // renew creds when there are 20 minutes remaining
78 #define cminMINLIFE          30   // minimum life of Kerberos creds
79
80 #define c100ns1SECOND        (LONGLONG)10000000
81 #define cmsec1SECOND         1000
82 #define cmsec1MINUTE         60000
83 #define csec1MINUTE          60
84
85 /* Function Pointer Declarations for Delayed Loading */
86 // CCAPI
87 DECL_FUNC_PTR(cc_initialize);
88 DECL_FUNC_PTR(cc_shutdown);
89 DECL_FUNC_PTR(cc_get_NC_info);
90 DECL_FUNC_PTR(cc_free_NC_info);
91
92 // leash functions
93 DECL_FUNC_PTR(Leash_get_default_lifetime);
94 DECL_FUNC_PTR(Leash_get_default_forwardable);
95 DECL_FUNC_PTR(Leash_get_default_renew_till);
96 DECL_FUNC_PTR(Leash_get_default_noaddresses);
97 DECL_FUNC_PTR(Leash_get_default_proxiable);
98 DECL_FUNC_PTR(Leash_get_default_publicip);
99 DECL_FUNC_PTR(Leash_get_default_use_krb4);
100 DECL_FUNC_PTR(Leash_get_default_life_min);
101 DECL_FUNC_PTR(Leash_get_default_life_max);
102 DECL_FUNC_PTR(Leash_get_default_renew_min);
103 DECL_FUNC_PTR(Leash_get_default_renew_max);
104 DECL_FUNC_PTR(Leash_get_default_renewable);
105 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
106
107 // krb5 functions
108 DECL_FUNC_PTR(krb5_change_password);
109 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
110 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
111 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
112 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
113 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
114 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
115 DECL_FUNC_PTR(krb5_get_init_creds_password);
116 DECL_FUNC_PTR(krb5_build_principal_ext);
117 DECL_FUNC_PTR(krb5_cc_get_name);
118 DECL_FUNC_PTR(krb5_cc_resolve);
119 DECL_FUNC_PTR(krb5_cc_default);
120 DECL_FUNC_PTR(krb5_cc_default_name);
121 DECL_FUNC_PTR(krb5_cc_set_default_name);
122 DECL_FUNC_PTR(krb5_cc_initialize);
123 DECL_FUNC_PTR(krb5_cc_destroy);
124 DECL_FUNC_PTR(krb5_cc_close);
125 DECL_FUNC_PTR(krb5_cc_store_cred);
126 DECL_FUNC_PTR(krb5_cc_copy_creds);
127 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
128 DECL_FUNC_PTR(krb5_cc_get_principal);
129 DECL_FUNC_PTR(krb5_cc_start_seq_get);
130 DECL_FUNC_PTR(krb5_cc_next_cred);
131 DECL_FUNC_PTR(krb5_cc_end_seq_get);
132 DECL_FUNC_PTR(krb5_cc_remove_cred);
133 DECL_FUNC_PTR(krb5_cc_set_flags);
134 DECL_FUNC_PTR(krb5_cc_get_type);
135 DECL_FUNC_PTR(krb5_free_context);
136 DECL_FUNC_PTR(krb5_free_cred_contents);
137 DECL_FUNC_PTR(krb5_free_principal);
138 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
139 DECL_FUNC_PTR(krb5_init_context);
140 DECL_FUNC_PTR(krb5_parse_name);
141 DECL_FUNC_PTR(krb5_timeofday);
142 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
143 DECL_FUNC_PTR(krb5_unparse_name);
144 DECL_FUNC_PTR(krb5_get_credentials);
145 DECL_FUNC_PTR(krb5_mk_req);
146 DECL_FUNC_PTR(krb5_sname_to_principal);
147 DECL_FUNC_PTR(krb5_get_credentials_renew);
148 DECL_FUNC_PTR(krb5_free_data);
149 DECL_FUNC_PTR(krb5_free_data_contents);
150 DECL_FUNC_PTR(krb5_free_unparsed_name);
151 DECL_FUNC_PTR(krb5_os_localaddr);
152 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
153 DECL_FUNC_PTR(krb5_copy_data);
154 DECL_FUNC_PTR(krb5_free_creds);
155 DECL_FUNC_PTR(krb5_build_principal);
156 DECL_FUNC_PTR(krb5_get_renewed_creds);
157 DECL_FUNC_PTR(krb5_get_default_config_files);
158 DECL_FUNC_PTR(krb5_free_config_files);
159 DECL_FUNC_PTR(krb5_get_default_realm);
160 DECL_FUNC_PTR(krb5_free_default_realm);
161 DECL_FUNC_PTR(krb5_free_ticket);
162 DECL_FUNC_PTR(krb5_decode_ticket);
163 DECL_FUNC_PTR(krb5_get_host_realm);
164 DECL_FUNC_PTR(krb5_free_host_realm);
165 DECL_FUNC_PTR(krb5_free_addresses);
166 DECL_FUNC_PTR(krb5_c_random_make_octets);
167
168 // Krb524 functions
169 DECL_FUNC_PTR(krb524_init_ets);
170 DECL_FUNC_PTR(krb524_convert_creds_kdc);
171
172 // krb4 functions
173 DECL_FUNC_PTR(krb_get_cred);
174 DECL_FUNC_PTR(tkt_string);
175 DECL_FUNC_PTR(krb_get_tf_realm);
176 DECL_FUNC_PTR(krb_mk_req);
177
178 // ComErr functions
179 DECL_FUNC_PTR(com_err);
180 DECL_FUNC_PTR(error_message);
181
182 // Profile functions
183 DECL_FUNC_PTR(profile_init);
184 DECL_FUNC_PTR(profile_release);
185 DECL_FUNC_PTR(profile_get_subsection_names);
186 DECL_FUNC_PTR(profile_free_list);
187 DECL_FUNC_PTR(profile_get_string);
188 DECL_FUNC_PTR(profile_release_string);
189
190 // Service functions
191 DECL_FUNC_PTR(OpenSCManagerA);
192 DECL_FUNC_PTR(OpenServiceA);
193 DECL_FUNC_PTR(QueryServiceStatus);
194 DECL_FUNC_PTR(CloseServiceHandle);
195 #ifdef USE_MS2MIT
196 DECL_FUNC_PTR(LsaNtStatusToWinError);
197 #endif /* USE_MS2MIT */
198
199 #ifdef USE_MS2MIT
200 // LSA Functions
201 DECL_FUNC_PTR(LsaConnectUntrusted);
202 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
203 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
204 DECL_FUNC_PTR(LsaFreeReturnBuffer);
205 DECL_FUNC_PTR(LsaGetLogonSessionData);
206 #endif /* USE_MS2MIT */
207
208 // CCAPI
209 FUNC_INFO ccapi_fi[] = {
210     MAKE_FUNC_INFO(cc_initialize),
211     MAKE_FUNC_INFO(cc_shutdown),
212     MAKE_FUNC_INFO(cc_get_NC_info),
213     MAKE_FUNC_INFO(cc_free_NC_info),
214     END_FUNC_INFO
215 };
216
217 FUNC_INFO leash_fi[] = {
218     MAKE_FUNC_INFO(Leash_get_default_lifetime),
219     MAKE_FUNC_INFO(Leash_get_default_renew_till),
220     MAKE_FUNC_INFO(Leash_get_default_forwardable),
221     MAKE_FUNC_INFO(Leash_get_default_noaddresses),
222     MAKE_FUNC_INFO(Leash_get_default_proxiable),
223     MAKE_FUNC_INFO(Leash_get_default_publicip),
224     MAKE_FUNC_INFO(Leash_get_default_use_krb4),
225     MAKE_FUNC_INFO(Leash_get_default_life_min),
226     MAKE_FUNC_INFO(Leash_get_default_life_max),
227     MAKE_FUNC_INFO(Leash_get_default_renew_min),
228     MAKE_FUNC_INFO(Leash_get_default_renew_max),
229     MAKE_FUNC_INFO(Leash_get_default_renewable),
230     END_FUNC_INFO
231 };
232
233 FUNC_INFO leash_opt_fi[] = {
234     MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
235     END_FUNC_INFO
236 };
237
238 FUNC_INFO k5_fi[] = {
239     MAKE_FUNC_INFO(krb5_change_password),
240     MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
241     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
242     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
243     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
244     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
245     MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
246     MAKE_FUNC_INFO(krb5_get_init_creds_password),
247     MAKE_FUNC_INFO(krb5_build_principal_ext),
248     MAKE_FUNC_INFO(krb5_cc_get_name),
249     MAKE_FUNC_INFO(krb5_cc_resolve),
250     MAKE_FUNC_INFO(krb5_cc_default),
251     MAKE_FUNC_INFO(krb5_cc_default_name),
252     MAKE_FUNC_INFO(krb5_cc_set_default_name),
253     MAKE_FUNC_INFO(krb5_cc_initialize),
254     MAKE_FUNC_INFO(krb5_cc_destroy),
255     MAKE_FUNC_INFO(krb5_cc_close),
256     MAKE_FUNC_INFO(krb5_cc_copy_creds),
257     MAKE_FUNC_INFO(krb5_cc_store_cred),
258     MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
259     MAKE_FUNC_INFO(krb5_cc_get_principal),
260     MAKE_FUNC_INFO(krb5_cc_start_seq_get),
261     MAKE_FUNC_INFO(krb5_cc_next_cred),
262     MAKE_FUNC_INFO(krb5_cc_end_seq_get),
263     MAKE_FUNC_INFO(krb5_cc_remove_cred),
264     MAKE_FUNC_INFO(krb5_cc_set_flags),
265     MAKE_FUNC_INFO(krb5_cc_get_type),
266     MAKE_FUNC_INFO(krb5_free_context),
267     MAKE_FUNC_INFO(krb5_free_cred_contents),
268     MAKE_FUNC_INFO(krb5_free_principal),
269     MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
270     MAKE_FUNC_INFO(krb5_init_context),
271     MAKE_FUNC_INFO(krb5_parse_name),
272     MAKE_FUNC_INFO(krb5_timeofday),
273     MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
274     MAKE_FUNC_INFO(krb5_unparse_name),
275     MAKE_FUNC_INFO(krb5_get_credentials),
276     MAKE_FUNC_INFO(krb5_mk_req),
277     MAKE_FUNC_INFO(krb5_sname_to_principal),
278     MAKE_FUNC_INFO(krb5_get_credentials_renew),
279     MAKE_FUNC_INFO(krb5_free_data),
280     MAKE_FUNC_INFO(krb5_free_data_contents),
281     MAKE_FUNC_INFO(krb5_free_unparsed_name),
282     MAKE_FUNC_INFO(krb5_os_localaddr),
283     MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
284     MAKE_FUNC_INFO(krb5_copy_data),
285     MAKE_FUNC_INFO(krb5_free_creds),
286     MAKE_FUNC_INFO(krb5_build_principal),
287     MAKE_FUNC_INFO(krb5_get_renewed_creds),
288     MAKE_FUNC_INFO(krb5_free_addresses),
289     MAKE_FUNC_INFO(krb5_get_default_config_files),
290     MAKE_FUNC_INFO(krb5_free_config_files),
291     MAKE_FUNC_INFO(krb5_get_default_realm),
292     MAKE_FUNC_INFO(krb5_free_default_realm),
293     MAKE_FUNC_INFO(krb5_free_ticket),
294     MAKE_FUNC_INFO(krb5_decode_ticket),
295     MAKE_FUNC_INFO(krb5_get_host_realm),
296     MAKE_FUNC_INFO(krb5_free_host_realm),
297     MAKE_FUNC_INFO(krb5_free_addresses),
298     MAKE_FUNC_INFO(krb5_c_random_make_octets),
299     END_FUNC_INFO
300 };
301
302 #ifdef USE_KRB4
303 FUNC_INFO k4_fi[] = {
304     MAKE_FUNC_INFO(krb_get_cred),
305     MAKE_FUNC_INFO(krb_get_tf_realm),
306     MAKE_FUNC_INFO(krb_mk_req),
307     MAKE_FUNC_INFO(tkt_string),
308     END_FUNC_INFO
309 };
310 #endif
311
312 FUNC_INFO k524_fi[] = {
313     MAKE_FUNC_INFO(krb524_init_ets),
314     MAKE_FUNC_INFO(krb524_convert_creds_kdc),
315     END_FUNC_INFO
316 };
317
318 FUNC_INFO profile_fi[] = {
319         MAKE_FUNC_INFO(profile_init),
320         MAKE_FUNC_INFO(profile_release),
321         MAKE_FUNC_INFO(profile_get_subsection_names),
322         MAKE_FUNC_INFO(profile_free_list),
323         MAKE_FUNC_INFO(profile_get_string),
324         MAKE_FUNC_INFO(profile_release_string),
325         END_FUNC_INFO
326 };
327
328 FUNC_INFO ce_fi[] = {
329     MAKE_FUNC_INFO(com_err),
330     MAKE_FUNC_INFO(error_message),
331     END_FUNC_INFO
332 };
333
334 FUNC_INFO service_fi[] = {
335     MAKE_FUNC_INFO(OpenSCManagerA),
336     MAKE_FUNC_INFO(OpenServiceA),
337     MAKE_FUNC_INFO(QueryServiceStatus),
338     MAKE_FUNC_INFO(CloseServiceHandle),
339 #ifdef USE_MS2MIT
340     MAKE_FUNC_INFO(LsaNtStatusToWinError),
341 #endif /* USE_MS2MIT */
342     END_FUNC_INFO
343 };
344
345 #ifdef USE_MS2MIT
346 FUNC_INFO lsa_fi[] = {
347     MAKE_FUNC_INFO(LsaConnectUntrusted),
348     MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
349     MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
350     MAKE_FUNC_INFO(LsaFreeReturnBuffer),
351     MAKE_FUNC_INFO(LsaGetLogonSessionData),
352     END_FUNC_INFO
353 };
354 #endif /* USE_MS2MIT */
355
356 /* Static Prototypes */
357 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
358 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
359 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
360 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
361            void *data, const char *name, const char *banner, int num_prompts,
362            krb5_prompt prompts[]);
363
364
365 /* Static Declarations */
366 static int                inited = 0;
367 static int                mid_cnt = 0;
368 static struct textField * mid_tb = NULL;
369 static HINSTANCE hKrb5 = 0;
370 #ifdef USE_KRB4
371 static HINSTANCE hKrb4 = 0;
372 #endif /* USE_KRB4 */
373 static HINSTANCE hKrb524 = 0;
374 #ifdef USE_MS2MIT
375 static HINSTANCE hSecur32 = 0;
376 #endif /* USE_MS2MIT */
377 static HINSTANCE hAdvApi32 = 0;
378 static HINSTANCE hComErr = 0;
379 static HINSTANCE hService = 0;
380 static HINSTANCE hProfile = 0;
381 static HINSTANCE hLeash = 0;
382 static HINSTANCE hLeashOpt = 0;
383 static HINSTANCE hCCAPI = 0;
384 static struct principal_ccache_data * princ_cc_data = NULL;
385 static struct cell_principal_map    * cell_princ_map = NULL;
386
387 void
388 KFW_initialize(void)
389 {
390     static int inited = 0;
391
392     if ( !inited ) {
393         char mutexName[MAX_PATH];
394         HANDLE hMutex = NULL;
395
396         sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
397         
398         hMutex = CreateMutex( NULL, TRUE, mutexName );
399         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
400             if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
401                 return;
402             }
403         }
404         if ( !inited ) {
405             inited = 1;
406             LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
407 #ifdef USE_KRB4
408             LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
409 #endif /* USE_KRB4 */
410             LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
411             LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
412 #ifdef USE_MS2MIT
413             LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
414 #endif /* USE_MS2MIT */
415             LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
416             LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
417             LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
418             LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
419             LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
420
421             if ( KFW_is_available() ) {
422                 char rootcell[MAXCELLCHARS+1];
423 #ifdef USE_MS2MIT
424                 KFW_import_windows_lsa();
425 #endif /* USE_MS2MIT */
426                 KFW_import_ccache_data();
427                 KFW_AFS_renew_expiring_tokens();
428
429                 /* WIN32 NOTE: no way to get max chars */
430                 if (!cm_GetRootCellName(rootcell))
431                     KFW_AFS_renew_token_for_cell(rootcell);
432             }
433         }
434         ReleaseMutex(hMutex);
435         CloseHandle(hMutex);
436     }
437 }
438
439 void
440 KFW_cleanup(void)
441 {
442     if (hLeashOpt)
443         FreeLibrary(hLeashOpt);
444     if (hCCAPI)
445         FreeLibrary(hCCAPI);
446     if (hLeash)
447         FreeLibrary(hLeash);
448     if (hKrb524)
449         FreeLibrary(hKrb524);
450 #ifdef USE_MS2MIT
451     if (hSecur32)
452         FreeLibrary(hSecur32);
453 #endif /* USE_MS2MIT */
454     if (hService)
455         FreeLibrary(hService);
456     if (hComErr)
457         FreeLibrary(hComErr);
458     if (hProfile)
459         FreeLibrary(hProfile);
460 #ifdef USE_KRB4
461     if (hKrb4)
462         FreeLibrary(hKrb4);
463 #endif /* USE_KRB4 */
464     if (hKrb5)
465         FreeLibrary(hKrb5);
466 }
467
468 int
469 KFW_use_krb524(void)
470 {
471     HKEY parmKey;
472     DWORD code, len;
473     DWORD use524 = 0;
474
475     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
476                          0, KEY_QUERY_VALUE, &parmKey);
477     if (code == ERROR_SUCCESS) {
478         len = sizeof(use524);
479         code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
480                                 (BYTE *) &use524, &len);
481         RegCloseKey(parmKey);
482     }
483     if (code != ERROR_SUCCESS) {
484         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
485                              0, KEY_QUERY_VALUE, &parmKey);
486         if (code == ERROR_SUCCESS) {
487             len = sizeof(use524);
488             code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
489                                     (BYTE *) &use524, &len);
490             RegCloseKey (parmKey);
491         }
492     }
493     return use524;
494 }
495
496 int 
497 KFW_is_available(void)
498 {
499     HKEY parmKey;
500     DWORD code, len;
501     DWORD enableKFW = 1;
502
503     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
504                          0, KEY_QUERY_VALUE, &parmKey);
505     if (code == ERROR_SUCCESS) {
506         len = sizeof(enableKFW);
507         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
508                                 (BYTE *) &enableKFW, &len);
509         RegCloseKey (parmKey);
510     }
511     
512     if (code != ERROR_SUCCESS) {
513         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
514                              0, KEY_QUERY_VALUE, &parmKey);
515         if (code == ERROR_SUCCESS) {
516             len = sizeof(enableKFW);
517             code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
518                                     (BYTE *) &enableKFW, &len);
519             RegCloseKey (parmKey);
520         }
521     } 
522
523     if ( !enableKFW )
524         return FALSE;
525
526     KFW_initialize();
527     if ( hKrb5 && hComErr && hService && 
528 #ifdef USE_MS2MIT
529          hSecur32 && 
530 #endif /* USE_MS2MIT */
531          hKrb524 &&
532          hProfile && hLeash && hCCAPI )
533         return TRUE;
534     return FALSE;
535 }
536
537 int 
538 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, 
539                  int FreeContextFlag, krb5_context * ctx, 
540                  krb5_ccache * cache)
541 {
542     char message[256];
543     const char *errText;
544     int krb5Error = ((int)(rc & 255));  
545     
546     /*
547     switch (krb5Error)
548     {
549         // Wrong password
550         case 31:
551         case 8:
552             return;
553     }
554     */
555         
556     errText = perror_message(rc);   
557     _snprintf(message, sizeof(message), 
558               "%s\n(Kerberos error %ld)\n\n%s failed", 
559               errText, 
560               krb5Error, 
561               FailedFunctionName);
562
563     if ( IsDebuggerPresent() )
564         OutputDebugString(message);
565
566     MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 
567                MB_TASKMODAL | 
568                MB_SETFOREGROUND);
569     if (FreeContextFlag == 1)
570     {
571         if (ctx && *ctx != NULL)
572         {
573             if (cache && *cache != NULL) {
574                 pkrb5_cc_close(*ctx, *cache);
575                                 *cache = NULL;
576                         }
577         
578             pkrb5_free_context(*ctx);
579                         *ctx = NULL;
580         }
581     }
582
583     return rc;
584 }
585
586 void
587 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
588 {
589     struct principal_ccache_data * next = princ_cc_data;
590     krb5_principal principal = 0;
591     char * pname = NULL;
592     const char * ccname = NULL;
593     krb5_error_code code = 0;
594     krb5_error_code cc_code = 0;
595     krb5_cc_cursor cur;
596     krb5_creds creds;
597     krb5_flags flags=0;
598     krb5_timestamp now;
599
600     if (ctx == 0 || cc == 0)
601         return;
602
603     code = pkrb5_cc_get_principal(ctx, cc, &principal);
604     if ( code ) return;
605
606     code = pkrb5_unparse_name(ctx, principal, &pname);
607     if ( code ) goto cleanup;
608
609     ccname = pkrb5_cc_get_name(ctx, cc);
610     if (!ccname) goto cleanup;
611
612     // Search the existing list to see if we have a match 
613     if ( next ) {
614         for ( ; next ; next = next->next ) {
615             if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
616                 break;
617         }
618     } 
619
620     // If not, match add a new node to the beginning of the list and assign init it
621     if ( !next ) {
622         next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
623         next->next = princ_cc_data;
624         princ_cc_data = next;
625         next->principal = _strdup(pname);
626         next->ccache_name = _strdup(ccname);
627         next->from_lsa = lsa;
628         next->expired = 1;
629         next->expiration_time = 0;
630         next->renew = 0;
631     }
632
633     flags = 0;  // turn off OPENCLOSE mode
634     code = pkrb5_cc_set_flags(ctx, cc, flags);
635     if ( code ) goto cleanup;
636
637     code = pkrb5_timeofday(ctx, &now);
638
639     cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
640
641     while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
642         if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
643             int valid;
644             // we found the ticket we are looking for
645             // check validity of timestamp 
646             // We add a 5 minutes fudge factor to compensate for potential
647             // clock skew errors between the KDC and client OS
648
649             valid = ((creds.times.starttime > 0) &&
650                      now >= (creds.times.starttime - 300) &&
651                      now < (creds.times.endtime + 300) &&
652                      !(creds.ticket_flags & TKT_FLG_INVALID));
653
654             if ( next->from_lsa) {
655                 next->expired = 0;
656                 next->expiration_time = creds.times.endtime;
657                 next->renew = 1;
658             } else if ( valid ) {
659                 next->expired = 0;
660                 next->expiration_time = creds.times.endtime;
661                 next->renew = (creds.times.renew_till > creds.times.endtime) && 
662                                (creds.ticket_flags & TKT_FLG_RENEWABLE);
663             } else {
664                 next->expired = 1;
665                 next->expiration_time = 0;
666                 next->renew = 0;
667             }
668
669             pkrb5_free_cred_contents(ctx, &creds);
670             cc_code = KRB5_CC_END;
671             break;
672         }
673         pkrb5_free_cred_contents(ctx, &creds);
674     }
675
676     if (cc_code == KRB5_CC_END) {
677         code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
678         if (code) goto cleanup;
679     }
680
681   cleanup:
682     flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
683     code = pkrb5_cc_set_flags(ctx, cc, flags);
684
685     if ( pname )
686         pkrb5_free_unparsed_name(ctx,pname);
687     if ( principal )
688         pkrb5_free_principal(ctx,principal);
689 }   
690
691 int
692 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
693 {
694     struct principal_ccache_data * next = princ_cc_data;
695     char * response = NULL;
696
697     if ( !principal || !ccache )
698         return 0;
699
700     while ( next ) {
701         if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
702             if (response) {
703                 // we always want to prefer the MS Kerberos LSA cache or
704                 // the cache afscreds created specifically for the principal
705                 // if the current entry is either one, drop the previous find
706                 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
707                     free(response);
708             }
709             response = _strdup(next->ccache_name);
710             // MS Kerberos LSA is our best option so use it and quit
711             if ( next->from_lsa )   
712                 break;
713         }
714         next = next->next;
715     }
716
717     if ( response ) {
718         *ccache = response;
719         return 1;
720     }
721     return 0;
722 }
723
724 void 
725 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
726 {
727     struct principal_ccache_data ** next = &princ_cc_data;
728
729     if ( !pname && !ccname )
730         return;
731
732     while ( (*next) ) {
733         if ( !strcmp((*next)->principal,pname) || 
734              !strcmp((*next)->ccache_name,ccname) ) {
735             void * temp;
736             free((*next)->principal);
737             free((*next)->ccache_name);
738             temp = (*next);
739             (*next) = (*next)->next;
740             free(temp);
741         }
742     }
743 }
744
745 void 
746 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
747 {
748     struct cell_principal_map * next = cell_princ_map;
749
750     // Search the existing list to see if we have a match 
751     if ( next ) {
752         for ( ; next ; next = next->next ) {
753             if ( !strcmp(next->cell, cell) ) {
754                 if ( !strcmp(next->principal,pname) ) {
755                     next->active = active;
756                                         break;
757                 } else {
758                     // OpenAFS currently has a restriction of one active token per cell
759                     // Therefore, whenever we update the table with a new active cell we
760                     // must mark all of the other principal to cell entries as inactive.
761                     if (active)
762                         next->active = 0;
763                 }
764             }
765         }
766     } 
767
768     // If not, match add a new node to the beginning of the list and assign init it
769     if ( !next ) {
770         next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
771         next->next = cell_princ_map;
772         cell_princ_map = next;
773         next->principal = _strdup(pname);
774         next->cell = _strdup(cell);
775         next->active = active;
776     }
777 }
778
779 void 
780 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
781 {
782     struct cell_principal_map ** next = &cell_princ_map;
783
784     if ( !pname && !cell )
785         return;
786
787     while ( (*next) ) {
788         if ( !strcmp((*next)->principal,pname) || 
789              !strcmp((*next)->cell,cell) ) {
790             void * temp;
791             free((*next)->principal);
792             free((*next)->cell);
793             temp = (*next);
794             (*next) = (*next)->next;
795             free(temp);
796         }
797     }
798 }
799
800 // Returns (if possible) a principal which has been known in 
801 // the past to have been used to obtain tokens for the specified
802 // cell.  
803 // TODO: Attempt to return one which has not yet expired by checking
804 // the principal/ccache data
805 int
806 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
807 {
808     struct cell_principal_map * next_map = cell_princ_map;
809     const char * princ = NULL;
810     int count = 0, i;
811
812     if ( !cell )
813         return 0;
814
815     while ( next_map ) {
816         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
817             count++;
818         }
819         next_map = next_map->next;
820     }
821
822     if ( !principals || !count )
823         return count;
824
825     *principals = (char **) malloc(sizeof(char *) * count);
826     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
827     {
828         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
829             (*principals)[i++] = _strdup(next_map->principal);
830         }
831     }
832     return count;
833 }
834
835 int
836 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
837 {
838     int     count = 0, i;
839     struct cell_principal_map * next_map = cell_princ_map;
840     const char * princ = NULL;
841     
842     if ( !pname )
843         return 0;
844
845     while ( next_map ) {
846         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
847             count++;
848         }
849         next_map = next_map->next;
850     }
851
852     if ( !cells )
853         return count;
854
855     *cells = (char **) malloc(sizeof(char *) * count);
856     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
857     {
858         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
859             (*cells)[i++] = _strdup(next_map->cell);
860         }
861     }
862     return count;
863 }
864
865 /* Given a principal return an existing ccache or create one and return */
866 int
867 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
868 {
869     krb5_context ctx;
870     char * pname = 0;
871     char * ccname = 0;
872     krb5_error_code code;
873
874     if (!pkrb5_init_context)
875         return 0;
876
877     if ( alt_ctx ) {
878         ctx = alt_ctx;
879     } else {
880         code = pkrb5_init_context(&ctx);
881         if (code) goto cleanup;
882     }
883
884     if ( principal ) {
885         code = pkrb5_unparse_name(ctx, principal, &pname);
886         if (code) goto cleanup;
887
888         if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
889              !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
890             ccname = (char *)malloc(strlen(pname) + 5);
891             sprintf(ccname,"API:%s",pname);
892         }
893         code = pkrb5_cc_resolve(ctx, ccname, cc);
894     } else {
895         code = pkrb5_cc_default(ctx, cc);
896         if (code) goto cleanup;
897     }
898
899   cleanup:
900     if (ccname)
901         free(ccname);
902     if (pname)
903         pkrb5_free_unparsed_name(ctx,pname);
904     if (ctx && (ctx != alt_ctx))
905         pkrb5_free_context(ctx);
906     return(code);
907 }
908
909 #ifdef USE_MS2MIT
910 // Import Microsoft Credentials into a new MIT ccache
911 void
912 KFW_import_windows_lsa(void)
913 {
914     krb5_context ctx = 0;
915     krb5_ccache  cc = 0;
916     krb5_principal princ = 0;
917     char * pname = NULL;
918     krb5_data *  princ_realm;
919     krb5_error_code code;
920     char cell[128]="", realm[128]="", *def_realm = 0;
921     int i;
922     DWORD dwMsLsaImport;
923          
924     if (!pkrb5_init_context)
925         return;
926
927 #ifdef COMMENT
928     if ( !MSLSA_IsKerberosLogon() )
929         return;
930 #endif
931
932     code = pkrb5_init_context(&ctx);
933     if (code) goto cleanup;
934
935     code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
936     if (code) goto cleanup;
937
938     KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
939
940     code = pkrb5_cc_get_principal(ctx, cc, &princ);
941     if ( code ) goto cleanup;
942
943     dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
944     switch ( dwMsLsaImport ) {
945     case 0: /* do not import */
946         goto cleanup;
947     case 1: /* always import */
948         break;
949     case 2: { /* matching realm */
950         char ms_realm[128] = "", *r;
951         int i;
952
953         for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
954             *r = krb5_princ_realm(ctx, princ)->data[i];
955         }
956         *r = '\0';
957
958         if (code = pkrb5_get_default_realm(ctx, &def_realm))
959             goto cleanup;
960
961         if (strcmp(def_realm, ms_realm))
962             goto cleanup;
963         break;
964     }
965     default:
966         break;
967     }
968
969     code = pkrb5_unparse_name(ctx,princ,&pname);
970     if ( code ) goto cleanup;
971
972     princ_realm = krb5_princ_realm(ctx, princ);
973     for ( i=0; i<princ_realm->length; i++ ) {
974         realm[i] = princ_realm->data[i];
975         cell[i] = tolower(princ_realm->data[i]);
976     }
977     cell[i] = '\0';
978     realm[i] = '\0';
979
980     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
981     if ( IsDebuggerPresent() ) {
982         char message[256];
983         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
984         OutputDebugString(message);
985     }
986     if ( code ) goto cleanup;
987
988     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
989
990   cleanup:
991     if (pname)
992         pkrb5_free_unparsed_name(ctx,pname);
993     if (princ)
994         pkrb5_free_principal(ctx,princ);
995     if (def_realm)
996         pkrb5_free_default_realm(ctx, def_realm);
997     if (cc)
998         pkrb5_cc_close(ctx,cc);
999     if (ctx)
1000         pkrb5_free_context(ctx);
1001 }
1002 #endif /* USE_MS2MIT */
1003
1004 // If there are existing MIT credentials, copy them to a new
1005 // ccache named after the principal
1006
1007 // Enumerate all existing MIT ccaches and construct entries
1008 // in the principal_ccache table
1009
1010 // Enumerate all existing AFS Tokens and construct entries
1011 // in the cell_principal table
1012 void
1013 KFW_import_ccache_data(void)
1014 {
1015     krb5_context ctx = 0;
1016     krb5_ccache  cc = 0;
1017     krb5_principal principal = 0;
1018     krb5_creds creds;
1019     krb5_error_code code;
1020     krb5_error_code cc_code;
1021     krb5_cc_cursor cur;
1022     apiCB * cc_ctx = 0;
1023     struct _infoNC ** pNCi = NULL;
1024     int i, j, flags;
1025
1026     if ( !pcc_initialize )
1027         return;
1028
1029     if ( IsDebuggerPresent() )
1030         OutputDebugString("KFW_import_ccache_data()\n");
1031
1032     code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1033     if (code) goto cleanup;
1034
1035     code = pcc_get_NC_info(cc_ctx, &pNCi);
1036     if (code) goto cleanup;
1037
1038     code = pkrb5_init_context(&ctx);
1039     if (code) goto cleanup;
1040
1041     for ( i=0; pNCi[i]; i++ ) {
1042         if ( pNCi[i]->vers != CC_CRED_V5 )
1043             continue;
1044         if ( IsDebuggerPresent() ) {
1045             OutputDebugString("Principal: ");
1046             OutputDebugString(pNCi[i]->principal);
1047             OutputDebugString(" in ccache ");
1048             OutputDebugString(pNCi[i]->name);
1049             OutputDebugString("\n");
1050         }
1051         if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1052              && strcmp(pNCi[i]->name,LSA_CCNAME) 
1053              ) {
1054             int found = 0;
1055             for ( j=0; pNCi[j]; j++ ) {
1056                 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1057                     found = 1;
1058                     break;
1059                 }
1060             }
1061             
1062             code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1063             if (code) goto loop_cleanup;
1064
1065             if (!found) {
1066                 krb5_ccache oldcc = 0;
1067
1068                 if ( IsDebuggerPresent() )
1069                     OutputDebugString("copying ccache data to new ccache\n");
1070
1071                 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1072                 if (code) goto loop_cleanup;
1073                 code = pkrb5_cc_initialize(ctx, cc, principal);
1074                 if (code) goto loop_cleanup;
1075
1076                 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1077                 if (code) goto loop_cleanup;
1078                 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1079                 if (code) {
1080                     code = pkrb5_cc_close(ctx,cc);
1081                     cc = 0;
1082                     code = pkrb5_cc_close(ctx,oldcc);
1083                     oldcc = 0;
1084                     KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1085                     continue;
1086                 }
1087                 code = pkrb5_cc_close(ctx,oldcc);
1088             }
1089         } else {
1090             code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1091             if (code) goto loop_cleanup;
1092         }
1093
1094         flags = 0;  // turn off OPENCLOSE mode
1095         code = pkrb5_cc_set_flags(ctx, cc, flags);
1096         if ( code ) goto cleanup;
1097
1098         KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1099
1100         cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1101
1102         while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1103             krb5_data * sname = krb5_princ_name(ctx, creds.server);
1104             krb5_data * cell  = krb5_princ_component(ctx, creds.server, 1);
1105             krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1106             if ( sname && cell && !strcmp("afs",sname->data) ) {
1107                 struct ktc_principal    aserver;
1108                 struct ktc_principal    aclient;
1109                 struct ktc_token        atoken;
1110                 int active = TRUE;
1111
1112                 if ( IsDebuggerPresent() )  {
1113                     OutputDebugString("Found AFS ticket: ");
1114                     OutputDebugString(sname->data);
1115                     if ( cell->data ) {
1116                         OutputDebugString("/");
1117                         OutputDebugString(cell->data);
1118                     }
1119                     OutputDebugString("@");
1120                     OutputDebugString(realm->data);
1121                     OutputDebugString("\n");
1122                 }
1123
1124                 memset(&aserver, '\0', sizeof(aserver));
1125                 strcpy(aserver.name, sname->data);
1126                 strcpy(aserver.cell, cell->data);
1127
1128                 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1129                 if (!code) {
1130                     // Found a token in AFS Client Server which matches
1131                     char pname[128], *p, *q;
1132                     for ( p=pname, q=aclient.name; *q; p++, q++)
1133                         *p = *q;
1134                     for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1135                         *p = toupper(*q);
1136                     *p = '\0';
1137
1138                     if ( IsDebuggerPresent() )  {
1139                         OutputDebugString("Found AFS token: ");
1140                         OutputDebugString(pname);
1141                         OutputDebugString("\n");
1142                     }
1143
1144                     if ( strcmp(pname,pNCi[i]->principal)  )
1145                         active = FALSE;
1146                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1147                 } else {
1148                     // Attempt to import it
1149                     KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1150
1151                     if ( IsDebuggerPresent() )  {
1152                         OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1153                     }
1154
1155                     code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL);
1156                     if ( IsDebuggerPresent() ) {
1157                         char message[256];
1158                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1159                         OutputDebugString(message);
1160                     }
1161                 }
1162             } else if ( IsDebuggerPresent() ) {
1163                 OutputDebugString("Found ticket: ");
1164                 OutputDebugString(sname->data);
1165                 if ( cell && cell->data ) {
1166                     OutputDebugString("/");
1167                     OutputDebugString(cell->data);
1168                 }
1169                 OutputDebugString("@");
1170                 OutputDebugString(realm->data);
1171                 OutputDebugString("\n");
1172             }
1173             pkrb5_free_cred_contents(ctx, &creds);
1174         }
1175
1176         if (cc_code == KRB5_CC_END) {
1177             cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1178             if (cc_code) goto loop_cleanup;
1179         }
1180
1181       loop_cleanup:
1182         flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
1183         code = pkrb5_cc_set_flags(ctx, cc, flags);
1184         if (cc) {
1185             pkrb5_cc_close(ctx,cc);
1186             cc = 0;
1187         }
1188         if (principal) {
1189             pkrb5_free_principal(ctx,principal);
1190             principal = 0;
1191         }
1192     }
1193
1194   cleanup:
1195     if (ctx)
1196         pkrb5_free_context(ctx);
1197     if (pNCi)
1198         pcc_free_NC_info(cc_ctx, &pNCi);
1199     if (cc_ctx)
1200         pcc_shutdown(&cc_ctx);
1201 }
1202
1203
1204 int
1205 KFW_AFS_get_cred( char * username, 
1206                   char * cell,
1207                   char * password,
1208                   int lifetime,
1209                   char * smbname,
1210                   char ** reasonP )
1211 {
1212     krb5_context ctx = 0;
1213     krb5_ccache cc = 0;
1214     char * realm = 0, * userrealm = 0;
1215     krb5_principal principal = 0;
1216     char * pname = 0;
1217     krb5_error_code code;
1218         char local_cell[MAXCELLCHARS+1];
1219     char **cells = NULL;
1220     int  cell_count=0;
1221     struct afsconf_cell cellconfig;
1222     char * dot;
1223
1224
1225     if (!pkrb5_init_context)
1226         return 0;
1227
1228     if ( IsDebuggerPresent() ) {
1229         OutputDebugString("KFW_AFS_get_cred for token ");
1230         OutputDebugString(username);
1231         OutputDebugString(" in cell ");
1232         OutputDebugString(cell);
1233         OutputDebugString("\n");
1234     }
1235
1236     code = pkrb5_init_context(&ctx);
1237     if ( code ) goto cleanup;
1238
1239     code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1240     if ( code ) goto cleanup;
1241
1242     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1243
1244     userrealm = strchr(username,'@');
1245     if ( userrealm ) {
1246         pname = strdup(username);
1247         userrealm = strchr(pname, '@');
1248         *userrealm = '\0';
1249
1250         /* handle kerberos iv notation */
1251         while ( dot = strchr(pname,'.') ) {
1252             *dot = '/';
1253         }
1254         *userrealm++ = '@';
1255     } else {
1256         pname = malloc(strlen(username) + strlen(realm) + 2);
1257
1258         strcpy(pname, username);
1259
1260         /* handle kerberos iv notation */
1261         while ( dot = strchr(pname,'.') ) {
1262             *dot = '/';
1263         }
1264
1265         strcat(pname,"@");
1266         strcat(pname,realm);
1267     }
1268     if ( IsDebuggerPresent() ) {
1269         OutputDebugString("Realm: ");
1270         OutputDebugString(realm);
1271         OutputDebugString("\n");
1272     }
1273
1274     code = pkrb5_parse_name(ctx, pname, &principal);
1275     if ( code ) goto cleanup;
1276
1277     code = KFW_get_ccache(ctx, principal, &cc);
1278     if ( code ) goto cleanup;
1279
1280     if ( lifetime == 0 )
1281         lifetime = pLeash_get_default_lifetime();
1282
1283     if ( password && password[0] ) {
1284         code = KFW_kinit( ctx, cc, HWND_DESKTOP, 
1285                           pname, 
1286                           password,
1287                           lifetime,
1288                           pLeash_get_default_forwardable(),
1289                           pLeash_get_default_proxiable(),
1290                           pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1291                           pLeash_get_default_noaddresses(),
1292                           pLeash_get_default_publicip());
1293         if ( IsDebuggerPresent() ) {
1294             char message[256];
1295             sprintf(message,"KFW_kinit() returns: %d\n",code);
1296             OutputDebugString(message);
1297         }
1298         if ( code ) goto cleanup;
1299
1300         KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1301     }
1302
1303     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime,smbname);
1304     if ( IsDebuggerPresent() ) {
1305         char message[256];
1306         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1307         OutputDebugString(message);
1308     }
1309     if ( code ) goto cleanup;
1310
1311     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1312
1313     // Attempt to obtain new tokens for other cells supported by the same 
1314     // principal
1315     cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1316     if ( cell_count > 1 ) {
1317         while ( cell_count-- ) {
1318             if ( strcmp(cells[cell_count],cell) ) {
1319                 if ( IsDebuggerPresent() ) {
1320                     char message[256];
1321                     sprintf(message,"found another cell for the same principal: %s\n",cell);
1322                     OutputDebugString(message);
1323                 }
1324                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1325                 if ( code ) continue;
1326     
1327                 realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1328                 if ( IsDebuggerPresent() ) {
1329                     OutputDebugString("Realm: ");
1330                     OutputDebugString(realm);
1331                     OutputDebugString("\n");
1332                 }
1333                 
1334                 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime,smbname);
1335                 if ( IsDebuggerPresent() ) {
1336                     char message[256];
1337                     sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1338                     OutputDebugString(message);
1339                 }
1340             }
1341             free(cells[cell_count]);
1342         }
1343         free(cells);
1344     } else if ( cell_count == 1 ) {
1345         free(cells[0]);
1346         free(cells);
1347     }
1348
1349   cleanup:
1350     if ( pname )
1351         free(pname);
1352     if ( cc )
1353         pkrb5_cc_close(ctx, cc);
1354
1355     if ( code && reasonP ) {
1356         *reasonP = (char *)perror_message(code);
1357     }
1358     return(code);
1359 }
1360
1361 int 
1362 KFW_AFS_destroy_tickets_for_cell(char * cell)
1363 {
1364     krb5_context                ctx = 0;
1365     krb5_error_code             code;
1366     int count;
1367     char ** principals = NULL;
1368
1369     if (!pkrb5_init_context)
1370         return 0;
1371
1372     if ( IsDebuggerPresent() ) {
1373         OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1374         OutputDebugString(cell);
1375         OutputDebugString("\n");
1376     }
1377
1378     code = pkrb5_init_context(&ctx);
1379     if (code) ctx = 0;
1380
1381     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1382     if ( count > 0 ) {
1383         krb5_principal      princ = 0;
1384         krb5_ccache                     cc  = 0;
1385
1386         while ( count-- ) {
1387             int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1388             if ( cell_count > 1 ) {
1389                 // TODO - What we really should do here is verify whether or not any of the
1390                 // other cells which use this principal to obtain its credentials actually
1391                 // have valid tokens or not.  If they are currently using these credentials
1392                 // we will skip them.  For the time being we assume that if there is an active
1393                 // map in the table that they are actively being used.
1394                 goto loop_cleanup;
1395             }
1396
1397             code = pkrb5_parse_name(ctx, principals[count], &princ);
1398             if (code) goto loop_cleanup;
1399
1400             code = KFW_get_ccache(ctx, princ, &cc);
1401             if (code) goto loop_cleanup;
1402
1403             code = pkrb5_cc_destroy(ctx, cc);
1404             if (!code) cc = 0;
1405
1406           loop_cleanup:
1407             if ( cc ) {
1408                 pkrb5_cc_close(ctx, cc);
1409                 cc = 0;
1410             }
1411             if ( princ ) {
1412                 pkrb5_free_principal(ctx, princ);
1413                 princ = 0;
1414             }
1415
1416             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1417             free(principals[count]);
1418         }
1419         free(principals);
1420     }
1421     pkrb5_free_context(ctx);
1422     return 0;
1423 }
1424
1425 int 
1426 KFW_AFS_destroy_tickets_for_principal(char * user)
1427 {
1428     krb5_context                ctx = 0;
1429     krb5_error_code             code;
1430     int count;
1431     char ** cells = NULL;
1432     krb5_principal      princ = 0;
1433     krb5_ccache                 cc  = 0;
1434
1435     if (!pkrb5_init_context)
1436         return 0;
1437
1438     if ( IsDebuggerPresent() ) {
1439         OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1440         OutputDebugString(user);
1441         OutputDebugString("\n");
1442     }
1443
1444     code = pkrb5_init_context(&ctx);
1445     if (code) ctx = 0;
1446
1447     code = pkrb5_parse_name(ctx, user, &princ);
1448     if (code) goto loop_cleanup;
1449
1450     code = KFW_get_ccache(ctx, princ, &cc);
1451     if (code) goto loop_cleanup;
1452
1453     code = pkrb5_cc_destroy(ctx, cc);
1454     if (!code) cc = 0;
1455
1456   loop_cleanup:
1457     if ( cc ) {
1458         pkrb5_cc_close(ctx, cc);
1459         cc = 0;
1460     }
1461     if ( princ ) {
1462         pkrb5_free_principal(ctx, princ);
1463         princ = 0;
1464     }
1465
1466     count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1467     if ( count >= 1 ) {
1468         while ( count-- ) {
1469             KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1470             free(cells[count]);
1471         }
1472         free(cells);
1473     }
1474
1475     pkrb5_free_context(ctx);
1476     return 0;
1477 }
1478
1479 int
1480 KFW_AFS_renew_expiring_tokens(void)
1481 {
1482     krb5_error_code                     code = 0;
1483     krb5_context                        ctx = 0;
1484     krb5_ccache                         cc = 0;
1485     krb5_timestamp now;
1486     struct principal_ccache_data * pcc_next = princ_cc_data;
1487     int cell_count;
1488     char ** cells=NULL;
1489     const char * realm = NULL;
1490     char local_cell[MAXCELLCHARS+1]="";
1491     struct afsconf_cell cellconfig;
1492
1493     if (!pkrb5_init_context)
1494         return 0;
1495
1496     if ( pcc_next == NULL ) // nothing to do
1497         return 0;
1498
1499     if ( IsDebuggerPresent() ) {
1500         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1501     }
1502
1503     code = pkrb5_init_context(&ctx);
1504     if (code) goto cleanup;
1505
1506     code = pkrb5_timeofday(ctx, &now);
1507     if (code) goto cleanup; 
1508
1509     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1510         if ( pcc_next->expired ) 
1511             continue;
1512
1513         if ( now >= (pcc_next->expiration_time) ) {
1514             if ( !pcc_next->from_lsa ) {
1515                 pcc_next->expired = 1;
1516                 continue;
1517             }
1518         }
1519
1520         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1521             code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1522             if ( code ) 
1523                                 goto loop_cleanup;
1524             code = KFW_renew(ctx,cc);
1525 #ifdef USE_MS2MIT
1526             if ( code && pcc_next->from_lsa)
1527                 goto loop_cleanup;
1528 #endif /* USE_MS2MIT */
1529
1530
1531             KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1532             if (code) goto loop_cleanup;
1533
1534             // Attempt to obtain new tokens for other cells supported by the same 
1535             // principal
1536             cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1537             if ( cell_count > 0 ) {
1538                 while ( cell_count-- ) {
1539                     if ( IsDebuggerPresent() ) {
1540                         OutputDebugString("Cell: ");
1541                         OutputDebugString(cells[cell_count]);
1542                         OutputDebugString("\n");
1543                     }
1544                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1545                     if ( code ) continue;
1546                     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1547                     if ( IsDebuggerPresent() ) {
1548                         OutputDebugString("Realm: ");
1549                         OutputDebugString(realm);
1550                         OutputDebugString("\n");
1551                     }
1552                     code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime(),NULL);
1553                     if ( IsDebuggerPresent() ) {
1554                         char message[256];
1555                         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1556                         OutputDebugString(message);
1557                     }
1558                     free(cells[cell_count]);
1559                 }
1560                 free(cells);
1561             }
1562         }
1563
1564       loop_cleanup:
1565         if ( cc ) {
1566             pkrb5_cc_close(ctx,cc);
1567             cc = 0;
1568         }
1569     }
1570
1571   cleanup:
1572     if ( cc )
1573         pkrb5_cc_close(ctx,cc);
1574     if ( ctx )
1575         pkrb5_free_context(ctx);
1576
1577     return 0;
1578 }
1579
1580
1581 BOOL
1582 KFW_AFS_renew_token_for_cell(char * cell)
1583 {
1584     krb5_error_code                     code = 0;
1585     krb5_context                        ctx = 0;
1586     int count;
1587     char ** principals = NULL;
1588
1589     if (!pkrb5_init_context)
1590         return 0;
1591
1592     if ( IsDebuggerPresent() ) {
1593         OutputDebugString("KFW_AFS_renew_token_for_cell:");
1594         OutputDebugString(cell);
1595         OutputDebugString("\n");
1596     }
1597
1598     code = pkrb5_init_context(&ctx);
1599     if (code) goto cleanup;
1600
1601     count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1602     if ( count == 0 ) {
1603         // We know we must have a credential somewhere since we are
1604         // trying to renew a token
1605
1606         KFW_import_ccache_data();
1607         count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1608     }
1609     if ( count > 0 ) {
1610         krb5_principal      princ = 0;
1611         krb5_principal      service = 0;
1612 #ifdef COMMENT
1613         krb5_creds          mcreds, creds;
1614 #endif /* COMMENT */
1615         krb5_ccache                     cc  = 0;
1616         const char * realm = NULL;
1617         struct afsconf_cell cellconfig;
1618         char local_cell[MAXCELLCHARS+1];
1619
1620         while ( count-- ) {
1621             code = pkrb5_parse_name(ctx, principals[count], &princ);
1622             if (code) goto loop_cleanup;
1623
1624             code = KFW_get_ccache(ctx, princ, &cc);
1625             if (code) goto loop_cleanup;
1626
1627             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1628             if ( code ) goto loop_cleanup;
1629
1630             realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
1631             if ( IsDebuggerPresent() ) {
1632                 OutputDebugString("Realm: ");
1633                 OutputDebugString(realm);
1634                 OutputDebugString("\n");
1635             }
1636
1637 #ifdef COMMENT
1638             /* krb5_cc_remove_cred() is not implemented 
1639              * for a single cred 
1640              */
1641             code = pkrb5_build_principal(ctx, &service, strlen(realm),
1642                                           realm, "afs", cell, NULL);
1643             if (!code) {
1644                 memset(&mcreds, 0, sizeof(krb5_creds));
1645                 mcreds.client = princ;
1646                 mcreds.server = service;
1647
1648                 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1649                 if (!code) {
1650                     if ( IsDebuggerPresent() ) {
1651                         char * cname, *sname;
1652                         pkrb5_unparse_name(ctx, creds.client, &cname);
1653                         pkrb5_unparse_name(ctx, creds.server, &sname);
1654                         OutputDebugString("Removing credential for client \"");
1655                         OutputDebugString(cname);
1656                         OutputDebugString("\" and service \"");
1657                         OutputDebugString(sname);
1658                         OutputDebugString("\"\n");
1659                         pkrb5_free_unparsed_name(ctx,cname);
1660                         pkrb5_free_unparsed_name(ctx,sname);
1661                     }
1662
1663                     code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1664                     pkrb5_free_principal(ctx, creds.client);
1665                     pkrb5_free_principal(ctx, creds.server);
1666                 }
1667             }
1668 #endif /* COMMENT */
1669
1670             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime(),NULL);
1671             if ( IsDebuggerPresent() ) {
1672                 char message[256];
1673                 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1674                 OutputDebugString(message);
1675             }
1676
1677           loop_cleanup:
1678             if (cc) {
1679                 pkrb5_cc_close(ctx, cc);
1680                 cc = 0;
1681             }
1682             if (princ) {
1683                 pkrb5_free_principal(ctx, princ);
1684                 princ = 0;
1685             }
1686             if (service) {
1687                 pkrb5_free_principal(ctx, service);
1688                 princ = 0;
1689             }
1690
1691             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1692             free(principals[count]);
1693         }
1694         free(principals);
1695     } else
1696         code = -1;      // we did not renew the tokens 
1697
1698   cleanup:
1699     pkrb5_free_context(ctx);
1700     return (code ? FALSE : TRUE);
1701
1702 }
1703
1704 int
1705 KFW_AFS_renew_tokens_for_all_cells(void)
1706 {
1707     struct cell_principal_map * next = cell_princ_map;
1708
1709     if ( IsDebuggerPresent() )
1710         OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1711
1712     if ( !next )
1713         return 0;
1714
1715     for ( ; next ; next = next->next ) {
1716         if ( next->active )
1717             KFW_AFS_renew_token_for_cell(next->cell);
1718     }
1719     return 0;
1720 }
1721
1722 int
1723 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1724 {
1725     krb5_error_code                     code = 0;
1726     krb5_context                        ctx = 0;
1727     krb5_ccache                         cc = 0;
1728     krb5_principal                      me = 0;
1729     krb5_principal              server = 0;
1730     krb5_creds                          my_creds;
1731     krb5_data                   *realm = 0;
1732
1733     if (!pkrb5_init_context)
1734         return 0;
1735
1736         memset(&my_creds, 0, sizeof(krb5_creds));
1737
1738     if ( alt_ctx ) {
1739         ctx = alt_ctx;
1740     } else {
1741         code = pkrb5_init_context(&ctx);
1742         if (code) goto cleanup;
1743     }
1744
1745     if ( alt_cc ) {
1746         cc = alt_cc;
1747     } else {
1748         code = pkrb5_cc_default(ctx, &cc);
1749         if (code) goto cleanup;
1750     }
1751
1752     code = pkrb5_cc_get_principal(ctx, cc, &me);
1753     if (code) goto cleanup;
1754
1755     realm = krb5_princ_realm(ctx, me);
1756
1757     code = pkrb5_build_principal_ext(ctx, &server,
1758                                     realm->length,realm->data,
1759                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1760                                     realm->length,realm->data,
1761                                     0);
1762     if ( code ) 
1763         goto cleanup;
1764
1765     if ( IsDebuggerPresent() ) {
1766         char * cname, *sname;
1767         pkrb5_unparse_name(ctx, me, &cname);
1768         pkrb5_unparse_name(ctx, server, &sname);
1769         OutputDebugString("Renewing credential for client \"");
1770         OutputDebugString(cname);
1771         OutputDebugString("\" and service \"");
1772         OutputDebugString(sname);
1773         OutputDebugString("\"\n");
1774         pkrb5_free_unparsed_name(ctx,cname);
1775         pkrb5_free_unparsed_name(ctx,sname);
1776     }
1777
1778     my_creds.client = me;
1779     my_creds.server = server;
1780
1781     code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1782     if (code) {
1783         if ( IsDebuggerPresent() ) {
1784             char message[256];
1785             sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1786             OutputDebugString(message);
1787         }
1788         goto cleanup;
1789     }
1790
1791     code = pkrb5_cc_initialize(ctx, cc, me);
1792     if (code) {
1793         if ( IsDebuggerPresent() ) {
1794             char message[256];
1795             sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1796             OutputDebugString(message);
1797         }
1798         goto cleanup;
1799     }
1800
1801     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1802     if (code) {
1803         if ( IsDebuggerPresent() ) {
1804             char message[256];
1805             sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1806             OutputDebugString(message);
1807         }
1808         goto cleanup;
1809     }
1810
1811   cleanup:
1812     if (my_creds.client == me)
1813         my_creds.client = 0;
1814     if (my_creds.server == server)
1815         my_creds.server = 0;
1816     pkrb5_free_cred_contents(ctx, &my_creds);
1817     if (me)
1818         pkrb5_free_principal(ctx, me);
1819     if (server)
1820         pkrb5_free_principal(ctx, server);
1821     if (cc && (cc != alt_cc))
1822         pkrb5_cc_close(ctx, cc);
1823     if (ctx && (ctx != alt_ctx))
1824         pkrb5_free_context(ctx);
1825     return(code);
1826 }
1827
1828 int
1829 KFW_kinit( krb5_context alt_ctx,
1830             krb5_ccache  alt_cc,
1831             HWND hParent,
1832             char *principal_name,
1833             char *password,
1834             krb5_deltat lifetime,
1835             DWORD                       forwardable,
1836             DWORD                       proxiable,
1837             krb5_deltat                 renew_life,
1838             DWORD                       addressless,
1839             DWORD                       publicIP
1840             )
1841 {
1842     krb5_error_code                     code = 0;
1843     krb5_context                        ctx = 0;
1844     krb5_ccache                         cc = 0;
1845     krb5_principal                      me = 0;
1846     char*                       name = 0;
1847     krb5_creds                          my_creds;
1848     krb5_get_init_creds_opt     options;
1849     krb5_address **             addrs = NULL;
1850     int                         i = 0, addr_count = 0;
1851
1852     if (!pkrb5_init_context)
1853         return 0;
1854
1855     pkrb5_get_init_creds_opt_init(&options);
1856     memset(&my_creds, 0, sizeof(my_creds));
1857
1858     if (alt_ctx)
1859     {
1860         ctx = alt_ctx;
1861     }
1862     else
1863     {
1864         code = pkrb5_init_context(&ctx);
1865         if (code) goto cleanup;
1866     }
1867
1868     if ( alt_cc ) {
1869         cc = alt_cc;
1870     } else {
1871         code = pkrb5_cc_default(ctx, &cc);  
1872         if (code) goto cleanup;
1873     }
1874
1875     code = pkrb5_parse_name(ctx, principal_name, &me);
1876     if (code) 
1877                 goto cleanup;
1878
1879     code = pkrb5_unparse_name(ctx, me, &name);
1880     if (code) 
1881                 goto cleanup;
1882
1883     if (lifetime == 0)
1884         lifetime = pLeash_get_default_lifetime();
1885     else
1886         lifetime *= 5*60;
1887
1888         if (renew_life > 0)
1889                 renew_life *= 5*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 ul;
2154
2155     ul = (ULONG) 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 = 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         if ( pwid < strlen(tb[i].label) )
2286             pwid = strlen(tb[i].label);
2287     }
2288
2289     for ( i=0; i<tb_cnt; i++) {
2290         /* Prompt */
2291         /*-----------------------
2292          * Define a static text control.
2293          *-----------------------*/
2294         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2295         lpdit = (LPDLGITEMTEMPLATE) lpw;
2296         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2297         lpdit->dwExtendedStyle = 0;
2298         lpdit->x  = 10; 
2299         lpdit->y  = 10 + (numlines + i + 1) * 14;
2300         lpdit->cx = pwid * 4; 
2301         lpdit->cy = 14;
2302         lpdit->id = ID_TEXT + numlines + i;  // text identifier
2303
2304         lpw = (LPWORD) (lpdit + 1);
2305         *lpw++ = 0xFFFF;
2306         *lpw++ = 0x0082;                         // static class
2307
2308         lpwsz = (LPWSTR) lpw;
2309         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 
2310                                      -1, lpwsz, 128);
2311         lpw   += nchar;
2312         *lpw++ = 0;           // no creation data
2313
2314         /*-----------------------
2315          * Define an edit control.
2316          *-----------------------*/
2317         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2318         lpdit = (LPDLGITEMTEMPLATE) lpw;
2319         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2320         lpdit->dwExtendedStyle = 0;
2321         lpdit->x  = 10 + (pwid + 1) * 4; 
2322         lpdit->y  = 10 + (numlines + i + 1) * 14;
2323         lpdit->cx = (width - (pwid + 1)) * 4; 
2324         lpdit->cy = 14;
2325         lpdit->id = ID_MID_TEXT + i;             // identifier
2326
2327         lpw = (LPWORD) (lpdit + 1);
2328         *lpw++ = 0xFFFF;
2329         *lpw++ = 0x0081;                         // edit class
2330
2331         lpwsz = (LPWSTR) lpw;
2332         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 
2333                                      -1, lpwsz, 128);
2334         lpw   += nchar;
2335         *lpw++ = 0;           // no creation data
2336     }
2337
2338     GlobalUnlock(hgbl); 
2339     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
2340                                                         hwndOwner, (DLGPROC) MultiInputDialogProc); 
2341     GlobalFree(hgbl); 
2342
2343     switch ( ret ) {
2344     case 0:     /* Timeout */
2345         return -1;
2346     case IDOK:
2347         return 1;
2348     case IDCANCEL:
2349         return 0;
2350     default: {
2351         char buf[256];
2352         sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2353         MessageBox(hwndOwner,
2354                     buf,
2355                     "GetLastError()",
2356                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2357         return -1;
2358     }
2359     }
2360 }
2361
2362 static int
2363 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2364 {
2365         HINSTANCE hInst = 0;
2366     int maxwidth = 0;
2367     int numlines = 0;
2368     int len;
2369     char * plines[16], *p = preface ? preface : "";
2370     int i;
2371
2372     for ( i=0; i<16; i++ ) 
2373         plines[i] = NULL;
2374
2375     while (*p && numlines < 16) {
2376         plines[numlines++] = p;
2377         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2378         if ( *p == '\r' && *(p+1) == '\n' ) {
2379             *p++ = '\0';
2380             p++;
2381         } else if ( *p == '\n' ) {
2382             *p++ = '\0';
2383         } 
2384         if ( strlen(plines[numlines-1]) > maxwidth )
2385             maxwidth = strlen(plines[numlines-1]);
2386     }
2387
2388     for ( i=0;i<n;i++ ) {
2389         len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2390         if ( maxwidth < len )
2391             maxwidth = len;
2392     }
2393
2394     return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2395 }
2396
2397 static krb5_error_code KRB5_CALLCONV
2398 KRB5_prompter( krb5_context context,
2399                void *data,
2400                const char *name,
2401                const char *banner,
2402                int num_prompts,
2403                krb5_prompt prompts[])
2404 {
2405     krb5_error_code     errcode = 0;
2406     int                 i;
2407     struct textField * tb = NULL;
2408     int    len = 0, blen=0, nlen=0;
2409         HWND hParent = (HWND)data;
2410
2411     if (name)
2412         nlen = strlen(name)+2;
2413
2414     if (banner)
2415         blen = strlen(banner)+2;
2416
2417     tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2418     if ( tb != NULL ) {
2419         int ok;
2420         memset(tb,0,sizeof(struct textField) * num_prompts);
2421         for ( i=0; i < num_prompts; i++ ) {
2422             tb[i].buf = prompts[i].reply->data;
2423             tb[i].len = prompts[i].reply->length;
2424             tb[i].label = prompts[i].prompt;
2425             tb[i].def = NULL;
2426             tb[i].echo = (prompts[i].hidden ? 2 : 1);
2427         }   
2428
2429         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2430         if ( ok ) {
2431             for ( i=0; i < num_prompts; i++ )
2432                 prompts[i].reply->length = strlen(prompts[i].reply->data);
2433         } else
2434             errcode = -2;
2435     }
2436
2437     if ( tb )
2438         free(tb);
2439     if (errcode) {
2440         for (i = 0; i < num_prompts; i++) {
2441             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2442         }
2443     }
2444     return errcode;
2445 }
2446
2447 BOOL
2448 KFW_AFS_wait_for_service_start(void)
2449 {
2450     char    HostName[64];
2451     DWORD   CurrentState;
2452
2453     CurrentState = SERVICE_START_PENDING;
2454     memset(HostName, '\0', sizeof(HostName));
2455     gethostname(HostName, sizeof(HostName));
2456
2457     while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2458     {
2459         if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2460             return(0);
2461         if ( IsDebuggerPresent() ) {
2462             switch ( CurrentState ) {
2463             case SERVICE_STOPPED:
2464                 OutputDebugString("SERVICE_STOPPED\n");
2465                 break;
2466             case SERVICE_START_PENDING:
2467                 OutputDebugString("SERVICE_START_PENDING\n");
2468                 break;
2469             case SERVICE_STOP_PENDING:
2470                 OutputDebugString("SERVICE_STOP_PENDING\n");
2471                 break;
2472             case SERVICE_RUNNING:
2473                 OutputDebugString("SERVICE_RUNNING\n");
2474                 break;
2475             case SERVICE_CONTINUE_PENDING:
2476                 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2477                 break;
2478             case SERVICE_PAUSE_PENDING:
2479                 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2480                 break;
2481             case SERVICE_PAUSED:
2482                 OutputDebugString("SERVICE_PAUSED\n");
2483                 break;
2484             default:
2485                 OutputDebugString("UNKNOWN Service State\n");
2486             }
2487         }
2488         if (CurrentState == SERVICE_STOPPED)
2489             return(0);
2490         if (CurrentState == SERVICE_RUNNING)
2491             return(1);
2492         Sleep(500);
2493     }
2494     return(0);
2495 }
2496
2497
2498 int
2499 KFW_AFS_unlog(void)
2500 {
2501     long        rc;
2502     char    HostName[64];
2503     DWORD   CurrentState;
2504
2505     CurrentState = 0;
2506     memset(HostName, '\0', sizeof(HostName));
2507     gethostname(HostName, sizeof(HostName));
2508     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2509         return(0);
2510     if (CurrentState != SERVICE_RUNNING)
2511         return(0);
2512
2513     rc = ktc_ForgetAllTokens();
2514
2515     return(0);
2516 }
2517
2518
2519 #define ALLOW_REGISTER 1
2520 static int
2521 ViceIDToUsername(char *username, 
2522                  char *realm_of_user, 
2523                  char *realm_of_cell,
2524                  char * cell_to_use,
2525                  struct ktc_principal *aclient, 
2526                  struct ktc_principal *aserver, 
2527                  struct ktc_token *atoken)
2528 {
2529     static char lastcell[MAXCELLCHARS+1] = { 0 };
2530     static char confname[512] = { 0 };
2531 #ifdef AFS_ID_TO_NAME
2532     char username_copy[BUFSIZ];
2533 #endif /* AFS_ID_TO_NAME */
2534     long viceId;                        /* AFS uid of user */
2535     int  status = 0;
2536 #ifdef ALLOW_REGISTER
2537     afs_int32 id;
2538 #endif /* ALLOW_REGISTER */
2539
2540     if (confname[0] == '\0') {
2541         strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2542         confname[sizeof(confname) - 2] = '\0';
2543     }
2544
2545     /*
2546      * Talk about DUMB!  It turns out that there is a bug in
2547      * pr_Initialize -- even if you give a different cell name
2548      * to it, it still uses a connection to a previous AFS server
2549      * if one exists.  The way to fix this is to change the
2550      * _filename_ argument to pr_Initialize - that forces it to
2551      * re-initialize the connection.  We do this by adding and
2552      * removing a "/" on the end of the configuration directory name.
2553      */
2554
2555     if (lastcell[0] != '\0' && (strcmp(lastcell, aserver->cell) != 0)) {
2556         int i = strlen(confname);
2557         if (confname[i - 1] == '/') {
2558             confname[i - 1] = '\0';
2559         } else {
2560             confname[i] = '/';
2561             confname[i + 1] = '\0';
2562         }
2563     }
2564
2565     strcpy(lastcell, aserver->cell);
2566
2567     if (!pr_Initialize (0, confname, aserver->cell))
2568         status = pr_SNameToId (username, &viceId);
2569
2570     /*
2571      * This is a crock, but it is Transarc's crock, so
2572      * we have to play along in order to get the
2573      * functionality.  The way the afs id is stored is
2574      * as a string in the username field of the token.
2575      * Contrary to what you may think by looking at
2576      * the code for tokens, this hack (AFS ID %d) will
2577      * not work if you change %d to something else.
2578      */
2579
2580     /*
2581      * This code is taken from cklog -- it lets people
2582      * automatically register with the ptserver in foreign cells
2583      */
2584
2585 #ifdef ALLOW_REGISTER
2586     if (status == 0) {
2587         if (viceId != ANONYMOUSID) {
2588 #else /* ALLOW_REGISTER */
2589             if ((status == 0) && (viceId != ANONYMOUSID))
2590 #endif /* ALLOW_REGISTER */
2591             {
2592 #ifdef AFS_ID_TO_NAME
2593                 strncpy(username_copy, username, BUFSIZ);
2594                 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2595 #endif /* AFS_ID_TO_NAME */
2596             }
2597 #ifdef ALLOW_REGISTER
2598         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2599             id = 0;
2600             strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2601             strcpy(aclient->instance, "");
2602             strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2603             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2604                 return status;
2605
2606             /*                                    
2607              * In case you're wondering, we don't need to change the
2608              * filename here because we're still connecting to the
2609              * same cell -- we're just using a different authentication
2610              * level
2611              */
2612
2613             if (status = pr_Initialize(1L, confname, aserver->cell))
2614                 return status;
2615             if (status = pr_CreateUser(username, &id))
2616                 return status;
2617 #ifdef AFS_ID_TO_NAME
2618             strncpy(username_copy, username, BUFSIZ);
2619             snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2620 #endif /* AFS_ID_TO_NAME */
2621         }
2622     }
2623 #endif /* ALLOW_REGISTER */
2624     return status;
2625 }
2626
2627
2628 int
2629 KFW_AFS_klog(
2630     krb5_context alt_ctx,
2631     krb5_ccache  alt_cc,
2632     char *service,
2633     char *cell,
2634     char *realm,
2635     int LifeTime,
2636     char *smbname
2637     )
2638 {
2639     long        rc = 0;
2640     CREDENTIALS creds;
2641 #ifdef USE_KRB4
2642     KTEXT_ST    ticket;
2643 #endif /* USE_KRB4 */
2644     struct ktc_principal        aserver;
2645     struct ktc_principal        aclient;
2646     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2647     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2648     char        local_cell[MAXCELLCHARS+1];
2649     char        Dmycell[MAXCELLCHARS+1];
2650     struct ktc_token    atoken;
2651     struct ktc_token    btoken;
2652     struct afsconf_cell ak_cellconfig; /* General information about the cell */
2653     char        RealmName[128];
2654     char        CellName[128];
2655     char        ServiceName[128];
2656     DWORD       CurrentState;
2657     char        HostName[64];
2658     BOOL        try_krb5 = 0;
2659     krb5_context  ctx = 0;
2660     krb5_ccache   cc = 0;
2661     krb5_creds increds;
2662     krb5_creds * k5creds = 0;
2663     krb5_error_code code;
2664     krb5_principal client_principal = 0;
2665     krb5_data * k5data;
2666     int i, retry = 0;
2667
2668     CurrentState = 0;
2669     memset(HostName, '\0', sizeof(HostName));
2670     gethostname(HostName, sizeof(HostName));
2671     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2672         if ( IsDebuggerPresent() )
2673             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2674         return(-1);
2675     }
2676     if (CurrentState != SERVICE_RUNNING) {
2677         if ( IsDebuggerPresent() )
2678             OutputDebugString("AFSD Service NOT RUNNING\n");
2679         return(-2);
2680     }
2681
2682     if (!pkrb5_init_context)
2683         return 0;
2684
2685     memset(RealmName, '\0', sizeof(RealmName));
2686     memset(CellName, '\0', sizeof(CellName));
2687     memset(ServiceName, '\0', sizeof(ServiceName));
2688     memset(realm_of_user, '\0', sizeof(realm_of_user));
2689     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2690     if (cell && cell[0])
2691         strcpy(Dmycell, cell);
2692     else
2693         memset(Dmycell, '\0', sizeof(Dmycell));
2694
2695     // NULL or empty cell returns information on local cell
2696     if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2697     {
2698         // KFW_AFS_error(rc, "get_cellconfig()");
2699         return(rc);
2700     }
2701
2702     if ( alt_ctx ) {
2703         ctx = alt_ctx;
2704     } else {
2705         code = pkrb5_init_context(&ctx);
2706         if (code) goto cleanup;
2707     }
2708
2709     if ( alt_cc ) {
2710         cc = alt_cc;
2711     } else {
2712         code = pkrb5_cc_default(ctx, &cc);
2713         if (code) goto skip_krb5_init;
2714     }
2715
2716     memset((char *)&increds, 0, sizeof(increds));
2717
2718     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2719     if (code) {
2720         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
2721         {
2722             OutputDebugString("Principal Not Found for ccache\n");
2723         }
2724         goto skip_krb5_init;
2725     }
2726
2727     /* look for client principals which cannot be distinguished 
2728      * from Kerberos 4 multi-component principal names
2729      */
2730     k5data = krb5_princ_component(ctx,client_principal,0);
2731     for ( i=0; i<k5data->length; i++ ) {
2732         if ( k5data->data[i] == '.' )
2733             break;
2734     }
2735     if (i != k5data->length)
2736     {
2737         OutputDebugString("Illegal Principal name contains dot in first component\n");
2738         rc = KRB5KRB_ERR_GENERIC;
2739         goto cleanup;
2740     }
2741
2742     i = krb5_princ_realm(ctx, client_principal)->length;
2743     if (i > REALM_SZ-1) 
2744         i = REALM_SZ-1;
2745     strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2746     realm_of_user[i] = 0;
2747     try_krb5 = 1;
2748
2749   skip_krb5_init:
2750 #ifdef USE_KRB4
2751     if ( !try_krb5 || !realm_of_user[0] ) {
2752         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2753         {
2754             goto cleanup;
2755         }       
2756     }
2757 #else
2758     if (!try_krb5)
2759         goto cleanup;
2760 #endif
2761     strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2762
2763     if (strlen(service) == 0)
2764         strcpy(ServiceName, "afs");
2765     else
2766         strcpy(ServiceName, service);
2767
2768     if (strlen(cell) == 0)
2769         strcpy(CellName, local_cell);
2770     else
2771         strcpy(CellName, cell);
2772
2773     if (strlen(realm) == 0)
2774         strcpy(RealmName, realm_of_cell);
2775     else
2776         strcpy(RealmName, realm);
2777
2778     memset(&creds, '\0', sizeof(creds));
2779
2780     if ( try_krb5 ) {
2781         int len;
2782
2783         /* First try service/cell@REALM */
2784         if (code = pkrb5_build_principal(ctx, &increds.server,
2785                                           strlen(RealmName),
2786                                           RealmName,
2787                                           ServiceName,
2788                                           CellName,
2789                                           0)) 
2790         {
2791             goto cleanup;
2792         }
2793
2794         increds.client = client_principal;
2795         increds.times.endtime = 0;
2796         /* Ask for DES since that is what V4 understands */
2797         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2798
2799
2800         if ( IsDebuggerPresent() ) {
2801             char * cname, *sname;
2802             pkrb5_unparse_name(ctx, increds.client, &cname);
2803             pkrb5_unparse_name(ctx, increds.server, &sname);
2804             OutputDebugString("Getting tickets for \"");
2805             OutputDebugString(cname);
2806             OutputDebugString("\" and service \"");
2807             OutputDebugString(sname);
2808             OutputDebugString("\"\n");
2809             pkrb5_free_unparsed_name(ctx,cname);
2810             pkrb5_free_unparsed_name(ctx,sname);
2811         }
2812
2813         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2814         if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2815              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2816              code == KRB5KRB_AP_ERR_MSG_TYPE) {
2817             /* Or service@REALM */
2818             pkrb5_free_principal(ctx,increds.server);
2819             increds.server = 0;
2820             code = pkrb5_build_principal(ctx, &increds.server,
2821                                           strlen(RealmName),
2822                                           RealmName,
2823                                           ServiceName,
2824                                           0);
2825
2826             if ( IsDebuggerPresent() ) {
2827                 char * cname, *sname;
2828                 pkrb5_unparse_name(ctx, increds.client, &cname);
2829                 pkrb5_unparse_name(ctx, increds.server, &sname);
2830                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2831                 OutputDebugString("Trying again: getting tickets for \"");
2832                 OutputDebugString(cname);
2833                 OutputDebugString("\" and service \"");
2834                 OutputDebugString(sname);
2835                 OutputDebugString("\"\n");
2836                 pkrb5_free_unparsed_name(ctx,cname);
2837                 pkrb5_free_unparsed_name(ctx,sname);
2838             }
2839
2840             if (!code)
2841                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2842         }
2843
2844         if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2845               code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2846               code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2847              strcmp(RealmName, realm_of_cell)) {
2848             /* Or service/cell@REALM_OF_CELL */
2849             strcpy(RealmName, realm_of_cell);
2850             pkrb5_free_principal(ctx,increds.server);
2851             increds.server = 0;
2852             code = pkrb5_build_principal(ctx, &increds.server,
2853                                          strlen(RealmName),
2854                                          RealmName,
2855                                          ServiceName,
2856                                          CellName,
2857                                          0);
2858
2859             if ( IsDebuggerPresent() ) {
2860                 char * cname, *sname;
2861                 pkrb5_unparse_name(ctx, increds.client, &cname);
2862                 pkrb5_unparse_name(ctx, increds.server, &sname);
2863                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2864                 OutputDebugString("Trying again: getting tickets for \"");
2865                 OutputDebugString(cname);
2866                 OutputDebugString("\" and service \"");
2867                 OutputDebugString(sname);
2868                 OutputDebugString("\"\n");
2869                 pkrb5_free_unparsed_name(ctx,cname);
2870                 pkrb5_free_unparsed_name(ctx,sname);
2871             }
2872
2873             if (!code)
2874                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2875
2876         
2877             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2878                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2879                                  code == KRB5KRB_AP_ERR_MSG_TYPE) {
2880                 /* Or service@REALM_OF_CELL */
2881                 pkrb5_free_principal(ctx,increds.server);
2882                 increds.server = 0;
2883                 code = pkrb5_build_principal(ctx, &increds.server,
2884                                               strlen(RealmName),
2885                                               RealmName,
2886                                               ServiceName,
2887                                               0);
2888
2889                 if ( IsDebuggerPresent() ) {
2890                     char * cname, *sname;
2891                     pkrb5_unparse_name(ctx, increds.client, &cname);
2892                     pkrb5_unparse_name(ctx, increds.server, &sname);
2893                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2894                     OutputDebugString("Trying again: getting tickets for \"");
2895                     OutputDebugString(cname);
2896                     OutputDebugString("\" and service \"");
2897                     OutputDebugString(sname);
2898                     OutputDebugString("\"\n");
2899                     pkrb5_free_unparsed_name(ctx,cname);
2900                     pkrb5_free_unparsed_name(ctx,sname);
2901                 }
2902
2903                 if (!code)
2904                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2905             }
2906         }
2907
2908         if (code) {
2909             if ( IsDebuggerPresent() ) {
2910                 char message[256];
2911                 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2912                 OutputDebugString(message);
2913             }
2914             try_krb5 = 0;
2915             goto use_krb4;
2916         }
2917
2918         /* This code inserts the entire K5 ticket into the token
2919          * No need to perform a krb524 translation which is 
2920          * commented out in the code below
2921          */
2922         if (KFW_use_krb524() ||
2923             k5creds->ticket.length > MAXKTCTICKETLEN)
2924             goto try_krb524d;
2925
2926         memset(&aserver, '\0', sizeof(aserver));
2927         strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2928         strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2929
2930         memset(&atoken, '\0', sizeof(atoken));
2931         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2932         atoken.startTime = k5creds->times.starttime;
2933         atoken.endTime = k5creds->times.endtime;
2934         memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2935         atoken.ticketLen = k5creds->ticket.length;
2936         memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2937
2938       retry_gettoken5:
2939         rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2940         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2941             if ( rc == KTC_NOCM && retry < 20 ) {
2942                 Sleep(500);
2943                 retry++;
2944                 goto retry_gettoken5;
2945             }
2946             goto try_krb524d;
2947         }
2948
2949         if (atoken.kvno == btoken.kvno &&
2950              atoken.ticketLen == btoken.ticketLen &&
2951              !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2952              !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
2953         {
2954             /* Success - Nothing to do */
2955             goto cleanup;
2956         }
2957
2958         // * Reset the "aclient" structure before we call ktc_SetToken.
2959         // * This structure was first set by the ktc_GetToken call when
2960         // * we were comparing whether identical tokens already existed.
2961
2962         len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2963         strncpy(aclient.name, k5creds->client->data[0].data, len);
2964         aclient.name[len] = '\0';
2965
2966         if ( k5creds->client->length > 1 ) {
2967             char * p;
2968             strcat(aclient.name, ".");
2969             p = aclient.name + strlen(aclient.name);
2970             len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
2971             strncpy(p, k5creds->client->data[1].data, len);
2972             p[len] = '\0';
2973         }
2974         aclient.instance[0] = '\0';
2975
2976         strcpy(aclient.cell, realm_of_cell);
2977
2978         len = min(k5creds->client->realm.length,strlen(realm_of_cell));
2979         if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) {
2980             char * p;
2981             strcat(aclient.name, "@");
2982             p = aclient.name + strlen(aclient.name);
2983             len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
2984             strncpy(p, k5creds->client->realm.data, len);
2985             p[len] = '\0';
2986         }
2987
2988         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
2989                          &aclient, &aserver, &atoken);
2990
2991         if ( smbname ) {
2992             strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
2993             aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
2994         } else {
2995             aclient.smbname[0] = '\0';
2996         }
2997
2998         rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2999         if (!rc)
3000             goto cleanup;   /* We have successfully inserted the token */
3001
3002       try_krb524d:
3003         /* Otherwise, the ticket could have been too large so try to
3004          * convert using the krb524d running with the KDC 
3005          */
3006         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3007         pkrb5_free_creds(ctx, k5creds);
3008         if (code) {
3009             if ( IsDebuggerPresent() ) {
3010                 char message[256];
3011                 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3012                 OutputDebugString(message);
3013             }
3014             try_krb5 = 0;
3015             goto use_krb4;
3016         }
3017     } else {
3018       use_krb4:
3019 #ifdef USE_KRB4
3020         code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3021         if (code == NO_TKT_FIL) {
3022             // if the problem is that we have no krb4 tickets
3023             // do not attempt to continue
3024             goto cleanup;
3025         }
3026         if (code != KSUCCESS)
3027             code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3028
3029         if (code != KSUCCESS)
3030         {
3031             if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3032             {
3033                 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3034                 {
3035                     goto cleanup;
3036                 }
3037             }
3038             else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3039             {
3040                 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3041                 {
3042                     goto cleanup;
3043                 }
3044             }
3045             else
3046             {
3047                 goto cleanup;
3048             }
3049         }
3050 #else
3051         goto cleanup;
3052 #endif
3053     }
3054
3055     memset(&aserver, '\0', sizeof(aserver));
3056     strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3057     strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3058
3059     memset(&atoken, '\0', sizeof(atoken));
3060     atoken.kvno = creds.kvno;
3061     atoken.startTime = creds.issue_date;
3062     atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3063     memcpy(&atoken.sessionKey, creds.session, 8);
3064     atoken.ticketLen = creds.ticket_st.length;
3065     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3066
3067   retry_gettoken:
3068     rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3069     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3070         if ( rc == KTC_NOCM && retry < 20 ) {
3071             Sleep(500);
3072             retry++;
3073             goto retry_gettoken;
3074         }
3075         KFW_AFS_error(rc, "ktc_GetToken()");
3076         code = rc;
3077         goto cleanup;
3078     }
3079
3080     if (atoken.kvno == btoken.kvno &&
3081         atoken.ticketLen == btoken.ticketLen &&
3082         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3083         !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
3084     {
3085         goto cleanup;
3086     }
3087
3088     // * Reset the "aclient" structure before we call ktc_SetToken.
3089     // * This structure was first set by the ktc_GetToken call when
3090     // * we were comparing whether identical tokens already existed.
3091
3092     strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3093     if (creds.pinst[0])
3094     {
3095         strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3096         strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3097     }
3098     strcpy(aclient.instance, "");
3099
3100     if ( strcmp(realm_of_cell, creds.realm) ) 
3101     {
3102         strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3103         strncpy(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3104     }
3105     aclient.name[MAXKTCREALMLEN-1] = '\0';
3106
3107     strcpy(aclient.cell, CellName);
3108
3109     ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
3110                       &aclient, &aserver, &atoken);
3111
3112     if ( smbname ) {
3113         strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3114         aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3115     } else {
3116         aclient.smbname[0] = '\0';
3117     }
3118
3119     if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3120     {
3121         KFW_AFS_error(rc, "ktc_SetToken()");
3122         code = rc;
3123         goto cleanup;
3124     }
3125
3126   cleanup:
3127     if (client_principal)
3128         pkrb5_free_principal(ctx,client_principal);
3129     /* increds.client == client_principal */
3130     if (increds.server)
3131         pkrb5_free_principal(ctx,increds.server);
3132     if (cc && (cc != alt_cc))
3133         pkrb5_cc_close(ctx, cc);
3134     if (ctx && (ctx != alt_ctx))
3135         pkrb5_free_context(ctx);
3136
3137     return(rc? rc : code);
3138 }
3139
3140 /**************************************/
3141 /* afs_realm_of_cell():               */
3142 /**************************************/
3143 static char *
3144 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3145 {
3146     static char krbrlm[REALM_SZ+1]="";
3147     char ** realmlist=NULL;
3148     krb5_error_code r;
3149
3150     if (!cellconfig)
3151         return 0;
3152
3153     r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3154     if ( !r && realmlist && realmlist[0] ) {
3155         strcpy(krbrlm, realmlist[0]);
3156         pkrb5_free_host_realm(ctx, realmlist);
3157     }
3158
3159     if ( !krbrlm[0] )
3160     {
3161         char *s = krbrlm;
3162         char *t = cellconfig->name;
3163         int c;
3164
3165         while (c = *t++)
3166         {
3167             if (islower(c)) c=toupper(c);
3168             *s++ = c;
3169         }
3170         *s++ = 0;
3171     }
3172     return(krbrlm);
3173 }
3174
3175 /**************************************/
3176 /* KFW_AFS_get_cellconfig():          */
3177 /**************************************/
3178 int 
3179 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3180 {
3181     int rc;
3182     char newcell[MAXCELLCHARS+1];
3183
3184     local_cell[0] = (char)0;
3185     memset(cellconfig, 0, sizeof(*cellconfig));
3186
3187     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3188     if (rc = cm_GetRootCellName(local_cell))
3189     {
3190         return(rc);
3191     }
3192
3193     if (strlen(cell) == 0)
3194         strcpy(cell, local_cell);
3195
3196     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3197     strcpy(cellconfig->name, cell);
3198
3199     rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3200 #ifdef AFS_AFSDB_ENV
3201     if (rc != 0) {
3202         int ttl;
3203         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3204     }
3205 #endif
3206     return rc;
3207 }
3208
3209 /**************************************/
3210 /* get_cellconfig_callback():         */
3211 /**************************************/
3212 static long 
3213 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3214 {
3215     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3216
3217     cc->hostAddr[cc->numServers] = *addrp;
3218     strcpy(cc->hostName[cc->numServers], namep);
3219     cc->numServers++;
3220     return(0);
3221 }
3222
3223
3224 /**************************************/
3225 /* KFW_AFS_error():                  */
3226 /**************************************/
3227 void
3228 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3229 {
3230     char message[256];
3231     const char *errText; 
3232
3233     // Using AFS defines as error messages for now, until Transarc 
3234     // gets back to me with "string" translations of each of these 
3235     // const. defines. 
3236     if (rc == KTC_ERROR)
3237       errText = "KTC_ERROR";
3238     else if (rc == KTC_TOOBIG)
3239       errText = "KTC_TOOBIG";
3240     else if (rc == KTC_INVAL)
3241       errText = "KTC_INVAL";
3242     else if (rc == KTC_NOENT)
3243       errText = "KTC_NOENT";
3244     else if (rc == KTC_PIOCTLFAIL)
3245       errText = "KTC_PIOCTLFAIL";
3246     else if (rc == KTC_NOPIOCTL)
3247       errText = "KTC_NOPIOCTL";
3248     else if (rc == KTC_NOCELL)
3249       errText = "KTC_NOCELL";
3250     else if (rc == KTC_NOCM)
3251       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3252     else
3253       errText = "Unknown error!";
3254
3255     sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3256
3257     if ( IsDebuggerPresent() ) {
3258         OutputDebugString(message);
3259         OutputDebugString("\n");
3260     }
3261     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3262     return;
3263 }
3264
3265 static DWORD 
3266 GetServiceStatus(
3267     LPSTR lpszMachineName, 
3268     LPSTR lpszServiceName,
3269     DWORD *lpdwCurrentState) 
3270
3271     DWORD           hr               = NOERROR; 
3272     SC_HANDLE       schSCManager     = NULL; 
3273     SC_HANDLE       schService       = NULL; 
3274     DWORD           fdwDesiredAccess = 0; 
3275     SERVICE_STATUS  ssServiceStatus  = {0}; 
3276     BOOL            fRet             = FALSE; 
3277
3278     *lpdwCurrentState = 0; 
3279  
3280     fdwDesiredAccess = GENERIC_READ; 
3281  
3282     schSCManager = OpenSCManager(lpszMachineName,  
3283                                  NULL,
3284                                  fdwDesiredAccess); 
3285  
3286     if(schSCManager == NULL) 
3287     { 
3288         hr = GetLastError();
3289         goto cleanup; 
3290     } 
3291  
3292     schService = OpenService(schSCManager,
3293                              lpszServiceName,
3294                              fdwDesiredAccess); 
3295  
3296     if(schService == NULL) 
3297     { 
3298         hr = GetLastError();
3299         goto cleanup; 
3300     } 
3301  
3302     fRet = QueryServiceStatus(schService,
3303                               &ssServiceStatus); 
3304  
3305     if(fRet == FALSE) 
3306     { 
3307         hr = GetLastError(); 
3308         goto cleanup; 
3309     } 
3310  
3311     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
3312  
3313 cleanup: 
3314  
3315     CloseServiceHandle(schService); 
3316     CloseServiceHandle(schSCManager); 
3317  
3318     return(hr); 
3319
3320
3321 void
3322 UnloadFuncs(
3323     FUNC_INFO fi[], 
3324     HINSTANCE h
3325     )
3326 {
3327     int n;
3328     if (fi)
3329         for (n = 0; fi[n].func_ptr_var; n++)
3330             *(fi[n].func_ptr_var) = 0;
3331     if (h) FreeLibrary(h);
3332 }
3333
3334 int
3335 LoadFuncs(
3336     const char* dll_name, 
3337     FUNC_INFO fi[], 
3338     HINSTANCE* ph,  // [out, optional] - DLL handle
3339     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
3340     int cleanup,    // cleanup function pointers and unload on error
3341     int go_on,      // continue loading even if some functions cannot be loaded
3342     int silent      // do not pop-up a system dialog if DLL cannot be loaded
3343     )
3344 {
3345     HINSTANCE h;
3346     int i, n, last_i;
3347     int error = 0;
3348     UINT em;
3349
3350     if (ph) *ph = 0;
3351     if (pindex) *pindex = -1;
3352
3353     for (n = 0; fi[n].func_ptr_var; n++)
3354         *(fi[n].func_ptr_var) = 0;
3355
3356     if (silent)
3357         em = SetErrorMode(SEM_FAILCRITICALERRORS);
3358     h = LoadLibrary(dll_name);
3359     if (silent)
3360         SetErrorMode(em);
3361
3362     if (!h)
3363         return 0;
3364
3365     last_i = -1;
3366     for (i = 0; (go_on || !error) && (i < n); i++)
3367     {
3368         void* p = (void*)GetProcAddress(h, fi[i].func_name);
3369         if (!p)
3370             error = 1;
3371         else
3372         {
3373             last_i = i;
3374             *(fi[i].func_ptr_var) = p;
3375         }
3376     }
3377     if (pindex) *pindex = last_i;
3378     if (error && cleanup && !go_on) {
3379         for (i = 0; i < n; i++) {
3380             *(fi[i].func_ptr_var) = 0;
3381         }
3382         FreeLibrary(h);
3383         return 0;
3384     }
3385     if (ph) *ph = h;
3386     if (error) return 0;
3387     return 1;
3388 }
3389
3390 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3391 {
3392     krb5_context ctx = 0;
3393     krb5_ccache cc = 0;
3394     krb5_error_code code;
3395     krb5_data pwdata;
3396     const char * realm = 0;
3397     krb5_principal principal = 0;
3398     char * pname = 0;
3399     char   password[PROBE_PASSWORD_LEN+1];
3400     BOOL serverReachable = 0;
3401
3402     if (!pkrb5_init_context)
3403         return 0;
3404
3405     code = pkrb5_init_context(&ctx);
3406     if (code) goto cleanup;
3407
3408
3409     realm = afs_realm_of_cell(ctx, cellconfig);  // do not free
3410
3411     code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3412                                   realm, PROBE_USERNAME, NULL, NULL);
3413     if ( code ) goto cleanup;
3414
3415     code = KFW_get_ccache(ctx, principal, &cc);
3416     if ( code ) goto cleanup;
3417
3418     code = pkrb5_unparse_name(ctx, principal, &pname);
3419     if ( code ) goto cleanup;
3420
3421     pwdata.data = password;
3422     pwdata.length = PROBE_PASSWORD_LEN;
3423     code = pkrb5_c_random_make_octets(ctx, &pwdata);
3424     if (code) {
3425         int i;
3426         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3427             password[i] = 'x';
3428     }
3429     password[PROBE_PASSWORD_LEN] = '\0';
3430
3431     code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
3432                       pname, 
3433                       password,
3434                       5,
3435                       0,
3436                       0,
3437                       0,
3438                       1,
3439                       0);
3440     switch ( code ) {
3441     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3442     case KRB5KDC_ERR_CLIENT_REVOKED:
3443     case KRB5KDC_ERR_CLIENT_NOTYET:
3444     case KRB5KDC_ERR_PREAUTH_FAILED:
3445     case KRB5KDC_ERR_PREAUTH_REQUIRED:
3446     case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3447         serverReachable = TRUE;
3448         break;
3449     default:
3450         serverReachable = FALSE;
3451     }
3452
3453   cleanup:
3454     if ( pname )
3455         pkrb5_free_unparsed_name(ctx,pname);
3456     if ( principal )
3457         pkrb5_free_principal(ctx,principal);
3458     if (cc)
3459         pkrb5_cc_close(ctx,cc);
3460     if (ctx)
3461         pkrb5_free_context(ctx);
3462
3463     return serverReachable;
3464 }
3465
3466 BOOL
3467 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3468 {
3469     krb5_context   ctx = 0;
3470     krb5_error_code code;
3471     krb5_ccache mslsa_ccache=0;
3472     krb5_principal princ = 0;
3473     char * pname = 0;
3474     BOOL success = 0;
3475
3476     if (!KFW_is_available())
3477         return FALSE;
3478
3479     if (code = pkrb5_init_context(&ctx))
3480         goto cleanup;
3481
3482     if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3483         goto cleanup;
3484
3485     if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3486         goto cleanup;
3487
3488     if (code = pkrb5_unparse_name(ctx, princ, &pname))
3489         goto cleanup;
3490
3491     if ( strlen(pname) < *dwSize ) {
3492         strncpy(szUser, pname, *dwSize);
3493         szUser[*dwSize-1] = '\0';
3494         success = 1;
3495     }
3496     *dwSize = strlen(pname);
3497
3498   cleanup:
3499     if (pname)
3500         pkrb5_free_unparsed_name(ctx, pname);
3501
3502     if (princ)
3503         pkrb5_free_principal(ctx, princ);
3504
3505     if (mslsa_ccache)
3506         pkrb5_cc_close(ctx, mslsa_ccache);
3507
3508     if (ctx)
3509         pkrb5_free_context(ctx);
3510     return success;
3511 }
3512
3513 void
3514 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3515 {
3516     char filename[256];
3517     DWORD count;
3518     char cachename[264] = "FILE:";
3519     krb5_context                ctx = 0;
3520     krb5_error_code             code;
3521     krb5_principal              princ = 0;
3522     krb5_ccache                 cc  = 0;
3523     krb5_ccache                 ncc = 0;
3524
3525     if (!pkrb5_init_context)
3526         return;
3527
3528     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3529     if ( count > sizeof(filename) || count == 0 ) {
3530         GetWindowsDirectory(filename, sizeof(filename));
3531     }
3532
3533     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3534         return;
3535
3536     strcat(filename, "\\");
3537     strcat(filename, szLogonId);    
3538
3539     strcat(cachename, filename);
3540
3541     DeleteFile(filename);
3542
3543     code = pkrb5_init_context(&ctx);
3544     if (code) ctx = 0;
3545
3546     code = pkrb5_parse_name(ctx, user, &princ);
3547     if (code) goto cleanup;
3548
3549     code = KFW_get_ccache(ctx, princ, &cc);
3550     if (code) goto cleanup;
3551
3552     code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3553     if (code) goto cleanup;
3554
3555     code = pkrb5_cc_initialize(ctx, ncc, princ);
3556     if (code) goto cleanup;
3557
3558     code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3559
3560   cleanup:
3561     if ( cc ) {
3562         pkrb5_cc_close(ctx, cc);
3563         cc = 0;
3564     }
3565     if ( ncc ) {
3566         pkrb5_cc_close(ctx, ncc);
3567         ncc = 0;
3568     }
3569     if ( princ ) {
3570         pkrb5_free_principal(ctx, princ);
3571         princ = 0;
3572     }
3573
3574     if (ctx)
3575         pkrb5_free_context(ctx);
3576 }
3577
3578 int
3579 KFW_AFS_copy_system_file_to_default_cache(char * filename)
3580 {
3581     DWORD count;
3582     char cachename[264] = "FILE:";
3583     HANDLE hFile;
3584     krb5_context                ctx = 0;
3585     krb5_error_code             code;
3586     krb5_principal              princ = 0;
3587     krb5_ccache                 cc  = 0;
3588     krb5_ccache                 ncc = 0;
3589     int retval = 1;
3590
3591     if (!pkrb5_init_context)
3592         return 1;
3593
3594     if ( strlen(filename) + 6 > sizeof(cachename) )
3595         return 1;
3596
3597     strcat(cachename, filename);
3598
3599     code = pkrb5_init_context(&ctx);
3600     if (code) ctx = 0;
3601
3602     code = pkrb5_cc_resolve(ctx, cachename, &cc);
3603     if (code) goto cleanup;
3604     
3605     code = pkrb5_cc_get_principal(ctx, cc, &princ);
3606
3607     code = pkrb5_cc_default(ctx, &ncc);
3608     if (!code) {
3609         code = pkrb5_cc_initialize(ctx, ncc, princ);
3610
3611         if (!code)
3612             code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3613     }
3614     if ( ncc ) {
3615         pkrb5_cc_close(ctx, ncc);
3616         ncc = 0;
3617     }
3618
3619     retval=0;   /* success */
3620
3621   cleanup:
3622     if ( cc ) {
3623         pkrb5_cc_close(ctx, cc);
3624         cc = 0;
3625     }
3626
3627     DeleteFile(filename);
3628
3629     if ( princ ) {
3630         pkrb5_free_principal(ctx, princ);
3631         princ = 0;
3632     }
3633
3634     if (ctx)
3635         pkrb5_free_context(ctx);
3636
3637     return 0;
3638 }