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