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