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