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