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