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