2 * Copyright (c) 2004, 2005, 2006 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"
68 #include <afs/ptserver.h>
69 #include <afs/ptuser.h>
72 #include <WINNT\afsreg.h>
75 * TIMING _____________________________________________________________________
79 #define cminREMIND_TEST 1 // test every minute for expired creds
80 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
81 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
82 #define cminMINLIFE 30 // minimum life of Kerberos creds
84 #define c100ns1SECOND (LONGLONG)10000000
85 #define cmsec1SECOND 1000
86 #define cmsec1MINUTE 60000
87 #define csec1MINUTE 60
89 /* Function Pointer Declarations for Delayed Loading */
91 DECL_FUNC_PTR(cc_initialize);
92 DECL_FUNC_PTR(cc_shutdown);
93 DECL_FUNC_PTR(cc_get_NC_info);
94 DECL_FUNC_PTR(cc_free_NC_info);
97 DECL_FUNC_PTR(Leash_get_default_lifetime);
98 DECL_FUNC_PTR(Leash_get_default_forwardable);
99 DECL_FUNC_PTR(Leash_get_default_renew_till);
100 DECL_FUNC_PTR(Leash_get_default_noaddresses);
101 DECL_FUNC_PTR(Leash_get_default_proxiable);
102 DECL_FUNC_PTR(Leash_get_default_publicip);
103 DECL_FUNC_PTR(Leash_get_default_use_krb4);
104 DECL_FUNC_PTR(Leash_get_default_life_min);
105 DECL_FUNC_PTR(Leash_get_default_life_max);
106 DECL_FUNC_PTR(Leash_get_default_renew_min);
107 DECL_FUNC_PTR(Leash_get_default_renew_max);
108 DECL_FUNC_PTR(Leash_get_default_renewable);
109 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
112 DECL_FUNC_PTR(krb5_change_password);
113 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
114 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
115 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
116 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
117 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
118 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
119 DECL_FUNC_PTR(krb5_get_init_creds_password);
120 DECL_FUNC_PTR(krb5_build_principal_ext);
121 DECL_FUNC_PTR(krb5_cc_get_name);
122 DECL_FUNC_PTR(krb5_cc_resolve);
123 DECL_FUNC_PTR(krb5_cc_default);
124 DECL_FUNC_PTR(krb5_cc_default_name);
125 DECL_FUNC_PTR(krb5_cc_set_default_name);
126 DECL_FUNC_PTR(krb5_cc_initialize);
127 DECL_FUNC_PTR(krb5_cc_destroy);
128 DECL_FUNC_PTR(krb5_cc_close);
129 DECL_FUNC_PTR(krb5_cc_store_cred);
130 DECL_FUNC_PTR(krb5_cc_copy_creds);
131 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
132 DECL_FUNC_PTR(krb5_cc_get_principal);
133 DECL_FUNC_PTR(krb5_cc_start_seq_get);
134 DECL_FUNC_PTR(krb5_cc_next_cred);
135 DECL_FUNC_PTR(krb5_cc_end_seq_get);
136 DECL_FUNC_PTR(krb5_cc_remove_cred);
137 DECL_FUNC_PTR(krb5_cc_set_flags);
138 DECL_FUNC_PTR(krb5_cc_get_type);
139 DECL_FUNC_PTR(krb5_free_context);
140 DECL_FUNC_PTR(krb5_free_cred_contents);
141 DECL_FUNC_PTR(krb5_free_principal);
142 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
143 DECL_FUNC_PTR(krb5_init_context);
144 DECL_FUNC_PTR(krb5_parse_name);
145 DECL_FUNC_PTR(krb5_timeofday);
146 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
147 DECL_FUNC_PTR(krb5_unparse_name);
148 DECL_FUNC_PTR(krb5_get_credentials);
149 DECL_FUNC_PTR(krb5_mk_req);
150 DECL_FUNC_PTR(krb5_sname_to_principal);
151 DECL_FUNC_PTR(krb5_get_credentials_renew);
152 DECL_FUNC_PTR(krb5_free_data);
153 DECL_FUNC_PTR(krb5_free_data_contents);
154 DECL_FUNC_PTR(krb5_free_unparsed_name);
155 DECL_FUNC_PTR(krb5_os_localaddr);
156 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
157 DECL_FUNC_PTR(krb5_copy_data);
158 DECL_FUNC_PTR(krb5_free_creds);
159 DECL_FUNC_PTR(krb5_build_principal);
160 DECL_FUNC_PTR(krb5_get_renewed_creds);
161 DECL_FUNC_PTR(krb5_get_default_config_files);
162 DECL_FUNC_PTR(krb5_free_config_files);
163 DECL_FUNC_PTR(krb5_get_default_realm);
164 DECL_FUNC_PTR(krb5_free_default_realm);
165 DECL_FUNC_PTR(krb5_free_ticket);
166 DECL_FUNC_PTR(krb5_decode_ticket);
167 DECL_FUNC_PTR(krb5_get_host_realm);
168 DECL_FUNC_PTR(krb5_free_host_realm);
169 DECL_FUNC_PTR(krb5_free_addresses);
170 DECL_FUNC_PTR(krb5_c_random_make_octets);
173 DECL_FUNC_PTR(krb524_init_ets);
174 DECL_FUNC_PTR(krb524_convert_creds_kdc);
177 DECL_FUNC_PTR(krb_get_cred);
178 DECL_FUNC_PTR(tkt_string);
179 DECL_FUNC_PTR(krb_get_tf_realm);
180 DECL_FUNC_PTR(krb_mk_req);
183 DECL_FUNC_PTR(com_err);
184 DECL_FUNC_PTR(error_message);
187 DECL_FUNC_PTR(profile_init);
188 DECL_FUNC_PTR(profile_release);
189 DECL_FUNC_PTR(profile_get_subsection_names);
190 DECL_FUNC_PTR(profile_free_list);
191 DECL_FUNC_PTR(profile_get_string);
192 DECL_FUNC_PTR(profile_release_string);
195 DECL_FUNC_PTR(OpenSCManagerA);
196 DECL_FUNC_PTR(OpenServiceA);
197 DECL_FUNC_PTR(QueryServiceStatus);
198 DECL_FUNC_PTR(CloseServiceHandle);
200 DECL_FUNC_PTR(LsaNtStatusToWinError);
201 #endif /* USE_MS2MIT */
205 DECL_FUNC_PTR(LsaConnectUntrusted);
206 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
207 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
208 DECL_FUNC_PTR(LsaFreeReturnBuffer);
209 DECL_FUNC_PTR(LsaGetLogonSessionData);
210 #endif /* USE_MS2MIT */
213 FUNC_INFO ccapi_fi[] = {
214 MAKE_FUNC_INFO(cc_initialize),
215 MAKE_FUNC_INFO(cc_shutdown),
216 MAKE_FUNC_INFO(cc_get_NC_info),
217 MAKE_FUNC_INFO(cc_free_NC_info),
221 FUNC_INFO leash_fi[] = {
222 MAKE_FUNC_INFO(Leash_get_default_lifetime),
223 MAKE_FUNC_INFO(Leash_get_default_renew_till),
224 MAKE_FUNC_INFO(Leash_get_default_forwardable),
225 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
226 MAKE_FUNC_INFO(Leash_get_default_proxiable),
227 MAKE_FUNC_INFO(Leash_get_default_publicip),
228 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
229 MAKE_FUNC_INFO(Leash_get_default_life_min),
230 MAKE_FUNC_INFO(Leash_get_default_life_max),
231 MAKE_FUNC_INFO(Leash_get_default_renew_min),
232 MAKE_FUNC_INFO(Leash_get_default_renew_max),
233 MAKE_FUNC_INFO(Leash_get_default_renewable),
237 FUNC_INFO leash_opt_fi[] = {
238 MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
242 FUNC_INFO k5_fi[] = {
243 MAKE_FUNC_INFO(krb5_change_password),
244 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
245 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
246 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
247 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
248 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
249 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
250 MAKE_FUNC_INFO(krb5_get_init_creds_password),
251 MAKE_FUNC_INFO(krb5_build_principal_ext),
252 MAKE_FUNC_INFO(krb5_cc_get_name),
253 MAKE_FUNC_INFO(krb5_cc_resolve),
254 MAKE_FUNC_INFO(krb5_cc_default),
255 MAKE_FUNC_INFO(krb5_cc_default_name),
256 MAKE_FUNC_INFO(krb5_cc_set_default_name),
257 MAKE_FUNC_INFO(krb5_cc_initialize),
258 MAKE_FUNC_INFO(krb5_cc_destroy),
259 MAKE_FUNC_INFO(krb5_cc_close),
260 MAKE_FUNC_INFO(krb5_cc_copy_creds),
261 MAKE_FUNC_INFO(krb5_cc_store_cred),
262 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
263 MAKE_FUNC_INFO(krb5_cc_get_principal),
264 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
265 MAKE_FUNC_INFO(krb5_cc_next_cred),
266 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
267 MAKE_FUNC_INFO(krb5_cc_remove_cred),
268 MAKE_FUNC_INFO(krb5_cc_set_flags),
269 MAKE_FUNC_INFO(krb5_cc_get_type),
270 MAKE_FUNC_INFO(krb5_free_context),
271 MAKE_FUNC_INFO(krb5_free_cred_contents),
272 MAKE_FUNC_INFO(krb5_free_principal),
273 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
274 MAKE_FUNC_INFO(krb5_init_context),
275 MAKE_FUNC_INFO(krb5_parse_name),
276 MAKE_FUNC_INFO(krb5_timeofday),
277 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
278 MAKE_FUNC_INFO(krb5_unparse_name),
279 MAKE_FUNC_INFO(krb5_get_credentials),
280 MAKE_FUNC_INFO(krb5_mk_req),
281 MAKE_FUNC_INFO(krb5_sname_to_principal),
282 MAKE_FUNC_INFO(krb5_get_credentials_renew),
283 MAKE_FUNC_INFO(krb5_free_data),
284 MAKE_FUNC_INFO(krb5_free_data_contents),
285 MAKE_FUNC_INFO(krb5_free_unparsed_name),
286 MAKE_FUNC_INFO(krb5_os_localaddr),
287 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
288 MAKE_FUNC_INFO(krb5_copy_data),
289 MAKE_FUNC_INFO(krb5_free_creds),
290 MAKE_FUNC_INFO(krb5_build_principal),
291 MAKE_FUNC_INFO(krb5_get_renewed_creds),
292 MAKE_FUNC_INFO(krb5_free_addresses),
293 MAKE_FUNC_INFO(krb5_get_default_config_files),
294 MAKE_FUNC_INFO(krb5_free_config_files),
295 MAKE_FUNC_INFO(krb5_get_default_realm),
296 MAKE_FUNC_INFO(krb5_free_default_realm),
297 MAKE_FUNC_INFO(krb5_free_ticket),
298 MAKE_FUNC_INFO(krb5_decode_ticket),
299 MAKE_FUNC_INFO(krb5_get_host_realm),
300 MAKE_FUNC_INFO(krb5_free_host_realm),
301 MAKE_FUNC_INFO(krb5_free_addresses),
302 MAKE_FUNC_INFO(krb5_c_random_make_octets),
307 FUNC_INFO k4_fi[] = {
308 MAKE_FUNC_INFO(krb_get_cred),
309 MAKE_FUNC_INFO(krb_get_tf_realm),
310 MAKE_FUNC_INFO(krb_mk_req),
311 MAKE_FUNC_INFO(tkt_string),
316 FUNC_INFO k524_fi[] = {
317 MAKE_FUNC_INFO(krb524_init_ets),
318 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
322 FUNC_INFO profile_fi[] = {
323 MAKE_FUNC_INFO(profile_init),
324 MAKE_FUNC_INFO(profile_release),
325 MAKE_FUNC_INFO(profile_get_subsection_names),
326 MAKE_FUNC_INFO(profile_free_list),
327 MAKE_FUNC_INFO(profile_get_string),
328 MAKE_FUNC_INFO(profile_release_string),
332 FUNC_INFO ce_fi[] = {
333 MAKE_FUNC_INFO(com_err),
334 MAKE_FUNC_INFO(error_message),
338 FUNC_INFO service_fi[] = {
339 MAKE_FUNC_INFO(OpenSCManagerA),
340 MAKE_FUNC_INFO(OpenServiceA),
341 MAKE_FUNC_INFO(QueryServiceStatus),
342 MAKE_FUNC_INFO(CloseServiceHandle),
344 MAKE_FUNC_INFO(LsaNtStatusToWinError),
345 #endif /* USE_MS2MIT */
350 FUNC_INFO lsa_fi[] = {
351 MAKE_FUNC_INFO(LsaConnectUntrusted),
352 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
353 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
354 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
355 MAKE_FUNC_INFO(LsaGetLogonSessionData),
358 #endif /* USE_MS2MIT */
360 /* Static Prototypes */
361 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
362 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
363 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
364 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
365 void *data, const char *name, const char *banner, int num_prompts,
366 krb5_prompt prompts[]);
369 /* Static Declarations */
370 static int inited = 0;
371 static int mid_cnt = 0;
372 static struct textField * mid_tb = NULL;
373 static HINSTANCE hKrb5 = 0;
375 static HINSTANCE hKrb4 = 0;
376 #endif /* USE_KRB4 */
377 static HINSTANCE hKrb524 = 0;
379 static HINSTANCE hSecur32 = 0;
380 #endif /* USE_MS2MIT */
381 static HINSTANCE hAdvApi32 = 0;
382 static HINSTANCE hComErr = 0;
383 static HINSTANCE hService = 0;
384 static HINSTANCE hProfile = 0;
385 static HINSTANCE hLeash = 0;
386 static HINSTANCE hLeashOpt = 0;
387 static HINSTANCE hCCAPI = 0;
388 static struct principal_ccache_data * princ_cc_data = NULL;
389 static struct cell_principal_map * cell_princ_map = NULL;
394 static int inited = 0;
397 char mutexName[MAX_PATH];
398 HANDLE hMutex = NULL;
400 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
402 hMutex = CreateMutex( NULL, TRUE, mutexName );
403 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
404 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
410 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
412 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
413 #endif /* USE_KRB4 */
414 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
415 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
417 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
418 #endif /* USE_MS2MIT */
419 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
420 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
421 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
422 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
423 LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
425 if ( KFW_is_available() ) {
426 char rootcell[MAXCELLCHARS+1];
428 KFW_import_windows_lsa();
429 #endif /* USE_MS2MIT */
430 KFW_import_ccache_data();
431 KFW_AFS_renew_expiring_tokens();
433 /* WIN32 NOTE: no way to get max chars */
434 if (!cm_GetRootCellName(rootcell))
435 KFW_AFS_renew_token_for_cell(rootcell);
438 ReleaseMutex(hMutex);
447 FreeLibrary(hLeashOpt);
453 FreeLibrary(hKrb524);
456 FreeLibrary(hSecur32);
457 #endif /* USE_MS2MIT */
459 FreeLibrary(hService);
461 FreeLibrary(hComErr);
463 FreeLibrary(hProfile);
467 #endif /* USE_KRB4 */
479 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
480 0, KEY_QUERY_VALUE, &parmKey);
481 if (code == ERROR_SUCCESS) {
482 len = sizeof(use524);
483 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
484 (BYTE *) &use524, &len);
485 RegCloseKey(parmKey);
487 if (code != ERROR_SUCCESS) {
488 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
489 0, KEY_QUERY_VALUE, &parmKey);
490 if (code == ERROR_SUCCESS) {
491 len = sizeof(use524);
492 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
493 (BYTE *) &use524, &len);
494 RegCloseKey (parmKey);
501 KFW_is_available(void)
507 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
508 0, KEY_QUERY_VALUE, &parmKey);
509 if (code == ERROR_SUCCESS) {
510 len = sizeof(enableKFW);
511 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
512 (BYTE *) &enableKFW, &len);
513 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) {
520 len = sizeof(enableKFW);
521 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
522 (BYTE *) &enableKFW, &len);
523 RegCloseKey (parmKey);
531 if ( hKrb5 && hComErr && hService &&
534 #endif /* USE_MS2MIT */
536 hProfile && hLeash && hCCAPI )
542 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
543 int FreeContextFlag, krb5_context * ctx,
548 int krb5Error = ((int)(rc & 255));
560 errText = perror_message(rc);
561 _snprintf(message, sizeof(message),
562 "%s\n(Kerberos error %ld)\n\n%s failed",
567 if ( IsDebuggerPresent() )
568 OutputDebugString(message);
570 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
573 if (FreeContextFlag == 1)
575 if (ctx && *ctx != NULL)
577 if (cache && *cache != NULL) {
578 pkrb5_cc_close(*ctx, *cache);
582 pkrb5_free_context(*ctx);
591 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
593 struct principal_ccache_data * next = princ_cc_data;
594 krb5_principal principal = 0;
596 const char * ccname = NULL;
597 krb5_error_code code = 0;
598 krb5_error_code cc_code = 0;
604 if (ctx == 0 || cc == 0)
607 code = pkrb5_cc_get_principal(ctx, cc, &principal);
610 code = pkrb5_unparse_name(ctx, principal, &pname);
611 if ( code ) goto cleanup;
613 ccname = pkrb5_cc_get_name(ctx, cc);
614 if (!ccname) goto cleanup;
616 // Search the existing list to see if we have a match
618 for ( ; next ; next = next->next ) {
619 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
624 // If not, match add a new node to the beginning of the list and assign init it
626 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
627 next->next = princ_cc_data;
628 princ_cc_data = next;
629 next->principal = _strdup(pname);
630 next->ccache_name = _strdup(ccname);
631 next->from_lsa = lsa;
633 next->expiration_time = 0;
637 flags = 0; // turn off OPENCLOSE mode
638 code = pkrb5_cc_set_flags(ctx, cc, flags);
639 if ( code ) goto cleanup;
641 code = pkrb5_timeofday(ctx, &now);
643 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
645 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
646 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
648 // we found the ticket we are looking for
649 // check validity of timestamp
650 // We add a 5 minutes fudge factor to compensate for potential
651 // clock skew errors between the KDC and client OS
653 valid = ((creds.times.starttime > 0) &&
654 now >= (creds.times.starttime - 300) &&
655 now < (creds.times.endtime + 300) &&
656 !(creds.ticket_flags & TKT_FLG_INVALID));
658 if ( next->from_lsa) {
660 next->expiration_time = creds.times.endtime;
662 } else if ( valid ) {
664 next->expiration_time = creds.times.endtime;
665 next->renew = (creds.times.renew_till > creds.times.endtime) &&
666 (creds.ticket_flags & TKT_FLG_RENEWABLE);
669 next->expiration_time = 0;
673 pkrb5_free_cred_contents(ctx, &creds);
674 cc_code = KRB5_CC_END;
677 pkrb5_free_cred_contents(ctx, &creds);
680 if (cc_code == KRB5_CC_END) {
681 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
682 if (code) goto cleanup;
686 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
687 code = pkrb5_cc_set_flags(ctx, cc, flags);
690 pkrb5_free_unparsed_name(ctx,pname);
692 pkrb5_free_principal(ctx,principal);
696 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
698 struct principal_ccache_data * next = princ_cc_data;
699 char * response = NULL;
701 if ( !principal || !ccache )
705 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
707 // we always want to prefer the MS Kerberos LSA cache or
708 // the cache afscreds created specifically for the principal
709 // if the current entry is either one, drop the previous find
710 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
713 response = _strdup(next->ccache_name);
714 // MS Kerberos LSA is our best option so use it and quit
715 if ( next->from_lsa )
729 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
731 struct principal_ccache_data ** next = &princ_cc_data;
733 if ( !pname && !ccname )
737 if ( !strcmp((*next)->principal,pname) ||
738 !strcmp((*next)->ccache_name,ccname) ) {
740 free((*next)->principal);
741 free((*next)->ccache_name);
743 (*next) = (*next)->next;
750 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
752 struct cell_principal_map * next = cell_princ_map;
754 // Search the existing list to see if we have a match
756 for ( ; next ; next = next->next ) {
757 if ( !strcmp(next->cell, cell) ) {
758 if ( !strcmp(next->principal,pname) ) {
759 next->active = active;
762 // OpenAFS currently has a restriction of one active token per cell
763 // Therefore, whenever we update the table with a new active cell we
764 // must mark all of the other principal to cell entries as inactive.
772 // If not, match add a new node to the beginning of the list and assign init it
774 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
775 next->next = cell_princ_map;
776 cell_princ_map = next;
777 next->principal = _strdup(pname);
778 next->cell = _strdup(cell);
779 next->active = active;
784 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
786 struct cell_principal_map ** next = &cell_princ_map;
788 if ( !pname && !cell )
792 if ( !strcmp((*next)->principal,pname) ||
793 !strcmp((*next)->cell,cell) ) {
795 free((*next)->principal);
798 (*next) = (*next)->next;
804 // Returns (if possible) a principal which has been known in
805 // the past to have been used to obtain tokens for the specified
807 // TODO: Attempt to return one which has not yet expired by checking
808 // the principal/ccache data
810 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
812 struct cell_principal_map * next_map = cell_princ_map;
813 const char * princ = NULL;
820 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
823 next_map = next_map->next;
826 if ( !principals || !count )
829 *principals = (char **) malloc(sizeof(char *) * count);
830 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
832 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
833 (*principals)[i++] = _strdup(next_map->principal);
840 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
843 struct cell_principal_map * next_map = cell_princ_map;
844 const char * princ = NULL;
850 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
853 next_map = next_map->next;
859 *cells = (char **) malloc(sizeof(char *) * count);
860 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
862 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
863 (*cells)[i++] = _strdup(next_map->cell);
869 /* Given a principal return an existing ccache or create one and return */
871 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
876 krb5_error_code code;
878 if (!pkrb5_init_context)
884 code = pkrb5_init_context(&ctx);
885 if (code) goto cleanup;
889 code = pkrb5_unparse_name(ctx, principal, &pname);
890 if (code) goto cleanup;
892 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
893 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
894 ccname = (char *)malloc(strlen(pname) + 5);
895 sprintf(ccname,"API:%s",pname);
897 code = pkrb5_cc_resolve(ctx, ccname, cc);
899 code = pkrb5_cc_default(ctx, cc);
900 if (code) goto cleanup;
907 pkrb5_free_unparsed_name(ctx,pname);
908 if (ctx && (ctx != alt_ctx))
909 pkrb5_free_context(ctx);
914 // Import Microsoft Credentials into a new MIT ccache
916 KFW_import_windows_lsa(void)
918 krb5_context ctx = 0;
920 krb5_principal princ = 0;
922 krb5_data * princ_realm;
923 krb5_error_code code;
924 char cell[128]="", realm[128]="", *def_realm = 0;
928 if (!pkrb5_init_context)
932 if ( !MSLSA_IsKerberosLogon() )
936 code = pkrb5_init_context(&ctx);
937 if (code) goto cleanup;
939 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
940 if (code) goto cleanup;
942 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
944 code = pkrb5_cc_get_principal(ctx, cc, &princ);
945 if ( code ) goto cleanup;
947 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
948 switch ( dwMsLsaImport ) {
949 case 0: /* do not import */
951 case 1: /* always import */
953 case 2: { /* matching realm */
954 char ms_realm[128] = "", *r;
957 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
958 *r = krb5_princ_realm(ctx, princ)->data[i];
962 if (code = pkrb5_get_default_realm(ctx, &def_realm))
965 if (strcmp(def_realm, ms_realm))
973 code = pkrb5_unparse_name(ctx,princ,&pname);
974 if ( code ) goto cleanup;
976 princ_realm = krb5_princ_realm(ctx, princ);
977 for ( i=0; i<princ_realm->length; i++ ) {
978 realm[i] = princ_realm->data[i];
979 cell[i] = tolower(princ_realm->data[i]);
984 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
985 if ( IsDebuggerPresent() ) {
987 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
988 OutputDebugString(message);
990 if ( code ) goto cleanup;
992 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
996 pkrb5_free_unparsed_name(ctx,pname);
998 pkrb5_free_principal(ctx,princ);
1000 pkrb5_free_default_realm(ctx, def_realm);
1002 pkrb5_cc_close(ctx,cc);
1004 pkrb5_free_context(ctx);
1006 #endif /* USE_MS2MIT */
1008 // If there are existing MIT credentials, copy them to a new
1009 // ccache named after the principal
1011 // Enumerate all existing MIT ccaches and construct entries
1012 // in the principal_ccache table
1014 // Enumerate all existing AFS Tokens and construct entries
1015 // in the cell_principal table
1017 KFW_import_ccache_data(void)
1019 krb5_context ctx = 0;
1021 krb5_principal principal = 0;
1023 krb5_error_code code;
1024 krb5_error_code cc_code;
1027 struct _infoNC ** pNCi = NULL;
1030 if ( !pcc_initialize )
1033 if ( IsDebuggerPresent() )
1034 OutputDebugString("KFW_import_ccache_data()\n");
1036 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1037 if (code) goto cleanup;
1039 code = pcc_get_NC_info(cc_ctx, &pNCi);
1040 if (code) goto cleanup;
1042 code = pkrb5_init_context(&ctx);
1043 if (code) goto cleanup;
1045 for ( i=0; pNCi[i]; i++ ) {
1046 if ( pNCi[i]->vers != CC_CRED_V5 )
1048 if ( IsDebuggerPresent() ) {
1049 OutputDebugString("Principal: ");
1050 OutputDebugString(pNCi[i]->principal);
1051 OutputDebugString(" in ccache ");
1052 OutputDebugString(pNCi[i]->name);
1053 OutputDebugString("\n");
1055 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1056 && strcmp(pNCi[i]->name,LSA_CCNAME)
1059 for ( j=0; pNCi[j]; j++ ) {
1060 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1066 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1067 if (code) goto loop_cleanup;
1070 krb5_ccache oldcc = 0;
1072 if ( IsDebuggerPresent() )
1073 OutputDebugString("copying ccache data to new ccache\n");
1075 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1076 if (code) goto loop_cleanup;
1077 code = pkrb5_cc_initialize(ctx, cc, principal);
1078 if (code) goto loop_cleanup;
1080 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1081 if (code) goto loop_cleanup;
1082 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1084 code = pkrb5_cc_close(ctx,cc);
1086 code = pkrb5_cc_close(ctx,oldcc);
1088 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1091 code = pkrb5_cc_close(ctx,oldcc);
1094 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1095 if (code) goto loop_cleanup;
1098 flags = 0; // turn off OPENCLOSE mode
1099 code = pkrb5_cc_set_flags(ctx, cc, flags);
1100 if ( code ) goto cleanup;
1102 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1104 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1106 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1107 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1108 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1109 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1110 if ( sname && cell && !strcmp("afs",sname->data) ) {
1111 struct ktc_principal aserver;
1112 struct ktc_principal aclient;
1113 struct ktc_token atoken;
1116 if ( IsDebuggerPresent() ) {
1117 OutputDebugString("Found AFS ticket: ");
1118 OutputDebugString(sname->data);
1120 OutputDebugString("/");
1121 OutputDebugString(cell->data);
1123 OutputDebugString("@");
1124 OutputDebugString(realm->data);
1125 OutputDebugString("\n");
1128 memset(&aserver, '\0', sizeof(aserver));
1129 strcpy(aserver.name, sname->data);
1130 strcpy(aserver.cell, cell->data);
1132 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1134 // Found a token in AFS Client Server which matches
1135 char pname[128], *p, *q;
1136 for ( p=pname, q=aclient.name; *q; p++, q++)
1138 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1142 if ( IsDebuggerPresent() ) {
1143 OutputDebugString("Found AFS token: ");
1144 OutputDebugString(pname);
1145 OutputDebugString("\n");
1148 if ( strcmp(pname,pNCi[i]->principal) )
1150 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1152 // Attempt to import it
1153 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1155 if ( IsDebuggerPresent() ) {
1156 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1159 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL);
1160 if ( IsDebuggerPresent() ) {
1162 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1163 OutputDebugString(message);
1166 } else if ( IsDebuggerPresent() ) {
1167 OutputDebugString("Found ticket: ");
1168 OutputDebugString(sname->data);
1169 if ( cell && cell->data ) {
1170 OutputDebugString("/");
1171 OutputDebugString(cell->data);
1173 OutputDebugString("@");
1174 OutputDebugString(realm->data);
1175 OutputDebugString("\n");
1177 pkrb5_free_cred_contents(ctx, &creds);
1180 if (cc_code == KRB5_CC_END) {
1181 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1182 if (cc_code) goto loop_cleanup;
1186 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1187 code = pkrb5_cc_set_flags(ctx, cc, flags);
1189 pkrb5_cc_close(ctx,cc);
1193 pkrb5_free_principal(ctx,principal);
1200 pkrb5_free_context(ctx);
1202 pcc_free_NC_info(cc_ctx, &pNCi);
1204 pcc_shutdown(&cc_ctx);
1209 KFW_AFS_get_cred( char * username,
1216 krb5_context ctx = 0;
1218 char * realm = 0, * userrealm = 0;
1219 krb5_principal principal = 0;
1221 krb5_error_code code;
1222 char local_cell[MAXCELLCHARS+1];
1223 char **cells = NULL;
1225 struct afsconf_cell cellconfig;
1229 if (!pkrb5_init_context)
1232 if ( IsDebuggerPresent() ) {
1233 OutputDebugString("KFW_AFS_get_cred for token ");
1234 OutputDebugString(username);
1235 OutputDebugString(" in cell ");
1236 OutputDebugString(cell);
1237 OutputDebugString("\n");
1240 code = pkrb5_init_context(&ctx);
1241 if ( code ) goto cleanup;
1243 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1244 if ( code ) goto cleanup;
1246 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1248 userrealm = strchr(username,'@');
1250 pname = strdup(username);
1251 userrealm = strchr(pname, '@');
1254 /* handle kerberos iv notation */
1255 while ( dot = strchr(pname,'.') ) {
1260 pname = malloc(strlen(username) + strlen(realm) + 2);
1262 strcpy(pname, username);
1264 /* handle kerberos iv notation */
1265 while ( dot = strchr(pname,'.') ) {
1270 strcat(pname,realm);
1272 if ( IsDebuggerPresent() ) {
1273 OutputDebugString("Realm: ");
1274 OutputDebugString(realm);
1275 OutputDebugString("\n");
1278 code = pkrb5_parse_name(ctx, pname, &principal);
1279 if ( code ) goto cleanup;
1281 code = KFW_get_ccache(ctx, principal, &cc);
1282 if ( code ) goto cleanup;
1284 if ( lifetime == 0 )
1285 lifetime = pLeash_get_default_lifetime();
1287 if ( password && password[0] ) {
1288 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1292 pLeash_get_default_forwardable(),
1293 pLeash_get_default_proxiable(),
1294 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1295 pLeash_get_default_noaddresses(),
1296 pLeash_get_default_publicip());
1297 if ( IsDebuggerPresent() ) {
1299 sprintf(message,"KFW_kinit() returns: %d\n",code);
1300 OutputDebugString(message);
1302 if ( code ) goto cleanup;
1304 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1307 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1308 if ( IsDebuggerPresent() ) {
1310 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1311 OutputDebugString(message);
1313 if ( code ) goto cleanup;
1315 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1317 // Attempt to obtain new tokens for other cells supported by the same
1319 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1320 if ( cell_count > 1 ) {
1321 while ( cell_count-- ) {
1322 if ( strcmp(cells[cell_count],cell) ) {
1323 if ( IsDebuggerPresent() ) {
1325 sprintf(message,"found another cell for the same principal: %s\n",cell);
1326 OutputDebugString(message);
1328 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1329 if ( code ) continue;
1331 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1332 if ( IsDebuggerPresent() ) {
1333 OutputDebugString("Realm: ");
1334 OutputDebugString(realm);
1335 OutputDebugString("\n");
1338 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1339 if ( IsDebuggerPresent() ) {
1341 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1342 OutputDebugString(message);
1345 free(cells[cell_count]);
1348 } else if ( cell_count == 1 ) {
1357 pkrb5_cc_close(ctx, cc);
1359 if ( code && reasonP ) {
1360 *reasonP = (char *)perror_message(code);
1366 KFW_AFS_destroy_tickets_for_cell(char * cell)
1368 krb5_context ctx = 0;
1369 krb5_error_code code;
1371 char ** principals = NULL;
1373 if (!pkrb5_init_context)
1376 if ( IsDebuggerPresent() ) {
1377 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1378 OutputDebugString(cell);
1379 OutputDebugString("\n");
1382 code = pkrb5_init_context(&ctx);
1385 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1387 krb5_principal princ = 0;
1391 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1392 if ( cell_count > 1 ) {
1393 // TODO - What we really should do here is verify whether or not any of the
1394 // other cells which use this principal to obtain its credentials actually
1395 // have valid tokens or not. If they are currently using these credentials
1396 // we will skip them. For the time being we assume that if there is an active
1397 // map in the table that they are actively being used.
1401 code = pkrb5_parse_name(ctx, principals[count], &princ);
1402 if (code) goto loop_cleanup;
1404 code = KFW_get_ccache(ctx, princ, &cc);
1405 if (code) goto loop_cleanup;
1407 code = pkrb5_cc_destroy(ctx, cc);
1412 pkrb5_cc_close(ctx, cc);
1416 pkrb5_free_principal(ctx, princ);
1420 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1421 free(principals[count]);
1425 pkrb5_free_context(ctx);
1430 KFW_AFS_destroy_tickets_for_principal(char * user)
1432 krb5_context ctx = 0;
1433 krb5_error_code code;
1435 char ** cells = NULL;
1436 krb5_principal princ = 0;
1439 if (!pkrb5_init_context)
1442 if ( IsDebuggerPresent() ) {
1443 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1444 OutputDebugString(user);
1445 OutputDebugString("\n");
1448 code = pkrb5_init_context(&ctx);
1451 code = pkrb5_parse_name(ctx, user, &princ);
1452 if (code) goto loop_cleanup;
1454 code = KFW_get_ccache(ctx, princ, &cc);
1455 if (code) goto loop_cleanup;
1457 code = pkrb5_cc_destroy(ctx, cc);
1462 pkrb5_cc_close(ctx, cc);
1466 pkrb5_free_principal(ctx, princ);
1470 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1473 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1479 pkrb5_free_context(ctx);
1484 KFW_AFS_renew_expiring_tokens(void)
1486 krb5_error_code code = 0;
1487 krb5_context ctx = 0;
1490 struct principal_ccache_data * pcc_next = princ_cc_data;
1493 const char * realm = NULL;
1494 char local_cell[MAXCELLCHARS+1]="";
1495 struct afsconf_cell cellconfig;
1497 if (!pkrb5_init_context)
1500 if ( pcc_next == NULL ) // nothing to do
1503 if ( IsDebuggerPresent() ) {
1504 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1507 code = pkrb5_init_context(&ctx);
1508 if (code) goto cleanup;
1510 code = pkrb5_timeofday(ctx, &now);
1511 if (code) goto cleanup;
1513 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1514 if ( pcc_next->expired )
1517 if ( now >= (pcc_next->expiration_time) ) {
1518 if ( !pcc_next->from_lsa ) {
1519 pcc_next->expired = 1;
1524 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1525 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1528 code = KFW_renew(ctx,cc);
1530 if ( code && pcc_next->from_lsa)
1532 #endif /* USE_MS2MIT */
1535 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1536 if (code) goto loop_cleanup;
1538 // Attempt to obtain new tokens for other cells supported by the same
1540 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1541 if ( cell_count > 0 ) {
1542 while ( cell_count-- ) {
1543 if ( IsDebuggerPresent() ) {
1544 OutputDebugString("Cell: ");
1545 OutputDebugString(cells[cell_count]);
1546 OutputDebugString("\n");
1548 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1549 if ( code ) continue;
1550 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1551 if ( IsDebuggerPresent() ) {
1552 OutputDebugString("Realm: ");
1553 OutputDebugString(realm);
1554 OutputDebugString("\n");
1556 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1557 if ( IsDebuggerPresent() ) {
1559 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1560 OutputDebugString(message);
1562 free(cells[cell_count]);
1570 pkrb5_cc_close(ctx,cc);
1577 pkrb5_cc_close(ctx,cc);
1579 pkrb5_free_context(ctx);
1586 KFW_AFS_renew_token_for_cell(char * cell)
1588 krb5_error_code code = 0;
1589 krb5_context ctx = 0;
1591 char ** principals = NULL;
1593 if (!pkrb5_init_context)
1596 if ( IsDebuggerPresent() ) {
1597 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1598 OutputDebugString(cell);
1599 OutputDebugString("\n");
1602 code = pkrb5_init_context(&ctx);
1603 if (code) goto cleanup;
1605 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1607 // We know we must have a credential somewhere since we are
1608 // trying to renew a token
1610 KFW_import_ccache_data();
1611 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1614 krb5_principal princ = 0;
1615 krb5_principal service = 0;
1617 krb5_creds mcreds, creds;
1618 #endif /* COMMENT */
1620 const char * realm = NULL;
1621 struct afsconf_cell cellconfig;
1622 char local_cell[MAXCELLCHARS+1];
1625 code = pkrb5_parse_name(ctx, principals[count], &princ);
1626 if (code) goto loop_cleanup;
1628 code = KFW_get_ccache(ctx, princ, &cc);
1629 if (code) goto loop_cleanup;
1631 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1632 if ( code ) goto loop_cleanup;
1634 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1635 if ( IsDebuggerPresent() ) {
1636 OutputDebugString("Realm: ");
1637 OutputDebugString(realm);
1638 OutputDebugString("\n");
1642 /* krb5_cc_remove_cred() is not implemented
1645 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1646 realm, "afs", cell, NULL);
1648 memset(&mcreds, 0, sizeof(krb5_creds));
1649 mcreds.client = princ;
1650 mcreds.server = service;
1652 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1654 if ( IsDebuggerPresent() ) {
1655 char * cname, *sname;
1656 pkrb5_unparse_name(ctx, creds.client, &cname);
1657 pkrb5_unparse_name(ctx, creds.server, &sname);
1658 OutputDebugString("Removing credential for client \"");
1659 OutputDebugString(cname);
1660 OutputDebugString("\" and service \"");
1661 OutputDebugString(sname);
1662 OutputDebugString("\"\n");
1663 pkrb5_free_unparsed_name(ctx,cname);
1664 pkrb5_free_unparsed_name(ctx,sname);
1667 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1668 pkrb5_free_principal(ctx, creds.client);
1669 pkrb5_free_principal(ctx, creds.server);
1672 #endif /* COMMENT */
1674 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1675 if ( IsDebuggerPresent() ) {
1677 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1678 OutputDebugString(message);
1683 pkrb5_cc_close(ctx, cc);
1687 pkrb5_free_principal(ctx, princ);
1691 pkrb5_free_principal(ctx, service);
1695 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1696 free(principals[count]);
1700 code = -1; // we did not renew the tokens
1703 pkrb5_free_context(ctx);
1704 return (code ? FALSE : TRUE);
1709 KFW_AFS_renew_tokens_for_all_cells(void)
1711 struct cell_principal_map * next = cell_princ_map;
1713 if ( IsDebuggerPresent() )
1714 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1719 for ( ; next ; next = next->next ) {
1721 KFW_AFS_renew_token_for_cell(next->cell);
1727 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1729 krb5_error_code code = 0;
1730 krb5_context ctx = 0;
1732 krb5_principal me = 0;
1733 krb5_principal server = 0;
1734 krb5_creds my_creds;
1735 krb5_data *realm = 0;
1737 if (!pkrb5_init_context)
1740 memset(&my_creds, 0, sizeof(krb5_creds));
1745 code = pkrb5_init_context(&ctx);
1746 if (code) goto cleanup;
1752 code = pkrb5_cc_default(ctx, &cc);
1753 if (code) goto cleanup;
1756 code = pkrb5_cc_get_principal(ctx, cc, &me);
1757 if (code) goto cleanup;
1759 realm = krb5_princ_realm(ctx, me);
1761 code = pkrb5_build_principal_ext(ctx, &server,
1762 realm->length,realm->data,
1763 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1764 realm->length,realm->data,
1769 if ( IsDebuggerPresent() ) {
1770 char * cname, *sname;
1771 pkrb5_unparse_name(ctx, me, &cname);
1772 pkrb5_unparse_name(ctx, server, &sname);
1773 OutputDebugString("Renewing credential for client \"");
1774 OutputDebugString(cname);
1775 OutputDebugString("\" and service \"");
1776 OutputDebugString(sname);
1777 OutputDebugString("\"\n");
1778 pkrb5_free_unparsed_name(ctx,cname);
1779 pkrb5_free_unparsed_name(ctx,sname);
1782 my_creds.client = me;
1783 my_creds.server = server;
1785 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1787 if ( IsDebuggerPresent() ) {
1789 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1790 OutputDebugString(message);
1795 code = pkrb5_cc_initialize(ctx, cc, me);
1797 if ( IsDebuggerPresent() ) {
1799 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1800 OutputDebugString(message);
1805 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1807 if ( IsDebuggerPresent() ) {
1809 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1810 OutputDebugString(message);
1816 if (my_creds.client == me)
1817 my_creds.client = 0;
1818 if (my_creds.server == server)
1819 my_creds.server = 0;
1820 pkrb5_free_cred_contents(ctx, &my_creds);
1822 pkrb5_free_principal(ctx, me);
1824 pkrb5_free_principal(ctx, server);
1825 if (cc && (cc != alt_cc))
1826 pkrb5_cc_close(ctx, cc);
1827 if (ctx && (ctx != alt_ctx))
1828 pkrb5_free_context(ctx);
1833 KFW_kinit( krb5_context alt_ctx,
1836 char *principal_name,
1838 krb5_deltat lifetime,
1841 krb5_deltat renew_life,
1846 krb5_error_code code = 0;
1847 krb5_context ctx = 0;
1849 krb5_principal me = 0;
1851 krb5_creds my_creds;
1852 krb5_get_init_creds_opt options;
1853 krb5_address ** addrs = NULL;
1854 int i = 0, addr_count = 0;
1856 if (!pkrb5_init_context)
1859 pkrb5_get_init_creds_opt_init(&options);
1860 memset(&my_creds, 0, sizeof(my_creds));
1868 code = pkrb5_init_context(&ctx);
1869 if (code) goto cleanup;
1875 code = pkrb5_cc_default(ctx, &cc);
1876 if (code) goto cleanup;
1879 code = pkrb5_parse_name(ctx, principal_name, &me);
1883 code = pkrb5_unparse_name(ctx, me, &name);
1888 lifetime = pLeash_get_default_lifetime();
1895 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1896 pkrb5_get_init_creds_opt_set_forwardable(&options,
1897 forwardable ? 1 : 0);
1898 pkrb5_get_init_creds_opt_set_proxiable(&options,
1900 pkrb5_get_init_creds_opt_set_renew_life(&options,
1903 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1907 // we are going to add the public IP address specified by the user
1908 // to the list provided by the operating system
1909 krb5_address ** local_addrs=NULL;
1912 pkrb5_os_localaddr(ctx, &local_addrs);
1913 while ( local_addrs[i++] );
1916 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1918 pkrb5_free_addresses(ctx, local_addrs);
1921 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1923 while ( local_addrs[i] ) {
1924 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1925 if (addrs[i] == NULL) {
1926 pkrb5_free_addresses(ctx, local_addrs);
1930 addrs[i]->magic = local_addrs[i]->magic;
1931 addrs[i]->addrtype = local_addrs[i]->addrtype;
1932 addrs[i]->length = local_addrs[i]->length;
1933 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1934 if (!addrs[i]->contents) {
1935 pkrb5_free_addresses(ctx, local_addrs);
1939 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1940 local_addrs[i]->length); /* safe */
1943 pkrb5_free_addresses(ctx, local_addrs);
1945 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1946 if (addrs[i] == NULL)
1949 addrs[i]->magic = KV5M_ADDRESS;
1950 addrs[i]->addrtype = AF_INET;
1951 addrs[i]->length = 4;
1952 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1953 if (!addrs[i]->contents)
1956 netIPAddr = htonl(publicIP);
1957 memcpy(addrs[i]->contents,&netIPAddr,4);
1959 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1964 code = pkrb5_get_init_creds_password(ctx,
1967 password, // password
1968 KRB5_prompter, // prompter
1969 hParent, // prompter data
1976 code = pkrb5_cc_initialize(ctx, cc, me);
1980 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1986 for ( i=0;i<addr_count;i++ ) {
1988 if ( addrs[i]->contents )
1989 free(addrs[i]->contents);
1994 if (my_creds.client == me)
1995 my_creds.client = 0;
1996 pkrb5_free_cred_contents(ctx, &my_creds);
1998 pkrb5_free_unparsed_name(ctx, name);
2000 pkrb5_free_principal(ctx, me);
2001 if (cc && (cc != alt_cc))
2002 pkrb5_cc_close(ctx, cc);
2003 if (ctx && (ctx != alt_ctx))
2004 pkrb5_free_context(ctx);
2010 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2014 krb5_error_code code;
2016 if (!pkrb5_init_context)
2025 code = pkrb5_init_context(&ctx);
2026 if (code) goto cleanup;
2032 code = pkrb5_cc_default(ctx, &cc);
2033 if (code) goto cleanup;
2036 code = pkrb5_cc_destroy(ctx, cc);
2037 if ( !code ) cc = 0;
2040 if (cc && (cc != alt_cc))
2041 pkrb5_cc_close(ctx, cc);
2042 if (ctx && (ctx != alt_ctx))
2043 pkrb5_free_context(ctx);
2051 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2053 NTSTATUS Status = 0;
2055 TOKEN_STATISTICS Stats;
2061 *ppSessionData = NULL;
2063 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2067 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2068 CloseHandle( TokenHandle );
2072 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2073 if ( FAILED(Status) || !ppSessionData )
2080 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2081 // cache. It validates whether or not it is reasonable to assume that if we
2082 // attempted to retrieve valid tickets we could do so. Microsoft does not
2083 // automatically renew expired tickets. Therefore, the cache could contain
2084 // expired or invalid tickets. Microsoft also caches the user's password
2085 // and will use it to retrieve new TGTs if the cache is empty and tickets
2089 MSLSA_IsKerberosLogon(VOID)
2091 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2092 BOOL Success = FALSE;
2094 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2095 if ( pSessionData->AuthenticationPackage.Buffer ) {
2101 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2102 usLength = (pSessionData->AuthenticationPackage).Length;
2105 lstrcpynW (buffer, usBuffer, usLength);
2106 lstrcatW (buffer,L"");
2107 if ( !lstrcmpW(L"Kerberos",buffer) )
2111 pLsaFreeReturnBuffer(pSessionData);
2115 #endif /* USE_MS2MIT */
2117 static BOOL CALLBACK
2118 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2122 switch ( message ) {
2124 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2126 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2129 for ( i=0; i < mid_cnt ; i++ ) {
2130 if (mid_tb[i].echo == 0)
2131 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2132 else if (mid_tb[i].echo == 2)
2133 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2138 switch ( LOWORD(wParam) ) {
2140 for ( i=0; i < mid_cnt ; i++ ) {
2141 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2142 *mid_tb[i].buf = '\0';
2146 EndDialog(hDialog, LOWORD(wParam));
2154 lpwAlign( LPWORD lpIn )
2158 ul = (ULONG_PTR) lpIn;
2162 return (LPWORD) ul;;
2166 * dialog widths are measured in 1/4 character widths
2167 * dialog height are measured in 1/8 character heights
2171 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2172 char * ptext[], int numlines, int width,
2173 int tb_cnt, struct textField * tb)
2177 LPDLGITEMTEMPLATE lpdit;
2183 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2190 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2192 // Define a dialog box.
2194 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2195 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2196 | DS_SETFOREGROUND | DS_3DLOOK
2197 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2198 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2201 lpdt->cx = 20 + width * 4;
2202 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2204 lpw = (LPWORD) (lpdt + 1);
2205 *lpw++ = 0; // no menu
2206 *lpw++ = 0; // predefined dialog box class (by default)
2208 lpwsz = (LPWSTR) lpw;
2209 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2211 *lpw++ = 8; // font size (points)
2212 lpwsz = (LPWSTR) lpw;
2213 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2217 //-----------------------
2218 // Define an OK button.
2219 //-----------------------
2220 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2221 lpdit = (LPDLGITEMTEMPLATE) lpw;
2222 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2223 lpdit->dwExtendedStyle = 0;
2224 lpdit->x = (lpdt->cx - 14)/4 - 20;
2225 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2228 lpdit->id = IDOK; // OK button identifier
2230 lpw = (LPWORD) (lpdit + 1);
2232 *lpw++ = 0x0080; // button class
2234 lpwsz = (LPWSTR) lpw;
2235 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2237 *lpw++ = 0; // no creation data
2239 //-----------------------
2240 // Define an Cancel button.
2241 //-----------------------
2242 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2243 lpdit = (LPDLGITEMTEMPLATE) lpw;
2244 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2245 lpdit->dwExtendedStyle = 0;
2246 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2247 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2250 lpdit->id = IDCANCEL; // CANCEL button identifier
2252 lpw = (LPWORD) (lpdit + 1);
2254 *lpw++ = 0x0080; // button class
2256 lpwsz = (LPWSTR) lpw;
2257 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2259 *lpw++ = 0; // no creation data
2261 /* Add controls for preface data */
2262 for ( i=0; i<numlines; i++) {
2263 /*-----------------------
2264 * Define a static text control.
2265 *-----------------------*/
2266 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2267 lpdit = (LPDLGITEMTEMPLATE) lpw;
2268 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2269 lpdit->dwExtendedStyle = 0;
2271 lpdit->y = 10 + i * 14;
2272 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2274 lpdit->id = ID_TEXT + i; // text identifier
2276 lpw = (LPWORD) (lpdit + 1);
2278 *lpw++ = 0x0082; // static class
2280 lpwsz = (LPWSTR) lpw;
2281 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2282 -1, lpwsz, 2*width);
2284 *lpw++ = 0; // no creation data
2287 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2288 int len = (int)strlen(tb[i].label);
2293 for ( i=0; i<tb_cnt; i++) {
2295 /*-----------------------
2296 * Define a static text control.
2297 *-----------------------*/
2298 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2299 lpdit = (LPDLGITEMTEMPLATE) lpw;
2300 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2301 lpdit->dwExtendedStyle = 0;
2303 lpdit->y = 10 + (numlines + i + 1) * 14;
2304 lpdit->cx = pwid * 4;
2306 lpdit->id = ID_TEXT + numlines + i; // text identifier
2308 lpw = (LPWORD) (lpdit + 1);
2310 *lpw++ = 0x0082; // static class
2312 lpwsz = (LPWSTR) lpw;
2313 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2316 *lpw++ = 0; // no creation data
2318 /*-----------------------
2319 * Define an edit control.
2320 *-----------------------*/
2321 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2322 lpdit = (LPDLGITEMTEMPLATE) lpw;
2323 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2324 lpdit->dwExtendedStyle = 0;
2325 lpdit->x = 10 + (pwid + 1) * 4;
2326 lpdit->y = 10 + (numlines + i + 1) * 14;
2327 lpdit->cx = (width - (pwid + 1)) * 4;
2329 lpdit->id = ID_MID_TEXT + i; // identifier
2331 lpw = (LPWORD) (lpdit + 1);
2333 *lpw++ = 0x0081; // edit class
2335 lpwsz = (LPWSTR) lpw;
2336 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2339 *lpw++ = 0; // no creation data
2343 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2344 hwndOwner, (DLGPROC) MultiInputDialogProc);
2348 case 0: /* Timeout */
2356 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2357 MessageBox(hwndOwner,
2360 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2367 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2369 HINSTANCE hInst = 0;
2373 char * plines[16], *p = preface ? preface : "";
2376 for ( i=0; i<16; i++ )
2379 while (*p && numlines < 16) {
2380 plines[numlines++] = p;
2381 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2382 if ( *p == '\r' && *(p+1) == '\n' ) {
2385 } else if ( *p == '\n' ) {
2388 if ( strlen(plines[numlines-1]) > maxwidth )
2389 maxwidth = (int)strlen(plines[numlines-1]);
2392 for ( i=0;i<n;i++ ) {
2393 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2394 if ( maxwidth < len )
2398 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2401 static krb5_error_code KRB5_CALLCONV
2402 KRB5_prompter( krb5_context context,
2407 krb5_prompt prompts[])
2409 krb5_error_code errcode = 0;
2411 struct textField * tb = NULL;
2412 int len = 0, blen=0, nlen=0;
2413 HWND hParent = (HWND)data;
2416 nlen = (int)strlen(name)+2;
2419 blen = (int)strlen(banner)+2;
2421 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2424 memset(tb,0,sizeof(struct textField) * num_prompts);
2425 for ( i=0; i < num_prompts; i++ ) {
2426 tb[i].buf = prompts[i].reply->data;
2427 tb[i].len = prompts[i].reply->length;
2428 tb[i].label = prompts[i].prompt;
2430 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2433 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2435 for ( i=0; i < num_prompts; i++ )
2436 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2444 for (i = 0; i < num_prompts; i++) {
2445 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2452 KFW_AFS_wait_for_service_start(void)
2457 CurrentState = SERVICE_START_PENDING;
2458 memset(HostName, '\0', sizeof(HostName));
2459 gethostname(HostName, sizeof(HostName));
2461 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2463 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2465 if ( IsDebuggerPresent() ) {
2466 switch ( CurrentState ) {
2467 case SERVICE_STOPPED:
2468 OutputDebugString("SERVICE_STOPPED\n");
2470 case SERVICE_START_PENDING:
2471 OutputDebugString("SERVICE_START_PENDING\n");
2473 case SERVICE_STOP_PENDING:
2474 OutputDebugString("SERVICE_STOP_PENDING\n");
2476 case SERVICE_RUNNING:
2477 OutputDebugString("SERVICE_RUNNING\n");
2479 case SERVICE_CONTINUE_PENDING:
2480 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2482 case SERVICE_PAUSE_PENDING:
2483 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2485 case SERVICE_PAUSED:
2486 OutputDebugString("SERVICE_PAUSED\n");
2489 OutputDebugString("UNKNOWN Service State\n");
2492 if (CurrentState == SERVICE_STOPPED)
2494 if (CurrentState == SERVICE_RUNNING)
2510 memset(HostName, '\0', sizeof(HostName));
2511 gethostname(HostName, sizeof(HostName));
2512 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2514 if (CurrentState != SERVICE_RUNNING)
2517 rc = ktc_ForgetAllTokens();
2523 #define ALLOW_REGISTER 1
2525 ViceIDToUsername(char *username,
2526 char *realm_of_user,
2527 char *realm_of_cell,
2529 struct ktc_principal *aclient,
2530 struct ktc_principal *aserver,
2531 struct ktc_token *atoken)
2533 static char lastcell[MAXCELLCHARS+1] = { 0 };
2534 static char confname[512] = { 0 };
2535 #ifdef AFS_ID_TO_NAME
2536 char username_copy[BUFSIZ];
2537 #endif /* AFS_ID_TO_NAME */
2538 long viceId = ANONYMOUSID; /* AFS uid of user */
2540 #ifdef ALLOW_REGISTER
2542 #endif /* ALLOW_REGISTER */
2544 if (confname[0] == '\0') {
2545 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2546 confname[sizeof(confname) - 2] = '\0';
2549 strcpy(lastcell, aserver->cell);
2551 if (!pr_Initialize (0, confname, aserver->cell)) {
2552 char sname[PR_MAXNAMELEN];
2553 strncpy(sname, username, PR_MAXNAMELEN);
2554 sname[PR_MAXNAMELEN-1] = '\0';
2555 status = pr_SNameToId (sname, &viceId);
2560 * This is a crock, but it is Transarc's crock, so
2561 * we have to play along in order to get the
2562 * functionality. The way the afs id is stored is
2563 * as a string in the username field of the token.
2564 * Contrary to what you may think by looking at
2565 * the code for tokens, this hack (AFS ID %d) will
2566 * not work if you change %d to something else.
2570 * This code is taken from cklog -- it lets people
2571 * automatically register with the ptserver in foreign cells
2574 #ifdef ALLOW_REGISTER
2576 if (viceId != ANONYMOUSID) {
2577 #else /* ALLOW_REGISTER */
2578 if ((status == 0) && (viceId != ANONYMOUSID))
2579 #endif /* ALLOW_REGISTER */
2581 #ifdef AFS_ID_TO_NAME
2582 strncpy(username_copy, username, BUFSIZ);
2583 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2584 #endif /* AFS_ID_TO_NAME */
2586 #ifdef ALLOW_REGISTER
2587 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2589 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2590 strcpy(aclient->instance, "");
2591 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2592 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2594 if (status = pr_Initialize(1L, confname, aserver->cell))
2596 status = pr_CreateUser(username, &id);
2600 #ifdef AFS_ID_TO_NAME
2601 strncpy(username_copy, username, BUFSIZ);
2602 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2603 #endif /* AFS_ID_TO_NAME */
2606 #endif /* ALLOW_REGISTER */
2613 krb5_context alt_ctx,
2618 int lifetime, /* unused parameter */
2626 #endif /* USE_KRB4 */
2627 struct ktc_principal aserver;
2628 struct ktc_principal aclient;
2629 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2630 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2631 char local_cell[MAXCELLCHARS+1];
2632 char Dmycell[MAXCELLCHARS+1];
2633 struct ktc_token atoken;
2634 struct ktc_token btoken;
2635 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2636 char RealmName[128];
2638 char ServiceName[128];
2642 krb5_context ctx = 0;
2645 krb5_creds * k5creds = 0;
2646 krb5_error_code code;
2647 krb5_principal client_principal = 0;
2652 memset(HostName, '\0', sizeof(HostName));
2653 gethostname(HostName, sizeof(HostName));
2654 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2655 if ( IsDebuggerPresent() )
2656 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2659 if (CurrentState != SERVICE_RUNNING) {
2660 if ( IsDebuggerPresent() )
2661 OutputDebugString("AFSD Service NOT RUNNING\n");
2665 if (!pkrb5_init_context)
2668 memset(RealmName, '\0', sizeof(RealmName));
2669 memset(CellName, '\0', sizeof(CellName));
2670 memset(ServiceName, '\0', sizeof(ServiceName));
2671 memset(realm_of_user, '\0', sizeof(realm_of_user));
2672 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2673 if (cell && cell[0])
2674 strcpy(Dmycell, cell);
2676 memset(Dmycell, '\0', sizeof(Dmycell));
2678 // NULL or empty cell returns information on local cell
2679 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2681 // KFW_AFS_error(rc, "get_cellconfig()");
2688 code = pkrb5_init_context(&ctx);
2689 if (code) goto cleanup;
2695 code = pkrb5_cc_default(ctx, &cc);
2696 if (code) goto skip_krb5_init;
2699 memset((char *)&increds, 0, sizeof(increds));
2701 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2703 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2705 OutputDebugString("Principal Not Found for ccache\n");
2707 goto skip_krb5_init;
2710 /* look for client principals which cannot be distinguished
2711 * from Kerberos 4 multi-component principal names
2713 k5data = krb5_princ_component(ctx,client_principal,0);
2714 for ( i=0; i<k5data->length; i++ ) {
2715 if ( k5data->data[i] == '.' )
2718 if (i != k5data->length)
2720 OutputDebugString("Illegal Principal name contains dot in first component\n");
2721 rc = KRB5KRB_ERR_GENERIC;
2725 i = krb5_princ_realm(ctx, client_principal)->length;
2728 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2729 realm_of_user[i] = 0;
2734 if ( !try_krb5 || !realm_of_user[0] ) {
2735 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2744 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2746 if (strlen(service) == 0)
2747 strcpy(ServiceName, "afs");
2749 strcpy(ServiceName, service);
2751 if (strlen(cell) == 0)
2752 strcpy(CellName, local_cell);
2754 strcpy(CellName, cell);
2756 if (strlen(realm) == 0)
2757 strcpy(RealmName, realm_of_cell);
2759 strcpy(RealmName, realm);
2761 memset(&creds, '\0', sizeof(creds));
2766 /* First try service/cell@REALM */
2767 if (code = pkrb5_build_principal(ctx, &increds.server,
2768 (int)strlen(RealmName),
2777 increds.client = client_principal;
2778 increds.times.endtime = 0;
2779 /* Ask for DES since that is what V4 understands */
2780 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2783 if ( IsDebuggerPresent() ) {
2784 char * cname, *sname;
2785 pkrb5_unparse_name(ctx, increds.client, &cname);
2786 pkrb5_unparse_name(ctx, increds.server, &sname);
2787 OutputDebugString("Getting tickets for \"");
2788 OutputDebugString(cname);
2789 OutputDebugString("\" and service \"");
2790 OutputDebugString(sname);
2791 OutputDebugString("\"\n");
2792 pkrb5_free_unparsed_name(ctx,cname);
2793 pkrb5_free_unparsed_name(ctx,sname);
2796 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2797 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2798 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2799 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2800 /* Or service@REALM */
2801 pkrb5_free_principal(ctx,increds.server);
2803 code = pkrb5_build_principal(ctx, &increds.server,
2804 (int)strlen(RealmName),
2809 if ( IsDebuggerPresent() ) {
2810 char * cname, *sname;
2811 pkrb5_unparse_name(ctx, increds.client, &cname);
2812 pkrb5_unparse_name(ctx, increds.server, &sname);
2813 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2814 OutputDebugString("Trying again: getting tickets for \"");
2815 OutputDebugString(cname);
2816 OutputDebugString("\" and service \"");
2817 OutputDebugString(sname);
2818 OutputDebugString("\"\n");
2819 pkrb5_free_unparsed_name(ctx,cname);
2820 pkrb5_free_unparsed_name(ctx,sname);
2824 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2827 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2828 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2829 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2830 strcmp(RealmName, realm_of_cell)) {
2831 /* Or service/cell@REALM_OF_CELL */
2832 strcpy(RealmName, realm_of_cell);
2833 pkrb5_free_principal(ctx,increds.server);
2835 code = pkrb5_build_principal(ctx, &increds.server,
2836 (int)strlen(RealmName),
2842 if ( IsDebuggerPresent() ) {
2843 char * cname, *sname;
2844 pkrb5_unparse_name(ctx, increds.client, &cname);
2845 pkrb5_unparse_name(ctx, increds.server, &sname);
2846 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2847 OutputDebugString("Trying again: getting tickets for \"");
2848 OutputDebugString(cname);
2849 OutputDebugString("\" and service \"");
2850 OutputDebugString(sname);
2851 OutputDebugString("\"\n");
2852 pkrb5_free_unparsed_name(ctx,cname);
2853 pkrb5_free_unparsed_name(ctx,sname);
2857 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2860 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2861 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2862 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2863 /* Or service@REALM_OF_CELL */
2864 pkrb5_free_principal(ctx,increds.server);
2866 code = pkrb5_build_principal(ctx, &increds.server,
2867 (int)strlen(RealmName),
2872 if ( IsDebuggerPresent() ) {
2873 char * cname, *sname;
2874 pkrb5_unparse_name(ctx, increds.client, &cname);
2875 pkrb5_unparse_name(ctx, increds.server, &sname);
2876 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2877 OutputDebugString("Trying again: getting tickets for \"");
2878 OutputDebugString(cname);
2879 OutputDebugString("\" and service \"");
2880 OutputDebugString(sname);
2881 OutputDebugString("\"\n");
2882 pkrb5_free_unparsed_name(ctx,cname);
2883 pkrb5_free_unparsed_name(ctx,sname);
2887 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2892 if ( IsDebuggerPresent() ) {
2894 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2895 OutputDebugString(message);
2901 /* This code inserts the entire K5 ticket into the token
2902 * No need to perform a krb524 translation which is
2903 * commented out in the code below
2905 if (KFW_use_krb524() ||
2906 k5creds->ticket.length > MAXKTCTICKETLEN)
2909 memset(&aserver, '\0', sizeof(aserver));
2910 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2911 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2913 memset(&atoken, '\0', sizeof(atoken));
2914 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2915 atoken.startTime = k5creds->times.starttime;
2916 atoken.endTime = k5creds->times.endtime;
2917 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2918 atoken.ticketLen = k5creds->ticket.length;
2919 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2922 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2923 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2924 if ( rc == KTC_NOCM && retry < 20 ) {
2927 goto retry_gettoken5;
2932 if (atoken.kvno == btoken.kvno &&
2933 atoken.ticketLen == btoken.ticketLen &&
2934 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2935 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2937 /* Success - Nothing to do */
2941 // * Reset the "aclient" structure before we call ktc_SetToken.
2942 // * This structure was first set by the ktc_GetToken call when
2943 // * we were comparing whether identical tokens already existed.
2945 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2946 strncpy(aclient.name, k5creds->client->data[0].data, len);
2947 aclient.name[len] = '\0';
2949 if ( k5creds->client->length > 1 ) {
2951 strcat(aclient.name, ".");
2952 p = aclient.name + strlen(aclient.name);
2953 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2954 strncpy(p, k5creds->client->data[1].data, len);
2957 aclient.instance[0] = '\0';
2959 strcpy(aclient.cell, realm_of_cell);
2961 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
2962 /* For Khimaira, always append the realm name */
2963 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
2965 strcat(aclient.name, "@");
2966 p = aclient.name + strlen(aclient.name);
2967 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2968 strncpy(p, k5creds->client->realm.data, len);
2972 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2973 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2974 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2975 &aclient, &aserver, &atoken);
2978 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
2979 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
2981 aclient.smbname[0] = '\0';
2984 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2986 goto cleanup; /* We have successfully inserted the token */
2989 /* Otherwise, the ticket could have been too large so try to
2990 * convert using the krb524d running with the KDC
2992 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2993 pkrb5_free_creds(ctx, k5creds);
2995 if ( IsDebuggerPresent() ) {
2997 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2998 OutputDebugString(message);
3006 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3007 if (code == NO_TKT_FIL) {
3008 // if the problem is that we have no krb4 tickets
3009 // do not attempt to continue
3012 if (code != KSUCCESS)
3013 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3015 if (code != KSUCCESS)
3017 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3019 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3024 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3026 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3041 memset(&aserver, '\0', sizeof(aserver));
3042 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3043 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3045 memset(&atoken, '\0', sizeof(atoken));
3046 atoken.kvno = creds.kvno;
3047 atoken.startTime = creds.issue_date;
3048 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3049 memcpy(&atoken.sessionKey, creds.session, 8);
3050 atoken.ticketLen = creds.ticket_st.length;
3051 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3054 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3055 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3056 if ( rc == KTC_NOCM && retry < 20 ) {
3059 goto retry_gettoken;
3061 KFW_AFS_error(rc, "ktc_GetToken()");
3066 if (atoken.kvno == btoken.kvno &&
3067 atoken.ticketLen == btoken.ticketLen &&
3068 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3069 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3074 // * Reset the "aclient" structure before we call ktc_SetToken.
3075 // * This structure was first set by the ktc_GetToken call when
3076 // * we were comparing whether identical tokens already existed.
3078 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3081 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3082 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3084 strcpy(aclient.instance, "");
3086 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3087 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3088 aclient.name[MAXKTCREALMLEN-1] = '\0';
3090 strcpy(aclient.cell, CellName);
3092 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3093 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3094 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3095 &aclient, &aserver, &atoken);
3098 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3099 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3101 aclient.smbname[0] = '\0';
3104 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3106 KFW_AFS_error(rc, "ktc_SetToken()");
3112 if (client_principal)
3113 pkrb5_free_principal(ctx,client_principal);
3114 /* increds.client == client_principal */
3116 pkrb5_free_principal(ctx,increds.server);
3117 if (cc && (cc != alt_cc))
3118 pkrb5_cc_close(ctx, cc);
3119 if (ctx && (ctx != alt_ctx))
3120 pkrb5_free_context(ctx);
3122 return(rc? rc : code);
3125 /**************************************/
3126 /* afs_realm_of_cell(): */
3127 /**************************************/
3129 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3131 static char krbrlm[REALM_SZ+1]="";
3132 char ** realmlist=NULL;
3138 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3139 if ( !r && realmlist && realmlist[0] ) {
3140 strcpy(krbrlm, realmlist[0]);
3141 pkrb5_free_host_realm(ctx, realmlist);
3147 char *t = cellconfig->name;
3152 if (islower(c)) c=toupper(c);
3160 /**************************************/
3161 /* KFW_AFS_get_cellconfig(): */
3162 /**************************************/
3164 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3167 char newcell[MAXCELLCHARS+1];
3169 local_cell[0] = (char)0;
3170 memset(cellconfig, 0, sizeof(*cellconfig));
3172 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3173 if (rc = cm_GetRootCellName(local_cell))
3178 if (strlen(cell) == 0)
3179 strcpy(cell, local_cell);
3181 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3182 strcpy(cellconfig->name, cell);
3184 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3185 #ifdef AFS_AFSDB_ENV
3188 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3194 /**************************************/
3195 /* get_cellconfig_callback(): */
3196 /**************************************/
3198 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3200 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3202 cc->hostAddr[cc->numServers] = *addrp;
3203 strcpy(cc->hostName[cc->numServers], namep);
3209 /**************************************/
3210 /* KFW_AFS_error(): */
3211 /**************************************/
3213 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3216 const char *errText;
3218 // Using AFS defines as error messages for now, until Transarc
3219 // gets back to me with "string" translations of each of these
3221 if (rc == KTC_ERROR)
3222 errText = "KTC_ERROR";
3223 else if (rc == KTC_TOOBIG)
3224 errText = "KTC_TOOBIG";
3225 else if (rc == KTC_INVAL)
3226 errText = "KTC_INVAL";
3227 else if (rc == KTC_NOENT)
3228 errText = "KTC_NOENT";
3229 else if (rc == KTC_PIOCTLFAIL)
3230 errText = "KTC_PIOCTLFAIL";
3231 else if (rc == KTC_NOPIOCTL)
3232 errText = "KTC_NOPIOCTL";
3233 else if (rc == KTC_NOCELL)
3234 errText = "KTC_NOCELL";
3235 else if (rc == KTC_NOCM)
3236 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3238 errText = "Unknown error!";
3240 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3242 if ( IsDebuggerPresent() ) {
3243 OutputDebugString(message);
3244 OutputDebugString("\n");
3246 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3252 LPSTR lpszMachineName,
3253 LPSTR lpszServiceName,
3254 DWORD *lpdwCurrentState)
3257 SC_HANDLE schSCManager = NULL;
3258 SC_HANDLE schService = NULL;
3259 DWORD fdwDesiredAccess = 0;
3260 SERVICE_STATUS ssServiceStatus = {0};
3263 *lpdwCurrentState = 0;
3265 fdwDesiredAccess = GENERIC_READ;
3267 schSCManager = OpenSCManager(lpszMachineName,
3271 if(schSCManager == NULL)
3273 hr = GetLastError();
3277 schService = OpenService(schSCManager,
3281 if(schService == NULL)
3283 hr = GetLastError();
3287 fRet = QueryServiceStatus(schService,
3292 hr = GetLastError();
3296 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3300 CloseServiceHandle(schService);
3301 CloseServiceHandle(schSCManager);
3314 for (n = 0; fi[n].func_ptr_var; n++)
3315 *(fi[n].func_ptr_var) = 0;
3316 if (h) FreeLibrary(h);
3321 const char* dll_name,
3323 HINSTANCE* ph, // [out, optional] - DLL handle
3324 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3325 int cleanup, // cleanup function pointers and unload on error
3326 int go_on, // continue loading even if some functions cannot be loaded
3327 int silent // do not pop-up a system dialog if DLL cannot be loaded
3336 if (pindex) *pindex = -1;
3338 for (n = 0; fi[n].func_ptr_var; n++)
3339 *(fi[n].func_ptr_var) = 0;
3342 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3343 h = LoadLibrary(dll_name);
3351 for (i = 0; (go_on || !error) && (i < n); i++)
3353 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3359 *(fi[i].func_ptr_var) = p;
3362 if (pindex) *pindex = last_i;
3363 if (error && cleanup && !go_on) {
3364 for (i = 0; i < n; i++) {
3365 *(fi[i].func_ptr_var) = 0;
3371 if (error) return 0;
3375 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3377 krb5_context ctx = 0;
3379 krb5_error_code code;
3381 const char * realm = 0;
3382 krb5_principal principal = 0;
3384 char password[PROBE_PASSWORD_LEN+1];
3385 BOOL serverReachable = 0;
3387 if (!pkrb5_init_context)
3390 code = pkrb5_init_context(&ctx);
3391 if (code) goto cleanup;
3394 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3396 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3397 realm, PROBE_USERNAME, NULL, NULL);
3398 if ( code ) goto cleanup;
3400 code = KFW_get_ccache(ctx, principal, &cc);
3401 if ( code ) goto cleanup;
3403 code = pkrb5_unparse_name(ctx, principal, &pname);
3404 if ( code ) goto cleanup;
3406 pwdata.data = password;
3407 pwdata.length = PROBE_PASSWORD_LEN;
3408 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3411 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3414 password[PROBE_PASSWORD_LEN] = '\0';
3416 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3426 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3427 case KRB5KDC_ERR_CLIENT_REVOKED:
3428 case KRB5KDC_ERR_CLIENT_NOTYET:
3429 case KRB5KDC_ERR_PREAUTH_FAILED:
3430 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3431 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3432 serverReachable = TRUE;
3435 serverReachable = FALSE;
3440 pkrb5_free_unparsed_name(ctx,pname);
3442 pkrb5_free_principal(ctx,principal);
3444 pkrb5_cc_close(ctx,cc);
3446 pkrb5_free_context(ctx);
3448 return serverReachable;
3452 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3454 krb5_context ctx = 0;
3455 krb5_error_code code;
3456 krb5_ccache mslsa_ccache=0;
3457 krb5_principal princ = 0;
3461 if (!KFW_is_available())
3464 if (code = pkrb5_init_context(&ctx))
3467 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3470 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3473 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3476 if ( strlen(pname) < *dwSize ) {
3477 strncpy(szUser, pname, *dwSize);
3478 szUser[*dwSize-1] = '\0';
3481 *dwSize = (DWORD)strlen(pname);
3485 pkrb5_free_unparsed_name(ctx, pname);
3488 pkrb5_free_principal(ctx, princ);
3491 pkrb5_cc_close(ctx, mslsa_ccache);
3494 pkrb5_free_context(ctx);
3499 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3501 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3502 PSID pSystemSID = NULL;
3503 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3504 PACL ccacheACL = NULL;
3505 DWORD ccacheACLlength = 0;
3506 PTOKEN_USER pTokenUser = NULL;
3515 /* Get System SID */
3516 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3522 SystemSIDlength = GetLengthSid(pSystemSID);
3523 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3524 + SystemSIDlength - sizeof(DWORD);
3527 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3529 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3530 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3532 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3537 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3539 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3544 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3549 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3550 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3551 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3554 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3555 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3556 pTokenUser->User.Sid);
3557 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3558 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3563 gle = GetLastError();
3564 if (gle != ERROR_NO_TOKEN)
3567 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3568 OWNER_SECURITY_INFORMATION,
3569 pTokenUser->User.Sid,
3573 gle = GetLastError();
3574 if (gle != ERROR_NO_TOKEN)
3578 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3579 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3584 gle = GetLastError();
3585 if (gle != ERROR_NO_TOKEN)
3592 LocalFree(pSystemSID);
3594 LocalFree(pTokenUser);
3596 LocalFree(ccacheACL);
3601 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3604 DWORD dwSize = size-1; /* leave room for nul */
3607 if (!hUserToken || !newfilename || size <= 0)
3610 *newfilename = '\0';
3612 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3613 if ( !dwLen || dwLen > dwSize )
3614 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3615 if ( !dwLen || dwLen > dwSize )
3618 newfilename[dwSize] = '\0';
3623 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3625 char filename[MAX_PATH] = "";
3627 char cachename[MAX_PATH + 8] = "FILE:";
3628 krb5_context ctx = 0;
3629 krb5_error_code code;
3630 krb5_principal princ = 0;
3632 krb5_ccache ncc = 0;
3634 if (!pkrb5_init_context || !user || !szLogonId)
3637 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3638 if ( count > sizeof(filename) || count == 0 ) {
3639 GetWindowsDirectory(filename, sizeof(filename));
3642 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3645 strcat(filename, "\\");
3646 strcat(filename, szLogonId);
3648 strcat(cachename, filename);
3650 DeleteFile(filename);
3652 code = pkrb5_init_context(&ctx);
3655 code = pkrb5_parse_name(ctx, user, &princ);
3656 if (code) goto cleanup;
3658 code = KFW_get_ccache(ctx, princ, &cc);
3659 if (code) goto cleanup;
3661 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3662 if (code) goto cleanup;
3664 code = pkrb5_cc_initialize(ctx, ncc, princ);
3665 if (code) goto cleanup;
3667 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3668 if (code) goto cleanup;
3670 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3674 pkrb5_cc_close(ctx, cc);
3678 pkrb5_cc_close(ctx, ncc);
3682 pkrb5_free_principal(ctx, princ);
3687 pkrb5_free_context(ctx);
3691 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3693 char cachename[MAX_PATH + 8] = "FILE:";
3694 krb5_context ctx = 0;
3695 krb5_error_code code;
3696 krb5_principal princ = 0;
3698 krb5_ccache ncc = 0;
3701 if (!pkrb5_init_context || !filename)
3704 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3707 strcat(cachename, filename);
3709 code = pkrb5_init_context(&ctx);
3712 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3713 if (code) goto cleanup;
3715 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3717 code = pkrb5_cc_default(ctx, &ncc);
3719 code = pkrb5_cc_initialize(ctx, ncc, princ);
3722 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3725 pkrb5_cc_close(ctx, ncc);
3729 retval=0; /* success */
3733 pkrb5_cc_close(ctx, cc);
3737 DeleteFile(filename);
3740 pkrb5_free_principal(ctx, princ);
3745 pkrb5_free_context(ctx);
3750 /* We are including this
3752 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3753 fixed part of rande of the one byte lifetime field. Values less than 0x80
3754 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3755 0xBF should be looked up in this table. The value of 0x80 is the same using
3756 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3757 The intervening values of have a fixed ratio of roughly 1.06914. The value
3758 oxFF is defined to mean a ticket has no expiration time. This should be
3759 used advisedly since individual servers may impose defacto upperbounds on
3760 ticket lifetimes. */
3762 #define TKTLIFENUMFIXED 64
3763 #define TKTLIFEMINFIXED 0x80
3764 #define TKTLIFEMAXFIXED 0xBF
3765 #define TKTLIFENOEXPIRE 0xFF
3766 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3768 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3769 38400, /* 10.67 hours, 0.44 days */
3770 41055, /* 11.40 hours, 0.48 days */
3771 43894, /* 12.19 hours, 0.51 days */
3772 46929, /* 13.04 hours, 0.54 days */
3773 50174, /* 13.94 hours, 0.58 days */
3774 53643, /* 14.90 hours, 0.62 days */
3775 57352, /* 15.93 hours, 0.66 days */
3776 61318, /* 17.03 hours, 0.71 days */
3777 65558, /* 18.21 hours, 0.76 days */
3778 70091, /* 19.47 hours, 0.81 days */
3779 74937, /* 20.82 hours, 0.87 days */
3780 80119, /* 22.26 hours, 0.93 days */
3781 85658, /* 23.79 hours, 0.99 days */
3782 91581, /* 25.44 hours, 1.06 days */
3783 97914, /* 27.20 hours, 1.13 days */
3784 104684, /* 29.08 hours, 1.21 days */
3785 111922, /* 31.09 hours, 1.30 days */
3786 119661, /* 33.24 hours, 1.38 days */
3787 127935, /* 35.54 hours, 1.48 days */
3788 136781, /* 37.99 hours, 1.58 days */
3789 146239, /* 40.62 hours, 1.69 days */
3790 156350, /* 43.43 hours, 1.81 days */
3791 167161, /* 46.43 hours, 1.93 days */
3792 178720, /* 49.64 hours, 2.07 days */
3793 191077, /* 53.08 hours, 2.21 days */
3794 204289, /* 56.75 hours, 2.36 days */
3795 218415, /* 60.67 hours, 2.53 days */
3796 233517, /* 64.87 hours, 2.70 days */
3797 249664, /* 69.35 hours, 2.89 days */
3798 266926, /* 74.15 hours, 3.09 days */
3799 285383, /* 79.27 hours, 3.30 days */
3800 305116, /* 84.75 hours, 3.53 days */
3801 326213, /* 90.61 hours, 3.78 days */
3802 348769, /* 96.88 hours, 4.04 days */
3803 372885, /* 103.58 hours, 4.32 days */
3804 398668, /* 110.74 hours, 4.61 days */
3805 426234, /* 118.40 hours, 4.93 days */
3806 455705, /* 126.58 hours, 5.27 days */
3807 487215, /* 135.34 hours, 5.64 days */
3808 520904, /* 144.70 hours, 6.03 days */
3809 556921, /* 154.70 hours, 6.45 days */
3810 595430, /* 165.40 hours, 6.89 days */
3811 636601, /* 176.83 hours, 7.37 days */
3812 680618, /* 189.06 hours, 7.88 days */
3813 727680, /* 202.13 hours, 8.42 days */
3814 777995, /* 216.11 hours, 9.00 days */
3815 831789, /* 231.05 hours, 9.63 days */
3816 889303, /* 247.03 hours, 10.29 days */
3817 950794, /* 264.11 hours, 11.00 days */
3818 1016537, /* 282.37 hours, 11.77 days */
3819 1086825, /* 301.90 hours, 12.58 days */
3820 1161973, /* 322.77 hours, 13.45 days */
3821 1242318, /* 345.09 hours, 14.38 days */
3822 1328218, /* 368.95 hours, 15.37 days */
3823 1420057, /* 394.46 hours, 16.44 days */
3824 1518247, /* 421.74 hours, 17.57 days */
3825 1623226, /* 450.90 hours, 18.79 days */
3826 1735464, /* 482.07 hours, 20.09 days */
3827 1855462, /* 515.41 hours, 21.48 days */
3828 1983758, /* 551.04 hours, 22.96 days */
3829 2120925, /* 589.15 hours, 24.55 days */
3830 2267576, /* 629.88 hours, 26.25 days */
3831 2424367, /* 673.44 hours, 28.06 days */
3833 }; /* 720.00 hours, 30.00 days */
3835 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3836 * returns the corresponding end time. There are four simple cases to be
3837 * handled. The first is a life of 0xff, meaning no expiration, and results in
3838 * an end time of 0xffffffff. The second is when life is less than the values
3839 * covered by the table. In this case, the end time is the start time plus the
3840 * number of 5 minute intervals specified by life. The third case returns
3841 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3842 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3843 * table to extract the lifetime in seconds, which is added to start to produce
3847 life_to_time(afs_uint32 start, unsigned char life)
3851 if (life == TKTLIFENOEXPIRE)
3853 if (life < TKTLIFEMINFIXED)
3854 return start + life * 5 * 60;
3855 if (life > TKTLIFEMAXFIXED)
3856 return start + MAXTKTLIFETIME;
3857 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3858 return start + realLife;
3861 /* time_to_life - takes start and end times for the ticket and returns a
3862 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3863 * lifetimes above 127*5minutes. First, the special case of (end ==
3864 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3865 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3866 * less than the first table entry are handled by rounding the requested
3867 * lifetime *up* to the next 5 minute interval. The final step is to search
3868 * the table for the smallest entry *greater than or equal* to the requested
3869 * entry. The actual code is prepared to handle the case where the table is
3870 * unordered but that it an unnecessary frill. */
3872 static unsigned char
3873 time_to_life(afs_uint32 start, afs_uint32 end)
3875 int lifetime = end - start;
3879 if (end == NEVERDATE)
3880 return TKTLIFENOEXPIRE;
3881 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3883 if (lifetime < tkt_lifetimes[0])
3884 return (lifetime + 5 * 60 - 1) / (5 * 60);
3886 best = MAXKTCTICKETLIFETIME;
3887 for (i = 0; i < TKTLIFENUMFIXED; i++)
3888 if (tkt_lifetimes[i] >= lifetime) {
3889 int diff = tkt_lifetimes[i] - lifetime;
3897 return best_i + TKTLIFEMINFIXED;