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