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 */
502 KFW_accept_dotted_usernames(void)
508 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
509 0, KEY_QUERY_VALUE, &parmKey);
510 if (code == ERROR_SUCCESS) {
512 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
513 (BYTE *) &value, &len);
514 RegCloseKey(parmKey);
516 if (code != ERROR_SUCCESS) {
517 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
518 0, KEY_QUERY_VALUE, &parmKey);
519 if (code == ERROR_SUCCESS) {
521 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
522 (BYTE *) &value, &len);
523 RegCloseKey (parmKey);
537 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
538 0, KEY_QUERY_VALUE, &parmKey);
539 if (code == ERROR_SUCCESS) {
540 len = sizeof(use524);
541 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
542 (BYTE *) &use524, &len);
543 RegCloseKey(parmKey);
545 if (code != ERROR_SUCCESS) {
546 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
547 0, KEY_QUERY_VALUE, &parmKey);
548 if (code == ERROR_SUCCESS) {
549 len = sizeof(use524);
550 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
551 (BYTE *) &use524, &len);
552 RegCloseKey (parmKey);
559 KFW_is_available(void)
565 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
566 0, KEY_QUERY_VALUE, &parmKey);
567 if (code == ERROR_SUCCESS) {
568 len = sizeof(enableKFW);
569 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
570 (BYTE *) &enableKFW, &len);
571 RegCloseKey (parmKey);
574 if (code != ERROR_SUCCESS) {
575 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
576 0, KEY_QUERY_VALUE, &parmKey);
577 if (code == ERROR_SUCCESS) {
578 len = sizeof(enableKFW);
579 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
580 (BYTE *) &enableKFW, &len);
581 RegCloseKey (parmKey);
589 if ( hKrb5 && hComErr && hService &&
592 #endif /* USE_MS2MIT */
605 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
606 int FreeContextFlag, krb5_context * ctx,
611 int krb5Error = ((int)(rc & 255));
623 errText = perror_message(rc);
624 _snprintf(message, sizeof(message),
625 "%s\n(Kerberos error %ld)\n\n%s failed",
630 if ( IsDebuggerPresent() )
631 OutputDebugString(message);
633 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
636 if (FreeContextFlag == 1)
638 if (ctx && *ctx != NULL)
640 if (cache && *cache != NULL) {
641 pkrb5_cc_close(*ctx, *cache);
645 pkrb5_free_context(*ctx);
654 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
656 struct principal_ccache_data * next = princ_cc_data;
657 krb5_principal principal = 0;
659 const char * ccname = NULL;
660 const char * cctype = NULL;
661 krb5_error_code code = 0;
662 krb5_error_code cc_code = 0;
668 if (ctx == 0 || cc == 0)
671 code = pkrb5_cc_get_principal(ctx, cc, &principal);
674 code = pkrb5_unparse_name(ctx, principal, &pname);
675 if ( code ) goto cleanup;
677 ccname = pkrb5_cc_get_name(ctx, cc);
678 if (!ccname) goto cleanup;
680 cctype = pkrb5_cc_get_type(ctx, cc);
681 if (!cctype) goto cleanup;
683 // Search the existing list to see if we have a match
685 for ( ; next ; next = next->next ) {
686 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
691 // If not, match add a new node to the beginning of the list and assign init it
693 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
694 next->next = princ_cc_data;
695 princ_cc_data = next;
696 next->principal = _strdup(pname);
697 next->ccache_name = malloc(strlen(ccname) + strlen(cctype) + 2);
698 if (next->ccache_name)
699 sprintf(next->ccache_name, "%s:%s", cctype, ccname);
700 next->from_lsa = lsa;
702 next->expiration_time = 0;
706 flags = 0; // turn off OPENCLOSE mode
707 code = pkrb5_cc_set_flags(ctx, cc, flags);
708 if ( code ) goto cleanup;
710 code = pkrb5_timeofday(ctx, &now);
712 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
714 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
715 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
717 // we found the ticket we are looking for
718 // check validity of timestamp
719 // We add a 5 minutes fudge factor to compensate for potential
720 // clock skew errors between the KDC and client OS
722 valid = ((creds.times.starttime > 0) &&
723 now >= (creds.times.starttime - 300) &&
724 now < (creds.times.endtime + 300) &&
725 !(creds.ticket_flags & TKT_FLG_INVALID));
727 if ( next->from_lsa) {
729 next->expiration_time = creds.times.endtime;
731 } else if ( valid ) {
733 next->expiration_time = creds.times.endtime;
734 next->renew = (creds.times.renew_till > creds.times.endtime) &&
735 (creds.ticket_flags & TKT_FLG_RENEWABLE);
738 next->expiration_time = 0;
742 pkrb5_free_cred_contents(ctx, &creds);
743 cc_code = KRB5_CC_END;
746 pkrb5_free_cred_contents(ctx, &creds);
749 if (cc_code == KRB5_CC_END) {
750 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
751 if (code) goto cleanup;
755 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
756 code = pkrb5_cc_set_flags(ctx, cc, flags);
759 pkrb5_free_unparsed_name(ctx,pname);
761 pkrb5_free_principal(ctx,principal);
765 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
767 struct principal_ccache_data * next = princ_cc_data;
768 char * response = NULL;
770 if ( !principal || !ccache )
774 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
776 // we always want to prefer the MS Kerberos LSA cache or
777 // the cache afscreds created specifically for the principal
778 // if the current entry is either one, drop the previous find
779 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
782 response = _strdup(next->ccache_name);
783 // MS Kerberos LSA is our best option so use it and quit
784 if ( next->from_lsa )
798 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
800 struct principal_ccache_data ** next = &princ_cc_data;
802 if ( !pname && !ccname )
806 if ( !strcmp((*next)->principal,pname) ||
807 !strcmp((*next)->ccache_name,ccname) ) {
809 free((*next)->principal);
810 free((*next)->ccache_name);
812 (*next) = (*next)->next;
819 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
821 struct cell_principal_map * next = cell_princ_map;
823 // Search the existing list to see if we have a match
825 for ( ; next ; next = next->next ) {
826 if ( !strcmp(next->cell, cell) ) {
827 if ( !strcmp(next->principal,pname) ) {
828 next->active = active;
831 // OpenAFS currently has a restriction of one active token per cell
832 // Therefore, whenever we update the table with a new active cell we
833 // must mark all of the other principal to cell entries as inactive.
841 // If not, match add a new node to the beginning of the list and assign init it
843 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
844 next->next = cell_princ_map;
845 cell_princ_map = next;
846 next->principal = _strdup(pname);
847 next->cell = _strdup(cell);
848 next->active = active;
853 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
855 struct cell_principal_map ** next = &cell_princ_map;
857 if ( !pname && !cell )
861 if ( !strcmp((*next)->principal,pname) ||
862 !strcmp((*next)->cell,cell) ) {
864 free((*next)->principal);
867 (*next) = (*next)->next;
873 // Returns (if possible) a principal which has been known in
874 // the past to have been used to obtain tokens for the specified
876 // TODO: Attempt to return one which has not yet expired by checking
877 // the principal/ccache data
879 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
881 struct cell_principal_map * next_map = cell_princ_map;
882 const char * princ = NULL;
889 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
892 next_map = next_map->next;
895 if ( !principals || !count )
898 *principals = (char **) malloc(sizeof(char *) * count);
899 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
901 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
902 (*principals)[i++] = _strdup(next_map->principal);
909 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
912 struct cell_principal_map * next_map = cell_princ_map;
913 const char * princ = NULL;
919 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
922 next_map = next_map->next;
928 *cells = (char **) malloc(sizeof(char *) * count);
929 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
931 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
932 (*cells)[i++] = _strdup(next_map->cell);
938 /* Given a principal return an existing ccache or create one and return */
940 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
942 krb5_context ctx = NULL;
944 char * ccname = NULL;
945 krb5_error_code code;
947 if (!pkrb5_init_context)
953 code = pkrb5_init_context(&ctx);
954 if (code) goto cleanup;
958 code = pkrb5_unparse_name(ctx, principal, &pname);
959 if (code) goto cleanup;
961 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
962 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
963 ccname = (char *)malloc(strlen(pname) + 5);
964 sprintf(ccname,"API:%s",pname);
966 code = pkrb5_cc_resolve(ctx, ccname, cc);
968 code = pkrb5_cc_default(ctx, cc);
969 if (code) goto cleanup;
976 pkrb5_free_unparsed_name(ctx,pname);
977 if (ctx && (ctx != alt_ctx))
978 pkrb5_free_context(ctx);
983 // Import Microsoft Credentials into a new MIT ccache
985 KFW_import_windows_lsa(void)
987 krb5_context ctx = NULL;
988 krb5_ccache cc = NULL;
989 krb5_principal princ = NULL;
991 krb5_data * princ_realm;
992 krb5_error_code code;
993 char cell[128]="", realm[128]="", *def_realm = 0;
997 if (!pkrb5_init_context)
1000 code = pkrb5_init_context(&ctx);
1001 if (code) goto cleanup;
1003 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
1004 if (code) goto cleanup;
1006 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
1008 code = pkrb5_cc_get_principal(ctx, cc, &princ);
1009 if ( code ) goto cleanup;
1011 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
1012 switch ( dwMsLsaImport ) {
1013 case 0: /* do not import */
1015 case 1: /* always import */
1017 case 2: { /* matching realm */
1018 char ms_realm[128] = "", *r;
1021 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
1022 *r = krb5_princ_realm(ctx, princ)->data[i];
1026 if (code = pkrb5_get_default_realm(ctx, &def_realm))
1029 if (strcmp(def_realm, ms_realm))
1037 code = pkrb5_unparse_name(ctx,princ,&pname);
1038 if ( code ) goto cleanup;
1040 princ_realm = krb5_princ_realm(ctx, princ);
1041 for ( i=0; i<princ_realm->length; i++ ) {
1042 realm[i] = princ_realm->data[i];
1043 cell[i] = tolower(princ_realm->data[i]);
1048 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
1049 if ( IsDebuggerPresent() ) {
1051 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1052 OutputDebugString(message);
1054 if ( code ) goto cleanup;
1056 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1060 pkrb5_free_unparsed_name(ctx,pname);
1062 pkrb5_free_principal(ctx,princ);
1064 pkrb5_free_default_realm(ctx, def_realm);
1066 pkrb5_cc_close(ctx,cc);
1068 pkrb5_free_context(ctx);
1070 #endif /* USE_MS2MIT */
1072 // If there are existing MIT credentials, copy them to a new
1073 // ccache named after the principal
1075 // Enumerate all existing MIT ccaches and construct entries
1076 // in the principal_ccache table
1078 // Enumerate all existing AFS Tokens and construct entries
1079 // in the cell_principal table
1081 KFW_import_ccache_data(void)
1083 krb5_context ctx = NULL;
1084 krb5_ccache cc = NULL;
1085 krb5_principal principal = NULL;
1087 krb5_error_code code;
1088 krb5_error_code cc_code;
1090 apiCB * cc_ctx = NULL;
1091 struct _infoNC ** pNCi = NULL;
1094 if ( !pcc_initialize )
1097 if ( IsDebuggerPresent() )
1098 OutputDebugString("KFW_import_ccache_data()\n");
1100 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1101 if (code) goto cleanup;
1103 code = pcc_get_NC_info(cc_ctx, &pNCi);
1104 if (code) goto cleanup;
1106 code = pkrb5_init_context(&ctx);
1107 if (code) goto cleanup;
1109 for ( i=0; pNCi[i]; i++ ) {
1110 if ( pNCi[i]->vers != CC_CRED_V5 )
1112 if ( IsDebuggerPresent() ) {
1113 OutputDebugString("Principal: ");
1114 OutputDebugString(pNCi[i]->principal);
1115 OutputDebugString(" in ccache ");
1116 OutputDebugString(pNCi[i]->name);
1117 OutputDebugString("\n");
1119 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1120 && strcmp(pNCi[i]->name,LSA_CCNAME)
1123 for ( j=0; pNCi[j]; j++ ) {
1124 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1130 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1131 if (code) goto loop_cleanup;
1134 krb5_ccache oldcc = 0;
1136 if ( IsDebuggerPresent() )
1137 OutputDebugString("copying ccache data to new ccache\n");
1139 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1140 if (code) goto loop_cleanup;
1141 code = pkrb5_cc_initialize(ctx, cc, principal);
1142 if (code) goto loop_cleanup;
1144 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1145 if (code) goto loop_cleanup;
1146 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1148 code = pkrb5_cc_close(ctx,cc);
1150 code = pkrb5_cc_close(ctx,oldcc);
1152 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1155 code = pkrb5_cc_close(ctx,oldcc);
1158 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1159 if (code) goto loop_cleanup;
1162 flags = 0; // turn off OPENCLOSE mode
1163 code = pkrb5_cc_set_flags(ctx, cc, flags);
1164 if ( code ) goto cleanup;
1166 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1168 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1170 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1171 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1172 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1173 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1174 if ( sname && cell && !strcmp("afs",sname->data) ) {
1175 struct ktc_principal aserver;
1176 struct ktc_principal aclient;
1177 struct ktc_token atoken;
1180 if ( IsDebuggerPresent() ) {
1181 OutputDebugString("Found AFS ticket: ");
1182 OutputDebugString(sname->data);
1184 OutputDebugString("/");
1185 OutputDebugString(cell->data);
1187 OutputDebugString("@");
1188 OutputDebugString(realm->data);
1189 OutputDebugString("\n");
1192 memset(&aserver, '\0', sizeof(aserver));
1193 strcpy(aserver.name, sname->data);
1194 strcpy(aserver.cell, cell->data);
1196 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1198 // Found a token in AFS Client Server which matches
1199 char pname[128], *p, *q;
1200 for ( p=pname, q=aclient.name; *q; p++, q++)
1202 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1206 if ( IsDebuggerPresent() ) {
1207 OutputDebugString("Found AFS token: ");
1208 OutputDebugString(pname);
1209 OutputDebugString("\n");
1212 if ( strcmp(pname,pNCi[i]->principal) )
1214 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1216 // Attempt to import it
1217 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1219 if ( IsDebuggerPresent() ) {
1220 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1223 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data,
1227 pLeash_get_default_lifetime(),
1228 #endif /* USE_LEASH */
1230 if ( IsDebuggerPresent() ) {
1232 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1233 OutputDebugString(message);
1236 } else if ( IsDebuggerPresent() ) {
1237 OutputDebugString("Found ticket: ");
1238 OutputDebugString(sname->data);
1239 if ( cell && cell->data ) {
1240 OutputDebugString("/");
1241 OutputDebugString(cell->data);
1243 OutputDebugString("@");
1244 OutputDebugString(realm->data);
1245 OutputDebugString("\n");
1247 pkrb5_free_cred_contents(ctx, &creds);
1250 if (cc_code == KRB5_CC_END) {
1251 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1252 if (cc_code) goto loop_cleanup;
1256 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1257 code = pkrb5_cc_set_flags(ctx, cc, flags);
1259 pkrb5_cc_close(ctx,cc);
1263 pkrb5_free_principal(ctx,principal);
1270 pkrb5_free_context(ctx);
1272 pcc_free_NC_info(cc_ctx, &pNCi);
1274 pcc_shutdown(&cc_ctx);
1279 KFW_AFS_get_cred( char * username,
1286 krb5_context ctx = NULL;
1287 krb5_ccache cc = NULL;
1288 char * realm = NULL, * userrealm = NULL;
1289 krb5_principal principal = NULL;
1290 char * pname = NULL;
1291 krb5_error_code code;
1292 char local_cell[MAXCELLCHARS+1];
1293 char **cells = NULL;
1295 struct afsconf_cell cellconfig;
1298 if (!pkrb5_init_context)
1301 if ( IsDebuggerPresent() ) {
1302 OutputDebugString("KFW_AFS_get_cred for token ");
1303 OutputDebugString(username);
1304 OutputDebugString(" in cell ");
1305 OutputDebugString(cell);
1306 OutputDebugString("\n");
1309 code = pkrb5_init_context(&ctx);
1310 if ( code ) goto cleanup;
1312 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1313 if ( code ) goto cleanup;
1315 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1317 userrealm = strchr(username,'@');
1319 pname = strdup(username);
1320 if (!KFW_accept_dotted_usernames()) {
1321 userrealm = strchr(pname, '@');
1324 /* handle kerberos iv notation */
1325 while ( dot = strchr(pname,'.') ) {
1331 pname = malloc(strlen(username) + strlen(realm) + 2);
1333 strcpy(pname, username);
1335 if (!KFW_accept_dotted_usernames()) {
1336 /* handle kerberos iv notation */
1337 while ( dot = strchr(pname,'.') ) {
1342 strcat(pname,realm);
1344 if ( IsDebuggerPresent() ) {
1345 OutputDebugString("Realm: ");
1346 OutputDebugString(realm);
1347 OutputDebugString("\n");
1350 code = pkrb5_parse_name(ctx, pname, &principal);
1351 if ( code ) goto cleanup;
1353 code = KFW_get_ccache(ctx, principal, &cc);
1354 if ( code ) goto cleanup;
1356 if ( lifetime == 0 )
1360 lifetime = pLeash_get_default_lifetime();
1363 if ( password && password[0] ) {
1364 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1369 1, /* forwardable */
1370 0, /* not proxiable */
1372 1, /* noaddresses */
1373 0 /* no public ip */
1375 pLeash_get_default_forwardable(),
1376 pLeash_get_default_proxiable(),
1377 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1378 pLeash_get_default_noaddresses(),
1379 pLeash_get_default_publicip()
1380 #endif /* USE_LEASH */
1383 if ( IsDebuggerPresent() ) {
1385 sprintf(message,"KFW_kinit() returns: %d\n",code);
1386 OutputDebugString(message);
1388 if ( code ) goto cleanup;
1390 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1393 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1394 if ( IsDebuggerPresent() ) {
1396 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1397 OutputDebugString(message);
1399 if ( code ) goto cleanup;
1401 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1403 // Attempt to obtain new tokens for other cells supported by the same
1405 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1406 if ( cell_count > 1 ) {
1407 while ( cell_count-- ) {
1408 if ( strcmp(cells[cell_count],cell) ) {
1409 if ( IsDebuggerPresent() ) {
1411 sprintf(message,"found another cell for the same principal: %s\n",cell);
1412 OutputDebugString(message);
1414 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1415 if ( code ) continue;
1417 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1418 if ( IsDebuggerPresent() ) {
1419 OutputDebugString("Realm: ");
1420 OutputDebugString(realm);
1421 OutputDebugString("\n");
1424 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1425 if ( IsDebuggerPresent() ) {
1427 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1428 OutputDebugString(message);
1431 free(cells[cell_count]);
1434 } else if ( cell_count == 1 ) {
1443 pkrb5_cc_close(ctx, cc);
1445 if ( code && reasonP ) {
1446 *reasonP = (char *)perror_message(code);
1452 KFW_AFS_destroy_tickets_for_cell(char * cell)
1454 krb5_context ctx = NULL;
1455 krb5_error_code code;
1457 char ** principals = NULL;
1459 if (!pkrb5_init_context)
1462 if ( IsDebuggerPresent() ) {
1463 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1464 OutputDebugString(cell);
1465 OutputDebugString("\n");
1468 code = pkrb5_init_context(&ctx);
1471 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1473 krb5_principal princ = 0;
1477 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1478 if ( cell_count > 1 ) {
1479 // TODO - What we really should do here is verify whether or not any of the
1480 // other cells which use this principal to obtain its credentials actually
1481 // have valid tokens or not. If they are currently using these credentials
1482 // we will skip them. For the time being we assume that if there is an active
1483 // map in the table that they are actively being used.
1487 code = pkrb5_parse_name(ctx, principals[count], &princ);
1488 if (code) goto loop_cleanup;
1490 code = KFW_get_ccache(ctx, princ, &cc);
1491 if (code) goto loop_cleanup;
1493 code = pkrb5_cc_destroy(ctx, cc);
1498 pkrb5_cc_close(ctx, cc);
1502 pkrb5_free_principal(ctx, princ);
1506 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1507 free(principals[count]);
1512 pkrb5_free_context(ctx);
1517 KFW_AFS_destroy_tickets_for_principal(char * user)
1519 krb5_context ctx = NULL;
1520 krb5_error_code code;
1522 char ** cells = NULL;
1523 krb5_principal princ = NULL;
1524 krb5_ccache cc = NULL;
1526 if (!pkrb5_init_context)
1529 if ( IsDebuggerPresent() ) {
1530 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1531 OutputDebugString(user);
1532 OutputDebugString("\n");
1535 code = pkrb5_init_context(&ctx);
1538 code = pkrb5_parse_name(ctx, user, &princ);
1539 if (code) goto loop_cleanup;
1541 code = KFW_get_ccache(ctx, princ, &cc);
1542 if (code) goto loop_cleanup;
1544 code = pkrb5_cc_destroy(ctx, cc);
1549 pkrb5_cc_close(ctx, cc);
1553 pkrb5_free_principal(ctx, princ);
1557 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1560 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1567 pkrb5_free_context(ctx);
1572 KFW_AFS_renew_expiring_tokens(void)
1574 krb5_error_code code = 0;
1575 krb5_context ctx = NULL;
1576 krb5_ccache cc = NULL;
1578 struct principal_ccache_data * pcc_next = princ_cc_data;
1581 const char * realm = NULL;
1582 char local_cell[MAXCELLCHARS+1]="";
1583 struct afsconf_cell cellconfig;
1585 if (!pkrb5_init_context)
1588 if ( pcc_next == NULL ) // nothing to do
1591 if ( IsDebuggerPresent() ) {
1592 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1595 code = pkrb5_init_context(&ctx);
1596 if (code) goto cleanup;
1598 code = pkrb5_timeofday(ctx, &now);
1599 if (code) goto cleanup;
1601 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1602 if ( pcc_next->expired )
1605 if ( now >= (pcc_next->expiration_time) ) {
1606 if ( !pcc_next->from_lsa ) {
1607 pcc_next->expired = 1;
1612 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1613 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1616 code = KFW_renew(ctx,cc);
1618 if ( code && pcc_next->from_lsa)
1620 #endif /* USE_MS2MIT */
1623 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1624 if (code) goto loop_cleanup;
1626 // Attempt to obtain new tokens for other cells supported by the same
1628 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1629 if ( cell_count > 0 ) {
1630 while ( cell_count-- ) {
1631 if ( IsDebuggerPresent() ) {
1632 OutputDebugString("Cell: ");
1633 OutputDebugString(cells[cell_count]);
1634 OutputDebugString("\n");
1636 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1637 if ( code ) continue;
1638 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1639 if ( IsDebuggerPresent() ) {
1640 OutputDebugString("Realm: ");
1641 OutputDebugString(realm);
1642 OutputDebugString("\n");
1644 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1645 if ( IsDebuggerPresent() ) {
1647 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1648 OutputDebugString(message);
1650 free(cells[cell_count]);
1658 pkrb5_cc_close(ctx,cc);
1665 pkrb5_cc_close(ctx,cc);
1667 pkrb5_free_context(ctx);
1674 KFW_AFS_renew_token_for_cell(char * cell)
1676 krb5_error_code code = 0;
1677 krb5_context ctx = NULL;
1679 char ** principals = NULL;
1681 if (!pkrb5_init_context)
1684 if ( IsDebuggerPresent() ) {
1685 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1686 OutputDebugString(cell);
1687 OutputDebugString("\n");
1690 code = pkrb5_init_context(&ctx);
1691 if (code) goto cleanup;
1693 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1695 // We know we must have a credential somewhere since we are
1696 // trying to renew a token
1698 KFW_import_ccache_data();
1699 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1702 krb5_principal princ = 0;
1703 krb5_principal service = 0;
1705 krb5_creds mcreds, creds;
1706 #endif /* COMMENT */
1708 const char * realm = NULL;
1709 struct afsconf_cell cellconfig;
1710 char local_cell[MAXCELLCHARS+1];
1713 code = pkrb5_parse_name(ctx, principals[count], &princ);
1714 if (code) goto loop_cleanup;
1716 code = KFW_get_ccache(ctx, princ, &cc);
1717 if (code) goto loop_cleanup;
1719 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1720 if ( code ) goto loop_cleanup;
1722 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1723 if ( IsDebuggerPresent() ) {
1724 OutputDebugString("Realm: ");
1725 OutputDebugString(realm);
1726 OutputDebugString("\n");
1730 /* krb5_cc_remove_cred() is not implemented
1733 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1734 realm, "afs", cell, NULL);
1736 memset(&mcreds, 0, sizeof(krb5_creds));
1737 mcreds.client = princ;
1738 mcreds.server = service;
1740 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1742 if ( IsDebuggerPresent() ) {
1743 char * cname, *sname;
1744 pkrb5_unparse_name(ctx, creds.client, &cname);
1745 pkrb5_unparse_name(ctx, creds.server, &sname);
1746 OutputDebugString("Removing credential for client \"");
1747 OutputDebugString(cname);
1748 OutputDebugString("\" and service \"");
1749 OutputDebugString(sname);
1750 OutputDebugString("\"\n");
1751 pkrb5_free_unparsed_name(ctx,cname);
1752 pkrb5_free_unparsed_name(ctx,sname);
1755 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1756 pkrb5_free_principal(ctx, creds.client);
1757 pkrb5_free_principal(ctx, creds.server);
1760 #endif /* COMMENT */
1762 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1763 if ( IsDebuggerPresent() ) {
1765 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1766 OutputDebugString(message);
1771 pkrb5_cc_close(ctx, cc);
1775 pkrb5_free_principal(ctx, princ);
1779 pkrb5_free_principal(ctx, service);
1783 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1784 free(principals[count]);
1788 code = -1; // we did not renew the tokens
1792 pkrb5_free_context(ctx);
1793 return (code ? FALSE : TRUE);
1798 KFW_AFS_renew_tokens_for_all_cells(void)
1800 struct cell_principal_map * next = cell_princ_map;
1802 if ( IsDebuggerPresent() )
1803 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1808 for ( ; next ; next = next->next ) {
1810 KFW_AFS_renew_token_for_cell(next->cell);
1816 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1818 krb5_error_code code = 0;
1819 krb5_context ctx = NULL;
1820 krb5_ccache cc = NULL;
1821 krb5_principal me = NULL;
1822 krb5_principal server = NULL;
1823 krb5_creds my_creds;
1824 krb5_data *realm = NULL;
1826 if (!pkrb5_init_context)
1829 memset(&my_creds, 0, sizeof(krb5_creds));
1834 code = pkrb5_init_context(&ctx);
1835 if (code) goto cleanup;
1841 code = pkrb5_cc_default(ctx, &cc);
1842 if (code) goto cleanup;
1845 code = pkrb5_cc_get_principal(ctx, cc, &me);
1846 if (code) goto cleanup;
1848 realm = krb5_princ_realm(ctx, me);
1850 code = pkrb5_build_principal_ext(ctx, &server,
1851 realm->length,realm->data,
1852 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1853 realm->length,realm->data,
1858 if ( IsDebuggerPresent() ) {
1859 char * cname, *sname;
1860 pkrb5_unparse_name(ctx, me, &cname);
1861 pkrb5_unparse_name(ctx, server, &sname);
1862 OutputDebugString("Renewing credential for client \"");
1863 OutputDebugString(cname);
1864 OutputDebugString("\" and service \"");
1865 OutputDebugString(sname);
1866 OutputDebugString("\"\n");
1867 pkrb5_free_unparsed_name(ctx,cname);
1868 pkrb5_free_unparsed_name(ctx,sname);
1871 my_creds.client = me;
1872 my_creds.server = server;
1874 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1876 if ( IsDebuggerPresent() ) {
1878 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1879 OutputDebugString(message);
1884 code = pkrb5_cc_initialize(ctx, cc, me);
1886 if ( IsDebuggerPresent() ) {
1888 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1889 OutputDebugString(message);
1894 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1896 if ( IsDebuggerPresent() ) {
1898 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1899 OutputDebugString(message);
1905 if (my_creds.client == me)
1906 my_creds.client = 0;
1907 if (my_creds.server == server)
1908 my_creds.server = 0;
1909 pkrb5_free_cred_contents(ctx, &my_creds);
1911 pkrb5_free_principal(ctx, me);
1913 pkrb5_free_principal(ctx, server);
1914 if (cc && (cc != alt_cc))
1915 pkrb5_cc_close(ctx, cc);
1916 if (ctx && (ctx != alt_ctx))
1917 pkrb5_free_context(ctx);
1922 KFW_kinit( krb5_context alt_ctx,
1925 char *principal_name,
1927 krb5_deltat lifetime,
1930 krb5_deltat renew_life,
1935 krb5_error_code code = 0;
1936 krb5_context ctx = NULL;
1937 krb5_ccache cc = NULL;
1938 krb5_principal me = NULL;
1940 krb5_creds my_creds;
1941 krb5_get_init_creds_opt options;
1942 krb5_address ** addrs = NULL;
1943 int i = 0, addr_count = 0;
1945 if (!pkrb5_init_context)
1948 pkrb5_get_init_creds_opt_init(&options);
1949 memset(&my_creds, 0, sizeof(my_creds));
1957 code = pkrb5_init_context(&ctx);
1958 if (code) goto cleanup;
1964 code = pkrb5_cc_default(ctx, &cc);
1965 if (code) goto cleanup;
1968 code = pkrb5_parse_name(ctx, principal_name, &me);
1972 code = pkrb5_unparse_name(ctx, me, &name);
1980 lifetime = pLeash_get_default_lifetime();
1981 #endif /* USE_LEASH */
1988 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1989 pkrb5_get_init_creds_opt_set_forwardable(&options,
1990 forwardable ? 1 : 0);
1991 pkrb5_get_init_creds_opt_set_proxiable(&options,
1993 pkrb5_get_init_creds_opt_set_renew_life(&options,
1996 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
2000 // we are going to add the public IP address specified by the user
2001 // to the list provided by the operating system
2002 krb5_address ** local_addrs=NULL;
2005 pkrb5_os_localaddr(ctx, &local_addrs);
2006 while ( local_addrs[i++] );
2009 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
2011 pkrb5_free_addresses(ctx, local_addrs);
2014 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
2016 while ( local_addrs[i] ) {
2017 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2018 if (addrs[i] == NULL) {
2019 pkrb5_free_addresses(ctx, local_addrs);
2023 addrs[i]->magic = local_addrs[i]->magic;
2024 addrs[i]->addrtype = local_addrs[i]->addrtype;
2025 addrs[i]->length = local_addrs[i]->length;
2026 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2027 if (!addrs[i]->contents) {
2028 pkrb5_free_addresses(ctx, local_addrs);
2032 memcpy(addrs[i]->contents,local_addrs[i]->contents,
2033 local_addrs[i]->length); /* safe */
2036 pkrb5_free_addresses(ctx, local_addrs);
2038 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
2039 if (addrs[i] == NULL)
2042 addrs[i]->magic = KV5M_ADDRESS;
2043 addrs[i]->addrtype = AF_INET;
2044 addrs[i]->length = 4;
2045 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
2046 if (!addrs[i]->contents)
2049 netIPAddr = htonl(publicIP);
2050 memcpy(addrs[i]->contents,&netIPAddr,4);
2052 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
2057 code = pkrb5_get_init_creds_password(ctx,
2060 password, // password
2061 KRB5_prompter, // prompter
2062 hParent, // prompter data
2069 code = pkrb5_cc_initialize(ctx, cc, me);
2073 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
2079 for ( i=0;i<addr_count;i++ ) {
2081 if ( addrs[i]->contents )
2082 free(addrs[i]->contents);
2087 if (my_creds.client == me)
2088 my_creds.client = 0;
2089 pkrb5_free_cred_contents(ctx, &my_creds);
2091 pkrb5_free_unparsed_name(ctx, name);
2093 pkrb5_free_principal(ctx, me);
2094 if (cc && (cc != alt_cc))
2095 pkrb5_cc_close(ctx, cc);
2096 if (ctx && (ctx != alt_ctx))
2097 pkrb5_free_context(ctx);
2103 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2105 krb5_context ctx = NULL;
2106 krb5_ccache cc = NULL;
2107 krb5_error_code code;
2109 if (!pkrb5_init_context)
2118 code = pkrb5_init_context(&ctx);
2119 if (code) goto cleanup;
2125 code = pkrb5_cc_default(ctx, &cc);
2126 if (code) goto cleanup;
2129 code = pkrb5_cc_destroy(ctx, cc);
2130 if ( !code ) cc = 0;
2133 if (cc && (cc != alt_cc))
2134 pkrb5_cc_close(ctx, cc);
2135 if (ctx && (ctx != alt_ctx))
2136 pkrb5_free_context(ctx);
2144 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2146 NTSTATUS Status = 0;
2148 TOKEN_STATISTICS Stats;
2154 *ppSessionData = NULL;
2156 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2160 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2161 CloseHandle( TokenHandle );
2165 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2166 if ( FAILED(Status) || !ppSessionData )
2173 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2174 // cache. It validates whether or not it is reasonable to assume that if we
2175 // attempted to retrieve valid tickets we could do so. Microsoft does not
2176 // automatically renew expired tickets. Therefore, the cache could contain
2177 // expired or invalid tickets. Microsoft also caches the user's password
2178 // and will use it to retrieve new TGTs if the cache is empty and tickets
2182 MSLSA_IsKerberosLogon(VOID)
2184 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2185 BOOL Success = FALSE;
2187 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2188 if ( pSessionData->AuthenticationPackage.Buffer ) {
2194 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2195 usLength = (pSessionData->AuthenticationPackage).Length;
2198 lstrcpynW (buffer, usBuffer, usLength);
2199 lstrcatW (buffer,L"");
2200 if ( !lstrcmpW(L"Kerberos",buffer) )
2204 pLsaFreeReturnBuffer(pSessionData);
2208 #endif /* USE_MS2MIT */
2210 static BOOL CALLBACK
2211 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2215 switch ( message ) {
2217 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2219 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2222 for ( i=0; i < mid_cnt ; i++ ) {
2223 if (mid_tb[i].echo == 0)
2224 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2225 else if (mid_tb[i].echo == 2)
2226 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2231 switch ( LOWORD(wParam) ) {
2233 for ( i=0; i < mid_cnt ; i++ ) {
2234 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2235 *mid_tb[i].buf = '\0';
2239 EndDialog(hDialog, LOWORD(wParam));
2247 lpwAlign( LPWORD lpIn )
2251 ul = (ULONG_PTR) lpIn;
2255 return (LPWORD) ul;;
2259 * dialog widths are measured in 1/4 character widths
2260 * dialog height are measured in 1/8 character heights
2264 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2265 char * ptext[], int numlines, int width,
2266 int tb_cnt, struct textField * tb)
2270 LPDLGITEMTEMPLATE lpdit;
2276 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2283 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2285 // Define a dialog box.
2287 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2288 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2289 | DS_SETFOREGROUND | DS_3DLOOK
2290 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2291 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2294 lpdt->cx = 20 + width * 4;
2295 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2297 lpw = (LPWORD) (lpdt + 1);
2298 *lpw++ = 0; // no menu
2299 *lpw++ = 0; // predefined dialog box class (by default)
2301 lpwsz = (LPWSTR) lpw;
2302 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2304 *lpw++ = 8; // font size (points)
2305 lpwsz = (LPWSTR) lpw;
2306 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2310 //-----------------------
2311 // Define an OK button.
2312 //-----------------------
2313 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2314 lpdit = (LPDLGITEMTEMPLATE) lpw;
2315 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2316 lpdit->dwExtendedStyle = 0;
2317 lpdit->x = (lpdt->cx - 14)/4 - 20;
2318 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2321 lpdit->id = IDOK; // OK button identifier
2323 lpw = (LPWORD) (lpdit + 1);
2325 *lpw++ = 0x0080; // button class
2327 lpwsz = (LPWSTR) lpw;
2328 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2330 *lpw++ = 0; // no creation data
2332 //-----------------------
2333 // Define an Cancel button.
2334 //-----------------------
2335 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2336 lpdit = (LPDLGITEMTEMPLATE) lpw;
2337 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2338 lpdit->dwExtendedStyle = 0;
2339 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2340 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2343 lpdit->id = IDCANCEL; // CANCEL button identifier
2345 lpw = (LPWORD) (lpdit + 1);
2347 *lpw++ = 0x0080; // button class
2349 lpwsz = (LPWSTR) lpw;
2350 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2352 *lpw++ = 0; // no creation data
2354 /* Add controls for preface data */
2355 for ( i=0; i<numlines; i++) {
2356 /*-----------------------
2357 * Define a static text control.
2358 *-----------------------*/
2359 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2360 lpdit = (LPDLGITEMTEMPLATE) lpw;
2361 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2362 lpdit->dwExtendedStyle = 0;
2364 lpdit->y = 10 + i * 14;
2365 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2367 lpdit->id = ID_TEXT + i; // text identifier
2369 lpw = (LPWORD) (lpdit + 1);
2371 *lpw++ = 0x0082; // static class
2373 lpwsz = (LPWSTR) lpw;
2374 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2375 -1, lpwsz, 2*width);
2377 *lpw++ = 0; // no creation data
2380 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2381 int len = (int)strlen(tb[i].label);
2386 for ( i=0; i<tb_cnt; i++) {
2388 /*-----------------------
2389 * Define a static text control.
2390 *-----------------------*/
2391 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2392 lpdit = (LPDLGITEMTEMPLATE) lpw;
2393 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2394 lpdit->dwExtendedStyle = 0;
2396 lpdit->y = 10 + (numlines + i + 1) * 14;
2397 lpdit->cx = pwid * 4;
2399 lpdit->id = ID_TEXT + numlines + i; // text identifier
2401 lpw = (LPWORD) (lpdit + 1);
2403 *lpw++ = 0x0082; // static class
2405 lpwsz = (LPWSTR) lpw;
2406 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2409 *lpw++ = 0; // no creation data
2411 /*-----------------------
2412 * Define an edit control.
2413 *-----------------------*/
2414 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2415 lpdit = (LPDLGITEMTEMPLATE) lpw;
2416 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2417 lpdit->dwExtendedStyle = 0;
2418 lpdit->x = 10 + (pwid + 1) * 4;
2419 lpdit->y = 10 + (numlines + i + 1) * 14;
2420 lpdit->cx = (width - (pwid + 1)) * 4;
2422 lpdit->id = ID_MID_TEXT + i; // identifier
2424 lpw = (LPWORD) (lpdit + 1);
2426 *lpw++ = 0x0081; // edit class
2428 lpwsz = (LPWSTR) lpw;
2429 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2432 *lpw++ = 0; // no creation data
2436 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2437 hwndOwner, (DLGPROC) MultiInputDialogProc);
2441 case 0: /* Timeout */
2449 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2450 MessageBox(hwndOwner,
2453 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2460 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2462 HINSTANCE hInst = 0;
2466 char * plines[16], *p = preface ? preface : "";
2469 for ( i=0; i<16; i++ )
2472 while (*p && numlines < 16) {
2473 plines[numlines++] = p;
2474 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2475 if ( *p == '\r' && *(p+1) == '\n' ) {
2478 } else if ( *p == '\n' ) {
2481 if ( strlen(plines[numlines-1]) > maxwidth )
2482 maxwidth = (int)strlen(plines[numlines-1]);
2485 for ( i=0;i<n;i++ ) {
2486 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2487 if ( maxwidth < len )
2491 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2494 static krb5_error_code KRB5_CALLCONV
2495 KRB5_prompter( krb5_context context,
2500 krb5_prompt prompts[])
2502 krb5_error_code errcode = 0;
2504 struct textField * tb = NULL;
2505 int len = 0, blen=0, nlen=0;
2506 HWND hParent = (HWND)data;
2509 nlen = (int)strlen(name)+2;
2512 blen = (int)strlen(banner)+2;
2514 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2517 memset(tb,0,sizeof(struct textField) * num_prompts);
2518 for ( i=0; i < num_prompts; i++ ) {
2519 tb[i].buf = prompts[i].reply->data;
2520 tb[i].len = prompts[i].reply->length;
2521 tb[i].label = prompts[i].prompt;
2523 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2526 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2528 for ( i=0; i < num_prompts; i++ )
2529 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2537 for (i = 0; i < num_prompts; i++) {
2538 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2545 KFW_AFS_wait_for_service_start(void)
2550 CurrentState = SERVICE_START_PENDING;
2551 memset(HostName, '\0', sizeof(HostName));
2552 gethostname(HostName, sizeof(HostName));
2554 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2556 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2558 if ( IsDebuggerPresent() ) {
2559 switch ( CurrentState ) {
2560 case SERVICE_STOPPED:
2561 OutputDebugString("SERVICE_STOPPED\n");
2563 case SERVICE_START_PENDING:
2564 OutputDebugString("SERVICE_START_PENDING\n");
2566 case SERVICE_STOP_PENDING:
2567 OutputDebugString("SERVICE_STOP_PENDING\n");
2569 case SERVICE_RUNNING:
2570 OutputDebugString("SERVICE_RUNNING\n");
2572 case SERVICE_CONTINUE_PENDING:
2573 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2575 case SERVICE_PAUSE_PENDING:
2576 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2578 case SERVICE_PAUSED:
2579 OutputDebugString("SERVICE_PAUSED\n");
2582 OutputDebugString("UNKNOWN Service State\n");
2585 if (CurrentState == SERVICE_STOPPED)
2587 if (CurrentState == SERVICE_RUNNING)
2603 memset(HostName, '\0', sizeof(HostName));
2604 gethostname(HostName, sizeof(HostName));
2605 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2607 if (CurrentState != SERVICE_RUNNING)
2610 rc = ktc_ForgetAllTokens();
2616 #define ALLOW_REGISTER 1
2618 ViceIDToUsername(char *username,
2619 char *realm_of_user,
2620 char *realm_of_cell,
2622 struct ktc_principal *aclient,
2623 struct ktc_principal *aserver,
2624 struct ktc_token *atoken)
2626 static char lastcell[MAXCELLCHARS+1] = { 0 };
2627 static char confname[512] = { 0 };
2628 #ifdef AFS_ID_TO_NAME
2629 char username_copy[BUFSIZ];
2630 #endif /* AFS_ID_TO_NAME */
2631 long viceId = ANONYMOUSID; /* AFS uid of user */
2633 #ifdef ALLOW_REGISTER
2635 #endif /* ALLOW_REGISTER */
2637 if (confname[0] == '\0') {
2638 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2639 confname[sizeof(confname) - 2] = '\0';
2642 strcpy(lastcell, aserver->cell);
2644 if (!pr_Initialize (0, confname, aserver->cell)) {
2645 char sname[PR_MAXNAMELEN];
2646 strncpy(sname, username, PR_MAXNAMELEN);
2647 sname[PR_MAXNAMELEN-1] = '\0';
2648 status = pr_SNameToId (sname, &viceId);
2653 * This is a crock, but it is Transarc's crock, so
2654 * we have to play along in order to get the
2655 * functionality. The way the afs id is stored is
2656 * as a string in the username field of the token.
2657 * Contrary to what you may think by looking at
2658 * the code for tokens, this hack (AFS ID %d) will
2659 * not work if you change %d to something else.
2663 * This code is taken from cklog -- it lets people
2664 * automatically register with the ptserver in foreign cells
2667 #ifdef ALLOW_REGISTER
2669 if (viceId != ANONYMOUSID) {
2670 #else /* ALLOW_REGISTER */
2671 if ((status == 0) && (viceId != ANONYMOUSID))
2672 #endif /* ALLOW_REGISTER */
2674 #ifdef AFS_ID_TO_NAME
2675 strncpy(username_copy, username, BUFSIZ);
2676 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2677 #endif /* AFS_ID_TO_NAME */
2679 #ifdef ALLOW_REGISTER
2680 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2682 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2683 strcpy(aclient->instance, "");
2684 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2685 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2687 if (status = pr_Initialize(1L, confname, aserver->cell))
2689 status = pr_CreateUser(username, &id);
2693 #ifdef AFS_ID_TO_NAME
2694 strncpy(username_copy, username, BUFSIZ);
2695 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2696 #endif /* AFS_ID_TO_NAME */
2699 #endif /* ALLOW_REGISTER */
2706 krb5_context alt_ctx,
2711 int lifetime, /* unused parameter */
2719 #endif /* USE_KRB4 */
2720 struct ktc_principal aserver;
2721 struct ktc_principal aclient;
2722 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2723 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2724 char local_cell[MAXCELLCHARS+1];
2725 char Dmycell[MAXCELLCHARS+1];
2726 struct ktc_token atoken;
2727 struct ktc_token btoken;
2728 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2729 char RealmName[128];
2731 char ServiceName[128];
2735 krb5_context ctx = NULL;
2736 krb5_ccache cc = NULL;
2738 krb5_creds * k5creds = NULL;
2739 krb5_error_code code;
2740 krb5_principal client_principal = NULL;
2741 krb5_data * k5data = NULL;
2745 memset(HostName, '\0', sizeof(HostName));
2746 gethostname(HostName, sizeof(HostName));
2747 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2748 if ( IsDebuggerPresent() )
2749 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2752 if (CurrentState != SERVICE_RUNNING) {
2753 if ( IsDebuggerPresent() )
2754 OutputDebugString("AFSD Service NOT RUNNING\n");
2758 if (!pkrb5_init_context)
2761 memset(RealmName, '\0', sizeof(RealmName));
2762 memset(CellName, '\0', sizeof(CellName));
2763 memset(ServiceName, '\0', sizeof(ServiceName));
2764 memset(realm_of_user, '\0', sizeof(realm_of_user));
2765 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2766 if (cell && cell[0])
2767 strcpy(Dmycell, cell);
2769 memset(Dmycell, '\0', sizeof(Dmycell));
2771 // NULL or empty cell returns information on local cell
2772 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2774 // KFW_AFS_error(rc, "get_cellconfig()");
2781 code = pkrb5_init_context(&ctx);
2782 if (code) goto cleanup;
2788 code = pkrb5_cc_default(ctx, &cc);
2789 if (code) goto skip_krb5_init;
2792 memset((char *)&increds, 0, sizeof(increds));
2794 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2796 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2798 OutputDebugString("Principal Not Found for ccache\n");
2800 goto skip_krb5_init;
2803 if (!KFW_accept_dotted_usernames()) {
2804 /* look for client principals which cannot be distinguished
2805 * from Kerberos 4 multi-component principal names
2807 k5data = krb5_princ_component(ctx,client_principal,0);
2808 for ( i=0; i<k5data->length; i++ ) {
2809 if ( k5data->data[i] == '.' )
2812 if (i != k5data->length)
2814 OutputDebugString("Illegal Principal name contains dot in first component\n");
2815 rc = KRB5KRB_ERR_GENERIC;
2820 i = krb5_princ_realm(ctx, client_principal)->length;
2823 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2824 realm_of_user[i] = 0;
2829 if ( !try_krb5 || !realm_of_user[0] ) {
2830 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2839 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2841 if (strlen(service) == 0)
2842 strcpy(ServiceName, "afs");
2844 strcpy(ServiceName, service);
2846 if (strlen(cell) == 0)
2847 strcpy(CellName, local_cell);
2849 strcpy(CellName, cell);
2851 if (strlen(realm) == 0)
2852 strcpy(RealmName, realm_of_cell);
2854 strcpy(RealmName, realm);
2856 memset(&creds, '\0', sizeof(creds));
2861 /* First try service/cell@REALM */
2862 if (code = pkrb5_build_principal(ctx, &increds.server,
2863 (int)strlen(RealmName),
2872 increds.client = client_principal;
2873 increds.times.endtime = 0;
2874 /* Ask for DES since that is what V4 understands */
2875 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2878 if ( IsDebuggerPresent() ) {
2879 char * cname, *sname;
2880 pkrb5_unparse_name(ctx, increds.client, &cname);
2881 pkrb5_unparse_name(ctx, increds.server, &sname);
2882 OutputDebugString("Getting tickets for \"");
2883 OutputDebugString(cname);
2884 OutputDebugString("\" and service \"");
2885 OutputDebugString(sname);
2886 OutputDebugString("\"\n");
2887 pkrb5_free_unparsed_name(ctx,cname);
2888 pkrb5_free_unparsed_name(ctx,sname);
2891 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2892 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2893 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2894 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2895 /* Or service@REALM */
2896 pkrb5_free_principal(ctx,increds.server);
2898 code = pkrb5_build_principal(ctx, &increds.server,
2899 (int)strlen(RealmName),
2904 if ( IsDebuggerPresent() ) {
2905 char * cname, *sname;
2906 pkrb5_unparse_name(ctx, increds.client, &cname);
2907 pkrb5_unparse_name(ctx, increds.server, &sname);
2908 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2909 OutputDebugString("Trying again: getting tickets for \"");
2910 OutputDebugString(cname);
2911 OutputDebugString("\" and service \"");
2912 OutputDebugString(sname);
2913 OutputDebugString("\"\n");
2914 pkrb5_free_unparsed_name(ctx,cname);
2915 pkrb5_free_unparsed_name(ctx,sname);
2919 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2922 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2923 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2924 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2925 strcmp(RealmName, realm_of_cell)) {
2926 /* Or service/cell@REALM_OF_CELL */
2927 strcpy(RealmName, realm_of_cell);
2928 pkrb5_free_principal(ctx,increds.server);
2930 code = pkrb5_build_principal(ctx, &increds.server,
2931 (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 /* Or service@REALM_OF_CELL */
2959 pkrb5_free_principal(ctx,increds.server);
2961 code = pkrb5_build_principal(ctx, &increds.server,
2962 (int)strlen(RealmName),
2967 if ( IsDebuggerPresent() ) {
2968 char * cname, *sname;
2969 pkrb5_unparse_name(ctx, increds.client, &cname);
2970 pkrb5_unparse_name(ctx, increds.server, &sname);
2971 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2972 OutputDebugString("Trying again: getting tickets for \"");
2973 OutputDebugString(cname);
2974 OutputDebugString("\" and service \"");
2975 OutputDebugString(sname);
2976 OutputDebugString("\"\n");
2977 pkrb5_free_unparsed_name(ctx,cname);
2978 pkrb5_free_unparsed_name(ctx,sname);
2982 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2987 if ( IsDebuggerPresent() ) {
2989 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2990 OutputDebugString(message);
2996 /* This code inserts the entire K5 ticket into the token
2997 * No need to perform a krb524 translation which is
2998 * commented out in the code below
3000 if (KFW_use_krb524() ||
3001 k5creds->ticket.length > MAXKTCTICKETLEN)
3004 memset(&aserver, '\0', sizeof(aserver));
3005 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3006 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3008 memset(&atoken, '\0', sizeof(atoken));
3009 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
3010 atoken.startTime = k5creds->times.starttime;
3011 atoken.endTime = k5creds->times.endtime;
3012 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
3013 atoken.ticketLen = k5creds->ticket.length;
3014 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
3017 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3018 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3019 if ( rc == KTC_NOCM && retry < 20 ) {
3022 goto retry_gettoken5;
3027 if (atoken.kvno == btoken.kvno &&
3028 atoken.ticketLen == btoken.ticketLen &&
3029 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3030 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3032 /* Success - Nothing to do */
3036 // * Reset the "aclient" structure before we call ktc_SetToken.
3037 // * This structure was first set by the ktc_GetToken call when
3038 // * we were comparing whether identical tokens already existed.
3040 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
3041 strncpy(aclient.name, k5creds->client->data[0].data, len);
3042 aclient.name[len] = '\0';
3044 if ( k5creds->client->length > 1 ) {
3046 strcat(aclient.name, ".");
3047 p = aclient.name + strlen(aclient.name);
3048 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3049 strncpy(p, k5creds->client->data[1].data, len);
3052 aclient.instance[0] = '\0';
3054 strcpy(aclient.cell, realm_of_cell);
3056 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
3057 /* For Khimaira, always append the realm name */
3058 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
3060 strcat(aclient.name, "@");
3061 p = aclient.name + strlen(aclient.name);
3062 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
3063 strncpy(p, k5creds->client->realm.data, len);
3067 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3068 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3069 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3070 &aclient, &aserver, &atoken);
3073 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3074 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3076 aclient.smbname[0] = '\0';
3079 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
3081 goto cleanup; /* We have successfully inserted the token */
3087 /* Otherwise, the ticket could have been too large so try to
3088 * convert using the krb524d running with the KDC
3090 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
3091 pkrb5_free_creds(ctx, k5creds);
3093 if ( IsDebuggerPresent() ) {
3095 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3096 OutputDebugString(message);
3101 #endif /* USE_KRB524 */
3105 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3106 if (code == NO_TKT_FIL) {
3107 // if the problem is that we have no krb4 tickets
3108 // do not attempt to continue
3111 if (code != KSUCCESS)
3112 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3114 if (code != KSUCCESS)
3116 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3118 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3123 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3125 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3140 memset(&aserver, '\0', sizeof(aserver));
3141 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3142 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3144 memset(&atoken, '\0', sizeof(atoken));
3145 atoken.kvno = creds.kvno;
3146 atoken.startTime = creds.issue_date;
3147 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3148 memcpy(&atoken.sessionKey, creds.session, 8);
3149 atoken.ticketLen = creds.ticket_st.length;
3150 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3153 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3154 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3155 if ( rc == KTC_NOCM && retry < 20 ) {
3158 goto retry_gettoken;
3160 KFW_AFS_error(rc, "ktc_GetToken()");
3165 if (atoken.kvno == btoken.kvno &&
3166 atoken.ticketLen == btoken.ticketLen &&
3167 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3168 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3173 // * Reset the "aclient" structure before we call ktc_SetToken.
3174 // * This structure was first set by the ktc_GetToken call when
3175 // * we were comparing whether identical tokens already existed.
3177 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3180 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3181 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3183 strcpy(aclient.instance, "");
3185 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3186 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3187 aclient.name[MAXKTCREALMLEN-1] = '\0';
3189 strcpy(aclient.cell, CellName);
3191 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3192 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3193 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3194 &aclient, &aserver, &atoken);
3197 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3198 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3200 aclient.smbname[0] = '\0';
3203 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3205 KFW_AFS_error(rc, "ktc_SetToken()");
3211 if (client_principal)
3212 pkrb5_free_principal(ctx,client_principal);
3213 /* increds.client == client_principal */
3215 pkrb5_free_principal(ctx,increds.server);
3216 if (cc && (cc != alt_cc))
3217 pkrb5_cc_close(ctx, cc);
3218 if (ctx && (ctx != alt_ctx))
3219 pkrb5_free_context(ctx);
3221 return(rc? rc : code);
3224 /**************************************/
3225 /* afs_realm_of_cell(): */
3226 /**************************************/
3228 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3230 static char krbrlm[REALM_SZ+1]="";
3231 char ** realmlist=NULL;
3237 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3238 if ( !r && realmlist && realmlist[0] ) {
3239 strcpy(krbrlm, realmlist[0]);
3240 pkrb5_free_host_realm(ctx, realmlist);
3246 char *t = cellconfig->name;
3251 if (islower(c)) c=toupper(c);
3259 /**************************************/
3260 /* KFW_AFS_get_cellconfig(): */
3261 /**************************************/
3263 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3266 char newcell[MAXCELLCHARS+1];
3268 local_cell[0] = (char)0;
3269 memset(cellconfig, 0, sizeof(*cellconfig));
3271 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3272 if (rc = cm_GetRootCellName(local_cell))
3277 if (strlen(cell) == 0)
3278 strcpy(cell, local_cell);
3280 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3281 strcpy(cellconfig->name, cell);
3283 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3284 #ifdef AFS_AFSDB_ENV
3287 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3293 /**************************************/
3294 /* get_cellconfig_callback(): */
3295 /**************************************/
3297 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3299 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3301 cc->hostAddr[cc->numServers] = *addrp;
3302 strcpy(cc->hostName[cc->numServers], namep);
3308 /**************************************/
3309 /* KFW_AFS_error(): */
3310 /**************************************/
3312 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3315 const char *errText;
3317 // Using AFS defines as error messages for now, until Transarc
3318 // gets back to me with "string" translations of each of these
3320 if (rc == KTC_ERROR)
3321 errText = "KTC_ERROR";
3322 else if (rc == KTC_TOOBIG)
3323 errText = "KTC_TOOBIG";
3324 else if (rc == KTC_INVAL)
3325 errText = "KTC_INVAL";
3326 else if (rc == KTC_NOENT)
3327 errText = "KTC_NOENT";
3328 else if (rc == KTC_PIOCTLFAIL)
3329 errText = "KTC_PIOCTLFAIL";
3330 else if (rc == KTC_NOPIOCTL)
3331 errText = "KTC_NOPIOCTL";
3332 else if (rc == KTC_NOCELL)
3333 errText = "KTC_NOCELL";
3334 else if (rc == KTC_NOCM)
3335 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3337 errText = "Unknown error!";
3339 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3341 if ( IsDebuggerPresent() ) {
3342 OutputDebugString(message);
3343 OutputDebugString("\n");
3345 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3351 LPSTR lpszMachineName,
3352 LPSTR lpszServiceName,
3353 DWORD *lpdwCurrentState)
3356 SC_HANDLE schSCManager = NULL;
3357 SC_HANDLE schService = NULL;
3358 DWORD fdwDesiredAccess = 0;
3359 SERVICE_STATUS ssServiceStatus = {0};
3362 *lpdwCurrentState = 0;
3364 fdwDesiredAccess = GENERIC_READ;
3366 schSCManager = OpenSCManager(lpszMachineName,
3370 if(schSCManager == NULL)
3372 hr = GetLastError();
3376 schService = OpenService(schSCManager,
3380 if(schService == NULL)
3382 hr = GetLastError();
3386 fRet = QueryServiceStatus(schService,
3391 hr = GetLastError();
3395 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3399 CloseServiceHandle(schService);
3400 CloseServiceHandle(schSCManager);
3413 for (n = 0; fi[n].func_ptr_var; n++)
3414 *(fi[n].func_ptr_var) = 0;
3415 if (h) FreeLibrary(h);
3420 const char* dll_name,
3422 HINSTANCE* ph, // [out, optional] - DLL handle
3423 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3424 int cleanup, // cleanup function pointers and unload on error
3425 int go_on, // continue loading even if some functions cannot be loaded
3426 int silent // do not pop-up a system dialog if DLL cannot be loaded
3435 if (pindex) *pindex = -1;
3437 for (n = 0; fi[n].func_ptr_var; n++)
3438 *(fi[n].func_ptr_var) = 0;
3441 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3442 h = LoadLibrary(dll_name);
3450 for (i = 0; (go_on || !error) && (i < n); i++)
3452 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3458 *(fi[i].func_ptr_var) = p;
3461 if (pindex) *pindex = last_i;
3462 if (error && cleanup && !go_on) {
3463 for (i = 0; i < n; i++) {
3464 *(fi[i].func_ptr_var) = 0;
3470 if (error) return 0;
3474 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3476 krb5_context ctx = NULL;
3477 krb5_ccache cc = NULL;
3478 krb5_error_code code;
3480 const char * realm = NULL;
3481 krb5_principal principal = NULL;
3482 char * pname = NULL;
3483 char password[PROBE_PASSWORD_LEN+1];
3484 BOOL serverReachable = 0;
3486 if (!pkrb5_init_context)
3489 code = pkrb5_init_context(&ctx);
3490 if (code) goto cleanup;
3493 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3495 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3496 realm, PROBE_USERNAME, NULL, NULL);
3497 if ( code ) goto cleanup;
3499 code = KFW_get_ccache(ctx, principal, &cc);
3500 if ( code ) goto cleanup;
3502 code = pkrb5_unparse_name(ctx, principal, &pname);
3503 if ( code ) goto cleanup;
3505 pwdata.data = password;
3506 pwdata.length = PROBE_PASSWORD_LEN;
3507 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3510 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3513 password[PROBE_PASSWORD_LEN] = '\0';
3515 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3525 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3526 case KRB5KDC_ERR_CLIENT_REVOKED:
3527 case KRB5KDC_ERR_CLIENT_NOTYET:
3528 case KRB5KDC_ERR_PREAUTH_FAILED:
3529 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3530 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3531 serverReachable = TRUE;
3534 serverReachable = FALSE;
3539 pkrb5_free_unparsed_name(ctx,pname);
3541 pkrb5_free_principal(ctx,principal);
3543 pkrb5_cc_close(ctx,cc);
3545 pkrb5_free_context(ctx);
3547 return serverReachable;
3551 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3553 krb5_context ctx = NULL;
3554 krb5_error_code code;
3555 krb5_ccache mslsa_ccache=NULL;
3556 krb5_principal princ = NULL;
3557 char * pname = NULL;
3560 if (!KFW_is_available())
3563 if (code = pkrb5_init_context(&ctx))
3566 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3569 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3572 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3575 if ( strlen(pname) < *dwSize ) {
3576 strncpy(szUser, pname, *dwSize);
3577 szUser[*dwSize-1] = '\0';
3580 *dwSize = (DWORD)strlen(pname);
3584 pkrb5_free_unparsed_name(ctx, pname);
3587 pkrb5_free_principal(ctx, princ);
3590 pkrb5_cc_close(ctx, mslsa_ccache);
3593 pkrb5_free_context(ctx);
3598 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3600 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3601 PSID pSystemSID = NULL;
3602 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3603 PACL ccacheACL = NULL;
3604 DWORD ccacheACLlength = 0;
3605 PTOKEN_USER pTokenUser = NULL;
3614 /* Get System SID */
3615 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3621 SystemSIDlength = GetLengthSid(pSystemSID);
3622 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3623 + SystemSIDlength - sizeof(DWORD);
3626 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3628 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3629 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3631 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3636 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3638 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3643 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3648 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3649 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3650 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3653 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3654 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3655 pTokenUser->User.Sid);
3656 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3657 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3662 gle = GetLastError();
3663 if (gle != ERROR_NO_TOKEN)
3666 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3667 OWNER_SECURITY_INFORMATION,
3668 pTokenUser->User.Sid,
3672 gle = GetLastError();
3673 if (gle != ERROR_NO_TOKEN)
3677 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3678 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3683 gle = GetLastError();
3684 if (gle != ERROR_NO_TOKEN)
3691 LocalFree(pSystemSID);
3693 LocalFree(pTokenUser);
3695 LocalFree(ccacheACL);
3700 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3703 DWORD dwSize = size-1; /* leave room for nul */
3706 if (!hUserToken || !newfilename || size <= 0)
3709 *newfilename = '\0';
3711 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3712 if ( !dwLen || dwLen > dwSize )
3713 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3714 if ( !dwLen || dwLen > dwSize )
3717 newfilename[dwSize] = '\0';
3722 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3724 char filename[MAX_PATH] = "";
3726 char cachename[MAX_PATH + 8] = "FILE:";
3727 krb5_context ctx = NULL;
3728 krb5_error_code code;
3729 krb5_principal princ = NULL;
3730 krb5_ccache cc = NULL;
3731 krb5_ccache ncc = NULL;
3733 if (!pkrb5_init_context || !user || !szLogonId)
3736 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3737 if ( count > sizeof(filename) || count == 0 ) {
3738 GetWindowsDirectory(filename, sizeof(filename));
3741 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3744 strcat(filename, "\\");
3745 strcat(filename, szLogonId);
3747 strcat(cachename, filename);
3749 DeleteFile(filename);
3751 code = pkrb5_init_context(&ctx);
3752 if (code) goto cleanup;
3754 code = pkrb5_parse_name(ctx, user, &princ);
3755 if (code) goto cleanup;
3757 code = KFW_get_ccache(ctx, princ, &cc);
3758 if (code) goto cleanup;
3760 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3761 if (code) goto cleanup;
3763 code = pkrb5_cc_initialize(ctx, ncc, princ);
3764 if (code) goto cleanup;
3766 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3767 if (code) goto cleanup;
3769 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3773 pkrb5_cc_close(ctx, cc);
3777 pkrb5_cc_close(ctx, ncc);
3781 pkrb5_free_principal(ctx, princ);
3786 pkrb5_free_context(ctx);
3790 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3792 char cachename[MAX_PATH + 8] = "FILE:";
3793 krb5_context ctx = NULL;
3794 krb5_error_code code;
3795 krb5_principal princ = NULL;
3796 krb5_ccache cc = NULL;
3797 krb5_ccache ncc = NULL;
3800 if (!pkrb5_init_context || !filename)
3803 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3806 code = pkrb5_init_context(&ctx);
3809 strcat(cachename, filename);
3811 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3812 if (code) goto cleanup;
3814 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3816 code = pkrb5_cc_default(ctx, &ncc);
3818 code = pkrb5_cc_initialize(ctx, ncc, princ);
3821 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3824 pkrb5_cc_close(ctx, ncc);
3828 retval=0; /* success */
3832 pkrb5_cc_close(ctx, cc);
3836 DeleteFile(filename);
3839 pkrb5_free_principal(ctx, princ);
3844 pkrb5_free_context(ctx);
3849 /* We are including this
3851 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3852 fixed part of rande of the one byte lifetime field. Values less than 0x80
3853 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3854 0xBF should be looked up in this table. The value of 0x80 is the same using
3855 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3856 The intervening values of have a fixed ratio of roughly 1.06914. The value
3857 oxFF is defined to mean a ticket has no expiration time. This should be
3858 used advisedly since individual servers may impose defacto upperbounds on
3859 ticket lifetimes. */
3861 #define TKTLIFENUMFIXED 64
3862 #define TKTLIFEMINFIXED 0x80
3863 #define TKTLIFEMAXFIXED 0xBF
3864 #define TKTLIFENOEXPIRE 0xFF
3865 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3867 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3868 38400, /* 10.67 hours, 0.44 days */
3869 41055, /* 11.40 hours, 0.48 days */
3870 43894, /* 12.19 hours, 0.51 days */
3871 46929, /* 13.04 hours, 0.54 days */
3872 50174, /* 13.94 hours, 0.58 days */
3873 53643, /* 14.90 hours, 0.62 days */
3874 57352, /* 15.93 hours, 0.66 days */
3875 61318, /* 17.03 hours, 0.71 days */
3876 65558, /* 18.21 hours, 0.76 days */
3877 70091, /* 19.47 hours, 0.81 days */
3878 74937, /* 20.82 hours, 0.87 days */
3879 80119, /* 22.26 hours, 0.93 days */
3880 85658, /* 23.79 hours, 0.99 days */
3881 91581, /* 25.44 hours, 1.06 days */
3882 97914, /* 27.20 hours, 1.13 days */
3883 104684, /* 29.08 hours, 1.21 days */
3884 111922, /* 31.09 hours, 1.30 days */
3885 119661, /* 33.24 hours, 1.38 days */
3886 127935, /* 35.54 hours, 1.48 days */
3887 136781, /* 37.99 hours, 1.58 days */
3888 146239, /* 40.62 hours, 1.69 days */
3889 156350, /* 43.43 hours, 1.81 days */
3890 167161, /* 46.43 hours, 1.93 days */
3891 178720, /* 49.64 hours, 2.07 days */
3892 191077, /* 53.08 hours, 2.21 days */
3893 204289, /* 56.75 hours, 2.36 days */
3894 218415, /* 60.67 hours, 2.53 days */
3895 233517, /* 64.87 hours, 2.70 days */
3896 249664, /* 69.35 hours, 2.89 days */
3897 266926, /* 74.15 hours, 3.09 days */
3898 285383, /* 79.27 hours, 3.30 days */
3899 305116, /* 84.75 hours, 3.53 days */
3900 326213, /* 90.61 hours, 3.78 days */
3901 348769, /* 96.88 hours, 4.04 days */
3902 372885, /* 103.58 hours, 4.32 days */
3903 398668, /* 110.74 hours, 4.61 days */
3904 426234, /* 118.40 hours, 4.93 days */
3905 455705, /* 126.58 hours, 5.27 days */
3906 487215, /* 135.34 hours, 5.64 days */
3907 520904, /* 144.70 hours, 6.03 days */
3908 556921, /* 154.70 hours, 6.45 days */
3909 595430, /* 165.40 hours, 6.89 days */
3910 636601, /* 176.83 hours, 7.37 days */
3911 680618, /* 189.06 hours, 7.88 days */
3912 727680, /* 202.13 hours, 8.42 days */
3913 777995, /* 216.11 hours, 9.00 days */
3914 831789, /* 231.05 hours, 9.63 days */
3915 889303, /* 247.03 hours, 10.29 days */
3916 950794, /* 264.11 hours, 11.00 days */
3917 1016537, /* 282.37 hours, 11.77 days */
3918 1086825, /* 301.90 hours, 12.58 days */
3919 1161973, /* 322.77 hours, 13.45 days */
3920 1242318, /* 345.09 hours, 14.38 days */
3921 1328218, /* 368.95 hours, 15.37 days */
3922 1420057, /* 394.46 hours, 16.44 days */
3923 1518247, /* 421.74 hours, 17.57 days */
3924 1623226, /* 450.90 hours, 18.79 days */
3925 1735464, /* 482.07 hours, 20.09 days */
3926 1855462, /* 515.41 hours, 21.48 days */
3927 1983758, /* 551.04 hours, 22.96 days */
3928 2120925, /* 589.15 hours, 24.55 days */
3929 2267576, /* 629.88 hours, 26.25 days */
3930 2424367, /* 673.44 hours, 28.06 days */
3932 }; /* 720.00 hours, 30.00 days */
3934 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3935 * returns the corresponding end time. There are four simple cases to be
3936 * handled. The first is a life of 0xff, meaning no expiration, and results in
3937 * an end time of 0xffffffff. The second is when life is less than the values
3938 * covered by the table. In this case, the end time is the start time plus the
3939 * number of 5 minute intervals specified by life. The third case returns
3940 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3941 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3942 * table to extract the lifetime in seconds, which is added to start to produce
3946 life_to_time(afs_uint32 start, unsigned char life)
3950 if (life == TKTLIFENOEXPIRE)
3952 if (life < TKTLIFEMINFIXED)
3953 return start + life * 5 * 60;
3954 if (life > TKTLIFEMAXFIXED)
3955 return start + MAXTKTLIFETIME;
3956 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3957 return start + realLife;
3960 /* time_to_life - takes start and end times for the ticket and returns a
3961 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3962 * lifetimes above 127*5minutes. First, the special case of (end ==
3963 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3964 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3965 * less than the first table entry are handled by rounding the requested
3966 * lifetime *up* to the next 5 minute interval. The final step is to search
3967 * the table for the smallest entry *greater than or equal* to the requested
3968 * entry. The actual code is prepared to handle the case where the table is
3969 * unordered but that it an unnecessary frill. */
3971 static unsigned char
3972 time_to_life(afs_uint32 start, afs_uint32 end)
3974 int lifetime = end - start;
3978 if (end == NEVERDATE)
3979 return TKTLIFENOEXPIRE;
3980 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3982 if (lifetime < tkt_lifetimes[0])
3983 return (lifetime + 5 * 60 - 1) / (5 * 60);
3985 best = MAXKTCTICKETLIFETIME;
3986 for (i = 0; i < TKTLIFENUMFIXED; i++)
3987 if (tkt_lifetimes[i] >= lifetime) {
3988 int diff = tkt_lifetimes[i] - lifetime;
3996 return best_i + TKTLIFEMINFIXED;