2 * Copyright (c) 2003 SkyRope, LLC
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Skyrope, LLC nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission from Skyrope, LLC.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Portions of this code are derived from portions of the MIT
30 * Leash Ticket Manager and LoadFuncs utilities. For these portions the
31 * following copyright applies.
33 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
34 * All rights reserved.
36 * Export of this software from the United States of America may
37 * require a specific license from the United States Government.
38 * It is the responsibility of any person or organization contemplating
39 * export to obtain such a license before exporting.
41 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42 * distribute this software and its documentation for any purpose and
43 * without fee is hereby granted, provided that the above copyright
44 * notice appear in all copies and that both that copyright notice and
45 * this permission notice appear in supporting documentation, and that
46 * the name of M.I.T. not be used in advertising or publicity pertaining
47 * to distribution of the software without specific, written prior
48 * permission. Furthermore if you modify this software you must label
49 * your software as modified software and not distribute it in such a
50 * fashion that it might be confused with the original M.I.T. software.
51 * M.I.T. makes no representations about the suitability of
52 * this software for any purpose. It is provided "as is" without express
53 * or implied warranty.
60 #include "afskfw-int.h"
64 #include <rxkad_prototypes.h> /* for life_to_time */
67 * TIMING _____________________________________________________________________
71 #define cminREMIND_TEST 1 // test every minute for expired creds
72 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
73 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
74 #define cminMINLIFE 30 // minimum life of Kerberos creds
76 #define c100ns1SECOND (LONGLONG)10000000
77 #define cmsec1SECOND 1000
78 #define cmsec1MINUTE 60000
79 #define csec1MINUTE 60
81 /* Function Pointer Declarations for Delayed Loading */
83 DECL_FUNC_PTR(cc_initialize);
84 DECL_FUNC_PTR(cc_shutdown);
85 DECL_FUNC_PTR(cc_get_NC_info);
86 DECL_FUNC_PTR(cc_free_NC_info);
89 DECL_FUNC_PTR(Leash_get_default_lifetime);
90 DECL_FUNC_PTR(Leash_get_default_forwardable);
91 DECL_FUNC_PTR(Leash_get_default_renew_till);
92 DECL_FUNC_PTR(Leash_get_default_noaddresses);
93 DECL_FUNC_PTR(Leash_get_default_proxiable);
94 DECL_FUNC_PTR(Leash_get_default_publicip);
95 DECL_FUNC_PTR(Leash_get_default_use_krb4);
96 DECL_FUNC_PTR(Leash_get_default_life_min);
97 DECL_FUNC_PTR(Leash_get_default_life_max);
98 DECL_FUNC_PTR(Leash_get_default_renew_min);
99 DECL_FUNC_PTR(Leash_get_default_renew_max);
100 DECL_FUNC_PTR(Leash_get_default_renewable);
103 DECL_FUNC_PTR(krb5_change_password);
104 DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
105 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
106 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
107 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
108 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
109 DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
110 DECL_FUNC_PTR(krb5_get_init_creds_password);
111 DECL_FUNC_PTR(krb5_build_principal_ext);
112 DECL_FUNC_PTR(krb5_cc_get_name);
113 DECL_FUNC_PTR(krb5_cc_resolve);
114 DECL_FUNC_PTR(krb5_cc_default);
115 DECL_FUNC_PTR(krb5_cc_default_name);
116 DECL_FUNC_PTR(krb5_cc_set_default_name);
117 DECL_FUNC_PTR(krb5_cc_initialize);
118 DECL_FUNC_PTR(krb5_cc_destroy);
119 DECL_FUNC_PTR(krb5_cc_close);
120 DECL_FUNC_PTR(krb5_cc_store_cred);
121 DECL_FUNC_PTR(krb5_cc_copy_creds);
122 DECL_FUNC_PTR(krb5_cc_retrieve_cred);
123 DECL_FUNC_PTR(krb5_cc_get_principal);
124 DECL_FUNC_PTR(krb5_cc_start_seq_get);
125 DECL_FUNC_PTR(krb5_cc_next_cred);
126 DECL_FUNC_PTR(krb5_cc_end_seq_get);
127 DECL_FUNC_PTR(krb5_cc_remove_cred);
128 DECL_FUNC_PTR(krb5_cc_set_flags);
129 DECL_FUNC_PTR(krb5_cc_get_type);
130 DECL_FUNC_PTR(krb5_free_context);
131 DECL_FUNC_PTR(krb5_free_cred_contents);
132 DECL_FUNC_PTR(krb5_free_principal);
133 DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
134 DECL_FUNC_PTR(krb5_init_context);
135 DECL_FUNC_PTR(krb5_parse_name);
136 DECL_FUNC_PTR(krb5_timeofday);
137 DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
138 DECL_FUNC_PTR(krb5_unparse_name);
139 DECL_FUNC_PTR(krb5_get_credentials);
140 DECL_FUNC_PTR(krb5_mk_req);
141 DECL_FUNC_PTR(krb5_sname_to_principal);
142 DECL_FUNC_PTR(krb5_get_credentials_renew);
143 DECL_FUNC_PTR(krb5_free_data);
144 DECL_FUNC_PTR(krb5_free_data_contents);
145 DECL_FUNC_PTR(krb5_free_unparsed_name);
146 DECL_FUNC_PTR(krb5_os_localaddr);
147 DECL_FUNC_PTR(krb5_copy_keyblock_contents);
148 DECL_FUNC_PTR(krb5_copy_data);
149 DECL_FUNC_PTR(krb5_free_creds);
150 DECL_FUNC_PTR(krb5_build_principal);
151 DECL_FUNC_PTR(krb5_get_renewed_creds);
152 DECL_FUNC_PTR(krb5_get_default_config_files);
153 DECL_FUNC_PTR(krb5_free_config_files);
154 DECL_FUNC_PTR(krb5_get_default_realm);
155 DECL_FUNC_PTR(krb5_free_ticket);
156 DECL_FUNC_PTR(krb5_decode_ticket);
157 DECL_FUNC_PTR(krb5_get_host_realm);
158 DECL_FUNC_PTR(krb5_free_host_realm);
159 DECL_FUNC_PTR(krb5_free_addresses);
160 DECL_FUNC_PTR(krb5_c_random_make_octets);
163 DECL_FUNC_PTR(krb524_init_ets);
164 DECL_FUNC_PTR(krb524_convert_creds_kdc);
167 DECL_FUNC_PTR(krb_get_cred);
168 DECL_FUNC_PTR(tkt_string);
169 DECL_FUNC_PTR(krb_get_tf_realm);
170 DECL_FUNC_PTR(krb_mk_req);
173 DECL_FUNC_PTR(com_err);
174 DECL_FUNC_PTR(error_message);
177 DECL_FUNC_PTR(profile_init);
178 DECL_FUNC_PTR(profile_release);
179 DECL_FUNC_PTR(profile_get_subsection_names);
180 DECL_FUNC_PTR(profile_free_list);
181 DECL_FUNC_PTR(profile_get_string);
182 DECL_FUNC_PTR(profile_release_string);
185 DECL_FUNC_PTR(OpenSCManagerA);
186 DECL_FUNC_PTR(OpenServiceA);
187 DECL_FUNC_PTR(QueryServiceStatus);
188 DECL_FUNC_PTR(CloseServiceHandle);
190 DECL_FUNC_PTR(LsaNtStatusToWinError);
191 #endif /* USE_MS2MIT */
195 DECL_FUNC_PTR(LsaConnectUntrusted);
196 DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
197 DECL_FUNC_PTR(LsaCallAuthenticationPackage);
198 DECL_FUNC_PTR(LsaFreeReturnBuffer);
199 DECL_FUNC_PTR(LsaGetLogonSessionData);
200 #endif /* USE_MS2MIT */
203 FUNC_INFO ccapi_fi[] = {
204 MAKE_FUNC_INFO(cc_initialize),
205 MAKE_FUNC_INFO(cc_shutdown),
206 MAKE_FUNC_INFO(cc_get_NC_info),
207 MAKE_FUNC_INFO(cc_free_NC_info),
211 FUNC_INFO leash_fi[] = {
212 MAKE_FUNC_INFO(Leash_get_default_lifetime),
213 MAKE_FUNC_INFO(Leash_get_default_renew_till),
214 MAKE_FUNC_INFO(Leash_get_default_forwardable),
215 MAKE_FUNC_INFO(Leash_get_default_noaddresses),
216 MAKE_FUNC_INFO(Leash_get_default_proxiable),
217 MAKE_FUNC_INFO(Leash_get_default_publicip),
218 MAKE_FUNC_INFO(Leash_get_default_use_krb4),
219 MAKE_FUNC_INFO(Leash_get_default_life_min),
220 MAKE_FUNC_INFO(Leash_get_default_life_max),
221 MAKE_FUNC_INFO(Leash_get_default_renew_min),
222 MAKE_FUNC_INFO(Leash_get_default_renew_max),
223 MAKE_FUNC_INFO(Leash_get_default_renewable),
227 FUNC_INFO k5_fi[] = {
228 MAKE_FUNC_INFO(krb5_change_password),
229 MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
230 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
231 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
232 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
233 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
234 MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
235 MAKE_FUNC_INFO(krb5_get_init_creds_password),
236 MAKE_FUNC_INFO(krb5_build_principal_ext),
237 MAKE_FUNC_INFO(krb5_cc_get_name),
238 MAKE_FUNC_INFO(krb5_cc_resolve),
239 MAKE_FUNC_INFO(krb5_cc_default),
240 MAKE_FUNC_INFO(krb5_cc_default_name),
241 MAKE_FUNC_INFO(krb5_cc_set_default_name),
242 MAKE_FUNC_INFO(krb5_cc_initialize),
243 MAKE_FUNC_INFO(krb5_cc_destroy),
244 MAKE_FUNC_INFO(krb5_cc_close),
245 MAKE_FUNC_INFO(krb5_cc_copy_creds),
246 MAKE_FUNC_INFO(krb5_cc_store_cred),
247 MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
248 MAKE_FUNC_INFO(krb5_cc_get_principal),
249 MAKE_FUNC_INFO(krb5_cc_start_seq_get),
250 MAKE_FUNC_INFO(krb5_cc_next_cred),
251 MAKE_FUNC_INFO(krb5_cc_end_seq_get),
252 MAKE_FUNC_INFO(krb5_cc_remove_cred),
253 MAKE_FUNC_INFO(krb5_cc_set_flags),
254 MAKE_FUNC_INFO(krb5_cc_get_type),
255 MAKE_FUNC_INFO(krb5_free_context),
256 MAKE_FUNC_INFO(krb5_free_cred_contents),
257 MAKE_FUNC_INFO(krb5_free_principal),
258 MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
259 MAKE_FUNC_INFO(krb5_init_context),
260 MAKE_FUNC_INFO(krb5_parse_name),
261 MAKE_FUNC_INFO(krb5_timeofday),
262 MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
263 MAKE_FUNC_INFO(krb5_unparse_name),
264 MAKE_FUNC_INFO(krb5_get_credentials),
265 MAKE_FUNC_INFO(krb5_mk_req),
266 MAKE_FUNC_INFO(krb5_sname_to_principal),
267 MAKE_FUNC_INFO(krb5_get_credentials_renew),
268 MAKE_FUNC_INFO(krb5_free_data),
269 MAKE_FUNC_INFO(krb5_free_data_contents),
270 MAKE_FUNC_INFO(krb5_free_unparsed_name),
271 MAKE_FUNC_INFO(krb5_os_localaddr),
272 MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
273 MAKE_FUNC_INFO(krb5_copy_data),
274 MAKE_FUNC_INFO(krb5_free_creds),
275 MAKE_FUNC_INFO(krb5_build_principal),
276 MAKE_FUNC_INFO(krb5_get_renewed_creds),
277 MAKE_FUNC_INFO(krb5_free_addresses),
278 MAKE_FUNC_INFO(krb5_get_default_config_files),
279 MAKE_FUNC_INFO(krb5_free_config_files),
280 MAKE_FUNC_INFO(krb5_get_default_realm),
281 MAKE_FUNC_INFO(krb5_free_ticket),
282 MAKE_FUNC_INFO(krb5_decode_ticket),
283 MAKE_FUNC_INFO(krb5_get_host_realm),
284 MAKE_FUNC_INFO(krb5_free_host_realm),
285 MAKE_FUNC_INFO(krb5_free_addresses),
286 MAKE_FUNC_INFO(krb5_c_random_make_octets),
290 FUNC_INFO k4_fi[] = {
291 MAKE_FUNC_INFO(krb_get_cred),
292 MAKE_FUNC_INFO(krb_get_tf_realm),
293 MAKE_FUNC_INFO(krb_mk_req),
294 MAKE_FUNC_INFO(tkt_string),
298 FUNC_INFO k524_fi[] = {
299 MAKE_FUNC_INFO(krb524_init_ets),
300 MAKE_FUNC_INFO(krb524_convert_creds_kdc),
304 FUNC_INFO profile_fi[] = {
305 MAKE_FUNC_INFO(profile_init),
306 MAKE_FUNC_INFO(profile_release),
307 MAKE_FUNC_INFO(profile_get_subsection_names),
308 MAKE_FUNC_INFO(profile_free_list),
309 MAKE_FUNC_INFO(profile_get_string),
310 MAKE_FUNC_INFO(profile_release_string),
314 FUNC_INFO ce_fi[] = {
315 MAKE_FUNC_INFO(com_err),
316 MAKE_FUNC_INFO(error_message),
320 FUNC_INFO service_fi[] = {
321 MAKE_FUNC_INFO(OpenSCManagerA),
322 MAKE_FUNC_INFO(OpenServiceA),
323 MAKE_FUNC_INFO(QueryServiceStatus),
324 MAKE_FUNC_INFO(CloseServiceHandle),
326 MAKE_FUNC_INFO(LsaNtStatusToWinError),
327 #endif /* USE_MS2MIT */
332 FUNC_INFO lsa_fi[] = {
333 MAKE_FUNC_INFO(LsaConnectUntrusted),
334 MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
335 MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
336 MAKE_FUNC_INFO(LsaFreeReturnBuffer),
337 MAKE_FUNC_INFO(LsaGetLogonSessionData),
340 #endif /* USE_MS2MIT */
342 /* Static Prototypes */
343 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
344 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
345 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
346 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
347 void *data, const char *name, const char *banner, int num_prompts,
348 krb5_prompt prompts[]);
351 /* Static Declarations */
352 static int inited = 0;
353 static int mid_cnt = 0;
354 static struct textField * mid_tb = NULL;
355 static HINSTANCE hKrb5 = 0;
356 static HINSTANCE hKrb4 = 0;
357 static HINSTANCE hKrb524 = 0;
359 static HINSTANCE hSecur32 = 0;
360 #endif /* USE_MS2MIT */
361 static HINSTANCE hAdvApi32 = 0;
362 static HINSTANCE hComErr = 0;
363 static HINSTANCE hService = 0;
364 static HINSTANCE hProfile = 0;
365 static HINSTANCE hLeash = 0;
366 static HINSTANCE hCCAPI = 0;
367 static struct principal_ccache_data * princ_cc_data = NULL;
368 static struct cell_principal_map * cell_princ_map = NULL;
373 static int inited = 0;
376 char mutexName[MAX_PATH];
377 HANDLE hMutex = NULL;
379 sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
381 hMutex = CreateMutex( NULL, TRUE, mutexName );
382 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
383 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
389 LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
390 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
391 LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
392 LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
394 LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
395 #endif /* USE_MS2MIT */
396 LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
397 LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
398 LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
399 LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
401 if ( KFW_is_available() ) {
402 char rootcell[MAXCELLCHARS+1];
404 KFW_import_windows_lsa();
405 #endif /* USE_MS2MIT */
406 KFW_import_ccache_data();
407 KFW_AFS_renew_expiring_tokens();
409 /* WIN32 NOTE: no way to get max chars */
410 if (!cm_GetRootCellName(rootcell))
411 KFW_AFS_renew_token_for_cell(rootcell);
414 ReleaseMutex(hMutex);
427 FreeLibrary(hProfile);
429 FreeLibrary(hComErr);
431 FreeLibrary(hService);
434 FreeLibrary(hSecur32);
435 #endif /* USE_MS2MIT */
437 FreeLibrary(hKrb524);
444 static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
447 KFW_is_available(void)
453 code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
454 0, KEY_QUERY_VALUE, &parmKey);
455 if (code != ERROR_SUCCESS)
456 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
457 0, KEY_QUERY_VALUE, &parmKey);
458 if (code == ERROR_SUCCESS) {
459 len = sizeof(enableKFW);
460 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
461 (BYTE *) &enableKFW, &len);
462 if (code != ERROR_SUCCESS) {
465 RegCloseKey (parmKey);
472 if ( hKrb5 && hComErr && hService &&
475 #endif /* USE_MS2MIT */
477 hProfile && hLeash && hCCAPI )
483 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
484 int FreeContextFlag, krb5_context * ctx,
489 int krb5Error = ((int)(rc & 255));
501 errText = perror_message(rc);
502 _snprintf(message, sizeof(message),
503 "%s\n(Kerberos error %ld)\n\n%s failed",
508 if ( IsDebuggerPresent() )
509 OutputDebugString(message);
511 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
514 if (FreeContextFlag == 1)
516 if (ctx && *ctx != NULL)
518 if (cache && *cache != NULL) {
519 pkrb5_cc_close(*ctx, *cache);
523 pkrb5_free_context(*ctx);
532 KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
534 struct principal_ccache_data * next = princ_cc_data;
535 krb5_principal principal = 0;
537 const char * ccname = NULL;
538 krb5_error_code code = 0;
539 krb5_error_code cc_code = 0;
545 if (ctx == 0 || cc == 0)
548 code = pkrb5_cc_get_principal(ctx, cc, &principal);
551 code = pkrb5_unparse_name(ctx, principal, &pname);
552 if ( code ) goto cleanup;
554 ccname = pkrb5_cc_get_name(ctx, cc);
555 if (!ccname) goto cleanup;
557 // Search the existing list to see if we have a match
559 for ( ; next ; next = next->next ) {
560 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
565 // If not, match add a new node to the beginning of the list and assign init it
567 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
568 next->next = princ_cc_data;
569 princ_cc_data = next;
570 next->principal = _strdup(pname);
571 next->ccache_name = _strdup(ccname);
572 next->from_lsa = lsa;
574 next->expiration_time = 0;
578 flags = 0; // turn off OPENCLOSE mode
579 code = pkrb5_cc_set_flags(ctx, cc, flags);
580 if ( code ) goto cleanup;
582 code = pkrb5_timeofday(ctx, &now);
584 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
586 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
587 if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
589 // we found the ticket we are looking for
590 // check validity of timestamp
591 // We add a 5 minutes fudge factor to compensate for potential
592 // clock skew errors between the KDC and client OS
594 valid = ((creds.times.starttime > 0) &&
595 now >= (creds.times.starttime - 300) &&
596 now < (creds.times.endtime + 300) &&
597 !(creds.ticket_flags & TKT_FLG_INVALID));
599 if ( next->from_lsa) {
601 next->expiration_time = creds.times.endtime;
603 } else if ( valid ) {
605 next->expiration_time = creds.times.endtime;
606 next->renew = (creds.times.renew_till > creds.times.endtime) &&
607 (creds.ticket_flags & TKT_FLG_RENEWABLE);
610 next->expiration_time = 0;
614 pkrb5_free_cred_contents(ctx, &creds);
615 cc_code = KRB5_CC_END;
618 pkrb5_free_cred_contents(ctx, &creds);
621 if (cc_code == KRB5_CC_END) {
622 code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
623 if (code) goto cleanup;
627 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
628 code = pkrb5_cc_set_flags(ctx, cc, flags);
631 pkrb5_free_unparsed_name(ctx,pname);
633 pkrb5_free_principal(ctx,principal);
637 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
639 struct principal_ccache_data * next = princ_cc_data;
640 char * response = NULL;
642 if ( !principal || !ccache )
646 if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) {
648 // we always want to prefer the MS Kerberos LSA cache or
649 // the cache afscreds created specifically for the principal
650 // if the current entry is either one, drop the previous find
651 if ( next->from_lsa || !strcmp(next->ccache_name,principal) )
654 response = _strdup(next->ccache_name);
655 // MS Kerberos LSA is our best option so use it and quit
656 if ( next->from_lsa )
670 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
672 struct principal_ccache_data ** next = &princ_cc_data;
674 if ( !pname && !ccname )
678 if ( !strcmp((*next)->principal,pname) ||
679 !strcmp((*next)->ccache_name,ccname) ) {
681 free((*next)->principal);
682 free((*next)->ccache_name);
684 (*next) = (*next)->next;
691 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
693 struct cell_principal_map * next = cell_princ_map;
695 // Search the existing list to see if we have a match
697 for ( ; next ; next = next->next ) {
698 if ( !strcmp(next->cell, cell) ) {
699 if ( !strcmp(next->principal,pname) ) {
700 next->active = active;
703 // OpenAFS currently has a restriction of one active token per cell
704 // Therefore, whenever we update the table with a new active cell we
705 // must mark all of the other principal to cell entries as inactive.
713 // If not, match add a new node to the beginning of the list and assign init it
715 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
716 next->next = cell_princ_map;
717 cell_princ_map = next;
718 next->principal = _strdup(pname);
719 next->cell = _strdup(cell);
720 next->active = active;
725 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
727 struct cell_principal_map ** next = &cell_princ_map;
729 if ( !pname && !cell )
733 if ( !strcmp((*next)->principal,pname) ||
734 !strcmp((*next)->cell,cell) ) {
736 free((*next)->principal);
739 (*next) = (*next)->next;
745 // Returns (if possible) a principal which has been known in
746 // the past to have been used to obtain tokens for the specified
748 // TODO: Attempt to return one which has not yet expired by checking
749 // the principal/ccache data
751 KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only)
753 struct cell_principal_map * next_map = cell_princ_map;
754 const char * princ = NULL;
761 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
764 next_map = next_map->next;
767 if ( !principals || !count )
770 *principals = (char **) malloc(sizeof(char *) * count);
771 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
773 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
774 (*principals)[i++] = _strdup(next_map->principal);
781 KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only)
784 struct cell_principal_map * next_map = cell_princ_map;
785 const char * princ = NULL;
791 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
794 next_map = next_map->next;
800 *cells = (char **) malloc(sizeof(char *) * count);
801 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
803 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
804 (*cells)[i++] = _strdup(next_map->cell);
810 /* Given a principal return an existing ccache or create one and return */
812 KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
817 krb5_error_code code;
819 if (!pkrb5_init_context)
825 code = pkrb5_init_context(&ctx);
826 if (code) goto cleanup;
830 code = pkrb5_unparse_name(ctx, principal, &pname);
831 if (code) goto cleanup;
833 if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
834 !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
835 ccname = (char *)malloc(strlen(pname) + 5);
836 sprintf(ccname,"API:%s",pname);
838 code = pkrb5_cc_resolve(ctx, ccname, cc);
840 code = pkrb5_cc_default(ctx, cc);
841 if (code) goto cleanup;
848 pkrb5_free_unparsed_name(ctx,pname);
849 if (ctx && (ctx != alt_ctx))
850 pkrb5_free_context(ctx);
855 // Import Microsoft Credentials into a new MIT ccache
857 KFW_import_windows_lsa(void)
859 krb5_context ctx = 0;
861 krb5_principal princ = 0;
863 krb5_data * princ_realm;
864 krb5_error_code code;
865 char cell[128]="", realm[128]="";
868 if (!pkrb5_init_context)
872 if ( !MSLSA_IsKerberosLogon() )
876 code = pkrb5_init_context(&ctx);
877 if (code) goto cleanup;
879 code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc);
880 if (code) goto cleanup;
882 KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE);
884 code = pkrb5_cc_get_principal(ctx, cc, &princ);
885 if ( code ) goto cleanup;
887 code = pkrb5_unparse_name(ctx,princ,&pname);
888 if ( code ) goto cleanup;
890 princ_realm = krb5_princ_realm(ctx, princ);
891 for ( i=0; i<princ_realm->length; i++ ) {
892 realm[i] = princ_realm->data[i];
893 cell[i] = tolower(princ_realm->data[i]);
898 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
899 if ( IsDebuggerPresent() ) {
901 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
902 OutputDebugString(message);
904 if ( code ) goto cleanup;
906 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
910 pkrb5_free_unparsed_name(ctx,pname);
912 pkrb5_free_principal(ctx,princ);
914 pkrb5_cc_close(ctx,cc);
916 pkrb5_free_context(ctx);
918 #endif /* USE_MS2MIT */
920 // If there are existing MIT credentials, copy them to a new
921 // ccache named after the principal
923 // Enumerate all existing MIT ccaches and construct entries
924 // in the principal_ccache table
926 // Enumerate all existing AFS Tokens and construct entries
927 // in the cell_principal table
929 KFW_import_ccache_data(void)
931 krb5_context ctx = 0;
933 krb5_principal principal = 0;
935 krb5_error_code code;
936 krb5_error_code cc_code;
939 struct _infoNC ** pNCi = NULL;
942 if ( !pcc_initialize )
945 if ( IsDebuggerPresent() )
946 OutputDebugString("KFW_import_ccache_data()\n");
948 code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
949 if (code) goto cleanup;
951 code = pcc_get_NC_info(cc_ctx, &pNCi);
952 if (code) goto cleanup;
954 code = pkrb5_init_context(&ctx);
955 if (code) goto cleanup;
957 for ( i=0; pNCi[i]; i++ ) {
958 if ( pNCi[i]->vers != CC_CRED_V5 )
960 if ( IsDebuggerPresent() ) {
961 OutputDebugString("Principal: ");
962 OutputDebugString(pNCi[i]->principal);
963 OutputDebugString(" in ccache ");
964 OutputDebugString(pNCi[i]->name);
965 OutputDebugString("\n");
967 if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
968 && strcmp(pNCi[i]->name,LSA_CCNAME)
971 for ( j=0; pNCi[j]; j++ ) {
972 if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) {
978 code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
979 if (code) goto loop_cleanup;
982 krb5_ccache oldcc = 0;
984 if ( IsDebuggerPresent() )
985 OutputDebugString("copying ccache data to new ccache\n");
987 code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal);
988 if (code) goto loop_cleanup;
989 code = pkrb5_cc_initialize(ctx, cc, principal);
990 if (code) goto loop_cleanup;
992 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc);
993 if (code) goto loop_cleanup;
994 code = pkrb5_cc_copy_creds(ctx,oldcc,cc);
996 code = pkrb5_cc_close(ctx,cc);
998 code = pkrb5_cc_close(ctx,oldcc);
1000 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
1003 code = pkrb5_cc_close(ctx,oldcc);
1006 code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc);
1007 if (code) goto loop_cleanup;
1010 flags = 0; // turn off OPENCLOSE mode
1011 code = pkrb5_cc_set_flags(ctx, cc, flags);
1012 if ( code ) goto cleanup;
1014 KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
1016 cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
1018 while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
1019 krb5_data * sname = krb5_princ_name(ctx, creds.server);
1020 krb5_data * cell = krb5_princ_component(ctx, creds.server, 1);
1021 krb5_data * realm = krb5_princ_realm(ctx, creds.server);
1022 if ( sname && cell && !strcmp("afs",sname->data) ) {
1023 struct ktc_principal aserver;
1024 struct ktc_principal aclient;
1025 struct ktc_token atoken;
1028 if ( IsDebuggerPresent() ) {
1029 OutputDebugString("Found AFS ticket: ");
1030 OutputDebugString(sname->data);
1032 OutputDebugString("/");
1033 OutputDebugString(cell->data);
1035 OutputDebugString("@");
1036 OutputDebugString(realm->data);
1037 OutputDebugString("\n");
1040 memset(&aserver, '\0', sizeof(aserver));
1041 strcpy(aserver.name, sname->data);
1042 strcpy(aserver.cell, cell->data);
1044 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
1046 // Found a token in AFS Client Server which matches
1047 char pname[128], *p, *q;
1048 for ( p=pname, q=aclient.name; *q; p++, q++)
1050 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
1054 if ( IsDebuggerPresent() ) {
1055 OutputDebugString("Found AFS token: ");
1056 OutputDebugString(pname);
1057 OutputDebugString("\n");
1060 if ( strcmp(pname,pNCi[i]->principal) )
1062 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1064 // Attempt to import it
1065 KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active);
1067 if ( IsDebuggerPresent() ) {
1068 OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
1071 code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL);
1072 if ( IsDebuggerPresent() ) {
1074 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1075 OutputDebugString(message);
1078 } else if ( IsDebuggerPresent() ) {
1079 OutputDebugString("Found ticket: ");
1080 OutputDebugString(sname->data);
1081 if ( cell && cell->data ) {
1082 OutputDebugString("/");
1083 OutputDebugString(cell->data);
1085 OutputDebugString("@");
1086 OutputDebugString(realm->data);
1087 OutputDebugString("\n");
1089 pkrb5_free_cred_contents(ctx, &creds);
1092 if (cc_code == KRB5_CC_END) {
1093 cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
1094 if (cc_code) goto loop_cleanup;
1098 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1099 code = pkrb5_cc_set_flags(ctx, cc, flags);
1101 pkrb5_cc_close(ctx,cc);
1105 pkrb5_free_principal(ctx,principal);
1112 pkrb5_free_context(ctx);
1114 pcc_free_NC_info(cc_ctx, &pNCi);
1116 pcc_shutdown(&cc_ctx);
1121 KFW_AFS_get_cred( char * username,
1128 krb5_context ctx = 0;
1131 char ** realmlist = 0;
1132 krb5_principal principal = 0;
1134 krb5_error_code code;
1135 char local_cell[MAXCELLCHARS+1];
1136 char **cells = NULL;
1138 struct afsconf_cell cellconfig;
1142 if (!pkrb5_init_context)
1145 if ( IsDebuggerPresent() ) {
1146 OutputDebugString("KFW_AFS_get_cred for token ");
1147 OutputDebugString(username);
1148 OutputDebugString(" in cell ");
1149 OutputDebugString(cell);
1150 OutputDebugString("\n");
1153 code = pkrb5_init_context(&ctx);
1154 if ( code ) goto cleanup;
1156 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1157 if ( code ) goto cleanup;
1159 realm = strchr(username,'@');
1161 pname = strdup(username);
1162 realm = strchr(pname, '@');
1165 /* handle kerberos iv notation */
1166 while ( dot = strchr(pname,'.') ) {
1171 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1172 pname = malloc(strlen(username) + strlen(realm) + 2);
1174 strcpy(pname, username);
1176 /* handle kerberos iv notation */
1177 while ( dot = strchr(pname,'.') ) {
1182 strcat(pname,realm);
1185 if ( IsDebuggerPresent() ) {
1186 OutputDebugString("Realm: ");
1187 OutputDebugString(realm);
1188 OutputDebugString("\n");
1191 code = pkrb5_parse_name(ctx, pname, &principal);
1192 if ( code ) goto cleanup;
1194 code = KFW_get_ccache(ctx, principal, &cc);
1195 if ( code ) goto cleanup;
1197 if ( lifetime == 0 )
1198 lifetime = pLeash_get_default_lifetime();
1200 code = KFW_kinit(ctx, cc, HWND_DESKTOP,
1204 pLeash_get_default_forwardable(),
1205 pLeash_get_default_proxiable(),
1206 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1207 pLeash_get_default_noaddresses(),
1208 pLeash_get_default_publicip());
1209 if ( IsDebuggerPresent() ) {
1211 sprintf(message,"KFW_kinit() returns: %d\n",code);
1212 OutputDebugString(message);
1214 if ( code ) goto cleanup;
1216 KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
1218 code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime,smbname);
1219 if ( IsDebuggerPresent() ) {
1221 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1222 OutputDebugString(message);
1224 if ( code ) goto cleanup;
1226 KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
1228 // Attempt to obtain new tokens for other cells supported by the same
1230 cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
1231 if ( cell_count > 1 ) {
1232 while ( cell_count-- ) {
1233 if ( strcmp(cells[cell_count],cell) ) {
1234 if ( IsDebuggerPresent() ) {
1236 sprintf(message,"found another cell for the same principal: %s\n",cell);
1237 OutputDebugString(message);
1239 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1240 if ( code ) continue;
1242 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1243 if ( IsDebuggerPresent() ) {
1244 OutputDebugString("Realm: ");
1245 OutputDebugString(realm);
1246 OutputDebugString("\n");
1249 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime,smbname);
1250 if ( IsDebuggerPresent() ) {
1252 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1253 OutputDebugString(message);
1256 free(cells[cell_count]);
1259 } else if ( cell_count == 1 ) {
1268 pkrb5_cc_close(ctx, cc);
1270 if ( code && reasonP ) {
1271 *reasonP = (char *)perror_message(code);
1277 KFW_AFS_destroy_tickets_for_cell(char * cell)
1279 krb5_context ctx = 0;
1280 krb5_error_code code;
1282 char ** principals = NULL;
1284 if (!pkrb5_init_context)
1287 if ( IsDebuggerPresent() ) {
1288 OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
1289 OutputDebugString(cell);
1290 OutputDebugString("\n");
1293 code = pkrb5_init_context(&ctx);
1296 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE);
1298 krb5_principal princ = 0;
1302 int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE);
1303 if ( cell_count > 1 ) {
1304 // TODO - What we really should do here is verify whether or not any of the
1305 // other cells which use this principal to obtain its credentials actually
1306 // have valid tokens or not. If they are currently using these credentials
1307 // we will skip them. For the time being we assume that if there is an active
1308 // map in the table that they are actively being used.
1312 code = pkrb5_parse_name(ctx, principals[count], &princ);
1313 if (code) goto loop_cleanup;
1315 code = KFW_get_ccache(ctx, princ, &cc);
1316 if (code) goto loop_cleanup;
1318 code = pkrb5_cc_destroy(ctx, cc);
1323 pkrb5_cc_close(ctx, cc);
1327 pkrb5_free_principal(ctx, princ);
1331 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE);
1332 free(principals[count]);
1336 pkrb5_free_context(ctx);
1341 KFW_AFS_renew_expiring_tokens(void)
1343 krb5_error_code code = 0;
1344 krb5_context ctx = 0;
1347 struct principal_ccache_data * pcc_next = princ_cc_data;
1350 const char * realm = NULL;
1351 char local_cell[MAXCELLCHARS+1]="";
1352 struct afsconf_cell cellconfig;
1354 if (!pkrb5_init_context)
1357 if ( pcc_next == NULL ) // nothing to do
1360 if ( IsDebuggerPresent() ) {
1361 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1364 code = pkrb5_init_context(&ctx);
1365 if (code) goto cleanup;
1367 code = pkrb5_timeofday(ctx, &now);
1368 if (code) goto cleanup;
1370 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1371 if ( pcc_next->expired )
1374 if ( now >= (pcc_next->expiration_time) ) {
1375 if ( !pcc_next->from_lsa ) {
1376 pcc_next->expired = 1;
1381 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1382 code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
1385 code = KFW_renew(ctx,cc);
1387 if ( code && pcc_next->from_lsa)
1389 #endif /* USE_MS2MIT */
1392 KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
1393 if (code) goto loop_cleanup;
1395 // Attempt to obtain new tokens for other cells supported by the same
1397 cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
1398 if ( cell_count > 0 ) {
1399 while ( cell_count-- ) {
1400 if ( IsDebuggerPresent() ) {
1401 OutputDebugString("Cell: ");
1402 OutputDebugString(cells[cell_count]);
1403 OutputDebugString("\n");
1405 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1406 if ( code ) continue;
1407 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1408 if ( IsDebuggerPresent() ) {
1409 OutputDebugString("Realm: ");
1410 OutputDebugString(realm);
1411 OutputDebugString("\n");
1413 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime(),NULL);
1414 if ( IsDebuggerPresent() ) {
1416 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1417 OutputDebugString(message);
1419 free(cells[cell_count]);
1427 pkrb5_cc_close(ctx,cc);
1434 pkrb5_cc_close(ctx,cc);
1436 pkrb5_free_context(ctx);
1443 KFW_AFS_renew_token_for_cell(char * cell)
1445 krb5_error_code code = 0;
1446 krb5_context ctx = 0;
1448 char ** principals = NULL;
1450 if (!pkrb5_init_context)
1453 if ( IsDebuggerPresent() ) {
1454 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1455 OutputDebugString(cell);
1456 OutputDebugString("\n");
1459 code = pkrb5_init_context(&ctx);
1460 if (code) goto cleanup;
1462 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1464 // We know we must have a credential somewhere since we are
1465 // trying to renew a token
1467 KFW_import_ccache_data();
1468 count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE);
1471 krb5_principal princ = 0;
1472 krb5_principal service = 0;
1474 krb5_creds mcreds, creds;
1475 #endif /* COMMENT */
1477 const char * realm = NULL;
1478 struct afsconf_cell cellconfig;
1479 char local_cell[MAXCELLCHARS+1];
1482 code = pkrb5_parse_name(ctx, principals[count], &princ);
1483 if (code) goto loop_cleanup;
1485 code = KFW_get_ccache(ctx, princ, &cc);
1486 if (code) goto loop_cleanup;
1488 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1489 if ( code ) goto loop_cleanup;
1491 realm = afs_realm_of_cell(ctx, &cellconfig); // do not free
1492 if ( IsDebuggerPresent() ) {
1493 OutputDebugString("Realm: ");
1494 OutputDebugString(realm);
1495 OutputDebugString("\n");
1499 /* krb5_cc_remove_cred() is not implemented
1502 code = pkrb5_build_principal(ctx, &service, strlen(realm),
1503 realm, "afs", cell, NULL);
1505 memset(&mcreds, 0, sizeof(krb5_creds));
1506 mcreds.client = princ;
1507 mcreds.server = service;
1509 code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds);
1511 if ( IsDebuggerPresent() ) {
1512 char * cname, *sname;
1513 pkrb5_unparse_name(ctx, creds.client, &cname);
1514 pkrb5_unparse_name(ctx, creds.server, &sname);
1515 OutputDebugString("Removing credential for client \"");
1516 OutputDebugString(cname);
1517 OutputDebugString("\" and service \"");
1518 OutputDebugString(sname);
1519 OutputDebugString("\"\n");
1520 pkrb5_free_unparsed_name(ctx,cname);
1521 pkrb5_free_unparsed_name(ctx,sname);
1524 code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds);
1525 pkrb5_free_principal(ctx, creds.client);
1526 pkrb5_free_principal(ctx, creds.server);
1529 #endif /* COMMENT */
1531 code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime(),NULL);
1532 if ( IsDebuggerPresent() ) {
1534 sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
1535 OutputDebugString(message);
1540 pkrb5_cc_close(ctx, cc);
1544 pkrb5_free_principal(ctx, princ);
1548 pkrb5_free_principal(ctx, service);
1552 KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
1553 free(principals[count]);
1557 code = -1; // we did not renew the tokens
1560 pkrb5_free_context(ctx);
1561 return (code ? FALSE : TRUE);
1566 KFW_AFS_renew_tokens_for_all_cells(void)
1568 struct cell_principal_map * next = cell_princ_map;
1570 if ( IsDebuggerPresent() )
1571 OutputDebugString("KFW_AFS_renew_tokens_for_all()\n");
1576 for ( ; next ; next = next->next ) {
1578 KFW_AFS_renew_token_for_cell(next->cell);
1584 KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
1586 krb5_error_code code = 0;
1587 krb5_context ctx = 0;
1589 krb5_principal me = 0;
1590 krb5_principal server = 0;
1591 krb5_creds my_creds;
1592 krb5_data *realm = 0;
1594 if (!pkrb5_init_context)
1597 memset(&my_creds, 0, sizeof(krb5_creds));
1602 code = pkrb5_init_context(&ctx);
1603 if (code) goto cleanup;
1609 code = pkrb5_cc_default(ctx, &cc);
1610 if (code) goto cleanup;
1613 code = pkrb5_cc_get_principal(ctx, cc, &me);
1614 if (code) goto cleanup;
1616 realm = krb5_princ_realm(ctx, me);
1618 code = pkrb5_build_principal_ext(ctx, &server,
1619 realm->length,realm->data,
1620 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1621 realm->length,realm->data,
1626 if ( IsDebuggerPresent() ) {
1627 char * cname, *sname;
1628 pkrb5_unparse_name(ctx, me, &cname);
1629 pkrb5_unparse_name(ctx, server, &sname);
1630 OutputDebugString("Renewing credential for client \"");
1631 OutputDebugString(cname);
1632 OutputDebugString("\" and service \"");
1633 OutputDebugString(sname);
1634 OutputDebugString("\"\n");
1635 pkrb5_free_unparsed_name(ctx,cname);
1636 pkrb5_free_unparsed_name(ctx,sname);
1639 my_creds.client = me;
1640 my_creds.server = server;
1642 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
1644 if ( IsDebuggerPresent() ) {
1646 sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
1647 OutputDebugString(message);
1652 code = pkrb5_cc_initialize(ctx, cc, me);
1654 if ( IsDebuggerPresent() ) {
1656 sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
1657 OutputDebugString(message);
1662 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1664 if ( IsDebuggerPresent() ) {
1666 sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
1667 OutputDebugString(message);
1673 if (my_creds.client == me)
1674 my_creds.client = 0;
1675 if (my_creds.server == server)
1676 my_creds.server = 0;
1677 pkrb5_free_cred_contents(ctx, &my_creds);
1679 pkrb5_free_principal(ctx, me);
1681 pkrb5_free_principal(ctx, server);
1682 if (cc && (cc != alt_cc))
1683 pkrb5_cc_close(ctx, cc);
1684 if (ctx && (ctx != alt_ctx))
1685 pkrb5_free_context(ctx);
1690 KFW_kinit( krb5_context alt_ctx,
1693 char *principal_name,
1695 krb5_deltat lifetime,
1698 krb5_deltat renew_life,
1703 krb5_error_code code = 0;
1704 krb5_context ctx = 0;
1706 krb5_principal me = 0;
1708 krb5_creds my_creds;
1709 krb5_get_init_creds_opt options;
1710 krb5_address ** addrs = NULL;
1711 int i = 0, addr_count = 0;
1713 if (!pkrb5_init_context)
1716 pkrb5_get_init_creds_opt_init(&options);
1717 memset(&my_creds, 0, sizeof(my_creds));
1725 code = pkrb5_init_context(&ctx);
1726 if (code) goto cleanup;
1732 code = pkrb5_cc_default(ctx, &cc);
1733 if (code) goto cleanup;
1736 code = pkrb5_parse_name(ctx, principal_name, &me);
1740 code = pkrb5_unparse_name(ctx, me, &name);
1745 lifetime = pLeash_get_default_lifetime();
1753 pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
1754 pkrb5_get_init_creds_opt_set_forwardable(&options,
1755 forwardable ? 1 : 0);
1756 pkrb5_get_init_creds_opt_set_proxiable(&options,
1758 pkrb5_get_init_creds_opt_set_renew_life(&options,
1761 pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
1765 // we are going to add the public IP address specified by the user
1766 // to the list provided by the operating system
1767 krb5_address ** local_addrs=NULL;
1770 pkrb5_os_localaddr(ctx, &local_addrs);
1771 while ( local_addrs[i++] );
1774 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
1776 pkrb5_free_addresses(ctx, local_addrs);
1779 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
1781 while ( local_addrs[i] ) {
1782 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1783 if (addrs[i] == NULL) {
1784 pkrb5_free_addresses(ctx, local_addrs);
1788 addrs[i]->magic = local_addrs[i]->magic;
1789 addrs[i]->addrtype = local_addrs[i]->addrtype;
1790 addrs[i]->length = local_addrs[i]->length;
1791 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1792 if (!addrs[i]->contents) {
1793 pkrb5_free_addresses(ctx, local_addrs);
1797 memcpy(addrs[i]->contents,local_addrs[i]->contents,
1798 local_addrs[i]->length); /* safe */
1801 pkrb5_free_addresses(ctx, local_addrs);
1803 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
1804 if (addrs[i] == NULL)
1807 addrs[i]->magic = KV5M_ADDRESS;
1808 addrs[i]->addrtype = AF_INET;
1809 addrs[i]->length = 4;
1810 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
1811 if (!addrs[i]->contents)
1814 netIPAddr = htonl(publicIP);
1815 memcpy(addrs[i]->contents,&netIPAddr,4);
1817 pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
1822 code = pkrb5_get_init_creds_password(ctx,
1825 password, // password
1826 KRB5_prompter, // prompter
1827 hParent, // prompter data
1834 code = pkrb5_cc_initialize(ctx, cc, me);
1838 code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
1844 for ( i=0;i<addr_count;i++ ) {
1846 if ( addrs[i]->contents )
1847 free(addrs[i]->contents);
1852 if (my_creds.client == me)
1853 my_creds.client = 0;
1854 pkrb5_free_cred_contents(ctx, &my_creds);
1856 pkrb5_free_unparsed_name(ctx, name);
1858 pkrb5_free_principal(ctx, me);
1859 if (cc && (cc != alt_cc))
1860 pkrb5_cc_close(ctx, cc);
1861 if (ctx && (ctx != alt_ctx))
1862 pkrb5_free_context(ctx);
1868 KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
1872 krb5_error_code code;
1874 if (!pkrb5_init_context)
1883 code = pkrb5_init_context(&ctx);
1884 if (code) goto cleanup;
1890 code = pkrb5_cc_default(ctx, &cc);
1891 if (code) goto cleanup;
1894 code = pkrb5_cc_destroy(ctx, cc);
1895 if ( !code ) cc = 0;
1898 if (cc && (cc != alt_cc))
1899 pkrb5_cc_close(ctx, cc);
1900 if (ctx && (ctx != alt_ctx))
1901 pkrb5_free_context(ctx);
1909 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1911 NTSTATUS Status = 0;
1913 TOKEN_STATISTICS Stats;
1919 *ppSessionData = NULL;
1921 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1925 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1926 CloseHandle( TokenHandle );
1930 Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1931 if ( FAILED(Status) || !ppSessionData )
1938 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1939 // cache. It validates whether or not it is reasonable to assume that if we
1940 // attempted to retrieve valid tickets we could do so. Microsoft does not
1941 // automatically renew expired tickets. Therefore, the cache could contain
1942 // expired or invalid tickets. Microsoft also caches the user's password
1943 // and will use it to retrieve new TGTs if the cache is empty and tickets
1947 MSLSA_IsKerberosLogon(VOID)
1949 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1950 BOOL Success = FALSE;
1952 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1953 if ( pSessionData->AuthenticationPackage.Buffer ) {
1959 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1960 usLength = (pSessionData->AuthenticationPackage).Length;
1963 lstrcpynW (buffer, usBuffer, usLength);
1964 lstrcatW (buffer,L"");
1965 if ( !lstrcmpW(L"Kerberos",buffer) )
1969 pLsaFreeReturnBuffer(pSessionData);
1973 #endif /* USE_MS2MIT */
1975 static BOOL CALLBACK
1976 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1980 switch ( message ) {
1982 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1984 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1987 for ( i=0; i < mid_cnt ; i++ ) {
1988 if (mid_tb[i].echo == 0)
1989 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1990 else if (mid_tb[i].echo == 2)
1991 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1996 switch ( LOWORD(wParam) ) {
1998 for ( i=0; i < mid_cnt ; i++ ) {
1999 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2000 *mid_tb[i].buf = '\0';
2004 EndDialog(hDialog, LOWORD(wParam));
2012 lpwAlign( LPWORD lpIn )
2020 return (LPWORD) ul;;
2024 * dialog widths are measured in 1/4 character widths
2025 * dialog height are measured in 1/8 character heights
2029 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2030 char * ptext[], int numlines, int width,
2031 int tb_cnt, struct textField * tb)
2035 LPDLGITEMTEMPLATE lpdit;
2041 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2048 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2050 // Define a dialog box.
2052 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2053 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2054 | DS_SETFOREGROUND | DS_3DLOOK
2055 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2056 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2059 lpdt->cx = 20 + width * 4;
2060 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2062 lpw = (LPWORD) (lpdt + 1);
2063 *lpw++ = 0; // no menu
2064 *lpw++ = 0; // predefined dialog box class (by default)
2066 lpwsz = (LPWSTR) lpw;
2067 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2069 *lpw++ = 8; // font size (points)
2070 lpwsz = (LPWSTR) lpw;
2071 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2075 //-----------------------
2076 // Define an OK button.
2077 //-----------------------
2078 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2079 lpdit = (LPDLGITEMTEMPLATE) lpw;
2080 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2081 lpdit->dwExtendedStyle = 0;
2082 lpdit->x = (lpdt->cx - 14)/4 - 20;
2083 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2086 lpdit->id = IDOK; // OK button identifier
2088 lpw = (LPWORD) (lpdit + 1);
2090 *lpw++ = 0x0080; // button class
2092 lpwsz = (LPWSTR) lpw;
2093 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2095 *lpw++ = 0; // no creation data
2097 //-----------------------
2098 // Define an Cancel button.
2099 //-----------------------
2100 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2101 lpdit = (LPDLGITEMTEMPLATE) lpw;
2102 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2103 lpdit->dwExtendedStyle = 0;
2104 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2105 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2108 lpdit->id = IDCANCEL; // CANCEL button identifier
2110 lpw = (LPWORD) (lpdit + 1);
2112 *lpw++ = 0x0080; // button class
2114 lpwsz = (LPWSTR) lpw;
2115 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2117 *lpw++ = 0; // no creation data
2119 /* Add controls for preface data */
2120 for ( i=0; i<numlines; i++) {
2121 /*-----------------------
2122 * Define a static text control.
2123 *-----------------------*/
2124 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2125 lpdit = (LPDLGITEMTEMPLATE) lpw;
2126 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2127 lpdit->dwExtendedStyle = 0;
2129 lpdit->y = 10 + i * 14;
2130 lpdit->cx = strlen(ptext[i]) * 4 + 10;
2132 lpdit->id = ID_TEXT + i; // text identifier
2134 lpw = (LPWORD) (lpdit + 1);
2136 *lpw++ = 0x0082; // static class
2138 lpwsz = (LPWSTR) lpw;
2139 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2140 -1, lpwsz, 2*width);
2142 *lpw++ = 0; // no creation data
2145 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2146 if ( pwid < strlen(tb[i].label) )
2147 pwid = strlen(tb[i].label);
2150 for ( i=0; i<tb_cnt; i++) {
2152 /*-----------------------
2153 * Define a static text control.
2154 *-----------------------*/
2155 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2156 lpdit = (LPDLGITEMTEMPLATE) lpw;
2157 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2158 lpdit->dwExtendedStyle = 0;
2160 lpdit->y = 10 + (numlines + i + 1) * 14;
2161 lpdit->cx = pwid * 4;
2163 lpdit->id = ID_TEXT + numlines + i; // text identifier
2165 lpw = (LPWORD) (lpdit + 1);
2167 *lpw++ = 0x0082; // static class
2169 lpwsz = (LPWSTR) lpw;
2170 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2173 *lpw++ = 0; // no creation data
2175 /*-----------------------
2176 * Define an edit control.
2177 *-----------------------*/
2178 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2179 lpdit = (LPDLGITEMTEMPLATE) lpw;
2180 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2181 lpdit->dwExtendedStyle = 0;
2182 lpdit->x = 10 + (pwid + 1) * 4;
2183 lpdit->y = 10 + (numlines + i + 1) * 14;
2184 lpdit->cx = (width - (pwid + 1)) * 4;
2186 lpdit->id = ID_MID_TEXT + i; // identifier
2188 lpw = (LPWORD) (lpdit + 1);
2190 *lpw++ = 0x0081; // edit class
2192 lpwsz = (LPWSTR) lpw;
2193 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2196 *lpw++ = 0; // no creation data
2200 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2201 hwndOwner, (DLGPROC) MultiInputDialogProc);
2205 case 0: /* Timeout */
2213 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
2214 MessageBox(hwndOwner,
2217 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2224 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2226 HINSTANCE hInst = 0;
2230 char * plines[16], *p = preface ? preface : "";
2233 for ( i=0; i<16; i++ )
2236 while (*p && numlines < 16) {
2237 plines[numlines++] = p;
2238 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2239 if ( *p == '\r' && *(p+1) == '\n' ) {
2242 } else if ( *p == '\n' ) {
2245 if ( strlen(plines[numlines-1]) > maxwidth )
2246 maxwidth = strlen(plines[numlines-1]);
2249 for ( i=0;i<n;i++ ) {
2250 len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2251 if ( maxwidth < len )
2255 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb));
2258 static krb5_error_code KRB5_CALLCONV
2259 KRB5_prompter( krb5_context context,
2264 krb5_prompt prompts[])
2266 krb5_error_code errcode = 0;
2268 struct textField * tb = NULL;
2269 int len = 0, blen=0, nlen=0;
2270 HWND hParent = (HWND)data;
2273 nlen = strlen(name)+2;
2276 blen = strlen(banner)+2;
2278 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2281 memset(tb,0,sizeof(struct textField) * num_prompts);
2282 for ( i=0; i < num_prompts; i++ ) {
2283 tb[i].buf = prompts[i].reply->data;
2284 tb[i].len = prompts[i].reply->length;
2285 tb[i].label = prompts[i].prompt;
2287 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2290 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2292 for ( i=0; i < num_prompts; i++ )
2293 prompts[i].reply->length = strlen(prompts[i].reply->data);
2301 for (i = 0; i < num_prompts; i++) {
2302 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2309 KFW_AFS_wait_for_service_start(void)
2314 CurrentState = SERVICE_START_PENDING;
2315 memset(HostName, '\0', sizeof(HostName));
2316 gethostname(HostName, sizeof(HostName));
2318 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2320 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2322 if ( IsDebuggerPresent() ) {
2323 switch ( CurrentState ) {
2324 case SERVICE_STOPPED:
2325 OutputDebugString("SERVICE_STOPPED\n");
2327 case SERVICE_START_PENDING:
2328 OutputDebugString("SERVICE_START_PENDING\n");
2330 case SERVICE_STOP_PENDING:
2331 OutputDebugString("SERVICE_STOP_PENDING\n");
2333 case SERVICE_RUNNING:
2334 OutputDebugString("SERVICE_RUNNING\n");
2336 case SERVICE_CONTINUE_PENDING:
2337 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2339 case SERVICE_PAUSE_PENDING:
2340 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2342 case SERVICE_PAUSED:
2343 OutputDebugString("SERVICE_PAUSED\n");
2346 OutputDebugString("UNKNOWN Service State\n");
2349 if (CurrentState == SERVICE_STOPPED)
2351 if (CurrentState == SERVICE_RUNNING)
2367 memset(HostName, '\0', sizeof(HostName));
2368 gethostname(HostName, sizeof(HostName));
2369 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2371 if (CurrentState != SERVICE_RUNNING)
2374 rc = ktc_ForgetAllTokens();
2381 krb5_context alt_ctx,
2393 struct ktc_principal aserver;
2394 struct ktc_principal aclient;
2395 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2396 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2397 char local_cell[MAXCELLCHARS+1];
2398 char Dmycell[MAXCELLCHARS+1];
2399 struct ktc_token atoken;
2400 struct ktc_token btoken;
2401 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2402 char RealmName[128];
2404 char ServiceName[128];
2408 krb5_context ctx = 0;
2411 krb5_creds * k5creds = 0;
2412 krb5_error_code code;
2413 krb5_principal client_principal = 0;
2417 memset(HostName, '\0', sizeof(HostName));
2418 gethostname(HostName, sizeof(HostName));
2419 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2420 if ( IsDebuggerPresent() )
2421 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2424 if (CurrentState != SERVICE_RUNNING) {
2425 if ( IsDebuggerPresent() )
2426 OutputDebugString("AFSD Service NOT RUNNING\n");
2430 if (!pkrb5_init_context)
2433 memset(RealmName, '\0', sizeof(RealmName));
2434 memset(CellName, '\0', sizeof(CellName));
2435 memset(ServiceName, '\0', sizeof(ServiceName));
2436 memset(realm_of_user, '\0', sizeof(realm_of_user));
2437 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2438 if (cell && cell[0])
2439 strcpy(Dmycell, cell);
2441 memset(Dmycell, '\0', sizeof(Dmycell));
2443 // NULL or empty cell returns information on local cell
2444 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2446 // KFW_AFS_error(rc, "get_cellconfig()");
2453 code = pkrb5_init_context(&ctx);
2454 if (code) goto cleanup;
2460 code = pkrb5_cc_default(ctx, &cc);
2461 if (code) goto skip_krb5_init;
2464 memset((char *)&increds, 0, sizeof(increds));
2466 code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
2468 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2470 OutputDebugString("Principal Not Found for ccache\n");
2472 goto skip_krb5_init;
2474 i = krb5_princ_realm(ctx, client_principal)->length;
2477 strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
2478 realm_of_user[i] = 0;
2483 if ( !try_krb5 || !realm_of_user[0] ) {
2484 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
2492 strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
2494 if (strlen(service) == 0)
2495 strcpy(ServiceName, "afs");
2497 strcpy(ServiceName, service);
2499 if (strlen(cell) == 0)
2500 strcpy(CellName, local_cell);
2502 strcpy(CellName, cell);
2504 if (strlen(realm) == 0)
2505 strcpy(RealmName, realm_of_cell);
2507 strcpy(RealmName, realm);
2509 memset(&creds, '\0', sizeof(creds));
2514 /* First try service/cell@REALM */
2515 if (code = pkrb5_build_principal(ctx, &increds.server,
2525 increds.client = client_principal;
2526 increds.times.endtime = 0;
2527 /* Ask for DES since that is what V4 understands */
2528 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
2531 if ( IsDebuggerPresent() ) {
2532 char * cname, *sname;
2533 pkrb5_unparse_name(ctx, increds.client, &cname);
2534 pkrb5_unparse_name(ctx, increds.server, &sname);
2535 OutputDebugString("Getting tickets for \"");
2536 OutputDebugString(cname);
2537 OutputDebugString("\" and service \"");
2538 OutputDebugString(sname);
2539 OutputDebugString("\"\n");
2540 pkrb5_free_unparsed_name(ctx,cname);
2541 pkrb5_free_unparsed_name(ctx,sname);
2544 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2545 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2546 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2547 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2548 /* Or service@REALM */
2549 pkrb5_free_principal(ctx,increds.server);
2551 code = pkrb5_build_principal(ctx, &increds.server,
2557 if ( IsDebuggerPresent() ) {
2558 char * cname, *sname;
2559 pkrb5_unparse_name(ctx, increds.client, &cname);
2560 pkrb5_unparse_name(ctx, increds.server, &sname);
2561 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2562 OutputDebugString("Trying again: getting tickets for \"");
2563 OutputDebugString(cname);
2564 OutputDebugString("\" and service \"");
2565 OutputDebugString(sname);
2566 OutputDebugString("\"\n");
2567 pkrb5_free_unparsed_name(ctx,cname);
2568 pkrb5_free_unparsed_name(ctx,sname);
2572 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2575 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2576 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2577 code == KRB5KRB_AP_ERR_MSG_TYPE) &&
2578 strcmp(RealmName, realm_of_cell)) {
2579 /* Or service/cell@REALM_OF_CELL */
2580 strcpy(RealmName, realm_of_cell);
2581 pkrb5_free_principal(ctx,increds.server);
2583 code = pkrb5_build_principal(ctx, &increds.server,
2590 if ( IsDebuggerPresent() ) {
2591 char * cname, *sname;
2592 pkrb5_unparse_name(ctx, increds.client, &cname);
2593 pkrb5_unparse_name(ctx, increds.server, &sname);
2594 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2595 OutputDebugString("Trying again: getting tickets for \"");
2596 OutputDebugString(cname);
2597 OutputDebugString("\" and service \"");
2598 OutputDebugString(sname);
2599 OutputDebugString("\"\n");
2600 pkrb5_free_unparsed_name(ctx,cname);
2601 pkrb5_free_unparsed_name(ctx,sname);
2605 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2608 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2609 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2610 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2611 /* Or service@REALM_OF_CELL */
2612 pkrb5_free_principal(ctx,increds.server);
2614 code = pkrb5_build_principal(ctx, &increds.server,
2620 if ( IsDebuggerPresent() ) {
2621 char * cname, *sname;
2622 pkrb5_unparse_name(ctx, increds.client, &cname);
2623 pkrb5_unparse_name(ctx, increds.server, &sname);
2624 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2625 OutputDebugString("Trying again: getting tickets for \"");
2626 OutputDebugString(cname);
2627 OutputDebugString("\" and service \"");
2628 OutputDebugString(sname);
2629 OutputDebugString("\"\n");
2630 pkrb5_free_unparsed_name(ctx,cname);
2631 pkrb5_free_unparsed_name(ctx,sname);
2635 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
2640 if ( IsDebuggerPresent() ) {
2642 sprintf(message,"krb5_get_credentials returns: %d\n",code);
2643 OutputDebugString(message);
2649 /* This code inserts the entire K5 ticket into the token
2650 * No need to perform a krb524 translation which is
2651 * commented out in the code below
2653 if (k5creds->ticket.length > MAXKTCTICKETLEN)
2656 memset(&aserver, '\0', sizeof(aserver));
2657 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2658 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2660 memset(&atoken, '\0', sizeof(atoken));
2661 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2662 atoken.startTime = k5creds->times.starttime;
2663 atoken.endTime = k5creds->times.endtime;
2664 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
2665 atoken.ticketLen = k5creds->ticket.length;
2666 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2669 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2670 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2671 if ( rc == KTC_NOCM && retry < 20 ) {
2674 goto retry_gettoken5;
2679 if (atoken.kvno == btoken.kvno &&
2680 atoken.ticketLen == btoken.ticketLen &&
2681 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2682 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2684 /* Success - Nothing to do */
2688 // * Reset the "aclient" structure before we call ktc_SetToken.
2689 // * This structure was first set by the ktc_GetToken call when
2690 // * we were comparing whether identical tokens already existed.
2692 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
2693 strncpy(aclient.name, k5creds->client->data[0].data, len);
2694 aclient.name[len] = '\0';
2696 if ( k5creds->client->length > 1 ) {
2698 strcat(aclient.name, ".");
2699 p = aclient.name + strlen(aclient.name);
2700 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
2701 strncpy(p, k5creds->client->data[1].data, len);
2704 aclient.instance[0] = '\0';
2706 strcpy(aclient.cell, realm_of_cell);
2708 len = min(k5creds->client->realm.length,strlen(realm_of_cell));
2709 if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) {
2711 strcat(aclient.name, "@");
2712 p = aclient.name + strlen(aclient.name);
2713 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
2714 strncpy(p, k5creds->client->realm.data, len);
2719 strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN);
2720 aclient.smbname[MAXRANDOMNAMELEN-1] = '\0';
2722 aclient.smbname[0] = '\0';
2725 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
2727 goto cleanup; /* We have successfully inserted the token */
2730 /* Otherwise, the ticket could have been too large so try to
2731 * convert using the krb524d running with the KDC
2733 code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
2734 pkrb5_free_creds(ctx, k5creds);
2736 if ( IsDebuggerPresent() ) {
2738 sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
2739 OutputDebugString(message);
2747 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
2748 if (code == NO_TKT_FIL) {
2749 // if the problem is that we have no krb4 tickets
2750 // do not attempt to continue
2753 if (code != KSUCCESS)
2754 code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
2756 if (code != KSUCCESS)
2758 if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS)
2760 if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS)
2765 else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS)
2767 if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS)
2782 memset(&aserver, '\0', sizeof(aserver));
2783 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
2784 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
2786 memset(&atoken, '\0', sizeof(atoken));
2787 atoken.kvno = creds.kvno;
2788 atoken.startTime = creds.issue_date;
2789 atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime);
2790 memcpy(&atoken.sessionKey, creds.session, 8);
2791 atoken.ticketLen = creds.ticket_st.length;
2792 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
2795 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2796 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2797 if ( rc == KTC_NOCM && retry < 20 ) {
2800 goto retry_gettoken;
2802 KFW_AFS_error(rc, "ktc_GetToken()");
2807 if (atoken.kvno == btoken.kvno &&
2808 atoken.ticketLen == btoken.ticketLen &&
2809 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2810 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2815 // * Reset the "aclient" structure before we call ktc_SetToken.
2816 // * This structure was first set by the ktc_GetToken call when
2817 // * we were comparing whether identical tokens already existed.
2819 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
2822 strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
2823 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
2825 strcpy(aclient.instance, "");
2827 if ( strcmp(realm_of_cell, creds.realm) )
2829 strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
2830 strncpy(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
2832 aclient.name[MAXKTCREALMLEN-1] = '\0';
2834 strcpy(aclient.cell, CellName);
2837 strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN);
2838 aclient.smbname[MAXRANDOMNAMELEN-1] = '\0';
2840 aclient.smbname[0] = '\0';
2843 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0))
2845 KFW_AFS_error(rc, "ktc_SetToken()");
2851 if (client_principal)
2852 pkrb5_free_principal(ctx,client_principal);
2853 /* increds.client == client_principal */
2855 pkrb5_free_principal(ctx,increds.server);
2856 if (cc && (cc != alt_cc))
2857 pkrb5_cc_close(ctx, cc);
2858 if (ctx && (ctx != alt_ctx))
2859 pkrb5_free_context(ctx);
2861 return(rc? rc : code);
2864 /**************************************/
2865 /* afs_realm_of_cell(): */
2866 /**************************************/
2868 afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
2870 static char krbrlm[REALM_SZ+1]="";
2871 char ** realmlist=NULL;
2877 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
2878 if ( !r && realmlist && realmlist[0] ) {
2879 strcpy(krbrlm, realmlist[0]);
2880 pkrb5_free_host_realm(ctx, realmlist);
2886 char *t = cellconfig->name;
2891 if (islower(c)) c=toupper(c);
2899 /**************************************/
2900 /* KFW_AFS_get_cellconfig(): */
2901 /**************************************/
2903 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2906 char newcell[MAXCELLCHARS+1];
2908 local_cell[0] = (char)0;
2909 memset(cellconfig, 0, sizeof(*cellconfig));
2911 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2912 if (rc = cm_GetRootCellName(local_cell))
2917 if (strlen(cell) == 0)
2918 strcpy(cell, local_cell);
2920 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
2921 strcpy(cellconfig->name, cell);
2923 rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
2924 #ifdef AFS_AFSDB_ENV
2927 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2933 /**************************************/
2934 /* get_cellconfig_callback(): */
2935 /**************************************/
2937 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
2939 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2941 cc->hostAddr[cc->numServers] = *addrp;
2942 strcpy(cc->hostName[cc->numServers], namep);
2948 /**************************************/
2949 /* KFW_AFS_error(): */
2950 /**************************************/
2952 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2955 const char *errText;
2957 // Using AFS defines as error messages for now, until Transarc
2958 // gets back to me with "string" translations of each of these
2960 if (rc == KTC_ERROR)
2961 errText = "KTC_ERROR";
2962 else if (rc == KTC_TOOBIG)
2963 errText = "KTC_TOOBIG";
2964 else if (rc == KTC_INVAL)
2965 errText = "KTC_INVAL";
2966 else if (rc == KTC_NOENT)
2967 errText = "KTC_NOENT";
2968 else if (rc == KTC_PIOCTLFAIL)
2969 errText = "KTC_PIOCTLFAIL";
2970 else if (rc == KTC_NOPIOCTL)
2971 errText = "KTC_NOPIOCTL";
2972 else if (rc == KTC_NOCELL)
2973 errText = "KTC_NOCELL";
2974 else if (rc == KTC_NOCM)
2975 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2977 errText = "Unknown error!";
2979 sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
2981 if ( IsDebuggerPresent() ) {
2982 OutputDebugString(message);
2983 OutputDebugString("\n");
2985 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
2991 LPSTR lpszMachineName,
2992 LPSTR lpszServiceName,
2993 DWORD *lpdwCurrentState)
2996 SC_HANDLE schSCManager = NULL;
2997 SC_HANDLE schService = NULL;
2998 DWORD fdwDesiredAccess = 0;
2999 SERVICE_STATUS ssServiceStatus = {0};
3002 *lpdwCurrentState = 0;
3004 fdwDesiredAccess = GENERIC_READ;
3006 schSCManager = OpenSCManager(lpszMachineName,
3010 if(schSCManager == NULL)
3012 hr = GetLastError();
3016 schService = OpenService(schSCManager,
3020 if(schService == NULL)
3022 hr = GetLastError();
3026 fRet = QueryServiceStatus(schService,
3031 hr = GetLastError();
3035 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3039 CloseServiceHandle(schService);
3040 CloseServiceHandle(schSCManager);
3053 for (n = 0; fi[n].func_ptr_var; n++)
3054 *(fi[n].func_ptr_var) = 0;
3055 if (h) FreeLibrary(h);
3060 const char* dll_name,
3062 HINSTANCE* ph, // [out, optional] - DLL handle
3063 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
3064 int cleanup, // cleanup function pointers and unload on error
3065 int go_on, // continue loading even if some functions cannot be loaded
3066 int silent // do not pop-up a system dialog if DLL cannot be loaded
3075 if (pindex) *pindex = -1;
3077 for (n = 0; fi[n].func_ptr_var; n++)
3078 *(fi[n].func_ptr_var) = 0;
3081 em = SetErrorMode(SEM_FAILCRITICALERRORS);
3082 h = LoadLibrary(dll_name);
3090 for (i = 0; (go_on || !error) && (i < n); i++)
3092 void* p = (void*)GetProcAddress(h, fi[i].func_name);
3098 *(fi[i].func_ptr_var) = p;
3101 if (pindex) *pindex = last_i;
3102 if (error && cleanup && !go_on) {
3103 for (i = 0; i < n; i++) {
3104 *(fi[i].func_ptr_var) = 0;
3110 if (error) return 0;
3114 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3116 krb5_context ctx = 0;
3118 krb5_error_code code;
3120 const char * realm = 0;
3121 krb5_principal principal = 0;
3123 char password[PROBE_PASSWORD_LEN+1];
3124 BOOL serverReachable = 0;
3126 if (!pkrb5_init_context)
3129 code = pkrb5_init_context(&ctx);
3130 if (code) goto cleanup;
3133 realm = afs_realm_of_cell(ctx, cellconfig); // do not free
3135 code = pkrb5_build_principal(ctx, &principal, strlen(realm),
3136 realm, PROBE_USERNAME, NULL, NULL);
3137 if ( code ) goto cleanup;
3139 code = KFW_get_ccache(ctx, principal, &cc);
3140 if ( code ) goto cleanup;
3142 code = pkrb5_unparse_name(ctx, principal, &pname);
3143 if ( code ) goto cleanup;
3145 pwdata.data = password;
3146 pwdata.length = PROBE_PASSWORD_LEN;
3147 code = pkrb5_c_random_make_octets(ctx, &pwdata);
3150 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3153 password[PROBE_PASSWORD_LEN] = '\0';
3155 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3165 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3166 case KRB5KDC_ERR_CLIENT_REVOKED:
3167 case KRB5KDC_ERR_CLIENT_NOTYET:
3168 case KRB5KDC_ERR_PREAUTH_FAILED:
3169 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3170 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3171 serverReachable = TRUE;
3174 serverReachable = FALSE;
3179 pkrb5_free_unparsed_name(ctx,pname);
3181 pkrb5_free_principal(ctx,principal);
3183 pkrb5_cc_close(ctx,cc);
3185 pkrb5_free_context(ctx);
3187 return serverReachable;