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