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"
69 #include <afs/ptserver.h>
70 #include <afs/ptuser.h>
73 #include <WINNT\afsreg.h>
76 * TIMING _____________________________________________________________________
80 #define cminREMIND_TEST 1 // test every minute for expired creds
81 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
82 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
83 #define cminMINLIFE 30 // minimum life of Kerberos creds
85 #define c100ns1SECOND (LONGLONG)10000000
86 #define cmsec1SECOND 1000
87 #define cmsec1MINUTE 60000
88 #define csec1MINUTE 60
90 /* Function Pointer Declarations for Delayed Loading */
92 DECL_FUNC_PTR(cc_initialize);
93 DECL_FUNC_PTR(cc_shutdown);
94 DECL_FUNC_PTR(cc_get_NC_info);
95 DECL_FUNC_PTR(cc_free_NC_info);
98 DECL_FUNC_PTR(Leash_get_default_lifetime);
99 DECL_FUNC_PTR(Leash_get_default_forwardable);
100 DECL_FUNC_PTR(Leash_get_default_renew_till);
101 DECL_FUNC_PTR(Leash_get_default_noaddresses);
102 DECL_FUNC_PTR(Leash_get_default_proxiable);
103 DECL_FUNC_PTR(Leash_get_default_publicip);
104 DECL_FUNC_PTR(Leash_get_default_use_krb4);
105 DECL_FUNC_PTR(Leash_get_default_life_min);
106 DECL_FUNC_PTR(Leash_get_default_life_max);
107 DECL_FUNC_PTR(Leash_get_default_renew_min);
108 DECL_FUNC_PTR(Leash_get_default_renew_max);
109 DECL_FUNC_PTR(Leash_get_default_renewable);
110 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
113 DECL_FUNC_PTR(krb5_change_password);
114 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
115 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
116 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
117 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
118 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
119 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
120 DECL_FUNC_PTR(krb5_get_init_creds_password);
121 DECL_FUNC_PTR(krb5_build_principal_ext);
122 DECL_FUNC_PTR(krb5_cc_get_name);
123 DECL_FUNC_PTR(krb5_cc_resolve);
124 DECL_FUNC_PTR(krb5_cc_default);
125 DECL_FUNC_PTR(krb5_cc_default_name);
126 DECL_FUNC_PTR(krb5_cc_set_default_name);
127 DECL_FUNC_PTR(krb5_cc_initialize);
128 DECL_FUNC_PTR(krb5_cc_destroy);
129 DECL_FUNC_PTR(krb5_cc_close);
130 DECL_FUNC_PTR(krb5_cc_store_cred);
131 DECL_FUNC_PTR(krb5_cc_copy_creds);
132 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
133 DECL_FUNC_PTR(krb5_cc_get_principal);
134 DECL_FUNC_PTR(krb5_cc_start_seq_get);
135 DECL_FUNC_PTR(krb5_cc_next_cred);
136 DECL_FUNC_PTR(krb5_cc_end_seq_get);
137 DECL_FUNC_PTR(krb5_cc_remove_cred);
138 DECL_FUNC_PTR(krb5_cc_set_flags);
139 DECL_FUNC_PTR(krb5_cc_get_type);
140 DECL_FUNC_PTR(krb5_free_context);
141 DECL_FUNC_PTR(krb5_free_cred_contents);
142 DECL_FUNC_PTR(krb5_free_principal);
143 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
144 DECL_FUNC_PTR(krb5_init_context);
145 DECL_FUNC_PTR(krb5_parse_name);
146 DECL_FUNC_PTR(krb5_timeofday);
147 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
148 DECL_FUNC_PTR(krb5_unparse_name);
149 DECL_FUNC_PTR(krb5_get_credentials);
150 DECL_FUNC_PTR(krb5_mk_req);
151 DECL_FUNC_PTR(krb5_sname_to_principal);
152 DECL_FUNC_PTR(krb5_get_credentials_renew);
153 DECL_FUNC_PTR(krb5_free_data);
154 DECL_FUNC_PTR(krb5_free_data_contents);
155 DECL_FUNC_PTR(krb5_free_unparsed_name);
156 DECL_FUNC_PTR(krb5_os_localaddr);
157 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
158 DECL_FUNC_PTR(krb5_copy_data);
159 DECL_FUNC_PTR(krb5_free_creds);
160 DECL_FUNC_PTR(krb5_build_principal);
161 DECL_FUNC_PTR(krb5_get_renewed_creds);
162 DECL_FUNC_PTR(krb5_get_default_config_files);
163 DECL_FUNC_PTR(krb5_free_config_files);
164 DECL_FUNC_PTR(krb5_get_default_realm);
165 DECL_FUNC_PTR(krb5_free_default_realm);
166 DECL_FUNC_PTR(krb5_free_ticket);
167 DECL_FUNC_PTR(krb5_decode_ticket);
168 DECL_FUNC_PTR(krb5_get_host_realm);
169 DECL_FUNC_PTR(krb5_free_host_realm);
170 DECL_FUNC_PTR(krb5_free_addresses);
171 DECL_FUNC_PTR(krb5_c_random_make_octets);
174 DECL_FUNC_PTR(krb524_init_ets);
175 DECL_FUNC_PTR(krb524_convert_creds_kdc);
178 DECL_FUNC_PTR(krb_get_cred);
179 DECL_FUNC_PTR(tkt_string);
180 DECL_FUNC_PTR(krb_get_tf_realm);
181 DECL_FUNC_PTR(krb_mk_req);
184 DECL_FUNC_PTR(com_err);
185 DECL_FUNC_PTR(error_message);
188 DECL_FUNC_PTR(profile_init);
189 DECL_FUNC_PTR(profile_release);
190 DECL_FUNC_PTR(profile_get_subsection_names);
191 DECL_FUNC_PTR(profile_free_list);
192 DECL_FUNC_PTR(profile_get_string);
193 DECL_FUNC_PTR(profile_release_string);
196 DECL_FUNC_PTR(OpenSCManagerA);
197 DECL_FUNC_PTR(OpenServiceA);
198 DECL_FUNC_PTR(QueryServiceStatus);
199 DECL_FUNC_PTR(CloseServiceHandle);
201 DECL_FUNC_PTR(LsaNtStatusToWinError);
202 #endif /* USE_MS2MIT */
206 DECL_FUNC_PTR(LsaConnectUntrusted);
207 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
208 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
209 DECL_FUNC_PTR(LsaFreeReturnBuffer);
210 DECL_FUNC_PTR(LsaGetLogonSessionData);
211 #endif /* USE_MS2MIT */
214 FUNC_INFO ccapi_fi[] = {
215 MAKE_FUNC_INFO(cc_initialize),
216 MAKE_FUNC_INFO(cc_shutdown),
217 MAKE_FUNC_INFO(cc_get_NC_info),
218 MAKE_FUNC_INFO(cc_free_NC_info),
222 FUNC_INFO leash_fi[] = {
223 MAKE_FUNC_INFO(Leash_get_default_lifetime),
224 MAKE_FUNC_INFO(Leash_get_default_renew_till),
225 MAKE_FUNC_INFO(Leash_get_default_forwardable),
226 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
227 MAKE_FUNC_INFO(Leash_get_default_proxiable),
228 MAKE_FUNC_INFO(Leash_get_default_publicip),
229 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
230 MAKE_FUNC_INFO(Leash_get_default_life_min),
231 MAKE_FUNC_INFO(Leash_get_default_life_max),
232 MAKE_FUNC_INFO(Leash_get_default_renew_min),
233 MAKE_FUNC_INFO(Leash_get_default_renew_max),
234 MAKE_FUNC_INFO(Leash_get_default_renewable),
238 FUNC_INFO leash_opt_fi[] = {
239 MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
243 FUNC_INFO k5_fi[] = {
244 MAKE_FUNC_INFO(krb5_change_password),
245 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
246 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
247 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
248 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
249 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
250 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
251 MAKE_FUNC_INFO(krb5_get_init_creds_password),
252 MAKE_FUNC_INFO(krb5_build_principal_ext),
253 MAKE_FUNC_INFO(krb5_cc_get_name),
254 MAKE_FUNC_INFO(krb5_cc_resolve),
255 MAKE_FUNC_INFO(krb5_cc_default),
256 MAKE_FUNC_INFO(krb5_cc_default_name),
257 MAKE_FUNC_INFO(krb5_cc_set_default_name),
258 MAKE_FUNC_INFO(krb5_cc_initialize),
259 MAKE_FUNC_INFO(krb5_cc_destroy),
260 MAKE_FUNC_INFO(krb5_cc_close),
261 MAKE_FUNC_INFO(krb5_cc_copy_creds),
262 MAKE_FUNC_INFO(krb5_cc_store_cred),
263 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
264 MAKE_FUNC_INFO(krb5_cc_get_principal),
265 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
266 MAKE_FUNC_INFO(krb5_cc_next_cred),
267 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
268 MAKE_FUNC_INFO(krb5_cc_remove_cred),
269 MAKE_FUNC_INFO(krb5_cc_set_flags),
270 MAKE_FUNC_INFO(krb5_cc_get_type),
271 MAKE_FUNC_INFO(krb5_free_context),
272 MAKE_FUNC_INFO(krb5_free_cred_contents),
273 MAKE_FUNC_INFO(krb5_free_principal),
274 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
275 MAKE_FUNC_INFO(krb5_init_context),
276 MAKE_FUNC_INFO(krb5_parse_name),
277 MAKE_FUNC_INFO(krb5_timeofday),
278 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
279 MAKE_FUNC_INFO(krb5_unparse_name),
280 MAKE_FUNC_INFO(krb5_get_credentials),
281 MAKE_FUNC_INFO(krb5_mk_req),
282 MAKE_FUNC_INFO(krb5_sname_to_principal),
283 MAKE_FUNC_INFO(krb5_get_credentials_renew),
284 MAKE_FUNC_INFO(krb5_free_data),
285 MAKE_FUNC_INFO(krb5_free_data_contents),
286 MAKE_FUNC_INFO(krb5_free_unparsed_name),
287 MAKE_FUNC_INFO(krb5_os_localaddr),
288 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
289 MAKE_FUNC_INFO(krb5_copy_data),
290 MAKE_FUNC_INFO(krb5_free_creds),
291 MAKE_FUNC_INFO(krb5_build_principal),
292 MAKE_FUNC_INFO(krb5_get_renewed_creds),
293 MAKE_FUNC_INFO(krb5_free_addresses),
294 MAKE_FUNC_INFO(krb5_get_default_config_files),
295 MAKE_FUNC_INFO(krb5_free_config_files),
296 MAKE_FUNC_INFO(krb5_get_default_realm),
297 MAKE_FUNC_INFO(krb5_free_default_realm),
298 MAKE_FUNC_INFO(krb5_free_ticket),
299 MAKE_FUNC_INFO(krb5_decode_ticket),
300 MAKE_FUNC_INFO(krb5_get_host_realm),
301 MAKE_FUNC_INFO(krb5_free_host_realm),
302 MAKE_FUNC_INFO(krb5_free_addresses),
303 MAKE_FUNC_INFO(krb5_c_random_make_octets),
308 FUNC_INFO k4_fi[] = {
309 MAKE_FUNC_INFO(krb_get_cred),
310 MAKE_FUNC_INFO(krb_get_tf_realm),
311 MAKE_FUNC_INFO(krb_mk_req),
312 MAKE_FUNC_INFO(tkt_string),
317 FUNC_INFO k524_fi[] = {
318 MAKE_FUNC_INFO(krb524_init_ets),
319 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
323 FUNC_INFO profile_fi[] = {
324 MAKE_FUNC_INFO(profile_init),
325 MAKE_FUNC_INFO(profile_release),
326 MAKE_FUNC_INFO(profile_get_subsection_names),
327 MAKE_FUNC_INFO(profile_free_list),
328 MAKE_FUNC_INFO(profile_get_string),
329 MAKE_FUNC_INFO(profile_release_string),
333 FUNC_INFO ce_fi[] = {
334 MAKE_FUNC_INFO(com_err),
335 MAKE_FUNC_INFO(error_message),
339 FUNC_INFO service_fi[] = {
340 MAKE_FUNC_INFO(OpenSCManagerA),
341 MAKE_FUNC_INFO(OpenServiceA),
342 MAKE_FUNC_INFO(QueryServiceStatus),
343 MAKE_FUNC_INFO(CloseServiceHandle),
345 MAKE_FUNC_INFO(LsaNtStatusToWinError),
346 #endif /* USE_MS2MIT */
351 FUNC_INFO lsa_fi[] = {
352 MAKE_FUNC_INFO(LsaConnectUntrusted),
353 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
354 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
355 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
356 MAKE_FUNC_INFO(LsaGetLogonSessionData),
359 #endif /* USE_MS2MIT */
361 /* Static Prototypes */
362 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
363 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
364 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
365 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
366 void *data, const char *name, const char *banner, int num_prompts,
367 krb5_prompt prompts[]);
370 /* Static Declarations */
371 static int inited = 0;
372 static int mid_cnt = 0;
373 static struct textField * mid_tb = NULL;
374 static HINSTANCE hKrb5 = 0;
376 static HINSTANCE hKrb4 = 0;
377 #endif /* USE_KRB4 */
378 static HINSTANCE hKrb524 = 0;
380 static HINSTANCE hSecur32 = 0;
381 #endif /* USE_MS2MIT */
382 static HINSTANCE hAdvApi32 = 0;
383 static HINSTANCE hComErr = 0;
384 static HINSTANCE hService = 0;
385 static HINSTANCE hProfile = 0;
386 static HINSTANCE hLeash = 0;
387 static HINSTANCE hLeashOpt = 0;
388 static HINSTANCE hCCAPI = 0;
389 static struct principal_ccache_data * princ_cc_data = NULL;
390 static struct cell_principal_map * cell_princ_map = NULL;
395 static int inited = 0;
398 char mutexName[MAX_PATH];
399 HANDLE hMutex = NULL;
401 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
403 hMutex = CreateMutex( NULL, TRUE, mutexName );
404 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
405 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
411 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
413 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
414 #endif /* USE_KRB4 */
415 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
416 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
418 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
419 #endif /* USE_MS2MIT */
420 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
421 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
422 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
423 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
424 LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
426 if ( KFW_is_available() ) {
427 char rootcell[MAXCELLCHARS+1];
429 KFW_import_windows_lsa();
430 #endif /* USE_MS2MIT */
431 KFW_import_ccache_data();
432 KFW_AFS_renew_expiring_tokens();
434 /* WIN32 NOTE: no way to get max chars */
435 if (!cm_GetRootCellName(rootcell))
436 KFW_AFS_renew_token_for_cell(rootcell);
439 ReleaseMutex(hMutex);
448 FreeLibrary(hLeashOpt);
454 FreeLibrary(hKrb524);
457 FreeLibrary(hSecur32);
458 #endif /* USE_MS2MIT */
460 FreeLibrary(hService);
462 FreeLibrary(hComErr);
464 FreeLibrary(hProfile);
468 #endif /* USE_KRB4 */
480 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
481 0, KEY_QUERY_VALUE, &parmKey);
482 if (code == ERROR_SUCCESS) {
483 len = sizeof(use524);
484 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
485 (BYTE *) &use524, &len);
486 RegCloseKey(parmKey);
488 if (code != ERROR_SUCCESS) {
489 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
490 0, KEY_QUERY_VALUE, &parmKey);
491 if (code == ERROR_SUCCESS) {
492 len = sizeof(use524);
493 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
494 (BYTE *) &use524, &len);
495 RegCloseKey (parmKey);
502 KFW_is_available(void)
508 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
509 0, KEY_QUERY_VALUE, &parmKey);
510 if (code == ERROR_SUCCESS) {
511 len = sizeof(enableKFW);
512 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
513 (BYTE *) &enableKFW, &len);
514 RegCloseKey (parmKey);
517 if (code != ERROR_SUCCESS) {
518 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
519 0, KEY_QUERY_VALUE, &parmKey);
520 if (code == ERROR_SUCCESS) {
521 len = sizeof(enableKFW);
522 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
523 (BYTE *) &enableKFW, &len);
524 RegCloseKey (parmKey);
532 if ( hKrb5 && hComErr && hService &&
535 #endif /* USE_MS2MIT */
537 hProfile && hLeash && hCCAPI )
543 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
544 int FreeContextFlag, krb5_context * ctx,
549 int krb5Error = ((int)(rc & 255));
561 errText = perror_message(rc);
562 _snprintf(message, sizeof(message),
563 "%s\n(Kerberos error %ld)\n\n%s failed",
568 if ( IsDebuggerPresent() )
569 OutputDebugString(message);
571 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
574 if (FreeContextFlag == 1)
576 if (ctx && *ctx != NULL)
578 if (cache && *cache != NULL) {
579 pkrb5_cc_close(*ctx, *cache);
583 pkrb5_free_context(*ctx);
592 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
594 struct principal_ccache_data * next = princ_cc_data;
595 krb5_principal principal = 0;
597 const char * ccname = NULL;
598 krb5_error_code code = 0;
599 krb5_error_code cc_code = 0;
605 if (ctx == 0 || cc == 0)
608 code = pkrb5_cc_get_principal(ctx, cc, &principal);
611 code = pkrb5_unparse_name(ctx, principal, &pname);
612 if ( code ) goto cleanup;
614 ccname = pkrb5_cc_get_name(ctx, cc);
615 if (!ccname) goto cleanup;
617 // Search the existing list to see if we have a match
619 for ( ; next ; next = next->next ) {
620 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
625 // If not, match add a new node to the beginning of the list and assign init it
627 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
628 next->next = princ_cc_data;
629 princ_cc_data = next;
630 next->principal = _strdup(pname);
631 next->ccache_name = _strdup(ccname);
632 next->from_lsa = lsa;
634 next->expiration_time = 0;
638 flags = 0; // turn off OPENCLOSE mode
639 code = pkrb5_cc_set_flags(ctx, cc, flags);
640 if ( code ) goto cleanup;
642 code = pkrb5_timeofday(ctx, &now);
644 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
646 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
647 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
649 // we found the ticket we are looking for
650 // check validity of timestamp
651 // We add a 5 minutes fudge factor to compensate for potential
652 // clock skew errors between the KDC and client OS
654 valid = ((creds.times.starttime > 0) &&
655 now >= (creds.times.starttime - 300) &&
656 now < (creds.times.endtime + 300) &&
657 !(creds.ticket_flags & TKT_FLG_INVALID));
659 if ( next->from_lsa) {
661 next->expiration_time = creds.times.endtime;
663 } else if ( valid ) {
665 next->expiration_time = creds.times.endtime;
666 next->renew = (creds.times.renew_till > creds.times.endtime) &&
667 (creds.ticket_flags & TKT_FLG_RENEWABLE);
670 next->expiration_time = 0;
674 pkrb5_free_cred_contents(ctx, &creds);
675 cc_code = KRB5_CC_END;
678 pkrb5_free_cred_contents(ctx, &creds);
681 if (cc_code == KRB5_CC_END) {
682 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
683 if (code) goto cleanup;
687 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
688 code = pkrb5_cc_set_flags(ctx, cc, flags);
691 pkrb5_free_unparsed_name(ctx,pname);
693 pkrb5_free_principal(ctx,principal);
697 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
699 struct principal_ccache_data * next = princ_cc_data;
700 char * response = NULL;
702 if ( !principal || !ccache )
706 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
708 // we always want to prefer the MS Kerberos LSA cache or
709 // the cache afscreds created specifically for the principal
710 // if the current entry is either one, drop the previous find
711 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
714 response = _strdup(next->ccache_name);
715 // MS Kerberos LSA is our best option so use it and quit
716 if ( next->from_lsa )
730 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
732 struct principal_ccache_data ** next = &princ_cc_data;
734 if ( !pname && !ccname )
738 if ( !strcmp((*next)->principal,pname) ||
739 !strcmp((*next)->ccache_name,ccname) ) {
741 free((*next)->principal);
742 free((*next)->ccache_name);
744 (*next) = (*next)->next;
751 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
753 struct cell_principal_map * next = cell_princ_map;
755 // Search the existing list to see if we have a match
757 for ( ; next ; next = next->next ) {
758 if ( !strcmp(next->cell, cell) ) {
759 if ( !strcmp(next->principal,pname) ) {
760 next->active = active;
763 // OpenAFS currently has a restriction of one active token per cell
764 // Therefore, whenever we update the table with a new active cell we
765 // must mark all of the other principal to cell entries as inactive.
773 // If not, match add a new node to the beginning of the list and assign init it
775 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
776 next->next = cell_princ_map;
777 cell_princ_map = next;
778 next->principal = _strdup(pname);
779 next->cell = _strdup(cell);
780 next->active = active;
785 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
787 struct cell_principal_map ** next = &cell_princ_map;
789 if ( !pname && !cell )
793 if ( !strcmp((*next)->principal,pname) ||
794 !strcmp((*next)->cell,cell) ) {
796 free((*next)->principal);
799 (*next) = (*next)->next;
805 // Returns (if possible) a principal which has been known in
806 // the past to have been used to obtain tokens for the specified
808 // TODO: Attempt to return one which has not yet expired by checking
809 // the principal/ccache data
811 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
813 struct cell_principal_map * next_map = cell_princ_map;
814 const char * princ = NULL;
821 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
824 next_map = next_map->next;
827 if ( !principals || !count )
830 *principals = (char **) malloc(sizeof(char *) * count);
831 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
833 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
834 (*principals)[i++] = _strdup(next_map->principal);
841 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
844 struct cell_principal_map * next_map = cell_princ_map;
845 const char * princ = NULL;
851 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
854 next_map = next_map->next;
860 *cells = (char **) malloc(sizeof(char *) * count);
861 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
863 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
864 (*cells)[i++] = _strdup(next_map->cell);
870 /* Given a principal return an existing ccache or create one and return */
872 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
874 krb5_context ctx = NULL;
876 char * ccname = NULL;
877 krb5_error_code code;
879 if (!pkrb5_init_context)
885 code = pkrb5_init_context(&ctx);
886 if (code) goto cleanup;
890 code = pkrb5_unparse_name(ctx, principal, &pname);
891 if (code) goto cleanup;
893 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
894 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
895 ccname = (char *)malloc(strlen(pname) + 5);
896 sprintf(ccname,"API:%s",pname);
898 code = pkrb5_cc_resolve(ctx, ccname, cc);
900 code = pkrb5_cc_default(ctx, cc);
901 if (code) goto cleanup;
908 pkrb5_free_unparsed_name(ctx,pname);
909 if (ctx && (ctx != alt_ctx))
910 pkrb5_free_context(ctx);
915 // Import Microsoft Credentials into a new MIT ccache
917 KFW_import_windows_lsa(void)
919 krb5_context ctx = NULL;
920 krb5_ccache cc = NULL;
921 krb5_principal princ = NULL;
923 krb5_data * princ_realm;
924 krb5_error_code code;
925 char cell[128]="", realm[128]="", *def_realm = 0;
929 if (!pkrb5_init_context)
933 if ( !MSLSA_IsKerberosLogon() )
937 code = pkrb5_init_context(&ctx);
938 if (code) goto cleanup;
940 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
941 if (code) goto cleanup;
943 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
945 code = pkrb5_cc_get_principal(ctx, cc, &princ);
946 if ( code ) goto cleanup;
948 dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
949 switch ( dwMsLsaImport ) {
950 case 0: /* do not import */
952 case 1: /* always import */
954 case 2: { /* matching realm */
955 char ms_realm[128] = "", *r;
958 for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
959 *r = krb5_princ_realm(ctx, princ)->data[i];
963 if (code = pkrb5_get_default_realm(ctx, &def_realm))
966 if (strcmp(def_realm, ms_realm))
974 code = pkrb5_unparse_name(ctx,princ,&pname);
975 if ( code ) goto cleanup;
977 princ_realm = krb5_princ_realm(ctx, princ);
978 for ( i=0; i<princ_realm->length; i++ ) {
979 realm[i] = princ_realm->data[i];
980 cell[i] = tolower(princ_realm->data[i]);
985 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
986 if ( IsDebuggerPresent() ) {
988 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
989 OutputDebugString(message);
991 if ( code ) goto cleanup;
993 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
997 pkrb5_free_unparsed_name(ctx,pname);
999 pkrb5_free_principal(ctx,princ);
1001 pkrb5_free_default_realm(ctx, def_realm);
1003 pkrb5_cc_close(ctx,cc);
1005 pkrb5_free_context(ctx);
1007 #endif /* USE_MS2MIT */
1009 // If there are existing MIT credentials, copy them to a new
1010 // ccache named after the principal
1012 // Enumerate all existing MIT ccaches and construct entries
1013 // in the principal_ccache table
1015 // Enumerate all existing AFS Tokens and construct entries
1016 // in the cell_principal table
1018 KFW_import_ccache_data(void)
1020 krb5_context ctx = NULL;
1021 krb5_ccache cc = NULL;
1022 krb5_principal principal = NULL;
1024 krb5_error_code code;
1025 krb5_error_code cc_code;
1027 apiCB * cc_ctx = NULL;
1028 struct _infoNC ** pNCi = NULL;
1031 if ( !pcc_initialize )
1034 if ( IsDebuggerPresent() )
1035 OutputDebugString("KFW_import_ccache_data()\n");
1037 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
1038 if (code) goto cleanup;
1040 code = pcc_get_NC_info(cc_ctx, &pNCi);
1041 if (code) goto cleanup;
1043 code = pkrb5_init_context(&ctx);
1044 if (code) goto cleanup;
1046 for ( i=0; pNCi[i]; i++ ) {
1047 if ( pNCi[i]->vers != CC_CRED_V5 )
1049 if ( IsDebuggerPresent() ) {
1050 OutputDebugString("Principal: ");
1051 OutputDebugString(pNCi[i]->principal);
1052 OutputDebugString(" in ccache ");
1053 OutputDebugString(pNCi[i]->name);
1054 OutputDebugString("\n");
1056 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
1057 && strcmp(pNCi[i]->name,LSA_CCNAME)
1060 for ( j=0; pNCi[j]; j++ ) {
1061 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
1067 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
1068 if (code) goto loop_cleanup;
1071 krb5_ccache oldcc = 0;
1073 if ( IsDebuggerPresent() )
1074 OutputDebugString("copying ccache data to new ccache\n");
1076 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
1077 if (code) goto loop_cleanup;
1078 code = pkrb5_cc_initialize(ctx, cc, principal);
1079 if (code) goto loop_cleanup;
1081 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
1082 if (code) goto loop_cleanup;
1083 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
1085 code = pkrb5_cc_close(ctx,cc);
1087 code = pkrb5_cc_close(ctx,oldcc);
1089 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1092 code = pkrb5_cc_close(ctx,oldcc);
1095 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1096 if (code) goto loop_cleanup;
1099 flags = 0; // turn off OPENCLOSE mode
1100 code = pkrb5_cc_set_flags(ctx, cc, flags);
1101 if ( code ) goto cleanup;
1103 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1105 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1107 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1108 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1109 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1110 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1111 if ( sname && cell && !strcmp("afs",sname->data) ) {
1112 struct ktc_principal aserver;
1113 struct ktc_principal aclient;
1114 struct ktc_token atoken;
1117 if ( IsDebuggerPresent() ) {
1118 OutputDebugString("Found AFS ticket: ");
1119 OutputDebugString(sname->data);
1121 OutputDebugString("/");
1122 OutputDebugString(cell->data);
1124 OutputDebugString("@");
1125 OutputDebugString(realm->data);
1126 OutputDebugString("\n");
1129 memset(&aserver, '\0', sizeof(aserver));
1130 strcpy(aserver.name, sname->data);
1131 strcpy(aserver.cell, cell->data);
1133 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1135 // Found a token in AFS Client Server which matches
1136 char pname[128], *p, *q;
1137 for ( p=pname, q=aclient.name; *q; p++, q++)
1139 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1143 if ( IsDebuggerPresent() ) {
1144 OutputDebugString("Found AFS token: ");
1145 OutputDebugString(pname);
1146 OutputDebugString("\n");
1149 if ( strcmp(pname,pNCi[i]->principal) )
1151 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1153 // Attempt to import it
1154 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1156 if ( IsDebuggerPresent() ) {
1157 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1160 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL);
1161 if ( IsDebuggerPresent() ) {
1163 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1164 OutputDebugString(message);
1167 } else if ( IsDebuggerPresent() ) {
1168 OutputDebugString("Found ticket: ");
1169 OutputDebugString(sname->data);
1170 if ( cell && cell->data ) {
1171 OutputDebugString("/");
1172 OutputDebugString(cell->data);
1174 OutputDebugString("@");
1175 OutputDebugString(realm->data);
1176 OutputDebugString("\n");
1178 pkrb5_free_cred_contents(ctx, &creds);
1181 if (cc_code == KRB5_CC_END) {
1182 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1183 if (cc_code) goto loop_cleanup;
1187 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1188 code = pkrb5_cc_set_flags(ctx, cc, flags);
1190 pkrb5_cc_close(ctx,cc);
1194 pkrb5_free_principal(ctx,principal);
1201 pkrb5_free_context(ctx);
1203 pcc_free_NC_info(cc_ctx, &pNCi);
1205 pcc_shutdown(&cc_ctx);
1210 KFW_AFS_get_cred( char * username,
1217 krb5_context ctx = NULL;
1218 krb5_ccache cc = NULL;
1219 char * realm = NULL, * userrealm = NULL;
1220 krb5_principal principal = NULL;
1221 char * pname = NULL;
1222 krb5_error_code code;
1223 char local_cell[MAXCELLCHARS+1];
1224 char **cells = NULL;
1226 struct afsconf_cell cellconfig;
1230 if (!pkrb5_init_context)
1233 if ( IsDebuggerPresent() ) {
1234 OutputDebugString("KFW_AFS_get_cred for token ");
1235 OutputDebugString(username);
1236 OutputDebugString(" in cell ");
1237 OutputDebugString(cell);
1238 OutputDebugString("\n");
1241 code = pkrb5_init_context(&ctx);
1242 if ( code ) goto cleanup;
1244 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1245 if ( code ) goto cleanup;
1247 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1249 userrealm = strchr(username,'@');
1251 pname = strdup(username);
1252 userrealm = strchr(pname, '@');
1255 /* handle kerberos iv notation */
1256 while ( dot = strchr(pname,'.') ) {
1261 pname = malloc(strlen(username) + strlen(realm) + 2);
1263 strcpy(pname, username);
1265 /* handle kerberos iv notation */
1266 while ( dot = strchr(pname,'.') ) {
1271 strcat(pname,realm);
1273 if ( IsDebuggerPresent() ) {
1274 OutputDebugString("Realm: ");
1275 OutputDebugString(realm);
1276 OutputDebugString("\n");
1279 code = pkrb5_parse_name(ctx, pname, &principal);
1280 if ( code ) goto cleanup;
1282 code = KFW_get_ccache(ctx, principal, &cc);
1283 if ( code ) goto cleanup;
1285 if ( lifetime == 0 )
1286 lifetime = pLeash_get_default_lifetime();
1288 if ( password && password[0] ) {
1289 code = KFW_kinit( ctx, cc, HWND_DESKTOP,
1293 pLeash_get_default_forwardable(),
1294 pLeash_get_default_proxiable(),
1295 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1296 pLeash_get_default_noaddresses(),
1297 pLeash_get_default_publicip());
1298 if ( IsDebuggerPresent() ) {
1300 sprintf(message,"KFW_kinit() returns: %d\n",code);
1301 OutputDebugString(message);
1303 if ( code ) goto cleanup;
1305 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1308 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
1309 if ( IsDebuggerPresent() ) {
1311 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1312 OutputDebugString(message);
1314 if ( code ) goto cleanup;
1316 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1318 // Attempt to obtain new tokens for other cells supported by the same
1320 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1321 if ( cell_count > 1 ) {
1322 while ( cell_count-- ) {
1323 if ( strcmp(cells[cell_count],cell) ) {
1324 if ( IsDebuggerPresent() ) {
1326 sprintf(message,"found another cell for the same principal: %s\n",cell);
1327 OutputDebugString(message);
1329 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1330 if ( code ) continue;
1332 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1333 if ( IsDebuggerPresent() ) {
1334 OutputDebugString("Realm: ");
1335 OutputDebugString(realm);
1336 OutputDebugString("\n");
1339 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1340 if ( IsDebuggerPresent() ) {
1342 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1343 OutputDebugString(message);
1346 free(cells[cell_count]);
1349 } else if ( cell_count == 1 ) {
1358 pkrb5_cc_close(ctx, cc);
1360 if ( code && reasonP ) {
1361 *reasonP = (char *)perror_message(code);
1367 KFW_AFS_destroy_tickets_for_cell(char * cell)
1369 krb5_context ctx = NULL;
1370 krb5_error_code code;
1372 char ** principals = NULL;
1374 if (!pkrb5_init_context)
1377 if ( IsDebuggerPresent() ) {
1378 OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
1379 OutputDebugString(cell);
1380 OutputDebugString("\n");
1383 code = pkrb5_init_context(&ctx);
1386 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1388 krb5_principal princ = 0;
1392 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1393 if ( cell_count > 1 ) {
1394 // TODO - What we really should do here is verify whether or not any of the
1395 // other cells which use this principal to obtain its credentials actually
1396 // have valid tokens or not. If they are currently using these credentials
1397 // we will skip them. For the time being we assume that if there is an active
1398 // map in the table that they are actively being used.
1402 code = pkrb5_parse_name(ctx, principals[count], &princ);
1403 if (code) goto loop_cleanup;
1405 code = KFW_get_ccache(ctx, princ, &cc);
1406 if (code) goto loop_cleanup;
1408 code = pkrb5_cc_destroy(ctx, cc);
1413 pkrb5_cc_close(ctx, cc);
1417 pkrb5_free_principal(ctx, princ);
1421 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1422 free(principals[count]);
1427 pkrb5_free_context(ctx);
1432 KFW_AFS_destroy_tickets_for_principal(char * user)
1434 krb5_context ctx = NULL;
1435 krb5_error_code code;
1437 char ** cells = NULL;
1438 krb5_principal princ = NULL;
1439 krb5_ccache cc = NULL;
1441 if (!pkrb5_init_context)
1444 if ( IsDebuggerPresent() ) {
1445 OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
1446 OutputDebugString(user);
1447 OutputDebugString("\n");
1450 code = pkrb5_init_context(&ctx);
1453 code = pkrb5_parse_name(ctx, user, &princ);
1454 if (code) goto loop_cleanup;
1456 code = KFW_get_ccache(ctx, princ, &cc);
1457 if (code) goto loop_cleanup;
1459 code = pkrb5_cc_destroy(ctx, cc);
1464 pkrb5_cc_close(ctx, cc);
1468 pkrb5_free_principal(ctx, princ);
1472 count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
1475 KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
1482 pkrb5_free_context(ctx);
1487 KFW_AFS_renew_expiring_tokens(void)
1489 krb5_error_code code = 0;
1490 krb5_context ctx = NULL;
1491 krb5_ccache cc = NULL;
1493 struct principal_ccache_data * pcc_next = princ_cc_data;
1496 const char * realm = NULL;
1497 char local_cell[MAXCELLCHARS+1]="";
1498 struct afsconf_cell cellconfig;
1500 if (!pkrb5_init_context)
1503 if ( pcc_next == NULL ) // nothing to do
1506 if ( IsDebuggerPresent() ) {
1507 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1510 code = pkrb5_init_context(&ctx);
1511 if (code) goto cleanup;
1513 code = pkrb5_timeofday(ctx, &now);
1514 if (code) goto cleanup;
1516 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1517 if ( pcc_next->expired )
1520 if ( now >= (pcc_next->expiration_time) ) {
1521 if ( !pcc_next->from_lsa ) {
1522 pcc_next->expired = 1;
1527 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1528 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1531 code = KFW_renew(ctx,cc);
1533 if ( code && pcc_next->from_lsa)
1535 #endif /* USE_MS2MIT */
1538 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1539 if (code) goto loop_cleanup;
1541 // Attempt to obtain new tokens for other cells supported by the same
1543 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1544 if ( cell_count > 0 ) {
1545 while ( cell_count-- ) {
1546 if ( IsDebuggerPresent() ) {
1547 OutputDebugString("Cell: ");
1548 OutputDebugString(cells[cell_count]);
1549 OutputDebugString("\n");
1551 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1552 if ( code ) continue;
1553 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1554 if ( IsDebuggerPresent() ) {
1555 OutputDebugString("Realm: ");
1556 OutputDebugString(realm);
1557 OutputDebugString("\n");
1559 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1560 if ( IsDebuggerPresent() ) {
1562 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1563 OutputDebugString(message);
1565 free(cells[cell_count]);
1573 pkrb5_cc_close(ctx,cc);
1580 pkrb5_cc_close(ctx,cc);
1582 pkrb5_free_context(ctx);
1589 KFW_AFS_renew_token_for_cell(char * cell)
1591 krb5_error_code code = 0;
1592 krb5_context ctx = NULL;
1594 char ** principals = NULL;
1596 if (!pkrb5_init_context)
1599 if ( IsDebuggerPresent() ) {
1600 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1601 OutputDebugString(cell);
1602 OutputDebugString("\n");
1605 code = pkrb5_init_context(&ctx);
1606 if (code) goto cleanup;
1608 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1610 // We know we must have a credential somewhere since we are
1611 // trying to renew a token
1613 KFW_import_ccache_data();
1614 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1617 krb5_principal princ = 0;
1618 krb5_principal service = 0;
1620 krb5_creds mcreds, creds;
1621 #endif /* COMMENT */
1623 const char * realm = NULL;
1624 struct afsconf_cell cellconfig;
1625 char local_cell[MAXCELLCHARS+1];
1628 code = pkrb5_parse_name(ctx, principals[count], &princ);
1629 if (code) goto loop_cleanup;
1631 code = KFW_get_ccache(ctx, princ, &cc);
1632 if (code) goto loop_cleanup;
1634 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1635 if ( code ) goto loop_cleanup;
1637 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1638 if ( IsDebuggerPresent() ) {
1639 OutputDebugString("Realm: ");
1640 OutputDebugString(realm);
1641 OutputDebugString("\n");
1645 /* krb5_cc_remove_cred() is not implemented
1648 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1649 realm, "afs", cell, NULL);
1651 memset(&mcreds, 0, sizeof(krb5_creds));
1652 mcreds.client = princ;
1653 mcreds.server = service;
1655 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1657 if ( IsDebuggerPresent() ) {
1658 char * cname, *sname;
1659 pkrb5_unparse_name(ctx, creds.client, &cname);
1660 pkrb5_unparse_name(ctx, creds.server, &sname);
1661 OutputDebugString("Removing credential for client \"");
1662 OutputDebugString(cname);
1663 OutputDebugString("\" and service \"");
1664 OutputDebugString(sname);
1665 OutputDebugString("\"\n");
1666 pkrb5_free_unparsed_name(ctx,cname);
1667 pkrb5_free_unparsed_name(ctx,sname);
1670 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1671 pkrb5_free_principal(ctx, creds.client);
1672 pkrb5_free_principal(ctx, creds.server);
1675 #endif /* COMMENT */
1677 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
1678 if ( IsDebuggerPresent() ) {
1680 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1681 OutputDebugString(message);
1686 pkrb5_cc_close(ctx, cc);
1690 pkrb5_free_principal(ctx, princ);
1694 pkrb5_free_principal(ctx, service);
1698 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1699 free(principals[count]);
1703 code = -1; // we did not renew the tokens
1707 pkrb5_free_context(ctx);
1708 return (code ? FALSE : TRUE);
1713 KFW_AFS_renew_tokens_for_all_cells(void)
1715 struct cell_principal_map * next = cell_princ_map;
1717 if ( IsDebuggerPresent() )
1718 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1723 for ( ; next ; next = next->next ) {
1725 KFW_AFS_renew_token_for_cell(next->cell);
1731 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1733 krb5_error_code code = 0;
1734 krb5_context ctx = NULL;
1735 krb5_ccache cc = NULL;
1736 krb5_principal me = NULL;
1737 krb5_principal server = NULL;
1738 krb5_creds my_creds;
1739 krb5_data *realm = NULL;
1741 if (!pkrb5_init_context)
1744 memset(&my_creds, 0, sizeof(krb5_creds));
1749 code = pkrb5_init_context(&ctx);
1750 if (code) goto cleanup;
1756 code = pkrb5_cc_default(ctx, &cc);
1757 if (code) goto cleanup;
1760 code = pkrb5_cc_get_principal(ctx, cc, &me);
1761 if (code) goto cleanup;
1763 realm = krb5_princ_realm(ctx, me);
1765 code = pkrb5_build_principal_ext(ctx, &server,
1766 realm->length,realm->data,
1767 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1768 realm->length,realm->data,
1773 if ( IsDebuggerPresent() ) {
1774 char * cname, *sname;
1775 pkrb5_unparse_name(ctx, me, &cname);
1776 pkrb5_unparse_name(ctx, server, &sname);
1777 OutputDebugString("Renewing credential for client \"");
1778 OutputDebugString(cname);
1779 OutputDebugString("\" and service \"");
1780 OutputDebugString(sname);
1781 OutputDebugString("\"\n");
1782 pkrb5_free_unparsed_name(ctx,cname);
1783 pkrb5_free_unparsed_name(ctx,sname);
1786 my_creds.client = me;
1787 my_creds.server = server;
1789 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1791 if ( IsDebuggerPresent() ) {
1793 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1794 OutputDebugString(message);
1799 code = pkrb5_cc_initialize(ctx, cc, me);
1801 if ( IsDebuggerPresent() ) {
1803 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1804 OutputDebugString(message);
1809 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1811 if ( IsDebuggerPresent() ) {
1813 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1814 OutputDebugString(message);
1820 if (my_creds.client == me)
1821 my_creds.client = 0;
1822 if (my_creds.server == server)
1823 my_creds.server = 0;
1824 pkrb5_free_cred_contents(ctx, &my_creds);
1826 pkrb5_free_principal(ctx, me);
1828 pkrb5_free_principal(ctx, server);
1829 if (cc && (cc != alt_cc))
1830 pkrb5_cc_close(ctx, cc);
1831 if (ctx && (ctx != alt_ctx))
1832 pkrb5_free_context(ctx);
1837 KFW_kinit( krb5_context alt_ctx,
1840 char *principal_name,
1842 krb5_deltat lifetime,
1845 krb5_deltat renew_life,
1850 krb5_error_code code = 0;
1851 krb5_context ctx = NULL;
1852 krb5_ccache cc = NULL;
1853 krb5_principal me = NULL;
1855 krb5_creds my_creds;
1856 krb5_get_init_creds_opt options;
1857 krb5_address ** addrs = NULL;
1858 int i = 0, addr_count = 0;
1860 if (!pkrb5_init_context)
1863 pkrb5_get_init_creds_opt_init(&options);
1864 memset(&my_creds, 0, sizeof(my_creds));
1872 code = pkrb5_init_context(&ctx);
1873 if (code) goto cleanup;
1879 code = pkrb5_cc_default(ctx, &cc);
1880 if (code) goto cleanup;
1883 code = pkrb5_parse_name(ctx, principal_name, &me);
1887 code = pkrb5_unparse_name(ctx, me, &name);
1892 lifetime = pLeash_get_default_lifetime();
1899 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1900 pkrb5_get_init_creds_opt_set_forwardable(&options,
1901 forwardable ? 1 : 0);
1902 pkrb5_get_init_creds_opt_set_proxiable(&options,
1904 pkrb5_get_init_creds_opt_set_renew_life(&options,
1907 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1911 // we are going to add the public IP address specified by the user
1912 // to the list provided by the operating system
1913 krb5_address ** local_addrs=NULL;
1916 pkrb5_os_localaddr(ctx, &local_addrs);
1917 while ( local_addrs[i++] );
1920 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1922 pkrb5_free_addresses(ctx, local_addrs);
1925 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1927 while ( local_addrs[i] ) {
1928 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1929 if (addrs[i] == NULL) {
1930 pkrb5_free_addresses(ctx, local_addrs);
1934 addrs[i]->magic = local_addrs[i]->magic;
1935 addrs[i]->addrtype = local_addrs[i]->addrtype;
1936 addrs[i]->length = local_addrs[i]->length;
1937 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1938 if (!addrs[i]->contents) {
1939 pkrb5_free_addresses(ctx, local_addrs);
1943 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1944 local_addrs[i]->length); /* safe */
1947 pkrb5_free_addresses(ctx, local_addrs);
1949 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1950 if (addrs[i] == NULL)
1953 addrs[i]->magic = KV5M_ADDRESS;
1954 addrs[i]->addrtype = AF_INET;
1955 addrs[i]->length = 4;
1956 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1957 if (!addrs[i]->contents)
1960 netIPAddr = htonl(publicIP);
1961 memcpy(addrs[i]->contents,&netIPAddr,4);
1963 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1968 code = pkrb5_get_init_creds_password(ctx,
1971 password, // password
1972 KRB5_prompter, // prompter
1973 hParent, // prompter data
1980 code = pkrb5_cc_initialize(ctx, cc, me);
1984 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1990 for ( i=0;i<addr_count;i++ ) {
1992 if ( addrs[i]->contents )
1993 free(addrs[i]->contents);
1998 if (my_creds.client == me)
1999 my_creds.client = 0;
2000 pkrb5_free_cred_contents(ctx, &my_creds);
2002 pkrb5_free_unparsed_name(ctx, name);
2004 pkrb5_free_principal(ctx, me);
2005 if (cc && (cc != alt_cc))
2006 pkrb5_cc_close(ctx, cc);
2007 if (ctx && (ctx != alt_ctx))
2008 pkrb5_free_context(ctx);
2014 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
2016 krb5_context ctx = NULL;
2017 krb5_ccache cc = NULL;
2018 krb5_error_code code;
2020 if (!pkrb5_init_context)
2029 code = pkrb5_init_context(&ctx);
2030 if (code) goto cleanup;
2036 code = pkrb5_cc_default(ctx, &cc);
2037 if (code) goto cleanup;
2040 code = pkrb5_cc_destroy(ctx, cc);
2041 if ( !code ) cc = 0;
2044 if (cc && (cc != alt_cc))
2045 pkrb5_cc_close(ctx, cc);
2046 if (ctx && (ctx != alt_ctx))
2047 pkrb5_free_context(ctx);
2055 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
2057 NTSTATUS Status = 0;
2059 TOKEN_STATISTICS Stats;
2065 *ppSessionData = NULL;
2067 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
2071 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
2072 CloseHandle( TokenHandle );
2076 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
2077 if ( FAILED(Status) || !ppSessionData )
2084 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
2085 // cache. It validates whether or not it is reasonable to assume that if we
2086 // attempted to retrieve valid tickets we could do so. Microsoft does not
2087 // automatically renew expired tickets. Therefore, the cache could contain
2088 // expired or invalid tickets. Microsoft also caches the user's password
2089 // and will use it to retrieve new TGTs if the cache is empty and tickets
2093 MSLSA_IsKerberosLogon(VOID)
2095 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
2096 BOOL Success = FALSE;
2098 if ( GetSecurityLogonSessionData(&pSessionData) ) {
2099 if ( pSessionData->AuthenticationPackage.Buffer ) {
2105 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
2106 usLength = (pSessionData->AuthenticationPackage).Length;
2109 lstrcpynW (buffer, usBuffer, usLength);
2110 lstrcatW (buffer,L"");
2111 if ( !lstrcmpW(L"Kerberos",buffer) )
2115 pLsaFreeReturnBuffer(pSessionData);
2119 #endif /* USE_MS2MIT */
2121 static BOOL CALLBACK
2122 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
2126 switch ( message ) {
2128 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
2130 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
2133 for ( i=0; i < mid_cnt ; i++ ) {
2134 if (mid_tb[i].echo == 0)
2135 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
2136 else if (mid_tb[i].echo == 2)
2137 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2142 switch ( LOWORD(wParam) ) {
2144 for ( i=0; i < mid_cnt ; i++ ) {
2145 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2146 *mid_tb[i].buf = '\0';
2150 EndDialog(hDialog, LOWORD(wParam));
2158 lpwAlign( LPWORD lpIn )
2162 ul = (ULONG_PTR) lpIn;
2166 return (LPWORD) ul;;
2170 * dialog widths are measured in 1/4 character widths
2171 * dialog height are measured in 1/8 character heights
2175 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2176 char * ptext[], int numlines, int width,
2177 int tb_cnt, struct textField * tb)
2181 LPDLGITEMTEMPLATE lpdit;
2187 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2194 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2196 // Define a dialog box.
2198 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2199 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2200 | DS_SETFOREGROUND | DS_3DLOOK
2201 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2202 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2205 lpdt->cx = 20 + width * 4;
2206 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2208 lpw = (LPWORD) (lpdt + 1);
2209 *lpw++ = 0; // no menu
2210 *lpw++ = 0; // predefined dialog box class (by default)
2212 lpwsz = (LPWSTR) lpw;
2213 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2215 *lpw++ = 8; // font size (points)
2216 lpwsz = (LPWSTR) lpw;
2217 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2221 //-----------------------
2222 // Define an OK button.
2223 //-----------------------
2224 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2225 lpdit = (LPDLGITEMTEMPLATE) lpw;
2226 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2227 lpdit->dwExtendedStyle = 0;
2228 lpdit->x = (lpdt->cx - 14)/4 - 20;
2229 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2232 lpdit->id = IDOK; // OK button identifier
2234 lpw = (LPWORD) (lpdit + 1);
2236 *lpw++ = 0x0080; // button class
2238 lpwsz = (LPWSTR) lpw;
2239 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2241 *lpw++ = 0; // no creation data
2243 //-----------------------
2244 // Define an Cancel button.
2245 //-----------------------
2246 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2247 lpdit = (LPDLGITEMTEMPLATE) lpw;
2248 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2249 lpdit->dwExtendedStyle = 0;
2250 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2251 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2254 lpdit->id = IDCANCEL; // CANCEL button identifier
2256 lpw = (LPWORD) (lpdit + 1);
2258 *lpw++ = 0x0080; // button class
2260 lpwsz = (LPWSTR) lpw;
2261 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2263 *lpw++ = 0; // no creation data
2265 /* Add controls for preface data */
2266 for ( i=0; i<numlines; i++) {
2267 /*-----------------------
2268 * Define a static text control.
2269 *-----------------------*/
2270 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2271 lpdit = (LPDLGITEMTEMPLATE) lpw;
2272 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2273 lpdit->dwExtendedStyle = 0;
2275 lpdit->y = 10 + i * 14;
2276 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2278 lpdit->id = ID_TEXT + i; // text identifier
2280 lpw = (LPWORD) (lpdit + 1);
2282 *lpw++ = 0x0082; // static class
2284 lpwsz = (LPWSTR) lpw;
2285 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2286 -1, lpwsz, 2*width);
2288 *lpw++ = 0; // no creation data
2291 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2292 int len = (int)strlen(tb[i].label);
2297 for ( i=0; i<tb_cnt; i++) {
2299 /*-----------------------
2300 * Define a static text control.
2301 *-----------------------*/
2302 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2303 lpdit = (LPDLGITEMTEMPLATE) lpw;
2304 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2305 lpdit->dwExtendedStyle = 0;
2307 lpdit->y = 10 + (numlines + i + 1) * 14;
2308 lpdit->cx = pwid * 4;
2310 lpdit->id = ID_TEXT + numlines + i; // text identifier
2312 lpw = (LPWORD) (lpdit + 1);
2314 *lpw++ = 0x0082; // static class
2316 lpwsz = (LPWSTR) lpw;
2317 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2320 *lpw++ = 0; // no creation data
2322 /*-----------------------
2323 * Define an edit control.
2324 *-----------------------*/
2325 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2326 lpdit = (LPDLGITEMTEMPLATE) lpw;
2327 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2328 lpdit->dwExtendedStyle = 0;
2329 lpdit->x = 10 + (pwid + 1) * 4;
2330 lpdit->y = 10 + (numlines + i + 1) * 14;
2331 lpdit->cx = (width - (pwid + 1)) * 4;
2333 lpdit->id = ID_MID_TEXT + i; // identifier
2335 lpw = (LPWORD) (lpdit + 1);
2337 *lpw++ = 0x0081; // edit class
2339 lpwsz = (LPWSTR) lpw;
2340 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2343 *lpw++ = 0; // no creation data
2347 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2348 hwndOwner, (DLGPROC) MultiInputDialogProc);
2352 case 0: /* Timeout */
2360 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2361 MessageBox(hwndOwner,
2364 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2371 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2373 HINSTANCE hInst = 0;
2377 char * plines[16], *p = preface ? preface : "";
2380 for ( i=0; i<16; i++ )
2383 while (*p && numlines < 16) {
2384 plines[numlines++] = p;
2385 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2386 if ( *p == '\r' && *(p+1) == '\n' ) {
2389 } else if ( *p == '\n' ) {
2392 if ( strlen(plines[numlines-1]) > maxwidth )
2393 maxwidth = (int)strlen(plines[numlines-1]);
2396 for ( i=0;i<n;i++ ) {
2397 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2398 if ( maxwidth < len )
2402 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2405 static krb5_error_code KRB5_CALLCONV
2406 KRB5_prompter( krb5_context context,
2411 krb5_prompt prompts[])
2413 krb5_error_code errcode = 0;
2415 struct textField * tb = NULL;
2416 int len = 0, blen=0, nlen=0;
2417 HWND hParent = (HWND)data;
2420 nlen = (int)strlen(name)+2;
2423 blen = (int)strlen(banner)+2;
2425 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2428 memset(tb,0,sizeof(struct textField) * num_prompts);
2429 for ( i=0; i < num_prompts; i++ ) {
2430 tb[i].buf = prompts[i].reply->data;
2431 tb[i].len = prompts[i].reply->length;
2432 tb[i].label = prompts[i].prompt;
2434 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2437 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2439 for ( i=0; i < num_prompts; i++ )
2440 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2448 for (i = 0; i < num_prompts; i++) {
2449 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2456 KFW_AFS_wait_for_service_start(void)
2461 CurrentState = SERVICE_START_PENDING;
2462 memset(HostName, '\0', sizeof(HostName));
2463 gethostname(HostName, sizeof(HostName));
2465 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2467 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2469 if ( IsDebuggerPresent() ) {
2470 switch ( CurrentState ) {
2471 case SERVICE_STOPPED:
2472 OutputDebugString("SERVICE_STOPPED\n");
2474 case SERVICE_START_PENDING:
2475 OutputDebugString("SERVICE_START_PENDING\n");
2477 case SERVICE_STOP_PENDING:
2478 OutputDebugString("SERVICE_STOP_PENDING\n");
2480 case SERVICE_RUNNING:
2481 OutputDebugString("SERVICE_RUNNING\n");
2483 case SERVICE_CONTINUE_PENDING:
2484 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2486 case SERVICE_PAUSE_PENDING:
2487 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2489 case SERVICE_PAUSED:
2490 OutputDebugString("SERVICE_PAUSED\n");
2493 OutputDebugString("UNKNOWN Service State\n");
2496 if (CurrentState == SERVICE_STOPPED)
2498 if (CurrentState == SERVICE_RUNNING)
2514 memset(HostName, '\0', sizeof(HostName));
2515 gethostname(HostName, sizeof(HostName));
2516 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2518 if (CurrentState != SERVICE_RUNNING)
2521 rc = ktc_ForgetAllTokens();
2527 #define ALLOW_REGISTER 1
2529 ViceIDToUsername(char *username,
2530 char *realm_of_user,
2531 char *realm_of_cell,
2533 struct ktc_principal *aclient,
2534 struct ktc_principal *aserver,
2535 struct ktc_token *atoken)
2537 static char lastcell[MAXCELLCHARS+1] = { 0 };
2538 static char confname[512] = { 0 };
2539 #ifdef AFS_ID_TO_NAME
2540 char username_copy[BUFSIZ];
2541 #endif /* AFS_ID_TO_NAME */
2542 long viceId = ANONYMOUSID; /* AFS uid of user */
2544 #ifdef ALLOW_REGISTER
2546 #endif /* ALLOW_REGISTER */
2548 if (confname[0] == '\0') {
2549 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
2550 confname[sizeof(confname) - 2] = '\0';
2553 strcpy(lastcell, aserver->cell);
2555 if (!pr_Initialize (0, confname, aserver->cell)) {
2556 char sname[PR_MAXNAMELEN];
2557 strncpy(sname, username, PR_MAXNAMELEN);
2558 sname[PR_MAXNAMELEN-1] = '\0';
2559 status = pr_SNameToId (sname, &viceId);
2564 * This is a crock, but it is Transarc's crock, so
2565 * we have to play along in order to get the
2566 * functionality. The way the afs id is stored is
2567 * as a string in the username field of the token.
2568 * Contrary to what you may think by looking at
2569 * the code for tokens, this hack (AFS ID %d) will
2570 * not work if you change %d to something else.
2574 * This code is taken from cklog -- it lets people
2575 * automatically register with the ptserver in foreign cells
2578 #ifdef ALLOW_REGISTER
2580 if (viceId != ANONYMOUSID) {
2581 #else /* ALLOW_REGISTER */
2582 if ((status == 0) && (viceId != ANONYMOUSID))
2583 #endif /* ALLOW_REGISTER */
2585 #ifdef AFS_ID_TO_NAME
2586 strncpy(username_copy, username, BUFSIZ);
2587 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2588 #endif /* AFS_ID_TO_NAME */
2590 #ifdef ALLOW_REGISTER
2591 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2593 strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
2594 strcpy(aclient->instance, "");
2595 strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
2596 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2598 if (status = pr_Initialize(1L, confname, aserver->cell))
2600 status = pr_CreateUser(username, &id);
2604 #ifdef AFS_ID_TO_NAME
2605 strncpy(username_copy, username, BUFSIZ);
2606 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2607 #endif /* AFS_ID_TO_NAME */
2610 #endif /* ALLOW_REGISTER */
2617 krb5_context alt_ctx,
2622 int lifetime, /* unused parameter */
2630 #endif /* USE_KRB4 */
2631 struct ktc_principal aserver;
2632 struct ktc_principal aclient;
2633 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2634 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2635 char local_cell[MAXCELLCHARS+1];
2636 char Dmycell[MAXCELLCHARS+1];
2637 struct ktc_token atoken;
2638 struct ktc_token btoken;
2639 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2640 char RealmName[128];
2642 char ServiceName[128];
2646 krb5_context ctx = NULL;
2647 krb5_ccache cc = NULL;
2649 krb5_creds * k5creds = NULL;
2650 krb5_error_code code;
2651 krb5_principal client_principal = NULL;
2652 krb5_data * k5data = NULL;
2656 memset(HostName, '\0', sizeof(HostName));
2657 gethostname(HostName, sizeof(HostName));
2658 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2659 if ( IsDebuggerPresent() )
2660 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2663 if (CurrentState != SERVICE_RUNNING) {
2664 if ( IsDebuggerPresent() )
2665 OutputDebugString("AFSD Service NOT RUNNING\n");
2669 if (!pkrb5_init_context)
2672 memset(RealmName, '\0', sizeof(RealmName));
2673 memset(CellName, '\0', sizeof(CellName));
2674 memset(ServiceName, '\0', sizeof(ServiceName));
2675 memset(realm_of_user, '\0', sizeof(realm_of_user));
2676 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2677 if (cell && cell[0])
2678 strcpy(Dmycell, cell);
2680 memset(Dmycell, '\0', sizeof(Dmycell));
2682 // NULL or empty cell returns information on local cell
2683 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2685 // KFW_AFS_error(rc, "get_cellconfig()");
2692 code = pkrb5_init_context(&ctx);
2693 if (code) goto cleanup;
2699 code = pkrb5_cc_default(ctx, &cc);
2700 if (code) goto skip_krb5_init;
2703 memset((char *)&increds, 0, sizeof(increds));
2705 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2707 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2709 OutputDebugString("Principal Not Found for ccache\n");
2711 goto skip_krb5_init;
2714 /* look for client principals which cannot be distinguished
2715 * from Kerberos 4 multi-component principal names
2717 k5data = krb5_princ_component(ctx,client_principal,0);
2718 for ( i=0; i<k5data->length; i++ ) {
2719 if ( k5data->data[i] == '.' )
2722 if (i != k5data->length)
2724 OutputDebugString("Illegal Principal name contains dot in first component\n");
2725 rc = KRB5KRB_ERR_GENERIC;
2729 i = krb5_princ_realm(ctx, client_principal)->length;
2732 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2733 realm_of_user[i] = 0;
2738 if ( !try_krb5 || !realm_of_user[0] ) {
2739 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2748 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2750 if (strlen(service) == 0)
2751 strcpy(ServiceName, "afs");
2753 strcpy(ServiceName, service);
2755 if (strlen(cell) == 0)
2756 strcpy(CellName, local_cell);
2758 strcpy(CellName, cell);
2760 if (strlen(realm) == 0)
2761 strcpy(RealmName, realm_of_cell);
2763 strcpy(RealmName, realm);
2765 memset(&creds, '\0', sizeof(creds));
2770 /* First try service/cell@REALM */
2771 if (code = pkrb5_build_principal(ctx, &increds.server,
2772 (int)strlen(RealmName),
2781 increds.client = client_principal;
2782 increds.times.endtime = 0;
2783 /* Ask for DES since that is what V4 understands */
2784 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2787 if ( IsDebuggerPresent() ) {
2788 char * cname, *sname;
2789 pkrb5_unparse_name(ctx, increds.client, &cname);
2790 pkrb5_unparse_name(ctx, increds.server, &sname);
2791 OutputDebugString("Getting tickets for \"");
2792 OutputDebugString(cname);
2793 OutputDebugString("\" and service \"");
2794 OutputDebugString(sname);
2795 OutputDebugString("\"\n");
2796 pkrb5_free_unparsed_name(ctx,cname);
2797 pkrb5_free_unparsed_name(ctx,sname);
2800 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2801 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2802 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2803 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2804 /* Or service@REALM */
2805 pkrb5_free_principal(ctx,increds.server);
2807 code = pkrb5_build_principal(ctx, &increds.server,
2808 (int)strlen(RealmName),
2813 if ( IsDebuggerPresent() ) {
2814 char * cname, *sname;
2815 pkrb5_unparse_name(ctx, increds.client, &cname);
2816 pkrb5_unparse_name(ctx, increds.server, &sname);
2817 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2818 OutputDebugString("Trying again: getting tickets for \"");
2819 OutputDebugString(cname);
2820 OutputDebugString("\" and service \"");
2821 OutputDebugString(sname);
2822 OutputDebugString("\"\n");
2823 pkrb5_free_unparsed_name(ctx,cname);
2824 pkrb5_free_unparsed_name(ctx,sname);
2828 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2831 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2832 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2833 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2834 strcmp(RealmName, realm_of_cell)) {
2835 /* Or service/cell@REALM_OF_CELL */
2836 strcpy(RealmName, realm_of_cell);
2837 pkrb5_free_principal(ctx,increds.server);
2839 code = pkrb5_build_principal(ctx, &increds.server,
2840 (int)strlen(RealmName),
2846 if ( IsDebuggerPresent() ) {
2847 char * cname, *sname;
2848 pkrb5_unparse_name(ctx, increds.client, &cname);
2849 pkrb5_unparse_name(ctx, increds.server, &sname);
2850 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2851 OutputDebugString("Trying again: getting tickets for \"");
2852 OutputDebugString(cname);
2853 OutputDebugString("\" and service \"");
2854 OutputDebugString(sname);
2855 OutputDebugString("\"\n");
2856 pkrb5_free_unparsed_name(ctx,cname);
2857 pkrb5_free_unparsed_name(ctx,sname);
2861 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2864 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2865 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2866 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2867 /* Or service@REALM_OF_CELL */
2868 pkrb5_free_principal(ctx,increds.server);
2870 code = pkrb5_build_principal(ctx, &increds.server,
2871 (int)strlen(RealmName),
2876 if ( IsDebuggerPresent() ) {
2877 char * cname, *sname;
2878 pkrb5_unparse_name(ctx, increds.client, &cname);
2879 pkrb5_unparse_name(ctx, increds.server, &sname);
2880 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2881 OutputDebugString("Trying again: getting tickets for \"");
2882 OutputDebugString(cname);
2883 OutputDebugString("\" and service \"");
2884 OutputDebugString(sname);
2885 OutputDebugString("\"\n");
2886 pkrb5_free_unparsed_name(ctx,cname);
2887 pkrb5_free_unparsed_name(ctx,sname);
2891 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2896 if ( IsDebuggerPresent() ) {
2898 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2899 OutputDebugString(message);
2905 /* This code inserts the entire K5 ticket into the token
2906 * No need to perform a krb524 translation which is
2907 * commented out in the code below
2909 if (KFW_use_krb524() ||
2910 k5creds->ticket.length > MAXKTCTICKETLEN)
2913 memset(&aserver, '\0', sizeof(aserver));
2914 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2915 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2917 memset(&atoken, '\0', sizeof(atoken));
2918 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2919 atoken.startTime = k5creds->times.starttime;
2920 atoken.endTime = k5creds->times.endtime;
2921 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2922 atoken.ticketLen = k5creds->ticket.length;
2923 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2926 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2927 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2928 if ( rc == KTC_NOCM && retry < 20 ) {
2931 goto retry_gettoken5;
2936 if (atoken.kvno == btoken.kvno &&
2937 atoken.ticketLen == btoken.ticketLen &&
2938 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2939 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2941 /* Success - Nothing to do */
2945 // * Reset the "aclient" structure before we call ktc_SetToken.
2946 // * This structure was first set by the ktc_GetToken call when
2947 // * we were comparing whether identical tokens already existed.
2949 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2950 strncpy(aclient.name, k5creds->client->data[0].data, len);
2951 aclient.name[len] = '\0';
2953 if ( k5creds->client->length > 1 ) {
2955 strcat(aclient.name, ".");
2956 p = aclient.name + strlen(aclient.name);
2957 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2958 strncpy(p, k5creds->client->data[1].data, len);
2961 aclient.instance[0] = '\0';
2963 strcpy(aclient.cell, realm_of_cell);
2965 len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
2966 /* For Khimaira, always append the realm name */
2967 if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
2969 strcat(aclient.name, "@");
2970 p = aclient.name + strlen(aclient.name);
2971 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
2972 strncpy(p, k5creds->client->realm.data, len);
2976 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2977 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2978 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2979 &aclient, &aserver, &atoken);
2982 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
2983 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
2985 aclient.smbname[0] = '\0';
2988 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2990 goto cleanup; /* We have successfully inserted the token */
2993 /* Otherwise, the ticket could have been too large so try to
2994 * convert using the krb524d running with the KDC
2996 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2997 pkrb5_free_creds(ctx, k5creds);
2999 if ( IsDebuggerPresent() ) {
3001 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
3002 OutputDebugString(message);
3010 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
3011 if (code == NO_TKT_FIL) {
3012 // if the problem is that we have no krb4 tickets
3013 // do not attempt to continue
3016 if (code != KSUCCESS)
3017 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
3019 if (code != KSUCCESS)
3021 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
3023 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
3028 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
3030 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
3045 memset(&aserver, '\0', sizeof(aserver));
3046 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
3047 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
3049 memset(&atoken, '\0', sizeof(atoken));
3050 atoken.kvno = creds.kvno;
3051 atoken.startTime = creds.issue_date;
3052 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
3053 memcpy(&atoken.sessionKey, creds.session, 8);
3054 atoken.ticketLen = creds.ticket_st.length;
3055 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
3058 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
3059 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
3060 if ( rc == KTC_NOCM && retry < 20 ) {
3063 goto retry_gettoken;
3065 KFW_AFS_error(rc, "ktc_GetToken()");
3070 if (atoken.kvno == btoken.kvno &&
3071 atoken.ticketLen == btoken.ticketLen &&
3072 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
3073 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
3078 // * Reset the "aclient" structure before we call ktc_SetToken.
3079 // * This structure was first set by the ktc_GetToken call when
3080 // * we were comparing whether identical tokens already existed.
3082 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
3085 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
3086 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
3088 strcpy(aclient.instance, "");
3090 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
3091 strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
3092 aclient.name[MAXKTCREALMLEN-1] = '\0';
3094 strcpy(aclient.cell, CellName);
3096 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
3097 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
3098 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
3099 &aclient, &aserver, &atoken);
3102 strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
3103 aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
3105 aclient.smbname[0] = '\0';
3108 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
3110 KFW_AFS_error(rc, "ktc_SetToken()");
3116 if (client_principal)
3117 pkrb5_free_principal(ctx,client_principal);
3118 /* increds.client == client_principal */
3120 pkrb5_free_principal(ctx,increds.server);
3121 if (cc && (cc != alt_cc))
3122 pkrb5_cc_close(ctx, cc);
3123 if (ctx && (ctx != alt_ctx))
3124 pkrb5_free_context(ctx);
3126 return(rc? rc : code);
3129 /**************************************/
3130 /* afs_realm_of_cell(): */
3131 /**************************************/
3133 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
3135 static char krbrlm[REALM_SZ+1]="";
3136 char ** realmlist=NULL;
3142 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
3143 if ( !r && realmlist && realmlist[0] ) {
3144 strcpy(krbrlm, realmlist[0]);
3145 pkrb5_free_host_realm(ctx, realmlist);
3151 char *t = cellconfig->name;
3156 if (islower(c)) c=toupper(c);
3164 /**************************************/
3165 /* KFW_AFS_get_cellconfig(): */
3166 /**************************************/
3168 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
3171 char newcell[MAXCELLCHARS+1];
3173 local_cell[0] = (char)0;
3174 memset(cellconfig, 0, sizeof(*cellconfig));
3176 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
3177 if (rc = cm_GetRootCellName(local_cell))
3182 if (strlen(cell) == 0)
3183 strcpy(cell, local_cell);
3185 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
3186 strcpy(cellconfig->name, cell);
3188 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
3189 #ifdef AFS_AFSDB_ENV
3192 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
3198 /**************************************/
3199 /* get_cellconfig_callback(): */
3200 /**************************************/
3202 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
3204 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
3206 cc->hostAddr[cc->numServers] = *addrp;
3207 strcpy(cc->hostName[cc->numServers], namep);
3213 /**************************************/
3214 /* KFW_AFS_error(): */
3215 /**************************************/
3217 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
3220 const char *errText;
3222 // Using AFS defines as error messages for now, until Transarc
3223 // gets back to me with "string" translations of each of these
3225 if (rc == KTC_ERROR)
3226 errText = "KTC_ERROR";
3227 else if (rc == KTC_TOOBIG)
3228 errText = "KTC_TOOBIG";
3229 else if (rc == KTC_INVAL)
3230 errText = "KTC_INVAL";
3231 else if (rc == KTC_NOENT)
3232 errText = "KTC_NOENT";
3233 else if (rc == KTC_PIOCTLFAIL)
3234 errText = "KTC_PIOCTLFAIL";
3235 else if (rc == KTC_NOPIOCTL)
3236 errText = "KTC_NOPIOCTL";
3237 else if (rc == KTC_NOCELL)
3238 errText = "KTC_NOCELL";
3239 else if (rc == KTC_NOCM)
3240 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3242 errText = "Unknown error!";
3244 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3246 if ( IsDebuggerPresent() ) {
3247 OutputDebugString(message);
3248 OutputDebugString("\n");
3250 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3256 LPSTR lpszMachineName,
3257 LPSTR lpszServiceName,
3258 DWORD *lpdwCurrentState)
3261 SC_HANDLE schSCManager = NULL;
3262 SC_HANDLE schService = NULL;
3263 DWORD fdwDesiredAccess = 0;
3264 SERVICE_STATUS ssServiceStatus = {0};
3267 *lpdwCurrentState = 0;
3269 fdwDesiredAccess = GENERIC_READ;
3271 schSCManager = OpenSCManager(lpszMachineName,
3275 if(schSCManager == NULL)
3277 hr = GetLastError();
3281 schService = OpenService(schSCManager,
3285 if(schService == NULL)
3287 hr = GetLastError();
3291 fRet = QueryServiceStatus(schService,
3296 hr = GetLastError();
3300 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3304 CloseServiceHandle(schService);
3305 CloseServiceHandle(schSCManager);
3318 for (n = 0; fi[n].func_ptr_var; n++)
3319 *(fi[n].func_ptr_var) = 0;
3320 if (h) FreeLibrary(h);
3325 const char* dll_name,
3327 HINSTANCE* ph, // [out, optional] - DLL handle
3328 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3329 int cleanup, // cleanup function pointers and unload on error
3330 int go_on, // continue loading even if some functions cannot be loaded
3331 int silent // do not pop-up a system dialog if DLL cannot be loaded
3340 if (pindex) *pindex = -1;
3342 for (n = 0; fi[n].func_ptr_var; n++)
3343 *(fi[n].func_ptr_var) = 0;
3346 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3347 h = LoadLibrary(dll_name);
3355 for (i = 0; (go_on || !error) && (i < n); i++)
3357 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3363 *(fi[i].func_ptr_var) = p;
3366 if (pindex) *pindex = last_i;
3367 if (error && cleanup && !go_on) {
3368 for (i = 0; i < n; i++) {
3369 *(fi[i].func_ptr_var) = 0;
3375 if (error) return 0;
3379 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3381 krb5_context ctx = NULL;
3382 krb5_ccache cc = NULL;
3383 krb5_error_code code;
3385 const char * realm = NULL;
3386 krb5_principal principal = NULL;
3387 char * pname = NULL;
3388 char password[PROBE_PASSWORD_LEN+1];
3389 BOOL serverReachable = 0;
3391 if (!pkrb5_init_context)
3394 code = pkrb5_init_context(&ctx);
3395 if (code) goto cleanup;
3398 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3400 code = pkrb5_build_principal(ctx, &principal, (int)strlen(realm),
3401 realm, PROBE_USERNAME, NULL, NULL);
3402 if ( code ) goto cleanup;
3404 code = KFW_get_ccache(ctx, principal, &cc);
3405 if ( code ) goto cleanup;
3407 code = pkrb5_unparse_name(ctx, principal, &pname);
3408 if ( code ) goto cleanup;
3410 pwdata.data = password;
3411 pwdata.length = PROBE_PASSWORD_LEN;
3412 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3415 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3418 password[PROBE_PASSWORD_LEN] = '\0';
3420 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3430 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3431 case KRB5KDC_ERR_CLIENT_REVOKED:
3432 case KRB5KDC_ERR_CLIENT_NOTYET:
3433 case KRB5KDC_ERR_PREAUTH_FAILED:
3434 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3435 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3436 serverReachable = TRUE;
3439 serverReachable = FALSE;
3444 pkrb5_free_unparsed_name(ctx,pname);
3446 pkrb5_free_principal(ctx,principal);
3448 pkrb5_cc_close(ctx,cc);
3450 pkrb5_free_context(ctx);
3452 return serverReachable;
3456 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3458 krb5_context ctx = NULL;
3459 krb5_error_code code;
3460 krb5_ccache mslsa_ccache=NULL;
3461 krb5_principal princ = NULL;
3462 char * pname = NULL;
3465 if (!KFW_is_available())
3468 if (code = pkrb5_init_context(&ctx))
3471 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
3474 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
3477 if (code = pkrb5_unparse_name(ctx, princ, &pname))
3480 if ( strlen(pname) < *dwSize ) {
3481 strncpy(szUser, pname, *dwSize);
3482 szUser[*dwSize-1] = '\0';
3485 *dwSize = (DWORD)strlen(pname);
3489 pkrb5_free_unparsed_name(ctx, pname);
3492 pkrb5_free_principal(ctx, princ);
3495 pkrb5_cc_close(ctx, mslsa_ccache);
3498 pkrb5_free_context(ctx);
3503 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3505 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3506 PSID pSystemSID = NULL;
3507 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3508 PACL ccacheACL = NULL;
3509 DWORD ccacheACLlength = 0;
3510 PTOKEN_USER pTokenUser = NULL;
3519 /* Get System SID */
3520 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3526 SystemSIDlength = GetLengthSid(pSystemSID);
3527 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3528 + SystemSIDlength - sizeof(DWORD);
3531 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3533 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3534 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3536 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3541 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3543 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3548 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3553 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3554 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3555 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3558 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3559 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3560 pTokenUser->User.Sid);
3561 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3562 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3567 gle = GetLastError();
3568 if (gle != ERROR_NO_TOKEN)
3571 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3572 OWNER_SECURITY_INFORMATION,
3573 pTokenUser->User.Sid,
3577 gle = GetLastError();
3578 if (gle != ERROR_NO_TOKEN)
3582 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3583 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3588 gle = GetLastError();
3589 if (gle != ERROR_NO_TOKEN)
3596 LocalFree(pSystemSID);
3598 LocalFree(pTokenUser);
3600 LocalFree(ccacheACL);
3605 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3608 DWORD dwSize = size-1; /* leave room for nul */
3611 if (!hUserToken || !newfilename || size <= 0)
3614 *newfilename = '\0';
3616 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3617 if ( !dwLen || dwLen > dwSize )
3618 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3619 if ( !dwLen || dwLen > dwSize )
3622 newfilename[dwSize] = '\0';
3627 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3629 char filename[MAX_PATH] = "";
3631 char cachename[MAX_PATH + 8] = "FILE:";
3632 krb5_context ctx = NULL;
3633 krb5_error_code code;
3634 krb5_principal princ = NULL;
3635 krb5_ccache cc = NULL;
3636 krb5_ccache ncc = NULL;
3638 if (!pkrb5_init_context || !user || !szLogonId)
3641 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3642 if ( count > sizeof(filename) || count == 0 ) {
3643 GetWindowsDirectory(filename, sizeof(filename));
3646 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3649 strcat(filename, "\\");
3650 strcat(filename, szLogonId);
3652 strcat(cachename, filename);
3654 DeleteFile(filename);
3656 code = pkrb5_init_context(&ctx);
3657 if (code) goto cleanup;
3659 code = pkrb5_parse_name(ctx, user, &princ);
3660 if (code) goto cleanup;
3662 code = KFW_get_ccache(ctx, princ, &cc);
3663 if (code) goto cleanup;
3665 code = pkrb5_cc_resolve(ctx, cachename, &ncc);
3666 if (code) goto cleanup;
3668 code = pkrb5_cc_initialize(ctx, ncc, princ);
3669 if (code) goto cleanup;
3671 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3672 if (code) goto cleanup;
3674 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3678 pkrb5_cc_close(ctx, cc);
3682 pkrb5_cc_close(ctx, ncc);
3686 pkrb5_free_principal(ctx, princ);
3691 pkrb5_free_context(ctx);
3695 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3697 char cachename[MAX_PATH + 8] = "FILE:";
3698 krb5_context ctx = NULL;
3699 krb5_error_code code;
3700 krb5_principal princ = NULL;
3701 krb5_ccache cc = NULL;
3702 krb5_ccache ncc = NULL;
3705 if (!pkrb5_init_context || !filename)
3708 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3711 code = pkrb5_init_context(&ctx);
3714 strcat(cachename, filename);
3716 code = pkrb5_cc_resolve(ctx, cachename, &cc);
3717 if (code) goto cleanup;
3719 code = pkrb5_cc_get_principal(ctx, cc, &princ);
3721 code = pkrb5_cc_default(ctx, &ncc);
3723 code = pkrb5_cc_initialize(ctx, ncc, princ);
3726 code = pkrb5_cc_copy_creds(ctx,cc,ncc);
3729 pkrb5_cc_close(ctx, ncc);
3733 retval=0; /* success */
3737 pkrb5_cc_close(ctx, cc);
3741 DeleteFile(filename);
3744 pkrb5_free_principal(ctx, princ);
3749 pkrb5_free_context(ctx);
3754 /* We are including this
3756 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3757 fixed part of rande of the one byte lifetime field. Values less than 0x80
3758 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3759 0xBF should be looked up in this table. The value of 0x80 is the same using
3760 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3761 The intervening values of have a fixed ratio of roughly 1.06914. The value
3762 oxFF is defined to mean a ticket has no expiration time. This should be
3763 used advisedly since individual servers may impose defacto upperbounds on
3764 ticket lifetimes. */
3766 #define TKTLIFENUMFIXED 64
3767 #define TKTLIFEMINFIXED 0x80
3768 #define TKTLIFEMAXFIXED 0xBF
3769 #define TKTLIFENOEXPIRE 0xFF
3770 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3772 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3773 38400, /* 10.67 hours, 0.44 days */
3774 41055, /* 11.40 hours, 0.48 days */
3775 43894, /* 12.19 hours, 0.51 days */
3776 46929, /* 13.04 hours, 0.54 days */
3777 50174, /* 13.94 hours, 0.58 days */
3778 53643, /* 14.90 hours, 0.62 days */
3779 57352, /* 15.93 hours, 0.66 days */
3780 61318, /* 17.03 hours, 0.71 days */
3781 65558, /* 18.21 hours, 0.76 days */
3782 70091, /* 19.47 hours, 0.81 days */
3783 74937, /* 20.82 hours, 0.87 days */
3784 80119, /* 22.26 hours, 0.93 days */
3785 85658, /* 23.79 hours, 0.99 days */
3786 91581, /* 25.44 hours, 1.06 days */
3787 97914, /* 27.20 hours, 1.13 days */
3788 104684, /* 29.08 hours, 1.21 days */
3789 111922, /* 31.09 hours, 1.30 days */
3790 119661, /* 33.24 hours, 1.38 days */
3791 127935, /* 35.54 hours, 1.48 days */
3792 136781, /* 37.99 hours, 1.58 days */
3793 146239, /* 40.62 hours, 1.69 days */
3794 156350, /* 43.43 hours, 1.81 days */
3795 167161, /* 46.43 hours, 1.93 days */
3796 178720, /* 49.64 hours, 2.07 days */
3797 191077, /* 53.08 hours, 2.21 days */
3798 204289, /* 56.75 hours, 2.36 days */
3799 218415, /* 60.67 hours, 2.53 days */
3800 233517, /* 64.87 hours, 2.70 days */
3801 249664, /* 69.35 hours, 2.89 days */
3802 266926, /* 74.15 hours, 3.09 days */
3803 285383, /* 79.27 hours, 3.30 days */
3804 305116, /* 84.75 hours, 3.53 days */
3805 326213, /* 90.61 hours, 3.78 days */
3806 348769, /* 96.88 hours, 4.04 days */
3807 372885, /* 103.58 hours, 4.32 days */
3808 398668, /* 110.74 hours, 4.61 days */
3809 426234, /* 118.40 hours, 4.93 days */
3810 455705, /* 126.58 hours, 5.27 days */
3811 487215, /* 135.34 hours, 5.64 days */
3812 520904, /* 144.70 hours, 6.03 days */
3813 556921, /* 154.70 hours, 6.45 days */
3814 595430, /* 165.40 hours, 6.89 days */
3815 636601, /* 176.83 hours, 7.37 days */
3816 680618, /* 189.06 hours, 7.88 days */
3817 727680, /* 202.13 hours, 8.42 days */
3818 777995, /* 216.11 hours, 9.00 days */
3819 831789, /* 231.05 hours, 9.63 days */
3820 889303, /* 247.03 hours, 10.29 days */
3821 950794, /* 264.11 hours, 11.00 days */
3822 1016537, /* 282.37 hours, 11.77 days */
3823 1086825, /* 301.90 hours, 12.58 days */
3824 1161973, /* 322.77 hours, 13.45 days */
3825 1242318, /* 345.09 hours, 14.38 days */
3826 1328218, /* 368.95 hours, 15.37 days */
3827 1420057, /* 394.46 hours, 16.44 days */
3828 1518247, /* 421.74 hours, 17.57 days */
3829 1623226, /* 450.90 hours, 18.79 days */
3830 1735464, /* 482.07 hours, 20.09 days */
3831 1855462, /* 515.41 hours, 21.48 days */
3832 1983758, /* 551.04 hours, 22.96 days */
3833 2120925, /* 589.15 hours, 24.55 days */
3834 2267576, /* 629.88 hours, 26.25 days */
3835 2424367, /* 673.44 hours, 28.06 days */
3837 }; /* 720.00 hours, 30.00 days */
3839 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3840 * returns the corresponding end time. There are four simple cases to be
3841 * handled. The first is a life of 0xff, meaning no expiration, and results in
3842 * an end time of 0xffffffff. The second is when life is less than the values
3843 * covered by the table. In this case, the end time is the start time plus the
3844 * number of 5 minute intervals specified by life. The third case returns
3845 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3846 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3847 * table to extract the lifetime in seconds, which is added to start to produce
3851 life_to_time(afs_uint32 start, unsigned char life)
3855 if (life == TKTLIFENOEXPIRE)
3857 if (life < TKTLIFEMINFIXED)
3858 return start + life * 5 * 60;
3859 if (life > TKTLIFEMAXFIXED)
3860 return start + MAXTKTLIFETIME;
3861 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3862 return start + realLife;
3865 /* time_to_life - takes start and end times for the ticket and returns a
3866 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3867 * lifetimes above 127*5minutes. First, the special case of (end ==
3868 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3869 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3870 * less than the first table entry are handled by rounding the requested
3871 * lifetime *up* to the next 5 minute interval. The final step is to search
3872 * the table for the smallest entry *greater than or equal* to the requested
3873 * entry. The actual code is prepared to handle the case where the table is
3874 * unordered but that it an unnecessary frill. */
3876 static unsigned char
3877 time_to_life(afs_uint32 start, afs_uint32 end)
3879 int lifetime = end - start;
3883 if (end == NEVERDATE)
3884 return TKTLIFENOEXPIRE;
3885 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3887 if (lifetime < tkt_lifetimes[0])
3888 return (lifetime + 5 * 60 - 1) / (5 * 60);
3890 best = MAXKTCTICKETLIFETIME;
3891 for (i = 0; i < TKTLIFENUMFIXED; i++)
3892 if (tkt_lifetimes[i] >= lifetime) {
3893 int diff = tkt_lifetimes[i] - lifetime;
3901 return best_i + TKTLIFEMINFIXED;