2 * Copyright (c) 2004, 2005, 2006, 2007, 2008 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 char * ccfullname = NULL;
690 krb5_error_code code = 0;
691 krb5_error_code cc_code = 0;
697 if (ctx == 0 || cc == 0)
700 code = pkrb5_cc_get_principal(ctx, cc, &principal);
703 code = pkrb5_unparse_name(ctx, principal, &pname);
704 if ( code ) goto cleanup;
706 ccname = pkrb5_cc_get_name(ctx, cc);
707 if (!ccname) goto cleanup;
709 cctype = pkrb5_cc_get_type(ctx, cc);
710 if (!cctype) goto cleanup;
712 ccfullname = malloc(strlen(ccname) + strlen(cctype) + 2);
713 if (!ccfullname) goto cleanup;
715 sprintf(ccfullname, "%s:%s", cctype, ccname);
717 // Search the existing list to see if we have a match
719 for ( ; next ; next = next->next ) {
720 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
725 // If not, match add a new node to the beginning of the list and assign init it
727 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
728 next->next = princ_cc_data;
729 princ_cc_data = next;
730 next->principal = _strdup(pname);
731 next->ccache_name = ccfullname;
733 next->from_lsa = lsa;
735 next->expiration_time = 0;
739 flags = 0; // turn off OPENCLOSE mode
740 code = pkrb5_cc_set_flags(ctx, cc, flags);
741 if ( code ) goto cleanup;
743 code = pkrb5_timeofday(ctx, &now);
745 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
747 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
748 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
750 // we found the ticket we are looking for
751 // check validity of timestamp
752 // We add a 5 minutes fudge factor to compensate for potential
753 // clock skew errors between the KDC and client OS
755 valid = ((creds.times.starttime > 0) &&
756 now >= (creds.times.starttime - 300) &&
757 now < (creds.times.endtime + 300) &&
758 !(creds.ticket_flags & TKT_FLG_INVALID));
760 if ( next->from_lsa) {
762 next->expiration_time = creds.times.endtime;
764 } else if ( valid ) {
766 next->expiration_time = creds.times.endtime;
767 next->renew = (creds.times.renew_till > creds.times.endtime) &&
768 (creds.ticket_flags & TKT_FLG_RENEWABLE);
771 next->expiration_time = 0;
775 pkrb5_free_cred_contents(ctx, &creds);
776 cc_code = KRB5_CC_END;
779 pkrb5_free_cred_contents(ctx, &creds);
782 if (cc_code == KRB5_CC_END) {
783 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
784 if (code) goto cleanup;
788 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
789 code = pkrb5_cc_set_flags(ctx, cc, flags);
794 pkrb5_free_unparsed_name(ctx,pname);
796 pkrb5_free_principal(ctx,principal);
800 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
802 struct principal_ccache_data * next = princ_cc_data;
803 char * response = NULL;
805 if ( !principal || !ccache )
809 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
811 // we always want to prefer the MS Kerberos LSA cache or
812 // the cache afscreds created specifically for the principal
813 // if the current entry is either one, drop the previous find
814 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
817 response = _strdup(next->ccache_name);
818 // MS Kerberos LSA is our best option so use it and quit
819 if ( next->from_lsa )
833 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
835 struct principal_ccache_data ** next = &princ_cc_data;
837 if ( !pname && !ccname )
841 if ( !strcmp((*next)->principal,pname) ||
842 !strcmp((*next)->ccache_name,ccname) ) {
844 free((*next)->principal);
845 free((*next)->ccache_name);
847 (*next) = (*next)->next;
854 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
856 struct cell_principal_map * next = cell_princ_map;
858 // Search the existing list to see if we have a match
860 for ( ; next ; next = next->next ) {
861 if ( !strcmp(next->cell, cell) ) {
862 if ( !strcmp(next->principal,pname) ) {
863 next->active = active;
866 // OpenAFS currently has a restriction of one active token per cell
867 // Therefore, whenever we update the table with a new active cell we
868 // must mark all of the other principal to cell entries as inactive.
876 // If not, match add a new node to the beginning of the list and assign init it
878 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
879 next->next = cell_princ_map;
880 cell_princ_map = next;
881 next->principal = _strdup(pname);
882 next->cell = _strdup(cell);
883 next->active = active;
888 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
890 struct cell_principal_map ** next = &cell_princ_map;
892 if ( !pname && !cell )
896 if ( !strcmp((*next)->principal,pname) ||
897 !strcmp((*next)->cell,cell) ) {
899 free((*next)->principal);
902 (*next) = (*next)->next;
908 // Returns (if possible) a principal which has been known in
909 // the past to have been used to obtain tokens for the specified
911 // TODO: Attempt to return one which has not yet expired by checking
912 // the principal/ccache data
914 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
916 struct cell_principal_map * next_map = cell_princ_map;
917 const char * princ = NULL;
924 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
927 next_map = next_map->next;
930 if ( !principals || !count )
933 *principals = (char **) malloc(sizeof(char *) * count);
934 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
936 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
937 (*principals)[i++] = _strdup(next_map->principal);
944 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
947 struct cell_principal_map * next_map = cell_princ_map;
948 const char * princ = NULL;
954 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
957 next_map = next_map->next;
963 *cells = (char **) malloc(sizeof(char *) * count);
964 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
966 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
967 (*cells)[i++] = _strdup(next_map->cell);
973 /* Given a principal return an existing ccache or create one and return */
975 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
977 krb5_context ctx = NULL;
979 char * ccname = NULL;
980 krb5_error_code code;
982 if (!pkrb5_init_context)
988 code = pkrb5_init_context(&ctx);
989 if (code) goto cleanup;
993 code = pkrb5_unparse_name(ctx, principal, &pname);
994 if (code) goto cleanup;
996 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
997 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
998 ccname = (char *)malloc(strlen(pname) + 5);
999 sprintf(ccname,"API:%s",pname);
1001 code = pkrb5_cc_resolve(ctx, ccname, cc);
1003 code = pkrb5_cc_default(ctx, cc);
1004 if (code) goto cleanup;
1011 pkrb5_free_unparsed_name(ctx,pname);
1012 if (ctx && (ctx != alt_ctx))
1013 pkrb5_free_context(ctx);
1018 // Import Microsoft Credentials into a new MIT ccache
1020 KFW_import_windows_lsa(void)
1022 krb5_context ctx = NULL;
1023 krb5_ccache cc = NULL;
1024 krb5_principal princ = NULL;
1025 char * pname = NULL;
1026 krb5_data * princ_realm;
1027 krb5_error_code code;
1028 char cell[128]="", realm[128]="", *def_realm = 0;
1030 DWORD dwMsLsaImport;
1032 if (!pkrb5_init_context)
1035 code = pkrb5_init_context(&ctx);
1036 if (code) goto cleanup;
1038 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
1039 if (code) goto cleanup;
1041 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
1043 code = pkrb5_cc_get_principal(ctx, cc, &princ);
1044 if ( code ) goto cleanup;
1046 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
1047 switch ( dwMsLsaImport ) {
1048 case 0: /* do not import */
1050 case 1: /* always import */
1052 case 2: { /* matching realm */
1053 char ms_realm[128] = "", *r;
1056 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
1057 *r = krb5_princ_realm(ctx, princ)->data[i];
1061 if (code = pkrb5_get_default_realm(ctx, &def_realm))
1064 if (strcmp(def_realm, ms_realm))
1072 code = pkrb5_unparse_name(ctx,princ,&pname);
1073 if ( code ) goto cleanup;
1075 princ_realm = krb5_princ_realm(ctx, princ);
1076 for ( i=0; i<princ_realm->length; i++ ) {
1077 realm[i] = princ_realm->data[i];
1078 cell[i] = tolower(princ_realm->data[i]);
1083 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
1084 if ( IsDebuggerPresent() ) {
1086 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1087 OutputDebugString(message);
1089 if ( code ) goto cleanup;
1091 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1095 pkrb5_free_unparsed_name(ctx,pname);
1097 pkrb5_free_principal(ctx,princ);
1099 pkrb5_free_default_realm(ctx, def_realm);
1101 pkrb5_cc_close(ctx,cc);
1103 pkrb5_free_context(ctx);
1105 #endif /* USE_MS2MIT */
1107 // If there are existing MIT credentials, copy them to a new
1108 // ccache named after the principal
1110 // Enumerate all existing MIT ccaches and construct entries
1111 // in the principal_ccache table
1113 // Enumerate all existing AFS Tokens and construct entries
1114 // in the cell_principal table
1116 KFW_import_ccache_data(void)
1118 krb5_context ctx = NULL;
1119 krb5_ccache cc = NULL;
1120 krb5_principal principal = NULL;
1122 krb5_error_code code;
1123 krb5_error_code cc_code;
1125 apiCB * cc_ctx = NULL;
1126 struct _infoNC ** pNCi = NULL;
1129 if ( !pcc_initialize )
1132 if ( IsDebuggerPresent() )
1133 OutputDebugString("KFW_import_ccache_data()\n");
1135 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1136 if (code) goto cleanup;
1138 code = pcc_get_NC_info(cc_ctx, &pNCi);
1139 if (code) goto cleanup;
1141 code = pkrb5_init_context(&ctx);
1142 if (code) goto cleanup;
1144 for ( i=0; pNCi[i]; i++ ) {
1145 if ( pNCi[i]->vers != CC_CRED_V5 )
1147 if ( IsDebuggerPresent() ) {
1148 OutputDebugString("Principal: ");
1149 OutputDebugString(pNCi[i]->principal);
1150 OutputDebugString(" in ccache ");
1151 OutputDebugString(pNCi[i]->name);
1152 OutputDebugString("\n");
1154 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1155 && strcmp(pNCi[i]->name,LSA_CCNAME)
1158 for ( j=0; pNCi[j]; j++ ) {
1159 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1165 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1166 if (code) goto loop_cleanup;
1169 krb5_ccache oldcc = 0;
1171 if ( IsDebuggerPresent() )
1172 OutputDebugString("copying ccache data to new ccache\n");
1174 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1175 if (code) goto loop_cleanup;
1176 code = pkrb5_cc_initialize(ctx, cc, principal);
1177 if (code) goto loop_cleanup;
1179 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1180 if (code) goto loop_cleanup;
1181 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1183 code = pkrb5_cc_close(ctx,cc);
1185 code = pkrb5_cc_close(ctx,oldcc);
1187 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1190 code = pkrb5_cc_close(ctx,oldcc);
1193 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1194 if (code) goto loop_cleanup;
1197 flags = 0; // turn off OPENCLOSE mode
1198 code = pkrb5_cc_set_flags(ctx, cc, flags);
1199 if ( code ) goto cleanup;
1201 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1203 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1205 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1206 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1207 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1208 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1209 if ( sname && cell && !strcmp("afs",sname->data) ) {
1210 struct ktc_principal aserver;
1211 struct ktc_principal aclient;
1212 struct ktc_token atoken;
1215 if ( IsDebuggerPresent() ) {
1216 OutputDebugString("Found AFS ticket: ");
1217 OutputDebugString(sname->data);
1219 OutputDebugString("/");
1220 OutputDebugString(cell->data);
1222 OutputDebugString("@");
1223 OutputDebugString(realm->data);
1224 OutputDebugString("\n");
1227 memset(&aserver, '\0', sizeof(aserver));
1228 strcpy(aserver.name, sname->data);
1229 strcpy(aserver.cell, cell->data);
1231 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1233 // Found a token in AFS Client Server which matches
1234 char pname[128], *p, *q;
1235 for ( p=pname, q=aclient.name; *q; p++, q++)
1237 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1241 if ( IsDebuggerPresent() ) {
1242 OutputDebugString("Found AFS token: ");
1243 OutputDebugString(pname);
1244 OutputDebugString("\n");
1247 if ( strcmp(pname,pNCi[i]->principal) )
1249 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1251 // Attempt to import it
1252 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1254 if ( IsDebuggerPresent() ) {
1255 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1258 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data,
1262 pLeash_get_default_lifetime(),
1263 #endif /* USE_LEASH */
1265 if ( IsDebuggerPresent() ) {
1267 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1268 OutputDebugString(message);
1271 } else if ( IsDebuggerPresent() ) {
1272 OutputDebugString("Found ticket: ");
1273 OutputDebugString(sname->data);
1274 if ( cell && cell->data ) {
1275 OutputDebugString("/");
1276 OutputDebugString(cell->data);
1278 OutputDebugString("@");
1279 OutputDebugString(realm->data);
1280 OutputDebugString("\n");
1282 pkrb5_free_cred_contents(ctx, &creds);
1285 if (cc_code == KRB5_CC_END) {
1286 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1287 if (cc_code) goto loop_cleanup;
1291 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1292 code = pkrb5_cc_set_flags(ctx, cc, flags);
1294 pkrb5_cc_close(ctx,cc);
1298 pkrb5_free_principal(ctx,principal);
1305 pkrb5_free_context(ctx);
1307 pcc_free_NC_info(cc_ctx, &pNCi);
1309 pcc_shutdown(&cc_ctx);
1314 KFW_AFS_get_cred( char * username,
1321 krb5_context ctx = NULL;
1322 krb5_ccache cc = NULL;
1323 char * realm = NULL, * userrealm = NULL;
1324 krb5_principal principal = NULL;
1325 char * pname = NULL;
1326 krb5_error_code code;
1327 char local_cell[MAXCELLCHARS+1];
1328 char **cells = NULL;
1330 struct afsconf_cell cellconfig;
1333 if (!pkrb5_init_context)
1336 if ( IsDebuggerPresent() ) {
1337 OutputDebugString("KFW_AFS_get_cred for token ");
1338 OutputDebugString(username);
1339 OutputDebugString(" in cell ");
1340 OutputDebugString(cell);
1341 OutputDebugString("\n");
1344 code = pkrb5_init_context(&ctx);
1345 if ( code ) goto cleanup;
1347 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1348 if ( code ) goto cleanup;
1350 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1352 userrealm = strchr(username,'@');
1354 pname = strdup(username);
1355 if (!KFW_accept_dotted_usernames()) {
1356 userrealm = strchr(pname, '@');
1359 /* handle kerberos iv notation */
1360 while ( dot = strchr(pname,'.') ) {
1366 pname = malloc(strlen(username) + strlen(realm) + 2);
1368 strcpy(pname, username);
1370 if (!KFW_accept_dotted_usernames()) {
1371 /* handle kerberos iv notation */
1372 while ( dot = strchr(pname,'.') ) {
1377 strcat(pname,realm);
1379 if ( IsDebuggerPresent() ) {
1380 OutputDebugString("Realm: ");
1381 OutputDebugString(realm);
1382 OutputDebugString("\n");
1385 code = pkrb5_parse_name(ctx, pname, &principal);
1386 if ( code ) goto cleanup;
1388 code = KFW_get_ccache(ctx, principal, &cc);
1389 if ( code ) goto cleanup;
1391 if ( lifetime == 0 )
1395 lifetime = pLeash_get_default_lifetime();
1398 if ( password && password[0] ) {
1399 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1404 1, /* forwardable */
1405 0, /* not proxiable */
1407 1, /* noaddresses */
1408 0 /* no public ip */
1410 pLeash_get_default_forwardable(),
1411 pLeash_get_default_proxiable(),
1412 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1413 pLeash_get_default_noaddresses(),
1414 pLeash_get_default_publicip()
1415 #endif /* USE_LEASH */
1418 if ( IsDebuggerPresent() ) {
1420 sprintf(message,"KFW_kinit() returns: %d\n",code);
1421 OutputDebugString(message);
1423 if ( code ) goto cleanup;
1425 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1428 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1429 if ( IsDebuggerPresent() ) {
1431 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1432 OutputDebugString(message);
1434 if ( code ) goto cleanup;
1436 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1438 // Attempt to obtain new tokens for other cells supported by the same
1440 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1441 if ( cell_count > 1 ) {
1442 while ( cell_count-- ) {
1443 if ( strcmp(cells[cell_count],cell) ) {
1444 if ( IsDebuggerPresent() ) {
1446 sprintf(message,"found another cell for the same principal: %s\n",cell);
1447 OutputDebugString(message);
1449 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1450 if ( code ) continue;
1452 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1453 if ( IsDebuggerPresent() ) {
1454 OutputDebugString("Realm: ");
1455 OutputDebugString(realm);
1456 OutputDebugString("\n");
1459 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1460 if ( IsDebuggerPresent() ) {
1462 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1463 OutputDebugString(message);
1466 free(cells[cell_count]);
1469 } else if ( cell_count == 1 ) {
1478 pkrb5_cc_close(ctx, cc);
1480 if ( code && reasonP ) {
1481 *reasonP = (char *)perror_message(code);
1487 KFW_AFS_destroy_tickets_for_cell(char * cell)
1489 krb5_context ctx = NULL;
1490 krb5_error_code code;
1492 char ** principals = NULL;
1494 if (!pkrb5_init_context)
1497 if ( IsDebuggerPresent() ) {
1498 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1499 OutputDebugString(cell);
1500 OutputDebugString("\n");
1503 code = pkrb5_init_context(&ctx);
1506 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1508 krb5_principal princ = 0;
1512 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1513 if ( cell_count > 1 ) {
1514 // TODO - What we really should do here is verify whether or not any of the
1515 // other cells which use this principal to obtain its credentials actually
1516 // have valid tokens or not. If they are currently using these credentials
1517 // we will skip them. For the time being we assume that if there is an active
1518 // map in the table that they are actively being used.
1522 code = pkrb5_parse_name(ctx, principals[count], &princ);
1523 if (code) goto loop_cleanup;
1525 code = KFW_get_ccache(ctx, princ, &cc);
1526 if (code) goto loop_cleanup;
1528 code = pkrb5_cc_destroy(ctx, cc);
1533 pkrb5_cc_close(ctx, cc);
1537 pkrb5_free_principal(ctx, princ);
1541 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1542 free(principals[count]);
1547 pkrb5_free_context(ctx);
1552 KFW_AFS_destroy_tickets_for_principal(char * user)
1554 krb5_context ctx = NULL;
1555 krb5_error_code code;
1557 char ** cells = NULL;
1558 krb5_principal princ = NULL;
1559 krb5_ccache cc = NULL;
1561 if (!pkrb5_init_context)
1564 if ( IsDebuggerPresent() ) {
1565 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1566 OutputDebugString(user);
1567 OutputDebugString("\n");
1570 code = pkrb5_init_context(&ctx);
1573 code = pkrb5_parse_name(ctx, user, &princ);
1574 if (code) goto loop_cleanup;
1576 code = KFW_get_ccache(ctx, princ, &cc);
1577 if (code) goto loop_cleanup;
1579 code = pkrb5_cc_destroy(ctx, cc);
1584 pkrb5_cc_close(ctx, cc);
1588 pkrb5_free_principal(ctx, princ);
1592 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1595 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1602 pkrb5_free_context(ctx);
1607 KFW_AFS_renew_expiring_tokens(void)
1609 krb5_error_code code = 0;
1610 krb5_context ctx = NULL;
1611 krb5_ccache cc = NULL;
1613 struct principal_ccache_data * pcc_next = princ_cc_data;
1616 const char * realm = NULL;
1617 char local_cell[MAXCELLCHARS+1]="";
1618 struct afsconf_cell cellconfig;
1620 if (!pkrb5_init_context)
1623 if ( pcc_next == NULL ) // nothing to do
1626 if ( IsDebuggerPresent() ) {
1627 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1630 code = pkrb5_init_context(&ctx);
1631 if (code) goto cleanup;
1633 code = pkrb5_timeofday(ctx, &now);
1634 if (code) goto cleanup;
1636 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1637 if ( pcc_next->expired )
1640 if ( now >= (pcc_next->expiration_time) ) {
1641 if ( !pcc_next->from_lsa ) {
1642 pcc_next->expired = 1;
1647 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1648 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1651 code = KFW_renew(ctx,cc);
1653 if ( code && pcc_next->from_lsa)
1655 #endif /* USE_MS2MIT */
1658 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1659 if (code) goto loop_cleanup;
1661 // Attempt to obtain new tokens for other cells supported by the same
1663 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1664 if ( cell_count > 0 ) {
1665 while ( cell_count-- ) {
1666 if ( IsDebuggerPresent() ) {
1667 OutputDebugString("Cell: ");
1668 OutputDebugString(cells[cell_count]);
1669 OutputDebugString("\n");
1671 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1672 if ( code ) continue;
1673 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1674 if ( IsDebuggerPresent() ) {
1675 OutputDebugString("Realm: ");
1676 OutputDebugString(realm);
1677 OutputDebugString("\n");
1679 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1680 if ( IsDebuggerPresent() ) {
1682 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1683 OutputDebugString(message);
1685 free(cells[cell_count]);
1693 pkrb5_cc_close(ctx,cc);
1700 pkrb5_cc_close(ctx,cc);
1702 pkrb5_free_context(ctx);
1709 KFW_AFS_renew_token_for_cell(char * cell)
1711 krb5_error_code code = 0;
1712 krb5_context ctx = NULL;
1714 char ** principals = NULL;
1716 if (!pkrb5_init_context)
1719 if ( IsDebuggerPresent() ) {
1720 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1721 OutputDebugString(cell);
1722 OutputDebugString("\n");
1725 code = pkrb5_init_context(&ctx);
1726 if (code) goto cleanup;
1728 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1730 // We know we must have a credential somewhere since we are
1731 // trying to renew a token
1733 KFW_import_ccache_data();
1734 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1737 krb5_principal princ = 0;
1738 krb5_principal service = 0;
1740 krb5_creds mcreds, creds;
1741 #endif /* COMMENT */
1743 const char * realm = NULL;
1744 struct afsconf_cell cellconfig;
1745 char local_cell[MAXCELLCHARS+1];
1748 code = pkrb5_parse_name(ctx, principals[count], &princ);
1749 if (code) goto loop_cleanup;
1751 code = KFW_get_ccache(ctx, princ, &cc);
1752 if (code) goto loop_cleanup;
1754 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1755 if ( code ) goto loop_cleanup;
1757 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1758 if ( IsDebuggerPresent() ) {
1759 OutputDebugString("Realm: ");
1760 OutputDebugString(realm);
1761 OutputDebugString("\n");
1765 /* krb5_cc_remove_cred() is not implemented
1768 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1769 realm, "afs", cell, NULL);
1771 memset(&mcreds, 0, sizeof(krb5_creds));
1772 mcreds.client = princ;
1773 mcreds.server = service;
1775 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1777 if ( IsDebuggerPresent() ) {
1778 char * cname, *sname;
1779 pkrb5_unparse_name(ctx, creds.client, &cname);
1780 pkrb5_unparse_name(ctx, creds.server, &sname);
1781 OutputDebugString("Removing credential for client \"");
1782 OutputDebugString(cname);
1783 OutputDebugString("\" and service \"");
1784 OutputDebugString(sname);
1785 OutputDebugString("\"\n");
1786 pkrb5_free_unparsed_name(ctx,cname);
1787 pkrb5_free_unparsed_name(ctx,sname);
1790 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1791 pkrb5_free_principal(ctx, creds.client);
1792 pkrb5_free_principal(ctx, creds.server);
1795 #endif /* COMMENT */
1797 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1798 if ( IsDebuggerPresent() ) {
1800 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1801 OutputDebugString(message);
1806 pkrb5_cc_close(ctx, cc);
1810 pkrb5_free_principal(ctx, princ);
1814 pkrb5_free_principal(ctx, service);
1818 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1819 free(principals[count]);
1823 code = -1; // we did not renew the tokens
1827 pkrb5_free_context(ctx);
1828 return (code ? FALSE : TRUE);
1833 KFW_AFS_renew_tokens_for_all_cells(void)
1835 struct cell_principal_map * next = cell_princ_map;
1837 if ( IsDebuggerPresent() )
1838 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1843 for ( ; next ; next = next->next ) {
1845 KFW_AFS_renew_token_for_cell(next->cell);
1851 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1853 krb5_error_code code = 0;
1854 krb5_context ctx = NULL;
1855 krb5_ccache cc = NULL;
1856 krb5_principal me = NULL;
1857 krb5_principal server = NULL;
1858 krb5_creds my_creds;
1859 krb5_data *realm = NULL;
1861 if (!pkrb5_init_context)
1864 memset(&my_creds, 0, sizeof(krb5_creds));
1869 code = pkrb5_init_context(&ctx);
1870 if (code) goto cleanup;
1876 code = pkrb5_cc_default(ctx, &cc);
1877 if (code) goto cleanup;
1880 code = pkrb5_cc_get_principal(ctx, cc, &me);
1881 if (code) goto cleanup;
1883 realm = krb5_princ_realm(ctx, me);
1885 code = pkrb5_build_principal_ext(ctx, &server,
1886 realm->length,realm->data,
1887 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1888 realm->length,realm->data,
1893 if ( IsDebuggerPresent() ) {
1894 char * cname, *sname;
1895 pkrb5_unparse_name(ctx, me, &cname);
1896 pkrb5_unparse_name(ctx, server, &sname);
1897 OutputDebugString("Renewing credential for client \"");
1898 OutputDebugString(cname);
1899 OutputDebugString("\" and service \"");
1900 OutputDebugString(sname);
1901 OutputDebugString("\"\n");
1902 pkrb5_free_unparsed_name(ctx,cname);
1903 pkrb5_free_unparsed_name(ctx,sname);
1906 my_creds.client = me;
1907 my_creds.server = server;
1909 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1911 if ( IsDebuggerPresent() ) {
1913 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1914 OutputDebugString(message);
1919 code = pkrb5_cc_initialize(ctx, cc, me);
1921 if ( IsDebuggerPresent() ) {
1923 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1924 OutputDebugString(message);
1929 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1931 if ( IsDebuggerPresent() ) {
1933 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1934 OutputDebugString(message);
1940 if (my_creds.client == me)
1941 my_creds.client = 0;
1942 if (my_creds.server == server)
1943 my_creds.server = 0;
1944 pkrb5_free_cred_contents(ctx, &my_creds);
1946 pkrb5_free_principal(ctx, me);
1948 pkrb5_free_principal(ctx, server);
1949 if (cc && (cc != alt_cc))
1950 pkrb5_cc_close(ctx, cc);
1951 if (ctx && (ctx != alt_ctx))
1952 pkrb5_free_context(ctx);
1957 KFW_kinit( krb5_context alt_ctx,
1960 char *principal_name,
1962 krb5_deltat lifetime,
1965 krb5_deltat renew_life,
1970 krb5_error_code code = 0;
1971 krb5_context ctx = NULL;
1972 krb5_ccache cc = NULL;
1973 krb5_principal me = NULL;
1975 krb5_creds my_creds;
1976 krb5_get_init_creds_opt options;
1977 krb5_address ** addrs = NULL;
1978 int i = 0, addr_count = 0;
1980 if (!pkrb5_init_context)
1983 pkrb5_get_init_creds_opt_init(&options);
1984 memset(&my_creds, 0, sizeof(my_creds));
1992 code = pkrb5_init_context(&ctx);
1993 if (code) goto cleanup;
1999 code = pkrb5_cc_default(ctx, &cc);
2000 if (code) goto cleanup;
2003 code = pkrb5_parse_name(ctx, principal_name, &me);
2007 code = pkrb5_unparse_name(ctx, me, &name);
2015 lifetime = pLeash_get_default_lifetime();
2016 #endif /* USE_LEASH */
2023 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
2024 pkrb5_get_init_creds_opt_set_forwardable(&options,
2025 forwardable ? 1 : 0);
2026 pkrb5_get_init_creds_opt_set_proxiable(&options,
2028 pkrb5_get_init_creds_opt_set_renew_life(&options,
2031 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
2035 // we are going to add the public IP address specified by the user
2036 // to the list provided by the operating system
2037 krb5_address ** local_addrs=NULL;
2040 pkrb5_os_localaddr(ctx, &local_addrs);
2041 while ( local_addrs[i++] );
2044 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
2046 pkrb5_free_addresses(ctx, local_addrs);
2049 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
2051 while ( local_addrs[i] ) {
2052 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2053 if (addrs[i] == NULL) {
2054 pkrb5_free_addresses(ctx, local_addrs);
2058 addrs[i]->magic = local_addrs[i]->magic;
2059 addrs[i]->addrtype = local_addrs[i]->addrtype;
2060 addrs[i]->length = local_addrs[i]->length;
2061 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2062 if (!addrs[i]->contents) {
2063 pkrb5_free_addresses(ctx, local_addrs);
2067 memcpy(addrs[i]->contents,local_addrs[i]->contents,
2068 local_addrs[i]->length); /* safe */
2071 pkrb5_free_addresses(ctx, local_addrs);
2073 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2074 if (addrs[i] == NULL)
2077 addrs[i]->magic = KV5M_ADDRESS;
2078 addrs[i]->addrtype = AF_INET;
2079 addrs[i]->length = 4;
2080 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2081 if (!addrs[i]->contents)
2084 netIPAddr = htonl(publicIP);
2085 memcpy(addrs[i]->contents,&netIPAddr,4);
2087 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
2092 code = pkrb5_get_init_creds_password(ctx,
2095 password, // password
2096 KRB5_prompter, // prompter
2097 hParent, // prompter data
2104 code = pkrb5_cc_initialize(ctx, cc, me);
2108 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
2114 for ( i=0;i<addr_count;i++ ) {
2116 if ( addrs[i]->contents )
2117 free(addrs[i]->contents);
2122 if (my_creds.client == me)
2123 my_creds.client = 0;
2124 pkrb5_free_cred_contents(ctx, &my_creds);
2126 pkrb5_free_unparsed_name(ctx, name);
2128 pkrb5_free_principal(ctx, me);
2129 if (cc && (cc != alt_cc))
2130 pkrb5_cc_close(ctx, cc);
2131 if (ctx && (ctx != alt_ctx))
2132 pkrb5_free_context(ctx);
2138 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2140 krb5_context ctx = NULL;
2141 krb5_ccache cc = NULL;
2142 krb5_error_code code;
2144 if (!pkrb5_init_context)
2153 code = pkrb5_init_context(&ctx);
2154 if (code) goto cleanup;
2160 code = pkrb5_cc_default(ctx, &cc);
2161 if (code) goto cleanup;
2164 code = pkrb5_cc_destroy(ctx, cc);
2165 if ( !code ) cc = 0;
2168 if (cc && (cc != alt_cc))
2169 pkrb5_cc_close(ctx, cc);
2170 if (ctx && (ctx != alt_ctx))
2171 pkrb5_free_context(ctx);
2179 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2181 NTSTATUS Status = 0;
2183 TOKEN_STATISTICS Stats;
2189 *ppSessionData = NULL;
2191 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2195 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2196 CloseHandle( TokenHandle );
2200 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2201 if ( FAILED(Status) || !ppSessionData )
2208 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2209 // cache. It validates whether or not it is reasonable to assume that if we
2210 // attempted to retrieve valid tickets we could do so. Microsoft does not
2211 // automatically renew expired tickets. Therefore, the cache could contain
2212 // expired or invalid tickets. Microsoft also caches the user's password
2213 // and will use it to retrieve new TGTs if the cache is empty and tickets
2217 MSLSA_IsKerberosLogon(VOID)
2219 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2220 BOOL Success = FALSE;
2222 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2223 if ( pSessionData->AuthenticationPackage.Buffer ) {
2229 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2230 usLength = (pSessionData->AuthenticationPackage).Length;
2233 lstrcpynW (buffer, usBuffer, usLength);
2234 lstrcatW (buffer,L"");
2235 if ( !lstrcmpW(L"Kerberos",buffer) )
2239 pLsaFreeReturnBuffer(pSessionData);
2243 #endif /* USE_MS2MIT */
2245 static BOOL CALLBACK
2246 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2250 switch ( message ) {
2252 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2254 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2257 for ( i=0; i < mid_cnt ; i++ ) {
2258 if (mid_tb[i].echo == 0)
2259 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2260 else if (mid_tb[i].echo == 2)
2261 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2266 switch ( LOWORD(wParam) ) {
2268 for ( i=0; i < mid_cnt ; i++ ) {
2269 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2270 *mid_tb[i].buf = '\0';
2274 EndDialog(hDialog, LOWORD(wParam));
2282 lpwAlign( LPWORD lpIn )
2286 ul = (ULONG_PTR) lpIn;
2290 return (LPWORD) ul;;
2294 * dialog widths are measured in 1/4 character widths
2295 * dialog height are measured in 1/8 character heights
2299 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2300 char * ptext[], int numlines, int width,
2301 int tb_cnt, struct textField * tb)
2305 LPDLGITEMTEMPLATE lpdit;
2311 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2318 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2320 // Define a dialog box.
2322 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2323 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2324 | DS_SETFOREGROUND | DS_3DLOOK
2325 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2326 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2329 lpdt->cx = 20 + width * 4;
2330 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2332 lpw = (LPWORD) (lpdt + 1);
2333 *lpw++ = 0; // no menu
2334 *lpw++ = 0; // predefined dialog box class (by default)
2336 lpwsz = (LPWSTR) lpw;
2337 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2339 *lpw++ = 8; // font size (points)
2340 lpwsz = (LPWSTR) lpw;
2341 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2345 //-----------------------
2346 // Define an OK button.
2347 //-----------------------
2348 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2349 lpdit = (LPDLGITEMTEMPLATE) lpw;
2350 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2351 lpdit->dwExtendedStyle = 0;
2352 lpdit->x = (lpdt->cx - 14)/4 - 20;
2353 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2356 lpdit->id = IDOK; // OK button identifier
2358 lpw = (LPWORD) (lpdit + 1);
2360 *lpw++ = 0x0080; // button class
2362 lpwsz = (LPWSTR) lpw;
2363 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2365 *lpw++ = 0; // no creation data
2367 //-----------------------
2368 // Define an Cancel button.
2369 //-----------------------
2370 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2371 lpdit = (LPDLGITEMTEMPLATE) lpw;
2372 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2373 lpdit->dwExtendedStyle = 0;
2374 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2375 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2378 lpdit->id = IDCANCEL; // CANCEL button identifier
2380 lpw = (LPWORD) (lpdit + 1);
2382 *lpw++ = 0x0080; // button class
2384 lpwsz = (LPWSTR) lpw;
2385 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2387 *lpw++ = 0; // no creation data
2389 /* Add controls for preface data */
2390 for ( i=0; i<numlines; i++) {
2391 /*-----------------------
2392 * Define a static text control.
2393 *-----------------------*/
2394 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2395 lpdit = (LPDLGITEMTEMPLATE) lpw;
2396 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2397 lpdit->dwExtendedStyle = 0;
2399 lpdit->y = 10 + i * 14;
2400 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2402 lpdit->id = ID_TEXT + i; // text identifier
2404 lpw = (LPWORD) (lpdit + 1);
2406 *lpw++ = 0x0082; // static class
2408 lpwsz = (LPWSTR) lpw;
2409 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2410 -1, lpwsz, 2*width);
2412 *lpw++ = 0; // no creation data
2415 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2416 int len = (int)strlen(tb[i].label);
2421 for ( i=0; i<tb_cnt; i++) {
2423 /*-----------------------
2424 * Define a static text control.
2425 *-----------------------*/
2426 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2427 lpdit = (LPDLGITEMTEMPLATE) lpw;
2428 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2429 lpdit->dwExtendedStyle = 0;
2431 lpdit->y = 10 + (numlines + i + 1) * 14;
2432 lpdit->cx = pwid * 4;
2434 lpdit->id = ID_TEXT + numlines + i; // text identifier
2436 lpw = (LPWORD) (lpdit + 1);
2438 *lpw++ = 0x0082; // static class
2440 lpwsz = (LPWSTR) lpw;
2441 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2444 *lpw++ = 0; // no creation data
2446 /*-----------------------
2447 * Define an edit control.
2448 *-----------------------*/
2449 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2450 lpdit = (LPDLGITEMTEMPLATE) lpw;
2451 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2452 lpdit->dwExtendedStyle = 0;
2453 lpdit->x = 10 + (pwid + 1) * 4;
2454 lpdit->y = 10 + (numlines + i + 1) * 14;
2455 lpdit->cx = (width - (pwid + 1)) * 4;
2457 lpdit->id = ID_MID_TEXT + i; // identifier
2459 lpw = (LPWORD) (lpdit + 1);
2461 *lpw++ = 0x0081; // edit class
2463 lpwsz = (LPWSTR) lpw;
2464 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2467 *lpw++ = 0; // no creation data
2471 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2472 hwndOwner, (DLGPROC) MultiInputDialogProc);
2476 case 0: /* Timeout */
2484 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2485 MessageBox(hwndOwner,
2488 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2495 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2497 HINSTANCE hInst = 0;
2501 char * plines[16], *p = preface ? preface : "";
2504 for ( i=0; i<16; i++ )
2507 while (*p && numlines < 16) {
2508 plines[numlines++] = p;
2509 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2510 if ( *p == '\r' && *(p+1) == '\n' ) {
2513 } else if ( *p == '\n' ) {
2516 if ( strlen(plines[numlines-1]) > maxwidth )
2517 maxwidth = (int)strlen(plines[numlines-1]);
2520 for ( i=0;i<n;i++ ) {
2521 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2522 if ( maxwidth < len )
2526 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2529 static krb5_error_code KRB5_CALLCONV
2530 KRB5_prompter( krb5_context context,
2535 krb5_prompt prompts[])
2537 krb5_error_code errcode = 0;
2539 struct textField * tb = NULL;
2540 int len = 0, blen=0, nlen=0;
2541 HWND hParent = (HWND)data;
2544 nlen = (int)strlen(name)+2;
2547 blen = (int)strlen(banner)+2;
2549 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2552 memset(tb,0,sizeof(struct textField) * num_prompts);
2553 for ( i=0; i < num_prompts; i++ ) {
2554 tb[i].buf = prompts[i].reply->data;
2555 tb[i].len = prompts[i].reply->length;
2556 tb[i].label = prompts[i].prompt;
2558 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2561 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2563 for ( i=0; i < num_prompts; i++ )
2564 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2572 for (i = 0; i < num_prompts; i++) {
2573 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2580 KFW_AFS_wait_for_service_start(void)
2585 CurrentState = SERVICE_START_PENDING;
2586 memset(HostName, '\0', sizeof(HostName));
2587 gethostname(HostName, sizeof(HostName));
2589 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2591 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2593 if ( IsDebuggerPresent() ) {
2594 switch ( CurrentState ) {
2595 case SERVICE_STOPPED:
2596 OutputDebugString("SERVICE_STOPPED\n");
2598 case SERVICE_START_PENDING:
2599 OutputDebugString("SERVICE_START_PENDING\n");
2601 case SERVICE_STOP_PENDING:
2602 OutputDebugString("SERVICE_STOP_PENDING\n");
2604 case SERVICE_RUNNING:
2605 OutputDebugString("SERVICE_RUNNING\n");
2607 case SERVICE_CONTINUE_PENDING:
2608 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2610 case SERVICE_PAUSE_PENDING:
2611 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2613 case SERVICE_PAUSED:
2614 OutputDebugString("SERVICE_PAUSED\n");
2617 OutputDebugString("UNKNOWN Service State\n");
2620 if (CurrentState == SERVICE_STOPPED)
2622 if (CurrentState == SERVICE_RUNNING)
2638 memset(HostName, '\0', sizeof(HostName));
2639 gethostname(HostName, sizeof(HostName));
2640 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2642 if (CurrentState != SERVICE_RUNNING)
2645 rc = ktc_ForgetAllTokens();
2651 #define ALLOW_REGISTER 1
2653 ViceIDToUsername(char *username,
2654 char *realm_of_user,
2655 char *realm_of_cell,
2657 struct ktc_principal *aclient,
2658 struct ktc_principal *aserver,
2659 struct ktc_token *atoken)
2661 static char lastcell[MAXCELLCHARS+1] = { 0 };
2662 static char confdir[512] = { 0 };
2663 #ifdef AFS_ID_TO_NAME
2664 char username_copy[BUFSIZ];
2665 #endif /* AFS_ID_TO_NAME */
2666 long viceId = ANONYMOUSID; /* AFS uid of user */
2668 #ifdef ALLOW_REGISTER
2670 #endif /* ALLOW_REGISTER */
2672 if (confdir[0] == '\0')
2673 cm_GetConfigDir(confdir, sizeof(confdir));
2675 strcpy(lastcell, aserver->cell);
2677 if (!pr_Initialize (0, confdir, aserver->cell)) {
2678 char sname[PR_MAXNAMELEN];
2679 strncpy(sname, username, PR_MAXNAMELEN);
2680 sname[PR_MAXNAMELEN-1] = '\0';
2681 status = pr_SNameToId (sname, &viceId);
2686 * This is a crock, but it is Transarc's crock, so
2687 * we have to play along in order to get the
2688 * functionality. The way the afs id is stored is
2689 * as a string in the username field of the token.
2690 * Contrary to what you may think by looking at
2691 * the code for tokens, this hack (AFS ID %d) will
2692 * not work if you change %d to something else.
2696 * This code is taken from cklog -- it lets people
2697 * automatically register with the ptserver in foreign cells
2700 #ifdef ALLOW_REGISTER
2702 if (viceId != ANONYMOUSID) {
2703 #else /* ALLOW_REGISTER */
2704 if ((status == 0) && (viceId != ANONYMOUSID))
2705 #endif /* ALLOW_REGISTER */
2707 #ifdef AFS_ID_TO_NAME
2708 strncpy(username_copy, username, BUFSIZ);
2709 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2710 #endif /* AFS_ID_TO_NAME */
2712 #ifdef ALLOW_REGISTER
2713 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2715 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2716 strcpy(aclient->instance, "");
2717 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2718 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2720 if (status = pr_Initialize(1L, confdir, aserver->cell))
2722 status = pr_CreateUser(username, &id);
2726 #ifdef AFS_ID_TO_NAME
2727 strncpy(username_copy, username, BUFSIZ);
2728 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2729 #endif /* AFS_ID_TO_NAME */
2732 #endif /* ALLOW_REGISTER */
2739 krb5_context alt_ctx,
2744 int lifetime, /* unused parameter */
2752 #endif /* USE_KRB4 */
2753 struct ktc_principal aserver;
2754 struct ktc_principal aclient;
2755 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2756 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2757 char local_cell[MAXCELLCHARS+1];
2758 char Dmycell[MAXCELLCHARS+1];
2759 struct ktc_token atoken;
2760 struct ktc_token btoken;
2761 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2762 char RealmName[128];
2764 char ServiceName[128];
2768 krb5_context ctx = NULL;
2769 krb5_ccache cc = NULL;
2771 krb5_creds * k5creds = NULL;
2772 krb5_error_code code;
2773 krb5_principal client_principal = NULL;
2774 krb5_data * k5data = NULL;
2778 memset(HostName, '\0', sizeof(HostName));
2779 gethostname(HostName, sizeof(HostName));
2780 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2781 if ( IsDebuggerPresent() )
2782 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2785 if (CurrentState != SERVICE_RUNNING) {
2786 if ( IsDebuggerPresent() )
2787 OutputDebugString("AFSD Service NOT RUNNING\n");
2791 if (!pkrb5_init_context)
2794 memset(RealmName, '\0', sizeof(RealmName));
2795 memset(CellName, '\0', sizeof(CellName));
2796 memset(ServiceName, '\0', sizeof(ServiceName));
2797 memset(realm_of_user, '\0', sizeof(realm_of_user));
2798 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2799 if (cell && cell[0])
2800 strcpy(Dmycell, cell);
2802 memset(Dmycell, '\0', sizeof(Dmycell));
2804 // NULL or empty cell returns information on local cell
2805 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2807 // KFW_AFS_error(rc, "get_cellconfig()");
2814 code = pkrb5_init_context(&ctx);
2815 if (code) goto cleanup;
2821 code = pkrb5_cc_default(ctx, &cc);
2822 if (code) goto skip_krb5_init;
2825 memset((char *)&increds, 0, sizeof(increds));
2827 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2829 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2831 OutputDebugString("Principal Not Found for ccache\n");
2833 goto skip_krb5_init;
2836 if (!KFW_accept_dotted_usernames()) {
2837 /* look for client principals which cannot be distinguished
2838 * from Kerberos 4 multi-component principal names
2840 k5data = krb5_princ_component(ctx,client_principal,0);
2841 for ( i=0; i<k5data->length; i++ ) {
2842 if ( k5data->data[i] == '.' )
2845 if (i != k5data->length)
2847 OutputDebugString("Illegal Principal name contains dot in first component\n");
2848 rc = KRB5KRB_ERR_GENERIC;
2853 i = krb5_princ_realm(ctx, client_principal)->length;
2856 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2857 realm_of_user[i] = 0;
2862 if ( !try_krb5 || !realm_of_user[0] ) {
2863 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2872 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2874 if (strlen(service) == 0)
2875 strcpy(ServiceName, "afs");
2877 strcpy(ServiceName, service);
2879 if (strlen(cell) == 0)
2880 strcpy(CellName, local_cell);
2882 strcpy(CellName, cell);
2884 if (strlen(realm) == 0)
2885 strcpy(RealmName, realm_of_cell);
2887 strcpy(RealmName, realm);
2889 memset(&creds, '\0', sizeof(creds));
2894 /* First try service/cell@REALM */
2895 if (code = pkrb5_build_principal(ctx, &increds.server,
2896 (int)strlen(RealmName),
2905 increds.client = client_principal;
2906 increds.times.endtime = 0;
2907 /* Ask for DES since that is what V4 understands */
2908 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2911 if ( IsDebuggerPresent() ) {
2912 char * cname, *sname;
2913 pkrb5_unparse_name(ctx, increds.client, &cname);
2914 pkrb5_unparse_name(ctx, increds.server, &sname);
2915 OutputDebugString("Getting tickets for \"");
2916 OutputDebugString(cname);
2917 OutputDebugString("\" and service \"");
2918 OutputDebugString(sname);
2919 OutputDebugString("\"\n");
2920 pkrb5_free_unparsed_name(ctx,cname);
2921 pkrb5_free_unparsed_name(ctx,sname);
2924 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2925 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2926 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2927 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2928 /* Or service@REALM */
2929 pkrb5_free_principal(ctx,increds.server);
2931 code = pkrb5_build_principal(ctx, &increds.server,
2932 (int)strlen(RealmName),
2937 if ( IsDebuggerPresent() ) {
2938 char * cname, *sname;
2939 pkrb5_unparse_name(ctx, increds.client, &cname);
2940 pkrb5_unparse_name(ctx, increds.server, &sname);
2941 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2942 OutputDebugString("Trying again: getting tickets for \"");
2943 OutputDebugString(cname);
2944 OutputDebugString("\" and service \"");
2945 OutputDebugString(sname);
2946 OutputDebugString("\"\n");
2947 pkrb5_free_unparsed_name(ctx,cname);
2948 pkrb5_free_unparsed_name(ctx,sname);
2952 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2955 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2956 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2957 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2958 strcmp(RealmName, realm_of_cell)) {
2959 /* Or service/cell@REALM_OF_CELL */
2960 strcpy(RealmName, realm_of_cell);
2961 pkrb5_free_principal(ctx,increds.server);
2963 code = pkrb5_build_principal(ctx, &increds.server,
2964 (int)strlen(RealmName),
2970 if ( IsDebuggerPresent() ) {
2971 char * cname, *sname;
2972 pkrb5_unparse_name(ctx, increds.client, &cname);
2973 pkrb5_unparse_name(ctx, increds.server, &sname);
2974 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2975 OutputDebugString("Trying again: getting tickets for \"");
2976 OutputDebugString(cname);
2977 OutputDebugString("\" and service \"");
2978 OutputDebugString(sname);
2979 OutputDebugString("\"\n");
2980 pkrb5_free_unparsed_name(ctx,cname);
2981 pkrb5_free_unparsed_name(ctx,sname);
2985 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2988 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2989 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2990 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2991 /* Or service@REALM_OF_CELL */
2992 pkrb5_free_principal(ctx,increds.server);
2994 code = pkrb5_build_principal(ctx, &increds.server,
2995 (int)strlen(RealmName),
3000 if ( IsDebuggerPresent() ) {
3001 char * cname, *sname;
3002 pkrb5_unparse_name(ctx, increds.client, &cname);
3003 pkrb5_unparse_name(ctx, increds.server, &sname);
3004 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
3005 OutputDebugString("Trying again: getting tickets for \"");
3006 OutputDebugString(cname);
3007 OutputDebugString("\" and service \"");
3008 OutputDebugString(sname);
3009 OutputDebugString("\"\n");
3010 pkrb5_free_unparsed_name(ctx,cname);
3011 pkrb5_free_unparsed_name(ctx,sname);
3015 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
3020 if ( IsDebuggerPresent() ) {
3022 sprintf(message,"krb5_get_credentials returns: %d\n",code);
3023 OutputDebugString(message);
3029 /* This code inserts the entire K5 ticket into the token
3030 * No need to perform a krb524 translation which is
3031 * commented out in the code below
3033 if (KFW_use_krb524() ||
3034 k5creds->ticket.length > MAXKTCTICKETLEN)
3037 memset(&aserver, '\0', sizeof(aserver));
3038 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3039 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3041 memset(&atoken, '\0', sizeof(atoken));
3042 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
3043 atoken.startTime = k5creds->times.starttime;
3044 atoken.endTime = k5creds->times.endtime;
3045 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
3046 atoken.ticketLen = k5creds->ticket.length;
3047 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
3050 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3051 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3052 if ( rc == KTC_NOCM && retry < 20 ) {
3055 goto retry_gettoken5;
3060 if (atoken.kvno == btoken.kvno &&
3061 atoken.ticketLen == btoken.ticketLen &&
3062 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3063 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3065 /* Success - Nothing to do */
3069 // * Reset the "aclient" structure before we call ktc_SetToken.
3070 // * This structure was first set by the ktc_GetToken call when
3071 // * we were comparing whether identical tokens already existed.
3073 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
3074 strncpy(aclient.name, k5creds->client->data[0].data, len);
3075 aclient.name[len] = '\0';
3077 if ( k5creds->client->length > 1 ) {
3079 strcat(aclient.name, ".");
3080 p = aclient.name + strlen(aclient.name);
3081 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3082 strncpy(p, k5creds->client->data[1].data, len);
3085 aclient.instance[0] = '\0';
3087 strcpy(aclient.cell, realm_of_cell);
3089 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3090 /* For Khimaira, always append the realm name */
3091 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3093 strcat(aclient.name, "@");
3094 p = aclient.name + strlen(aclient.name);
3095 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3096 strncpy(p, k5creds->client->realm.data, len);
3100 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3101 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3102 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3103 &aclient, &aserver, &atoken);
3106 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3107 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3109 aclient.smbname[0] = '\0';
3112 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3114 goto cleanup; /* We have successfully inserted the token */
3120 /* Otherwise, the ticket could have been too large so try to
3121 * convert using the krb524d running with the KDC
3123 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3124 pkrb5_free_creds(ctx, k5creds);
3126 if ( IsDebuggerPresent() ) {
3128 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3129 OutputDebugString(message);
3134 #endif /* USE_KRB524 */
3138 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3139 if (code == NO_TKT_FIL) {
3140 // if the problem is that we have no krb4 tickets
3141 // do not attempt to continue
3144 if (code != KSUCCESS)
3145 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3147 if (code != KSUCCESS)
3149 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3151 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3156 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3158 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3173 memset(&aserver, '\0', sizeof(aserver));
3174 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3175 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3177 memset(&atoken, '\0', sizeof(atoken));
3178 atoken.kvno = creds.kvno;
3179 atoken.startTime = creds.issue_date;
3180 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3181 memcpy(&atoken.sessionKey, creds.session, 8);
3182 atoken.ticketLen = creds.ticket_st.length;
3183 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3186 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3187 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3188 if ( rc == KTC_NOCM && retry < 20 ) {
3191 goto retry_gettoken;
3193 KFW_AFS_error(rc, "ktc_GetToken()");
3198 if (atoken.kvno == btoken.kvno &&
3199 atoken.ticketLen == btoken.ticketLen &&
3200 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3201 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3206 // * Reset the "aclient" structure before we call ktc_SetToken.
3207 // * This structure was first set by the ktc_GetToken call when
3208 // * we were comparing whether identical tokens already existed.
3210 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3213 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3214 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3216 strcpy(aclient.instance, "");
3218 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3219 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3220 aclient.name[MAXKTCREALMLEN-1] = '\0';
3222 strcpy(aclient.cell, CellName);
3224 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3225 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3226 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3227 &aclient, &aserver, &atoken);
3230 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3231 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3233 aclient.smbname[0] = '\0';
3236 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3238 KFW_AFS_error(rc, "ktc_SetToken()");
3244 if (client_principal)
3245 pkrb5_free_principal(ctx,client_principal);
3246 /* increds.client == client_principal */
3248 pkrb5_free_principal(ctx,increds.server);
3249 if (cc && (cc != alt_cc))
3250 pkrb5_cc_close(ctx, cc);
3251 if (ctx && (ctx != alt_ctx))
3252 pkrb5_free_context(ctx);
3254 return(rc? rc : code);
3257 /**************************************/
3258 /* afs_realm_of_cell(): */
3259 /**************************************/
3261 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3263 static char krbrlm[REALM_SZ+1]="";
3264 char ** realmlist=NULL;
3270 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3271 if ( !r && realmlist && realmlist[0] ) {
3272 strcpy(krbrlm, realmlist[0]);
3273 pkrb5_free_host_realm(ctx, realmlist);
3279 char *t = cellconfig->name;
3284 if (islower(c)) c=toupper(c);
3292 /**************************************/
3293 /* KFW_AFS_get_cellconfig(): */
3294 /**************************************/
3296 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3299 char newcell[MAXCELLCHARS+1];
3301 local_cell[0] = (char)0;
3302 memset(cellconfig, 0, sizeof(*cellconfig));
3304 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3305 if (rc = cm_GetRootCellName(local_cell))
3310 if (strlen(cell) == 0)
3311 strcpy(cell, local_cell);
3313 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3314 strcpy(cellconfig->name, cell);
3316 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3317 #ifdef AFS_AFSDB_ENV
3320 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3326 /**************************************/
3327 /* get_cellconfig_callback(): */
3328 /**************************************/
3330 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3332 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3334 cc->hostAddr[cc->numServers] = *addrp;
3335 strcpy(cc->hostName[cc->numServers], namep);
3341 /**************************************/
3342 /* KFW_AFS_error(): */
3343 /**************************************/
3345 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3348 const char *errText;
3350 // Using AFS defines as error messages for now, until Transarc
3351 // gets back to me with "string" translations of each of these
3353 if (rc == KTC_ERROR)
3354 errText = "KTC_ERROR";
3355 else if (rc == KTC_TOOBIG)
3356 errText = "KTC_TOOBIG";
3357 else if (rc == KTC_INVAL)
3358 errText = "KTC_INVAL";
3359 else if (rc == KTC_NOENT)
3360 errText = "KTC_NOENT";
3361 else if (rc == KTC_PIOCTLFAIL)
3362 errText = "KTC_PIOCTLFAIL";
3363 else if (rc == KTC_NOPIOCTL)
3364 errText = "KTC_NOPIOCTL";
3365 else if (rc == KTC_NOCELL)
3366 errText = "KTC_NOCELL";
3367 else if (rc == KTC_NOCM)
3368 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3370 errText = "Unknown error!";
3372 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3374 if ( IsDebuggerPresent() ) {
3375 OutputDebugString(message);
3376 OutputDebugString("\n");
3378 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3384 LPSTR lpszMachineName,
3385 LPSTR lpszServiceName,
3386 DWORD *lpdwCurrentState)
3389 SC_HANDLE schSCManager = NULL;
3390 SC_HANDLE schService = NULL;
3391 DWORD fdwDesiredAccess = 0;
3392 SERVICE_STATUS ssServiceStatus = {0};
3395 *lpdwCurrentState = 0;
3397 fdwDesiredAccess = GENERIC_READ;
3399 schSCManager = OpenSCManager(lpszMachineName,
3403 if(schSCManager == NULL)
3405 hr = GetLastError();
3409 schService = OpenService(schSCManager,
3413 if(schService == NULL)
3415 hr = GetLastError();
3419 fRet = QueryServiceStatus(schService,
3424 hr = GetLastError();
3428 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3432 CloseServiceHandle(schService);
3433 CloseServiceHandle(schSCManager);
3446 for (n = 0; fi[n].func_ptr_var; n++)
3447 *(fi[n].func_ptr_var) = 0;
3448 if (h) FreeLibrary(h);
3453 const char* dll_name,
3455 HINSTANCE* ph, // [out, optional] - DLL handle
3456 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3457 int cleanup, // cleanup function pointers and unload on error
3458 int go_on, // continue loading even if some functions cannot be loaded
3459 int silent // do not pop-up a system dialog if DLL cannot be loaded
3468 if (pindex) *pindex = -1;
3470 for (n = 0; fi[n].func_ptr_var; n++)
3471 *(fi[n].func_ptr_var) = 0;
3474 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3475 h = LoadLibrary(dll_name);
3483 for (i = 0; (go_on || !error) && (i < n); i++)
3485 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3491 *(fi[i].func_ptr_var) = p;
3494 if (pindex) *pindex = last_i;
3495 if (error && cleanup && !go_on) {
3496 for (i = 0; i < n; i++) {
3497 *(fi[i].func_ptr_var) = 0;
3503 if (error) return 0;
3507 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3509 krb5_context ctx = NULL;
3510 krb5_ccache cc = NULL;
3511 krb5_error_code code;
3513 const char * realm = NULL;
3514 krb5_principal principal = NULL;
3515 char * pname = NULL;
3516 char password[PROBE_PASSWORD_LEN+1];
3517 BOOL serverReachable = 0;
3519 if (!pkrb5_init_context)
3522 code = pkrb5_init_context(&ctx);
3523 if (code) goto cleanup;
3526 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3528 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3529 realm, PROBE_USERNAME, NULL, NULL);
3530 if ( code ) goto cleanup;
3532 code = KFW_get_ccache(ctx, principal, &cc);
3533 if ( code ) goto cleanup;
3535 code = pkrb5_unparse_name(ctx, principal, &pname);
3536 if ( code ) goto cleanup;
3538 pwdata.data = password;
3539 pwdata.length = PROBE_PASSWORD_LEN;
3540 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3543 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3546 password[PROBE_PASSWORD_LEN] = '\0';
3548 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3558 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3559 case KRB5KDC_ERR_CLIENT_REVOKED:
3560 case KRB5KDC_ERR_CLIENT_NOTYET:
3561 case KRB5KDC_ERR_PREAUTH_FAILED:
3562 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3563 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3564 serverReachable = TRUE;
3567 serverReachable = FALSE;
3572 pkrb5_free_unparsed_name(ctx,pname);
3574 pkrb5_free_principal(ctx,principal);
3576 pkrb5_cc_close(ctx,cc);
3578 pkrb5_free_context(ctx);
3580 return serverReachable;
3584 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3586 krb5_context ctx = NULL;
3587 krb5_error_code code;
3588 krb5_ccache mslsa_ccache=NULL;
3589 krb5_principal princ = NULL;
3590 char * pname = NULL;
3593 if (!KFW_is_available())
3596 if (code = pkrb5_init_context(&ctx))
3599 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3602 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3605 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3608 if ( strlen(pname) < *dwSize ) {
3609 strncpy(szUser, pname, *dwSize);
3610 szUser[*dwSize-1] = '\0';
3613 *dwSize = (DWORD)strlen(pname);
3617 pkrb5_free_unparsed_name(ctx, pname);
3620 pkrb5_free_principal(ctx, princ);
3623 pkrb5_cc_close(ctx, mslsa_ccache);
3626 pkrb5_free_context(ctx);
3631 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3633 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3634 PSID pSystemSID = NULL;
3635 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3636 PACL ccacheACL = NULL;
3637 DWORD ccacheACLlength = 0;
3638 PTOKEN_USER pTokenUser = NULL;
3647 /* Get System SID */
3648 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3654 SystemSIDlength = GetLengthSid(pSystemSID);
3655 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3656 + SystemSIDlength - sizeof(DWORD);
3659 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3661 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3662 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3664 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3669 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3671 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3676 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3681 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3682 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3683 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3686 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3687 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3688 pTokenUser->User.Sid);
3689 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3690 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3695 gle = GetLastError();
3696 if (gle != ERROR_NO_TOKEN)
3699 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3700 OWNER_SECURITY_INFORMATION,
3701 pTokenUser->User.Sid,
3705 gle = GetLastError();
3706 if (gle != ERROR_NO_TOKEN)
3710 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3711 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3716 gle = GetLastError();
3717 if (gle != ERROR_NO_TOKEN)
3724 LocalFree(pSystemSID);
3726 LocalFree(pTokenUser);
3728 LocalFree(ccacheACL);
3733 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3736 DWORD dwSize = size-1; /* leave room for nul */
3739 if (!hUserToken || !newfilename || size <= 0)
3742 *newfilename = '\0';
3744 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3745 if ( !dwLen || dwLen > dwSize )
3746 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3747 if ( !dwLen || dwLen > dwSize )
3750 newfilename[dwSize] = '\0';
3755 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3757 char filename[MAX_PATH] = "";
3759 char cachename[MAX_PATH + 8] = "FILE:";
3760 krb5_context ctx = NULL;
3761 krb5_error_code code;
3762 krb5_principal princ = NULL;
3763 krb5_ccache cc = NULL;
3764 krb5_ccache ncc = NULL;
3766 if (!pkrb5_init_context || !user || !szLogonId)
3769 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3770 if ( count > sizeof(filename) || count == 0 ) {
3771 GetWindowsDirectory(filename, sizeof(filename));
3774 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3777 strcat(filename, "\\");
3778 strcat(filename, szLogonId);
3780 strcat(cachename, filename);
3782 DeleteFile(filename);
3784 code = pkrb5_init_context(&ctx);
3785 if (code) goto cleanup;
3787 code = pkrb5_parse_name(ctx, user, &princ);
3788 if (code) goto cleanup;
3790 code = KFW_get_ccache(ctx, princ, &cc);
3791 if (code) goto cleanup;
3793 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3794 if (code) goto cleanup;
3796 code = pkrb5_cc_initialize(ctx, ncc, princ);
3797 if (code) goto cleanup;
3799 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3800 if (code) goto cleanup;
3802 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3806 pkrb5_cc_close(ctx, cc);
3810 pkrb5_cc_close(ctx, ncc);
3814 pkrb5_free_principal(ctx, princ);
3819 pkrb5_free_context(ctx);
3823 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3825 char cachename[MAX_PATH + 8] = "FILE:";
3826 krb5_context ctx = NULL;
3827 krb5_error_code code;
3828 krb5_principal princ = NULL;
3829 krb5_ccache cc = NULL;
3830 krb5_ccache ncc = NULL;
3833 if (!pkrb5_init_context || !filename)
3836 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3839 code = pkrb5_init_context(&ctx);
3842 strcat(cachename, filename);
3844 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3845 if (code) goto cleanup;
3847 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3849 code = pkrb5_cc_default(ctx, &ncc);
3851 code = pkrb5_cc_initialize(ctx, ncc, princ);
3854 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3857 pkrb5_cc_close(ctx, ncc);
3861 retval=0; /* success */
3865 pkrb5_cc_close(ctx, cc);
3869 DeleteFile(filename);
3872 pkrb5_free_principal(ctx, princ);
3877 pkrb5_free_context(ctx);
3882 /* We are including this
3884 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3885 fixed part of rande of the one byte lifetime field. Values less than 0x80
3886 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3887 0xBF should be looked up in this table. The value of 0x80 is the same using
3888 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3889 The intervening values of have a fixed ratio of roughly 1.06914. The value
3890 oxFF is defined to mean a ticket has no expiration time. This should be
3891 used advisedly since individual servers may impose defacto upperbounds on
3892 ticket lifetimes. */
3894 #define TKTLIFENUMFIXED 64
3895 #define TKTLIFEMINFIXED 0x80
3896 #define TKTLIFEMAXFIXED 0xBF
3897 #define TKTLIFENOEXPIRE 0xFF
3898 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3900 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3901 38400, /* 10.67 hours, 0.44 days */
3902 41055, /* 11.40 hours, 0.48 days */
3903 43894, /* 12.19 hours, 0.51 days */
3904 46929, /* 13.04 hours, 0.54 days */
3905 50174, /* 13.94 hours, 0.58 days */
3906 53643, /* 14.90 hours, 0.62 days */
3907 57352, /* 15.93 hours, 0.66 days */
3908 61318, /* 17.03 hours, 0.71 days */
3909 65558, /* 18.21 hours, 0.76 days */
3910 70091, /* 19.47 hours, 0.81 days */
3911 74937, /* 20.82 hours, 0.87 days */
3912 80119, /* 22.26 hours, 0.93 days */
3913 85658, /* 23.79 hours, 0.99 days */
3914 91581, /* 25.44 hours, 1.06 days */
3915 97914, /* 27.20 hours, 1.13 days */
3916 104684, /* 29.08 hours, 1.21 days */
3917 111922, /* 31.09 hours, 1.30 days */
3918 119661, /* 33.24 hours, 1.38 days */
3919 127935, /* 35.54 hours, 1.48 days */
3920 136781, /* 37.99 hours, 1.58 days */
3921 146239, /* 40.62 hours, 1.69 days */
3922 156350, /* 43.43 hours, 1.81 days */
3923 167161, /* 46.43 hours, 1.93 days */
3924 178720, /* 49.64 hours, 2.07 days */
3925 191077, /* 53.08 hours, 2.21 days */
3926 204289, /* 56.75 hours, 2.36 days */
3927 218415, /* 60.67 hours, 2.53 days */
3928 233517, /* 64.87 hours, 2.70 days */
3929 249664, /* 69.35 hours, 2.89 days */
3930 266926, /* 74.15 hours, 3.09 days */
3931 285383, /* 79.27 hours, 3.30 days */
3932 305116, /* 84.75 hours, 3.53 days */
3933 326213, /* 90.61 hours, 3.78 days */
3934 348769, /* 96.88 hours, 4.04 days */
3935 372885, /* 103.58 hours, 4.32 days */
3936 398668, /* 110.74 hours, 4.61 days */
3937 426234, /* 118.40 hours, 4.93 days */
3938 455705, /* 126.58 hours, 5.27 days */
3939 487215, /* 135.34 hours, 5.64 days */
3940 520904, /* 144.70 hours, 6.03 days */
3941 556921, /* 154.70 hours, 6.45 days */
3942 595430, /* 165.40 hours, 6.89 days */
3943 636601, /* 176.83 hours, 7.37 days */
3944 680618, /* 189.06 hours, 7.88 days */
3945 727680, /* 202.13 hours, 8.42 days */
3946 777995, /* 216.11 hours, 9.00 days */
3947 831789, /* 231.05 hours, 9.63 days */
3948 889303, /* 247.03 hours, 10.29 days */
3949 950794, /* 264.11 hours, 11.00 days */
3950 1016537, /* 282.37 hours, 11.77 days */
3951 1086825, /* 301.90 hours, 12.58 days */
3952 1161973, /* 322.77 hours, 13.45 days */
3953 1242318, /* 345.09 hours, 14.38 days */
3954 1328218, /* 368.95 hours, 15.37 days */
3955 1420057, /* 394.46 hours, 16.44 days */
3956 1518247, /* 421.74 hours, 17.57 days */
3957 1623226, /* 450.90 hours, 18.79 days */
3958 1735464, /* 482.07 hours, 20.09 days */
3959 1855462, /* 515.41 hours, 21.48 days */
3960 1983758, /* 551.04 hours, 22.96 days */
3961 2120925, /* 589.15 hours, 24.55 days */
3962 2267576, /* 629.88 hours, 26.25 days */
3963 2424367, /* 673.44 hours, 28.06 days */
3965 }; /* 720.00 hours, 30.00 days */
3967 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3968 * returns the corresponding end time. There are four simple cases to be
3969 * handled. The first is a life of 0xff, meaning no expiration, and results in
3970 * an end time of 0xffffffff. The second is when life is less than the values
3971 * covered by the table. In this case, the end time is the start time plus the
3972 * number of 5 minute intervals specified by life. The third case returns
3973 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3974 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3975 * table to extract the lifetime in seconds, which is added to start to produce
3979 life_to_time(afs_uint32 start, unsigned char life)
3983 if (life == TKTLIFENOEXPIRE)
3985 if (life < TKTLIFEMINFIXED)
3986 return start + life * 5 * 60;
3987 if (life > TKTLIFEMAXFIXED)
3988 return start + MAXTKTLIFETIME;
3989 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3990 return start + realLife;
3993 /* time_to_life - takes start and end times for the ticket and returns a
3994 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3995 * lifetimes above 127*5minutes. First, the special case of (end ==
3996 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3997 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3998 * less than the first table entry are handled by rounding the requested
3999 * lifetime *up* to the next 5 minute interval. The final step is to search
4000 * the table for the smallest entry *greater than or equal* to the requested
4001 * entry. The actual code is prepared to handle the case where the table is
4002 * unordered but that it an unnecessary frill. */
4004 static unsigned char
4005 time_to_life(afs_uint32 start, afs_uint32 end)
4007 int lifetime = end - start;
4011 if (end == NEVERDATE)
4012 return TKTLIFENOEXPIRE;
4013 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
4015 if (lifetime < tkt_lifetimes[0])
4016 return (lifetime + 5 * 60 - 1) / (5 * 60);
4018 best = MAXKTCTICKETLIFETIME;
4019 for (i = 0; i < TKTLIFENUMFIXED; i++)
4020 if (tkt_lifetimes[i] >= lifetime) {
4021 int diff = tkt_lifetimes[i] - lifetime;
4029 return best_i + TKTLIFEMINFIXED;