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