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