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