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