2 * Copyright (c) 2004, 2005, 2006, 2007 Secure Endpoints Inc.
3 * Copyright (c) 2003 SkyRope, LLC
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * - Neither the name of Skyrope, LLC nor the names of its contributors may be
15 * used to endorse or promote products derived from this software without
16 * specific prior written permission from Skyrope, LLC.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Portions of this code are derived from portions of the MIT
31 * Leash Ticket Manager and LoadFuncs utilities. For these portions the
32 * following copyright applies.
34 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
35 * All rights reserved.
37 * Export of this software from the United States of America may
38 * require a specific license from the United States Government.
39 * It is the responsibility of any person or organization contemplating
40 * export to obtain such a license before exporting.
42 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43 * distribute this software and its documentation for any purpose and
44 * without fee is hereby granted, provided that the above copyright
45 * notice appear in all copies and that both that copyright notice and
46 * this permission notice appear in supporting documentation, and that
47 * the name of M.I.T. not be used in advertising or publicity pertaining
48 * to distribution of the software without specific, written prior
49 * permission. Furthermore if you modify this software you must label
50 * your software as modified software and not distribute it in such a
51 * fashion that it might be confused with the original M.I.T. software.
52 * M.I.T. makes no representations about the suitability of
53 * this software for any purpose. It is provided "as is" without express
54 * or implied warranty.
66 #include "afskfw-int.h"
74 #include <afs/ptserver.h>
75 #include <afs/ptuser.h>
78 #include <WINNT\afsreg.h>
81 * TIMING _____________________________________________________________________
85 #define cminREMIND_TEST 1 // test every minute for expired creds
86 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
87 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
88 #define cminMINLIFE 30 // minimum life of Kerberos creds
90 #define c100ns1SECOND (LONGLONG)10000000
91 #define cmsec1SECOND 1000
92 #define cmsec1MINUTE 60000
93 #define csec1MINUTE 60
95 /* Function Pointer Declarations for Delayed Loading */
97 DECL_FUNC_PTR(cc_initialize);
98 DECL_FUNC_PTR(cc_shutdown);
99 DECL_FUNC_PTR(cc_get_NC_info);
100 DECL_FUNC_PTR(cc_free_NC_info);
104 DECL_FUNC_PTR(Leash_get_default_lifetime);
105 DECL_FUNC_PTR(Leash_get_default_forwardable);
106 DECL_FUNC_PTR(Leash_get_default_renew_till);
107 DECL_FUNC_PTR(Leash_get_default_noaddresses);
108 DECL_FUNC_PTR(Leash_get_default_proxiable);
109 DECL_FUNC_PTR(Leash_get_default_publicip);
110 DECL_FUNC_PTR(Leash_get_default_use_krb4);
111 DECL_FUNC_PTR(Leash_get_default_life_min);
112 DECL_FUNC_PTR(Leash_get_default_life_max);
113 DECL_FUNC_PTR(Leash_get_default_renew_min);
114 DECL_FUNC_PTR(Leash_get_default_renew_max);
115 DECL_FUNC_PTR(Leash_get_default_renewable);
116 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
120 DECL_FUNC_PTR(krb5_change_password);
121 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
122 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
123 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
124 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
125 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
126 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
127 DECL_FUNC_PTR(krb5_get_init_creds_password);
128 DECL_FUNC_PTR(krb5_build_principal_ext);
129 DECL_FUNC_PTR(krb5_cc_get_name);
130 DECL_FUNC_PTR(krb5_cc_resolve);
131 DECL_FUNC_PTR(krb5_cc_default);
132 DECL_FUNC_PTR(krb5_cc_default_name);
133 DECL_FUNC_PTR(krb5_cc_set_default_name);
134 DECL_FUNC_PTR(krb5_cc_initialize);
135 DECL_FUNC_PTR(krb5_cc_destroy);
136 DECL_FUNC_PTR(krb5_cc_close);
137 DECL_FUNC_PTR(krb5_cc_store_cred);
138 DECL_FUNC_PTR(krb5_cc_copy_creds);
139 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
140 DECL_FUNC_PTR(krb5_cc_get_principal);
141 DECL_FUNC_PTR(krb5_cc_start_seq_get);
142 DECL_FUNC_PTR(krb5_cc_next_cred);
143 DECL_FUNC_PTR(krb5_cc_end_seq_get);
144 DECL_FUNC_PTR(krb5_cc_remove_cred);
145 DECL_FUNC_PTR(krb5_cc_set_flags);
146 DECL_FUNC_PTR(krb5_cc_get_type);
147 DECL_FUNC_PTR(krb5_free_context);
148 DECL_FUNC_PTR(krb5_free_cred_contents);
149 DECL_FUNC_PTR(krb5_free_principal);
150 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
151 DECL_FUNC_PTR(krb5_init_context);
152 DECL_FUNC_PTR(krb5_parse_name);
153 DECL_FUNC_PTR(krb5_timeofday);
154 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
155 DECL_FUNC_PTR(krb5_unparse_name);
156 DECL_FUNC_PTR(krb5_get_credentials);
157 DECL_FUNC_PTR(krb5_mk_req);
158 DECL_FUNC_PTR(krb5_sname_to_principal);
159 DECL_FUNC_PTR(krb5_get_credentials_renew);
160 DECL_FUNC_PTR(krb5_free_data);
161 DECL_FUNC_PTR(krb5_free_data_contents);
162 DECL_FUNC_PTR(krb5_free_unparsed_name);
163 DECL_FUNC_PTR(krb5_os_localaddr);
164 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
165 DECL_FUNC_PTR(krb5_copy_data);
166 DECL_FUNC_PTR(krb5_free_creds);
167 DECL_FUNC_PTR(krb5_build_principal);
168 DECL_FUNC_PTR(krb5_get_renewed_creds);
169 DECL_FUNC_PTR(krb5_get_default_config_files);
170 DECL_FUNC_PTR(krb5_free_config_files);
171 DECL_FUNC_PTR(krb5_get_default_realm);
172 DECL_FUNC_PTR(krb5_free_default_realm);
173 DECL_FUNC_PTR(krb5_free_ticket);
174 DECL_FUNC_PTR(krb5_decode_ticket);
175 DECL_FUNC_PTR(krb5_get_host_realm);
176 DECL_FUNC_PTR(krb5_free_host_realm);
177 DECL_FUNC_PTR(krb5_free_addresses);
178 DECL_FUNC_PTR(krb5_c_random_make_octets);
182 DECL_FUNC_PTR(krb524_init_ets);
183 DECL_FUNC_PTR(krb524_convert_creds_kdc);
188 DECL_FUNC_PTR(krb_get_cred);
189 DECL_FUNC_PTR(tkt_string);
190 DECL_FUNC_PTR(krb_get_tf_realm);
191 DECL_FUNC_PTR(krb_mk_req);
195 DECL_FUNC_PTR(com_err);
196 DECL_FUNC_PTR(error_message);
199 DECL_FUNC_PTR(profile_init);
200 DECL_FUNC_PTR(profile_release);
201 DECL_FUNC_PTR(profile_get_subsection_names);
202 DECL_FUNC_PTR(profile_free_list);
203 DECL_FUNC_PTR(profile_get_string);
204 DECL_FUNC_PTR(profile_release_string);
207 DECL_FUNC_PTR(OpenSCManagerA);
208 DECL_FUNC_PTR(OpenServiceA);
209 DECL_FUNC_PTR(QueryServiceStatus);
210 DECL_FUNC_PTR(CloseServiceHandle);
212 DECL_FUNC_PTR(LsaNtStatusToWinError);
213 #endif /* USE_MS2MIT */
217 DECL_FUNC_PTR(LsaConnectUntrusted);
218 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
219 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
220 DECL_FUNC_PTR(LsaFreeReturnBuffer);
221 DECL_FUNC_PTR(LsaGetLogonSessionData);
222 #endif /* USE_MS2MIT */
225 FUNC_INFO ccapi_fi[] = {
226 MAKE_FUNC_INFO(cc_initialize),
227 MAKE_FUNC_INFO(cc_shutdown),
228 MAKE_FUNC_INFO(cc_get_NC_info),
229 MAKE_FUNC_INFO(cc_free_NC_info),
234 FUNC_INFO leash_fi[] = {
235 MAKE_FUNC_INFO(Leash_get_default_lifetime),
236 MAKE_FUNC_INFO(Leash_get_default_renew_till),
237 MAKE_FUNC_INFO(Leash_get_default_forwardable),
238 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
239 MAKE_FUNC_INFO(Leash_get_default_proxiable),
240 MAKE_FUNC_INFO(Leash_get_default_publicip),
241 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
242 MAKE_FUNC_INFO(Leash_get_default_life_min),
243 MAKE_FUNC_INFO(Leash_get_default_life_max),
244 MAKE_FUNC_INFO(Leash_get_default_renew_min),
245 MAKE_FUNC_INFO(Leash_get_default_renew_max),
246 MAKE_FUNC_INFO(Leash_get_default_renewable),
250 FUNC_INFO leash_opt_fi[] = {
251 MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
256 FUNC_INFO k5_fi[] = {
257 MAKE_FUNC_INFO(krb5_change_password),
258 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
259 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
260 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
261 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
262 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
263 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
264 MAKE_FUNC_INFO(krb5_get_init_creds_password),
265 MAKE_FUNC_INFO(krb5_build_principal_ext),
266 MAKE_FUNC_INFO(krb5_cc_get_name),
267 MAKE_FUNC_INFO(krb5_cc_resolve),
268 MAKE_FUNC_INFO(krb5_cc_default),
269 MAKE_FUNC_INFO(krb5_cc_default_name),
270 MAKE_FUNC_INFO(krb5_cc_set_default_name),
271 MAKE_FUNC_INFO(krb5_cc_initialize),
272 MAKE_FUNC_INFO(krb5_cc_destroy),
273 MAKE_FUNC_INFO(krb5_cc_close),
274 MAKE_FUNC_INFO(krb5_cc_copy_creds),
275 MAKE_FUNC_INFO(krb5_cc_store_cred),
276 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
277 MAKE_FUNC_INFO(krb5_cc_get_principal),
278 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
279 MAKE_FUNC_INFO(krb5_cc_next_cred),
280 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
281 MAKE_FUNC_INFO(krb5_cc_remove_cred),
282 MAKE_FUNC_INFO(krb5_cc_set_flags),
283 MAKE_FUNC_INFO(krb5_cc_get_type),
284 MAKE_FUNC_INFO(krb5_free_context),
285 MAKE_FUNC_INFO(krb5_free_cred_contents),
286 MAKE_FUNC_INFO(krb5_free_principal),
287 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
288 MAKE_FUNC_INFO(krb5_init_context),
289 MAKE_FUNC_INFO(krb5_parse_name),
290 MAKE_FUNC_INFO(krb5_timeofday),
291 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
292 MAKE_FUNC_INFO(krb5_unparse_name),
293 MAKE_FUNC_INFO(krb5_get_credentials),
294 MAKE_FUNC_INFO(krb5_mk_req),
295 MAKE_FUNC_INFO(krb5_sname_to_principal),
296 MAKE_FUNC_INFO(krb5_get_credentials_renew),
297 MAKE_FUNC_INFO(krb5_free_data),
298 MAKE_FUNC_INFO(krb5_free_data_contents),
299 MAKE_FUNC_INFO(krb5_free_unparsed_name),
300 MAKE_FUNC_INFO(krb5_os_localaddr),
301 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
302 MAKE_FUNC_INFO(krb5_copy_data),
303 MAKE_FUNC_INFO(krb5_free_creds),
304 MAKE_FUNC_INFO(krb5_build_principal),
305 MAKE_FUNC_INFO(krb5_get_renewed_creds),
306 MAKE_FUNC_INFO(krb5_free_addresses),
307 MAKE_FUNC_INFO(krb5_get_default_config_files),
308 MAKE_FUNC_INFO(krb5_free_config_files),
309 MAKE_FUNC_INFO(krb5_get_default_realm),
310 MAKE_FUNC_INFO(krb5_free_default_realm),
311 MAKE_FUNC_INFO(krb5_free_ticket),
312 MAKE_FUNC_INFO(krb5_decode_ticket),
313 MAKE_FUNC_INFO(krb5_get_host_realm),
314 MAKE_FUNC_INFO(krb5_free_host_realm),
315 MAKE_FUNC_INFO(krb5_free_addresses),
316 MAKE_FUNC_INFO(krb5_c_random_make_octets),
321 FUNC_INFO k4_fi[] = {
322 MAKE_FUNC_INFO(krb_get_cred),
323 MAKE_FUNC_INFO(krb_get_tf_realm),
324 MAKE_FUNC_INFO(krb_mk_req),
325 MAKE_FUNC_INFO(tkt_string),
331 FUNC_INFO k524_fi[] = {
332 MAKE_FUNC_INFO(krb524_init_ets),
333 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
338 FUNC_INFO profile_fi[] = {
339 MAKE_FUNC_INFO(profile_init),
340 MAKE_FUNC_INFO(profile_release),
341 MAKE_FUNC_INFO(profile_get_subsection_names),
342 MAKE_FUNC_INFO(profile_free_list),
343 MAKE_FUNC_INFO(profile_get_string),
344 MAKE_FUNC_INFO(profile_release_string),
348 FUNC_INFO ce_fi[] = {
349 MAKE_FUNC_INFO(com_err),
350 MAKE_FUNC_INFO(error_message),
354 FUNC_INFO service_fi[] = {
355 MAKE_FUNC_INFO(OpenSCManagerA),
356 MAKE_FUNC_INFO(OpenServiceA),
357 MAKE_FUNC_INFO(QueryServiceStatus),
358 MAKE_FUNC_INFO(CloseServiceHandle),
360 MAKE_FUNC_INFO(LsaNtStatusToWinError),
361 #endif /* USE_MS2MIT */
366 FUNC_INFO lsa_fi[] = {
367 MAKE_FUNC_INFO(LsaConnectUntrusted),
368 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
369 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
370 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
371 MAKE_FUNC_INFO(LsaGetLogonSessionData),
374 #endif /* USE_MS2MIT */
376 /* Static Prototypes */
377 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
378 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
379 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
380 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
381 void *data, const char *name, const char *banner, int num_prompts,
382 krb5_prompt prompts[]);
385 /* Static Declarations */
386 static int inited = 0;
387 static int mid_cnt = 0;
388 static struct textField * mid_tb = NULL;
389 static HINSTANCE hKrb5 = 0;
391 static HINSTANCE hKrb4 = 0;
392 #endif /* USE_KRB4 */
394 static HINSTANCE hKrb524 = 0;
397 static HINSTANCE hSecur32 = 0;
398 #endif /* USE_MS2MIT */
399 static HINSTANCE hAdvApi32 = 0;
400 static HINSTANCE hComErr = 0;
401 static HINSTANCE hService = 0;
402 static HINSTANCE hProfile = 0;
404 static HINSTANCE hLeash = 0;
405 static HINSTANCE hLeashOpt = 0;
407 static HINSTANCE hCCAPI = 0;
408 static struct principal_ccache_data * princ_cc_data = NULL;
409 static struct cell_principal_map * cell_princ_map = NULL;
414 static int inited = 0;
417 char mutexName[MAX_PATH];
418 HANDLE hMutex = NULL;
420 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
422 hMutex = CreateMutex( NULL, TRUE, mutexName );
423 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
424 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
430 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
431 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
432 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
434 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
435 #endif /* USE_KRB4 */
436 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
438 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
439 #endif /* USE_MS2MIT */
441 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
444 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
445 LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
447 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
449 if ( KFW_is_available() ) {
450 char rootcell[MAXCELLCHARS+1];
452 KFW_import_windows_lsa();
453 #endif /* USE_MS2MIT */
454 KFW_import_ccache_data();
455 KFW_AFS_renew_expiring_tokens();
457 /* WIN32 NOTE: no way to get max chars */
458 if (!cm_GetRootCellName(rootcell))
459 KFW_AFS_renew_token_for_cell(rootcell);
462 ReleaseMutex(hMutex);
472 FreeLibrary(hLeashOpt);
478 FreeLibrary(hKrb524);
484 FreeLibrary(hSecur32);
485 #endif /* USE_MS2MIT */
487 FreeLibrary(hService);
489 FreeLibrary(hComErr);
491 FreeLibrary(hProfile);
495 #endif /* USE_KRB4 */
507 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
508 0, KEY_QUERY_VALUE, &parmKey);
509 if (code == ERROR_SUCCESS) {
510 len = sizeof(use524);
511 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
512 (BYTE *) &use524, &len);
513 RegCloseKey(parmKey);
515 if (code != ERROR_SUCCESS) {
516 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
517 0, KEY_QUERY_VALUE, &parmKey);
518 if (code == ERROR_SUCCESS) {
519 len = sizeof(use524);
520 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
521 (BYTE *) &use524, &len);
522 RegCloseKey (parmKey);
529 KFW_is_available(void)
535 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
536 0, KEY_QUERY_VALUE, &parmKey);
537 if (code == ERROR_SUCCESS) {
538 len = sizeof(enableKFW);
539 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
540 (BYTE *) &enableKFW, &len);
541 RegCloseKey (parmKey);
544 if (code != ERROR_SUCCESS) {
545 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
546 0, KEY_QUERY_VALUE, &parmKey);
547 if (code == ERROR_SUCCESS) {
548 len = sizeof(enableKFW);
549 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
550 (BYTE *) &enableKFW, &len);
551 RegCloseKey (parmKey);
559 if ( hKrb5 && hComErr && hService &&
562 #endif /* USE_MS2MIT */
575 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
576 int FreeContextFlag, krb5_context * ctx,
581 int krb5Error = ((int)(rc & 255));
593 errText = perror_message(rc);
594 _snprintf(message, sizeof(message),
595 "%s\n(Kerberos error %ld)\n\n%s failed",
600 if ( IsDebuggerPresent() )
601 OutputDebugString(message);
603 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
606 if (FreeContextFlag == 1)
608 if (ctx && *ctx != NULL)
610 if (cache && *cache != NULL) {
611 pkrb5_cc_close(*ctx, *cache);
615 pkrb5_free_context(*ctx);
624 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
626 struct principal_ccache_data * next = princ_cc_data;
627 krb5_principal principal = 0;
629 const char * ccname = NULL;
630 krb5_error_code code = 0;
631 krb5_error_code cc_code = 0;
637 if (ctx == 0 || cc == 0)
640 code = pkrb5_cc_get_principal(ctx, cc, &principal);
643 code = pkrb5_unparse_name(ctx, principal, &pname);
644 if ( code ) goto cleanup;
646 ccname = pkrb5_cc_get_name(ctx, cc);
647 if (!ccname) goto cleanup;
649 // Search the existing list to see if we have a match
651 for ( ; next ; next = next->next ) {
652 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
657 // If not, match add a new node to the beginning of the list and assign init it
659 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
660 next->next = princ_cc_data;
661 princ_cc_data = next;
662 next->principal = _strdup(pname);
663 next->ccache_name = _strdup(ccname);
664 next->from_lsa = lsa;
666 next->expiration_time = 0;
670 flags = 0; // turn off OPENCLOSE mode
671 code = pkrb5_cc_set_flags(ctx, cc, flags);
672 if ( code ) goto cleanup;
674 code = pkrb5_timeofday(ctx, &now);
676 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
678 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
679 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
681 // we found the ticket we are looking for
682 // check validity of timestamp
683 // We add a 5 minutes fudge factor to compensate for potential
684 // clock skew errors between the KDC and client OS
686 valid = ((creds.times.starttime > 0) &&
687 now >= (creds.times.starttime - 300) &&
688 now < (creds.times.endtime + 300) &&
689 !(creds.ticket_flags & TKT_FLG_INVALID));
691 if ( next->from_lsa) {
693 next->expiration_time = creds.times.endtime;
695 } else if ( valid ) {
697 next->expiration_time = creds.times.endtime;
698 next->renew = (creds.times.renew_till > creds.times.endtime) &&
699 (creds.ticket_flags & TKT_FLG_RENEWABLE);
702 next->expiration_time = 0;
706 pkrb5_free_cred_contents(ctx, &creds);
707 cc_code = KRB5_CC_END;
710 pkrb5_free_cred_contents(ctx, &creds);
713 if (cc_code == KRB5_CC_END) {
714 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
715 if (code) goto cleanup;
719 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
720 code = pkrb5_cc_set_flags(ctx, cc, flags);
723 pkrb5_free_unparsed_name(ctx,pname);
725 pkrb5_free_principal(ctx,principal);
729 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
731 struct principal_ccache_data * next = princ_cc_data;
732 char * response = NULL;
734 if ( !principal || !ccache )
738 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
740 // we always want to prefer the MS Kerberos LSA cache or
741 // the cache afscreds created specifically for the principal
742 // if the current entry is either one, drop the previous find
743 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
746 response = _strdup(next->ccache_name);
747 // MS Kerberos LSA is our best option so use it and quit
748 if ( next->from_lsa )
762 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
764 struct principal_ccache_data ** next = &princ_cc_data;
766 if ( !pname && !ccname )
770 if ( !strcmp((*next)->principal,pname) ||
771 !strcmp((*next)->ccache_name,ccname) ) {
773 free((*next)->principal);
774 free((*next)->ccache_name);
776 (*next) = (*next)->next;
783 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
785 struct cell_principal_map * next = cell_princ_map;
787 // Search the existing list to see if we have a match
789 for ( ; next ; next = next->next ) {
790 if ( !strcmp(next->cell, cell) ) {
791 if ( !strcmp(next->principal,pname) ) {
792 next->active = active;
795 // OpenAFS currently has a restriction of one active token per cell
796 // Therefore, whenever we update the table with a new active cell we
797 // must mark all of the other principal to cell entries as inactive.
805 // If not, match add a new node to the beginning of the list and assign init it
807 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
808 next->next = cell_princ_map;
809 cell_princ_map = next;
810 next->principal = _strdup(pname);
811 next->cell = _strdup(cell);
812 next->active = active;
817 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
819 struct cell_principal_map ** next = &cell_princ_map;
821 if ( !pname && !cell )
825 if ( !strcmp((*next)->principal,pname) ||
826 !strcmp((*next)->cell,cell) ) {
828 free((*next)->principal);
831 (*next) = (*next)->next;
837 // Returns (if possible) a principal which has been known in
838 // the past to have been used to obtain tokens for the specified
840 // TODO: Attempt to return one which has not yet expired by checking
841 // the principal/ccache data
843 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
845 struct cell_principal_map * next_map = cell_princ_map;
846 const char * princ = NULL;
853 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
856 next_map = next_map->next;
859 if ( !principals || !count )
862 *principals = (char **) malloc(sizeof(char *) * count);
863 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
865 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
866 (*principals)[i++] = _strdup(next_map->principal);
873 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
876 struct cell_principal_map * next_map = cell_princ_map;
877 const char * princ = NULL;
883 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
886 next_map = next_map->next;
892 *cells = (char **) malloc(sizeof(char *) * count);
893 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
895 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
896 (*cells)[i++] = _strdup(next_map->cell);
902 /* Given a principal return an existing ccache or create one and return */
904 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
906 krb5_context ctx = NULL;
908 char * ccname = NULL;
909 krb5_error_code code;
911 if (!pkrb5_init_context)
917 code = pkrb5_init_context(&ctx);
918 if (code) goto cleanup;
922 code = pkrb5_unparse_name(ctx, principal, &pname);
923 if (code) goto cleanup;
925 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
926 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
927 ccname = (char *)malloc(strlen(pname) + 5);
928 sprintf(ccname,"API:%s",pname);
930 code = pkrb5_cc_resolve(ctx, ccname, cc);
932 code = pkrb5_cc_default(ctx, cc);
933 if (code) goto cleanup;
940 pkrb5_free_unparsed_name(ctx,pname);
941 if (ctx && (ctx != alt_ctx))
942 pkrb5_free_context(ctx);
947 // Import Microsoft Credentials into a new MIT ccache
949 KFW_import_windows_lsa(void)
951 krb5_context ctx = NULL;
952 krb5_ccache cc = NULL;
953 krb5_principal princ = NULL;
955 krb5_data * princ_realm;
956 krb5_error_code code;
957 char cell[128]="", realm[128]="", *def_realm = 0;
961 if (!pkrb5_init_context)
964 code = pkrb5_init_context(&ctx);
965 if (code) goto cleanup;
967 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
968 if (code) goto cleanup;
970 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
972 code = pkrb5_cc_get_principal(ctx, cc, &princ);
973 if ( code ) goto cleanup;
975 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
976 switch ( dwMsLsaImport ) {
977 case 0: /* do not import */
979 case 1: /* always import */
981 case 2: { /* matching realm */
982 char ms_realm[128] = "", *r;
985 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
986 *r = krb5_princ_realm(ctx, princ)->data[i];
990 if (code = pkrb5_get_default_realm(ctx, &def_realm))
993 if (strcmp(def_realm, ms_realm))
1001 code = pkrb5_unparse_name(ctx,princ,&pname);
1002 if ( code ) goto cleanup;
1004 princ_realm = krb5_princ_realm(ctx, princ);
1005 for ( i=0; i<princ_realm->length; i++ ) {
1006 realm[i] = princ_realm->data[i];
1007 cell[i] = tolower(princ_realm->data[i]);
1012 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
1013 if ( IsDebuggerPresent() ) {
1015 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1016 OutputDebugString(message);
1018 if ( code ) goto cleanup;
1020 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1024 pkrb5_free_unparsed_name(ctx,pname);
1026 pkrb5_free_principal(ctx,princ);
1028 pkrb5_free_default_realm(ctx, def_realm);
1030 pkrb5_cc_close(ctx,cc);
1032 pkrb5_free_context(ctx);
1034 #endif /* USE_MS2MIT */
1036 // If there are existing MIT credentials, copy them to a new
1037 // ccache named after the principal
1039 // Enumerate all existing MIT ccaches and construct entries
1040 // in the principal_ccache table
1042 // Enumerate all existing AFS Tokens and construct entries
1043 // in the cell_principal table
1045 KFW_import_ccache_data(void)
1047 krb5_context ctx = NULL;
1048 krb5_ccache cc = NULL;
1049 krb5_principal principal = NULL;
1051 krb5_error_code code;
1052 krb5_error_code cc_code;
1054 apiCB * cc_ctx = NULL;
1055 struct _infoNC ** pNCi = NULL;
1058 if ( !pcc_initialize )
1061 if ( IsDebuggerPresent() )
1062 OutputDebugString("KFW_import_ccache_data()\n");
1064 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1065 if (code) goto cleanup;
1067 code = pcc_get_NC_info(cc_ctx, &pNCi);
1068 if (code) goto cleanup;
1070 code = pkrb5_init_context(&ctx);
1071 if (code) goto cleanup;
1073 for ( i=0; pNCi[i]; i++ ) {
1074 if ( pNCi[i]->vers != CC_CRED_V5 )
1076 if ( IsDebuggerPresent() ) {
1077 OutputDebugString("Principal: ");
1078 OutputDebugString(pNCi[i]->principal);
1079 OutputDebugString(" in ccache ");
1080 OutputDebugString(pNCi[i]->name);
1081 OutputDebugString("\n");
1083 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1084 && strcmp(pNCi[i]->name,LSA_CCNAME)
1087 for ( j=0; pNCi[j]; j++ ) {
1088 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1094 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1095 if (code) goto loop_cleanup;
1098 krb5_ccache oldcc = 0;
1100 if ( IsDebuggerPresent() )
1101 OutputDebugString("copying ccache data to new ccache\n");
1103 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1104 if (code) goto loop_cleanup;
1105 code = pkrb5_cc_initialize(ctx, cc, principal);
1106 if (code) goto loop_cleanup;
1108 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1109 if (code) goto loop_cleanup;
1110 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1112 code = pkrb5_cc_close(ctx,cc);
1114 code = pkrb5_cc_close(ctx,oldcc);
1116 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1119 code = pkrb5_cc_close(ctx,oldcc);
1122 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1123 if (code) goto loop_cleanup;
1126 flags = 0; // turn off OPENCLOSE mode
1127 code = pkrb5_cc_set_flags(ctx, cc, flags);
1128 if ( code ) goto cleanup;
1130 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1132 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1134 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1135 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1136 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1137 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1138 if ( sname && cell && !strcmp("afs",sname->data) ) {
1139 struct ktc_principal aserver;
1140 struct ktc_principal aclient;
1141 struct ktc_token atoken;
1144 if ( IsDebuggerPresent() ) {
1145 OutputDebugString("Found AFS ticket: ");
1146 OutputDebugString(sname->data);
1148 OutputDebugString("/");
1149 OutputDebugString(cell->data);
1151 OutputDebugString("@");
1152 OutputDebugString(realm->data);
1153 OutputDebugString("\n");
1156 memset(&aserver, '\0', sizeof(aserver));
1157 strcpy(aserver.name, sname->data);
1158 strcpy(aserver.cell, cell->data);
1160 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1162 // Found a token in AFS Client Server which matches
1163 char pname[128], *p, *q;
1164 for ( p=pname, q=aclient.name; *q; p++, q++)
1166 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1170 if ( IsDebuggerPresent() ) {
1171 OutputDebugString("Found AFS token: ");
1172 OutputDebugString(pname);
1173 OutputDebugString("\n");
1176 if ( strcmp(pname,pNCi[i]->principal) )
1178 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1180 // Attempt to import it
1181 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1183 if ( IsDebuggerPresent() ) {
1184 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1187 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data,
1191 pLeash_get_default_lifetime(),
1192 #endif /* USE_LEASH */
1194 if ( IsDebuggerPresent() ) {
1196 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1197 OutputDebugString(message);
1200 } else if ( IsDebuggerPresent() ) {
1201 OutputDebugString("Found ticket: ");
1202 OutputDebugString(sname->data);
1203 if ( cell && cell->data ) {
1204 OutputDebugString("/");
1205 OutputDebugString(cell->data);
1207 OutputDebugString("@");
1208 OutputDebugString(realm->data);
1209 OutputDebugString("\n");
1211 pkrb5_free_cred_contents(ctx, &creds);
1214 if (cc_code == KRB5_CC_END) {
1215 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1216 if (cc_code) goto loop_cleanup;
1220 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1221 code = pkrb5_cc_set_flags(ctx, cc, flags);
1223 pkrb5_cc_close(ctx,cc);
1227 pkrb5_free_principal(ctx,principal);
1234 pkrb5_free_context(ctx);
1236 pcc_free_NC_info(cc_ctx, &pNCi);
1238 pcc_shutdown(&cc_ctx);
1243 KFW_AFS_get_cred( char * username,
1250 krb5_context ctx = NULL;
1251 krb5_ccache cc = NULL;
1252 char * realm = NULL, * userrealm = NULL;
1253 krb5_principal principal = NULL;
1254 char * pname = NULL;
1255 krb5_error_code code;
1256 char local_cell[MAXCELLCHARS+1];
1257 char **cells = NULL;
1259 struct afsconf_cell cellconfig;
1263 if (!pkrb5_init_context)
1266 if ( IsDebuggerPresent() ) {
1267 OutputDebugString("KFW_AFS_get_cred for token ");
1268 OutputDebugString(username);
1269 OutputDebugString(" in cell ");
1270 OutputDebugString(cell);
1271 OutputDebugString("\n");
1274 code = pkrb5_init_context(&ctx);
1275 if ( code ) goto cleanup;
1277 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1278 if ( code ) goto cleanup;
1280 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1282 userrealm = strchr(username,'@');
1284 pname = strdup(username);
1285 userrealm = strchr(pname, '@');
1288 /* handle kerberos iv notation */
1289 while ( dot = strchr(pname,'.') ) {
1294 pname = malloc(strlen(username) + strlen(realm) + 2);
1296 strcpy(pname, username);
1298 /* handle kerberos iv notation */
1299 while ( dot = strchr(pname,'.') ) {
1304 strcat(pname,realm);
1306 if ( IsDebuggerPresent() ) {
1307 OutputDebugString("Realm: ");
1308 OutputDebugString(realm);
1309 OutputDebugString("\n");
1312 code = pkrb5_parse_name(ctx, pname, &principal);
1313 if ( code ) goto cleanup;
1315 code = KFW_get_ccache(ctx, principal, &cc);
1316 if ( code ) goto cleanup;
1318 if ( lifetime == 0 )
1322 lifetime = pLeash_get_default_lifetime();
1325 if ( password && password[0] ) {
1326 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1331 1, /* forwardable */
1332 0, /* not proxiable */
1334 1, /* noaddresses */
1335 0 /* no public ip */
1337 pLeash_get_default_forwardable(),
1338 pLeash_get_default_proxiable(),
1339 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1340 pLeash_get_default_noaddresses(),
1341 pLeash_get_default_publicip()
1342 #endif /* USE_LEASH */
1345 if ( IsDebuggerPresent() ) {
1347 sprintf(message,"KFW_kinit() returns: %d\n",code);
1348 OutputDebugString(message);
1350 if ( code ) goto cleanup;
1352 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1355 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1356 if ( IsDebuggerPresent() ) {
1358 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1359 OutputDebugString(message);
1361 if ( code ) goto cleanup;
1363 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1365 // Attempt to obtain new tokens for other cells supported by the same
1367 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1368 if ( cell_count > 1 ) {
1369 while ( cell_count-- ) {
1370 if ( strcmp(cells[cell_count],cell) ) {
1371 if ( IsDebuggerPresent() ) {
1373 sprintf(message,"found another cell for the same principal: %s\n",cell);
1374 OutputDebugString(message);
1376 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1377 if ( code ) continue;
1379 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1380 if ( IsDebuggerPresent() ) {
1381 OutputDebugString("Realm: ");
1382 OutputDebugString(realm);
1383 OutputDebugString("\n");
1386 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1387 if ( IsDebuggerPresent() ) {
1389 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1390 OutputDebugString(message);
1393 free(cells[cell_count]);
1396 } else if ( cell_count == 1 ) {
1405 pkrb5_cc_close(ctx, cc);
1407 if ( code && reasonP ) {
1408 *reasonP = (char *)perror_message(code);
1414 KFW_AFS_destroy_tickets_for_cell(char * cell)
1416 krb5_context ctx = NULL;
1417 krb5_error_code code;
1419 char ** principals = NULL;
1421 if (!pkrb5_init_context)
1424 if ( IsDebuggerPresent() ) {
1425 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1426 OutputDebugString(cell);
1427 OutputDebugString("\n");
1430 code = pkrb5_init_context(&ctx);
1433 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1435 krb5_principal princ = 0;
1439 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1440 if ( cell_count > 1 ) {
1441 // TODO - What we really should do here is verify whether or not any of the
1442 // other cells which use this principal to obtain its credentials actually
1443 // have valid tokens or not. If they are currently using these credentials
1444 // we will skip them. For the time being we assume that if there is an active
1445 // map in the table that they are actively being used.
1449 code = pkrb5_parse_name(ctx, principals[count], &princ);
1450 if (code) goto loop_cleanup;
1452 code = KFW_get_ccache(ctx, princ, &cc);
1453 if (code) goto loop_cleanup;
1455 code = pkrb5_cc_destroy(ctx, cc);
1460 pkrb5_cc_close(ctx, cc);
1464 pkrb5_free_principal(ctx, princ);
1468 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1469 free(principals[count]);
1474 pkrb5_free_context(ctx);
1479 KFW_AFS_destroy_tickets_for_principal(char * user)
1481 krb5_context ctx = NULL;
1482 krb5_error_code code;
1484 char ** cells = NULL;
1485 krb5_principal princ = NULL;
1486 krb5_ccache cc = NULL;
1488 if (!pkrb5_init_context)
1491 if ( IsDebuggerPresent() ) {
1492 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1493 OutputDebugString(user);
1494 OutputDebugString("\n");
1497 code = pkrb5_init_context(&ctx);
1500 code = pkrb5_parse_name(ctx, user, &princ);
1501 if (code) goto loop_cleanup;
1503 code = KFW_get_ccache(ctx, princ, &cc);
1504 if (code) goto loop_cleanup;
1506 code = pkrb5_cc_destroy(ctx, cc);
1511 pkrb5_cc_close(ctx, cc);
1515 pkrb5_free_principal(ctx, princ);
1519 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1522 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1529 pkrb5_free_context(ctx);
1534 KFW_AFS_renew_expiring_tokens(void)
1536 krb5_error_code code = 0;
1537 krb5_context ctx = NULL;
1538 krb5_ccache cc = NULL;
1540 struct principal_ccache_data * pcc_next = princ_cc_data;
1543 const char * realm = NULL;
1544 char local_cell[MAXCELLCHARS+1]="";
1545 struct afsconf_cell cellconfig;
1547 if (!pkrb5_init_context)
1550 if ( pcc_next == NULL ) // nothing to do
1553 if ( IsDebuggerPresent() ) {
1554 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1557 code = pkrb5_init_context(&ctx);
1558 if (code) goto cleanup;
1560 code = pkrb5_timeofday(ctx, &now);
1561 if (code) goto cleanup;
1563 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1564 if ( pcc_next->expired )
1567 if ( now >= (pcc_next->expiration_time) ) {
1568 if ( !pcc_next->from_lsa ) {
1569 pcc_next->expired = 1;
1574 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1575 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1578 code = KFW_renew(ctx,cc);
1580 if ( code && pcc_next->from_lsa)
1582 #endif /* USE_MS2MIT */
1585 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1586 if (code) goto loop_cleanup;
1588 // Attempt to obtain new tokens for other cells supported by the same
1590 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1591 if ( cell_count > 0 ) {
1592 while ( cell_count-- ) {
1593 if ( IsDebuggerPresent() ) {
1594 OutputDebugString("Cell: ");
1595 OutputDebugString(cells[cell_count]);
1596 OutputDebugString("\n");
1598 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1599 if ( code ) continue;
1600 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1601 if ( IsDebuggerPresent() ) {
1602 OutputDebugString("Realm: ");
1603 OutputDebugString(realm);
1604 OutputDebugString("\n");
1606 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1607 if ( IsDebuggerPresent() ) {
1609 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1610 OutputDebugString(message);
1612 free(cells[cell_count]);
1620 pkrb5_cc_close(ctx,cc);
1627 pkrb5_cc_close(ctx,cc);
1629 pkrb5_free_context(ctx);
1636 KFW_AFS_renew_token_for_cell(char * cell)
1638 krb5_error_code code = 0;
1639 krb5_context ctx = NULL;
1641 char ** principals = NULL;
1643 if (!pkrb5_init_context)
1646 if ( IsDebuggerPresent() ) {
1647 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1648 OutputDebugString(cell);
1649 OutputDebugString("\n");
1652 code = pkrb5_init_context(&ctx);
1653 if (code) goto cleanup;
1655 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1657 // We know we must have a credential somewhere since we are
1658 // trying to renew a token
1660 KFW_import_ccache_data();
1661 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1664 krb5_principal princ = 0;
1665 krb5_principal service = 0;
1667 krb5_creds mcreds, creds;
1668 #endif /* COMMENT */
1670 const char * realm = NULL;
1671 struct afsconf_cell cellconfig;
1672 char local_cell[MAXCELLCHARS+1];
1675 code = pkrb5_parse_name(ctx, principals[count], &princ);
1676 if (code) goto loop_cleanup;
1678 code = KFW_get_ccache(ctx, princ, &cc);
1679 if (code) goto loop_cleanup;
1681 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1682 if ( code ) goto loop_cleanup;
1684 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1685 if ( IsDebuggerPresent() ) {
1686 OutputDebugString("Realm: ");
1687 OutputDebugString(realm);
1688 OutputDebugString("\n");
1692 /* krb5_cc_remove_cred() is not implemented
1695 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1696 realm, "afs", cell, NULL);
1698 memset(&mcreds, 0, sizeof(krb5_creds));
1699 mcreds.client = princ;
1700 mcreds.server = service;
1702 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1704 if ( IsDebuggerPresent() ) {
1705 char * cname, *sname;
1706 pkrb5_unparse_name(ctx, creds.client, &cname);
1707 pkrb5_unparse_name(ctx, creds.server, &sname);
1708 OutputDebugString("Removing credential for client \"");
1709 OutputDebugString(cname);
1710 OutputDebugString("\" and service \"");
1711 OutputDebugString(sname);
1712 OutputDebugString("\"\n");
1713 pkrb5_free_unparsed_name(ctx,cname);
1714 pkrb5_free_unparsed_name(ctx,sname);
1717 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1718 pkrb5_free_principal(ctx, creds.client);
1719 pkrb5_free_principal(ctx, creds.server);
1722 #endif /* COMMENT */
1724 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1725 if ( IsDebuggerPresent() ) {
1727 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1728 OutputDebugString(message);
1733 pkrb5_cc_close(ctx, cc);
1737 pkrb5_free_principal(ctx, princ);
1741 pkrb5_free_principal(ctx, service);
1745 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1746 free(principals[count]);
1750 code = -1; // we did not renew the tokens
1754 pkrb5_free_context(ctx);
1755 return (code ? FALSE : TRUE);
1760 KFW_AFS_renew_tokens_for_all_cells(void)
1762 struct cell_principal_map * next = cell_princ_map;
1764 if ( IsDebuggerPresent() )
1765 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1770 for ( ; next ; next = next->next ) {
1772 KFW_AFS_renew_token_for_cell(next->cell);
1778 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1780 krb5_error_code code = 0;
1781 krb5_context ctx = NULL;
1782 krb5_ccache cc = NULL;
1783 krb5_principal me = NULL;
1784 krb5_principal server = NULL;
1785 krb5_creds my_creds;
1786 krb5_data *realm = NULL;
1788 if (!pkrb5_init_context)
1791 memset(&my_creds, 0, sizeof(krb5_creds));
1796 code = pkrb5_init_context(&ctx);
1797 if (code) goto cleanup;
1803 code = pkrb5_cc_default(ctx, &cc);
1804 if (code) goto cleanup;
1807 code = pkrb5_cc_get_principal(ctx, cc, &me);
1808 if (code) goto cleanup;
1810 realm = krb5_princ_realm(ctx, me);
1812 code = pkrb5_build_principal_ext(ctx, &server,
1813 realm->length,realm->data,
1814 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1815 realm->length,realm->data,
1820 if ( IsDebuggerPresent() ) {
1821 char * cname, *sname;
1822 pkrb5_unparse_name(ctx, me, &cname);
1823 pkrb5_unparse_name(ctx, server, &sname);
1824 OutputDebugString("Renewing credential for client \"");
1825 OutputDebugString(cname);
1826 OutputDebugString("\" and service \"");
1827 OutputDebugString(sname);
1828 OutputDebugString("\"\n");
1829 pkrb5_free_unparsed_name(ctx,cname);
1830 pkrb5_free_unparsed_name(ctx,sname);
1833 my_creds.client = me;
1834 my_creds.server = server;
1836 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1838 if ( IsDebuggerPresent() ) {
1840 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1841 OutputDebugString(message);
1846 code = pkrb5_cc_initialize(ctx, cc, me);
1848 if ( IsDebuggerPresent() ) {
1850 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1851 OutputDebugString(message);
1856 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1858 if ( IsDebuggerPresent() ) {
1860 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1861 OutputDebugString(message);
1867 if (my_creds.client == me)
1868 my_creds.client = 0;
1869 if (my_creds.server == server)
1870 my_creds.server = 0;
1871 pkrb5_free_cred_contents(ctx, &my_creds);
1873 pkrb5_free_principal(ctx, me);
1875 pkrb5_free_principal(ctx, server);
1876 if (cc && (cc != alt_cc))
1877 pkrb5_cc_close(ctx, cc);
1878 if (ctx && (ctx != alt_ctx))
1879 pkrb5_free_context(ctx);
1884 KFW_kinit( krb5_context alt_ctx,
1887 char *principal_name,
1889 krb5_deltat lifetime,
1892 krb5_deltat renew_life,
1897 krb5_error_code code = 0;
1898 krb5_context ctx = NULL;
1899 krb5_ccache cc = NULL;
1900 krb5_principal me = NULL;
1902 krb5_creds my_creds;
1903 krb5_get_init_creds_opt options;
1904 krb5_address ** addrs = NULL;
1905 int i = 0, addr_count = 0;
1907 if (!pkrb5_init_context)
1910 pkrb5_get_init_creds_opt_init(&options);
1911 memset(&my_creds, 0, sizeof(my_creds));
1919 code = pkrb5_init_context(&ctx);
1920 if (code) goto cleanup;
1926 code = pkrb5_cc_default(ctx, &cc);
1927 if (code) goto cleanup;
1930 code = pkrb5_parse_name(ctx, principal_name, &me);
1934 code = pkrb5_unparse_name(ctx, me, &name);
1942 lifetime = pLeash_get_default_lifetime();
1943 #endif /* USE_LEASH */
1950 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1951 pkrb5_get_init_creds_opt_set_forwardable(&options,
1952 forwardable ? 1 : 0);
1953 pkrb5_get_init_creds_opt_set_proxiable(&options,
1955 pkrb5_get_init_creds_opt_set_renew_life(&options,
1958 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1962 // we are going to add the public IP address specified by the user
1963 // to the list provided by the operating system
1964 krb5_address ** local_addrs=NULL;
1967 pkrb5_os_localaddr(ctx, &local_addrs);
1968 while ( local_addrs[i++] );
1971 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1973 pkrb5_free_addresses(ctx, local_addrs);
1976 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1978 while ( local_addrs[i] ) {
1979 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1980 if (addrs[i] == NULL) {
1981 pkrb5_free_addresses(ctx, local_addrs);
1985 addrs[i]->magic = local_addrs[i]->magic;
1986 addrs[i]->addrtype = local_addrs[i]->addrtype;
1987 addrs[i]->length = local_addrs[i]->length;
1988 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1989 if (!addrs[i]->contents) {
1990 pkrb5_free_addresses(ctx, local_addrs);
1994 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1995 local_addrs[i]->length); /* safe */
1998 pkrb5_free_addresses(ctx, local_addrs);
2000 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2001 if (addrs[i] == NULL)
2004 addrs[i]->magic = KV5M_ADDRESS;
2005 addrs[i]->addrtype = AF_INET;
2006 addrs[i]->length = 4;
2007 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2008 if (!addrs[i]->contents)
2011 netIPAddr = htonl(publicIP);
2012 memcpy(addrs[i]->contents,&netIPAddr,4);
2014 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
2019 code = pkrb5_get_init_creds_password(ctx,
2022 password, // password
2023 KRB5_prompter, // prompter
2024 hParent, // prompter data
2031 code = pkrb5_cc_initialize(ctx, cc, me);
2035 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
2041 for ( i=0;i<addr_count;i++ ) {
2043 if ( addrs[i]->contents )
2044 free(addrs[i]->contents);
2049 if (my_creds.client == me)
2050 my_creds.client = 0;
2051 pkrb5_free_cred_contents(ctx, &my_creds);
2053 pkrb5_free_unparsed_name(ctx, name);
2055 pkrb5_free_principal(ctx, me);
2056 if (cc && (cc != alt_cc))
2057 pkrb5_cc_close(ctx, cc);
2058 if (ctx && (ctx != alt_ctx))
2059 pkrb5_free_context(ctx);
2065 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2067 krb5_context ctx = NULL;
2068 krb5_ccache cc = NULL;
2069 krb5_error_code code;
2071 if (!pkrb5_init_context)
2080 code = pkrb5_init_context(&ctx);
2081 if (code) goto cleanup;
2087 code = pkrb5_cc_default(ctx, &cc);
2088 if (code) goto cleanup;
2091 code = pkrb5_cc_destroy(ctx, cc);
2092 if ( !code ) cc = 0;
2095 if (cc && (cc != alt_cc))
2096 pkrb5_cc_close(ctx, cc);
2097 if (ctx && (ctx != alt_ctx))
2098 pkrb5_free_context(ctx);
2106 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2108 NTSTATUS Status = 0;
2110 TOKEN_STATISTICS Stats;
2116 *ppSessionData = NULL;
2118 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2122 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2123 CloseHandle( TokenHandle );
2127 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2128 if ( FAILED(Status) || !ppSessionData )
2135 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2136 // cache. It validates whether or not it is reasonable to assume that if we
2137 // attempted to retrieve valid tickets we could do so. Microsoft does not
2138 // automatically renew expired tickets. Therefore, the cache could contain
2139 // expired or invalid tickets. Microsoft also caches the user's password
2140 // and will use it to retrieve new TGTs if the cache is empty and tickets
2144 MSLSA_IsKerberosLogon(VOID)
2146 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2147 BOOL Success = FALSE;
2149 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2150 if ( pSessionData->AuthenticationPackage.Buffer ) {
2156 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2157 usLength = (pSessionData->AuthenticationPackage).Length;
2160 lstrcpynW (buffer, usBuffer, usLength);
2161 lstrcatW (buffer,L"");
2162 if ( !lstrcmpW(L"Kerberos",buffer) )
2166 pLsaFreeReturnBuffer(pSessionData);
2170 #endif /* USE_MS2MIT */
2172 static BOOL CALLBACK
2173 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2177 switch ( message ) {
2179 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2181 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2184 for ( i=0; i < mid_cnt ; i++ ) {
2185 if (mid_tb[i].echo == 0)
2186 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2187 else if (mid_tb[i].echo == 2)
2188 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2193 switch ( LOWORD(wParam) ) {
2195 for ( i=0; i < mid_cnt ; i++ ) {
2196 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2197 *mid_tb[i].buf = '\0';
2201 EndDialog(hDialog, LOWORD(wParam));
2209 lpwAlign( LPWORD lpIn )
2213 ul = (ULONG_PTR) lpIn;
2217 return (LPWORD) ul;;
2221 * dialog widths are measured in 1/4 character widths
2222 * dialog height are measured in 1/8 character heights
2226 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2227 char * ptext[], int numlines, int width,
2228 int tb_cnt, struct textField * tb)
2232 LPDLGITEMTEMPLATE lpdit;
2238 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2245 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2247 // Define a dialog box.
2249 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2250 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2251 | DS_SETFOREGROUND | DS_3DLOOK
2252 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2253 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2256 lpdt->cx = 20 + width * 4;
2257 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2259 lpw = (LPWORD) (lpdt + 1);
2260 *lpw++ = 0; // no menu
2261 *lpw++ = 0; // predefined dialog box class (by default)
2263 lpwsz = (LPWSTR) lpw;
2264 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2266 *lpw++ = 8; // font size (points)
2267 lpwsz = (LPWSTR) lpw;
2268 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2272 //-----------------------
2273 // Define an OK button.
2274 //-----------------------
2275 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2276 lpdit = (LPDLGITEMTEMPLATE) lpw;
2277 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2278 lpdit->dwExtendedStyle = 0;
2279 lpdit->x = (lpdt->cx - 14)/4 - 20;
2280 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2283 lpdit->id = IDOK; // OK button identifier
2285 lpw = (LPWORD) (lpdit + 1);
2287 *lpw++ = 0x0080; // button class
2289 lpwsz = (LPWSTR) lpw;
2290 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2292 *lpw++ = 0; // no creation data
2294 //-----------------------
2295 // Define an Cancel button.
2296 //-----------------------
2297 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2298 lpdit = (LPDLGITEMTEMPLATE) lpw;
2299 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2300 lpdit->dwExtendedStyle = 0;
2301 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2302 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2305 lpdit->id = IDCANCEL; // CANCEL button identifier
2307 lpw = (LPWORD) (lpdit + 1);
2309 *lpw++ = 0x0080; // button class
2311 lpwsz = (LPWSTR) lpw;
2312 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2314 *lpw++ = 0; // no creation data
2316 /* Add controls for preface data */
2317 for ( i=0; i<numlines; i++) {
2318 /*-----------------------
2319 * Define a static text control.
2320 *-----------------------*/
2321 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2322 lpdit = (LPDLGITEMTEMPLATE) lpw;
2323 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2324 lpdit->dwExtendedStyle = 0;
2326 lpdit->y = 10 + i * 14;
2327 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2329 lpdit->id = ID_TEXT + i; // text identifier
2331 lpw = (LPWORD) (lpdit + 1);
2333 *lpw++ = 0x0082; // static class
2335 lpwsz = (LPWSTR) lpw;
2336 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2337 -1, lpwsz, 2*width);
2339 *lpw++ = 0; // no creation data
2342 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2343 int len = (int)strlen(tb[i].label);
2348 for ( i=0; i<tb_cnt; i++) {
2350 /*-----------------------
2351 * Define a static text control.
2352 *-----------------------*/
2353 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2354 lpdit = (LPDLGITEMTEMPLATE) lpw;
2355 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2356 lpdit->dwExtendedStyle = 0;
2358 lpdit->y = 10 + (numlines + i + 1) * 14;
2359 lpdit->cx = pwid * 4;
2361 lpdit->id = ID_TEXT + numlines + i; // text identifier
2363 lpw = (LPWORD) (lpdit + 1);
2365 *lpw++ = 0x0082; // static class
2367 lpwsz = (LPWSTR) lpw;
2368 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2371 *lpw++ = 0; // no creation data
2373 /*-----------------------
2374 * Define an edit control.
2375 *-----------------------*/
2376 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2377 lpdit = (LPDLGITEMTEMPLATE) lpw;
2378 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2379 lpdit->dwExtendedStyle = 0;
2380 lpdit->x = 10 + (pwid + 1) * 4;
2381 lpdit->y = 10 + (numlines + i + 1) * 14;
2382 lpdit->cx = (width - (pwid + 1)) * 4;
2384 lpdit->id = ID_MID_TEXT + i; // identifier
2386 lpw = (LPWORD) (lpdit + 1);
2388 *lpw++ = 0x0081; // edit class
2390 lpwsz = (LPWSTR) lpw;
2391 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2394 *lpw++ = 0; // no creation data
2398 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2399 hwndOwner, (DLGPROC) MultiInputDialogProc);
2403 case 0: /* Timeout */
2411 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2412 MessageBox(hwndOwner,
2415 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2422 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2424 HINSTANCE hInst = 0;
2428 char * plines[16], *p = preface ? preface : "";
2431 for ( i=0; i<16; i++ )
2434 while (*p && numlines < 16) {
2435 plines[numlines++] = p;
2436 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2437 if ( *p == '\r' && *(p+1) == '\n' ) {
2440 } else if ( *p == '\n' ) {
2443 if ( strlen(plines[numlines-1]) > maxwidth )
2444 maxwidth = (int)strlen(plines[numlines-1]);
2447 for ( i=0;i<n;i++ ) {
2448 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2449 if ( maxwidth < len )
2453 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2456 static krb5_error_code KRB5_CALLCONV
2457 KRB5_prompter( krb5_context context,
2462 krb5_prompt prompts[])
2464 krb5_error_code errcode = 0;
2466 struct textField * tb = NULL;
2467 int len = 0, blen=0, nlen=0;
2468 HWND hParent = (HWND)data;
2471 nlen = (int)strlen(name)+2;
2474 blen = (int)strlen(banner)+2;
2476 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2479 memset(tb,0,sizeof(struct textField) * num_prompts);
2480 for ( i=0; i < num_prompts; i++ ) {
2481 tb[i].buf = prompts[i].reply->data;
2482 tb[i].len = prompts[i].reply->length;
2483 tb[i].label = prompts[i].prompt;
2485 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2488 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2490 for ( i=0; i < num_prompts; i++ )
2491 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2499 for (i = 0; i < num_prompts; i++) {
2500 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2507 KFW_AFS_wait_for_service_start(void)
2512 CurrentState = SERVICE_START_PENDING;
2513 memset(HostName, '\0', sizeof(HostName));
2514 gethostname(HostName, sizeof(HostName));
2516 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2518 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2520 if ( IsDebuggerPresent() ) {
2521 switch ( CurrentState ) {
2522 case SERVICE_STOPPED:
2523 OutputDebugString("SERVICE_STOPPED\n");
2525 case SERVICE_START_PENDING:
2526 OutputDebugString("SERVICE_START_PENDING\n");
2528 case SERVICE_STOP_PENDING:
2529 OutputDebugString("SERVICE_STOP_PENDING\n");
2531 case SERVICE_RUNNING:
2532 OutputDebugString("SERVICE_RUNNING\n");
2534 case SERVICE_CONTINUE_PENDING:
2535 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2537 case SERVICE_PAUSE_PENDING:
2538 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2540 case SERVICE_PAUSED:
2541 OutputDebugString("SERVICE_PAUSED\n");
2544 OutputDebugString("UNKNOWN Service State\n");
2547 if (CurrentState == SERVICE_STOPPED)
2549 if (CurrentState == SERVICE_RUNNING)
2565 memset(HostName, '\0', sizeof(HostName));
2566 gethostname(HostName, sizeof(HostName));
2567 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2569 if (CurrentState != SERVICE_RUNNING)
2572 rc = ktc_ForgetAllTokens();
2578 #define ALLOW_REGISTER 1
2580 ViceIDToUsername(char *username,
2581 char *realm_of_user,
2582 char *realm_of_cell,
2584 struct ktc_principal *aclient,
2585 struct ktc_principal *aserver,
2586 struct ktc_token *atoken)
2588 static char lastcell[MAXCELLCHARS+1] = { 0 };
2589 static char confname[512] = { 0 };
2590 #ifdef AFS_ID_TO_NAME
2591 char username_copy[BUFSIZ];
2592 #endif /* AFS_ID_TO_NAME */
2593 long viceId = ANONYMOUSID; /* AFS uid of user */
2595 #ifdef ALLOW_REGISTER
2597 #endif /* ALLOW_REGISTER */
2599 if (confname[0] == '\0') {
2600 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2601 confname[sizeof(confname) - 2] = '\0';
2604 strcpy(lastcell, aserver->cell);
2606 if (!pr_Initialize (0, confname, aserver->cell)) {
2607 char sname[PR_MAXNAMELEN];
2608 strncpy(sname, username, PR_MAXNAMELEN);
2609 sname[PR_MAXNAMELEN-1] = '\0';
2610 status = pr_SNameToId (sname, &viceId);
2615 * This is a crock, but it is Transarc's crock, so
2616 * we have to play along in order to get the
2617 * functionality. The way the afs id is stored is
2618 * as a string in the username field of the token.
2619 * Contrary to what you may think by looking at
2620 * the code for tokens, this hack (AFS ID %d) will
2621 * not work if you change %d to something else.
2625 * This code is taken from cklog -- it lets people
2626 * automatically register with the ptserver in foreign cells
2629 #ifdef ALLOW_REGISTER
2631 if (viceId != ANONYMOUSID) {
2632 #else /* ALLOW_REGISTER */
2633 if ((status == 0) && (viceId != ANONYMOUSID))
2634 #endif /* ALLOW_REGISTER */
2636 #ifdef AFS_ID_TO_NAME
2637 strncpy(username_copy, username, BUFSIZ);
2638 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2639 #endif /* AFS_ID_TO_NAME */
2641 #ifdef ALLOW_REGISTER
2642 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2644 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2645 strcpy(aclient->instance, "");
2646 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2647 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2649 if (status = pr_Initialize(1L, confname, aserver->cell))
2651 status = pr_CreateUser(username, &id);
2655 #ifdef AFS_ID_TO_NAME
2656 strncpy(username_copy, username, BUFSIZ);
2657 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2658 #endif /* AFS_ID_TO_NAME */
2661 #endif /* ALLOW_REGISTER */
2668 krb5_context alt_ctx,
2673 int lifetime, /* unused parameter */
2681 #endif /* USE_KRB4 */
2682 struct ktc_principal aserver;
2683 struct ktc_principal aclient;
2684 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2685 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2686 char local_cell[MAXCELLCHARS+1];
2687 char Dmycell[MAXCELLCHARS+1];
2688 struct ktc_token atoken;
2689 struct ktc_token btoken;
2690 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2691 char RealmName[128];
2693 char ServiceName[128];
2697 krb5_context ctx = NULL;
2698 krb5_ccache cc = NULL;
2700 krb5_creds * k5creds = NULL;
2701 krb5_error_code code;
2702 krb5_principal client_principal = NULL;
2703 krb5_data * k5data = NULL;
2707 memset(HostName, '\0', sizeof(HostName));
2708 gethostname(HostName, sizeof(HostName));
2709 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2710 if ( IsDebuggerPresent() )
2711 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2714 if (CurrentState != SERVICE_RUNNING) {
2715 if ( IsDebuggerPresent() )
2716 OutputDebugString("AFSD Service NOT RUNNING\n");
2720 if (!pkrb5_init_context)
2723 memset(RealmName, '\0', sizeof(RealmName));
2724 memset(CellName, '\0', sizeof(CellName));
2725 memset(ServiceName, '\0', sizeof(ServiceName));
2726 memset(realm_of_user, '\0', sizeof(realm_of_user));
2727 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2728 if (cell && cell[0])
2729 strcpy(Dmycell, cell);
2731 memset(Dmycell, '\0', sizeof(Dmycell));
2733 // NULL or empty cell returns information on local cell
2734 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2736 // KFW_AFS_error(rc, "get_cellconfig()");
2743 code = pkrb5_init_context(&ctx);
2744 if (code) goto cleanup;
2750 code = pkrb5_cc_default(ctx, &cc);
2751 if (code) goto skip_krb5_init;
2754 memset((char *)&increds, 0, sizeof(increds));
2756 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2758 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2760 OutputDebugString("Principal Not Found for ccache\n");
2762 goto skip_krb5_init;
2765 /* look for client principals which cannot be distinguished
2766 * from Kerberos 4 multi-component principal names
2768 k5data = krb5_princ_component(ctx,client_principal,0);
2769 for ( i=0; i<k5data->length; i++ ) {
2770 if ( k5data->data[i] == '.' )
2773 if (i != k5data->length)
2775 OutputDebugString("Illegal Principal name contains dot in first component\n");
2776 rc = KRB5KRB_ERR_GENERIC;
2780 i = krb5_princ_realm(ctx, client_principal)->length;
2783 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2784 realm_of_user[i] = 0;
2789 if ( !try_krb5 || !realm_of_user[0] ) {
2790 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2799 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2801 if (strlen(service) == 0)
2802 strcpy(ServiceName, "afs");
2804 strcpy(ServiceName, service);
2806 if (strlen(cell) == 0)
2807 strcpy(CellName, local_cell);
2809 strcpy(CellName, cell);
2811 if (strlen(realm) == 0)
2812 strcpy(RealmName, realm_of_cell);
2814 strcpy(RealmName, realm);
2816 memset(&creds, '\0', sizeof(creds));
2821 /* First try service/cell@REALM */
2822 if (code = pkrb5_build_principal(ctx, &increds.server,
2823 (int)strlen(RealmName),
2832 increds.client = client_principal;
2833 increds.times.endtime = 0;
2834 /* Ask for DES since that is what V4 understands */
2835 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2838 if ( IsDebuggerPresent() ) {
2839 char * cname, *sname;
2840 pkrb5_unparse_name(ctx, increds.client, &cname);
2841 pkrb5_unparse_name(ctx, increds.server, &sname);
2842 OutputDebugString("Getting tickets for \"");
2843 OutputDebugString(cname);
2844 OutputDebugString("\" and service \"");
2845 OutputDebugString(sname);
2846 OutputDebugString("\"\n");
2847 pkrb5_free_unparsed_name(ctx,cname);
2848 pkrb5_free_unparsed_name(ctx,sname);
2851 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2852 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2853 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2854 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2855 /* Or service@REALM */
2856 pkrb5_free_principal(ctx,increds.server);
2858 code = pkrb5_build_principal(ctx, &increds.server,
2859 (int)strlen(RealmName),
2864 if ( IsDebuggerPresent() ) {
2865 char * cname, *sname;
2866 pkrb5_unparse_name(ctx, increds.client, &cname);
2867 pkrb5_unparse_name(ctx, increds.server, &sname);
2868 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2869 OutputDebugString("Trying again: getting tickets for \"");
2870 OutputDebugString(cname);
2871 OutputDebugString("\" and service \"");
2872 OutputDebugString(sname);
2873 OutputDebugString("\"\n");
2874 pkrb5_free_unparsed_name(ctx,cname);
2875 pkrb5_free_unparsed_name(ctx,sname);
2879 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2882 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2883 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2884 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2885 strcmp(RealmName, realm_of_cell)) {
2886 /* Or service/cell@REALM_OF_CELL */
2887 strcpy(RealmName, realm_of_cell);
2888 pkrb5_free_principal(ctx,increds.server);
2890 code = pkrb5_build_principal(ctx, &increds.server,
2891 (int)strlen(RealmName),
2897 if ( IsDebuggerPresent() ) {
2898 char * cname, *sname;
2899 pkrb5_unparse_name(ctx, increds.client, &cname);
2900 pkrb5_unparse_name(ctx, increds.server, &sname);
2901 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2902 OutputDebugString("Trying again: getting tickets for \"");
2903 OutputDebugString(cname);
2904 OutputDebugString("\" and service \"");
2905 OutputDebugString(sname);
2906 OutputDebugString("\"\n");
2907 pkrb5_free_unparsed_name(ctx,cname);
2908 pkrb5_free_unparsed_name(ctx,sname);
2912 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2915 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2916 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2917 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2918 /* Or service@REALM_OF_CELL */
2919 pkrb5_free_principal(ctx,increds.server);
2921 code = pkrb5_build_principal(ctx, &increds.server,
2922 (int)strlen(RealmName),
2927 if ( IsDebuggerPresent() ) {
2928 char * cname, *sname;
2929 pkrb5_unparse_name(ctx, increds.client, &cname);
2930 pkrb5_unparse_name(ctx, increds.server, &sname);
2931 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2932 OutputDebugString("Trying again: getting tickets for \"");
2933 OutputDebugString(cname);
2934 OutputDebugString("\" and service \"");
2935 OutputDebugString(sname);
2936 OutputDebugString("\"\n");
2937 pkrb5_free_unparsed_name(ctx,cname);
2938 pkrb5_free_unparsed_name(ctx,sname);
2942 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2947 if ( IsDebuggerPresent() ) {
2949 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2950 OutputDebugString(message);
2956 /* This code inserts the entire K5 ticket into the token
2957 * No need to perform a krb524 translation which is
2958 * commented out in the code below
2960 if (KFW_use_krb524() ||
2961 k5creds->ticket.length > MAXKTCTICKETLEN)
2964 memset(&aserver, '\0', sizeof(aserver));
2965 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2966 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2968 memset(&atoken, '\0', sizeof(atoken));
2969 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2970 atoken.startTime = k5creds->times.starttime;
2971 atoken.endTime = k5creds->times.endtime;
2972 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2973 atoken.ticketLen = k5creds->ticket.length;
2974 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2977 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2978 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2979 if ( rc == KTC_NOCM && retry < 20 ) {
2982 goto retry_gettoken5;
2987 if (atoken.kvno == btoken.kvno &&
2988 atoken.ticketLen == btoken.ticketLen &&
2989 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2990 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2992 /* Success - Nothing to do */
2996 // * Reset the "aclient" structure before we call ktc_SetToken.
2997 // * This structure was first set by the ktc_GetToken call when
2998 // * we were comparing whether identical tokens already existed.
3000 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
3001 strncpy(aclient.name, k5creds->client->data[0].data, len);
3002 aclient.name[len] = '\0';
3004 if ( k5creds->client->length > 1 ) {
3006 strcat(aclient.name, ".");
3007 p = aclient.name + strlen(aclient.name);
3008 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3009 strncpy(p, k5creds->client->data[1].data, len);
3012 aclient.instance[0] = '\0';
3014 strcpy(aclient.cell, realm_of_cell);
3016 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3017 /* For Khimaira, always append the realm name */
3018 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3020 strcat(aclient.name, "@");
3021 p = aclient.name + strlen(aclient.name);
3022 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3023 strncpy(p, k5creds->client->realm.data, len);
3027 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3028 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3029 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3030 &aclient, &aserver, &atoken);
3033 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3034 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3036 aclient.smbname[0] = '\0';
3039 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3041 goto cleanup; /* We have successfully inserted the token */
3047 /* Otherwise, the ticket could have been too large so try to
3048 * convert using the krb524d running with the KDC
3050 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3051 pkrb5_free_creds(ctx, k5creds);
3053 if ( IsDebuggerPresent() ) {
3055 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3056 OutputDebugString(message);
3061 #endif /* USE_KRB524 */
3065 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3066 if (code == NO_TKT_FIL) {
3067 // if the problem is that we have no krb4 tickets
3068 // do not attempt to continue
3071 if (code != KSUCCESS)
3072 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3074 if (code != KSUCCESS)
3076 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3078 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3083 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3085 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3100 memset(&aserver, '\0', sizeof(aserver));
3101 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3102 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3104 memset(&atoken, '\0', sizeof(atoken));
3105 atoken.kvno = creds.kvno;
3106 atoken.startTime = creds.issue_date;
3107 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3108 memcpy(&atoken.sessionKey, creds.session, 8);
3109 atoken.ticketLen = creds.ticket_st.length;
3110 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3113 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3114 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3115 if ( rc == KTC_NOCM && retry < 20 ) {
3118 goto retry_gettoken;
3120 KFW_AFS_error(rc, "ktc_GetToken()");
3125 if (atoken.kvno == btoken.kvno &&
3126 atoken.ticketLen == btoken.ticketLen &&
3127 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3128 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3133 // * Reset the "aclient" structure before we call ktc_SetToken.
3134 // * This structure was first set by the ktc_GetToken call when
3135 // * we were comparing whether identical tokens already existed.
3137 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3140 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3141 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3143 strcpy(aclient.instance, "");
3145 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3146 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3147 aclient.name[MAXKTCREALMLEN-1] = '\0';
3149 strcpy(aclient.cell, CellName);
3151 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3152 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3153 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3154 &aclient, &aserver, &atoken);
3157 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3158 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3160 aclient.smbname[0] = '\0';
3163 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3165 KFW_AFS_error(rc, "ktc_SetToken()");
3171 if (client_principal)
3172 pkrb5_free_principal(ctx,client_principal);
3173 /* increds.client == client_principal */
3175 pkrb5_free_principal(ctx,increds.server);
3176 if (cc && (cc != alt_cc))
3177 pkrb5_cc_close(ctx, cc);
3178 if (ctx && (ctx != alt_ctx))
3179 pkrb5_free_context(ctx);
3181 return(rc? rc : code);
3184 /**************************************/
3185 /* afs_realm_of_cell(): */
3186 /**************************************/
3188 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3190 static char krbrlm[REALM_SZ+1]="";
3191 char ** realmlist=NULL;
3197 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3198 if ( !r && realmlist && realmlist[0] ) {
3199 strcpy(krbrlm, realmlist[0]);
3200 pkrb5_free_host_realm(ctx, realmlist);
3206 char *t = cellconfig->name;
3211 if (islower(c)) c=toupper(c);
3219 /**************************************/
3220 /* KFW_AFS_get_cellconfig(): */
3221 /**************************************/
3223 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3226 char newcell[MAXCELLCHARS+1];
3228 local_cell[0] = (char)0;
3229 memset(cellconfig, 0, sizeof(*cellconfig));
3231 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3232 if (rc = cm_GetRootCellName(local_cell))
3237 if (strlen(cell) == 0)
3238 strcpy(cell, local_cell);
3240 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3241 strcpy(cellconfig->name, cell);
3243 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3244 #ifdef AFS_AFSDB_ENV
3247 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3253 /**************************************/
3254 /* get_cellconfig_callback(): */
3255 /**************************************/
3257 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3259 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3261 cc->hostAddr[cc->numServers] = *addrp;
3262 strcpy(cc->hostName[cc->numServers], namep);
3268 /**************************************/
3269 /* KFW_AFS_error(): */
3270 /**************************************/
3272 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3275 const char *errText;
3277 // Using AFS defines as error messages for now, until Transarc
3278 // gets back to me with "string" translations of each of these
3280 if (rc == KTC_ERROR)
3281 errText = "KTC_ERROR";
3282 else if (rc == KTC_TOOBIG)
3283 errText = "KTC_TOOBIG";
3284 else if (rc == KTC_INVAL)
3285 errText = "KTC_INVAL";
3286 else if (rc == KTC_NOENT)
3287 errText = "KTC_NOENT";
3288 else if (rc == KTC_PIOCTLFAIL)
3289 errText = "KTC_PIOCTLFAIL";
3290 else if (rc == KTC_NOPIOCTL)
3291 errText = "KTC_NOPIOCTL";
3292 else if (rc == KTC_NOCELL)
3293 errText = "KTC_NOCELL";
3294 else if (rc == KTC_NOCM)
3295 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3297 errText = "Unknown error!";
3299 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3301 if ( IsDebuggerPresent() ) {
3302 OutputDebugString(message);
3303 OutputDebugString("\n");
3305 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3311 LPSTR lpszMachineName,
3312 LPSTR lpszServiceName,
3313 DWORD *lpdwCurrentState)
3316 SC_HANDLE schSCManager = NULL;
3317 SC_HANDLE schService = NULL;
3318 DWORD fdwDesiredAccess = 0;
3319 SERVICE_STATUS ssServiceStatus = {0};
3322 *lpdwCurrentState = 0;
3324 fdwDesiredAccess = GENERIC_READ;
3326 schSCManager = OpenSCManager(lpszMachineName,
3330 if(schSCManager == NULL)
3332 hr = GetLastError();
3336 schService = OpenService(schSCManager,
3340 if(schService == NULL)
3342 hr = GetLastError();
3346 fRet = QueryServiceStatus(schService,
3351 hr = GetLastError();
3355 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3359 CloseServiceHandle(schService);
3360 CloseServiceHandle(schSCManager);
3373 for (n = 0; fi[n].func_ptr_var; n++)
3374 *(fi[n].func_ptr_var) = 0;
3375 if (h) FreeLibrary(h);
3380 const char* dll_name,
3382 HINSTANCE* ph, // [out, optional] - DLL handle
3383 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3384 int cleanup, // cleanup function pointers and unload on error
3385 int go_on, // continue loading even if some functions cannot be loaded
3386 int silent // do not pop-up a system dialog if DLL cannot be loaded
3395 if (pindex) *pindex = -1;
3397 for (n = 0; fi[n].func_ptr_var; n++)
3398 *(fi[n].func_ptr_var) = 0;
3401 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3402 h = LoadLibrary(dll_name);
3410 for (i = 0; (go_on || !error) && (i < n); i++)
3412 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3418 *(fi[i].func_ptr_var) = p;
3421 if (pindex) *pindex = last_i;
3422 if (error && cleanup && !go_on) {
3423 for (i = 0; i < n; i++) {
3424 *(fi[i].func_ptr_var) = 0;
3430 if (error) return 0;
3434 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3436 krb5_context ctx = NULL;
3437 krb5_ccache cc = NULL;
3438 krb5_error_code code;
3440 const char * realm = NULL;
3441 krb5_principal principal = NULL;
3442 char * pname = NULL;
3443 char password[PROBE_PASSWORD_LEN+1];
3444 BOOL serverReachable = 0;
3446 if (!pkrb5_init_context)
3449 code = pkrb5_init_context(&ctx);
3450 if (code) goto cleanup;
3453 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3455 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3456 realm, PROBE_USERNAME, NULL, NULL);
3457 if ( code ) goto cleanup;
3459 code = KFW_get_ccache(ctx, principal, &cc);
3460 if ( code ) goto cleanup;
3462 code = pkrb5_unparse_name(ctx, principal, &pname);
3463 if ( code ) goto cleanup;
3465 pwdata.data = password;
3466 pwdata.length = PROBE_PASSWORD_LEN;
3467 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3470 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3473 password[PROBE_PASSWORD_LEN] = '\0';
3475 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3485 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3486 case KRB5KDC_ERR_CLIENT_REVOKED:
3487 case KRB5KDC_ERR_CLIENT_NOTYET:
3488 case KRB5KDC_ERR_PREAUTH_FAILED:
3489 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3490 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3491 serverReachable = TRUE;
3494 serverReachable = FALSE;
3499 pkrb5_free_unparsed_name(ctx,pname);
3501 pkrb5_free_principal(ctx,principal);
3503 pkrb5_cc_close(ctx,cc);
3505 pkrb5_free_context(ctx);
3507 return serverReachable;
3511 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3513 krb5_context ctx = NULL;
3514 krb5_error_code code;
3515 krb5_ccache mslsa_ccache=NULL;
3516 krb5_principal princ = NULL;
3517 char * pname = NULL;
3520 if (!KFW_is_available())
3523 if (code = pkrb5_init_context(&ctx))
3526 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3529 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3532 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3535 if ( strlen(pname) < *dwSize ) {
3536 strncpy(szUser, pname, *dwSize);
3537 szUser[*dwSize-1] = '\0';
3540 *dwSize = (DWORD)strlen(pname);
3544 pkrb5_free_unparsed_name(ctx, pname);
3547 pkrb5_free_principal(ctx, princ);
3550 pkrb5_cc_close(ctx, mslsa_ccache);
3553 pkrb5_free_context(ctx);
3558 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3560 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3561 PSID pSystemSID = NULL;
3562 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3563 PACL ccacheACL = NULL;
3564 DWORD ccacheACLlength = 0;
3565 PTOKEN_USER pTokenUser = NULL;
3574 /* Get System SID */
3575 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3581 SystemSIDlength = GetLengthSid(pSystemSID);
3582 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3583 + SystemSIDlength - sizeof(DWORD);
3586 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3588 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3589 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3591 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3596 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3598 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3603 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3608 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3609 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3610 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3613 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3614 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3615 pTokenUser->User.Sid);
3616 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3617 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3622 gle = GetLastError();
3623 if (gle != ERROR_NO_TOKEN)
3626 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3627 OWNER_SECURITY_INFORMATION,
3628 pTokenUser->User.Sid,
3632 gle = GetLastError();
3633 if (gle != ERROR_NO_TOKEN)
3637 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3638 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3643 gle = GetLastError();
3644 if (gle != ERROR_NO_TOKEN)
3651 LocalFree(pSystemSID);
3653 LocalFree(pTokenUser);
3655 LocalFree(ccacheACL);
3660 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3663 DWORD dwSize = size-1; /* leave room for nul */
3666 if (!hUserToken || !newfilename || size <= 0)
3669 *newfilename = '\0';
3671 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3672 if ( !dwLen || dwLen > dwSize )
3673 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3674 if ( !dwLen || dwLen > dwSize )
3677 newfilename[dwSize] = '\0';
3682 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3684 char filename[MAX_PATH] = "";
3686 char cachename[MAX_PATH + 8] = "FILE:";
3687 krb5_context ctx = NULL;
3688 krb5_error_code code;
3689 krb5_principal princ = NULL;
3690 krb5_ccache cc = NULL;
3691 krb5_ccache ncc = NULL;
3693 if (!pkrb5_init_context || !user || !szLogonId)
3696 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3697 if ( count > sizeof(filename) || count == 0 ) {
3698 GetWindowsDirectory(filename, sizeof(filename));
3701 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3704 strcat(filename, "\\");
3705 strcat(filename, szLogonId);
3707 strcat(cachename, filename);
3709 DeleteFile(filename);
3711 code = pkrb5_init_context(&ctx);
3712 if (code) goto cleanup;
3714 code = pkrb5_parse_name(ctx, user, &princ);
3715 if (code) goto cleanup;
3717 code = KFW_get_ccache(ctx, princ, &cc);
3718 if (code) goto cleanup;
3720 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3721 if (code) goto cleanup;
3723 code = pkrb5_cc_initialize(ctx, ncc, princ);
3724 if (code) goto cleanup;
3726 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3727 if (code) goto cleanup;
3729 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3733 pkrb5_cc_close(ctx, cc);
3737 pkrb5_cc_close(ctx, ncc);
3741 pkrb5_free_principal(ctx, princ);
3746 pkrb5_free_context(ctx);
3750 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3752 char cachename[MAX_PATH + 8] = "FILE:";
3753 krb5_context ctx = NULL;
3754 krb5_error_code code;
3755 krb5_principal princ = NULL;
3756 krb5_ccache cc = NULL;
3757 krb5_ccache ncc = NULL;
3760 if (!pkrb5_init_context || !filename)
3763 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3766 code = pkrb5_init_context(&ctx);
3769 strcat(cachename, filename);
3771 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3772 if (code) goto cleanup;
3774 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3776 code = pkrb5_cc_default(ctx, &ncc);
3778 code = pkrb5_cc_initialize(ctx, ncc, princ);
3781 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3784 pkrb5_cc_close(ctx, ncc);
3788 retval=0; /* success */
3792 pkrb5_cc_close(ctx, cc);
3796 DeleteFile(filename);
3799 pkrb5_free_principal(ctx, princ);
3804 pkrb5_free_context(ctx);
3809 /* We are including this
3811 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3812 fixed part of rande of the one byte lifetime field. Values less than 0x80
3813 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3814 0xBF should be looked up in this table. The value of 0x80 is the same using
3815 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3816 The intervening values of have a fixed ratio of roughly 1.06914. The value
3817 oxFF is defined to mean a ticket has no expiration time. This should be
3818 used advisedly since individual servers may impose defacto upperbounds on
3819 ticket lifetimes. */
3821 #define TKTLIFENUMFIXED 64
3822 #define TKTLIFEMINFIXED 0x80
3823 #define TKTLIFEMAXFIXED 0xBF
3824 #define TKTLIFENOEXPIRE 0xFF
3825 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3827 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3828 38400, /* 10.67 hours, 0.44 days */
3829 41055, /* 11.40 hours, 0.48 days */
3830 43894, /* 12.19 hours, 0.51 days */
3831 46929, /* 13.04 hours, 0.54 days */
3832 50174, /* 13.94 hours, 0.58 days */
3833 53643, /* 14.90 hours, 0.62 days */
3834 57352, /* 15.93 hours, 0.66 days */
3835 61318, /* 17.03 hours, 0.71 days */
3836 65558, /* 18.21 hours, 0.76 days */
3837 70091, /* 19.47 hours, 0.81 days */
3838 74937, /* 20.82 hours, 0.87 days */
3839 80119, /* 22.26 hours, 0.93 days */
3840 85658, /* 23.79 hours, 0.99 days */
3841 91581, /* 25.44 hours, 1.06 days */
3842 97914, /* 27.20 hours, 1.13 days */
3843 104684, /* 29.08 hours, 1.21 days */
3844 111922, /* 31.09 hours, 1.30 days */
3845 119661, /* 33.24 hours, 1.38 days */
3846 127935, /* 35.54 hours, 1.48 days */
3847 136781, /* 37.99 hours, 1.58 days */
3848 146239, /* 40.62 hours, 1.69 days */
3849 156350, /* 43.43 hours, 1.81 days */
3850 167161, /* 46.43 hours, 1.93 days */
3851 178720, /* 49.64 hours, 2.07 days */
3852 191077, /* 53.08 hours, 2.21 days */
3853 204289, /* 56.75 hours, 2.36 days */
3854 218415, /* 60.67 hours, 2.53 days */
3855 233517, /* 64.87 hours, 2.70 days */
3856 249664, /* 69.35 hours, 2.89 days */
3857 266926, /* 74.15 hours, 3.09 days */
3858 285383, /* 79.27 hours, 3.30 days */
3859 305116, /* 84.75 hours, 3.53 days */
3860 326213, /* 90.61 hours, 3.78 days */
3861 348769, /* 96.88 hours, 4.04 days */
3862 372885, /* 103.58 hours, 4.32 days */
3863 398668, /* 110.74 hours, 4.61 days */
3864 426234, /* 118.40 hours, 4.93 days */
3865 455705, /* 126.58 hours, 5.27 days */
3866 487215, /* 135.34 hours, 5.64 days */
3867 520904, /* 144.70 hours, 6.03 days */
3868 556921, /* 154.70 hours, 6.45 days */
3869 595430, /* 165.40 hours, 6.89 days */
3870 636601, /* 176.83 hours, 7.37 days */
3871 680618, /* 189.06 hours, 7.88 days */
3872 727680, /* 202.13 hours, 8.42 days */
3873 777995, /* 216.11 hours, 9.00 days */
3874 831789, /* 231.05 hours, 9.63 days */
3875 889303, /* 247.03 hours, 10.29 days */
3876 950794, /* 264.11 hours, 11.00 days */
3877 1016537, /* 282.37 hours, 11.77 days */
3878 1086825, /* 301.90 hours, 12.58 days */
3879 1161973, /* 322.77 hours, 13.45 days */
3880 1242318, /* 345.09 hours, 14.38 days */
3881 1328218, /* 368.95 hours, 15.37 days */
3882 1420057, /* 394.46 hours, 16.44 days */
3883 1518247, /* 421.74 hours, 17.57 days */
3884 1623226, /* 450.90 hours, 18.79 days */
3885 1735464, /* 482.07 hours, 20.09 days */
3886 1855462, /* 515.41 hours, 21.48 days */
3887 1983758, /* 551.04 hours, 22.96 days */
3888 2120925, /* 589.15 hours, 24.55 days */
3889 2267576, /* 629.88 hours, 26.25 days */
3890 2424367, /* 673.44 hours, 28.06 days */
3892 }; /* 720.00 hours, 30.00 days */
3894 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3895 * returns the corresponding end time. There are four simple cases to be
3896 * handled. The first is a life of 0xff, meaning no expiration, and results in
3897 * an end time of 0xffffffff. The second is when life is less than the values
3898 * covered by the table. In this case, the end time is the start time plus the
3899 * number of 5 minute intervals specified by life. The third case returns
3900 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3901 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3902 * table to extract the lifetime in seconds, which is added to start to produce
3906 life_to_time(afs_uint32 start, unsigned char life)
3910 if (life == TKTLIFENOEXPIRE)
3912 if (life < TKTLIFEMINFIXED)
3913 return start + life * 5 * 60;
3914 if (life > TKTLIFEMAXFIXED)
3915 return start + MAXTKTLIFETIME;
3916 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3917 return start + realLife;
3920 /* time_to_life - takes start and end times for the ticket and returns a
3921 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3922 * lifetimes above 127*5minutes. First, the special case of (end ==
3923 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3924 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3925 * less than the first table entry are handled by rounding the requested
3926 * lifetime *up* to the next 5 minute interval. The final step is to search
3927 * the table for the smallest entry *greater than or equal* to the requested
3928 * entry. The actual code is prepared to handle the case where the table is
3929 * unordered but that it an unnecessary frill. */
3931 static unsigned char
3932 time_to_life(afs_uint32 start, afs_uint32 end)
3934 int lifetime = end - start;
3938 if (end == NEVERDATE)
3939 return TKTLIFENOEXPIRE;
3940 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3942 if (lifetime < tkt_lifetimes[0])
3943 return (lifetime + 5 * 60 - 1) / (5 * 60);
3945 best = MAXKTCTICKETLIFETIME;
3946 for (i = 0; i < TKTLIFENUMFIXED; i++)
3947 if (tkt_lifetimes[i] >= lifetime) {
3948 int diff = tkt_lifetimes[i] - lifetime;
3956 return best_i + TKTLIFEMINFIXED;