/* * Copyright (c) 2003 SkyRope, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Skyrope, LLC nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission from Skyrope, LLC. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this code are derived from portions of the MIT * Leash Ticket Manager and LoadFuncs utilities. For these portions the * following copyright applies. * * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. * All rights reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ #define USE_MS2MIT #define USE_KRB4 #include "afskfw-int.h" #include "afskfw.h" #include #include /* for life_to_time */ #include /* * TIMING _____________________________________________________________________ * */ #define cminREMIND_TEST 1 // test every minute for expired creds #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes #define cminRENEW 20 // renew creds when there are 20 minutes remaining #define cminMINLIFE 30 // minimum life of Kerberos creds #define c100ns1SECOND (LONGLONG)10000000 #define cmsec1SECOND 1000 #define cmsec1MINUTE 60000 #define csec1MINUTE 60 /* Function Pointer Declarations for Delayed Loading */ // CCAPI DECL_FUNC_PTR(cc_initialize); DECL_FUNC_PTR(cc_shutdown); DECL_FUNC_PTR(cc_get_NC_info); DECL_FUNC_PTR(cc_free_NC_info); // leash functions DECL_FUNC_PTR(Leash_get_default_lifetime); DECL_FUNC_PTR(Leash_get_default_forwardable); DECL_FUNC_PTR(Leash_get_default_renew_till); DECL_FUNC_PTR(Leash_get_default_noaddresses); DECL_FUNC_PTR(Leash_get_default_proxiable); DECL_FUNC_PTR(Leash_get_default_publicip); DECL_FUNC_PTR(Leash_get_default_use_krb4); DECL_FUNC_PTR(Leash_get_default_life_min); DECL_FUNC_PTR(Leash_get_default_life_max); DECL_FUNC_PTR(Leash_get_default_renew_min); DECL_FUNC_PTR(Leash_get_default_renew_max); DECL_FUNC_PTR(Leash_get_default_renewable); // krb5 functions DECL_FUNC_PTR(krb5_change_password); DECL_FUNC_PTR(krb5_get_init_creds_opt_init); DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); DECL_FUNC_PTR(krb5_get_init_creds_password); DECL_FUNC_PTR(krb5_build_principal_ext); DECL_FUNC_PTR(krb5_cc_get_name); DECL_FUNC_PTR(krb5_cc_resolve); DECL_FUNC_PTR(krb5_cc_default); DECL_FUNC_PTR(krb5_cc_default_name); DECL_FUNC_PTR(krb5_cc_set_default_name); DECL_FUNC_PTR(krb5_cc_initialize); DECL_FUNC_PTR(krb5_cc_destroy); DECL_FUNC_PTR(krb5_cc_close); DECL_FUNC_PTR(krb5_cc_store_cred); DECL_FUNC_PTR(krb5_cc_copy_creds); DECL_FUNC_PTR(krb5_cc_retrieve_cred); DECL_FUNC_PTR(krb5_cc_get_principal); DECL_FUNC_PTR(krb5_cc_start_seq_get); DECL_FUNC_PTR(krb5_cc_next_cred); DECL_FUNC_PTR(krb5_cc_end_seq_get); DECL_FUNC_PTR(krb5_cc_remove_cred); DECL_FUNC_PTR(krb5_cc_set_flags); DECL_FUNC_PTR(krb5_cc_get_type); DECL_FUNC_PTR(krb5_free_context); DECL_FUNC_PTR(krb5_free_cred_contents); DECL_FUNC_PTR(krb5_free_principal); DECL_FUNC_PTR(krb5_get_in_tkt_with_password); DECL_FUNC_PTR(krb5_init_context); DECL_FUNC_PTR(krb5_parse_name); DECL_FUNC_PTR(krb5_timeofday); DECL_FUNC_PTR(krb5_timestamp_to_sfstring); DECL_FUNC_PTR(krb5_unparse_name); DECL_FUNC_PTR(krb5_get_credentials); DECL_FUNC_PTR(krb5_mk_req); DECL_FUNC_PTR(krb5_sname_to_principal); DECL_FUNC_PTR(krb5_get_credentials_renew); DECL_FUNC_PTR(krb5_free_data); DECL_FUNC_PTR(krb5_free_data_contents); DECL_FUNC_PTR(krb5_free_unparsed_name); DECL_FUNC_PTR(krb5_os_localaddr); DECL_FUNC_PTR(krb5_copy_keyblock_contents); DECL_FUNC_PTR(krb5_copy_data); DECL_FUNC_PTR(krb5_free_creds); DECL_FUNC_PTR(krb5_build_principal); DECL_FUNC_PTR(krb5_get_renewed_creds); DECL_FUNC_PTR(krb5_get_default_config_files); DECL_FUNC_PTR(krb5_free_config_files); DECL_FUNC_PTR(krb5_get_default_realm); DECL_FUNC_PTR(krb5_free_ticket); DECL_FUNC_PTR(krb5_decode_ticket); DECL_FUNC_PTR(krb5_get_host_realm); DECL_FUNC_PTR(krb5_free_host_realm); DECL_FUNC_PTR(krb5_free_addresses); DECL_FUNC_PTR(krb5_c_random_make_octets); // Krb524 functions DECL_FUNC_PTR(krb524_init_ets); DECL_FUNC_PTR(krb524_convert_creds_kdc); // krb4 functions DECL_FUNC_PTR(krb_get_cred); DECL_FUNC_PTR(tkt_string); DECL_FUNC_PTR(krb_get_tf_realm); DECL_FUNC_PTR(krb_mk_req); // ComErr functions DECL_FUNC_PTR(com_err); DECL_FUNC_PTR(error_message); // Profile functions DECL_FUNC_PTR(profile_init); DECL_FUNC_PTR(profile_release); DECL_FUNC_PTR(profile_get_subsection_names); DECL_FUNC_PTR(profile_free_list); DECL_FUNC_PTR(profile_get_string); DECL_FUNC_PTR(profile_release_string); // Service functions DECL_FUNC_PTR(OpenSCManagerA); DECL_FUNC_PTR(OpenServiceA); DECL_FUNC_PTR(QueryServiceStatus); DECL_FUNC_PTR(CloseServiceHandle); #ifdef USE_MS2MIT DECL_FUNC_PTR(LsaNtStatusToWinError); #endif /* USE_MS2MIT */ #ifdef USE_MS2MIT // LSA Functions DECL_FUNC_PTR(LsaConnectUntrusted); DECL_FUNC_PTR(LsaLookupAuthenticationPackage); DECL_FUNC_PTR(LsaCallAuthenticationPackage); DECL_FUNC_PTR(LsaFreeReturnBuffer); DECL_FUNC_PTR(LsaGetLogonSessionData); #endif /* USE_MS2MIT */ // CCAPI FUNC_INFO ccapi_fi[] = { MAKE_FUNC_INFO(cc_initialize), MAKE_FUNC_INFO(cc_shutdown), MAKE_FUNC_INFO(cc_get_NC_info), MAKE_FUNC_INFO(cc_free_NC_info), END_FUNC_INFO }; FUNC_INFO leash_fi[] = { MAKE_FUNC_INFO(Leash_get_default_lifetime), MAKE_FUNC_INFO(Leash_get_default_renew_till), MAKE_FUNC_INFO(Leash_get_default_forwardable), MAKE_FUNC_INFO(Leash_get_default_noaddresses), MAKE_FUNC_INFO(Leash_get_default_proxiable), MAKE_FUNC_INFO(Leash_get_default_publicip), MAKE_FUNC_INFO(Leash_get_default_use_krb4), MAKE_FUNC_INFO(Leash_get_default_life_min), MAKE_FUNC_INFO(Leash_get_default_life_max), MAKE_FUNC_INFO(Leash_get_default_renew_min), MAKE_FUNC_INFO(Leash_get_default_renew_max), MAKE_FUNC_INFO(Leash_get_default_renewable), END_FUNC_INFO }; FUNC_INFO k5_fi[] = { MAKE_FUNC_INFO(krb5_change_password), MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), MAKE_FUNC_INFO(krb5_get_init_creds_password), MAKE_FUNC_INFO(krb5_build_principal_ext), MAKE_FUNC_INFO(krb5_cc_get_name), MAKE_FUNC_INFO(krb5_cc_resolve), MAKE_FUNC_INFO(krb5_cc_default), MAKE_FUNC_INFO(krb5_cc_default_name), MAKE_FUNC_INFO(krb5_cc_set_default_name), MAKE_FUNC_INFO(krb5_cc_initialize), MAKE_FUNC_INFO(krb5_cc_destroy), MAKE_FUNC_INFO(krb5_cc_close), MAKE_FUNC_INFO(krb5_cc_copy_creds), MAKE_FUNC_INFO(krb5_cc_store_cred), MAKE_FUNC_INFO(krb5_cc_retrieve_cred), MAKE_FUNC_INFO(krb5_cc_get_principal), MAKE_FUNC_INFO(krb5_cc_start_seq_get), MAKE_FUNC_INFO(krb5_cc_next_cred), MAKE_FUNC_INFO(krb5_cc_end_seq_get), MAKE_FUNC_INFO(krb5_cc_remove_cred), MAKE_FUNC_INFO(krb5_cc_set_flags), MAKE_FUNC_INFO(krb5_cc_get_type), MAKE_FUNC_INFO(krb5_free_context), MAKE_FUNC_INFO(krb5_free_cred_contents), MAKE_FUNC_INFO(krb5_free_principal), MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), MAKE_FUNC_INFO(krb5_init_context), MAKE_FUNC_INFO(krb5_parse_name), MAKE_FUNC_INFO(krb5_timeofday), MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), MAKE_FUNC_INFO(krb5_unparse_name), MAKE_FUNC_INFO(krb5_get_credentials), MAKE_FUNC_INFO(krb5_mk_req), MAKE_FUNC_INFO(krb5_sname_to_principal), MAKE_FUNC_INFO(krb5_get_credentials_renew), MAKE_FUNC_INFO(krb5_free_data), MAKE_FUNC_INFO(krb5_free_data_contents), MAKE_FUNC_INFO(krb5_free_unparsed_name), MAKE_FUNC_INFO(krb5_os_localaddr), MAKE_FUNC_INFO(krb5_copy_keyblock_contents), MAKE_FUNC_INFO(krb5_copy_data), MAKE_FUNC_INFO(krb5_free_creds), MAKE_FUNC_INFO(krb5_build_principal), MAKE_FUNC_INFO(krb5_get_renewed_creds), MAKE_FUNC_INFO(krb5_free_addresses), MAKE_FUNC_INFO(krb5_get_default_config_files), MAKE_FUNC_INFO(krb5_free_config_files), MAKE_FUNC_INFO(krb5_get_default_realm), MAKE_FUNC_INFO(krb5_free_ticket), MAKE_FUNC_INFO(krb5_decode_ticket), MAKE_FUNC_INFO(krb5_get_host_realm), MAKE_FUNC_INFO(krb5_free_host_realm), MAKE_FUNC_INFO(krb5_free_addresses), MAKE_FUNC_INFO(krb5_c_random_make_octets), END_FUNC_INFO }; FUNC_INFO k4_fi[] = { MAKE_FUNC_INFO(krb_get_cred), MAKE_FUNC_INFO(krb_get_tf_realm), MAKE_FUNC_INFO(krb_mk_req), MAKE_FUNC_INFO(tkt_string), END_FUNC_INFO }; FUNC_INFO k524_fi[] = { MAKE_FUNC_INFO(krb524_init_ets), MAKE_FUNC_INFO(krb524_convert_creds_kdc), END_FUNC_INFO }; FUNC_INFO profile_fi[] = { MAKE_FUNC_INFO(profile_init), MAKE_FUNC_INFO(profile_release), MAKE_FUNC_INFO(profile_get_subsection_names), MAKE_FUNC_INFO(profile_free_list), MAKE_FUNC_INFO(profile_get_string), MAKE_FUNC_INFO(profile_release_string), END_FUNC_INFO }; FUNC_INFO ce_fi[] = { MAKE_FUNC_INFO(com_err), MAKE_FUNC_INFO(error_message), END_FUNC_INFO }; FUNC_INFO service_fi[] = { MAKE_FUNC_INFO(OpenSCManagerA), MAKE_FUNC_INFO(OpenServiceA), MAKE_FUNC_INFO(QueryServiceStatus), MAKE_FUNC_INFO(CloseServiceHandle), #ifdef USE_MS2MIT MAKE_FUNC_INFO(LsaNtStatusToWinError), #endif /* USE_MS2MIT */ END_FUNC_INFO }; #ifdef USE_MS2MIT FUNC_INFO lsa_fi[] = { MAKE_FUNC_INFO(LsaConnectUntrusted), MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), MAKE_FUNC_INFO(LsaCallAuthenticationPackage), MAKE_FUNC_INFO(LsaFreeReturnBuffer), MAKE_FUNC_INFO(LsaGetLogonSessionData), END_FUNC_INFO }; #endif /* USE_MS2MIT */ /* Static Prototypes */ char *afs_realm_of_cell(krb5_context, struct afsconf_cell *); static long get_cellconfig_callback(void *, struct sockaddr_in *, char *); int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *); static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context, void *data, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]); /* Static Declarations */ static int inited = 0; static int mid_cnt = 0; static struct textField * mid_tb = NULL; static HINSTANCE hKrb5 = 0; static HINSTANCE hKrb4 = 0; static HINSTANCE hKrb524 = 0; #ifdef USE_MS2MIT static HINSTANCE hSecur32 = 0; #endif /* USE_MS2MIT */ static HINSTANCE hAdvApi32 = 0; static HINSTANCE hComErr = 0; static HINSTANCE hService = 0; static HINSTANCE hProfile = 0; static HINSTANCE hLeash = 0; static HINSTANCE hCCAPI = 0; static struct principal_ccache_data * princ_cc_data = NULL; static struct cell_principal_map * cell_princ_map = NULL; void KFW_initialize(void) { static int inited = 0; if ( !inited ) { char mutexName[MAX_PATH]; HANDLE hMutex = NULL; sprintf(mutexName, "AFS KFW Init pid=%d", getpid()); hMutex = CreateMutex( NULL, TRUE, mutexName ); if ( GetLastError() == ERROR_ALREADY_EXISTS ) { if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) { return; } } if ( !inited ) { inited = 1; LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); #ifdef USE_MS2MIT LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); #endif /* USE_MS2MIT */ LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); if ( KFW_is_available() ) { char rootcell[MAXCELLCHARS+1]; #ifdef USE_MS2MIT KFW_import_windows_lsa(); #endif /* USE_MS2MIT */ KFW_import_ccache_data(); KFW_AFS_renew_expiring_tokens(); /* WIN32 NOTE: no way to get max chars */ if (!cm_GetRootCellName(rootcell)) KFW_AFS_renew_token_for_cell(rootcell); } } ReleaseMutex(hMutex); CloseHandle(hMutex); } } void KFW_cleanup(void) { if (hKrb5) FreeLibrary(hKrb5); if (hKrb4) FreeLibrary(hKrb4); if (hProfile) FreeLibrary(hProfile); if (hComErr) FreeLibrary(hComErr); if (hService) FreeLibrary(hService); #ifdef USE_MS2MIT if (hSecur32) FreeLibrary(hSecur32); #endif /* USE_MS2MIT */ if (hKrb524) FreeLibrary(hKrb524); if (hLeash) FreeLibrary(hLeash); if (hCCAPI) FreeLibrary(hCCAPI); } static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client"; int KFW_use_krb524(void) { HKEY parmKey; DWORD code, len; DWORD use524 = 0; code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { len = sizeof(use524); code = RegQueryValueEx(parmKey, "Use524", NULL, NULL, (BYTE *) &use524, &len); if (code != ERROR_SUCCESS) { RegCloseKey(parmKey); code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { len = sizeof(use524); code = RegQueryValueEx(parmKey, "Use524", NULL, NULL, (BYTE *) &use524, &len); if (code != ERROR_SUCCESS) use524 = 0; } } RegCloseKey (parmKey); } return use524; } int KFW_is_available(void) { HKEY parmKey; DWORD code, len; DWORD enableKFW = 1; code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { len = sizeof(enableKFW); code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL, (BYTE *) &enableKFW, &len); if (code != ERROR_SUCCESS) { RegCloseKey(parmKey); code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName, 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { len = sizeof(enableKFW); code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL, (BYTE *) &enableKFW, &len); if (code != ERROR_SUCCESS) enableKFW = 1; } } RegCloseKey (parmKey); } if ( !enableKFW ) return FALSE; KFW_initialize(); if ( hKrb5 && hComErr && hService && #ifdef USE_MS2MIT hSecur32 && #endif /* USE_MS2MIT */ hKrb524 && hProfile && hLeash && hCCAPI ) return TRUE; return FALSE; } int KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, int FreeContextFlag, krb5_context * ctx, krb5_ccache * cache) { char message[256]; const char *errText; int krb5Error = ((int)(rc & 255)); /* switch (krb5Error) { // Wrong password case 31: case 8: return; } */ errText = perror_message(rc); _snprintf(message, sizeof(message), "%s\n(Kerberos error %ld)\n\n%s failed", errText, krb5Error, FailedFunctionName); if ( IsDebuggerPresent() ) OutputDebugString(message); MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); if (FreeContextFlag == 1) { if (ctx && *ctx != NULL) { if (cache && *cache != NULL) { pkrb5_cc_close(*ctx, *cache); *cache = NULL; } pkrb5_free_context(*ctx); *ctx = NULL; } } return rc; } void KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa) { struct principal_ccache_data * next = princ_cc_data; krb5_principal principal = 0; char * pname = NULL; const char * ccname = NULL; krb5_error_code code = 0; krb5_error_code cc_code = 0; krb5_cc_cursor cur; krb5_creds creds; krb5_flags flags=0; krb5_timestamp now; if (ctx == 0 || cc == 0) return; code = pkrb5_cc_get_principal(ctx, cc, &principal); if ( code ) return; code = pkrb5_unparse_name(ctx, principal, &pname); if ( code ) goto cleanup; ccname = pkrb5_cc_get_name(ctx, cc); if (!ccname) goto cleanup; // Search the existing list to see if we have a match if ( next ) { for ( ; next ; next = next->next ) { if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) ) break; } } // If not, match add a new node to the beginning of the list and assign init it if ( !next ) { next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data)); next->next = princ_cc_data; princ_cc_data = next; next->principal = _strdup(pname); next->ccache_name = _strdup(ccname); next->from_lsa = lsa; next->expired = 1; next->expiration_time = 0; next->renew = 0; } flags = 0; // turn off OPENCLOSE mode code = pkrb5_cc_set_flags(ctx, cc, flags); if ( code ) goto cleanup; code = pkrb5_timeofday(ctx, &now); cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { if ( creds.ticket_flags & TKT_FLG_INITIAL ) { int valid; // we found the ticket we are looking for // check validity of timestamp // We add a 5 minutes fudge factor to compensate for potential // clock skew errors between the KDC and client OS valid = ((creds.times.starttime > 0) && now >= (creds.times.starttime - 300) && now < (creds.times.endtime + 300) && !(creds.ticket_flags & TKT_FLG_INVALID)); if ( next->from_lsa) { next->expired = 0; next->expiration_time = creds.times.endtime; next->renew = 1; } else if ( valid ) { next->expired = 0; next->expiration_time = creds.times.endtime; next->renew = (creds.times.renew_till > creds.times.endtime) && (creds.ticket_flags & TKT_FLG_RENEWABLE); } else { next->expired = 1; next->expiration_time = 0; next->renew = 0; } pkrb5_free_cred_contents(ctx, &creds); cc_code = KRB5_CC_END; break; } pkrb5_free_cred_contents(ctx, &creds); } if (cc_code == KRB5_CC_END) { code = pkrb5_cc_end_seq_get(ctx, cc, &cur); if (code) goto cleanup; } cleanup: flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE code = pkrb5_cc_set_flags(ctx, cc, flags); if ( pname ) pkrb5_free_unparsed_name(ctx,pname); if ( principal ) pkrb5_free_principal(ctx,principal); } int KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only) { struct principal_ccache_data * next = princ_cc_data; char * response = NULL; if ( !principal || !ccache ) return 0; while ( next ) { if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) { if (response) { // we always want to prefer the MS Kerberos LSA cache or // the cache afscreds created specifically for the principal // if the current entry is either one, drop the previous find if ( next->from_lsa || !strcmp(next->ccache_name,principal) ) free(response); } response = _strdup(next->ccache_name); // MS Kerberos LSA is our best option so use it and quit if ( next->from_lsa ) break; } next = next->next; } if ( response ) { *ccache = response; return 1; } return 0; } void KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname) { struct principal_ccache_data ** next = &princ_cc_data; if ( !pname && !ccname ) return; while ( (*next) ) { if ( !strcmp((*next)->principal,pname) || !strcmp((*next)->ccache_name,ccname) ) { void * temp; free((*next)->principal); free((*next)->ccache_name); temp = (*next); (*next) = (*next)->next; free(temp); } } } void KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active) { struct cell_principal_map * next = cell_princ_map; // Search the existing list to see if we have a match if ( next ) { for ( ; next ; next = next->next ) { if ( !strcmp(next->cell, cell) ) { if ( !strcmp(next->principal,pname) ) { next->active = active; break; } else { // OpenAFS currently has a restriction of one active token per cell // Therefore, whenever we update the table with a new active cell we // must mark all of the other principal to cell entries as inactive. if (active) next->active = 0; } } } } // If not, match add a new node to the beginning of the list and assign init it if ( !next ) { next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map)); next->next = cell_princ_map; cell_princ_map = next; next->principal = _strdup(pname); next->cell = _strdup(cell); next->active = active; } } void KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell) { struct cell_principal_map ** next = &cell_princ_map; if ( !pname && !cell ) return; while ( (*next) ) { if ( !strcmp((*next)->principal,pname) || !strcmp((*next)->cell,cell) ) { void * temp; free((*next)->principal); free((*next)->cell); temp = (*next); (*next) = (*next)->next; free(temp); } } } // Returns (if possible) a principal which has been known in // the past to have been used to obtain tokens for the specified // cell. // TODO: Attempt to return one which has not yet expired by checking // the principal/ccache data int KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only) { struct cell_principal_map * next_map = cell_princ_map; const char * princ = NULL; int count = 0, i; if ( !cell ) return 0; while ( next_map ) { if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { count++; } next_map = next_map->next; } if ( !principals || !count ) return count; *principals = (char **) malloc(sizeof(char *) * count); for ( next_map = cell_princ_map, i=0 ; next_map && inext ) { if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { (*principals)[i++] = _strdup(next_map->principal); } } return count; } int KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only) { int count = 0, i; struct cell_principal_map * next_map = cell_princ_map; const char * princ = NULL; if ( !pname ) return 0; while ( next_map ) { if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { count++; } next_map = next_map->next; } if ( !cells ) return count; *cells = (char **) malloc(sizeof(char *) * count); for ( next_map = cell_princ_map, i=0 ; next_map && inext ) { if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { (*cells)[i++] = _strdup(next_map->cell); } } return count; } /* Given a principal return an existing ccache or create one and return */ int KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc) { krb5_context ctx; char * pname = 0; char * ccname = 0; krb5_error_code code; if (!pkrb5_init_context) return 0; if ( alt_ctx ) { ctx = alt_ctx; } else { code = pkrb5_init_context(&ctx); if (code) goto cleanup; } if ( principal ) { code = pkrb5_unparse_name(ctx, principal, &pname); if (code) goto cleanup; if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) && !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) { ccname = (char *)malloc(strlen(pname) + 5); sprintf(ccname,"API:%s",pname); } code = pkrb5_cc_resolve(ctx, ccname, cc); } else { code = pkrb5_cc_default(ctx, cc); if (code) goto cleanup; } cleanup: if (ccname) free(ccname); if (pname) pkrb5_free_unparsed_name(ctx,pname); if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); return(code); } #ifdef USE_MS2MIT // Import Microsoft Credentials into a new MIT ccache void KFW_import_windows_lsa(void) { krb5_context ctx = 0; krb5_ccache cc = 0; krb5_principal princ = 0; char * pname = NULL; krb5_data * princ_realm; krb5_error_code code; char cell[128]="", realm[128]=""; int i; if (!pkrb5_init_context) return; #ifdef COMMENT if ( !MSLSA_IsKerberosLogon() ) return; #endif code = pkrb5_init_context(&ctx); if (code) goto cleanup; code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc); if (code) goto cleanup; KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE); code = pkrb5_cc_get_principal(ctx, cc, &princ); if ( code ) goto cleanup; code = pkrb5_unparse_name(ctx,princ,&pname); if ( code ) goto cleanup; princ_realm = krb5_princ_realm(ctx, princ); for ( i=0; ilength; i++ ) { realm[i] = princ_realm->data[i]; cell[i] = tolower(princ_realm->data[i]); } cell[i] = '\0'; realm[i] = '\0'; code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } if ( code ) goto cleanup; KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); cleanup: if (pname) pkrb5_free_unparsed_name(ctx,pname); if (princ) pkrb5_free_principal(ctx,princ); if (cc) pkrb5_cc_close(ctx,cc); if (ctx) pkrb5_free_context(ctx); } #endif /* USE_MS2MIT */ // If there are existing MIT credentials, copy them to a new // ccache named after the principal // Enumerate all existing MIT ccaches and construct entries // in the principal_ccache table // Enumerate all existing AFS Tokens and construct entries // in the cell_principal table void KFW_import_ccache_data(void) { krb5_context ctx = 0; krb5_ccache cc = 0; krb5_principal principal = 0; krb5_creds creds; krb5_error_code code; krb5_error_code cc_code; krb5_cc_cursor cur; apiCB * cc_ctx = 0; struct _infoNC ** pNCi = NULL; int i, j, flags; if ( !pcc_initialize ) return; if ( IsDebuggerPresent() ) OutputDebugString("KFW_import_ccache_data()\n"); code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); if (code) goto cleanup; code = pcc_get_NC_info(cc_ctx, &pNCi); if (code) goto cleanup; code = pkrb5_init_context(&ctx); if (code) goto cleanup; for ( i=0; pNCi[i]; i++ ) { if ( pNCi[i]->vers != CC_CRED_V5 ) continue; if ( IsDebuggerPresent() ) { OutputDebugString("Principal: "); OutputDebugString(pNCi[i]->principal); OutputDebugString(" in ccache "); OutputDebugString(pNCi[i]->name); OutputDebugString("\n"); } if ( strcmp(pNCi[i]->name,pNCi[i]->principal) && strcmp(pNCi[i]->name,LSA_CCNAME) ) { int found = 0; for ( j=0; pNCi[j]; j++ ) { if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) { found = 1; break; } } code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc); if (code) goto loop_cleanup; if (!found) { krb5_ccache oldcc = 0; if ( IsDebuggerPresent() ) OutputDebugString("copying ccache data to new ccache\n"); code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal); if (code) goto loop_cleanup; code = pkrb5_cc_initialize(ctx, cc, principal); if (code) goto loop_cleanup; code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc); if (code) goto loop_cleanup; code = pkrb5_cc_copy_creds(ctx,oldcc,cc); if (code) { code = pkrb5_cc_close(ctx,cc); cc = 0; code = pkrb5_cc_close(ctx,oldcc); cc = 0; KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL); continue; } code = pkrb5_cc_close(ctx,oldcc); } } else { code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc); if (code) goto loop_cleanup; } flags = 0; // turn off OPENCLOSE mode code = pkrb5_cc_set_flags(ctx, cc, flags); if ( code ) goto cleanup; KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME)); cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { krb5_data * sname = krb5_princ_name(ctx, creds.server); krb5_data * cell = krb5_princ_component(ctx, creds.server, 1); krb5_data * realm = krb5_princ_realm(ctx, creds.server); if ( sname && cell && !strcmp("afs",sname->data) ) { struct ktc_principal aserver; struct ktc_principal aclient; struct ktc_token atoken; int active = TRUE; if ( IsDebuggerPresent() ) { OutputDebugString("Found AFS ticket: "); OutputDebugString(sname->data); if ( cell->data ) { OutputDebugString("/"); OutputDebugString(cell->data); } OutputDebugString("@"); OutputDebugString(realm->data); OutputDebugString("\n"); } memset(&aserver, '\0', sizeof(aserver)); strcpy(aserver.name, sname->data); strcpy(aserver.cell, cell->data); code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient); if (!code) { // Found a token in AFS Client Server which matches char pname[128], *p, *q; for ( p=pname, q=aclient.name; *q; p++, q++) *p = *q; for ( *p++ = '@', q=aclient.cell; *q; p++, q++) *p = toupper(*q); *p = '\0'; if ( IsDebuggerPresent() ) { OutputDebugString("Found AFS token: "); OutputDebugString(pname); OutputDebugString("\n"); } if ( strcmp(pname,pNCi[i]->principal) ) active = FALSE; KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); } else { // Attempt to import it KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); if ( IsDebuggerPresent() ) { OutputDebugString("Calling KFW_AFS_klog() to obtain token\n"); } code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } } } else if ( IsDebuggerPresent() ) { OutputDebugString("Found ticket: "); OutputDebugString(sname->data); if ( cell && cell->data ) { OutputDebugString("/"); OutputDebugString(cell->data); } OutputDebugString("@"); OutputDebugString(realm->data); OutputDebugString("\n"); } pkrb5_free_cred_contents(ctx, &creds); } if (cc_code == KRB5_CC_END) { cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); if (cc_code) goto loop_cleanup; } loop_cleanup: flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE code = pkrb5_cc_set_flags(ctx, cc, flags); if (cc) { pkrb5_cc_close(ctx,cc); cc = 0; } if (principal) { pkrb5_free_principal(ctx,principal); principal = 0; } } cleanup: if (ctx) pkrb5_free_context(ctx); if (pNCi) pcc_free_NC_info(cc_ctx, &pNCi); if (cc_ctx) pcc_shutdown(&cc_ctx); } int KFW_AFS_get_cred( char * username, char * cell, char * password, int lifetime, char * smbname, char ** reasonP ) { krb5_context ctx = 0; krb5_ccache cc = 0; char * realm = 0; char ** realmlist = 0; krb5_principal principal = 0; char * pname = 0; krb5_error_code code; char local_cell[MAXCELLCHARS+1]; char **cells = NULL; int cell_count=0; struct afsconf_cell cellconfig; char * dot; if (!pkrb5_init_context) return 0; if ( IsDebuggerPresent() ) { OutputDebugString("KFW_AFS_get_cred for token "); OutputDebugString(username); OutputDebugString(" in cell "); OutputDebugString(cell); OutputDebugString("\n"); } code = pkrb5_init_context(&ctx); if ( code ) goto cleanup; code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell); if ( code ) goto cleanup; realm = strchr(username,'@'); if ( realm ) { pname = strdup(username); realm = strchr(pname, '@'); *realm = '\0'; /* handle kerberos iv notation */ while ( dot = strchr(pname,'.') ) { *dot = '/'; } *realm++ = '@'; } else { realm = afs_realm_of_cell(ctx, &cellconfig); // do not free pname = malloc(strlen(username) + strlen(realm) + 2); strcpy(pname, username); /* handle kerberos iv notation */ while ( dot = strchr(pname,'.') ) { *dot = '/'; } strcat(pname,"@"); strcat(pname,realm); } if ( IsDebuggerPresent() ) { OutputDebugString("Realm: "); OutputDebugString(realm); OutputDebugString("\n"); } code = pkrb5_parse_name(ctx, pname, &principal); if ( code ) goto cleanup; code = KFW_get_ccache(ctx, principal, &cc); if ( code ) goto cleanup; if ( lifetime == 0 ) lifetime = pLeash_get_default_lifetime(); if ( password && password[0] ) { code = KFW_kinit( ctx, cc, HWND_DESKTOP, pname, password, lifetime, pLeash_get_default_forwardable(), pLeash_get_default_proxiable(), pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0, pLeash_get_default_noaddresses(), pLeash_get_default_publicip()); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_kinit() returns: %d\n",code); OutputDebugString(message); } if ( code ) goto cleanup; KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE); } code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime,smbname); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } if ( code ) goto cleanup; KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); // Attempt to obtain new tokens for other cells supported by the same // principal cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE); if ( cell_count > 1 ) { while ( cell_count-- ) { if ( strcmp(cells[cell_count],cell) ) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"found another cell for the same principal: %s\n",cell); OutputDebugString(message); } code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); if ( code ) continue; realm = afs_realm_of_cell(ctx, &cellconfig); // do not free if ( IsDebuggerPresent() ) { OutputDebugString("Realm: "); OutputDebugString(realm); OutputDebugString("\n"); } code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime,smbname); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } } free(cells[cell_count]); } free(cells); } else if ( cell_count == 1 ) { free(cells[0]); free(cells); } cleanup: if ( pname ) free(pname); if ( cc ) pkrb5_cc_close(ctx, cc); if ( code && reasonP ) { *reasonP = (char *)perror_message(code); } return(code); } int KFW_AFS_destroy_tickets_for_cell(char * cell) { krb5_context ctx = 0; krb5_error_code code; int count; char ** principals = NULL; if (!pkrb5_init_context) return 0; if ( IsDebuggerPresent() ) { OutputDebugString("KFW_AFS_destroy_ticets_for_cell: "); OutputDebugString(cell); OutputDebugString("\n"); } code = pkrb5_init_context(&ctx); if (code) ctx = 0; count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE); if ( count > 0 ) { krb5_principal princ = 0; krb5_ccache cc = 0; while ( count-- ) { int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE); if ( cell_count > 1 ) { // TODO - What we really should do here is verify whether or not any of the // other cells which use this principal to obtain its credentials actually // have valid tokens or not. If they are currently using these credentials // we will skip them. For the time being we assume that if there is an active // map in the table that they are actively being used. goto loop_cleanup; } code = pkrb5_parse_name(ctx, principals[count], &princ); if (code) goto loop_cleanup; code = KFW_get_ccache(ctx, princ, &cc); if (code) goto loop_cleanup; code = pkrb5_cc_destroy(ctx, cc); if (!code) cc = 0; loop_cleanup: if ( cc ) { pkrb5_cc_close(ctx, cc); cc = 0; } if ( princ ) { pkrb5_free_principal(ctx, princ); princ = 0; } KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE); free(principals[count]); } free(principals); } pkrb5_free_context(ctx); return 0; } int KFW_AFS_renew_expiring_tokens(void) { krb5_error_code code = 0; krb5_context ctx = 0; krb5_ccache cc = 0; krb5_timestamp now; struct principal_ccache_data * pcc_next = princ_cc_data; int cell_count; char ** cells=NULL; const char * realm = NULL; char local_cell[MAXCELLCHARS+1]=""; struct afsconf_cell cellconfig; if (!pkrb5_init_context) return 0; if ( pcc_next == NULL ) // nothing to do return 0; if ( IsDebuggerPresent() ) { OutputDebugString("KFW_AFS_renew_expiring_tokens\n"); } code = pkrb5_init_context(&ctx); if (code) goto cleanup; code = pkrb5_timeofday(ctx, &now); if (code) goto cleanup; for ( ; pcc_next ; pcc_next = pcc_next->next ) { if ( pcc_next->expired ) continue; if ( now >= (pcc_next->expiration_time) ) { if ( !pcc_next->from_lsa ) { pcc_next->expired = 1; continue; } } if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) { code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc); if ( code ) goto loop_cleanup; code = KFW_renew(ctx,cc); #ifdef USE_MS2MIT if ( code && pcc_next->from_lsa) goto loop_cleanup; #endif /* USE_MS2MIT */ KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa); if (code) goto loop_cleanup; // Attempt to obtain new tokens for other cells supported by the same // principal cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE); if ( cell_count > 0 ) { while ( cell_count-- ) { if ( IsDebuggerPresent() ) { OutputDebugString("Cell: "); OutputDebugString(cells[cell_count]); OutputDebugString("\n"); } code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); if ( code ) continue; realm = afs_realm_of_cell(ctx, &cellconfig); // do not free if ( IsDebuggerPresent() ) { OutputDebugString("Realm: "); OutputDebugString(realm); OutputDebugString("\n"); } code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime(),NULL); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } free(cells[cell_count]); } free(cells); } } loop_cleanup: if ( cc ) { pkrb5_cc_close(ctx,cc); cc = 0; } } cleanup: if ( cc ) pkrb5_cc_close(ctx,cc); if ( ctx ) pkrb5_free_context(ctx); return 0; } BOOL KFW_AFS_renew_token_for_cell(char * cell) { krb5_error_code code = 0; krb5_context ctx = 0; int count; char ** principals = NULL; if (!pkrb5_init_context) return 0; if ( IsDebuggerPresent() ) { OutputDebugString("KFW_AFS_renew_token_for_cell:"); OutputDebugString(cell); OutputDebugString("\n"); } code = pkrb5_init_context(&ctx); if (code) goto cleanup; count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); if ( count == 0 ) { // We know we must have a credential somewhere since we are // trying to renew a token KFW_import_ccache_data(); count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); } if ( count > 0 ) { krb5_principal princ = 0; krb5_principal service = 0; #ifdef COMMENT krb5_creds mcreds, creds; #endif /* COMMENT */ krb5_ccache cc = 0; const char * realm = NULL; struct afsconf_cell cellconfig; char local_cell[MAXCELLCHARS+1]; while ( count-- ) { code = pkrb5_parse_name(ctx, principals[count], &princ); if (code) goto loop_cleanup; code = KFW_get_ccache(ctx, princ, &cc); if (code) goto loop_cleanup; code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell); if ( code ) goto loop_cleanup; realm = afs_realm_of_cell(ctx, &cellconfig); // do not free if ( IsDebuggerPresent() ) { OutputDebugString("Realm: "); OutputDebugString(realm); OutputDebugString("\n"); } #ifdef COMMENT /* krb5_cc_remove_cred() is not implemented * for a single cred */ code = pkrb5_build_principal(ctx, &service, strlen(realm), realm, "afs", cell, NULL); if (!code) { memset(&mcreds, 0, sizeof(krb5_creds)); mcreds.client = princ; mcreds.server = service; code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds); if (!code) { if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, creds.client, &cname); pkrb5_unparse_name(ctx, creds.server, &sname); OutputDebugString("Removing credential for client \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds); pkrb5_free_principal(ctx, creds.client); pkrb5_free_principal(ctx, creds.server); } } #endif /* COMMENT */ code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime(),NULL); if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"KFW_AFS_klog() returns: %d\n",code); OutputDebugString(message); } loop_cleanup: if (cc) { pkrb5_cc_close(ctx, cc); cc = 0; } if (princ) { pkrb5_free_principal(ctx, princ); princ = 0; } if (service) { pkrb5_free_principal(ctx, service); princ = 0; } KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE); free(principals[count]); } free(principals); } else code = -1; // we did not renew the tokens cleanup: pkrb5_free_context(ctx); return (code ? FALSE : TRUE); } int KFW_AFS_renew_tokens_for_all_cells(void) { struct cell_principal_map * next = cell_princ_map; if ( IsDebuggerPresent() ) OutputDebugString("KFW_AFS_renew_tokens_for_all()\n"); if ( !next ) return 0; for ( ; next ; next = next->next ) { if ( next->active ) KFW_AFS_renew_token_for_cell(next->cell); } return 0; } int KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc) { krb5_error_code code = 0; krb5_context ctx = 0; krb5_ccache cc = 0; krb5_principal me = 0; krb5_principal server = 0; krb5_creds my_creds; krb5_data *realm = 0; if (!pkrb5_init_context) return 0; memset(&my_creds, 0, sizeof(krb5_creds)); if ( alt_ctx ) { ctx = alt_ctx; } else { code = pkrb5_init_context(&ctx); if (code) goto cleanup; } if ( alt_cc ) { cc = alt_cc; } else { code = pkrb5_cc_default(ctx, &cc); if (code) goto cleanup; } code = pkrb5_cc_get_principal(ctx, cc, &me); if (code) goto cleanup; realm = krb5_princ_realm(ctx, me); code = pkrb5_build_principal_ext(ctx, &server, realm->length,realm->data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, realm->length,realm->data, 0); if ( code ) goto cleanup; if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, me, &cname); pkrb5_unparse_name(ctx, server, &sname); OutputDebugString("Renewing credential for client \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } my_creds.client = me; my_creds.server = server; code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); if (code) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code); OutputDebugString(message); } goto cleanup; } code = pkrb5_cc_initialize(ctx, cc, me); if (code) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"krb5_cc_initialize() failed: %d\n",code); OutputDebugString(message); } goto cleanup; } code = pkrb5_cc_store_cred(ctx, cc, &my_creds); if (code) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"krb5_cc_store_cred() failed: %d\n",code); OutputDebugString(message); } goto cleanup; } cleanup: if (my_creds.client == me) my_creds.client = 0; if (my_creds.server == server) my_creds.server = 0; pkrb5_free_cred_contents(ctx, &my_creds); if (me) pkrb5_free_principal(ctx, me); if (server) pkrb5_free_principal(ctx, server); if (cc && (cc != alt_cc)) pkrb5_cc_close(ctx, cc); if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); return(code); } int KFW_kinit( krb5_context alt_ctx, krb5_ccache alt_cc, HWND hParent, char *principal_name, char *password, krb5_deltat lifetime, DWORD forwardable, DWORD proxiable, krb5_deltat renew_life, DWORD addressless, DWORD publicIP ) { krb5_error_code code = 0; krb5_context ctx = 0; krb5_ccache cc = 0; krb5_principal me = 0; char* name = 0; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_address ** addrs = NULL; int i = 0, addr_count = 0; if (!pkrb5_init_context) return 0; pkrb5_get_init_creds_opt_init(&options); memset(&my_creds, 0, sizeof(my_creds)); if (alt_ctx) { ctx = alt_ctx; } else { code = pkrb5_init_context(&ctx); if (code) goto cleanup; } if ( alt_cc ) { cc = alt_cc; } else { code = pkrb5_cc_default(ctx, &cc); if (code) goto cleanup; } code = pkrb5_parse_name(ctx, principal_name, &me); if (code) goto cleanup; code = pkrb5_unparse_name(ctx, me, &name); if (code) goto cleanup; if (lifetime == 0) lifetime = pLeash_get_default_lifetime(); else lifetime *= 5*60; if (renew_life > 0) renew_life *= 5*60; if (lifetime) pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); pkrb5_get_init_creds_opt_set_forwardable(&options, forwardable ? 1 : 0); pkrb5_get_init_creds_opt_set_proxiable(&options, proxiable ? 1 : 0); pkrb5_get_init_creds_opt_set_renew_life(&options, renew_life); if (addressless) pkrb5_get_init_creds_opt_set_address_list(&options,NULL); else { if (publicIP) { // we are going to add the public IP address specified by the user // to the list provided by the operating system krb5_address ** local_addrs=NULL; DWORD netIPAddr; pkrb5_os_localaddr(ctx, &local_addrs); while ( local_addrs[i++] ); addr_count = i + 1; addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); if ( !addrs ) { pkrb5_free_addresses(ctx, local_addrs); goto cleanup; } memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); i = 0; while ( local_addrs[i] ) { addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); if (addrs[i] == NULL) { pkrb5_free_addresses(ctx, local_addrs); goto cleanup; } addrs[i]->magic = local_addrs[i]->magic; addrs[i]->addrtype = local_addrs[i]->addrtype; addrs[i]->length = local_addrs[i]->length; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) { pkrb5_free_addresses(ctx, local_addrs); goto cleanup; } memcpy(addrs[i]->contents,local_addrs[i]->contents, local_addrs[i]->length); /* safe */ i++; } pkrb5_free_addresses(ctx, local_addrs); addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); if (addrs[i] == NULL) goto cleanup; addrs[i]->magic = KV5M_ADDRESS; addrs[i]->addrtype = AF_INET; addrs[i]->length = 4; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) goto cleanup; netIPAddr = htonl(publicIP); memcpy(addrs[i]->contents,&netIPAddr,4); pkrb5_get_init_creds_opt_set_address_list(&options,addrs); } } code = pkrb5_get_init_creds_password(ctx, &my_creds, me, password, // password KRB5_prompter, // prompter hParent, // prompter data 0, // start time 0, // service name &options); if (code) goto cleanup; code = pkrb5_cc_initialize(ctx, cc, me); if (code) goto cleanup; code = pkrb5_cc_store_cred(ctx, cc, &my_creds); if (code) goto cleanup; cleanup: if ( addrs ) { for ( i=0;icontents ) free(addrs[i]->contents); free(addrs[i]); } } } if (my_creds.client == me) my_creds.client = 0; pkrb5_free_cred_contents(ctx, &my_creds); if (name) pkrb5_free_unparsed_name(ctx, name); if (me) pkrb5_free_principal(ctx, me); if (cc && (cc != alt_cc)) pkrb5_cc_close(ctx, cc); if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); return(code); } int KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc) { krb5_context ctx; krb5_ccache cc; krb5_error_code code; if (!pkrb5_init_context) return 0; if (alt_ctx) { ctx = alt_ctx; } else { code = pkrb5_init_context(&ctx); if (code) goto cleanup; } if ( alt_cc ) { cc = alt_cc; } else { code = pkrb5_cc_default(ctx, &cc); if (code) goto cleanup; } code = pkrb5_cc_destroy(ctx, cc); if ( !code ) cc = 0; cleanup: if (cc && (cc != alt_cc)) pkrb5_cc_close(ctx, cc); if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); return(code); } #ifdef USE_MS2MIT static BOOL GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) { NTSTATUS Status = 0; HANDLE TokenHandle; TOKEN_STATISTICS Stats; DWORD ReqLen; BOOL Success; if (!ppSessionData) return FALSE; *ppSessionData = NULL; Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); if ( !Success ) return FALSE; Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); CloseHandle( TokenHandle ); if ( !Success ) return FALSE; Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); if ( FAILED(Status) || !ppSessionData ) return FALSE; return TRUE; } // // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the // cache. It validates whether or not it is reasonable to assume that if we // attempted to retrieve valid tickets we could do so. Microsoft does not // automatically renew expired tickets. Therefore, the cache could contain // expired or invalid tickets. Microsoft also caches the user's password // and will use it to retrieve new TGTs if the cache is empty and tickets // are requested. static BOOL MSLSA_IsKerberosLogon(VOID) { PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; BOOL Success = FALSE; if ( GetSecurityLogonSessionData(&pSessionData) ) { if ( pSessionData->AuthenticationPackage.Buffer ) { WCHAR buffer[256]; WCHAR *usBuffer; int usLength; Success = FALSE; usBuffer = (pSessionData->AuthenticationPackage).Buffer; usLength = (pSessionData->AuthenticationPackage).Length; if (usLength < 256) { lstrcpynW (buffer, usBuffer, usLength); lstrcatW (buffer,L""); if ( !lstrcmpW(L"Kerberos",buffer) ) Success = TRUE; } } pLsaFreeReturnBuffer(pSessionData); } return Success; } #endif /* USE_MS2MIT */ static BOOL CALLBACK MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam) { int i; switch ( message ) { case WM_INITDIALOG: if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT ) { SetFocus(GetDlgItem( hDialog, ID_MID_TEXT)); return FALSE; } for ( i=0; i < mid_cnt ; i++ ) { if (mid_tb[i].echo == 0) SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0); else if (mid_tb[i].echo == 2) SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0); } return TRUE; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: for ( i=0; i < mid_cnt ; i++ ) { if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) ) *mid_tb[i].buf = '\0'; } /* fallthrough */ case IDCANCEL: EndDialog(hDialog, LOWORD(wParam)); return TRUE; } } return FALSE; } static LPWORD lpwAlign( LPWORD lpIn ) { ULONG ul; ul = (ULONG) lpIn; ul += 3; ul >>=2; ul <<=2; return (LPWORD) ul;; } /* * dialog widths are measured in 1/4 character widths * dialog height are measured in 1/8 character heights */ static LRESULT MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, char * ptext[], int numlines, int width, int tb_cnt, struct textField * tb) { HGLOBAL hgbl; LPDLGTEMPLATE lpdt; LPDLGITEMTEMPLATE lpdit; LPWORD lpw; LPWSTR lpwsz; LRESULT ret; int nchar, i, pwid; hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096); if (!hgbl) return -1; mid_cnt = tb_cnt; mid_tb = tb; lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); // Define a dialog box. lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_CENTER | DS_SETFOREGROUND | DS_3DLOOK | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE; lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls lpdt->x = 10; lpdt->y = 10; lpdt->cx = 20 + width * 4; lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14; lpw = (LPWORD) (lpdt + 1); *lpw++ = 0; // no menu *lpw++ = 0; // predefined dialog box class (by default) lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128); lpw += nchar; *lpw++ = 8; // font size (points) lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", -1, lpwsz, 128); lpw += nchar; //----------------------- // Define an OK button. //----------------------- lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary lpdit = (LPDLGITEMTEMPLATE) lpw; lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER; lpdit->dwExtendedStyle = 0; lpdit->x = (lpdt->cx - 14)/4 - 20; lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; lpdit->cx = 40; lpdit->cy = 14; lpdit->id = IDOK; // OK button identifier lpw = (LPWORD) (lpdit + 1); *lpw++ = 0xFFFF; *lpw++ = 0x0080; // button class lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50); lpw += nchar; *lpw++ = 0; // no creation data //----------------------- // Define an Cancel button. //----------------------- lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary lpdit = (LPDLGITEMTEMPLATE) lpw; lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER; lpdit->dwExtendedStyle = 0; lpdit->x = (lpdt->cx - 14)*3/4 - 20; lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; lpdit->cx = 40; lpdit->cy = 14; lpdit->id = IDCANCEL; // CANCEL button identifier lpw = (LPWORD) (lpdit + 1); *lpw++ = 0xFFFF; *lpw++ = 0x0080; // button class lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50); lpw += nchar; *lpw++ = 0; // no creation data /* Add controls for preface data */ for ( i=0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; lpdit->dwExtendedStyle = 0; lpdit->x = 10; lpdit->y = 10 + i * 14; lpdit->cx = strlen(ptext[i]) * 4 + 10; lpdit->cy = 14; lpdit->id = ID_TEXT + i; // text identifier lpw = (LPWORD) (lpdit + 1); *lpw++ = 0xFFFF; *lpw++ = 0x0082; // static class lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], -1, lpwsz, 2*width); lpw += nchar; *lpw++ = 0; // no creation data } for ( i=0, pwid = 0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; lpdit->dwExtendedStyle = 0; lpdit->x = 10; lpdit->y = 10 + (numlines + i + 1) * 14; lpdit->cx = pwid * 4; lpdit->cy = 14; lpdit->id = ID_TEXT + numlines + i; // text identifier lpw = (LPWORD) (lpdit + 1); *lpw++ = 0xFFFF; *lpw++ = 0x0082; // static class lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", -1, lpwsz, 128); lpw += nchar; *lpw++ = 0; // no creation data /*----------------------- * Define an edit control. *-----------------------*/ lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ lpdit = (LPDLGITEMTEMPLATE) lpw; lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD); lpdit->dwExtendedStyle = 0; lpdit->x = 10 + (pwid + 1) * 4; lpdit->y = 10 + (numlines + i + 1) * 14; lpdit->cx = (width - (pwid + 1)) * 4; lpdit->cy = 14; lpdit->id = ID_MID_TEXT + i; // identifier lpw = (LPWORD) (lpdit + 1); *lpw++ = 0xFFFF; *lpw++ = 0x0081; // edit class lpwsz = (LPWSTR) lpw; nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", -1, lpwsz, 128); lpw += nchar; *lpw++ = 0; // no creation data } GlobalUnlock(hgbl); ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, hwndOwner, (DLGPROC) MultiInputDialogProc); GlobalFree(hgbl); switch ( ret ) { case 0: /* Timeout */ return -1; case IDOK: return 1; case IDCANCEL: return 0; default: { char buf[256]; sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError()); MessageBox(hwndOwner, buf, "GetLastError()", MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); return -1; } } } static int multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[]) { HINSTANCE hInst = 0; int maxwidth = 0; int numlines = 0; int len; char * plines[16], *p = preface ? preface : ""; int i; for ( i=0; i<16; i++ ) plines[i] = NULL; while (*p && numlines < 16) { plines[numlines++] = p; for ( ;*p && *p != '\r' && *p != '\n'; p++ ); if ( *p == '\r' && *(p+1) == '\n' ) { *p++ = '\0'; p++; } else if ( *p == '\n' ) { *p++ = '\0'; } if ( strlen(plines[numlines-1]) > maxwidth ) maxwidth = strlen(plines[numlines-1]); } for ( i=0;i 40 ? 40 : tb[i].len); if ( maxwidth < len ) maxwidth = len; } return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)); } static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context, void *data, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]) { krb5_error_code errcode = 0; int i; struct textField * tb = NULL; int len = 0, blen=0, nlen=0; HWND hParent = (HWND)data; if (name) nlen = strlen(name)+2; if (banner) blen = strlen(banner)+2; tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts); if ( tb != NULL ) { int ok; memset(tb,0,sizeof(struct textField) * num_prompts); for ( i=0; i < num_prompts; i++ ) { tb[i].buf = prompts[i].reply->data; tb[i].len = prompts[i].reply->length; tb[i].label = prompts[i].prompt; tb[i].def = NULL; tb[i].echo = (prompts[i].hidden ? 2 : 1); } ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb); if ( ok ) { for ( i=0; i < num_prompts; i++ ) prompts[i].reply->length = strlen(prompts[i].reply->data); } else errcode = -2; } if ( tb ) free(tb); if (errcode) { for (i = 0; i < num_prompts; i++) { memset(prompts[i].reply->data, 0, prompts[i].reply->length); } } return errcode; } BOOL KFW_AFS_wait_for_service_start(void) { char HostName[64]; DWORD CurrentState; CurrentState = SERVICE_START_PENDING; memset(HostName, '\0', sizeof(HostName)); gethostname(HostName, sizeof(HostName)); while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED) { if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) return(0); if ( IsDebuggerPresent() ) { switch ( CurrentState ) { case SERVICE_STOPPED: OutputDebugString("SERVICE_STOPPED\n"); break; case SERVICE_START_PENDING: OutputDebugString("SERVICE_START_PENDING\n"); break; case SERVICE_STOP_PENDING: OutputDebugString("SERVICE_STOP_PENDING\n"); break; case SERVICE_RUNNING: OutputDebugString("SERVICE_RUNNING\n"); break; case SERVICE_CONTINUE_PENDING: OutputDebugString("SERVICE_CONTINUE_PENDING\n"); break; case SERVICE_PAUSE_PENDING: OutputDebugString("SERVICE_PAUSE_PENDING\n"); break; case SERVICE_PAUSED: OutputDebugString("SERVICE_PAUSED\n"); break; default: OutputDebugString("UNKNOWN Service State\n"); } } if (CurrentState == SERVICE_STOPPED) return(0); if (CurrentState == SERVICE_RUNNING) return(1); Sleep(500); } return(0); } int KFW_AFS_unlog(void) { long rc; char HostName[64]; DWORD CurrentState; CurrentState = 0; memset(HostName, '\0', sizeof(HostName)); gethostname(HostName, sizeof(HostName)); if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) return(0); if (CurrentState != SERVICE_RUNNING) return(0); rc = ktc_ForgetAllTokens(); return(0); } #define ALLOW_REGISTER 1 static int ViceIDToUsername(char *username, char *realm_of_user, char *realm_of_cell, char * cell_to_use, struct ktc_principal *aclient, struct ktc_principal *aserver, struct ktc_token *atoken) { static char lastcell[MAXCELLCHARS+1] = { 0 }; static char confname[512] = { 0 }; char username_copy[BUFSIZ]; long viceId; /* AFS uid of user */ int status = 0; #ifdef ALLOW_REGISTER afs_int32 id; #endif /* ALLOW_REGISTER */ if (confname[0] == '\0') { strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname)); confname[sizeof(confname) - 2] = '\0'; } /* * Talk about DUMB! It turns out that there is a bug in * pr_Initialize -- even if you give a different cell name * to it, it still uses a connection to a previous AFS server * if one exists. The way to fix this is to change the * _filename_ argument to pr_Initialize - that forces it to * re-initialize the connection. We do this by adding and * removing a "/" on the end of the configuration directory name. */ if (lastcell[0] != '\0' && (strcmp(lastcell, aserver->cell) != 0)) { int i = strlen(confname); if (confname[i - 1] == '/') { confname[i - 1] = '\0'; } else { confname[i] = '/'; confname[i + 1] = '\0'; } } strcpy(lastcell, aserver->cell); if (!pr_Initialize (0, confname, aserver->cell)) status = pr_SNameToId (username, &viceId); /* * This is a crock, but it is Transarc's crock, so * we have to play along in order to get the * functionality. The way the afs id is stored is * as a string in the username field of the token. * Contrary to what you may think by looking at * the code for tokens, this hack (AFS ID %d) will * not work if you change %d to something else. */ /* * This code is taken from cklog -- it lets people * automatically register with the ptserver in foreign cells */ #ifdef ALLOW_REGISTER if (status == 0) { if (viceId != ANONYMOUSID) { #else /* ALLOW_REGISTER */ if ((status == 0) && (viceId != ANONYMOUSID)) #endif /* ALLOW_REGISTER */ { #ifdef AFS_ID_TO_NAME strncpy(username_copy, username, BUFSIZ); snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId); #endif /* AFS_ID_TO_NAME */ } #ifdef ALLOW_REGISTER } else if (strcmp(realm_of_user, realm_of_cell) != 0) { id = 0; strncpy(aclient->name, username, MAXKTCNAMELEN - 1); strcpy(aclient->instance, ""); strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1); if (status = ktc_SetToken(aserver, atoken, aclient, 0)) return status; /* * In case you're wondering, we don't need to change the * filename here because we're still connecting to the * same cell -- we're just using a different authentication * level */ if (status = pr_Initialize(1L, confname, aserver->cell, 0)) return status; if (status = pr_CreateUser(username, &id)) return status; #ifdef AFS_ID_TO_NAME strncpy(username_copy, username, BUFSIZ); snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId); #endif /* AFS_ID_TO_NAME */ } } #endif /* ALLOW_REGISTER */ return status; } int KFW_AFS_klog( krb5_context alt_ctx, krb5_ccache alt_cc, char *service, char *cell, char *realm, int LifeTime, char *smbname ) { long rc = 0; CREDENTIALS creds; KTEXT_ST ticket; struct ktc_principal aserver; struct ktc_principal aclient; char realm_of_user[REALM_SZ]; /* Kerberos realm of user */ char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */ char local_cell[MAXCELLCHARS+1]; char Dmycell[MAXCELLCHARS+1]; struct ktc_token atoken; struct ktc_token btoken; struct afsconf_cell ak_cellconfig; /* General information about the cell */ char RealmName[128]; char CellName[128]; char ServiceName[128]; DWORD CurrentState; char HostName[64]; BOOL try_krb5 = 0; krb5_context ctx = 0; krb5_ccache cc = 0; krb5_creds increds; krb5_creds * k5creds = 0; krb5_error_code code; krb5_principal client_principal = 0; int i, retry = 0; CurrentState = 0; memset(HostName, '\0', sizeof(HostName)); gethostname(HostName, sizeof(HostName)); if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) { if ( IsDebuggerPresent() ) OutputDebugString("Unable to retrieve AFSD Service Status\n"); return(-1); } if (CurrentState != SERVICE_RUNNING) { if ( IsDebuggerPresent() ) OutputDebugString("AFSD Service NOT RUNNING\n"); return(-2); } if (!pkrb5_init_context) return 0; memset(RealmName, '\0', sizeof(RealmName)); memset(CellName, '\0', sizeof(CellName)); memset(ServiceName, '\0', sizeof(ServiceName)); memset(realm_of_user, '\0', sizeof(realm_of_user)); memset(realm_of_cell, '\0', sizeof(realm_of_cell)); if (cell && cell[0]) strcpy(Dmycell, cell); else memset(Dmycell, '\0', sizeof(Dmycell)); // NULL or empty cell returns information on local cell if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell)) { // KFW_AFS_error(rc, "get_cellconfig()"); return(rc); } if ( alt_ctx ) { ctx = alt_ctx; } else { code = pkrb5_init_context(&ctx); if (code) goto cleanup; } if ( alt_cc ) { cc = alt_cc; } else { code = pkrb5_cc_default(ctx, &cc); if (code) goto skip_krb5_init; } memset((char *)&increds, 0, sizeof(increds)); code = pkrb5_cc_get_principal(ctx, cc, &client_principal); if (code) { if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) { OutputDebugString("Principal Not Found for ccache\n"); } goto skip_krb5_init; } if ( strchr(krb5_princ_component(ctx,client_principal,0),'.') != NULL ) { OutputDebugString("Illegal Principal name contains dot in first component\n"); rc = KRB5KRB_ERR_GENERIC; goto cleanup; } i = krb5_princ_realm(ctx, client_principal)->length; if (i > REALM_SZ-1) i = REALM_SZ-1; strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i); realm_of_user[i] = 0; try_krb5 = 1; skip_krb5_init: #ifdef USE_KRB4 if ( !try_krb5 || !realm_of_user[0] ) { if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS) { goto cleanup; } } #else goto cleanup; #endif strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig)); if (strlen(service) == 0) strcpy(ServiceName, "afs"); else strcpy(ServiceName, service); if (strlen(cell) == 0) strcpy(CellName, local_cell); else strcpy(CellName, cell); if (strlen(realm) == 0) strcpy(RealmName, realm_of_cell); else strcpy(RealmName, realm); memset(&creds, '\0', sizeof(creds)); if ( try_krb5 ) { int len; /* First try service/cell@REALM */ if (code = pkrb5_build_principal(ctx, &increds.server, strlen(RealmName), RealmName, ServiceName, CellName, 0)) { goto cleanup; } increds.client = client_principal; increds.times.endtime = 0; /* Ask for DES since that is what V4 understands */ increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, increds.client, &cname); pkrb5_unparse_name(ctx, increds.server, &sname); OutputDebugString("Getting tickets for \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || code == KRB5KRB_ERR_GENERIC /* heimdal */ || code == KRB5KRB_AP_ERR_MSG_TYPE) { /* Or service@REALM */ pkrb5_free_principal(ctx,increds.server); increds.server = 0; code = pkrb5_build_principal(ctx, &increds.server, strlen(RealmName), RealmName, ServiceName, 0); if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, increds.client, &cname); pkrb5_unparse_name(ctx, increds.server, &sname); OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); OutputDebugString("Trying again: getting tickets for \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } if (!code) code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); } if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || code == KRB5KRB_ERR_GENERIC /* heimdal */ || code == KRB5KRB_AP_ERR_MSG_TYPE) && strcmp(RealmName, realm_of_cell)) { /* Or service/cell@REALM_OF_CELL */ strcpy(RealmName, realm_of_cell); pkrb5_free_principal(ctx,increds.server); increds.server = 0; code = pkrb5_build_principal(ctx, &increds.server, strlen(RealmName), RealmName, ServiceName, CellName, 0); if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, increds.client, &cname); pkrb5_unparse_name(ctx, increds.server, &sname); OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); OutputDebugString("Trying again: getting tickets for \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } if (!code) code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || code == KRB5KRB_ERR_GENERIC /* heimdal */ || code == KRB5KRB_AP_ERR_MSG_TYPE) { /* Or service@REALM_OF_CELL */ pkrb5_free_principal(ctx,increds.server); increds.server = 0; code = pkrb5_build_principal(ctx, &increds.server, strlen(RealmName), RealmName, ServiceName, 0); if ( IsDebuggerPresent() ) { char * cname, *sname; pkrb5_unparse_name(ctx, increds.client, &cname); pkrb5_unparse_name(ctx, increds.server, &sname); OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); OutputDebugString("Trying again: getting tickets for \""); OutputDebugString(cname); OutputDebugString("\" and service \""); OutputDebugString(sname); OutputDebugString("\"\n"); pkrb5_free_unparsed_name(ctx,cname); pkrb5_free_unparsed_name(ctx,sname); } if (!code) code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); } } if (code) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"krb5_get_credentials returns: %d\n",code); OutputDebugString(message); } try_krb5 = 0; goto use_krb4; } /* This code inserts the entire K5 ticket into the token * No need to perform a krb524 translation which is * commented out in the code below */ if (KFW_use_krb524() || k5creds->ticket.length > MAXKTCTICKETLEN) goto try_krb524d; memset(&aserver, '\0', sizeof(aserver)); strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); memset(&atoken, '\0', sizeof(atoken)); atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5; atoken.startTime = k5creds->times.starttime; atoken.endTime = k5creds->times.endtime; memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length); atoken.ticketLen = k5creds->ticket.length; memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen); retry_gettoken5: rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { if ( rc == KTC_NOCM && retry < 20 ) { Sleep(500); retry++; goto retry_gettoken5; } goto try_krb524d; } if (atoken.kvno == btoken.kvno && atoken.ticketLen == btoken.ticketLen && !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) { /* Success - Nothing to do */ goto cleanup; } // * Reset the "aclient" structure before we call ktc_SetToken. // * This structure was first set by the ktc_GetToken call when // * we were comparing whether identical tokens already existed. len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1); strncpy(aclient.name, k5creds->client->data[0].data, len); aclient.name[len] = '\0'; if ( k5creds->client->length > 1 ) { char * p; strcat(aclient.name, "."); p = aclient.name + strlen(aclient.name); len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1); strncpy(p, k5creds->client->data[1].data, len); p[len] = '\0'; } aclient.instance[0] = '\0'; strcpy(aclient.cell, realm_of_cell); len = min(k5creds->client->realm.length,strlen(realm_of_cell)); if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) { char * p; strcat(aclient.name, "@"); p = aclient.name + strlen(aclient.name); len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1); strncpy(p, k5creds->client->realm.data, len); p[len] = '\0'; } ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, &aclient, &aserver, &atoken); if ( smbname ) { strncpy(aclient.smbname, smbname, sizeof(aclient.smbname)); aclient.smbname[sizeof(aclient.smbname)-1] = '\0'; } else { aclient.smbname[0] = '\0'; } rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)); if (!rc) goto cleanup; /* We have successfully inserted the token */ try_krb524d: /* Otherwise, the ticket could have been too large so try to * convert using the krb524d running with the KDC */ code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds); pkrb5_free_creds(ctx, k5creds); if (code) { if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code); OutputDebugString(message); } try_krb5 = 0; goto use_krb4; } } else { use_krb4: #ifdef USE_KRB4 code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds); if (code == NO_TKT_FIL) { // if the problem is that we have no krb4 tickets // do not attempt to continue goto cleanup; } if (code != KSUCCESS) code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds); if (code != KSUCCESS) { if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS) { if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS) { goto cleanup; } } else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS) { if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS) { goto cleanup; } } else { goto cleanup; } } #else goto cleanup; #endif } memset(&aserver, '\0', sizeof(aserver)); strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); memset(&atoken, '\0', sizeof(atoken)); atoken.kvno = creds.kvno; atoken.startTime = creds.issue_date; atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime); memcpy(&atoken.sessionKey, creds.session, 8); atoken.ticketLen = creds.ticket_st.length; memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen); retry_gettoken: rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { if ( rc == KTC_NOCM && retry < 20 ) { Sleep(500); retry++; goto retry_gettoken; } KFW_AFS_error(rc, "ktc_GetToken()"); code = rc; goto cleanup; } if (atoken.kvno == btoken.kvno && atoken.ticketLen == btoken.ticketLen && !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) { goto cleanup; } // * Reset the "aclient" structure before we call ktc_SetToken. // * This structure was first set by the ktc_GetToken call when // * we were comparing whether identical tokens already existed. strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1); if (creds.pinst[0]) { strncat(aclient.name, ".", MAXKTCNAMELEN - 1); strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1); } strcpy(aclient.instance, ""); if ( strcmp(realm_of_cell, creds.realm) ) { strncat(aclient.name, "@", MAXKTCNAMELEN - 1); strncpy(aclient.name, creds.realm, MAXKTCREALMLEN - 1); } aclient.name[MAXKTCREALMLEN-1] = '\0'; strcpy(aclient.cell, CellName); ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, &aclient, &aserver, &atoken); if ( smbname ) { strncpy(aclient.smbname, smbname, sizeof(aclient.smbname)); aclient.smbname[sizeof(aclient.smbname)-1] = '\0'; } else { aclient.smbname[0] = '\0'; } if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0))) { KFW_AFS_error(rc, "ktc_SetToken()"); code = rc; goto cleanup; } cleanup: if (client_principal) pkrb5_free_principal(ctx,client_principal); /* increds.client == client_principal */ if (increds.server) pkrb5_free_principal(ctx,increds.server); if (cc && (cc != alt_cc)) pkrb5_cc_close(ctx, cc); if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); return(rc? rc : code); } /**************************************/ /* afs_realm_of_cell(): */ /**************************************/ static char * afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig) { static char krbrlm[REALM_SZ+1]=""; char ** realmlist=NULL; krb5_error_code r; if (!cellconfig) return 0; r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist); if ( !r && realmlist && realmlist[0] ) { strcpy(krbrlm, realmlist[0]); pkrb5_free_host_realm(ctx, realmlist); } if ( !krbrlm[0] ) { char *s = krbrlm; char *t = cellconfig->name; int c; while (c = *t++) { if (islower(c)) c=toupper(c); *s++ = c; } *s++ = 0; } return(krbrlm); } /**************************************/ /* KFW_AFS_get_cellconfig(): */ /**************************************/ int KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell) { int rc; char newcell[MAXCELLCHARS+1]; local_cell[0] = (char)0; memset(cellconfig, 0, sizeof(*cellconfig)); /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */ if (rc = cm_GetRootCellName(local_cell)) { return(rc); } if (strlen(cell) == 0) strcpy(cell, local_cell); /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */ strcpy(cellconfig->name, cell); rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig); #ifdef AFS_AFSDB_ENV if (rc != 0) { int ttl; rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig); } #endif return rc; } /**************************************/ /* get_cellconfig_callback(): */ /**************************************/ static long get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep) { struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig; cc->hostAddr[cc->numServers] = *addrp; strcpy(cc->hostName[cc->numServers], namep); cc->numServers++; return(0); } /**************************************/ /* KFW_AFS_error(): */ /**************************************/ void KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName) { char message[256]; const char *errText; // Using AFS defines as error messages for now, until Transarc // gets back to me with "string" translations of each of these // const. defines. if (rc == KTC_ERROR) errText = "KTC_ERROR"; else if (rc == KTC_TOOBIG) errText = "KTC_TOOBIG"; else if (rc == KTC_INVAL) errText = "KTC_INVAL"; else if (rc == KTC_NOENT) errText = "KTC_NOENT"; else if (rc == KTC_PIOCTLFAIL) errText = "KTC_PIOCTLFAIL"; else if (rc == KTC_NOPIOCTL) errText = "KTC_NOPIOCTL"; else if (rc == KTC_NOCELL) errText = "KTC_NOCELL"; else if (rc == KTC_NOCM) errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!"; else errText = "Unknown error!"; sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName); if ( IsDebuggerPresent() ) { OutputDebugString(message); OutputDebugString("\n"); } MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); return; } static DWORD GetServiceStatus( LPSTR lpszMachineName, LPSTR lpszServiceName, DWORD *lpdwCurrentState) { DWORD hr = NOERROR; SC_HANDLE schSCManager = NULL; SC_HANDLE schService = NULL; DWORD fdwDesiredAccess = 0; SERVICE_STATUS ssServiceStatus = {0}; BOOL fRet = FALSE; *lpdwCurrentState = 0; fdwDesiredAccess = GENERIC_READ; schSCManager = OpenSCManager(lpszMachineName, NULL, fdwDesiredAccess); if(schSCManager == NULL) { hr = GetLastError(); goto cleanup; } schService = OpenService(schSCManager, lpszServiceName, fdwDesiredAccess); if(schService == NULL) { hr = GetLastError(); goto cleanup; } fRet = QueryServiceStatus(schService, &ssServiceStatus); if(fRet == FALSE) { hr = GetLastError(); goto cleanup; } *lpdwCurrentState = ssServiceStatus.dwCurrentState; cleanup: CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return(hr); } void UnloadFuncs( FUNC_INFO fi[], HINSTANCE h ) { int n; if (fi) for (n = 0; fi[n].func_ptr_var; n++) *(fi[n].func_ptr_var) = 0; if (h) FreeLibrary(h); } int LoadFuncs( const char* dll_name, FUNC_INFO fi[], HINSTANCE* ph, // [out, optional] - DLL handle int* pindex, // [out, optional] - index of last func loaded (-1 if none) int cleanup, // cleanup function pointers and unload on error int go_on, // continue loading even if some functions cannot be loaded int silent // do not pop-up a system dialog if DLL cannot be loaded ) { HINSTANCE h; int i, n, last_i; int error = 0; UINT em; if (ph) *ph = 0; if (pindex) *pindex = -1; for (n = 0; fi[n].func_ptr_var; n++) *(fi[n].func_ptr_var) = 0; if (silent) em = SetErrorMode(SEM_FAILCRITICALERRORS); h = LoadLibrary(dll_name); if (silent) SetErrorMode(em); if (!h) return 0; last_i = -1; for (i = 0; (go_on || !error) && (i < n); i++) { void* p = (void*)GetProcAddress(h, fi[i].func_name); if (!p) error = 1; else { last_i = i; *(fi[i].func_ptr_var) = p; } } if (pindex) *pindex = last_i; if (error && cleanup && !go_on) { for (i = 0; i < n; i++) { *(fi[i].func_ptr_var) = 0; } FreeLibrary(h); return 0; } if (ph) *ph = h; if (error) return 0; return 1; } BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig) { krb5_context ctx = 0; krb5_ccache cc = 0; krb5_error_code code; krb5_data pwdata; const char * realm = 0; krb5_principal principal = 0; char * pname = 0; char password[PROBE_PASSWORD_LEN+1]; BOOL serverReachable = 0; if (!pkrb5_init_context) return 0; code = pkrb5_init_context(&ctx); if (code) goto cleanup; realm = afs_realm_of_cell(ctx, cellconfig); // do not free code = pkrb5_build_principal(ctx, &principal, strlen(realm), realm, PROBE_USERNAME, NULL, NULL); if ( code ) goto cleanup; code = KFW_get_ccache(ctx, principal, &cc); if ( code ) goto cleanup; code = pkrb5_unparse_name(ctx, principal, &pname); if ( code ) goto cleanup; pwdata.data = password; pwdata.length = PROBE_PASSWORD_LEN; code = pkrb5_c_random_make_octets(ctx, &pwdata); if (code) { int i; for ( i=0 ; i