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