2 * Copyright (c) 2004, 2005 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.
61 #include "afskfw-int.h"
65 #include <afs/ptserver.h>
66 #include <afs/ptuser.h>
69 #include <WINNT\afsreg.h>
72 * TIMING _____________________________________________________________________
76 #define cminREMIND_TEST 1 // test every minute for expired creds
77 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
78 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
79 #define cminMINLIFE 30 // minimum life of Kerberos creds
81 #define c100ns1SECOND (LONGLONG)10000000
82 #define cmsec1SECOND 1000
83 #define cmsec1MINUTE 60000
84 #define csec1MINUTE 60
86 /* Function Pointer Declarations for Delayed Loading */
88 DECL_FUNC_PTR(cc_initialize);
89 DECL_FUNC_PTR(cc_shutdown);
90 DECL_FUNC_PTR(cc_get_NC_info);
91 DECL_FUNC_PTR(cc_free_NC_info);
94 DECL_FUNC_PTR(Leash_get_default_lifetime);
95 DECL_FUNC_PTR(Leash_get_default_forwardable);
96 DECL_FUNC_PTR(Leash_get_default_renew_till);
97 DECL_FUNC_PTR(Leash_get_default_noaddresses);
98 DECL_FUNC_PTR(Leash_get_default_proxiable);
99 DECL_FUNC_PTR(Leash_get_default_publicip);
100 DECL_FUNC_PTR(Leash_get_default_use_krb4);
101 DECL_FUNC_PTR(Leash_get_default_life_min);
102 DECL_FUNC_PTR(Leash_get_default_life_max);
103 DECL_FUNC_PTR(Leash_get_default_renew_min);
104 DECL_FUNC_PTR(Leash_get_default_renew_max);
105 DECL_FUNC_PTR(Leash_get_default_renewable);
106 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
109 DECL_FUNC_PTR(krb5_change_password);
110 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
111 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
112 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
113 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
114 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
115 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
116 DECL_FUNC_PTR(krb5_get_init_creds_password);
117 DECL_FUNC_PTR(krb5_build_principal_ext);
118 DECL_FUNC_PTR(krb5_cc_get_name);
119 DECL_FUNC_PTR(krb5_cc_resolve);
120 DECL_FUNC_PTR(krb5_cc_default);
121 DECL_FUNC_PTR(krb5_cc_default_name);
122 DECL_FUNC_PTR(krb5_cc_set_default_name);
123 DECL_FUNC_PTR(krb5_cc_initialize);
124 DECL_FUNC_PTR(krb5_cc_destroy);
125 DECL_FUNC_PTR(krb5_cc_close);
126 DECL_FUNC_PTR(krb5_cc_store_cred);
127 DECL_FUNC_PTR(krb5_cc_copy_creds);
128 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
129 DECL_FUNC_PTR(krb5_cc_get_principal);
130 DECL_FUNC_PTR(krb5_cc_start_seq_get);
131 DECL_FUNC_PTR(krb5_cc_next_cred);
132 DECL_FUNC_PTR(krb5_cc_end_seq_get);
133 DECL_FUNC_PTR(krb5_cc_remove_cred);
134 DECL_FUNC_PTR(krb5_cc_set_flags);
135 DECL_FUNC_PTR(krb5_cc_get_type);
136 DECL_FUNC_PTR(krb5_free_context);
137 DECL_FUNC_PTR(krb5_free_cred_contents);
138 DECL_FUNC_PTR(krb5_free_principal);
139 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
140 DECL_FUNC_PTR(krb5_init_context);
141 DECL_FUNC_PTR(krb5_parse_name);
142 DECL_FUNC_PTR(krb5_timeofday);
143 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
144 DECL_FUNC_PTR(krb5_unparse_name);
145 DECL_FUNC_PTR(krb5_get_credentials);
146 DECL_FUNC_PTR(krb5_mk_req);
147 DECL_FUNC_PTR(krb5_sname_to_principal);
148 DECL_FUNC_PTR(krb5_get_credentials_renew);
149 DECL_FUNC_PTR(krb5_free_data);
150 DECL_FUNC_PTR(krb5_free_data_contents);
151 DECL_FUNC_PTR(krb5_free_unparsed_name);
152 DECL_FUNC_PTR(krb5_os_localaddr);
153 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
154 DECL_FUNC_PTR(krb5_copy_data);
155 DECL_FUNC_PTR(krb5_free_creds);
156 DECL_FUNC_PTR(krb5_build_principal);
157 DECL_FUNC_PTR(krb5_get_renewed_creds);
158 DECL_FUNC_PTR(krb5_get_default_config_files);
159 DECL_FUNC_PTR(krb5_free_config_files);
160 DECL_FUNC_PTR(krb5_get_default_realm);
161 DECL_FUNC_PTR(krb5_free_default_realm);
162 DECL_FUNC_PTR(krb5_free_ticket);
163 DECL_FUNC_PTR(krb5_decode_ticket);
164 DECL_FUNC_PTR(krb5_get_host_realm);
165 DECL_FUNC_PTR(krb5_free_host_realm);
166 DECL_FUNC_PTR(krb5_free_addresses);
167 DECL_FUNC_PTR(krb5_c_random_make_octets);
170 DECL_FUNC_PTR(krb524_init_ets);
171 DECL_FUNC_PTR(krb524_convert_creds_kdc);
174 DECL_FUNC_PTR(krb_get_cred);
175 DECL_FUNC_PTR(tkt_string);
176 DECL_FUNC_PTR(krb_get_tf_realm);
177 DECL_FUNC_PTR(krb_mk_req);
180 DECL_FUNC_PTR(com_err);
181 DECL_FUNC_PTR(error_message);
184 DECL_FUNC_PTR(profile_init);
185 DECL_FUNC_PTR(profile_release);
186 DECL_FUNC_PTR(profile_get_subsection_names);
187 DECL_FUNC_PTR(profile_free_list);
188 DECL_FUNC_PTR(profile_get_string);
189 DECL_FUNC_PTR(profile_release_string);
192 DECL_FUNC_PTR(OpenSCManagerA);
193 DECL_FUNC_PTR(OpenServiceA);
194 DECL_FUNC_PTR(QueryServiceStatus);
195 DECL_FUNC_PTR(CloseServiceHandle);
197 DECL_FUNC_PTR(LsaNtStatusToWinError);
198 #endif /* USE_MS2MIT */
202 DECL_FUNC_PTR(LsaConnectUntrusted);
203 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
204 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
205 DECL_FUNC_PTR(LsaFreeReturnBuffer);
206 DECL_FUNC_PTR(LsaGetLogonSessionData);
207 #endif /* USE_MS2MIT */
210 FUNC_INFO ccapi_fi[] = {
211 MAKE_FUNC_INFO(cc_initialize),
212 MAKE_FUNC_INFO(cc_shutdown),
213 MAKE_FUNC_INFO(cc_get_NC_info),
214 MAKE_FUNC_INFO(cc_free_NC_info),
218 FUNC_INFO leash_fi[] = {
219 MAKE_FUNC_INFO(Leash_get_default_lifetime),
220 MAKE_FUNC_INFO(Leash_get_default_renew_till),
221 MAKE_FUNC_INFO(Leash_get_default_forwardable),
222 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
223 MAKE_FUNC_INFO(Leash_get_default_proxiable),
224 MAKE_FUNC_INFO(Leash_get_default_publicip),
225 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
226 MAKE_FUNC_INFO(Leash_get_default_life_min),
227 MAKE_FUNC_INFO(Leash_get_default_life_max),
228 MAKE_FUNC_INFO(Leash_get_default_renew_min),
229 MAKE_FUNC_INFO(Leash_get_default_renew_max),
230 MAKE_FUNC_INFO(Leash_get_default_renewable),
234 FUNC_INFO leash_opt_fi[] = {
235 MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
239 FUNC_INFO k5_fi[] = {
240 MAKE_FUNC_INFO(krb5_change_password),
241 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
242 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
243 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
244 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
245 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
246 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
247 MAKE_FUNC_INFO(krb5_get_init_creds_password),
248 MAKE_FUNC_INFO(krb5_build_principal_ext),
249 MAKE_FUNC_INFO(krb5_cc_get_name),
250 MAKE_FUNC_INFO(krb5_cc_resolve),
251 MAKE_FUNC_INFO(krb5_cc_default),
252 MAKE_FUNC_INFO(krb5_cc_default_name),
253 MAKE_FUNC_INFO(krb5_cc_set_default_name),
254 MAKE_FUNC_INFO(krb5_cc_initialize),
255 MAKE_FUNC_INFO(krb5_cc_destroy),
256 MAKE_FUNC_INFO(krb5_cc_close),
257 MAKE_FUNC_INFO(krb5_cc_copy_creds),
258 MAKE_FUNC_INFO(krb5_cc_store_cred),
259 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
260 MAKE_FUNC_INFO(krb5_cc_get_principal),
261 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
262 MAKE_FUNC_INFO(krb5_cc_next_cred),
263 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
264 MAKE_FUNC_INFO(krb5_cc_remove_cred),
265 MAKE_FUNC_INFO(krb5_cc_set_flags),
266 MAKE_FUNC_INFO(krb5_cc_get_type),
267 MAKE_FUNC_INFO(krb5_free_context),
268 MAKE_FUNC_INFO(krb5_free_cred_contents),
269 MAKE_FUNC_INFO(krb5_free_principal),
270 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
271 MAKE_FUNC_INFO(krb5_init_context),
272 MAKE_FUNC_INFO(krb5_parse_name),
273 MAKE_FUNC_INFO(krb5_timeofday),
274 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
275 MAKE_FUNC_INFO(krb5_unparse_name),
276 MAKE_FUNC_INFO(krb5_get_credentials),
277 MAKE_FUNC_INFO(krb5_mk_req),
278 MAKE_FUNC_INFO(krb5_sname_to_principal),
279 MAKE_FUNC_INFO(krb5_get_credentials_renew),
280 MAKE_FUNC_INFO(krb5_free_data),
281 MAKE_FUNC_INFO(krb5_free_data_contents),
282 MAKE_FUNC_INFO(krb5_free_unparsed_name),
283 MAKE_FUNC_INFO(krb5_os_localaddr),
284 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
285 MAKE_FUNC_INFO(krb5_copy_data),
286 MAKE_FUNC_INFO(krb5_free_creds),
287 MAKE_FUNC_INFO(krb5_build_principal),
288 MAKE_FUNC_INFO(krb5_get_renewed_creds),
289 MAKE_FUNC_INFO(krb5_free_addresses),
290 MAKE_FUNC_INFO(krb5_get_default_config_files),
291 MAKE_FUNC_INFO(krb5_free_config_files),
292 MAKE_FUNC_INFO(krb5_get_default_realm),
293 MAKE_FUNC_INFO(krb5_free_default_realm),
294 MAKE_FUNC_INFO(krb5_free_ticket),
295 MAKE_FUNC_INFO(krb5_decode_ticket),
296 MAKE_FUNC_INFO(krb5_get_host_realm),
297 MAKE_FUNC_INFO(krb5_free_host_realm),
298 MAKE_FUNC_INFO(krb5_free_addresses),
299 MAKE_FUNC_INFO(krb5_c_random_make_octets),
304 FUNC_INFO k4_fi[] = {
305 MAKE_FUNC_INFO(krb_get_cred),
306 MAKE_FUNC_INFO(krb_get_tf_realm),
307 MAKE_FUNC_INFO(krb_mk_req),
308 MAKE_FUNC_INFO(tkt_string),
313 FUNC_INFO k524_fi[] = {
314 MAKE_FUNC_INFO(krb524_init_ets),
315 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
319 FUNC_INFO profile_fi[] = {
320 MAKE_FUNC_INFO(profile_init),
321 MAKE_FUNC_INFO(profile_release),
322 MAKE_FUNC_INFO(profile_get_subsection_names),
323 MAKE_FUNC_INFO(profile_free_list),
324 MAKE_FUNC_INFO(profile_get_string),
325 MAKE_FUNC_INFO(profile_release_string),
329 FUNC_INFO ce_fi[] = {
330 MAKE_FUNC_INFO(com_err),
331 MAKE_FUNC_INFO(error_message),
335 FUNC_INFO service_fi[] = {
336 MAKE_FUNC_INFO(OpenSCManagerA),
337 MAKE_FUNC_INFO(OpenServiceA),
338 MAKE_FUNC_INFO(QueryServiceStatus),
339 MAKE_FUNC_INFO(CloseServiceHandle),
341 MAKE_FUNC_INFO(LsaNtStatusToWinError),
342 #endif /* USE_MS2MIT */
347 FUNC_INFO lsa_fi[] = {
348 MAKE_FUNC_INFO(LsaConnectUntrusted),
349 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
350 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
351 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
352 MAKE_FUNC_INFO(LsaGetLogonSessionData),
355 #endif /* USE_MS2MIT */
357 /* Static Prototypes */
358 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
359 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
360 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
361 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
362 void *data, const char *name, const char *banner, int num_prompts,
363 krb5_prompt prompts[]);
366 /* Static Declarations */
367 static int inited = 0;
368 static int mid_cnt = 0;
369 static struct textField * mid_tb = NULL;
370 static HINSTANCE hKrb5 = 0;
372 static HINSTANCE hKrb4 = 0;
373 #endif /* USE_KRB4 */
374 static HINSTANCE hKrb524 = 0;
376 static HINSTANCE hSecur32 = 0;
377 #endif /* USE_MS2MIT */
378 static HINSTANCE hAdvApi32 = 0;
379 static HINSTANCE hComErr = 0;
380 static HINSTANCE hService = 0;
381 static HINSTANCE hProfile = 0;
382 static HINSTANCE hLeash = 0;
383 static HINSTANCE hLeashOpt = 0;
384 static HINSTANCE hCCAPI = 0;
385 static struct principal_ccache_data * princ_cc_data = NULL;
386 static struct cell_principal_map * cell_princ_map = NULL;
391 static int inited = 0;
394 char mutexName[MAX_PATH];
395 HANDLE hMutex = NULL;
397 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
399 hMutex = CreateMutex( NULL, TRUE, mutexName );
400 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
401 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
407 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
409 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
410 #endif /* USE_KRB4 */
411 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
412 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
414 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
415 #endif /* USE_MS2MIT */
416 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
417 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
418 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
419 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
420 LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
422 if ( KFW_is_available() ) {
423 char rootcell[MAXCELLCHARS+1];
425 KFW_import_windows_lsa();
426 #endif /* USE_MS2MIT */
427 KFW_import_ccache_data();
428 KFW_AFS_renew_expiring_tokens();
430 /* WIN32 NOTE: no way to get max chars */
431 if (!cm_GetRootCellName(rootcell))
432 KFW_AFS_renew_token_for_cell(rootcell);
435 ReleaseMutex(hMutex);
444 FreeLibrary(hLeashOpt);
450 FreeLibrary(hKrb524);
453 FreeLibrary(hSecur32);
454 #endif /* USE_MS2MIT */
456 FreeLibrary(hService);
458 FreeLibrary(hComErr);
460 FreeLibrary(hProfile);
464 #endif /* USE_KRB4 */
476 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
477 0, KEY_QUERY_VALUE, &parmKey);
478 if (code == ERROR_SUCCESS) {
479 len = sizeof(use524);
480 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
481 (BYTE *) &use524, &len);
482 RegCloseKey(parmKey);
484 if (code != ERROR_SUCCESS) {
485 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
486 0, KEY_QUERY_VALUE, &parmKey);
487 if (code == ERROR_SUCCESS) {
488 len = sizeof(use524);
489 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
490 (BYTE *) &use524, &len);
491 RegCloseKey (parmKey);
498 KFW_is_available(void)
504 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
505 0, KEY_QUERY_VALUE, &parmKey);
506 if (code == ERROR_SUCCESS) {
507 len = sizeof(enableKFW);
508 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
509 (BYTE *) &enableKFW, &len);
510 RegCloseKey (parmKey);
513 if (code != ERROR_SUCCESS) {
514 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
515 0, KEY_QUERY_VALUE, &parmKey);
516 if (code == ERROR_SUCCESS) {
517 len = sizeof(enableKFW);
518 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
519 (BYTE *) &enableKFW, &len);
520 RegCloseKey (parmKey);
528 if ( hKrb5 && hComErr && hService &&
531 #endif /* USE_MS2MIT */
533 hProfile && hLeash && hCCAPI )
539 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
540 int FreeContextFlag, krb5_context * ctx,
545 int krb5Error = ((int)(rc & 255));
557 errText = perror_message(rc);
558 _snprintf(message, sizeof(message),
559 "%s\n(Kerberos error %ld)\n\n%s failed",
564 if ( IsDebuggerPresent() )
565 OutputDebugString(message);
567 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
570 if (FreeContextFlag == 1)
572 if (ctx && *ctx != NULL)
574 if (cache && *cache != NULL) {
575 pkrb5_cc_close(*ctx, *cache);
579 pkrb5_free_context(*ctx);
588 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
590 struct principal_ccache_data * next = princ_cc_data;
591 krb5_principal principal = 0;
593 const char * ccname = NULL;
594 krb5_error_code code = 0;
595 krb5_error_code cc_code = 0;
601 if (ctx == 0 || cc == 0)
604 code = pkrb5_cc_get_principal(ctx, cc, &principal);
607 code = pkrb5_unparse_name(ctx, principal, &pname);
608 if ( code ) goto cleanup;
610 ccname = pkrb5_cc_get_name(ctx, cc);
611 if (!ccname) goto cleanup;
613 // Search the existing list to see if we have a match
615 for ( ; next ; next = next->next ) {
616 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
621 // If not, match add a new node to the beginning of the list and assign init it
623 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
624 next->next = princ_cc_data;
625 princ_cc_data = next;
626 next->principal = _strdup(pname);
627 next->ccache_name = _strdup(ccname);
628 next->from_lsa = lsa;
630 next->expiration_time = 0;
634 flags = 0; // turn off OPENCLOSE mode
635 code = pkrb5_cc_set_flags(ctx, cc, flags);
636 if ( code ) goto cleanup;
638 code = pkrb5_timeofday(ctx, &now);
640 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
642 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
643 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
645 // we found the ticket we are looking for
646 // check validity of timestamp
647 // We add a 5 minutes fudge factor to compensate for potential
648 // clock skew errors between the KDC and client OS
650 valid = ((creds.times.starttime > 0) &&
651 now >= (creds.times.starttime - 300) &&
652 now < (creds.times.endtime + 300) &&
653 !(creds.ticket_flags & TKT_FLG_INVALID));
655 if ( next->from_lsa) {
657 next->expiration_time = creds.times.endtime;
659 } else if ( valid ) {
661 next->expiration_time = creds.times.endtime;
662 next->renew = (creds.times.renew_till > creds.times.endtime) &&
663 (creds.ticket_flags & TKT_FLG_RENEWABLE);
666 next->expiration_time = 0;
670 pkrb5_free_cred_contents(ctx, &creds);
671 cc_code = KRB5_CC_END;
674 pkrb5_free_cred_contents(ctx, &creds);
677 if (cc_code == KRB5_CC_END) {
678 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
679 if (code) goto cleanup;
683 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
684 code = pkrb5_cc_set_flags(ctx, cc, flags);
687 pkrb5_free_unparsed_name(ctx,pname);
689 pkrb5_free_principal(ctx,principal);
693 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
695 struct principal_ccache_data * next = princ_cc_data;
696 char * response = NULL;
698 if ( !principal || !ccache )
702 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
704 // we always want to prefer the MS Kerberos LSA cache or
705 // the cache afscreds created specifically for the principal
706 // if the current entry is either one, drop the previous find
707 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
710 response = _strdup(next->ccache_name);
711 // MS Kerberos LSA is our best option so use it and quit
712 if ( next->from_lsa )
726 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
728 struct principal_ccache_data ** next = &princ_cc_data;
730 if ( !pname && !ccname )
734 if ( !strcmp((*next)->principal,pname) ||
735 !strcmp((*next)->ccache_name,ccname) ) {
737 free((*next)->principal);
738 free((*next)->ccache_name);
740 (*next) = (*next)->next;
747 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
749 struct cell_principal_map * next = cell_princ_map;
751 // Search the existing list to see if we have a match
753 for ( ; next ; next = next->next ) {
754 if ( !strcmp(next->cell, cell) ) {
755 if ( !strcmp(next->principal,pname) ) {
756 next->active = active;
759 // OpenAFS currently has a restriction of one active token per cell
760 // Therefore, whenever we update the table with a new active cell we
761 // must mark all of the other principal to cell entries as inactive.
769 // If not, match add a new node to the beginning of the list and assign init it
771 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
772 next->next = cell_princ_map;
773 cell_princ_map = next;
774 next->principal = _strdup(pname);
775 next->cell = _strdup(cell);
776 next->active = active;
781 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
783 struct cell_principal_map ** next = &cell_princ_map;
785 if ( !pname && !cell )
789 if ( !strcmp((*next)->principal,pname) ||
790 !strcmp((*next)->cell,cell) ) {
792 free((*next)->principal);
795 (*next) = (*next)->next;
801 // Returns (if possible) a principal which has been known in
802 // the past to have been used to obtain tokens for the specified
804 // TODO: Attempt to return one which has not yet expired by checking
805 // the principal/ccache data
807 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
809 struct cell_principal_map * next_map = cell_princ_map;
810 const char * princ = NULL;
817 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
820 next_map = next_map->next;
823 if ( !principals || !count )
826 *principals = (char **) malloc(sizeof(char *) * count);
827 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
829 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
830 (*principals)[i++] = _strdup(next_map->principal);
837 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
840 struct cell_principal_map * next_map = cell_princ_map;
841 const char * princ = NULL;
847 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
850 next_map = next_map->next;
856 *cells = (char **) malloc(sizeof(char *) * count);
857 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
859 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
860 (*cells)[i++] = _strdup(next_map->cell);
866 /* Given a principal return an existing ccache or create one and return */
868 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
873 krb5_error_code code;
875 if (!pkrb5_init_context)
881 code = pkrb5_init_context(&ctx);
882 if (code) goto cleanup;
886 code = pkrb5_unparse_name(ctx, principal, &pname);
887 if (code) goto cleanup;
889 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
890 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
891 ccname = (char *)malloc(strlen(pname) + 5);
892 sprintf(ccname,"API:%s",pname);
894 code = pkrb5_cc_resolve(ctx, ccname, cc);
896 code = pkrb5_cc_default(ctx, cc);
897 if (code) goto cleanup;
904 pkrb5_free_unparsed_name(ctx,pname);
905 if (ctx && (ctx != alt_ctx))
906 pkrb5_free_context(ctx);
911 // Import Microsoft Credentials into a new MIT ccache
913 KFW_import_windows_lsa(void)
915 krb5_context ctx = 0;
917 krb5_principal princ = 0;
919 krb5_data * princ_realm;
920 krb5_error_code code;
921 char cell[128]="", realm[128]="", *def_realm = 0;
925 if (!pkrb5_init_context)
929 if ( !MSLSA_IsKerberosLogon() )
933 code = pkrb5_init_context(&ctx);
934 if (code) goto cleanup;
936 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
937 if (code) goto cleanup;
939 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
941 code = pkrb5_cc_get_principal(ctx, cc, &princ);
942 if ( code ) goto cleanup;
944 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
945 switch ( dwMsLsaImport ) {
946 case 0: /* do not import */
948 case 1: /* always import */
950 case 2: { /* matching realm */
951 char ms_realm[128] = "", *r;
954 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
955 *r = krb5_princ_realm(ctx, princ)->data[i];
959 if (code = pkrb5_get_default_realm(ctx, &def_realm))
962 if (strcmp(def_realm, ms_realm))
970 code = pkrb5_unparse_name(ctx,princ,&pname);
971 if ( code ) goto cleanup;
973 princ_realm = krb5_princ_realm(ctx, princ);
974 for ( i=0; i<princ_realm->length; i++ ) {
975 realm[i] = princ_realm->data[i];
976 cell[i] = tolower(princ_realm->data[i]);
981 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
982 if ( IsDebuggerPresent() ) {
984 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
985 OutputDebugString(message);
987 if ( code ) goto cleanup;
989 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
993 pkrb5_free_unparsed_name(ctx,pname);
995 pkrb5_free_principal(ctx,princ);
997 pkrb5_free_default_realm(ctx, def_realm);
999 pkrb5_cc_close(ctx,cc);
1001 pkrb5_free_context(ctx);
1003 #endif /* USE_MS2MIT */
1005 // If there are existing MIT credentials, copy them to a new
1006 // ccache named after the principal
1008 // Enumerate all existing MIT ccaches and construct entries
1009 // in the principal_ccache table
1011 // Enumerate all existing AFS Tokens and construct entries
1012 // in the cell_principal table
1014 KFW_import_ccache_data(void)
1016 krb5_context ctx = 0;
1018 krb5_principal principal = 0;
1020 krb5_error_code code;
1021 krb5_error_code cc_code;
1024 struct _infoNC ** pNCi = NULL;
1027 if ( !pcc_initialize )
1030 if ( IsDebuggerPresent() )
1031 OutputDebugString("KFW_import_ccache_data()\n");
1033 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1034 if (code) goto cleanup;
1036 code = pcc_get_NC_info(cc_ctx, &pNCi);
1037 if (code) goto cleanup;
1039 code = pkrb5_init_context(&ctx);
1040 if (code) goto cleanup;
1042 for ( i=0; pNCi[i]; i++ ) {
1043 if ( pNCi[i]->vers != CC_CRED_V5 )
1045 if ( IsDebuggerPresent() ) {
1046 OutputDebugString("Principal: ");
1047 OutputDebugString(pNCi[i]->principal);
1048 OutputDebugString(" in ccache ");
1049 OutputDebugString(pNCi[i]->name);
1050 OutputDebugString("\n");
1052 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1053 && strcmp(pNCi[i]->name,LSA_CCNAME)
1056 for ( j=0; pNCi[j]; j++ ) {
1057 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1063 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1064 if (code) goto loop_cleanup;
1067 krb5_ccache oldcc = 0;
1069 if ( IsDebuggerPresent() )
1070 OutputDebugString("copying ccache data to new ccache\n");
1072 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1073 if (code) goto loop_cleanup;
1074 code = pkrb5_cc_initialize(ctx, cc, principal);
1075 if (code) goto loop_cleanup;
1077 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1078 if (code) goto loop_cleanup;
1079 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1081 code = pkrb5_cc_close(ctx,cc);
1083 code = pkrb5_cc_close(ctx,oldcc);
1085 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1088 code = pkrb5_cc_close(ctx,oldcc);
1091 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1092 if (code) goto loop_cleanup;
1095 flags = 0; // turn off OPENCLOSE mode
1096 code = pkrb5_cc_set_flags(ctx, cc, flags);
1097 if ( code ) goto cleanup;
1099 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1101 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1103 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1104 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1105 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1106 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1107 if ( sname && cell && !strcmp("afs",sname->data) ) {
1108 struct ktc_principal aserver;
1109 struct ktc_principal aclient;
1110 struct ktc_token atoken;
1113 if ( IsDebuggerPresent() ) {
1114 OutputDebugString("Found AFS ticket: ");
1115 OutputDebugString(sname->data);
1117 OutputDebugString("/");
1118 OutputDebugString(cell->data);
1120 OutputDebugString("@");
1121 OutputDebugString(realm->data);
1122 OutputDebugString("\n");
1125 memset(&aserver, '\0', sizeof(aserver));
1126 strcpy(aserver.name, sname->data);
1127 strcpy(aserver.cell, cell->data);
1129 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1131 // Found a token in AFS Client Server which matches
1132 char pname[128], *p, *q;
1133 for ( p=pname, q=aclient.name; *q; p++, q++)
1135 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1139 if ( IsDebuggerPresent() ) {
1140 OutputDebugString("Found AFS token: ");
1141 OutputDebugString(pname);
1142 OutputDebugString("\n");
1145 if ( strcmp(pname,pNCi[i]->principal) )
1147 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1149 // Attempt to import it
1150 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1152 if ( IsDebuggerPresent() ) {
1153 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1156 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL);
1157 if ( IsDebuggerPresent() ) {
1159 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1160 OutputDebugString(message);
1163 } else if ( IsDebuggerPresent() ) {
1164 OutputDebugString("Found ticket: ");
1165 OutputDebugString(sname->data);
1166 if ( cell && cell->data ) {
1167 OutputDebugString("/");
1168 OutputDebugString(cell->data);
1170 OutputDebugString("@");
1171 OutputDebugString(realm->data);
1172 OutputDebugString("\n");
1174 pkrb5_free_cred_contents(ctx, &creds);
1177 if (cc_code == KRB5_CC_END) {
1178 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1179 if (cc_code) goto loop_cleanup;
1183 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1184 code = pkrb5_cc_set_flags(ctx, cc, flags);
1186 pkrb5_cc_close(ctx,cc);
1190 pkrb5_free_principal(ctx,principal);
1197 pkrb5_free_context(ctx);
1199 pcc_free_NC_info(cc_ctx, &pNCi);
1201 pcc_shutdown(&cc_ctx);
1206 KFW_AFS_get_cred( char * username,
1213 krb5_context ctx = 0;
1215 char * realm = 0, * userrealm = 0;
1216 krb5_principal principal = 0;
1218 krb5_error_code code;
1219 char local_cell[MAXCELLCHARS+1];
1220 char **cells = NULL;
1222 struct afsconf_cell cellconfig;
1226 if (!pkrb5_init_context)
1229 if ( IsDebuggerPresent() ) {
1230 OutputDebugString("KFW_AFS_get_cred for token ");
1231 OutputDebugString(username);
1232 OutputDebugString(" in cell ");
1233 OutputDebugString(cell);
1234 OutputDebugString("\n");
1237 code = pkrb5_init_context(&ctx);
1238 if ( code ) goto cleanup;
1240 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1241 if ( code ) goto cleanup;
1243 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1245 userrealm = strchr(username,'@');
1247 pname = strdup(username);
1248 userrealm = strchr(pname, '@');
1251 /* handle kerberos iv notation */
1252 while ( dot = strchr(pname,'.') ) {
1257 pname = malloc(strlen(username) + strlen(realm) + 2);
1259 strcpy(pname, username);
1261 /* handle kerberos iv notation */
1262 while ( dot = strchr(pname,'.') ) {
1267 strcat(pname,realm);
1269 if ( IsDebuggerPresent() ) {
1270 OutputDebugString("Realm: ");
1271 OutputDebugString(realm);
1272 OutputDebugString("\n");
1275 code = pkrb5_parse_name(ctx, pname, &principal);
1276 if ( code ) goto cleanup;
1278 code = KFW_get_ccache(ctx, principal, &cc);
1279 if ( code ) goto cleanup;
1281 if ( lifetime == 0 )
1282 lifetime = pLeash_get_default_lifetime();
1284 if ( password && password[0] ) {
1285 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1289 pLeash_get_default_forwardable(),
1290 pLeash_get_default_proxiable(),
1291 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1292 pLeash_get_default_noaddresses(),
1293 pLeash_get_default_publicip());
1294 if ( IsDebuggerPresent() ) {
1296 sprintf(message,"KFW_kinit() returns: %d\n",code);
1297 OutputDebugString(message);
1299 if ( code ) goto cleanup;
1301 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1304 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1305 if ( IsDebuggerPresent() ) {
1307 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1308 OutputDebugString(message);
1310 if ( code ) goto cleanup;
1312 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1314 // Attempt to obtain new tokens for other cells supported by the same
1316 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1317 if ( cell_count > 1 ) {
1318 while ( cell_count-- ) {
1319 if ( strcmp(cells[cell_count],cell) ) {
1320 if ( IsDebuggerPresent() ) {
1322 sprintf(message,"found another cell for the same principal: %s\n",cell);
1323 OutputDebugString(message);
1325 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1326 if ( code ) continue;
1328 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1329 if ( IsDebuggerPresent() ) {
1330 OutputDebugString("Realm: ");
1331 OutputDebugString(realm);
1332 OutputDebugString("\n");
1335 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1336 if ( IsDebuggerPresent() ) {
1338 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1339 OutputDebugString(message);
1342 free(cells[cell_count]);
1345 } else if ( cell_count == 1 ) {
1354 pkrb5_cc_close(ctx, cc);
1356 if ( code && reasonP ) {
1357 *reasonP = (char *)perror_message(code);
1363 KFW_AFS_destroy_tickets_for_cell(char * cell)
1365 krb5_context ctx = 0;
1366 krb5_error_code code;
1368 char ** principals = NULL;
1370 if (!pkrb5_init_context)
1373 if ( IsDebuggerPresent() ) {
1374 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1375 OutputDebugString(cell);
1376 OutputDebugString("\n");
1379 code = pkrb5_init_context(&ctx);
1382 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1384 krb5_principal princ = 0;
1388 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1389 if ( cell_count > 1 ) {
1390 // TODO - What we really should do here is verify whether or not any of the
1391 // other cells which use this principal to obtain its credentials actually
1392 // have valid tokens or not. If they are currently using these credentials
1393 // we will skip them. For the time being we assume that if there is an active
1394 // map in the table that they are actively being used.
1398 code = pkrb5_parse_name(ctx, principals[count], &princ);
1399 if (code) goto loop_cleanup;
1401 code = KFW_get_ccache(ctx, princ, &cc);
1402 if (code) goto loop_cleanup;
1404 code = pkrb5_cc_destroy(ctx, cc);
1409 pkrb5_cc_close(ctx, cc);
1413 pkrb5_free_principal(ctx, princ);
1417 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1418 free(principals[count]);
1422 pkrb5_free_context(ctx);
1427 KFW_AFS_destroy_tickets_for_principal(char * user)
1429 krb5_context ctx = 0;
1430 krb5_error_code code;
1432 char ** cells = NULL;
1433 krb5_principal princ = 0;
1436 if (!pkrb5_init_context)
1439 if ( IsDebuggerPresent() ) {
1440 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1441 OutputDebugString(user);
1442 OutputDebugString("\n");
1445 code = pkrb5_init_context(&ctx);
1448 code = pkrb5_parse_name(ctx, user, &princ);
1449 if (code) goto loop_cleanup;
1451 code = KFW_get_ccache(ctx, princ, &cc);
1452 if (code) goto loop_cleanup;
1454 code = pkrb5_cc_destroy(ctx, cc);
1459 pkrb5_cc_close(ctx, cc);
1463 pkrb5_free_principal(ctx, princ);
1467 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1470 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1476 pkrb5_free_context(ctx);
1481 KFW_AFS_renew_expiring_tokens(void)
1483 krb5_error_code code = 0;
1484 krb5_context ctx = 0;
1487 struct principal_ccache_data * pcc_next = princ_cc_data;
1490 const char * realm = NULL;
1491 char local_cell[MAXCELLCHARS+1]="";
1492 struct afsconf_cell cellconfig;
1494 if (!pkrb5_init_context)
1497 if ( pcc_next == NULL ) // nothing to do
1500 if ( IsDebuggerPresent() ) {
1501 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1504 code = pkrb5_init_context(&ctx);
1505 if (code) goto cleanup;
1507 code = pkrb5_timeofday(ctx, &now);
1508 if (code) goto cleanup;
1510 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1511 if ( pcc_next->expired )
1514 if ( now >= (pcc_next->expiration_time) ) {
1515 if ( !pcc_next->from_lsa ) {
1516 pcc_next->expired = 1;
1521 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1522 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1525 code = KFW_renew(ctx,cc);
1527 if ( code && pcc_next->from_lsa)
1529 #endif /* USE_MS2MIT */
1532 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1533 if (code) goto loop_cleanup;
1535 // Attempt to obtain new tokens for other cells supported by the same
1537 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1538 if ( cell_count > 0 ) {
1539 while ( cell_count-- ) {
1540 if ( IsDebuggerPresent() ) {
1541 OutputDebugString("Cell: ");
1542 OutputDebugString(cells[cell_count]);
1543 OutputDebugString("\n");
1545 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1546 if ( code ) continue;
1547 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1548 if ( IsDebuggerPresent() ) {
1549 OutputDebugString("Realm: ");
1550 OutputDebugString(realm);
1551 OutputDebugString("\n");
1553 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1554 if ( IsDebuggerPresent() ) {
1556 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1557 OutputDebugString(message);
1559 free(cells[cell_count]);
1567 pkrb5_cc_close(ctx,cc);
1574 pkrb5_cc_close(ctx,cc);
1576 pkrb5_free_context(ctx);
1583 KFW_AFS_renew_token_for_cell(char * cell)
1585 krb5_error_code code = 0;
1586 krb5_context ctx = 0;
1588 char ** principals = NULL;
1590 if (!pkrb5_init_context)
1593 if ( IsDebuggerPresent() ) {
1594 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1595 OutputDebugString(cell);
1596 OutputDebugString("\n");
1599 code = pkrb5_init_context(&ctx);
1600 if (code) goto cleanup;
1602 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1604 // We know we must have a credential somewhere since we are
1605 // trying to renew a token
1607 KFW_import_ccache_data();
1608 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1611 krb5_principal princ = 0;
1612 krb5_principal service = 0;
1614 krb5_creds mcreds, creds;
1615 #endif /* COMMENT */
1617 const char * realm = NULL;
1618 struct afsconf_cell cellconfig;
1619 char local_cell[MAXCELLCHARS+1];
1622 code = pkrb5_parse_name(ctx, principals[count], &princ);
1623 if (code) goto loop_cleanup;
1625 code = KFW_get_ccache(ctx, princ, &cc);
1626 if (code) goto loop_cleanup;
1628 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1629 if ( code ) goto loop_cleanup;
1631 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1632 if ( IsDebuggerPresent() ) {
1633 OutputDebugString("Realm: ");
1634 OutputDebugString(realm);
1635 OutputDebugString("\n");
1639 /* krb5_cc_remove_cred() is not implemented
1642 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1643 realm, "afs", cell, NULL);
1645 memset(&mcreds, 0, sizeof(krb5_creds));
1646 mcreds.client = princ;
1647 mcreds.server = service;
1649 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1651 if ( IsDebuggerPresent() ) {
1652 char * cname, *sname;
1653 pkrb5_unparse_name(ctx, creds.client, &cname);
1654 pkrb5_unparse_name(ctx, creds.server, &sname);
1655 OutputDebugString("Removing credential for client \"");
1656 OutputDebugString(cname);
1657 OutputDebugString("\" and service \"");
1658 OutputDebugString(sname);
1659 OutputDebugString("\"\n");
1660 pkrb5_free_unparsed_name(ctx,cname);
1661 pkrb5_free_unparsed_name(ctx,sname);
1664 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1665 pkrb5_free_principal(ctx, creds.client);
1666 pkrb5_free_principal(ctx, creds.server);
1669 #endif /* COMMENT */
1671 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1672 if ( IsDebuggerPresent() ) {
1674 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1675 OutputDebugString(message);
1680 pkrb5_cc_close(ctx, cc);
1684 pkrb5_free_principal(ctx, princ);
1688 pkrb5_free_principal(ctx, service);
1692 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1693 free(principals[count]);
1697 code = -1; // we did not renew the tokens
1700 pkrb5_free_context(ctx);
1701 return (code ? FALSE : TRUE);
1706 KFW_AFS_renew_tokens_for_all_cells(void)
1708 struct cell_principal_map * next = cell_princ_map;
1710 if ( IsDebuggerPresent() )
1711 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1716 for ( ; next ; next = next->next ) {
1718 KFW_AFS_renew_token_for_cell(next->cell);
1724 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1726 krb5_error_code code = 0;
1727 krb5_context ctx = 0;
1729 krb5_principal me = 0;
1730 krb5_principal server = 0;
1731 krb5_creds my_creds;
1732 krb5_data *realm = 0;
1734 if (!pkrb5_init_context)
1737 memset(&my_creds, 0, sizeof(krb5_creds));
1742 code = pkrb5_init_context(&ctx);
1743 if (code) goto cleanup;
1749 code = pkrb5_cc_default(ctx, &cc);
1750 if (code) goto cleanup;
1753 code = pkrb5_cc_get_principal(ctx, cc, &me);
1754 if (code) goto cleanup;
1756 realm = krb5_princ_realm(ctx, me);
1758 code = pkrb5_build_principal_ext(ctx, &server,
1759 realm->length,realm->data,
1760 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1761 realm->length,realm->data,
1766 if ( IsDebuggerPresent() ) {
1767 char * cname, *sname;
1768 pkrb5_unparse_name(ctx, me, &cname);
1769 pkrb5_unparse_name(ctx, server, &sname);
1770 OutputDebugString("Renewing credential for client \"");
1771 OutputDebugString(cname);
1772 OutputDebugString("\" and service \"");
1773 OutputDebugString(sname);
1774 OutputDebugString("\"\n");
1775 pkrb5_free_unparsed_name(ctx,cname);
1776 pkrb5_free_unparsed_name(ctx,sname);
1779 my_creds.client = me;
1780 my_creds.server = server;
1782 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1784 if ( IsDebuggerPresent() ) {
1786 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1787 OutputDebugString(message);
1792 code = pkrb5_cc_initialize(ctx, cc, me);
1794 if ( IsDebuggerPresent() ) {
1796 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1797 OutputDebugString(message);
1802 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1804 if ( IsDebuggerPresent() ) {
1806 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1807 OutputDebugString(message);
1813 if (my_creds.client == me)
1814 my_creds.client = 0;
1815 if (my_creds.server == server)
1816 my_creds.server = 0;
1817 pkrb5_free_cred_contents(ctx, &my_creds);
1819 pkrb5_free_principal(ctx, me);
1821 pkrb5_free_principal(ctx, server);
1822 if (cc && (cc != alt_cc))
1823 pkrb5_cc_close(ctx, cc);
1824 if (ctx && (ctx != alt_ctx))
1825 pkrb5_free_context(ctx);
1830 KFW_kinit( krb5_context alt_ctx,
1833 char *principal_name,
1835 krb5_deltat lifetime,
1838 krb5_deltat renew_life,
1843 krb5_error_code code = 0;
1844 krb5_context ctx = 0;
1846 krb5_principal me = 0;
1848 krb5_creds my_creds;
1849 krb5_get_init_creds_opt options;
1850 krb5_address ** addrs = NULL;
1851 int i = 0, addr_count = 0;
1853 if (!pkrb5_init_context)
1856 pkrb5_get_init_creds_opt_init(&options);
1857 memset(&my_creds, 0, sizeof(my_creds));
1865 code = pkrb5_init_context(&ctx);
1866 if (code) goto cleanup;
1872 code = pkrb5_cc_default(ctx, &cc);
1873 if (code) goto cleanup;
1876 code = pkrb5_parse_name(ctx, principal_name, &me);
1880 code = pkrb5_unparse_name(ctx, me, &name);
1885 lifetime = pLeash_get_default_lifetime();
1892 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1893 pkrb5_get_init_creds_opt_set_forwardable(&options,
1894 forwardable ? 1 : 0);
1895 pkrb5_get_init_creds_opt_set_proxiable(&options,
1897 pkrb5_get_init_creds_opt_set_renew_life(&options,
1900 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1904 // we are going to add the public IP address specified by the user
1905 // to the list provided by the operating system
1906 krb5_address ** local_addrs=NULL;
1909 pkrb5_os_localaddr(ctx, &local_addrs);
1910 while ( local_addrs[i++] );
1913 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1915 pkrb5_free_addresses(ctx, local_addrs);
1918 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1920 while ( local_addrs[i] ) {
1921 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1922 if (addrs[i] == NULL) {
1923 pkrb5_free_addresses(ctx, local_addrs);
1927 addrs[i]->magic = local_addrs[i]->magic;
1928 addrs[i]->addrtype = local_addrs[i]->addrtype;
1929 addrs[i]->length = local_addrs[i]->length;
1930 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1931 if (!addrs[i]->contents) {
1932 pkrb5_free_addresses(ctx, local_addrs);
1936 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1937 local_addrs[i]->length); /* safe */
1940 pkrb5_free_addresses(ctx, local_addrs);
1942 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1943 if (addrs[i] == NULL)
1946 addrs[i]->magic = KV5M_ADDRESS;
1947 addrs[i]->addrtype = AF_INET;
1948 addrs[i]->length = 4;
1949 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1950 if (!addrs[i]->contents)
1953 netIPAddr = htonl(publicIP);
1954 memcpy(addrs[i]->contents,&netIPAddr,4);
1956 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1961 code = pkrb5_get_init_creds_password(ctx,
1964 password, // password
1965 KRB5_prompter, // prompter
1966 hParent, // prompter data
1973 code = pkrb5_cc_initialize(ctx, cc, me);
1977 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1983 for ( i=0;i<addr_count;i++ ) {
1985 if ( addrs[i]->contents )
1986 free(addrs[i]->contents);
1991 if (my_creds.client == me)
1992 my_creds.client = 0;
1993 pkrb5_free_cred_contents(ctx, &my_creds);
1995 pkrb5_free_unparsed_name(ctx, name);
1997 pkrb5_free_principal(ctx, me);
1998 if (cc && (cc != alt_cc))
1999 pkrb5_cc_close(ctx, cc);
2000 if (ctx && (ctx != alt_ctx))
2001 pkrb5_free_context(ctx);
2007 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2011 krb5_error_code code;
2013 if (!pkrb5_init_context)
2022 code = pkrb5_init_context(&ctx);
2023 if (code) goto cleanup;
2029 code = pkrb5_cc_default(ctx, &cc);
2030 if (code) goto cleanup;
2033 code = pkrb5_cc_destroy(ctx, cc);
2034 if ( !code ) cc = 0;
2037 if (cc && (cc != alt_cc))
2038 pkrb5_cc_close(ctx, cc);
2039 if (ctx && (ctx != alt_ctx))
2040 pkrb5_free_context(ctx);
2048 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2050 NTSTATUS Status = 0;
2052 TOKEN_STATISTICS Stats;
2058 *ppSessionData = NULL;
2060 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2064 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2065 CloseHandle( TokenHandle );
2069 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2070 if ( FAILED(Status) || !ppSessionData )
2077 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2078 // cache. It validates whether or not it is reasonable to assume that if we
2079 // attempted to retrieve valid tickets we could do so. Microsoft does not
2080 // automatically renew expired tickets. Therefore, the cache could contain
2081 // expired or invalid tickets. Microsoft also caches the user's password
2082 // and will use it to retrieve new TGTs if the cache is empty and tickets
2086 MSLSA_IsKerberosLogon(VOID)
2088 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2089 BOOL Success = FALSE;
2091 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2092 if ( pSessionData->AuthenticationPackage.Buffer ) {
2098 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2099 usLength = (pSessionData->AuthenticationPackage).Length;
2102 lstrcpynW (buffer, usBuffer, usLength);
2103 lstrcatW (buffer,L"");
2104 if ( !lstrcmpW(L"Kerberos",buffer) )
2108 pLsaFreeReturnBuffer(pSessionData);
2112 #endif /* USE_MS2MIT */
2114 static BOOL CALLBACK
2115 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2119 switch ( message ) {
2121 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2123 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2126 for ( i=0; i < mid_cnt ; i++ ) {
2127 if (mid_tb[i].echo == 0)
2128 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2129 else if (mid_tb[i].echo == 2)
2130 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2135 switch ( LOWORD(wParam) ) {
2137 for ( i=0; i < mid_cnt ; i++ ) {
2138 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2139 *mid_tb[i].buf = '\0';
2143 EndDialog(hDialog, LOWORD(wParam));
2151 lpwAlign( LPWORD lpIn )
2155 ul = (ULONG_PTR) lpIn;
2159 return (LPWORD) ul;;
2163 * dialog widths are measured in 1/4 character widths
2164 * dialog height are measured in 1/8 character heights
2168 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2169 char * ptext[], int numlines, int width,
2170 int tb_cnt, struct textField * tb)
2174 LPDLGITEMTEMPLATE lpdit;
2180 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2187 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2189 // Define a dialog box.
2191 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2192 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2193 | DS_SETFOREGROUND | DS_3DLOOK
2194 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2195 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2198 lpdt->cx = 20 + width * 4;
2199 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2201 lpw = (LPWORD) (lpdt + 1);
2202 *lpw++ = 0; // no menu
2203 *lpw++ = 0; // predefined dialog box class (by default)
2205 lpwsz = (LPWSTR) lpw;
2206 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2208 *lpw++ = 8; // font size (points)
2209 lpwsz = (LPWSTR) lpw;
2210 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2214 //-----------------------
2215 // Define an OK button.
2216 //-----------------------
2217 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2218 lpdit = (LPDLGITEMTEMPLATE) lpw;
2219 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2220 lpdit->dwExtendedStyle = 0;
2221 lpdit->x = (lpdt->cx - 14)/4 - 20;
2222 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2225 lpdit->id = IDOK; // OK button identifier
2227 lpw = (LPWORD) (lpdit + 1);
2229 *lpw++ = 0x0080; // button class
2231 lpwsz = (LPWSTR) lpw;
2232 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2234 *lpw++ = 0; // no creation data
2236 //-----------------------
2237 // Define an Cancel button.
2238 //-----------------------
2239 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2240 lpdit = (LPDLGITEMTEMPLATE) lpw;
2241 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2242 lpdit->dwExtendedStyle = 0;
2243 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2244 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2247 lpdit->id = IDCANCEL; // CANCEL button identifier
2249 lpw = (LPWORD) (lpdit + 1);
2251 *lpw++ = 0x0080; // button class
2253 lpwsz = (LPWSTR) lpw;
2254 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2256 *lpw++ = 0; // no creation data
2258 /* Add controls for preface data */
2259 for ( i=0; i<numlines; i++) {
2260 /*-----------------------
2261 * Define a static text control.
2262 *-----------------------*/
2263 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2264 lpdit = (LPDLGITEMTEMPLATE) lpw;
2265 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2266 lpdit->dwExtendedStyle = 0;
2268 lpdit->y = 10 + i * 14;
2269 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2271 lpdit->id = ID_TEXT + i; // text identifier
2273 lpw = (LPWORD) (lpdit + 1);
2275 *lpw++ = 0x0082; // static class
2277 lpwsz = (LPWSTR) lpw;
2278 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2279 -1, lpwsz, 2*width);
2281 *lpw++ = 0; // no creation data
2284 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2285 int len = (int)strlen(tb[i].label);
2290 for ( i=0; i<tb_cnt; i++) {
2292 /*-----------------------
2293 * Define a static text control.
2294 *-----------------------*/
2295 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2296 lpdit = (LPDLGITEMTEMPLATE) lpw;
2297 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2298 lpdit->dwExtendedStyle = 0;
2300 lpdit->y = 10 + (numlines + i + 1) * 14;
2301 lpdit->cx = pwid * 4;
2303 lpdit->id = ID_TEXT + numlines + i; // text identifier
2305 lpw = (LPWORD) (lpdit + 1);
2307 *lpw++ = 0x0082; // static class
2309 lpwsz = (LPWSTR) lpw;
2310 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2313 *lpw++ = 0; // no creation data
2315 /*-----------------------
2316 * Define an edit control.
2317 *-----------------------*/
2318 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2319 lpdit = (LPDLGITEMTEMPLATE) lpw;
2320 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2321 lpdit->dwExtendedStyle = 0;
2322 lpdit->x = 10 + (pwid + 1) * 4;
2323 lpdit->y = 10 + (numlines + i + 1) * 14;
2324 lpdit->cx = (width - (pwid + 1)) * 4;
2326 lpdit->id = ID_MID_TEXT + i; // identifier
2328 lpw = (LPWORD) (lpdit + 1);
2330 *lpw++ = 0x0081; // edit class
2332 lpwsz = (LPWSTR) lpw;
2333 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2336 *lpw++ = 0; // no creation data
2340 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2341 hwndOwner, (DLGPROC) MultiInputDialogProc);
2345 case 0: /* Timeout */
2353 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2354 MessageBox(hwndOwner,
2357 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2364 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2366 HINSTANCE hInst = 0;
2370 char * plines[16], *p = preface ? preface : "";
2373 for ( i=0; i<16; i++ )
2376 while (*p && numlines < 16) {
2377 plines[numlines++] = p;
2378 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2379 if ( *p == '\r' && *(p+1) == '\n' ) {
2382 } else if ( *p == '\n' ) {
2385 if ( strlen(plines[numlines-1]) > maxwidth )
2386 maxwidth = (int)strlen(plines[numlines-1]);
2389 for ( i=0;i<n;i++ ) {
2390 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2391 if ( maxwidth < len )
2395 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2398 static krb5_error_code KRB5_CALLCONV
2399 KRB5_prompter( krb5_context context,
2404 krb5_prompt prompts[])
2406 krb5_error_code errcode = 0;
2408 struct textField * tb = NULL;
2409 int len = 0, blen=0, nlen=0;
2410 HWND hParent = (HWND)data;
2413 nlen = (int)strlen(name)+2;
2416 blen = (int)strlen(banner)+2;
2418 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2421 memset(tb,0,sizeof(struct textField) * num_prompts);
2422 for ( i=0; i < num_prompts; i++ ) {
2423 tb[i].buf = prompts[i].reply->data;
2424 tb[i].len = prompts[i].reply->length;
2425 tb[i].label = prompts[i].prompt;
2427 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2430 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2432 for ( i=0; i < num_prompts; i++ )
2433 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2441 for (i = 0; i < num_prompts; i++) {
2442 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2449 KFW_AFS_wait_for_service_start(void)
2454 CurrentState = SERVICE_START_PENDING;
2455 memset(HostName, '\0', sizeof(HostName));
2456 gethostname(HostName, sizeof(HostName));
2458 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2460 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2462 if ( IsDebuggerPresent() ) {
2463 switch ( CurrentState ) {
2464 case SERVICE_STOPPED:
2465 OutputDebugString("SERVICE_STOPPED\n");
2467 case SERVICE_START_PENDING:
2468 OutputDebugString("SERVICE_START_PENDING\n");
2470 case SERVICE_STOP_PENDING:
2471 OutputDebugString("SERVICE_STOP_PENDING\n");
2473 case SERVICE_RUNNING:
2474 OutputDebugString("SERVICE_RUNNING\n");
2476 case SERVICE_CONTINUE_PENDING:
2477 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2479 case SERVICE_PAUSE_PENDING:
2480 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2482 case SERVICE_PAUSED:
2483 OutputDebugString("SERVICE_PAUSED\n");
2486 OutputDebugString("UNKNOWN Service State\n");
2489 if (CurrentState == SERVICE_STOPPED)
2491 if (CurrentState == SERVICE_RUNNING)
2507 memset(HostName, '\0', sizeof(HostName));
2508 gethostname(HostName, sizeof(HostName));
2509 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2511 if (CurrentState != SERVICE_RUNNING)
2514 rc = ktc_ForgetAllTokens();
2520 #define ALLOW_REGISTER 1
2522 ViceIDToUsername(char *username,
2523 char *realm_of_user,
2524 char *realm_of_cell,
2526 struct ktc_principal *aclient,
2527 struct ktc_principal *aserver,
2528 struct ktc_token *atoken)
2530 static char lastcell[MAXCELLCHARS+1] = { 0 };
2531 static char confname[512] = { 0 };
2532 #ifdef AFS_ID_TO_NAME
2533 char username_copy[BUFSIZ];
2534 #endif /* AFS_ID_TO_NAME */
2535 long viceId = ANONYMOUSID; /* AFS uid of user */
2537 #ifdef ALLOW_REGISTER
2539 #endif /* ALLOW_REGISTER */
2541 if (confname[0] == '\0') {
2542 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2543 confname[sizeof(confname) - 2] = '\0';
2546 strcpy(lastcell, aserver->cell);
2548 if (!pr_Initialize (0, confname, aserver->cell)) {
2549 char sname[PR_MAXNAMELEN];
2550 strncpy(sname, username, PR_MAXNAMELEN);
2551 sname[PR_MAXNAMELEN-1] = '\0';
2552 status = pr_SNameToId (sname, &viceId);
2557 * This is a crock, but it is Transarc's crock, so
2558 * we have to play along in order to get the
2559 * functionality. The way the afs id is stored is
2560 * as a string in the username field of the token.
2561 * Contrary to what you may think by looking at
2562 * the code for tokens, this hack (AFS ID %d) will
2563 * not work if you change %d to something else.
2567 * This code is taken from cklog -- it lets people
2568 * automatically register with the ptserver in foreign cells
2571 #ifdef ALLOW_REGISTER
2573 if (viceId != ANONYMOUSID) {
2574 #else /* ALLOW_REGISTER */
2575 if ((status == 0) && (viceId != ANONYMOUSID))
2576 #endif /* ALLOW_REGISTER */
2578 #ifdef AFS_ID_TO_NAME
2579 strncpy(username_copy, username, BUFSIZ);
2580 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2581 #endif /* AFS_ID_TO_NAME */
2583 #ifdef ALLOW_REGISTER
2584 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2586 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2587 strcpy(aclient->instance, "");
2588 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2589 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2591 if (status = pr_Initialize(1L, confname, aserver->cell))
2593 status = pr_CreateUser(username, &id);
2597 #ifdef AFS_ID_TO_NAME
2598 strncpy(username_copy, username, BUFSIZ);
2599 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2600 #endif /* AFS_ID_TO_NAME */
2603 #endif /* ALLOW_REGISTER */
2610 krb5_context alt_ctx,
2615 int lifetime, /* unused parameter */
2623 #endif /* USE_KRB4 */
2624 struct ktc_principal aserver;
2625 struct ktc_principal aclient;
2626 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2627 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2628 char local_cell[MAXCELLCHARS+1];
2629 char Dmycell[MAXCELLCHARS+1];
2630 struct ktc_token atoken;
2631 struct ktc_token btoken;
2632 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2633 char RealmName[128];
2635 char ServiceName[128];
2639 krb5_context ctx = 0;
2642 krb5_creds * k5creds = 0;
2643 krb5_error_code code;
2644 krb5_principal client_principal = 0;
2649 memset(HostName, '\0', sizeof(HostName));
2650 gethostname(HostName, sizeof(HostName));
2651 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2652 if ( IsDebuggerPresent() )
2653 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2656 if (CurrentState != SERVICE_RUNNING) {
2657 if ( IsDebuggerPresent() )
2658 OutputDebugString("AFSD Service NOT RUNNING\n");
2662 if (!pkrb5_init_context)
2665 memset(RealmName, '\0', sizeof(RealmName));
2666 memset(CellName, '\0', sizeof(CellName));
2667 memset(ServiceName, '\0', sizeof(ServiceName));
2668 memset(realm_of_user, '\0', sizeof(realm_of_user));
2669 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2670 if (cell && cell[0])
2671 strcpy(Dmycell, cell);
2673 memset(Dmycell, '\0', sizeof(Dmycell));
2675 // NULL or empty cell returns information on local cell
2676 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2678 // KFW_AFS_error(rc, "get_cellconfig()");
2685 code = pkrb5_init_context(&ctx);
2686 if (code) goto cleanup;
2692 code = pkrb5_cc_default(ctx, &cc);
2693 if (code) goto skip_krb5_init;
2696 memset((char *)&increds, 0, sizeof(increds));
2698 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2700 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2702 OutputDebugString("Principal Not Found for ccache\n");
2704 goto skip_krb5_init;
2707 /* look for client principals which cannot be distinguished
2708 * from Kerberos 4 multi-component principal names
2710 k5data = krb5_princ_component(ctx,client_principal,0);
2711 for ( i=0; i<k5data->length; i++ ) {
2712 if ( k5data->data[i] == '.' )
2715 if (i != k5data->length)
2717 OutputDebugString("Illegal Principal name contains dot in first component\n");
2718 rc = KRB5KRB_ERR_GENERIC;
2722 i = krb5_princ_realm(ctx, client_principal)->length;
2725 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2726 realm_of_user[i] = 0;
2731 if ( !try_krb5 || !realm_of_user[0] ) {
2732 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2741 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2743 if (strlen(service) == 0)
2744 strcpy(ServiceName, "afs");
2746 strcpy(ServiceName, service);
2748 if (strlen(cell) == 0)
2749 strcpy(CellName, local_cell);
2751 strcpy(CellName, cell);
2753 if (strlen(realm) == 0)
2754 strcpy(RealmName, realm_of_cell);
2756 strcpy(RealmName, realm);
2758 memset(&creds, '\0', sizeof(creds));
2763 /* First try service/cell@REALM */
2764 if (code = pkrb5_build_principal(ctx, &increds.server,
2765 (int)strlen(RealmName),
2774 increds.client = client_principal;
2775 increds.times.endtime = 0;
2776 /* Ask for DES since that is what V4 understands */
2777 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2780 if ( IsDebuggerPresent() ) {
2781 char * cname, *sname;
2782 pkrb5_unparse_name(ctx, increds.client, &cname);
2783 pkrb5_unparse_name(ctx, increds.server, &sname);
2784 OutputDebugString("Getting tickets for \"");
2785 OutputDebugString(cname);
2786 OutputDebugString("\" and service \"");
2787 OutputDebugString(sname);
2788 OutputDebugString("\"\n");
2789 pkrb5_free_unparsed_name(ctx,cname);
2790 pkrb5_free_unparsed_name(ctx,sname);
2793 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2794 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2795 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2796 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2797 /* Or service@REALM */
2798 pkrb5_free_principal(ctx,increds.server);
2800 code = pkrb5_build_principal(ctx, &increds.server,
2801 (int)strlen(RealmName),
2806 if ( IsDebuggerPresent() ) {
2807 char * cname, *sname;
2808 pkrb5_unparse_name(ctx, increds.client, &cname);
2809 pkrb5_unparse_name(ctx, increds.server, &sname);
2810 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2811 OutputDebugString("Trying again: getting tickets for \"");
2812 OutputDebugString(cname);
2813 OutputDebugString("\" and service \"");
2814 OutputDebugString(sname);
2815 OutputDebugString("\"\n");
2816 pkrb5_free_unparsed_name(ctx,cname);
2817 pkrb5_free_unparsed_name(ctx,sname);
2821 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2824 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2825 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2826 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2827 strcmp(RealmName, realm_of_cell)) {
2828 /* Or service/cell@REALM_OF_CELL */
2829 strcpy(RealmName, realm_of_cell);
2830 pkrb5_free_principal(ctx,increds.server);
2832 code = pkrb5_build_principal(ctx, &increds.server,
2833 (int)strlen(RealmName),
2839 if ( IsDebuggerPresent() ) {
2840 char * cname, *sname;
2841 pkrb5_unparse_name(ctx, increds.client, &cname);
2842 pkrb5_unparse_name(ctx, increds.server, &sname);
2843 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2844 OutputDebugString("Trying again: getting tickets for \"");
2845 OutputDebugString(cname);
2846 OutputDebugString("\" and service \"");
2847 OutputDebugString(sname);
2848 OutputDebugString("\"\n");
2849 pkrb5_free_unparsed_name(ctx,cname);
2850 pkrb5_free_unparsed_name(ctx,sname);
2854 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2857 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2858 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2859 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2860 /* Or service@REALM_OF_CELL */
2861 pkrb5_free_principal(ctx,increds.server);
2863 code = pkrb5_build_principal(ctx, &increds.server,
2864 (int)strlen(RealmName),
2869 if ( IsDebuggerPresent() ) {
2870 char * cname, *sname;
2871 pkrb5_unparse_name(ctx, increds.client, &cname);
2872 pkrb5_unparse_name(ctx, increds.server, &sname);
2873 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2874 OutputDebugString("Trying again: getting tickets for \"");
2875 OutputDebugString(cname);
2876 OutputDebugString("\" and service \"");
2877 OutputDebugString(sname);
2878 OutputDebugString("\"\n");
2879 pkrb5_free_unparsed_name(ctx,cname);
2880 pkrb5_free_unparsed_name(ctx,sname);
2884 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2889 if ( IsDebuggerPresent() ) {
2891 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2892 OutputDebugString(message);
2898 /* This code inserts the entire K5 ticket into the token
2899 * No need to perform a krb524 translation which is
2900 * commented out in the code below
2902 if (KFW_use_krb524() ||
2903 k5creds->ticket.length > MAXKTCTICKETLEN)
2906 memset(&aserver, '\0', sizeof(aserver));
2907 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2908 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2910 memset(&atoken, '\0', sizeof(atoken));
2911 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2912 atoken.startTime = k5creds->times.starttime;
2913 atoken.endTime = k5creds->times.endtime;
2914 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2915 atoken.ticketLen = k5creds->ticket.length;
2916 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2919 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2920 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2921 if ( rc == KTC_NOCM && retry < 20 ) {
2924 goto retry_gettoken5;
2929 if (atoken.kvno == btoken.kvno &&
2930 atoken.ticketLen == btoken.ticketLen &&
2931 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2932 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2934 /* Success - Nothing to do */
2938 // * Reset the "aclient" structure before we call ktc_SetToken.
2939 // * This structure was first set by the ktc_GetToken call when
2940 // * we were comparing whether identical tokens already existed.
2942 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2943 strncpy(aclient.name, k5creds->client->data[0].data, len);
2944 aclient.name[len] = '\0';
2946 if ( k5creds->client->length > 1 ) {
2948 strcat(aclient.name, ".");
2949 p = aclient.name + strlen(aclient.name);
2950 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2951 strncpy(p, k5creds->client->data[1].data, len);
2954 aclient.instance[0] = '\0';
2956 strcpy(aclient.cell, realm_of_cell);
2958 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
2959 /* For Khimaira, always append the realm name */
2960 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
2962 strcat(aclient.name, "@");
2963 p = aclient.name + strlen(aclient.name);
2964 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2965 strncpy(p, k5creds->client->realm.data, len);
2969 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2970 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2971 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2972 &aclient, &aserver, &atoken);
2975 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
2976 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
2978 aclient.smbname[0] = '\0';
2981 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2983 goto cleanup; /* We have successfully inserted the token */
2986 /* Otherwise, the ticket could have been too large so try to
2987 * convert using the krb524d running with the KDC
2989 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2990 pkrb5_free_creds(ctx, k5creds);
2992 if ( IsDebuggerPresent() ) {
2994 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2995 OutputDebugString(message);
3003 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3004 if (code == NO_TKT_FIL) {
3005 // if the problem is that we have no krb4 tickets
3006 // do not attempt to continue
3009 if (code != KSUCCESS)
3010 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3012 if (code != KSUCCESS)
3014 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3016 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3021 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3023 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3038 memset(&aserver, '\0', sizeof(aserver));
3039 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3040 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3042 memset(&atoken, '\0', sizeof(atoken));
3043 atoken.kvno = creds.kvno;
3044 atoken.startTime = creds.issue_date;
3045 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3046 memcpy(&atoken.sessionKey, creds.session, 8);
3047 atoken.ticketLen = creds.ticket_st.length;
3048 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3051 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3052 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3053 if ( rc == KTC_NOCM && retry < 20 ) {
3056 goto retry_gettoken;
3058 KFW_AFS_error(rc, "ktc_GetToken()");
3063 if (atoken.kvno == btoken.kvno &&
3064 atoken.ticketLen == btoken.ticketLen &&
3065 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3066 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3071 // * Reset the "aclient" structure before we call ktc_SetToken.
3072 // * This structure was first set by the ktc_GetToken call when
3073 // * we were comparing whether identical tokens already existed.
3075 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3078 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3079 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3081 strcpy(aclient.instance, "");
3083 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3084 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3085 aclient.name[MAXKTCREALMLEN-1] = '\0';
3087 strcpy(aclient.cell, CellName);
3089 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3090 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3091 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3092 &aclient, &aserver, &atoken);
3095 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3096 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3098 aclient.smbname[0] = '\0';
3101 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3103 KFW_AFS_error(rc, "ktc_SetToken()");
3109 if (client_principal)
3110 pkrb5_free_principal(ctx,client_principal);
3111 /* increds.client == client_principal */
3113 pkrb5_free_principal(ctx,increds.server);
3114 if (cc && (cc != alt_cc))
3115 pkrb5_cc_close(ctx, cc);
3116 if (ctx && (ctx != alt_ctx))
3117 pkrb5_free_context(ctx);
3119 return(rc? rc : code);
3122 /**************************************/
3123 /* afs_realm_of_cell(): */
3124 /**************************************/
3126 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3128 static char krbrlm[REALM_SZ+1]="";
3129 char ** realmlist=NULL;
3135 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3136 if ( !r && realmlist && realmlist[0] ) {
3137 strcpy(krbrlm, realmlist[0]);
3138 pkrb5_free_host_realm(ctx, realmlist);
3144 char *t = cellconfig->name;
3149 if (islower(c)) c=toupper(c);
3157 /**************************************/
3158 /* KFW_AFS_get_cellconfig(): */
3159 /**************************************/
3161 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3164 char newcell[MAXCELLCHARS+1];
3166 local_cell[0] = (char)0;
3167 memset(cellconfig, 0, sizeof(*cellconfig));
3169 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3170 if (rc = cm_GetRootCellName(local_cell))
3175 if (strlen(cell) == 0)
3176 strcpy(cell, local_cell);
3178 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3179 strcpy(cellconfig->name, cell);
3181 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3182 #ifdef AFS_AFSDB_ENV
3185 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3191 /**************************************/
3192 /* get_cellconfig_callback(): */
3193 /**************************************/
3195 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3197 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3199 cc->hostAddr[cc->numServers] = *addrp;
3200 strcpy(cc->hostName[cc->numServers], namep);
3206 /**************************************/
3207 /* KFW_AFS_error(): */
3208 /**************************************/
3210 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3213 const char *errText;
3215 // Using AFS defines as error messages for now, until Transarc
3216 // gets back to me with "string" translations of each of these
3218 if (rc == KTC_ERROR)
3219 errText = "KTC_ERROR";
3220 else if (rc == KTC_TOOBIG)
3221 errText = "KTC_TOOBIG";
3222 else if (rc == KTC_INVAL)
3223 errText = "KTC_INVAL";
3224 else if (rc == KTC_NOENT)
3225 errText = "KTC_NOENT";
3226 else if (rc == KTC_PIOCTLFAIL)
3227 errText = "KTC_PIOCTLFAIL";
3228 else if (rc == KTC_NOPIOCTL)
3229 errText = "KTC_NOPIOCTL";
3230 else if (rc == KTC_NOCELL)
3231 errText = "KTC_NOCELL";
3232 else if (rc == KTC_NOCM)
3233 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3235 errText = "Unknown error!";
3237 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3239 if ( IsDebuggerPresent() ) {
3240 OutputDebugString(message);
3241 OutputDebugString("\n");
3243 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3249 LPSTR lpszMachineName,
3250 LPSTR lpszServiceName,
3251 DWORD *lpdwCurrentState)
3254 SC_HANDLE schSCManager = NULL;
3255 SC_HANDLE schService = NULL;
3256 DWORD fdwDesiredAccess = 0;
3257 SERVICE_STATUS ssServiceStatus = {0};
3260 *lpdwCurrentState = 0;
3262 fdwDesiredAccess = GENERIC_READ;
3264 schSCManager = OpenSCManager(lpszMachineName,
3268 if(schSCManager == NULL)
3270 hr = GetLastError();
3274 schService = OpenService(schSCManager,
3278 if(schService == NULL)
3280 hr = GetLastError();
3284 fRet = QueryServiceStatus(schService,
3289 hr = GetLastError();
3293 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3297 CloseServiceHandle(schService);
3298 CloseServiceHandle(schSCManager);
3311 for (n = 0; fi[n].func_ptr_var; n++)
3312 *(fi[n].func_ptr_var) = 0;
3313 if (h) FreeLibrary(h);
3318 const char* dll_name,
3320 HINSTANCE* ph, // [out, optional] - DLL handle
3321 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3322 int cleanup, // cleanup function pointers and unload on error
3323 int go_on, // continue loading even if some functions cannot be loaded
3324 int silent // do not pop-up a system dialog if DLL cannot be loaded
3333 if (pindex) *pindex = -1;
3335 for (n = 0; fi[n].func_ptr_var; n++)
3336 *(fi[n].func_ptr_var) = 0;
3339 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3340 h = LoadLibrary(dll_name);
3348 for (i = 0; (go_on || !error) && (i < n); i++)
3350 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3356 *(fi[i].func_ptr_var) = p;
3359 if (pindex) *pindex = last_i;
3360 if (error && cleanup && !go_on) {
3361 for (i = 0; i < n; i++) {
3362 *(fi[i].func_ptr_var) = 0;
3368 if (error) return 0;
3372 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3374 krb5_context ctx = 0;
3376 krb5_error_code code;
3378 const char * realm = 0;
3379 krb5_principal principal = 0;
3381 char password[PROBE_PASSWORD_LEN+1];
3382 BOOL serverReachable = 0;
3384 if (!pkrb5_init_context)
3387 code = pkrb5_init_context(&ctx);
3388 if (code) goto cleanup;
3391 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3393 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3394 realm, PROBE_USERNAME, NULL, NULL);
3395 if ( code ) goto cleanup;
3397 code = KFW_get_ccache(ctx, principal, &cc);
3398 if ( code ) goto cleanup;
3400 code = pkrb5_unparse_name(ctx, principal, &pname);
3401 if ( code ) goto cleanup;
3403 pwdata.data = password;
3404 pwdata.length = PROBE_PASSWORD_LEN;
3405 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3408 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3411 password[PROBE_PASSWORD_LEN] = '\0';
3413 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3423 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3424 case KRB5KDC_ERR_CLIENT_REVOKED:
3425 case KRB5KDC_ERR_CLIENT_NOTYET:
3426 case KRB5KDC_ERR_PREAUTH_FAILED:
3427 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3428 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3429 serverReachable = TRUE;
3432 serverReachable = FALSE;
3437 pkrb5_free_unparsed_name(ctx,pname);
3439 pkrb5_free_principal(ctx,principal);
3441 pkrb5_cc_close(ctx,cc);
3443 pkrb5_free_context(ctx);
3445 return serverReachable;
3449 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3451 krb5_context ctx = 0;
3452 krb5_error_code code;
3453 krb5_ccache mslsa_ccache=0;
3454 krb5_principal princ = 0;
3458 if (!KFW_is_available())
3461 if (code = pkrb5_init_context(&ctx))
3464 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3467 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3470 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3473 if ( strlen(pname) < *dwSize ) {
3474 strncpy(szUser, pname, *dwSize);
3475 szUser[*dwSize-1] = '\0';
3478 *dwSize = (DWORD)strlen(pname);
3482 pkrb5_free_unparsed_name(ctx, pname);
3485 pkrb5_free_principal(ctx, princ);
3488 pkrb5_cc_close(ctx, mslsa_ccache);
3491 pkrb5_free_context(ctx);
3496 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3500 char cachename[264] = "FILE:";
3501 krb5_context ctx = 0;
3502 krb5_error_code code;
3503 krb5_principal princ = 0;
3505 krb5_ccache ncc = 0;
3507 if (!pkrb5_init_context)
3510 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3511 if ( count > sizeof(filename) || count == 0 ) {
3512 GetWindowsDirectory(filename, sizeof(filename));
3515 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3518 strcat(filename, "\\");
3519 strcat(filename, szLogonId);
3521 strcat(cachename, filename);
3523 DeleteFile(filename);
3525 code = pkrb5_init_context(&ctx);
3528 code = pkrb5_parse_name(ctx, user, &princ);
3529 if (code) goto cleanup;
3531 code = KFW_get_ccache(ctx, princ, &cc);
3532 if (code) goto cleanup;
3534 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3535 if (code) goto cleanup;
3537 code = pkrb5_cc_initialize(ctx, ncc, princ);
3538 if (code) goto cleanup;
3540 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3544 pkrb5_cc_close(ctx, cc);
3548 pkrb5_cc_close(ctx, ncc);
3552 pkrb5_free_principal(ctx, princ);
3557 pkrb5_free_context(ctx);
3561 KFW_AFS_copy_system_file_to_default_cache(char * filename)
3563 char cachename[264] = "FILE:";
3564 krb5_context ctx = 0;
3565 krb5_error_code code;
3566 krb5_principal princ = 0;
3568 krb5_ccache ncc = 0;
3571 if (!pkrb5_init_context)
3574 if ( strlen(filename) + 6 > sizeof(cachename) )
3577 strcat(cachename, filename);
3579 code = pkrb5_init_context(&ctx);
3582 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3583 if (code) goto cleanup;
3585 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3587 code = pkrb5_cc_default(ctx, &ncc);
3589 code = pkrb5_cc_initialize(ctx, ncc, princ);
3592 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3595 pkrb5_cc_close(ctx, ncc);
3599 retval=0; /* success */
3603 pkrb5_cc_close(ctx, cc);
3607 DeleteFile(filename);
3610 pkrb5_free_principal(ctx, princ);
3615 pkrb5_free_context(ctx);
3620 /* We are including this
3622 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3623 fixed part of rande of the one byte lifetime field. Values less than 0x80
3624 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3625 0xBF should be looked up in this table. The value of 0x80 is the same using
3626 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3627 The intervening values of have a fixed ratio of roughly 1.06914. The value
3628 oxFF is defined to mean a ticket has no expiration time. This should be
3629 used advisedly since individual servers may impose defacto upperbounds on
3630 ticket lifetimes. */
3632 #define TKTLIFENUMFIXED 64
3633 #define TKTLIFEMINFIXED 0x80
3634 #define TKTLIFEMAXFIXED 0xBF
3635 #define TKTLIFENOEXPIRE 0xFF
3636 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3638 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3639 38400, /* 10.67 hours, 0.44 days */
3640 41055, /* 11.40 hours, 0.48 days */
3641 43894, /* 12.19 hours, 0.51 days */
3642 46929, /* 13.04 hours, 0.54 days */
3643 50174, /* 13.94 hours, 0.58 days */
3644 53643, /* 14.90 hours, 0.62 days */
3645 57352, /* 15.93 hours, 0.66 days */
3646 61318, /* 17.03 hours, 0.71 days */
3647 65558, /* 18.21 hours, 0.76 days */
3648 70091, /* 19.47 hours, 0.81 days */
3649 74937, /* 20.82 hours, 0.87 days */
3650 80119, /* 22.26 hours, 0.93 days */
3651 85658, /* 23.79 hours, 0.99 days */
3652 91581, /* 25.44 hours, 1.06 days */
3653 97914, /* 27.20 hours, 1.13 days */
3654 104684, /* 29.08 hours, 1.21 days */
3655 111922, /* 31.09 hours, 1.30 days */
3656 119661, /* 33.24 hours, 1.38 days */
3657 127935, /* 35.54 hours, 1.48 days */
3658 136781, /* 37.99 hours, 1.58 days */
3659 146239, /* 40.62 hours, 1.69 days */
3660 156350, /* 43.43 hours, 1.81 days */
3661 167161, /* 46.43 hours, 1.93 days */
3662 178720, /* 49.64 hours, 2.07 days */
3663 191077, /* 53.08 hours, 2.21 days */
3664 204289, /* 56.75 hours, 2.36 days */
3665 218415, /* 60.67 hours, 2.53 days */
3666 233517, /* 64.87 hours, 2.70 days */
3667 249664, /* 69.35 hours, 2.89 days */
3668 266926, /* 74.15 hours, 3.09 days */
3669 285383, /* 79.27 hours, 3.30 days */
3670 305116, /* 84.75 hours, 3.53 days */
3671 326213, /* 90.61 hours, 3.78 days */
3672 348769, /* 96.88 hours, 4.04 days */
3673 372885, /* 103.58 hours, 4.32 days */
3674 398668, /* 110.74 hours, 4.61 days */
3675 426234, /* 118.40 hours, 4.93 days */
3676 455705, /* 126.58 hours, 5.27 days */
3677 487215, /* 135.34 hours, 5.64 days */
3678 520904, /* 144.70 hours, 6.03 days */
3679 556921, /* 154.70 hours, 6.45 days */
3680 595430, /* 165.40 hours, 6.89 days */
3681 636601, /* 176.83 hours, 7.37 days */
3682 680618, /* 189.06 hours, 7.88 days */
3683 727680, /* 202.13 hours, 8.42 days */
3684 777995, /* 216.11 hours, 9.00 days */
3685 831789, /* 231.05 hours, 9.63 days */
3686 889303, /* 247.03 hours, 10.29 days */
3687 950794, /* 264.11 hours, 11.00 days */
3688 1016537, /* 282.37 hours, 11.77 days */
3689 1086825, /* 301.90 hours, 12.58 days */
3690 1161973, /* 322.77 hours, 13.45 days */
3691 1242318, /* 345.09 hours, 14.38 days */
3692 1328218, /* 368.95 hours, 15.37 days */
3693 1420057, /* 394.46 hours, 16.44 days */
3694 1518247, /* 421.74 hours, 17.57 days */
3695 1623226, /* 450.90 hours, 18.79 days */
3696 1735464, /* 482.07 hours, 20.09 days */
3697 1855462, /* 515.41 hours, 21.48 days */
3698 1983758, /* 551.04 hours, 22.96 days */
3699 2120925, /* 589.15 hours, 24.55 days */
3700 2267576, /* 629.88 hours, 26.25 days */
3701 2424367, /* 673.44 hours, 28.06 days */
3703 }; /* 720.00 hours, 30.00 days */
3705 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3706 * returns the corresponding end time. There are four simple cases to be
3707 * handled. The first is a life of 0xff, meaning no expiration, and results in
3708 * an end time of 0xffffffff. The second is when life is less than the values
3709 * covered by the table. In this case, the end time is the start time plus the
3710 * number of 5 minute intervals specified by life. The third case returns
3711 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3712 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3713 * table to extract the lifetime in seconds, which is added to start to produce
3717 life_to_time(afs_uint32 start, unsigned char life)
3721 if (life == TKTLIFENOEXPIRE)
3723 if (life < TKTLIFEMINFIXED)
3724 return start + life * 5 * 60;
3725 if (life > TKTLIFEMAXFIXED)
3726 return start + MAXTKTLIFETIME;
3727 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3728 return start + realLife;
3731 /* time_to_life - takes start and end times for the ticket and returns a
3732 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3733 * lifetimes above 127*5minutes. First, the special case of (end ==
3734 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3735 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3736 * less than the first table entry are handled by rounding the requested
3737 * lifetime *up* to the next 5 minute interval. The final step is to search
3738 * the table for the smallest entry *greater than or equal* to the requested
3739 * entry. The actual code is prepared to handle the case where the table is
3740 * unordered but that it an unnecessary frill. */
3742 static unsigned char
3743 time_to_life(afs_uint32 start, afs_uint32 end)
3745 int lifetime = end - start;
3749 if (end == NEVERDATE)
3750 return TKTLIFENOEXPIRE;
3751 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3753 if (lifetime < tkt_lifetimes[0])
3754 return (lifetime + 5 * 60 - 1) / (5 * 60);
3756 best = MAXKTCTICKETLIFETIME;
3757 for (i = 0; i < TKTLIFENUMFIXED; i++)
3758 if (tkt_lifetimes[i] >= lifetime) {
3759 int diff = tkt_lifetimes[i] - lifetime;
3767 return best_i + TKTLIFEMINFIXED;