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();