2 * Copyright (c) 2004, 2005, 2006, 2007 Secure Endpoints Inc.
3 * Copyright (c) 2003 SkyRope, LLC
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
34 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
35 * All rights reserved.
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.
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.
66 #include "afskfw-int.h"
74 #include <afs/ptserver.h>
75 #include <afs/ptuser.h>
78 #include <WINNT\afsreg.h>
81 * TIMING _____________________________________________________________________
85 #define cminREMIND_TEST 1 // test every minute for expired creds
86 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
87 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
88 #define cminMINLIFE 30 // minimum life of Kerberos creds
90 #define c100ns1SECOND (LONGLONG)10000000
91 #define cmsec1SECOND 1000
92 #define cmsec1MINUTE 60000
93 #define csec1MINUTE 60
95 /* Function Pointer Declarations for Delayed Loading */
97 DECL_FUNC_PTR(cc_initialize);
98 DECL_FUNC_PTR(cc_shutdown);
99 DECL_FUNC_PTR(cc_get_NC_info);
100 DECL_FUNC_PTR(cc_free_NC_info);
104 DECL_FUNC_PTR(Leash_get_default_lifetime);
105 DECL_FUNC_PTR(Leash_get_default_forwardable);
106 DECL_FUNC_PTR(Leash_get_default_renew_till);
107 DECL_FUNC_PTR(Leash_get_default_noaddresses);
108 DECL_FUNC_PTR(Leash_get_default_proxiable);
109 DECL_FUNC_PTR(Leash_get_default_publicip);
110 DECL_FUNC_PTR(Leash_get_default_use_krb4);
111 DECL_FUNC_PTR(Leash_get_default_life_min);
112 DECL_FUNC_PTR(Leash_get_default_life_max);
113 DECL_FUNC_PTR(Leash_get_default_renew_min);
114 DECL_FUNC_PTR(Leash_get_default_renew_max);
115 DECL_FUNC_PTR(Leash_get_default_renewable);
116 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
120 DECL_FUNC_PTR(krb5_change_password);
121 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
122 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
123 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
124 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
125 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
126 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
127 DECL_FUNC_PTR(krb5_get_init_creds_password);
128 DECL_FUNC_PTR(krb5_build_principal_ext);
129 DECL_FUNC_PTR(krb5_cc_get_name);
130 DECL_FUNC_PTR(krb5_cc_resolve);
131 DECL_FUNC_PTR(krb5_cc_default);
132 DECL_FUNC_PTR(krb5_cc_default_name);
133 DECL_FUNC_PTR(krb5_cc_set_default_name);
134 DECL_FUNC_PTR(krb5_cc_initialize);
135 DECL_FUNC_PTR(krb5_cc_destroy);
136 DECL_FUNC_PTR(krb5_cc_close);
137 DECL_FUNC_PTR(krb5_cc_store_cred);
138 DECL_FUNC_PTR(krb5_cc_copy_creds);
139 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
140 DECL_FUNC_PTR(krb5_cc_get_principal);
141 DECL_FUNC_PTR(krb5_cc_start_seq_get);
142 DECL_FUNC_PTR(krb5_cc_next_cred);
143 DECL_FUNC_PTR(krb5_cc_end_seq_get);
144 DECL_FUNC_PTR(krb5_cc_remove_cred);
145 DECL_FUNC_PTR(krb5_cc_set_flags);
146 DECL_FUNC_PTR(krb5_cc_get_type);
147 DECL_FUNC_PTR(krb5_free_context);
148 DECL_FUNC_PTR(krb5_free_cred_contents);
149 DECL_FUNC_PTR(krb5_free_principal);
150 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
151 DECL_FUNC_PTR(krb5_init_context);
152 DECL_FUNC_PTR(krb5_parse_name);
153 DECL_FUNC_PTR(krb5_timeofday);
154 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
155 DECL_FUNC_PTR(krb5_unparse_name);
156 DECL_FUNC_PTR(krb5_get_credentials);
157 DECL_FUNC_PTR(krb5_mk_req);
158 DECL_FUNC_PTR(krb5_sname_to_principal);
159 DECL_FUNC_PTR(krb5_get_credentials_renew);
160 DECL_FUNC_PTR(krb5_free_data);
161 DECL_FUNC_PTR(krb5_free_data_contents);
162 DECL_FUNC_PTR(krb5_free_unparsed_name);
163 DECL_FUNC_PTR(krb5_os_localaddr);
164 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
165 DECL_FUNC_PTR(krb5_copy_data);
166 DECL_FUNC_PTR(krb5_free_creds);
167 DECL_FUNC_PTR(krb5_build_principal);
168 DECL_FUNC_PTR(krb5_get_renewed_creds);
169 DECL_FUNC_PTR(krb5_get_default_config_files);
170 DECL_FUNC_PTR(krb5_free_config_files);
171 DECL_FUNC_PTR(krb5_get_default_realm);
172 DECL_FUNC_PTR(krb5_free_default_realm);
173 DECL_FUNC_PTR(krb5_free_ticket);
174 DECL_FUNC_PTR(krb5_decode_ticket);
175 DECL_FUNC_PTR(krb5_get_host_realm);
176 DECL_FUNC_PTR(krb5_free_host_realm);
177 DECL_FUNC_PTR(krb5_free_addresses);
178 DECL_FUNC_PTR(krb5_c_random_make_octets);
182 DECL_FUNC_PTR(krb524_init_ets);
183 DECL_FUNC_PTR(krb524_convert_creds_kdc);
188 DECL_FUNC_PTR(krb_get_cred);
189 DECL_FUNC_PTR(tkt_string);
190 DECL_FUNC_PTR(krb_get_tf_realm);
191 DECL_FUNC_PTR(krb_mk_req);
195 DECL_FUNC_PTR(com_err);
196 DECL_FUNC_PTR(error_message);
199 DECL_FUNC_PTR(profile_init);
200 DECL_FUNC_PTR(profile_release);
201 DECL_FUNC_PTR(profile_get_subsection_names);
202 DECL_FUNC_PTR(profile_free_list);
203 DECL_FUNC_PTR(profile_get_string);
204 DECL_FUNC_PTR(profile_release_string);
207 DECL_FUNC_PTR(OpenSCManagerA);
208 DECL_FUNC_PTR(OpenServiceA);
209 DECL_FUNC_PTR(QueryServiceStatus);
210 DECL_FUNC_PTR(CloseServiceHandle);
212 DECL_FUNC_PTR(LsaNtStatusToWinError);
213 #endif /* USE_MS2MIT */
217 DECL_FUNC_PTR(LsaConnectUntrusted);
218 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
219 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
220 DECL_FUNC_PTR(LsaFreeReturnBuffer);
221 DECL_FUNC_PTR(LsaGetLogonSessionData);
222 #endif /* USE_MS2MIT */
225 FUNC_INFO ccapi_fi[] = {
226 MAKE_FUNC_INFO(cc_initialize),
227 MAKE_FUNC_INFO(cc_shutdown),
228 MAKE_FUNC_INFO(cc_get_NC_info),
229 MAKE_FUNC_INFO(cc_free_NC_info),
234 FUNC_INFO leash_fi[] = {
235 MAKE_FUNC_INFO(Leash_get_default_lifetime),
236 MAKE_FUNC_INFO(Leash_get_default_renew_till),
237 MAKE_FUNC_INFO(Leash_get_default_forwardable),
238 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
239 MAKE_FUNC_INFO(Leash_get_default_proxiable),
240 MAKE_FUNC_INFO(Leash_get_default_publicip),
241 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
242 MAKE_FUNC_INFO(Leash_get_default_life_min),
243 MAKE_FUNC_INFO(Leash_get_default_life_max),
244 MAKE_FUNC_INFO(Leash_get_default_renew_min),
245 MAKE_FUNC_INFO(Leash_get_default_renew_max),
246 MAKE_FUNC_INFO(Leash_get_default_renewable),
250 FUNC_INFO leash_opt_fi[] = {
251 MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
256 FUNC_INFO k5_fi[] = {
257 MAKE_FUNC_INFO(krb5_change_password),
258 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
259 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
260 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
261 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
262 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
263 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
264 MAKE_FUNC_INFO(krb5_get_init_creds_password),
265 MAKE_FUNC_INFO(krb5_build_principal_ext),
266 MAKE_FUNC_INFO(krb5_cc_get_name),
267 MAKE_FUNC_INFO(krb5_cc_resolve),
268 MAKE_FUNC_INFO(krb5_cc_default),
269 MAKE_FUNC_INFO(krb5_cc_default_name),
270 MAKE_FUNC_INFO(krb5_cc_set_default_name),
271 MAKE_FUNC_INFO(krb5_cc_initialize),
272 MAKE_FUNC_INFO(krb5_cc_destroy),
273 MAKE_FUNC_INFO(krb5_cc_close),
274 MAKE_FUNC_INFO(krb5_cc_copy_creds),
275 MAKE_FUNC_INFO(krb5_cc_store_cred),
276 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
277 MAKE_FUNC_INFO(krb5_cc_get_principal),
278 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
279 MAKE_FUNC_INFO(krb5_cc_next_cred),
280 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
281 MAKE_FUNC_INFO(krb5_cc_remove_cred),
282 MAKE_FUNC_INFO(krb5_cc_set_flags),
283 MAKE_FUNC_INFO(krb5_cc_get_type),
284 MAKE_FUNC_INFO(krb5_free_context),
285 MAKE_FUNC_INFO(krb5_free_cred_contents),
286 MAKE_FUNC_INFO(krb5_free_principal),
287 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
288 MAKE_FUNC_INFO(krb5_init_context),
289 MAKE_FUNC_INFO(krb5_parse_name),
290 MAKE_FUNC_INFO(krb5_timeofday),
291 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
292 MAKE_FUNC_INFO(krb5_unparse_name),
293 MAKE_FUNC_INFO(krb5_get_credentials),
294 MAKE_FUNC_INFO(krb5_mk_req),
295 MAKE_FUNC_INFO(krb5_sname_to_principal),
296 MAKE_FUNC_INFO(krb5_get_credentials_renew),
297 MAKE_FUNC_INFO(krb5_free_data),
298 MAKE_FUNC_INFO(krb5_free_data_contents),
299 MAKE_FUNC_INFO(krb5_free_unparsed_name),
300 MAKE_FUNC_INFO(krb5_os_localaddr),
301 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
302 MAKE_FUNC_INFO(krb5_copy_data),
303 MAKE_FUNC_INFO(krb5_free_creds),
304 MAKE_FUNC_INFO(krb5_build_principal),
305 MAKE_FUNC_INFO(krb5_get_renewed_creds),
306 MAKE_FUNC_INFO(krb5_free_addresses),
307 MAKE_FUNC_INFO(krb5_get_default_config_files),
308 MAKE_FUNC_INFO(krb5_free_config_files),
309 MAKE_FUNC_INFO(krb5_get_default_realm),
310 MAKE_FUNC_INFO(krb5_free_default_realm),
311 MAKE_FUNC_INFO(krb5_free_ticket),
312 MAKE_FUNC_INFO(krb5_decode_ticket),
313 MAKE_FUNC_INFO(krb5_get_host_realm),
314 MAKE_FUNC_INFO(krb5_free_host_realm),
315 MAKE_FUNC_INFO(krb5_free_addresses),
316 MAKE_FUNC_INFO(krb5_c_random_make_octets),
321 FUNC_INFO k4_fi[] = {
322 MAKE_FUNC_INFO(krb_get_cred),
323 MAKE_FUNC_INFO(krb_get_tf_realm),
324 MAKE_FUNC_INFO(krb_mk_req),
325 MAKE_FUNC_INFO(tkt_string),
331 FUNC_INFO k524_fi[] = {
332 MAKE_FUNC_INFO(krb524_init_ets),
333 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
338 FUNC_INFO profile_fi[] = {
339 MAKE_FUNC_INFO(profile_init),
340 MAKE_FUNC_INFO(profile_release),
341 MAKE_FUNC_INFO(profile_get_subsection_names),
342 MAKE_FUNC_INFO(profile_free_list),
343 MAKE_FUNC_INFO(profile_get_string),
344 MAKE_FUNC_INFO(profile_release_string),
348 FUNC_INFO ce_fi[] = {
349 MAKE_FUNC_INFO(com_err),
350 MAKE_FUNC_INFO(error_message),
354 FUNC_INFO service_fi[] = {
355 MAKE_FUNC_INFO(OpenSCManagerA),
356 MAKE_FUNC_INFO(OpenServiceA),
357 MAKE_FUNC_INFO(QueryServiceStatus),
358 MAKE_FUNC_INFO(CloseServiceHandle),
360 MAKE_FUNC_INFO(LsaNtStatusToWinError),
361 #endif /* USE_MS2MIT */
366 FUNC_INFO lsa_fi[] = {
367 MAKE_FUNC_INFO(LsaConnectUntrusted),
368 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
369 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
370 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
371 MAKE_FUNC_INFO(LsaGetLogonSessionData),
374 #endif /* USE_MS2MIT */
376 /* Static Prototypes */
377 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
378 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
379 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
380 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
381 void *data, const char *name, const char *banner, int num_prompts,
382 krb5_prompt prompts[]);
385 /* Static Declarations */
386 static int inited = 0;
387 static int mid_cnt = 0;
388 static struct textField * mid_tb = NULL;
389 static HINSTANCE hKrb5 = 0;
391 static HINSTANCE hKrb4 = 0;
392 #endif /* USE_KRB4 */
394 static HINSTANCE hKrb524 = 0;
397 static HINSTANCE hSecur32 = 0;
398 #endif /* USE_MS2MIT */
399 static HINSTANCE hAdvApi32 = 0;
400 static HINSTANCE hComErr = 0;
401 static HINSTANCE hService = 0;
402 static HINSTANCE hProfile = 0;
404 static HINSTANCE hLeash = 0;
405 static HINSTANCE hLeashOpt = 0;
407 static HINSTANCE hCCAPI = 0;
408 static struct principal_ccache_data * princ_cc_data = NULL;
409 static struct cell_principal_map * cell_princ_map = NULL;
414 static int inited = 0;
417 char mutexName[MAX_PATH];
418 HANDLE hMutex = NULL;
420 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
422 hMutex = CreateMutex( NULL, TRUE, mutexName );
423 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
424 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
430 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
431 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
432 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
434 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
435 #endif /* USE_KRB4 */
436 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
438 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
439 #endif /* USE_MS2MIT */
441 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
444 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
445 LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
447 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
449 if ( KFW_is_available() ) {
450 char rootcell[MAXCELLCHARS+1];
452 KFW_import_windows_lsa();
453 #endif /* USE_MS2MIT */
454 KFW_import_ccache_data();
455 KFW_AFS_renew_expiring_tokens();
457 /* WIN32 NOTE: no way to get max chars */
458 if (!cm_GetRootCellName(rootcell))
459 KFW_AFS_renew_token_for_cell(rootcell);
462 ReleaseMutex(hMutex);
472 FreeLibrary(hLeashOpt);
478 FreeLibrary(hKrb524);
484 FreeLibrary(hSecur32);
485 #endif /* USE_MS2MIT */
487 FreeLibrary(hService);
489 FreeLibrary(hComErr);
491 FreeLibrary(hProfile);
495 #endif /* USE_KRB4 */
500 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
503 static int init = TRUE;
504 static int bIsWow64 = FALSE;
508 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
510 hModule = GetModuleHandle(TEXT("kernel32"));
512 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
514 if (NULL != fnIsWow64Process)
516 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
518 // on error, assume FALSE.
519 // in other words, do nothing.
522 FreeLibrary(hModule);
530 KFW_accept_dotted_usernames(void)
536 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
537 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
538 if (code == ERROR_SUCCESS) {
540 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
541 (BYTE *) &value, &len);
542 RegCloseKey(parmKey);
544 if (code != ERROR_SUCCESS) {
545 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
546 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
547 if (code == ERROR_SUCCESS) {
549 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
550 (BYTE *) &value, &len);
551 RegCloseKey (parmKey);
565 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
566 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
567 if (code == ERROR_SUCCESS) {
568 len = sizeof(use524);
569 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
570 (BYTE *) &use524, &len);
571 RegCloseKey(parmKey);
573 if (code != ERROR_SUCCESS) {
574 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
575 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
576 if (code == ERROR_SUCCESS) {
577 len = sizeof(use524);
578 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
579 (BYTE *) &use524, &len);
580 RegCloseKey (parmKey);
587 KFW_is_available(void)
593 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
594 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
595 if (code == ERROR_SUCCESS) {
596 len = sizeof(enableKFW);
597 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
598 (BYTE *) &enableKFW, &len);
599 RegCloseKey (parmKey);
602 if (code != ERROR_SUCCESS) {
603 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
604 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
605 if (code == ERROR_SUCCESS) {
606 len = sizeof(enableKFW);
607 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
608 (BYTE *) &enableKFW, &len);
609 RegCloseKey (parmKey);
617 if ( hKrb5 && hComErr && hService &&
620 #endif /* USE_MS2MIT */
633 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
634 int FreeContextFlag, krb5_context * ctx,
639 int krb5Error = ((int)(rc & 255));
651 errText = perror_message(rc);
652 _snprintf(message, sizeof(message),
653 "%s\n(Kerberos error %ld)\n\n%s failed",
658 if ( IsDebuggerPresent() )
659 OutputDebugString(message);
661 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
664 if (FreeContextFlag == 1)
666 if (ctx && *ctx != NULL)
668 if (cache && *cache != NULL) {
669 pkrb5_cc_close(*ctx, *cache);
673 pkrb5_free_context(*ctx);
682 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
684 struct principal_ccache_data * next = princ_cc_data;
685 krb5_principal principal = 0;
687 const char * ccname = NULL;
688 const char * cctype = NULL;
689 krb5_error_code code = 0;
690 krb5_error_code cc_code = 0;
696 if (ctx == 0 || cc == 0)
699 code = pkrb5_cc_get_principal(ctx, cc, &principal);
702 code = pkrb5_unparse_name(ctx, principal, &pname);
703 if ( code ) goto cleanup;
705 ccname = pkrb5_cc_get_name(ctx, cc);
706 if (!ccname) goto cleanup;
708 cctype = pkrb5_cc_get_type(ctx, cc);
709 if (!cctype) goto cleanup;
711 // Search the existing list to see if we have a match
713 for ( ; next ; next = next->next ) {
714 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
719 // If not, match add a new node to the beginning of the list and assign init it
721 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
722 next->next = princ_cc_data;
723 princ_cc_data = next;
724 next->principal = _strdup(pname);
725 next->ccache_name = malloc(strlen(ccname) + strlen(cctype) + 2);
726 if (next->ccache_name)
727 sprintf(next->ccache_name, "%s:%s", cctype, ccname);
728 next->from_lsa = lsa;
730 next->expiration_time = 0;
734 flags = 0; // turn off OPENCLOSE mode
735 code = pkrb5_cc_set_flags(ctx, cc, flags);
736 if ( code ) goto cleanup;
738 code = pkrb5_timeofday(ctx, &now);
740 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
742 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
743 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
745 // we found the ticket we are looking for
746 // check validity of timestamp
747 // We add a 5 minutes fudge factor to compensate for potential
748 // clock skew errors between the KDC and client OS
750 valid = ((creds.times.starttime > 0) &&
751 now >= (creds.times.starttime - 300) &&
752 now < (creds.times.endtime + 300) &&
753 !(creds.ticket_flags & TKT_FLG_INVALID));
755 if ( next->from_lsa) {
757 next->expiration_time = creds.times.endtime;
759 } else if ( valid ) {
761 next->expiration_time = creds.times.endtime;
762 next->renew = (creds.times.renew_till > creds.times.endtime) &&
763 (creds.ticket_flags & TKT_FLG_RENEWABLE);
766 next->expiration_time = 0;
770 pkrb5_free_cred_contents(ctx, &creds);
771 cc_code = KRB5_CC_END;
774 pkrb5_free_cred_contents(ctx, &creds);
777 if (cc_code == KRB5_CC_END) {
778 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
779 if (code) goto cleanup;
783 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
784 code = pkrb5_cc_set_flags(ctx, cc, flags);
787 pkrb5_free_unparsed_name(ctx,pname);
789 pkrb5_free_principal(ctx,principal);
793 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
795 struct principal_ccache_data * next = princ_cc_data;
796 char * response = NULL;
798 if ( !principal || !ccache )
802 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
804 // we always want to prefer the MS Kerberos LSA cache or
805 // the cache afscreds created specifically for the principal
806 // if the current entry is either one, drop the previous find
807 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
810 response = _strdup(next->ccache_name);
811 // MS Kerberos LSA is our best option so use it and quit
812 if ( next->from_lsa )
826 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
828 struct principal_ccache_data ** next = &princ_cc_data;
830 if ( !pname && !ccname )
834 if ( !strcmp((*next)->principal,pname) ||
835 !strcmp((*next)->ccache_name,ccname) ) {
837 free((*next)->principal);
838 free((*next)->ccache_name);
840 (*next) = (*next)->next;
847 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
849 struct cell_principal_map * next = cell_princ_map;
851 // Search the existing list to see if we have a match
853 for ( ; next ; next = next->next ) {
854 if ( !strcmp(next->cell, cell) ) {
855 if ( !strcmp(next->principal,pname) ) {
856 next->active = active;
859 // OpenAFS currently has a restriction of one active token per cell
860 // Therefore, whenever we update the table with a new active cell we
861 // must mark all of the other principal to cell entries as inactive.
869 // If not, match add a new node to the beginning of the list and assign init it
871 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
872 next->next = cell_princ_map;
873 cell_princ_map = next;
874 next->principal = _strdup(pname);
875 next->cell = _strdup(cell);
876 next->active = active;
881 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
883 struct cell_principal_map ** next = &cell_princ_map;
885 if ( !pname && !cell )
889 if ( !strcmp((*next)->principal,pname) ||
890 !strcmp((*next)->cell,cell) ) {
892 free((*next)->principal);
895 (*next) = (*next)->next;
901 // Returns (if possible) a principal which has been known in
902 // the past to have been used to obtain tokens for the specified
904 // TODO: Attempt to return one which has not yet expired by checking
905 // the principal/ccache data
907 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
909 struct cell_principal_map * next_map = cell_princ_map;
910 const char * princ = NULL;
917 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
920 next_map = next_map->next;
923 if ( !principals || !count )
926 *principals = (char **) malloc(sizeof(char *) * count);
927 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
929 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
930 (*principals)[i++] = _strdup(next_map->principal);
937 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
940 struct cell_principal_map * next_map = cell_princ_map;
941 const char * princ = NULL;
947 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
950 next_map = next_map->next;
956 *cells = (char **) malloc(sizeof(char *) * count);
957 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
959 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
960 (*cells)[i++] = _strdup(next_map->cell);
966 /* Given a principal return an existing ccache or create one and return */
968 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
970 krb5_context ctx = NULL;
972 char * ccname = NULL;
973 krb5_error_code code;
975 if (!pkrb5_init_context)
981 code = pkrb5_init_context(&ctx);
982 if (code) goto cleanup;
986 code = pkrb5_unparse_name(ctx, principal, &pname);
987 if (code) goto cleanup;
989 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
990 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
991 ccname = (char *)malloc(strlen(pname) + 5);
992 sprintf(ccname,"API:%s",pname);
994 code = pkrb5_cc_resolve(ctx, ccname, cc);
996 code = pkrb5_cc_default(ctx, cc);
997 if (code) goto cleanup;
1004 pkrb5_free_unparsed_name(ctx,pname);
1005 if (ctx && (ctx != alt_ctx))
1006 pkrb5_free_context(ctx);
1011 // Import Microsoft Credentials into a new MIT ccache
1013 KFW_import_windows_lsa(void)
1015 krb5_context ctx = NULL;
1016 krb5_ccache cc = NULL;
1017 krb5_principal princ = NULL;
1018 char * pname = NULL;
1019 krb5_data * princ_realm;
1020 krb5_error_code code;
1021 char cell[128]="", realm[128]="", *def_realm = 0;
1023 DWORD dwMsLsaImport;
1025 if (!pkrb5_init_context)
1028 code = pkrb5_init_context(&ctx);
1029 if (code) goto cleanup;
1031 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
1032 if (code) goto cleanup;
1034 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
1036 code = pkrb5_cc_get_principal(ctx, cc, &princ);
1037 if ( code ) goto cleanup;
1039 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
1040 switch ( dwMsLsaImport ) {
1041 case 0: /* do not import */
1043 case 1: /* always import */
1045 case 2: { /* matching realm */
1046 char ms_realm[128] = "", *r;
1049 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
1050 *r = krb5_princ_realm(ctx, princ)->data[i];
1054 if (code = pkrb5_get_default_realm(ctx, &def_realm))
1057 if (strcmp(def_realm, ms_realm))
1065 code = pkrb5_unparse_name(ctx,princ,&pname);
1066 if ( code ) goto cleanup;
1068 princ_realm = krb5_princ_realm(ctx, princ);
1069 for ( i=0; i<princ_realm->length; i++ ) {
1070 realm[i] = princ_realm->data[i];
1071 cell[i] = tolower(princ_realm->data[i]);
1076 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
1077 if ( IsDebuggerPresent() ) {
1079 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1080 OutputDebugString(message);
1082 if ( code ) goto cleanup;
1084 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1088 pkrb5_free_unparsed_name(ctx,pname);
1090 pkrb5_free_principal(ctx,princ);
1092 pkrb5_free_default_realm(ctx, def_realm);
1094 pkrb5_cc_close(ctx,cc);
1096 pkrb5_free_context(ctx);
1098 #endif /* USE_MS2MIT */
1100 // If there are existing MIT credentials, copy them to a new
1101 // ccache named after the principal
1103 // Enumerate all existing MIT ccaches and construct entries
1104 // in the principal_ccache table
1106 // Enumerate all existing AFS Tokens and construct entries
1107 // in the cell_principal table
1109 KFW_import_ccache_data(void)
1111 krb5_context ctx = NULL;
1112 krb5_ccache cc = NULL;
1113 krb5_principal principal = NULL;
1115 krb5_error_code code;
1116 krb5_error_code cc_code;
1118 apiCB * cc_ctx = NULL;
1119 struct _infoNC ** pNCi = NULL;
1122 if ( !pcc_initialize )
1125 if ( IsDebuggerPresent() )
1126 OutputDebugString("KFW_import_ccache_data()\n");
1128 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1129 if (code) goto cleanup;
1131 code = pcc_get_NC_info(cc_ctx, &pNCi);
1132 if (code) goto cleanup;
1134 code = pkrb5_init_context(&ctx);
1135 if (code) goto cleanup;
1137 for ( i=0; pNCi[i]; i++ ) {
1138 if ( pNCi[i]->vers != CC_CRED_V5 )
1140 if ( IsDebuggerPresent() ) {
1141 OutputDebugString("Principal: ");
1142 OutputDebugString(pNCi[i]->principal);
1143 OutputDebugString(" in ccache ");
1144 OutputDebugString(pNCi[i]->name);
1145 OutputDebugString("\n");
1147 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1148 && strcmp(pNCi[i]->name,LSA_CCNAME)
1151 for ( j=0; pNCi[j]; j++ ) {
1152 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1158 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1159 if (code) goto loop_cleanup;
1162 krb5_ccache oldcc = 0;
1164 if ( IsDebuggerPresent() )
1165 OutputDebugString("copying ccache data to new ccache\n");
1167 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1168 if (code) goto loop_cleanup;
1169 code = pkrb5_cc_initialize(ctx, cc, principal);
1170 if (code) goto loop_cleanup;
1172 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1173 if (code) goto loop_cleanup;
1174 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1176 code = pkrb5_cc_close(ctx,cc);
1178 code = pkrb5_cc_close(ctx,oldcc);
1180 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1183 code = pkrb5_cc_close(ctx,oldcc);
1186 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1187 if (code) goto loop_cleanup;
1190 flags = 0; // turn off OPENCLOSE mode
1191 code = pkrb5_cc_set_flags(ctx, cc, flags);
1192 if ( code ) goto cleanup;
1194 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1196 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1198 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1199 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1200 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1201 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1202 if ( sname && cell && !strcmp("afs",sname->data) ) {
1203 struct ktc_principal aserver;
1204 struct ktc_principal aclient;
1205 struct ktc_token atoken;
1208 if ( IsDebuggerPresent() ) {
1209 OutputDebugString("Found AFS ticket: ");
1210 OutputDebugString(sname->data);
1212 OutputDebugString("/");
1213 OutputDebugString(cell->data);
1215 OutputDebugString("@");
1216 OutputDebugString(realm->data);
1217 OutputDebugString("\n");
1220 memset(&aserver, '\0', sizeof(aserver));
1221 strcpy(aserver.name, sname->data);
1222 strcpy(aserver.cell, cell->data);
1224 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1226 // Found a token in AFS Client Server which matches
1227 char pname[128], *p, *q;
1228 for ( p=pname, q=aclient.name; *q; p++, q++)
1230 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1234 if ( IsDebuggerPresent() ) {
1235 OutputDebugString("Found AFS token: ");
1236 OutputDebugString(pname);
1237 OutputDebugString("\n");
1240 if ( strcmp(pname,pNCi[i]->principal) )
1242 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1244 // Attempt to import it
1245 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1247 if ( IsDebuggerPresent() ) {
1248 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1251 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data,
1255 pLeash_get_default_lifetime(),
1256 #endif /* USE_LEASH */
1258 if ( IsDebuggerPresent() ) {
1260 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1261 OutputDebugString(message);
1264 } else if ( IsDebuggerPresent() ) {
1265 OutputDebugString("Found ticket: ");
1266 OutputDebugString(sname->data);
1267 if ( cell && cell->data ) {
1268 OutputDebugString("/");
1269 OutputDebugString(cell->data);
1271 OutputDebugString("@");
1272 OutputDebugString(realm->data);
1273 OutputDebugString("\n");
1275 pkrb5_free_cred_contents(ctx, &creds);
1278 if (cc_code == KRB5_CC_END) {
1279 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1280 if (cc_code) goto loop_cleanup;
1284 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1285 code = pkrb5_cc_set_flags(ctx, cc, flags);
1287 pkrb5_cc_close(ctx,cc);
1291 pkrb5_free_principal(ctx,principal);
1298 pkrb5_free_context(ctx);
1300 pcc_free_NC_info(cc_ctx, &pNCi);
1302 pcc_shutdown(&cc_ctx);
1307 KFW_AFS_get_cred( char * username,
1314 krb5_context ctx = NULL;
1315 krb5_ccache cc = NULL;
1316 char * realm = NULL, * userrealm = NULL;
1317 krb5_principal principal = NULL;
1318 char * pname = NULL;
1319 krb5_error_code code;
1320 char local_cell[MAXCELLCHARS+1];
1321 char **cells = NULL;
1323 struct afsconf_cell cellconfig;
1326 if (!pkrb5_init_context)
1329 if ( IsDebuggerPresent() ) {
1330 OutputDebugString("KFW_AFS_get_cred for token ");
1331 OutputDebugString(username);
1332 OutputDebugString(" in cell ");
1333 OutputDebugString(cell);
1334 OutputDebugString("\n");
1337 code = pkrb5_init_context(&ctx);
1338 if ( code ) goto cleanup;
1340 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1341 if ( code ) goto cleanup;
1343 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1345 userrealm = strchr(username,'@');
1347 pname = strdup(username);
1348 if (!KFW_accept_dotted_usernames()) {
1349 userrealm = strchr(pname, '@');
1352 /* handle kerberos iv notation */
1353 while ( dot = strchr(pname,'.') ) {
1359 pname = malloc(strlen(username) + strlen(realm) + 2);
1361 strcpy(pname, username);
1363 if (!KFW_accept_dotted_usernames()) {
1364 /* handle kerberos iv notation */
1365 while ( dot = strchr(pname,'.') ) {
1370 strcat(pname,realm);
1372 if ( IsDebuggerPresent() ) {
1373 OutputDebugString("Realm: ");
1374 OutputDebugString(realm);
1375 OutputDebugString("\n");
1378 code = pkrb5_parse_name(ctx, pname, &principal);
1379 if ( code ) goto cleanup;
1381 code = KFW_get_ccache(ctx, principal, &cc);
1382 if ( code ) goto cleanup;
1384 if ( lifetime == 0 )
1388 lifetime = pLeash_get_default_lifetime();
1391 if ( password && password[0] ) {
1392 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1397 1, /* forwardable */
1398 0, /* not proxiable */
1400 1, /* noaddresses */
1401 0 /* no public ip */
1403 pLeash_get_default_forwardable(),
1404 pLeash_get_default_proxiable(),
1405 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1406 pLeash_get_default_noaddresses(),
1407 pLeash_get_default_publicip()
1408 #endif /* USE_LEASH */
1411 if ( IsDebuggerPresent() ) {
1413 sprintf(message,"KFW_kinit() returns: %d\n",code);
1414 OutputDebugString(message);
1416 if ( code ) goto cleanup;
1418 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1421 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1422 if ( IsDebuggerPresent() ) {
1424 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1425 OutputDebugString(message);
1427 if ( code ) goto cleanup;
1429 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1431 // Attempt to obtain new tokens for other cells supported by the same
1433 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1434 if ( cell_count > 1 ) {
1435 while ( cell_count-- ) {
1436 if ( strcmp(cells[cell_count],cell) ) {
1437 if ( IsDebuggerPresent() ) {
1439 sprintf(message,"found another cell for the same principal: %s\n",cell);
1440 OutputDebugString(message);
1442 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1443 if ( code ) continue;
1445 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1446 if ( IsDebuggerPresent() ) {
1447 OutputDebugString("Realm: ");
1448 OutputDebugString(realm);
1449 OutputDebugString("\n");
1452 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1453 if ( IsDebuggerPresent() ) {
1455 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1456 OutputDebugString(message);
1459 free(cells[cell_count]);
1462 } else if ( cell_count == 1 ) {
1471 pkrb5_cc_close(ctx, cc);
1473 if ( code && reasonP ) {
1474 *reasonP = (char *)perror_message(code);
1480 KFW_AFS_destroy_tickets_for_cell(char * cell)
1482 krb5_context ctx = NULL;
1483 krb5_error_code code;
1485 char ** principals = NULL;
1487 if (!pkrb5_init_context)
1490 if ( IsDebuggerPresent() ) {
1491 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1492 OutputDebugString(cell);
1493 OutputDebugString("\n");
1496 code = pkrb5_init_context(&ctx);
1499 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1501 krb5_principal princ = 0;
1505 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1506 if ( cell_count > 1 ) {
1507 // TODO - What we really should do here is verify whether or not any of the
1508 // other cells which use this principal to obtain its credentials actually
1509 // have valid tokens or not. If they are currently using these credentials
1510 // we will skip them. For the time being we assume that if there is an active
1511 // map in the table that they are actively being used.
1515 code = pkrb5_parse_name(ctx, principals[count], &princ);
1516 if (code) goto loop_cleanup;
1518 code = KFW_get_ccache(ctx, princ, &cc);
1519 if (code) goto loop_cleanup;
1521 code = pkrb5_cc_destroy(ctx, cc);
1526 pkrb5_cc_close(ctx, cc);
1530 pkrb5_free_principal(ctx, princ);
1534 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1535 free(principals[count]);
1540 pkrb5_free_context(ctx);
1545 KFW_AFS_destroy_tickets_for_principal(char * user)
1547 krb5_context ctx = NULL;
1548 krb5_error_code code;
1550 char ** cells = NULL;
1551 krb5_principal princ = NULL;
1552 krb5_ccache cc = NULL;
1554 if (!pkrb5_init_context)
1557 if ( IsDebuggerPresent() ) {
1558 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1559 OutputDebugString(user);
1560 OutputDebugString("\n");
1563 code = pkrb5_init_context(&ctx);
1566 code = pkrb5_parse_name(ctx, user, &princ);
1567 if (code) goto loop_cleanup;
1569 code = KFW_get_ccache(ctx, princ, &cc);
1570 if (code) goto loop_cleanup;
1572 code = pkrb5_cc_destroy(ctx, cc);
1577 pkrb5_cc_close(ctx, cc);
1581 pkrb5_free_principal(ctx, princ);
1585 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1588 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1595 pkrb5_free_context(ctx);
1600 KFW_AFS_renew_expiring_tokens(void)
1602 krb5_error_code code = 0;
1603 krb5_context ctx = NULL;
1604 krb5_ccache cc = NULL;
1606 struct principal_ccache_data * pcc_next = princ_cc_data;
1609 const char * realm = NULL;
1610 char local_cell[MAXCELLCHARS+1]="";
1611 struct afsconf_cell cellconfig;
1613 if (!pkrb5_init_context)
1616 if ( pcc_next == NULL ) // nothing to do
1619 if ( IsDebuggerPresent() ) {
1620 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1623 code = pkrb5_init_context(&ctx);
1624 if (code) goto cleanup;
1626 code = pkrb5_timeofday(ctx, &now);
1627 if (code) goto cleanup;
1629 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1630 if ( pcc_next->expired )
1633 if ( now >= (pcc_next->expiration_time) ) {
1634 if ( !pcc_next->from_lsa ) {
1635 pcc_next->expired = 1;
1640 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1641 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1644 code = KFW_renew(ctx,cc);
1646 if ( code && pcc_next->from_lsa)
1648 #endif /* USE_MS2MIT */
1651 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1652 if (code) goto loop_cleanup;
1654 // Attempt to obtain new tokens for other cells supported by the same
1656 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1657 if ( cell_count > 0 ) {
1658 while ( cell_count-- ) {
1659 if ( IsDebuggerPresent() ) {
1660 OutputDebugString("Cell: ");
1661 OutputDebugString(cells[cell_count]);
1662 OutputDebugString("\n");
1664 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1665 if ( code ) continue;
1666 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1667 if ( IsDebuggerPresent() ) {
1668 OutputDebugString("Realm: ");
1669 OutputDebugString(realm);
1670 OutputDebugString("\n");
1672 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1673 if ( IsDebuggerPresent() ) {
1675 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1676 OutputDebugString(message);
1678 free(cells[cell_count]);
1686 pkrb5_cc_close(ctx,cc);
1693 pkrb5_cc_close(ctx,cc);
1695 pkrb5_free_context(ctx);
1702 KFW_AFS_renew_token_for_cell(char * cell)
1704 krb5_error_code code = 0;
1705 krb5_context ctx = NULL;
1707 char ** principals = NULL;
1709 if (!pkrb5_init_context)
1712 if ( IsDebuggerPresent() ) {
1713 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1714 OutputDebugString(cell);
1715 OutputDebugString("\n");
1718 code = pkrb5_init_context(&ctx);
1719 if (code) goto cleanup;
1721 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1723 // We know we must have a credential somewhere since we are
1724 // trying to renew a token
1726 KFW_import_ccache_data();
1727 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1730 krb5_principal princ = 0;
1731 krb5_principal service = 0;
1733 krb5_creds mcreds, creds;
1734 #endif /* COMMENT */
1736 const char * realm = NULL;
1737 struct afsconf_cell cellconfig;
1738 char local_cell[MAXCELLCHARS+1];
1741 code = pkrb5_parse_name(ctx, principals[count], &princ);
1742 if (code) goto loop_cleanup;
1744 code = KFW_get_ccache(ctx, princ, &cc);
1745 if (code) goto loop_cleanup;
1747 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1748 if ( code ) goto loop_cleanup;
1750 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1751 if ( IsDebuggerPresent() ) {
1752 OutputDebugString("Realm: ");
1753 OutputDebugString(realm);
1754 OutputDebugString("\n");
1758 /* krb5_cc_remove_cred() is not implemented
1761 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1762 realm, "afs", cell, NULL);
1764 memset(&mcreds, 0, sizeof(krb5_creds));
1765 mcreds.client = princ;
1766 mcreds.server = service;
1768 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1770 if ( IsDebuggerPresent() ) {
1771 char * cname, *sname;
1772 pkrb5_unparse_name(ctx, creds.client, &cname);
1773 pkrb5_unparse_name(ctx, creds.server, &sname);
1774 OutputDebugString("Removing credential for client \"");
1775 OutputDebugString(cname);
1776 OutputDebugString("\" and service \"");
1777 OutputDebugString(sname);
1778 OutputDebugString("\"\n");
1779 pkrb5_free_unparsed_name(ctx,cname);
1780 pkrb5_free_unparsed_name(ctx,sname);
1783 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1784 pkrb5_free_principal(ctx, creds.client);
1785 pkrb5_free_principal(ctx, creds.server);
1788 #endif /* COMMENT */
1790 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1791 if ( IsDebuggerPresent() ) {
1793 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1794 OutputDebugString(message);
1799 pkrb5_cc_close(ctx, cc);
1803 pkrb5_free_principal(ctx, princ);
1807 pkrb5_free_principal(ctx, service);
1811 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1812 free(principals[count]);
1816 code = -1; // we did not renew the tokens
1820 pkrb5_free_context(ctx);
1821 return (code ? FALSE : TRUE);
1826 KFW_AFS_renew_tokens_for_all_cells(void)
1828 struct cell_principal_map * next = cell_princ_map;
1830 if ( IsDebuggerPresent() )
1831 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1836 for ( ; next ; next = next->next ) {
1838 KFW_AFS_renew_token_for_cell(next->cell);
1844 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1846 krb5_error_code code = 0;
1847 krb5_context ctx = NULL;
1848 krb5_ccache cc = NULL;
1849 krb5_principal me = NULL;
1850 krb5_principal server = NULL;
1851 krb5_creds my_creds;
1852 krb5_data *realm = NULL;
1854 if (!pkrb5_init_context)
1857 memset(&my_creds, 0, sizeof(krb5_creds));
1862 code = pkrb5_init_context(&ctx);
1863 if (code) goto cleanup;
1869 code = pkrb5_cc_default(ctx, &cc);
1870 if (code) goto cleanup;
1873 code = pkrb5_cc_get_principal(ctx, cc, &me);
1874 if (code) goto cleanup;
1876 realm = krb5_princ_realm(ctx, me);
1878 code = pkrb5_build_principal_ext(ctx, &server,
1879 realm->length,realm->data,
1880 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1881 realm->length,realm->data,
1886 if ( IsDebuggerPresent() ) {
1887 char * cname, *sname;
1888 pkrb5_unparse_name(ctx, me, &cname);
1889 pkrb5_unparse_name(ctx, server, &sname);
1890 OutputDebugString("Renewing credential for client \"");
1891 OutputDebugString(cname);
1892 OutputDebugString("\" and service \"");
1893 OutputDebugString(sname);
1894 OutputDebugString("\"\n");
1895 pkrb5_free_unparsed_name(ctx,cname);
1896 pkrb5_free_unparsed_name(ctx,sname);
1899 my_creds.client = me;
1900 my_creds.server = server;
1902 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1904 if ( IsDebuggerPresent() ) {
1906 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1907 OutputDebugString(message);
1912 code = pkrb5_cc_initialize(ctx, cc, me);
1914 if ( IsDebuggerPresent() ) {
1916 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1917 OutputDebugString(message);
1922 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1924 if ( IsDebuggerPresent() ) {
1926 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1927 OutputDebugString(message);
1933 if (my_creds.client == me)
1934 my_creds.client = 0;
1935 if (my_creds.server == server)
1936 my_creds.server = 0;
1937 pkrb5_free_cred_contents(ctx, &my_creds);
1939 pkrb5_free_principal(ctx, me);
1941 pkrb5_free_principal(ctx, server);
1942 if (cc && (cc != alt_cc))
1943 pkrb5_cc_close(ctx, cc);
1944 if (ctx && (ctx != alt_ctx))
1945 pkrb5_free_context(ctx);
1950 KFW_kinit( krb5_context alt_ctx,
1953 char *principal_name,
1955 krb5_deltat lifetime,
1958 krb5_deltat renew_life,
1963 krb5_error_code code = 0;
1964 krb5_context ctx = NULL;
1965 krb5_ccache cc = NULL;
1966 krb5_principal me = NULL;
1968 krb5_creds my_creds;
1969 krb5_get_init_creds_opt options;
1970 krb5_address ** addrs = NULL;
1971 int i = 0, addr_count = 0;
1973 if (!pkrb5_init_context)
1976 pkrb5_get_init_creds_opt_init(&options);
1977 memset(&my_creds, 0, sizeof(my_creds));
1985 code = pkrb5_init_context(&ctx);
1986 if (code) goto cleanup;
1992 code = pkrb5_cc_default(ctx, &cc);
1993 if (code) goto cleanup;
1996 code = pkrb5_parse_name(ctx, principal_name, &me);
2000 code = pkrb5_unparse_name(ctx, me, &name);
2008 lifetime = pLeash_get_default_lifetime();
2009 #endif /* USE_LEASH */
2016 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
2017 pkrb5_get_init_creds_opt_set_forwardable(&options,
2018 forwardable ? 1 : 0);
2019 pkrb5_get_init_creds_opt_set_proxiable(&options,
2021 pkrb5_get_init_creds_opt_set_renew_life(&options,
2024 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
2028 // we are going to add the public IP address specified by the user
2029 // to the list provided by the operating system
2030 krb5_address ** local_addrs=NULL;
2033 pkrb5_os_localaddr(ctx, &local_addrs);
2034 while ( local_addrs[i++] );
2037 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
2039 pkrb5_free_addresses(ctx, local_addrs);
2042 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
2044 while ( local_addrs[i] ) {
2045 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2046 if (addrs[i] == NULL) {
2047 pkrb5_free_addresses(ctx, local_addrs);
2051 addrs[i]->magic = local_addrs[i]->magic;
2052 addrs[i]->addrtype = local_addrs[i]->addrtype;
2053 addrs[i]->length = local_addrs[i]->length;
2054 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2055 if (!addrs[i]->contents) {
2056 pkrb5_free_addresses(ctx, local_addrs);
2060 memcpy(addrs[i]->contents,local_addrs[i]->contents,
2061 local_addrs[i]->length); /* safe */
2064 pkrb5_free_addresses(ctx, local_addrs);
2066 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2067 if (addrs[i] == NULL)
2070 addrs[i]->magic = KV5M_ADDRESS;
2071 addrs[i]->addrtype = AF_INET;
2072 addrs[i]->length = 4;
2073 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2074 if (!addrs[i]->contents)
2077 netIPAddr = htonl(publicIP);
2078 memcpy(addrs[i]->contents,&netIPAddr,4);
2080 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
2085 code = pkrb5_get_init_creds_password(ctx,
2088 password, // password
2089 KRB5_prompter, // prompter
2090 hParent, // prompter data
2097 code = pkrb5_cc_initialize(ctx, cc, me);
2101 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
2107 for ( i=0;i<addr_count;i++ ) {
2109 if ( addrs[i]->contents )
2110 free(addrs[i]->contents);
2115 if (my_creds.client == me)
2116 my_creds.client = 0;
2117 pkrb5_free_cred_contents(ctx, &my_creds);
2119 pkrb5_free_unparsed_name(ctx, name);
2121 pkrb5_free_principal(ctx, me);
2122 if (cc && (cc != alt_cc))
2123 pkrb5_cc_close(ctx, cc);
2124 if (ctx && (ctx != alt_ctx))
2125 pkrb5_free_context(ctx);
2131 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2133 krb5_context ctx = NULL;
2134 krb5_ccache cc = NULL;
2135 krb5_error_code code;
2137 if (!pkrb5_init_context)
2146 code = pkrb5_init_context(&ctx);
2147 if (code) goto cleanup;
2153 code = pkrb5_cc_default(ctx, &cc);
2154 if (code) goto cleanup;
2157 code = pkrb5_cc_destroy(ctx, cc);
2158 if ( !code ) cc = 0;
2161 if (cc && (cc != alt_cc))
2162 pkrb5_cc_close(ctx, cc);
2163 if (ctx && (ctx != alt_ctx))
2164 pkrb5_free_context(ctx);
2172 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2174 NTSTATUS Status = 0;
2176 TOKEN_STATISTICS Stats;
2182 *ppSessionData = NULL;
2184 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2188 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2189 CloseHandle( TokenHandle );
2193 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2194 if ( FAILED(Status) || !ppSessionData )
2201 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2202 // cache. It validates whether or not it is reasonable to assume that if we
2203 // attempted to retrieve valid tickets we could do so. Microsoft does not
2204 // automatically renew expired tickets. Therefore, the cache could contain
2205 // expired or invalid tickets. Microsoft also caches the user's password
2206 // and will use it to retrieve new TGTs if the cache is empty and tickets
2210 MSLSA_IsKerberosLogon(VOID)
2212 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2213 BOOL Success = FALSE;
2215 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2216 if ( pSessionData->AuthenticationPackage.Buffer ) {
2222 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2223 usLength = (pSessionData->AuthenticationPackage).Length;
2226 lstrcpynW (buffer, usBuffer, usLength);
2227 lstrcatW (buffer,L"");
2228 if ( !lstrcmpW(L"Kerberos",buffer) )
2232 pLsaFreeReturnBuffer(pSessionData);
2236 #endif /* USE_MS2MIT */
2238 static BOOL CALLBACK
2239 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2243 switch ( message ) {
2245 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2247 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2250 for ( i=0; i < mid_cnt ; i++ ) {
2251 if (mid_tb[i].echo == 0)
2252 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2253 else if (mid_tb[i].echo == 2)
2254 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2259 switch ( LOWORD(wParam) ) {
2261 for ( i=0; i < mid_cnt ; i++ ) {
2262 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2263 *mid_tb[i].buf = '\0';
2267 EndDialog(hDialog, LOWORD(wParam));
2275 lpwAlign( LPWORD lpIn )
2279 ul = (ULONG_PTR) lpIn;
2283 return (LPWORD) ul;;
2287 * dialog widths are measured in 1/4 character widths
2288 * dialog height are measured in 1/8 character heights
2292 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2293 char * ptext[], int numlines, int width,
2294 int tb_cnt, struct textField * tb)
2298 LPDLGITEMTEMPLATE lpdit;
2304 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2311 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2313 // Define a dialog box.
2315 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2316 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2317 | DS_SETFOREGROUND | DS_3DLOOK
2318 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2319 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2322 lpdt->cx = 20 + width * 4;
2323 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2325 lpw = (LPWORD) (lpdt + 1);
2326 *lpw++ = 0; // no menu
2327 *lpw++ = 0; // predefined dialog box class (by default)
2329 lpwsz = (LPWSTR) lpw;
2330 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2332 *lpw++ = 8; // font size (points)
2333 lpwsz = (LPWSTR) lpw;
2334 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2338 //-----------------------
2339 // Define an OK button.
2340 //-----------------------
2341 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2342 lpdit = (LPDLGITEMTEMPLATE) lpw;
2343 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2344 lpdit->dwExtendedStyle = 0;
2345 lpdit->x = (lpdt->cx - 14)/4 - 20;
2346 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2349 lpdit->id = IDOK; // OK button identifier
2351 lpw = (LPWORD) (lpdit + 1);
2353 *lpw++ = 0x0080; // button class
2355 lpwsz = (LPWSTR) lpw;
2356 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2358 *lpw++ = 0; // no creation data
2360 //-----------------------
2361 // Define an Cancel button.
2362 //-----------------------
2363 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2364 lpdit = (LPDLGITEMTEMPLATE) lpw;
2365 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2366 lpdit->dwExtendedStyle = 0;
2367 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2368 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2371 lpdit->id = IDCANCEL; // CANCEL button identifier
2373 lpw = (LPWORD) (lpdit + 1);
2375 *lpw++ = 0x0080; // button class
2377 lpwsz = (LPWSTR) lpw;
2378 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2380 *lpw++ = 0; // no creation data
2382 /* Add controls for preface data */
2383 for ( i=0; i<numlines; i++) {
2384 /*-----------------------
2385 * Define a static text control.
2386 *-----------------------*/
2387 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2388 lpdit = (LPDLGITEMTEMPLATE) lpw;
2389 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2390 lpdit->dwExtendedStyle = 0;
2392 lpdit->y = 10 + i * 14;
2393 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2395 lpdit->id = ID_TEXT + i; // text identifier
2397 lpw = (LPWORD) (lpdit + 1);
2399 *lpw++ = 0x0082; // static class
2401 lpwsz = (LPWSTR) lpw;
2402 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2403 -1, lpwsz, 2*width);
2405 *lpw++ = 0; // no creation data
2408 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2409 int len = (int)strlen(tb[i].label);
2414 for ( i=0; i<tb_cnt; i++) {
2416 /*-----------------------
2417 * Define a static text control.
2418 *-----------------------*/
2419 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2420 lpdit = (LPDLGITEMTEMPLATE) lpw;
2421 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2422 lpdit->dwExtendedStyle = 0;
2424 lpdit->y = 10 + (numlines + i + 1) * 14;
2425 lpdit->cx = pwid * 4;
2427 lpdit->id = ID_TEXT + numlines + i; // text identifier
2429 lpw = (LPWORD) (lpdit + 1);
2431 *lpw++ = 0x0082; // static class
2433 lpwsz = (LPWSTR) lpw;
2434 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2437 *lpw++ = 0; // no creation data
2439 /*-----------------------
2440 * Define an edit control.
2441 *-----------------------*/
2442 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2443 lpdit = (LPDLGITEMTEMPLATE) lpw;
2444 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2445 lpdit->dwExtendedStyle = 0;
2446 lpdit->x = 10 + (pwid + 1) * 4;
2447 lpdit->y = 10 + (numlines + i + 1) * 14;
2448 lpdit->cx = (width - (pwid + 1)) * 4;
2450 lpdit->id = ID_MID_TEXT + i; // identifier
2452 lpw = (LPWORD) (lpdit + 1);
2454 *lpw++ = 0x0081; // edit class
2456 lpwsz = (LPWSTR) lpw;
2457 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2460 *lpw++ = 0; // no creation data
2464 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2465 hwndOwner, (DLGPROC) MultiInputDialogProc);
2469 case 0: /* Timeout */
2477 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2478 MessageBox(hwndOwner,
2481 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2488 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2490 HINSTANCE hInst = 0;
2494 char * plines[16], *p = preface ? preface : "";
2497 for ( i=0; i<16; i++ )
2500 while (*p && numlines < 16) {
2501 plines[numlines++] = p;
2502 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2503 if ( *p == '\r' && *(p+1) == '\n' ) {
2506 } else if ( *p == '\n' ) {
2509 if ( strlen(plines[numlines-1]) > maxwidth )
2510 maxwidth = (int)strlen(plines[numlines-1]);
2513 for ( i=0;i<n;i++ ) {
2514 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2515 if ( maxwidth < len )
2519 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2522 static krb5_error_code KRB5_CALLCONV
2523 KRB5_prompter( krb5_context context,
2528 krb5_prompt prompts[])
2530 krb5_error_code errcode = 0;
2532 struct textField * tb = NULL;
2533 int len = 0, blen=0, nlen=0;
2534 HWND hParent = (HWND)data;
2537 nlen = (int)strlen(name)+2;
2540 blen = (int)strlen(banner)+2;
2542 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2545 memset(tb,0,sizeof(struct textField) * num_prompts);
2546 for ( i=0; i < num_prompts; i++ ) {
2547 tb[i].buf = prompts[i].reply->data;
2548 tb[i].len = prompts[i].reply->length;
2549 tb[i].label = prompts[i].prompt;
2551 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2554 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2556 for ( i=0; i < num_prompts; i++ )
2557 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2565 for (i = 0; i < num_prompts; i++) {
2566 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2573 KFW_AFS_wait_for_service_start(void)
2578 CurrentState = SERVICE_START_PENDING;
2579 memset(HostName, '\0', sizeof(HostName));
2580 gethostname(HostName, sizeof(HostName));
2582 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2584 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2586 if ( IsDebuggerPresent() ) {
2587 switch ( CurrentState ) {
2588 case SERVICE_STOPPED:
2589 OutputDebugString("SERVICE_STOPPED\n");
2591 case SERVICE_START_PENDING:
2592 OutputDebugString("SERVICE_START_PENDING\n");
2594 case SERVICE_STOP_PENDING:
2595 OutputDebugString("SERVICE_STOP_PENDING\n");
2597 case SERVICE_RUNNING:
2598 OutputDebugString("SERVICE_RUNNING\n");
2600 case SERVICE_CONTINUE_PENDING:
2601 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2603 case SERVICE_PAUSE_PENDING:
2604 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2606 case SERVICE_PAUSED:
2607 OutputDebugString("SERVICE_PAUSED\n");
2610 OutputDebugString("UNKNOWN Service State\n");
2613 if (CurrentState == SERVICE_STOPPED)
2615 if (CurrentState == SERVICE_RUNNING)
2631 memset(HostName, '\0', sizeof(HostName));
2632 gethostname(HostName, sizeof(HostName));
2633 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2635 if (CurrentState != SERVICE_RUNNING)
2638 rc = ktc_ForgetAllTokens();
2644 #define ALLOW_REGISTER 1
2646 ViceIDToUsername(char *username,
2647 char *realm_of_user,
2648 char *realm_of_cell,
2650 struct ktc_principal *aclient,
2651 struct ktc_principal *aserver,
2652 struct ktc_token *atoken)
2654 static char lastcell[MAXCELLCHARS+1] = { 0 };
2655 static char confdir[512] = { 0 };
2656 #ifdef AFS_ID_TO_NAME
2657 char username_copy[BUFSIZ];
2658 #endif /* AFS_ID_TO_NAME */
2659 long viceId = ANONYMOUSID; /* AFS uid of user */
2661 #ifdef ALLOW_REGISTER
2663 #endif /* ALLOW_REGISTER */
2665 if (confdir[0] == '\0')
2666 cm_GetConfigDir(confdir, sizeof(confdir));
2668 strcpy(lastcell, aserver->cell);
2670 if (!pr_Initialize (0, confdir, aserver->cell)) {
2671 char sname[PR_MAXNAMELEN];
2672 strncpy(sname, username, PR_MAXNAMELEN);
2673 sname[PR_MAXNAMELEN-1] = '\0';
2674 status = pr_SNameToId (sname, &viceId);
2679 * This is a crock, but it is Transarc's crock, so
2680 * we have to play along in order to get the
2681 * functionality. The way the afs id is stored is
2682 * as a string in the username field of the token.
2683 * Contrary to what you may think by looking at
2684 * the code for tokens, this hack (AFS ID %d) will
2685 * not work if you change %d to something else.
2689 * This code is taken from cklog -- it lets people
2690 * automatically register with the ptserver in foreign cells
2693 #ifdef ALLOW_REGISTER
2695 if (viceId != ANONYMOUSID) {
2696 #else /* ALLOW_REGISTER */
2697 if ((status == 0) && (viceId != ANONYMOUSID))
2698 #endif /* ALLOW_REGISTER */
2700 #ifdef AFS_ID_TO_NAME
2701 strncpy(username_copy, username, BUFSIZ);
2702 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2703 #endif /* AFS_ID_TO_NAME */
2705 #ifdef ALLOW_REGISTER
2706 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2708 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2709 strcpy(aclient->instance, "");
2710 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2711 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2713 if (status = pr_Initialize(1L, confdir, aserver->cell))
2715 status = pr_CreateUser(username, &id);
2719 #ifdef AFS_ID_TO_NAME
2720 strncpy(username_copy, username, BUFSIZ);
2721 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2722 #endif /* AFS_ID_TO_NAME */
2725 #endif /* ALLOW_REGISTER */
2732 krb5_context alt_ctx,
2737 int lifetime, /* unused parameter */
2745 #endif /* USE_KRB4 */
2746 struct ktc_principal aserver;
2747 struct ktc_principal aclient;
2748 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2749 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2750 char local_cell[MAXCELLCHARS+1];
2751 char Dmycell[MAXCELLCHARS+1];
2752 struct ktc_token atoken;
2753 struct ktc_token btoken;
2754 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2755 char RealmName[128];
2757 char ServiceName[128];
2761 krb5_context ctx = NULL;
2762 krb5_ccache cc = NULL;
2764 krb5_creds * k5creds = NULL;
2765 krb5_error_code code;
2766 krb5_principal client_principal = NULL;
2767 krb5_data * k5data = NULL;
2771 memset(HostName, '\0', sizeof(HostName));
2772 gethostname(HostName, sizeof(HostName));
2773 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2774 if ( IsDebuggerPresent() )
2775 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2778 if (CurrentState != SERVICE_RUNNING) {
2779 if ( IsDebuggerPresent() )
2780 OutputDebugString("AFSD Service NOT RUNNING\n");
2784 if (!pkrb5_init_context)
2787 memset(RealmName, '\0', sizeof(RealmName));
2788 memset(CellName, '\0', sizeof(CellName));
2789 memset(ServiceName, '\0', sizeof(ServiceName));
2790 memset(realm_of_user, '\0', sizeof(realm_of_user));
2791 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2792 if (cell && cell[0])
2793 strcpy(Dmycell, cell);
2795 memset(Dmycell, '\0', sizeof(Dmycell));
2797 // NULL or empty cell returns information on local cell
2798 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2800 // KFW_AFS_error(rc, "get_cellconfig()");
2807 code = pkrb5_init_context(&ctx);
2808 if (code) goto cleanup;
2814 code = pkrb5_cc_default(ctx, &cc);
2815 if (code) goto skip_krb5_init;
2818 memset((char *)&increds, 0, sizeof(increds));
2820 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2822 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2824 OutputDebugString("Principal Not Found for ccache\n");
2826 goto skip_krb5_init;
2829 if (!KFW_accept_dotted_usernames()) {
2830 /* look for client principals which cannot be distinguished
2831 * from Kerberos 4 multi-component principal names
2833 k5data = krb5_princ_component(ctx,client_principal,0);
2834 for ( i=0; i<k5data->length; i++ ) {
2835 if ( k5data->data[i] == '.' )
2838 if (i != k5data->length)
2840 OutputDebugString("Illegal Principal name contains dot in first component\n");
2841 rc = KRB5KRB_ERR_GENERIC;
2846 i = krb5_princ_realm(ctx, client_principal)->length;
2849 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2850 realm_of_user[i] = 0;
2855 if ( !try_krb5 || !realm_of_user[0] ) {
2856 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2865 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2867 if (strlen(service) == 0)
2868 strcpy(ServiceName, "afs");
2870 strcpy(ServiceName, service);
2872 if (strlen(cell) == 0)
2873 strcpy(CellName, local_cell);
2875 strcpy(CellName, cell);
2877 if (strlen(realm) == 0)
2878 strcpy(RealmName, realm_of_cell);
2880 strcpy(RealmName, realm);
2882 memset(&creds, '\0', sizeof(creds));
2887 /* First try service/cell@REALM */
2888 if (code = pkrb5_build_principal(ctx, &increds.server,
2889 (int)strlen(RealmName),
2898 increds.client = client_principal;
2899 increds.times.endtime = 0;
2900 /* Ask for DES since that is what V4 understands */
2901 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2904 if ( IsDebuggerPresent() ) {
2905 char * cname, *sname;
2906 pkrb5_unparse_name(ctx, increds.client, &cname);
2907 pkrb5_unparse_name(ctx, increds.server, &sname);
2908 OutputDebugString("Getting tickets for \"");
2909 OutputDebugString(cname);
2910 OutputDebugString("\" and service \"");
2911 OutputDebugString(sname);
2912 OutputDebugString("\"\n");
2913 pkrb5_free_unparsed_name(ctx,cname);
2914 pkrb5_free_unparsed_name(ctx,sname);
2917 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2918 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2919 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2920 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2921 /* Or service@REALM */
2922 pkrb5_free_principal(ctx,increds.server);
2924 code = pkrb5_build_principal(ctx, &increds.server,
2925 (int)strlen(RealmName),
2930 if ( IsDebuggerPresent() ) {
2931 char * cname, *sname;
2932 pkrb5_unparse_name(ctx, increds.client, &cname);
2933 pkrb5_unparse_name(ctx, increds.server, &sname);
2934 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2935 OutputDebugString("Trying again: getting tickets for \"");
2936 OutputDebugString(cname);
2937 OutputDebugString("\" and service \"");
2938 OutputDebugString(sname);
2939 OutputDebugString("\"\n");
2940 pkrb5_free_unparsed_name(ctx,cname);
2941 pkrb5_free_unparsed_name(ctx,sname);
2945 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2948 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2949 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2950 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2951 strcmp(RealmName, realm_of_cell)) {
2952 /* Or service/cell@REALM_OF_CELL */
2953 strcpy(RealmName, realm_of_cell);
2954 pkrb5_free_principal(ctx,increds.server);
2956 code = pkrb5_build_principal(ctx, &increds.server,
2957 (int)strlen(RealmName),
2963 if ( IsDebuggerPresent() ) {
2964 char * cname, *sname;
2965 pkrb5_unparse_name(ctx, increds.client, &cname);
2966 pkrb5_unparse_name(ctx, increds.server, &sname);
2967 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2968 OutputDebugString("Trying again: getting tickets for \"");
2969 OutputDebugString(cname);
2970 OutputDebugString("\" and service \"");
2971 OutputDebugString(sname);
2972 OutputDebugString("\"\n");
2973 pkrb5_free_unparsed_name(ctx,cname);
2974 pkrb5_free_unparsed_name(ctx,sname);
2978 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2981 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2982 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2983 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2984 /* Or service@REALM_OF_CELL */
2985 pkrb5_free_principal(ctx,increds.server);
2987 code = pkrb5_build_principal(ctx, &increds.server,
2988 (int)strlen(RealmName),
2993 if ( IsDebuggerPresent() ) {
2994 char * cname, *sname;
2995 pkrb5_unparse_name(ctx, increds.client, &cname);
2996 pkrb5_unparse_name(ctx, increds.server, &sname);
2997 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2998 OutputDebugString("Trying again: getting tickets for \"");
2999 OutputDebugString(cname);
3000 OutputDebugString("\" and service \"");
3001 OutputDebugString(sname);
3002 OutputDebugString("\"\n");
3003 pkrb5_free_unparsed_name(ctx,cname);
3004 pkrb5_free_unparsed_name(ctx,sname);
3008 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3013 if ( IsDebuggerPresent() ) {
3015 sprintf(message,"krb5_get_credentials returns: %d\n",code);
3016 OutputDebugString(message);
3022 /* This code inserts the entire K5 ticket into the token
3023 * No need to perform a krb524 translation which is
3024 * commented out in the code below
3026 if (KFW_use_krb524() ||
3027 k5creds->ticket.length > MAXKTCTICKETLEN)
3030 memset(&aserver, '\0', sizeof(aserver));
3031 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3032 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3034 memset(&atoken, '\0', sizeof(atoken));
3035 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
3036 atoken.startTime = k5creds->times.starttime;
3037 atoken.endTime = k5creds->times.endtime;
3038 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
3039 atoken.ticketLen = k5creds->ticket.length;
3040 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
3043 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3044 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3045 if ( rc == KTC_NOCM && retry < 20 ) {
3048 goto retry_gettoken5;
3053 if (atoken.kvno == btoken.kvno &&
3054 atoken.ticketLen == btoken.ticketLen &&
3055 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3056 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3058 /* Success - Nothing to do */
3062 // * Reset the "aclient" structure before we call ktc_SetToken.
3063 // * This structure was first set by the ktc_GetToken call when
3064 // * we were comparing whether identical tokens already existed.
3066 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
3067 strncpy(aclient.name, k5creds->client->data[0].data, len);
3068 aclient.name[len] = '\0';
3070 if ( k5creds->client->length > 1 ) {
3072 strcat(aclient.name, ".");
3073 p = aclient.name + strlen(aclient.name);
3074 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3075 strncpy(p, k5creds->client->data[1].data, len);
3078 aclient.instance[0] = '\0';
3080 strcpy(aclient.cell, realm_of_cell);
3082 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3083 /* For Khimaira, always append the realm name */
3084 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3086 strcat(aclient.name, "@");
3087 p = aclient.name + strlen(aclient.name);
3088 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3089 strncpy(p, k5creds->client->realm.data, len);
3093 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3094 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3095 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3096 &aclient, &aserver, &atoken);
3099 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3100 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3102 aclient.smbname[0] = '\0';
3105 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3107 goto cleanup; /* We have successfully inserted the token */
3113 /* Otherwise, the ticket could have been too large so try to
3114 * convert using the krb524d running with the KDC
3116 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3117 pkrb5_free_creds(ctx, k5creds);
3119 if ( IsDebuggerPresent() ) {
3121 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3122 OutputDebugString(message);
3127 #endif /* USE_KRB524 */
3131 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3132 if (code == NO_TKT_FIL) {
3133 // if the problem is that we have no krb4 tickets
3134 // do not attempt to continue
3137 if (code != KSUCCESS)
3138 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3140 if (code != KSUCCESS)
3142 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3144 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3149 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3151 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3166 memset(&aserver, '\0', sizeof(aserver));
3167 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3168 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3170 memset(&atoken, '\0', sizeof(atoken));
3171 atoken.kvno = creds.kvno;
3172 atoken.startTime = creds.issue_date;
3173 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3174 memcpy(&atoken.sessionKey, creds.session, 8);
3175 atoken.ticketLen = creds.ticket_st.length;
3176 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3179 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3180 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3181 if ( rc == KTC_NOCM && retry < 20 ) {
3184 goto retry_gettoken;
3186 KFW_AFS_error(rc, "ktc_GetToken()");
3191 if (atoken.kvno == btoken.kvno &&
3192 atoken.ticketLen == btoken.ticketLen &&
3193 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3194 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3199 // * Reset the "aclient" structure before we call ktc_SetToken.
3200 // * This structure was first set by the ktc_GetToken call when
3201 // * we were comparing whether identical tokens already existed.
3203 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3206 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3207 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3209 strcpy(aclient.instance, "");
3211 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3212 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3213 aclient.name[MAXKTCREALMLEN-1] = '\0';
3215 strcpy(aclient.cell, CellName);
3217 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3218 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3219 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3220 &aclient, &aserver, &atoken);
3223 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3224 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3226 aclient.smbname[0] = '\0';
3229 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3231 KFW_AFS_error(rc, "ktc_SetToken()");
3237 if (client_principal)
3238 pkrb5_free_principal(ctx,client_principal);
3239 /* increds.client == client_principal */
3241 pkrb5_free_principal(ctx,increds.server);
3242 if (cc && (cc != alt_cc))
3243 pkrb5_cc_close(ctx, cc);
3244 if (ctx && (ctx != alt_ctx))
3245 pkrb5_free_context(ctx);
3247 return(rc? rc : code);
3250 /**************************************/
3251 /* afs_realm_of_cell(): */
3252 /**************************************/
3254 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3256 static char krbrlm[REALM_SZ+1]="";
3257 char ** realmlist=NULL;
3263 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3264 if ( !r && realmlist && realmlist[0] ) {
3265 strcpy(krbrlm, realmlist[0]);
3266 pkrb5_free_host_realm(ctx, realmlist);
3272 char *t = cellconfig->name;
3277 if (islower(c)) c=toupper(c);
3285 /**************************************/
3286 /* KFW_AFS_get_cellconfig(): */
3287 /**************************************/
3289 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3292 char newcell[MAXCELLCHARS+1];
3294 local_cell[0] = (char)0;
3295 memset(cellconfig, 0, sizeof(*cellconfig));
3297 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3298 if (rc = cm_GetRootCellName(local_cell))
3303 if (strlen(cell) == 0)
3304 strcpy(cell, local_cell);
3306 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3307 strcpy(cellconfig->name, cell);
3309 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3310 #ifdef AFS_AFSDB_ENV
3313 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3319 /**************************************/
3320 /* get_cellconfig_callback(): */
3321 /**************************************/
3323 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3325 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3327 cc->hostAddr[cc->numServers] = *addrp;
3328 strcpy(cc->hostName[cc->numServers], namep);
3334 /**************************************/
3335 /* KFW_AFS_error(): */
3336 /**************************************/
3338 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3341 const char *errText;
3343 // Using AFS defines as error messages for now, until Transarc
3344 // gets back to me with "string" translations of each of these
3346 if (rc == KTC_ERROR)
3347 errText = "KTC_ERROR";
3348 else if (rc == KTC_TOOBIG)
3349 errText = "KTC_TOOBIG";
3350 else if (rc == KTC_INVAL)
3351 errText = "KTC_INVAL";
3352 else if (rc == KTC_NOENT)
3353 errText = "KTC_NOENT";
3354 else if (rc == KTC_PIOCTLFAIL)
3355 errText = "KTC_PIOCTLFAIL";
3356 else if (rc == KTC_NOPIOCTL)
3357 errText = "KTC_NOPIOCTL";
3358 else if (rc == KTC_NOCELL)
3359 errText = "KTC_NOCELL";
3360 else if (rc == KTC_NOCM)
3361 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3363 errText = "Unknown error!";
3365 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3367 if ( IsDebuggerPresent() ) {
3368 OutputDebugString(message);
3369 OutputDebugString("\n");
3371 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3377 LPSTR lpszMachineName,
3378 LPSTR lpszServiceName,
3379 DWORD *lpdwCurrentState)
3382 SC_HANDLE schSCManager = NULL;
3383 SC_HANDLE schService = NULL;
3384 DWORD fdwDesiredAccess = 0;
3385 SERVICE_STATUS ssServiceStatus = {0};
3388 *lpdwCurrentState = 0;
3390 fdwDesiredAccess = GENERIC_READ;
3392 schSCManager = OpenSCManager(lpszMachineName,
3396 if(schSCManager == NULL)
3398 hr = GetLastError();
3402 schService = OpenService(schSCManager,
3406 if(schService == NULL)
3408 hr = GetLastError();
3412 fRet = QueryServiceStatus(schService,
3417 hr = GetLastError();
3421 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3425 CloseServiceHandle(schService);
3426 CloseServiceHandle(schSCManager);
3439 for (n = 0; fi[n].func_ptr_var; n++)
3440 *(fi[n].func_ptr_var) = 0;
3441 if (h) FreeLibrary(h);
3446 const char* dll_name,
3448 HINSTANCE* ph, // [out, optional] - DLL handle
3449 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3450 int cleanup, // cleanup function pointers and unload on error
3451 int go_on, // continue loading even if some functions cannot be loaded
3452 int silent // do not pop-up a system dialog if DLL cannot be loaded
3461 if (pindex) *pindex = -1;
3463 for (n = 0; fi[n].func_ptr_var; n++)
3464 *(fi[n].func_ptr_var) = 0;
3467 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3468 h = LoadLibrary(dll_name);
3476 for (i = 0; (go_on || !error) && (i < n); i++)
3478 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3484 *(fi[i].func_ptr_var) = p;
3487 if (pindex) *pindex = last_i;
3488 if (error && cleanup && !go_on) {
3489 for (i = 0; i < n; i++) {
3490 *(fi[i].func_ptr_var) = 0;
3496 if (error) return 0;
3500 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3502 krb5_context ctx = NULL;
3503 krb5_ccache cc = NULL;
3504 krb5_error_code code;
3506 const char * realm = NULL;
3507 krb5_principal principal = NULL;
3508 char * pname = NULL;
3509 char password[PROBE_PASSWORD_LEN+1];
3510 BOOL serverReachable = 0;
3512 if (!pkrb5_init_context)
3515 code = pkrb5_init_context(&ctx);
3516 if (code) goto cleanup;
3519 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3521 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3522 realm, PROBE_USERNAME, NULL, NULL);
3523 if ( code ) goto cleanup;
3525 code = KFW_get_ccache(ctx, principal, &cc);
3526 if ( code ) goto cleanup;
3528 code = pkrb5_unparse_name(ctx, principal, &pname);
3529 if ( code ) goto cleanup;
3531 pwdata.data = password;
3532 pwdata.length = PROBE_PASSWORD_LEN;
3533 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3536 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3539 password[PROBE_PASSWORD_LEN] = '\0';
3541 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3551 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3552 case KRB5KDC_ERR_CLIENT_REVOKED:
3553 case KRB5KDC_ERR_CLIENT_NOTYET:
3554 case KRB5KDC_ERR_PREAUTH_FAILED:
3555 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3556 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3557 serverReachable = TRUE;
3560 serverReachable = FALSE;
3565 pkrb5_free_unparsed_name(ctx,pname);
3567 pkrb5_free_principal(ctx,principal);
3569 pkrb5_cc_close(ctx,cc);
3571 pkrb5_free_context(ctx);
3573 return serverReachable;
3577 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3579 krb5_context ctx = NULL;
3580 krb5_error_code code;
3581 krb5_ccache mslsa_ccache=NULL;
3582 krb5_principal princ = NULL;
3583 char * pname = NULL;
3586 if (!KFW_is_available())
3589 if (code = pkrb5_init_context(&ctx))
3592 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3595 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3598 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3601 if ( strlen(pname) < *dwSize ) {
3602 strncpy(szUser, pname, *dwSize);
3603 szUser[*dwSize-1] = '\0';
3606 *dwSize = (DWORD)strlen(pname);
3610 pkrb5_free_unparsed_name(ctx, pname);
3613 pkrb5_free_principal(ctx, princ);
3616 pkrb5_cc_close(ctx, mslsa_ccache);
3619 pkrb5_free_context(ctx);
3624 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3626 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3627 PSID pSystemSID = NULL;
3628 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3629 PACL ccacheACL = NULL;
3630 DWORD ccacheACLlength = 0;
3631 PTOKEN_USER pTokenUser = NULL;
3640 /* Get System SID */
3641 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3647 SystemSIDlength = GetLengthSid(pSystemSID);
3648 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3649 + SystemSIDlength - sizeof(DWORD);
3652 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3654 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3655 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3657 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3662 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3664 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3669 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3674 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3675 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3676 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3679 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3680 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3681 pTokenUser->User.Sid);
3682 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3683 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3688 gle = GetLastError();
3689 if (gle != ERROR_NO_TOKEN)
3692 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3693 OWNER_SECURITY_INFORMATION,
3694 pTokenUser->User.Sid,
3698 gle = GetLastError();
3699 if (gle != ERROR_NO_TOKEN)
3703 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3704 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3709 gle = GetLastError();
3710 if (gle != ERROR_NO_TOKEN)
3717 LocalFree(pSystemSID);
3719 LocalFree(pTokenUser);
3721 LocalFree(ccacheACL);
3726 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3729 DWORD dwSize = size-1; /* leave room for nul */
3732 if (!hUserToken || !newfilename || size <= 0)
3735 *newfilename = '\0';
3737 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3738 if ( !dwLen || dwLen > dwSize )
3739 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3740 if ( !dwLen || dwLen > dwSize )
3743 newfilename[dwSize] = '\0';
3748 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3750 char filename[MAX_PATH] = "";
3752 char cachename[MAX_PATH + 8] = "FILE:";
3753 krb5_context ctx = NULL;
3754 krb5_error_code code;
3755 krb5_principal princ = NULL;
3756 krb5_ccache cc = NULL;
3757 krb5_ccache ncc = NULL;
3759 if (!pkrb5_init_context || !user || !szLogonId)
3762 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3763 if ( count > sizeof(filename) || count == 0 ) {
3764 GetWindowsDirectory(filename, sizeof(filename));
3767 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3770 strcat(filename, "\\");
3771 strcat(filename, szLogonId);
3773 strcat(cachename, filename);
3775 DeleteFile(filename);
3777 code = pkrb5_init_context(&ctx);
3778 if (code) goto cleanup;
3780 code = pkrb5_parse_name(ctx, user, &princ);
3781 if (code) goto cleanup;
3783 code = KFW_get_ccache(ctx, princ, &cc);
3784 if (code) goto cleanup;
3786 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3787 if (code) goto cleanup;
3789 code = pkrb5_cc_initialize(ctx, ncc, princ);
3790 if (code) goto cleanup;
3792 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3793 if (code) goto cleanup;
3795 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3799 pkrb5_cc_close(ctx, cc);
3803 pkrb5_cc_close(ctx, ncc);
3807 pkrb5_free_principal(ctx, princ);
3812 pkrb5_free_context(ctx);
3816 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3818 char cachename[MAX_PATH + 8] = "FILE:";
3819 krb5_context ctx = NULL;
3820 krb5_error_code code;
3821 krb5_principal princ = NULL;
3822 krb5_ccache cc = NULL;
3823 krb5_ccache ncc = NULL;
3826 if (!pkrb5_init_context || !filename)
3829 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3832 code = pkrb5_init_context(&ctx);
3835 strcat(cachename, filename);
3837 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3838 if (code) goto cleanup;
3840 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3842 code = pkrb5_cc_default(ctx, &ncc);
3844 code = pkrb5_cc_initialize(ctx, ncc, princ);
3847 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3850 pkrb5_cc_close(ctx, ncc);
3854 retval=0; /* success */
3858 pkrb5_cc_close(ctx, cc);
3862 DeleteFile(filename);
3865 pkrb5_free_principal(ctx, princ);
3870 pkrb5_free_context(ctx);
3875 /* We are including this
3877 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3878 fixed part of rande of the one byte lifetime field. Values less than 0x80
3879 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3880 0xBF should be looked up in this table. The value of 0x80 is the same using
3881 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3882 The intervening values of have a fixed ratio of roughly 1.06914. The value
3883 oxFF is defined to mean a ticket has no expiration time. This should be
3884 used advisedly since individual servers may impose defacto upperbounds on
3885 ticket lifetimes. */
3887 #define TKTLIFENUMFIXED 64
3888 #define TKTLIFEMINFIXED 0x80
3889 #define TKTLIFEMAXFIXED 0xBF
3890 #define TKTLIFENOEXPIRE 0xFF
3891 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3893 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3894 38400, /* 10.67 hours, 0.44 days */
3895 41055, /* 11.40 hours, 0.48 days */
3896 43894, /* 12.19 hours, 0.51 days */
3897 46929, /* 13.04 hours, 0.54 days */
3898 50174, /* 13.94 hours, 0.58 days */
3899 53643, /* 14.90 hours, 0.62 days */
3900 57352, /* 15.93 hours, 0.66 days */
3901 61318, /* 17.03 hours, 0.71 days */
3902 65558, /* 18.21 hours, 0.76 days */
3903 70091, /* 19.47 hours, 0.81 days */
3904 74937, /* 20.82 hours, 0.87 days */
3905 80119, /* 22.26 hours, 0.93 days */
3906 85658, /* 23.79 hours, 0.99 days */
3907 91581, /* 25.44 hours, 1.06 days */
3908 97914, /* 27.20 hours, 1.13 days */
3909 104684, /* 29.08 hours, 1.21 days */
3910 111922, /* 31.09 hours, 1.30 days */
3911 119661, /* 33.24 hours, 1.38 days */
3912 127935, /* 35.54 hours, 1.48 days */
3913 136781, /* 37.99 hours, 1.58 days */
3914 146239, /* 40.62 hours, 1.69 days */
3915 156350, /* 43.43 hours, 1.81 days */
3916 167161, /* 46.43 hours, 1.93 days */
3917 178720, /* 49.64 hours, 2.07 days */
3918 191077, /* 53.08 hours, 2.21 days */
3919 204289, /* 56.75 hours, 2.36 days */
3920 218415, /* 60.67 hours, 2.53 days */
3921 233517, /* 64.87 hours, 2.70 days */
3922 249664, /* 69.35 hours, 2.89 days */
3923 266926, /* 74.15 hours, 3.09 days */
3924 285383, /* 79.27 hours, 3.30 days */
3925 305116, /* 84.75 hours, 3.53 days */
3926 326213, /* 90.61 hours, 3.78 days */
3927 348769, /* 96.88 hours, 4.04 days */
3928 372885, /* 103.58 hours, 4.32 days */
3929 398668, /* 110.74 hours, 4.61 days */
3930 426234, /* 118.40 hours, 4.93 days */
3931 455705, /* 126.58 hours, 5.27 days */
3932 487215, /* 135.34 hours, 5.64 days */
3933 520904, /* 144.70 hours, 6.03 days */
3934 556921, /* 154.70 hours, 6.45 days */
3935 595430, /* 165.40 hours, 6.89 days */
3936 636601, /* 176.83 hours, 7.37 days */
3937 680618, /* 189.06 hours, 7.88 days */
3938 727680, /* 202.13 hours, 8.42 days */
3939 777995, /* 216.11 hours, 9.00 days */
3940 831789, /* 231.05 hours, 9.63 days */
3941 889303, /* 247.03 hours, 10.29 days */
3942 950794, /* 264.11 hours, 11.00 days */
3943 1016537, /* 282.37 hours, 11.77 days */
3944 1086825, /* 301.90 hours, 12.58 days */
3945 1161973, /* 322.77 hours, 13.45 days */
3946 1242318, /* 345.09 hours, 14.38 days */
3947 1328218, /* 368.95 hours, 15.37 days */
3948 1420057, /* 394.46 hours, 16.44 days */
3949 1518247, /* 421.74 hours, 17.57 days */
3950 1623226, /* 450.90 hours, 18.79 days */
3951 1735464, /* 482.07 hours, 20.09 days */
3952 1855462, /* 515.41 hours, 21.48 days */
3953 1983758, /* 551.04 hours, 22.96 days */
3954 2120925, /* 589.15 hours, 24.55 days */
3955 2267576, /* 629.88 hours, 26.25 days */
3956 2424367, /* 673.44 hours, 28.06 days */
3958 }; /* 720.00 hours, 30.00 days */
3960 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3961 * returns the corresponding end time. There are four simple cases to be
3962 * handled. The first is a life of 0xff, meaning no expiration, and results in
3963 * an end time of 0xffffffff. The second is when life is less than the values
3964 * covered by the table. In this case, the end time is the start time plus the
3965 * number of 5 minute intervals specified by life. The third case returns
3966 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3967 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3968 * table to extract the lifetime in seconds, which is added to start to produce
3972 life_to_time(afs_uint32 start, unsigned char life)
3976 if (life == TKTLIFENOEXPIRE)
3978 if (life < TKTLIFEMINFIXED)
3979 return start + life * 5 * 60;
3980 if (life > TKTLIFEMAXFIXED)
3981 return start + MAXTKTLIFETIME;
3982 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3983 return start + realLife;
3986 /* time_to_life - takes start and end times for the ticket and returns a
3987 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3988 * lifetimes above 127*5minutes. First, the special case of (end ==
3989 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3990 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3991 * less than the first table entry are handled by rounding the requested
3992 * lifetime *up* to the next 5 minute interval. The final step is to search
3993 * the table for the smallest entry *greater than or equal* to the requested
3994 * entry. The actual code is prepared to handle the case where the table is
3995 * unordered but that it an unnecessary frill. */
3997 static unsigned char
3998 time_to_life(afs_uint32 start, afs_uint32 end)
4000 int lifetime = end - start;
4004 if (end == NEVERDATE)
4005 return TKTLIFENOEXPIRE;
4006 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
4008 if (lifetime < tkt_lifetimes[0])
4009 return (lifetime + 5 * 60 - 1) / (5 * 60);
4011 best = MAXKTCTICKETLIFETIME;
4012 for (i = 0; i < TKTLIFENUMFIXED; i++)
4013 if (tkt_lifetimes[i] >= lifetime) {
4014 int diff = tkt_lifetimes[i] - lifetime;
4022 return best_i + TKTLIFEMINFIXED;