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