From 5c27b523150384dd8655e739d68f01be2e4ff5d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 2 Nov 2005 01:14:30 +0000 Subject: Initial Commit Network Identity Manager for Windows Initial commit of Network Identity Manager for KFW 3.0 Beta 1 ticket: new tags: pullup component: windows git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17476 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/identity/plugins/common/Makefile | 42 + src/windows/identity/plugins/common/dynimport.c | 420 ++++ src/windows/identity/plugins/common/dynimport.h | 338 +++ src/windows/identity/plugins/common/krb5common.c | 156 ++ src/windows/identity/plugins/common/krb5common.h | 43 + src/windows/identity/plugins/krb4/Makefile | 78 + src/windows/identity/plugins/krb4/datarep.h | 37 + src/windows/identity/plugins/krb4/errorfuncs.c | 264 +++ src/windows/identity/plugins/krb4/errorfuncs.h | 80 + src/windows/identity/plugins/krb4/krb4configdlg.c | 88 + src/windows/identity/plugins/krb4/krb4funcs.c | 505 +++++ src/windows/identity/plugins/krb4/krb4funcs.h | 190 ++ src/windows/identity/plugins/krb4/krb4plugin.c | 164 ++ src/windows/identity/plugins/krb4/krbconfig.csv | 23 + src/windows/identity/plugins/krb4/krbcred.h | 114 + .../identity/plugins/krb4/lang/en_us/langres.rc | 141 ++ src/windows/identity/plugins/krb4/langres.h | 78 + src/windows/identity/plugins/krb4/main.c | 191 ++ src/windows/identity/plugins/krb5/Makefile | 91 + src/windows/identity/plugins/krb5/datarep.c | 269 +++ src/windows/identity/plugins/krb5/datarep.h | 37 + src/windows/identity/plugins/krb5/errorfuncs.c | 260 +++ src/windows/identity/plugins/krb5/errorfuncs.h | 75 + src/windows/identity/plugins/krb5/krb5configdlg.c | 421 ++++ src/windows/identity/plugins/krb5/krb5funcs.c | 1889 +++++++++++++++++ src/windows/identity/plugins/krb5/krb5funcs.h | 121 ++ src/windows/identity/plugins/krb5/krb5identpro.c | 1108 ++++++++++ src/windows/identity/plugins/krb5/krb5newcreds.c | 2167 ++++++++++++++++++++ src/windows/identity/plugins/krb5/krb5plugin.c | 230 +++ src/windows/identity/plugins/krb5/krb5props.c | 117 ++ src/windows/identity/plugins/krb5/krb5util.c | 1362 ++++++++++++ src/windows/identity/plugins/krb5/krbconfig.csv | 34 + src/windows/identity/plugins/krb5/krbcred.h | 182 ++ .../identity/plugins/krb5/lang/en_us/langres.rc | 406 ++++ .../identity/plugins/krb5/lang/krb5_msgs.mc | 151 ++ src/windows/identity/plugins/krb5/langres.h | 127 ++ src/windows/identity/plugins/krb5/main.c | 387 ++++ 37 files changed, 12386 insertions(+) create mode 100644 src/windows/identity/plugins/common/Makefile create mode 100644 src/windows/identity/plugins/common/dynimport.c create mode 100644 src/windows/identity/plugins/common/dynimport.h create mode 100644 src/windows/identity/plugins/common/krb5common.c create mode 100644 src/windows/identity/plugins/common/krb5common.h create mode 100644 src/windows/identity/plugins/krb4/Makefile create mode 100644 src/windows/identity/plugins/krb4/datarep.h create mode 100644 src/windows/identity/plugins/krb4/errorfuncs.c create mode 100644 src/windows/identity/plugins/krb4/errorfuncs.h create mode 100644 src/windows/identity/plugins/krb4/krb4configdlg.c create mode 100644 src/windows/identity/plugins/krb4/krb4funcs.c create mode 100644 src/windows/identity/plugins/krb4/krb4funcs.h create mode 100644 src/windows/identity/plugins/krb4/krb4plugin.c create mode 100644 src/windows/identity/plugins/krb4/krbconfig.csv create mode 100644 src/windows/identity/plugins/krb4/krbcred.h create mode 100644 src/windows/identity/plugins/krb4/lang/en_us/langres.rc create mode 100644 src/windows/identity/plugins/krb4/langres.h create mode 100644 src/windows/identity/plugins/krb4/main.c create mode 100644 src/windows/identity/plugins/krb5/Makefile create mode 100644 src/windows/identity/plugins/krb5/datarep.c create mode 100644 src/windows/identity/plugins/krb5/datarep.h create mode 100644 src/windows/identity/plugins/krb5/errorfuncs.c create mode 100644 src/windows/identity/plugins/krb5/errorfuncs.h create mode 100644 src/windows/identity/plugins/krb5/krb5configdlg.c create mode 100644 src/windows/identity/plugins/krb5/krb5funcs.c create mode 100644 src/windows/identity/plugins/krb5/krb5funcs.h create mode 100644 src/windows/identity/plugins/krb5/krb5identpro.c create mode 100644 src/windows/identity/plugins/krb5/krb5newcreds.c create mode 100644 src/windows/identity/plugins/krb5/krb5plugin.c create mode 100644 src/windows/identity/plugins/krb5/krb5props.c create mode 100644 src/windows/identity/plugins/krb5/krb5util.c create mode 100644 src/windows/identity/plugins/krb5/krbconfig.csv create mode 100644 src/windows/identity/plugins/krb5/krbcred.h create mode 100644 src/windows/identity/plugins/krb5/lang/en_us/langres.rc create mode 100644 src/windows/identity/plugins/krb5/lang/krb5_msgs.mc create mode 100644 src/windows/identity/plugins/krb5/langres.h create mode 100644 src/windows/identity/plugins/krb5/main.c (limited to 'src/windows/identity/plugins') diff --git a/src/windows/identity/plugins/common/Makefile b/src/windows/identity/plugins/common/Makefile new file mode 100644 index 0000000..cbadbc6 --- /dev/null +++ b/src/windows/identity/plugins/common/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\common +!include <../../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\krb5common.h \ + $(INCDIR)\dynimport.h + +OBJFILES= \ + $(LIBDIR)\krb5common.obj \ + $(LIBDIR)\dynimport.obj + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) + +{}.c{$(LIBDIR)}.obj: + $(C2OBJ) diff --git a/src/windows/identity/plugins/common/dynimport.c b/src/windows/identity/plugins/common/dynimport.c new file mode 100644 index 0000000..cd33813 --- /dev/null +++ b/src/windows/identity/plugins/common/dynimport.c @@ -0,0 +1,420 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include +#include +#include +#include + +HINSTANCE hKrb4 = 0; +HINSTANCE hKrb5 = 0; +HINSTANCE hKrb524 = 0; +HINSTANCE hSecur32 = 0; +HINSTANCE hComErr = 0; +HINSTANCE hService = 0; +HINSTANCE hProfile = 0; +HINSTANCE hPsapi = 0; +HINSTANCE hToolHelp32 = 0; +HINSTANCE hCCAPI = 0; + +DWORD AfsAvailable = 0; + +// 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); + +// krb4 functions +DECL_FUNC_PTR(get_krb_err_txt_entry); +DECL_FUNC_PTR(k_isinst); +DECL_FUNC_PTR(k_isname); +DECL_FUNC_PTR(k_isrealm); +DECL_FUNC_PTR(kadm_change_your_password); +DECL_FUNC_PTR(kname_parse); +DECL_FUNC_PTR(krb_get_cred); +DECL_FUNC_PTR(krb_get_krbhst); +DECL_FUNC_PTR(krb_get_lrealm); +DECL_FUNC_PTR(krb_get_pw_in_tkt); +DECL_FUNC_PTR(krb_get_tf_realm); +DECL_FUNC_PTR(krb_mk_req); +DECL_FUNC_PTR(krb_realmofhost); +DECL_FUNC_PTR(tf_init); +DECL_FUNC_PTR(tf_close); +DECL_FUNC_PTR(tf_get_cred); +DECL_FUNC_PTR(tf_get_pname); +DECL_FUNC_PTR(tf_get_pinst); +DECL_FUNC_PTR(LocalHostAddr); +DECL_FUNC_PTR(tkt_string); +DECL_FUNC_PTR(krb_set_tkt_string); +DECL_FUNC_PTR(initialize_krb_error_func); +DECL_FUNC_PTR(initialize_kadm_error_table); +DECL_FUNC_PTR(dest_tkt); +DECL_FUNC_PTR(krb_in_tkt); +DECL_FUNC_PTR(krb_save_credentials); +DECL_FUNC_PTR(krb_get_krbconf2); +DECL_FUNC_PTR(krb_get_krbrealm2); +DECL_FUNC_PTR(krb_life_to_time); + +// 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_get_prompt_types); +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_get_realm_domain); +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_c_random_make_octets); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +DECL_FUNC_PTR(krb524_init_ets); +DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// 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); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// 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 k4_fi[] = { + MAKE_FUNC_INFO(get_krb_err_txt_entry), + MAKE_FUNC_INFO(k_isinst), + MAKE_FUNC_INFO(k_isname), + MAKE_FUNC_INFO(k_isrealm), + MAKE_FUNC_INFO(kadm_change_your_password), + MAKE_FUNC_INFO(kname_parse), + MAKE_FUNC_INFO(krb_get_cred), + MAKE_FUNC_INFO(krb_get_krbhst), + MAKE_FUNC_INFO(krb_get_lrealm), + MAKE_FUNC_INFO(krb_get_pw_in_tkt), + MAKE_FUNC_INFO(krb_get_tf_realm), + MAKE_FUNC_INFO(krb_mk_req), + MAKE_FUNC_INFO(krb_realmofhost), + MAKE_FUNC_INFO(tf_init), + MAKE_FUNC_INFO(tf_close), + MAKE_FUNC_INFO(tf_get_cred), + MAKE_FUNC_INFO(tf_get_pname), + MAKE_FUNC_INFO(tf_get_pinst), + MAKE_FUNC_INFO(LocalHostAddr), + MAKE_FUNC_INFO(tkt_string), + MAKE_FUNC_INFO(krb_set_tkt_string), + MAKE_FUNC_INFO(initialize_krb_error_func), + MAKE_FUNC_INFO(initialize_kadm_error_table), + MAKE_FUNC_INFO(dest_tkt), + /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX + MAKE_FUNC_INFO(krb_in_tkt), + MAKE_FUNC_INFO(krb_save_credentials), + MAKE_FUNC_INFO(krb_get_krbconf2), + MAKE_FUNC_INFO(krb_get_krbrealm2), + MAKE_FUNC_INFO(krb_life_to_time), + 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_get_prompt_types), + 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_get_realm_domain), + 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_c_random_make_octets), + MAKE_FUNC_INFO(krb5_free_default_realm), + 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), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +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 +}; + +// psapi functions +DECL_FUNC_PTR(GetModuleFileNameExA); +DECL_FUNC_PTR(EnumProcessModules); + +FUNC_INFO psapi_fi[] = { + MAKE_FUNC_INFO(GetModuleFileNameExA), + MAKE_FUNC_INFO(EnumProcessModules), + END_FUNC_INFO +}; + +// toolhelp functions +DECL_FUNC_PTR(CreateToolhelp32Snapshot); +DECL_FUNC_PTR(Module32First); +DECL_FUNC_PTR(Module32Next); + +FUNC_INFO toolhelp_fi[] = { + MAKE_FUNC_INFO(CreateToolhelp32Snapshot), + MAKE_FUNC_INFO(Module32First), + MAKE_FUNC_INFO(Module32Next), + END_FUNC_INFO +}; + +khm_int32 init_imports(void) { + OSVERSIONINFO osvi; + + LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // XXX: We should really use feature testing, first + // checking for CreateToolhelp32Snapshot. If that's + // not around, we try the psapi stuff. + // + // Only load LSA functions if on NT/2000/XP + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + // Windows 9x + LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + hPsapi = 0; + } + else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + // Windows NT + LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + hToolHelp32 = 0; + } + + AfsAvailable = TRUE; //afscompat_init(); + + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_imports(void) { + //afscompat_close(); + + if (hKrb4) + FreeLibrary(hKrb4); + if (hKrb5) + FreeLibrary(hKrb5); + if (hProfile) + FreeLibrary(hProfile); + if (hComErr) + FreeLibrary(hComErr); + if (hService) + FreeLibrary(hService); + if (hSecur32) + FreeLibrary(hSecur32); + if (hKrb524) + FreeLibrary(hKrb524); + if (hPsapi) + FreeLibrary(hPsapi); + if (hToolHelp32) + FreeLibrary(hToolHelp32); + + return KHM_ERROR_SUCCESS; +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + +void Leash_load_com_err_callback(FARPROC ce, + FARPROC em, + FARPROC etn) +{ + (FARPROC)Lcom_err=ce; + (FARPROC)Lerror_message=em; + (FARPROC)Lerror_table_name=etn; +} diff --git a/src/windows/identity/plugins/common/dynimport.h b/src/windows/identity/plugins/common/dynimport.h new file mode 100644 index 0000000..b3ba225 --- /dev/null +++ b/src/windows/identity/plugins/common/dynimport.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_DYNIMPORT_H +#define __KHIMAIRA_DYNIMPORT_H + +/* Dynamic imports */ +#include +#include +#include + +extern HINSTANCE hKrb4; +extern HINSTANCE hKrb5; +extern HINSTANCE hProfile; + +/////////////////////////////////////////////////////////////////////////////// + +#define CCAPI_DLL "krbcc32.dll" +#define KRBCC32_DLL "krbcc32.dll" +#define SERVICE_DLL "advapi32.dll" +#define SECUR32_DLL "secur32.dll" +#define PROFILE_DLL "xpprof32.dll" + +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +//// CCAPI +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +//// \CCAPI + +extern DWORD AfsAvailable; + +// service definitions +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +////////////////////////////////////////////////////////////////////////////// + +// CCAPI +extern DECL_FUNC_PTR(cc_initialize); +extern DECL_FUNC_PTR(cc_shutdown); +extern DECL_FUNC_PTR(cc_get_NC_info); +extern DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +extern DECL_FUNC_PTR(get_krb_err_txt_entry); +extern DECL_FUNC_PTR(k_isinst); +extern DECL_FUNC_PTR(k_isname); +extern DECL_FUNC_PTR(k_isrealm); +extern DECL_FUNC_PTR(kadm_change_your_password); +extern DECL_FUNC_PTR(kname_parse); +extern DECL_FUNC_PTR(krb_get_cred); +extern DECL_FUNC_PTR(krb_get_krbhst); +extern DECL_FUNC_PTR(krb_get_lrealm); +extern DECL_FUNC_PTR(krb_get_pw_in_tkt); +extern DECL_FUNC_PTR(krb_get_tf_realm); +extern DECL_FUNC_PTR(krb_mk_req); +extern DECL_FUNC_PTR(krb_realmofhost); +extern DECL_FUNC_PTR(tf_init); +extern DECL_FUNC_PTR(tf_close); +extern DECL_FUNC_PTR(tf_get_cred); +extern DECL_FUNC_PTR(tf_get_pname); +extern DECL_FUNC_PTR(tf_get_pinst); +extern DECL_FUNC_PTR(LocalHostAddr); +extern DECL_FUNC_PTR(tkt_string); +extern DECL_FUNC_PTR(krb_set_tkt_string); +extern DECL_FUNC_PTR(initialize_krb_error_func); +extern DECL_FUNC_PTR(initialize_kadm_error_table); +extern DECL_FUNC_PTR(dest_tkt); +extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX +extern DECL_FUNC_PTR(krb_in_tkt); +extern DECL_FUNC_PTR(krb_save_credentials); +extern DECL_FUNC_PTR(krb_get_krbconf2); +extern DECL_FUNC_PTR(krb_get_krbrealm2); +extern DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +extern DECL_FUNC_PTR(krb5_change_password); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +extern DECL_FUNC_PTR(krb5_get_init_creds_password); +extern DECL_FUNC_PTR(krb5_get_prompt_types); +extern DECL_FUNC_PTR(krb5_build_principal_ext); +extern DECL_FUNC_PTR(krb5_cc_get_name); +extern DECL_FUNC_PTR(krb5_cc_resolve); +extern DECL_FUNC_PTR(krb5_cc_default); +extern DECL_FUNC_PTR(krb5_cc_default_name); +extern DECL_FUNC_PTR(krb5_cc_set_default_name); +extern DECL_FUNC_PTR(krb5_cc_initialize); +extern DECL_FUNC_PTR(krb5_cc_destroy); +extern DECL_FUNC_PTR(krb5_cc_close); +extern DECL_FUNC_PTR(krb5_cc_copy_creds); +extern DECL_FUNC_PTR(krb5_cc_store_cred); +extern DECL_FUNC_PTR(krb5_cc_retrieve_cred); +extern DECL_FUNC_PTR(krb5_cc_get_principal); +extern DECL_FUNC_PTR(krb5_cc_start_seq_get); +extern DECL_FUNC_PTR(krb5_cc_next_cred); +extern DECL_FUNC_PTR(krb5_cc_end_seq_get); +extern DECL_FUNC_PTR(krb5_cc_remove_cred); +extern DECL_FUNC_PTR(krb5_cc_set_flags); +// extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_free_context); +extern DECL_FUNC_PTR(krb5_free_cred_contents); +extern DECL_FUNC_PTR(krb5_free_principal); +extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +extern DECL_FUNC_PTR(krb5_init_context); +extern DECL_FUNC_PTR(krb5_parse_name); +extern DECL_FUNC_PTR(krb5_timeofday); +extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +extern DECL_FUNC_PTR(krb5_unparse_name); +extern DECL_FUNC_PTR(krb5_get_credentials); +extern DECL_FUNC_PTR(krb5_mk_req); +extern DECL_FUNC_PTR(krb5_sname_to_principal); +extern DECL_FUNC_PTR(krb5_get_credentials_renew); +extern DECL_FUNC_PTR(krb5_free_data); +extern DECL_FUNC_PTR(krb5_free_data_contents); +// extern DECL_FUNC_PTR(krb5_get_realm_domain); +extern DECL_FUNC_PTR(krb5_free_unparsed_name); +extern DECL_FUNC_PTR(krb5_os_localaddr); +extern DECL_FUNC_PTR(krb5_copy_keyblock_contents); +extern DECL_FUNC_PTR(krb5_copy_data); +extern DECL_FUNC_PTR(krb5_free_creds); +extern DECL_FUNC_PTR(krb5_build_principal); +extern DECL_FUNC_PTR(krb5_get_renewed_creds); +extern DECL_FUNC_PTR(krb5_free_addresses); +extern DECL_FUNC_PTR(krb5_get_default_config_files); +extern DECL_FUNC_PTR(krb5_free_config_files); +extern DECL_FUNC_PTR(krb5_get_default_realm); +extern DECL_FUNC_PTR(krb5_free_ticket); +extern DECL_FUNC_PTR(krb5_decode_ticket); +extern DECL_FUNC_PTR(krb5_get_host_realm); +extern DECL_FUNC_PTR(krb5_free_host_realm); +extern DECL_FUNC_PTR(krb5_c_random_make_octets); +extern DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +extern DECL_FUNC_PTR(krb524_init_ets); +extern DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +extern DECL_FUNC_PTR(com_err); +extern DECL_FUNC_PTR(error_message); + +// Profile functions +extern DECL_FUNC_PTR(profile_init); +extern DECL_FUNC_PTR(profile_release); +extern DECL_FUNC_PTR(profile_get_subsection_names); +extern DECL_FUNC_PTR(profile_free_list); +extern DECL_FUNC_PTR(profile_get_string); +extern DECL_FUNC_PTR(profile_release_string); + +// Service functions +extern DECL_FUNC_PTR(OpenSCManagerA); +extern DECL_FUNC_PTR(OpenServiceA); +extern DECL_FUNC_PTR(QueryServiceStatus); +extern DECL_FUNC_PTR(CloseServiceHandle); +extern DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +extern DECL_FUNC_PTR(LsaConnectUntrusted); +extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +extern DECL_FUNC_PTR(LsaCallAuthenticationPackage); +extern DECL_FUNC_PTR(LsaFreeReturnBuffer); +extern DECL_FUNC_PTR(LsaGetLogonSessionData); + +// toolhelp functions +TYPEDEF_FUNC( + HANDLE, + WINAPI, + CreateToolhelp32Snapshot, + (DWORD, DWORD) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32First, + (HANDLE, LPMODULEENTRY32) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32Next, + (HANDLE, LPMODULEENTRY32) + ); + +// psapi functions +TYPEDEF_FUNC( + DWORD, + WINAPI, + GetModuleFileNameExA, + (HANDLE, HMODULE, LPSTR, DWORD) + ); + +TYPEDEF_FUNC( + BOOL, + WINAPI, + EnumProcessModules, + (HANDLE, HMODULE*, DWORD, LPDWORD) + ); + +#define pGetModuleFileNameEx pGetModuleFileNameExA +#define TOOLHELPDLL "kernel32.dll" +#define PSAPIDLL "psapi.dll" + +// psapi functions +extern DECL_FUNC_PTR(GetModuleFileNameExA); +extern DECL_FUNC_PTR(EnumProcessModules); + +// toolhelp functions +extern DECL_FUNC_PTR(CreateToolhelp32Snapshot); +extern DECL_FUNC_PTR(Module32First); +extern DECL_FUNC_PTR(Module32Next); + +khm_int32 init_imports(void); +khm_int32 exit_imports(void); + +#endif diff --git a/src/windows/identity/plugins/common/krb5common.c b/src/windows/identity/plugins/common/krb5common.c new file mode 100644 index 0000000..5501a12 --- /dev/null +++ b/src/windows/identity/plugins/common/krb5common.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +/**************************************/ +/* khm_krb5_error(): */ +/**************************************/ +int +khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context * ctx, + krb5_ccache * cache) +{ +#ifdef NO_KRB5 + return 0; +#else + +#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY + char message[256]; + const char *errText; + int krb5Error = ((int)(rc & 255)); + + errText = perror_message(rc); + _snprintf(message, sizeof(message), + "%s\n(Kerberos error %ld)\n\n%s failed", + errText, + krb5Error, + FailedFunctionName); + + MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | + MB_TASKMODAL | + MB_SETFOREGROUND); +#endif + + if (FreeContextFlag == 1) + { + if (*ctx != NULL) + { + if (*cache != NULL) { + pkrb5_cc_close(*ctx, *cache); + *cache = NULL; + } + + pkrb5_free_context(*ctx); + *ctx = NULL; + } + } + + return rc; + +#endif //!NO_KRB5 +} + +int +khm_krb5_initialize(khm_handle ident, + krb5_context *ctx, + krb5_ccache *cache) +{ +#ifdef NO_KRB5 + return(0); +#else + + LPCSTR functionName; + int freeContextFlag; + krb5_error_code rc; + krb5_flags flags = 0; + + if (pkrb5_init_context == NULL) + return 1; + + if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) + { + functionName = "krb5_init_context()"; + freeContextFlag = 0; + goto on_error; + } + + if(*cache == 0) { + wchar_t wccname[256]; + khm_size cbwccname; + + if(ident != NULL) { + cbwccname = sizeof(wccname); + do { + char ccname[256]; + + if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", NULL, wccname, &cbwccname))) + break; + + if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0) + break; + + if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) { + functionName = "krb5_cc_resolve()"; + freeContextFlag = 1; + goto on_error; + } + } while(FALSE); + } + + if (*cache == 0 && (rc = (*pkrb5_cc_default)(*ctx, cache))) + { + functionName = "krb5_cc_default()"; + freeContextFlag = 1; + goto on_error; + } + } + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#endif + + if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags))) + { + if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND) + khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, + cache); + else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) + { + if (*cache != NULL) + (*pkrb5_cc_close)(*ctx, *cache); + } + return rc; + } + return 0; + +on_error: + return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache); +#endif //!NO_KRB5 +} diff --git a/src/windows/identity/plugins/common/krb5common.h b/src/windows/identity/plugins/common/krb5common.h new file mode 100644 index 0000000..7d99821 --- /dev/null +++ b/src/windows/identity/plugins/common/krb5common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5COMMON_H +#define __KHIMAIRA_KRB5COMMON_H + +#include + +#ifndef NO_KRB5 +int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context *ctx, + krb5_ccache *cache); + + +int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *); +#endif /* NO_KRB5 */ + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb4/Makefile b/src/windows/identity/plugins/krb4/Makefile new file mode 100644 index 0000000..d6b7491 --- /dev/null +++ b/src/windows/identity/plugins/krb4/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb4 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb4cred.dll + +LIBFILE=$(LIBDIR)\krb4cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\main.obj \ + $(OBJ)\krb4plugin.obj \ + $(OBJ)\krb4funcs.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb4config.obj \ + $(OBJ)\krb4configdlg.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= + +$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(OBJFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb4cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/src/windows/identity/plugins/krb4/datarep.h b/src/windows/identity/plugins/krb4/datarep.h new file mode 100644 index 0000000..9c7048e --- /dev/null +++ b/src/windows/identity/plugins/krb4/datarep.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRB_DATAREP_H +#define __KHIMAIRA_KRB_DATAREP_H + + +khm_int32 KHMAPI enctype_toString(const void * data, khm_int32 cbdata, wchar_t *destbuf, khm_int32 *pcbdestbuf, khm_int32 flags); +khm_int32 KHMAPI addr_list_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32); +khm_int32 KHMAPI krb5flags_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32); +khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_int32 * pcbsize); + + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb4/errorfuncs.c b/src/windows/identity/plugins/krb4/errorfuncs.c new file mode 100644 index 0000000..9feaad2 --- /dev/null +++ b/src/windows/identity/plugins/krb4/errorfuncs.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + +#if 0 + /*TODO: Do something about this */ + if (plsh_LoadKrb4LeashErrorTables) + plsh_LoadKrb4LeashErrorTables(hLeashInst, 0); +#endif + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +// Global Variables. +static long lsh_errno; +static char *err_context; /* error context */ +extern int (*Lcom_err)(LPSTR,long,LPSTR,...); +extern LPSTR (*Lerror_message)(long); +extern LPSTR (*Lerror_table_name)(long); + +#ifdef WIN16 +#define UNDERSCORE "_" +#else +#define UNDERSCORE +#endif + +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} + + +LPSTR err_describe(LPSTR buf, long code) +{ + LPSTR cp, com_err_msg; + int offset; + long table_num; + char *etype; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = Lerror_message(code); + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + strcpy(buf, com_err_msg); + return buf; + } + + cp = buf; + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + com_err_msg = "Something weird happened... try again, and if Leash" + " continues to fail, contact Network Services as listed in the " + "About box."; + break; + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + com_err_msg = "You have entered an unknown username/instance/realm" + " combination."; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + com_err_msg = "Something is wrong with the memory where your " + "tickets are stored. Try exiting Windows and restarting your " + "computer."; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + case RD_AP_TIME : /* 037 delta_t too big */ + com_err_msg = "Your computer's clock is out of sync with the " + "Kerberos server. Please see the help file about correcting " + "your clock."; + break; + + case RD_AP_UNDEC : /* 031 Can't decode authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + break; + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + com_err_msg = "Cannot contact the kerberos server for the selected realm."; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site specific + * information to be delivered from the Kerberos server. However the + * message box is too small for VGA screens. + * It does work well if we only have to support 1024x768 + */ + + com_err_msg = "You have entered an insecure or weak password."; + + default: + /* no extra error msg */ + break; + } + if(com_err_msg != buf) + strcpy(buf, com_err_msg); + cp = buf + strlen(buf); + *cp++ = '\n'; + switch(table_num) { + case krb_err_base: + etype = "Kerberos"; + break; + case kadm_err_base: + etype = "Kerberos supplemental"; + break; + default: + etype = Lerror_table_name(table_num); + break; + } + wsprintfA((LPSTR) cp, (LPSTR) "(%s error %d" +#ifdef DEBUG_COM_ERR + " (absolute error %ld)" +#endif + ")", etype, offset + //")\nPress F1 for help on this error.", etype, offset +#ifdef DEBUG_COM_ERR + , code +#endif + ); + + return (LPSTR)buf; +} + +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; /* changed to 512 by jms 8/23/93 */ + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} diff --git a/src/windows/identity/plugins/krb4/errorfuncs.h b/src/windows/identity/plugins/krb4/errorfuncs.h new file mode 100644 index 0000000..be8f4e7 --- /dev/null +++ b/src/windows/identity/plugins/krb4/errorfuncs.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +extern void Leash_initialize_krb_error_func(err_func func,struct et_list **); +#undef init_krb_err_func +#define init_krb_err_func(erf) Leash_initialize_krb_error_func(erf,&_et_list) + +#include + +extern void Leash_initialize_kadm_error_table(struct et_list **); +#undef init_kadm_err_tbl +#define init_kadm_err_tbl() Leash_initialize_kadm_error_table(&_et_list) +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#define krb_err_func Leash_krb_err_func + +#include +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args); +void FAR Leash_load_com_err_callback(FARPROC,FARPROC,FARPROC); + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +int lsh_com_err_proc (LPSTR whoami, long code, LPSTR fmt, va_list args); +int DoNiftyErrorReport(long errnum, LPSTR what); + +LPSTR err_describe(LPSTR buf, long code); + + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4configdlg.c b/src/windows/identity/plugins/krb4/krb4configdlg.c new file mode 100644 index 0000000..9ad3406 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4configdlg.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + { + wchar_t wbuf[MAX_PATH]; + CHAR krb_path[MAX_PATH]; + CHAR krbrealm_path[MAX_PATH]; + CHAR ticketName[MAX_PATH]; + char * pticketName; + unsigned int krb_path_sz = sizeof(krb_path); + unsigned int krbrealm_path_sz = sizeof(krbrealm_path); + + // Set KRB.CON + memset(krb_path, '\0', sizeof(krb_path)); + if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) { + // Error has happened + } else { // normal find + AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path); + SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf); + } + + // Set KRBREALM.CON + memset(krbrealm_path, '\0', sizeof(krbrealm_path)); + if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { + // Error has happened + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path); + SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf); + } + + // Set TICKET.KRB file Editbox + *ticketName = 0; + pkrb_set_tkt_string(0); + + pticketName = ptkt_string(); + if (pticketName) + StringCbCopyA(ticketName, sizeof(ticketName), pticketName); + + if (!*ticketName) { + // error + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName); + SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf); + } + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.c b/src/windows/identity/plugins/krb4/krb4funcs.c new file mode 100644 index 0000000..8fda720 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4funcs.c @@ -0,0 +1,505 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + + + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + + +long +khm_krb4_list_tickets(void) +{ + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + wchar_t wbuf[256]; + int k_errno; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft; + + // Since krb_get_tf_realm will return a ticket_file error, + // we will call tf_init and tf_close first to filter out + // things like no ticket file. Otherwise, the error that + // the user would see would be + // klist: can't find realm of ticket file: No ticket file (tf_util) + // instead of klist: No ticket file (tf_util) + if (ptf_init == NULL) + return(KSUCCESS); + + com_addr(); + + // Open ticket file + if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))) + { + goto cleanup; + } + // Close ticket file + (void) (*ptf_close)(); + + // We must find the realm of the ticket file here before calling + // tf_init because since the realm of the ticket file is not + // really stored in the principal section of the file, the + // routine we use must itself call tf_init and tf_close. + + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + + // Open ticket file + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + open = 1; + + // Get principal name and instance + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + // You may think that this is the obvious place to get the + // realm of the ticket file, but it can't be done here as the + // routine to do this must open the ticket file. This is why + // it was done before tf_init. + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident))) + { + goto cleanup; + } + + kcdb_credset_flush(krb4_credset); + + // Get KRB4 tickets + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", + c.service, + (c.instance[0] ? "." : ""), + c.instance, + (c.realm[0] ? "@" : ""), + c.realm); + + if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred))) + continue; + + tt = c.issue_date + c.lifetime * 5L * 60L; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft)); + + tt = c.issue_date; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = c.lifetime * 5L * 60L; + TimetToFileTimeInterval(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft)); + + kcdb_credset_add_cred(krb4_credset, cred, -1); + + } // while + + kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL); + +cleanup: + if (ptf_close == NULL) + return(KSUCCESS); + + if (open) + (*ptf_close)(); //close ticket file + + if (k_errno == EOF) + k_errno = 0; + + // XXX the if statement directly below was inserted to eliminate + // an error NO_TKT_FIL on Leash startup. The error occurs from an + // error number thrown from krb_get_tf_realm. We believe this + // change does not eliminate other errors, but it may. + + if (k_errno == NO_TKT_FIL) + k_errno = 0; + + if(ident) + kcdb_identity_release(ident); + +#if 0 + /*TODO: Handle errors here */ + if (k_errno) + { + CHAR message[256]; + CHAR errBuf[256]; + LPCSTR errText; + + if (!Lerror_message) + return -1; + + errText = err_describe(errBuf, KRBERR(k_errno)); + + sprintf(message, "%s\n\n%s failed", errText, functionName); + MessageBox(NULL, message, "Kerberos Four", + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + } +#endif + return k_errno; +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) + { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) + { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) + { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) + { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) + { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode strings, + each of which denotes one realm. The set is terminated by a zero length + null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = malloc(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = malloc(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The caller + should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = malloc(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.h b/src/windows/identity/plugins/krb4/krb4funcs.h new file mode 100644 index 0000000..ea97358 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4funcs.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +// Function Prototypes. +BOOL khm_krb5_ms2mit(BOOL); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data + ); + +long +Leash_int_kinit_ex( + krb5_context ctx, + HWND hParent, + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicIP, + int displayErrors + ); + +long +Leash_int_checkpwd( + char * principal, + char * password, + int displayErrors + ); + +long +Leash_int_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string, + int displayErrors + ); + +int +Leash_krb5_kdestroy( + void + ); + +int +Leash_krb5_kinit( + krb5_context, + HWND hParent, + char * principal_name, + char * password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP + ); + +long +khm_convert524( + krb5_context ctx + ); + +int +Leash_afs_unlog( + void + ); + +int +Leash_afs_klog( + char *, + char *, + char *, + int + ); + +int +LeashKRB5_renew(void); + +LONG +write_registry_setting( + char* setting, + DWORD type, + void* buffer, + size_t size + ); + +LONG +read_registry_setting_user( + char* setting, + void* buffer, + size_t size + ); + +LONG +read_registry_setting( + char* setting, + void* buffer, + size_t size + ); + +BOOL +get_STRING_from_registry( + HKEY hBaseKey, + char * key, + char * value, + char * outbuf, + DWORD outlen + ); + +BOOL +get_DWORD_from_registry( + HKEY hBaseKey, + char * key, + char * value, + DWORD * result + ); + +int +config_boolean_to_int( + const char *s + ); + + +wchar_t * khm_krb5_get_default_realm(void); +wchar_t * khm_krb5_get_realm_list(void); +long khm_krb5_list_tickets(krb5_context *krbv5Context); +long khm_krb4_list_tickets(void); + + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4plugin.c b/src/windows/identity/plugins/krb4/krb4plugin.c new file mode 100644 index 0000000..106feba --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4plugin.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include + +khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID; +khm_boolean krb4_initialized = FALSE; +khm_handle krb4_credset = NULL; + +/* Kerberos IV stuff */ +khm_int32 KHMAPI +krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + khui_config_node_reg reg; + wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC]; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB4_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = malloc(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB4_LONG_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = malloc(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + kmq_create_subscription(krb4_cb, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb4); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb4_credset); + + if(ct.short_desc) + free(ct.short_desc); + + if(ct.long_desc) + free(ct.long_desc); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4); + reg.dlg_proc = krb4_confg_proc; + reg.flags = 0; + + LoadString(hResModule, IDS_CFG_KRB4_LONG, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(NULL, ®); + + if(KHM_SUCCEEDED(rv)) { + krb4_initialized = TRUE; + + khm_krb4_list_tickets(); + } + } + break; + + case KMSG_SYSTEM_EXIT: + if(credtype_id_krb4 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb4); + + kcdb_credset_delete(krb4_credset); + } + break; + } + + return rv; +} + +khm_int32 KHMAPI +krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + khm_krb4_list_tickets(); + } + break; + } + + return rv; +} + +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return krb4_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb4/krbconfig.csv b/src/windows/identity/plugins/krb4/krbconfig.csv new file mode 100644 index 0000000..bed0d1c --- /dev/null +++ b/src/windows/identity/plugins/krb4/krbconfig.csv @@ -0,0 +1,23 @@ +Name,Type,Value,Description +Krb4Cred,KC_SPACE,0,"Kerberos IV Credentials Provider" + Module,KC_STRING,"MITKrb4", + Description,KC_STRING,"Kerberos IV Credentials Provider", + Dependencies,KC_STRING,Krb5Cred, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + CreateMissingConfig,KC_INT32,0,Create missing configuration files + MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials + AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) + Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) + Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + Renewable,KC_INT32,1,Obtain renewable tickets (boolean) + DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime + MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime + MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime + Parameters,KC_ENDSPACE,0, +Krb4Cred,KC_ENDSPACE,0, diff --git a/src/windows/identity/plugins/krb4/krbcred.h b/src/windows/identity/plugins/krb4/krbcred.h new file mode 100644 index 0000000..e56d114 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krbcred.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include +#include + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_RENEW_TILL L"RenewTill" +#define ATTRNAME_RENEW_FOR L"RenewFor" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_renew_till; +extern khm_int32 attr_id_renew_for; + +/* Configuration spaces */ +#define CSNAME_KRB4CRED L"Krb4Cred" +#define CSNAME_PARAMS L"Parameters" + +/* plugin constants */ +#define KRB4_PLUGIN_NAME L"Krb4Cred" + +#define KRB4_PLUGIN_DEPS L"Krb5Cred\0" + +#define KRB4_CREDTYPE_NAME L"Krb4Cred" + +#define KRB4_CONFIG_NODE_NAME L"Krb4Config" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb4; + +extern khm_boolean krb4_initialized; + +extern khm_handle krb4_credset; + +/* plugin callbacks */ +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +#endif diff --git a/src/windows/identity/plugins/krb4/lang/en_us/langres.rc b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc new file mode 100644 index 0000000..a5d62a2 --- /dev/null +++ b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc @@ -0,0 +1,141 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB4 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "kRB4",IDC_STATIC,38,43,71,24 +END + +IDD_CFG_KRB4 DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket cache location",IDC_CFG_LBL_CACHE,7,10,67,8 + EDITTEXT IDC_CFG_CACHE,83,7,165,14,ES_AUTOHSCROLL + LTEXT "Config file path",IDC_CFG_LBL_CFGFILE,7,30,50,8 + EDITTEXT IDC_CFG_CFGPATH,83,27,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_CFGBROW,200,27,48,14 + LTEXT "Realm file path",IDC_CFG_LBL_RLMPATH,7,50,48,8 + EDITTEXT IDC_CFG_RLMPATH,83,47,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_RLMBROW,200,47,48,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_CFG_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 83 + VERTGUIDE, 196 + VERTGUIDE, 200 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PLUGIN_DESC "Kerberos 4 Credentials Provider" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4 tickets" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_CFG_KRB4_LONG "Kerberos 4 Configuration" + IDS_CFG_KRB4_SHORT "Kerberos 4" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/plugins/krb4/langres.h b/src/windows/identity/plugins/krb4/langres.h new file mode 100644 index 0000000..2096ade --- /dev/null +++ b/src/windows/identity/plugins/krb4/langres.h @@ -0,0 +1,78 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\plugins\krb4\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDD_NC_KRB4 103 +#define IDS_PLUGIN_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CFG_KRB4 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDS_ETYPE_NULL 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_CFG_KRB4_LONG 135 +#define IDS_CFG_KRB4_SHORT 136 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_CACHE 1025 +#define IDC_CFG_LBL_CFGFILE 1026 +#define IDC_CFG_LBL_RLMPATH 1027 +#define IDC_CFG_CACHE 1028 +#define IDC_CFG_CFGPATH 1029 +#define IDC_CFG_RLMPATH 1030 +#define IDC_CFG_CFGBROW 1031 +#define IDC_CFG_RLMBROW 1032 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1033 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/plugins/krb4/main.c b/src/windows/identity/plugins/krb4/main.c new file mode 100644 index 0000000..60ceb7f --- /dev/null +++ b/src/windows/identity/plugins/krb4/main.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_renew_till = -1; +khm_int32 attr_id_renew_for = -1; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; + +int n_locales = ARRAYLENGTH(locales); + +/* These two probably should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB4_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = 0; + pi.msg_proc = krb4_cb; + pi.dependencies = KRB4_PLUGIN_DEPS; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Lookup common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + goto _exit; + } + + /* Lookup common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_TILL, &attr_id_renew_till))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_FOR, &attr_id_renew_for))) { + goto _exit; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/plugins/krb5/Makefile b/src/windows/identity/plugins/krb5/Makefile new file mode 100644 index 0000000..9bf9ef0 --- /dev/null +++ b/src/windows/identity/plugins/krb5/Makefile @@ -0,0 +1,91 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb5 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb5cred.dll + +LIBFILE=$(LIBDIR)\krb5cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\main.obj \ + $(OBJ)\datarep.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb5plugin.obj \ + $(OBJ)\krb5props.obj \ + $(OBJ)\krb5newcreds.obj \ + $(OBJ)\krb5funcs.obj \ + $(OBJ)\krb5config.obj \ + $(OBJ)\krb5identpro.obj \ + $(OBJ)\krb5configdlg.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= \ + netapi32.lib + +MSGRESFILE=$(OBJ)\krb5_msgs.res + +$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(MSGRESFILE) $(OBJFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +$(MSGRESFILE): $(OBJ)\krb5_msgs.rc + +$(OBJ)\krb5_msgs.rc: lang\krb5_msgs.mc + $(MC2RC) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb5cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) + +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/src/windows/identity/plugins/krb5/datarep.c b/src/windows/identity/plugins/krb5/datarep.c new file mode 100644 index 0000000..f8cc4cc --- /dev/null +++ b/src/windows/identity/plugins/krb5/datarep.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Data representation and related functions */ + +#include +#include +#include +#include + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags) +{ + int resid = 0; + int etype; + wchar_t buf[256]; + size_t cblength; + + if(cbdata != sizeof(khm_int32)) + return KHM_ERROR_INVALID_PARM; + + etype = *((khm_int32 *) data); + + switch(etype) { + case ENCTYPE_NULL: + resid = IDS_ETYPE_NULL; + break; + + case ENCTYPE_DES_CBC_CRC: + resid = IDS_ETYPE_DES_CBC_CRC; + break; + + case ENCTYPE_DES_CBC_MD4: + resid = IDS_ETYPE_DES_CBC_MD4; + break; + + case ENCTYPE_DES_CBC_MD5: + resid = IDS_ETYPE_DES_CBC_MD5; + break; + + case ENCTYPE_DES_CBC_RAW: + resid = IDS_ETYPE_DES_CBC_RAW; + break; + + case ENCTYPE_DES3_CBC_SHA: + resid = IDS_ETYPE_DES3_CBC_SHA; + break; + + case ENCTYPE_DES3_CBC_RAW: + resid = IDS_ETYPE_DES3_CBC_RAW; + break; + + case ENCTYPE_DES_HMAC_SHA1: + resid = IDS_ETYPE_DES_HMAC_SHA1; + break; + + case ENCTYPE_DES3_CBC_SHA1: + resid = IDS_ETYPE_DES3_CBC_SHA1; + break; + + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_ARCFOUR_HMAC: + resid = IDS_ETYPE_ARCFOUR_HMAC; + break; + + case ENCTYPE_ARCFOUR_HMAC_EXP: + resid = IDS_ETYPE_ARCFOUR_HMAC_EXP; + break; + + case ENCTYPE_UNKNOWN: + resid = IDS_ETYPE_UNKNOWN; + break; + +#if 0 + case ENCTYPE_LOCAL_DES3_HMAC_SHA1: + resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1; + break; + + case ENCTYPE_LOCAL_RC4_MD4: + resid = IDS_ETYPE_LOCAL_RC4_MD4; + break; +#endif + } + + if(resid != 0) { + LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf)); + } else { + StringCbPrintf(buf, sizeof(buf), L"#%d", etype); + } + + StringCbLength(buf, ARRAYLENGTH(buf), &cblength); + cblength += sizeof(wchar_t); + + if(!destbuf || *pcbdestbuf < cblength) { + *pcbdestbuf = cblength; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(destbuf, *pcbdestbuf, buf); + *pcbdestbuf = cblength; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 KHMAPI addr_list_toString(const void *d, khm_size cb_d, wchar_t *buf, khm_size *pcb_buf, khm_int32 flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +khm_int32 KHMAPI krb5flags_toString(const void *d, + khm_size cb_d, + wchar_t *buf, + khm_size *pcb_buf, + khm_int32 f) +{ + wchar_t sbuf[32]; + int i = 0; + khm_size cb; + khm_int32 flags; + + flags = *((khm_int32 *) d); + + if (flags & TKT_FLG_FORWARDABLE) + sbuf[i++] = L'F'; + + if (flags & TKT_FLG_FORWARDED) + sbuf[i++] = L'f'; + + if (flags & TKT_FLG_PROXIABLE) + sbuf[i++] = L'P'; + + if (flags & TKT_FLG_PROXY) + sbuf[i++] = L'p'; + + if (flags & TKT_FLG_MAY_POSTDATE) + sbuf[i++] = L'D'; + + if (flags & TKT_FLG_POSTDATED) + sbuf[i++] = L'd'; + + if (flags & TKT_FLG_INVALID) + sbuf[i++] = L'i'; + + if (flags & TKT_FLG_RENEWABLE) + sbuf[i++] = L'R'; + + if (flags & TKT_FLG_INITIAL) + sbuf[i++] = L'I'; + + if (flags & TKT_FLG_HW_AUTH) + sbuf[i++] = L'H'; + + if (flags & TKT_FLG_PRE_AUTH) + sbuf[i++] = L'A'; + + sbuf[i++] = L'\0'; + + cb = i * sizeof(wchar_t); + + if (!buf || *pcb_buf < cb) { + *pcb_buf = cb; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *pcb_buf, sbuf); + *pcb_buf = cb; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 serialize_krb5_addresses(krb5_address ** a, void ** buf, size_t * pcbbuf) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +#if 0 + +wchar_t * +one_addr(krb5_address *a) +{ + static wchar_t retstr[256]; + struct hostent *h; + int no_resolve = 1; + + retstr[0] = L'\0'; + + if ((a->addrtype == ADDRTYPE_INET && a->length == 4) +#ifdef AF_INET6 + || (a->addrtype == ADDRTYPE_INET6 && a->length == 16) +#endif + ) + { + int af = AF_INET; +#ifdef AF_INET6 + if (a->addrtype == ADDRTYPE_INET6) + af = AF_INET6; +#endif + if (!no_resolve) { +#ifdef HAVE_GETIPNODEBYADDR + int err; + h = getipnodebyaddr(a->contents, a->length, af, &err); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + freehostent(h); + } +#else + h = gethostbyaddr(a->contents, a->length, af); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + } +#endif + if (h) + return(retstr); + } + if (no_resolve || !h) { +#ifdef HAVE_INET_NTOP + char buf[46]; + const char *name = inet_ntop(a->addrtype, a->contents, buf, sizeof(buf)); + if (name) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", name); + return; + } +#else + if (a->addrtype == ADDRTYPE_INET) { + StringCbPrintf(retstr, sizeof(retstr), + L"%d.%d.%d.%d", a->contents[0], a->contents[1], + a->contents[2], a->contents[3]); + return(retstr); + } +#endif + } + } + { + wchar_t tmpfmt[128]; + LoadString(hResModule, IDS_UNK_ADDR_FMT, tmpfmt, sizeof(tmpfmt)/sizeof(wchar_t)); + StringCbPrintf(retstr, sizeof(retstr), tmpfmt, a->addrtype); + } + return(retstr); +} +#endif diff --git a/src/windows/identity/plugins/krb5/datarep.h b/src/windows/identity/plugins/krb5/datarep.h new file mode 100644 index 0000000..e5388f0 --- /dev/null +++ b/src/windows/identity/plugins/krb5/datarep.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRB_DATAREP_H +#define __KHIMAIRA_KRB_DATAREP_H + + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags); +khm_int32 KHMAPI addr_list_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI krb5flags_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_size * pcbsize); + + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb5/errorfuncs.c b/src/windows/identity/plugins/krb5/errorfuncs.c new file mode 100644 index 0000000..ab64889 --- /dev/null +++ b/src/windows/identity/plugins/krb5/errorfuncs.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +#ifdef DEPRECATED_REMOVABLE +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} +#endif + +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code) +{ + const char * com_err_msg; + int offset; + long table_num; + DWORD msg_id = 0; + DWORD sugg_id = 0; + kherr_suggestion sugg_code = KHERR_SUGGEST_NONE; + + if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0) + return; + + *buf = L'\0'; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = perror_message(code); + + *suggestion = 0; + *suggest_code = KHERR_SUGGEST_NONE; + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + *suggest_code = KHERR_SUGGEST_RETRY; + AnsiStrToUnicode(buf, cbbuf, com_err_msg); + return; + } + + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + msg_id = MSG_ERR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + msg_id = MSG_ERR_PR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + msg_id = MSG_ERR_TKFIL; + sugg_id = MSG_ERR_S_TKFIL; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + + case RD_AP_TIME : /* 037 delta_t too big */ + msg_id = MSG_ERR_CLOCKSKEW; + sugg_id = MSG_ERR_S_CLOCKSKEW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case RD_AP_UNDEC : /* 031 Can't decode + authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + msg_id = MSG_ERR_KDC_CONTACT; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site + * specific information to be delivered from the Kerberos + * server. However the message box is too small for VGA + * screens. It does work well if we only have to support + * 1024x768 + */ + + msg_id = MSG_ERR_INSECURE_PW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + default: + /* no extra error msg */ + break; + } + + if (msg_id != 0) { + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + KHERR_HMODULE, + msg_id, + 0, + buf, + (int) (cbbuf / sizeof(buf[0])), + NULL); + } + + if (sugg_id != 0) { + *suggestion = sugg_id; + } + + if (sugg_code != KHERR_SUGGEST_NONE) + *suggest_code = sugg_code; +} + +#ifdef DEPRECATED_REMOVABLE +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} +#endif diff --git a/src/windows/identity/plugins/krb5/errorfuncs.h b/src/windows/identity/plugins/krb5/errorfuncs.h new file mode 100644 index 0000000..46d68f9 --- /dev/null +++ b/src/windows/identity/plugins/krb5/errorfuncs.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +/*! \internal + \brief Describe an error + + \param[in] code Error code returned by Kerberos + \param[out] buf Receives the error string + \param[in] cbbuf Size of buffer pointed to by \a buf + \param[out] suggestion Message ID of suggestion + \param[out] suggest_code Suggestion ID +*/ +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code); + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5configdlg.c b/src/windows/identity/plugins/krb5/krb5configdlg.c new file mode 100644 index 0000000..c3b00e1 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5configdlg.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +INT_PTR CALLBACK +k5_config_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + HWND hw; + wchar_t * realms; + wchar_t * defrealm; + wchar_t * t; + char conffile[MAX_PATH]; + wchar_t wconffile[MAX_PATH]; + wchar_t importopts[256]; + WKSTA_INFO_100 * winfo100; + + hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM); +#ifdef DEBUG + assert(hw); +#endif + realms = khm_krb5_get_realm_list(); + defrealm = khm_krb5_get_default_realm(); +#ifdef DEBUG + assert(realms); + assert(defrealm); +#endif + + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for(t = realms; t && *t; t = multi_string_next(t)) { + SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t); + } + + SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) defrealm); + + free(defrealm); + free(realms); + + khm_get_profile_file(conffile, sizeof(conffile)); + + AnsiStrToUnicode(wconffile, sizeof(wconffile), conffile); + + SetDlgItemText(hwnd, IDC_CFG_CFGFILE, wconffile); + + /* hostname/domain */ + if (NetWkstaGetInfo(NULL, 100, (LPBYTE *) &winfo100) == NERR_Success) { + SetDlgItemText(hwnd, IDC_CFG_HOSTNAME, winfo100->wki100_computername); + SetDlgItemText(hwnd, IDC_CFG_DOMAIN, winfo100->wki100_langroup); + NetApiBufferFree(winfo100); + } + + /* and the import ticket options */ + LoadString(hResModule, IDS_K5CFG_IMPORT_OPTIONS, + importopts, ARRAYLENGTH(importopts)); + + hw = GetDlgItem(hwnd, IDC_CFG_IMPORT); +#ifdef DEBUG + assert(hw); +#endif + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for (t=importopts; + t && *t && *t != L' ' && + t < importopts + ARRAYLENGTH(importopts); + t = multi_string_next(t)) { + + SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t); + } + + SendMessage(hw, CB_SETCURSEL, 0, 0); + + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + +INT_PTR CALLBACK +k5_realms_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + +typedef struct tag_k5_ids_dlg_data { + khui_tracker tc_life; + khui_tracker tc_renew; + khui_tracker tc_life_min; + khui_tracker tc_life_max; + khui_tracker tc_renew_min; + khui_tracker tc_renew_max; + + time_t life; + time_t renew_life; + time_t life_min; + time_t life_max; + time_t renew_min; + time_t renew_max; +} k5_ids_dlg_data; + +static void +k5_ids_read_params(k5_ids_dlg_data * d) { + khm_int32 t; + khm_int32 rv; + +#ifdef DEBUG + assert(csp_params); +#endif + + rv = khc_read_int32(csp_params, L"DefaultLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life = t; + + rv = khc_read_int32(csp_params, L"DefaultRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_life = t; + + rv = khc_read_int32(csp_params, L"MaxLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_max = t; + + rv = khc_read_int32(csp_params, L"MinLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_min = t; + + rv = khc_read_int32(csp_params, L"MaxRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_max = t; + + rv = khc_read_int32(csp_params, L"MinRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_min = t; + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + khui_tracker_initialize(&d->tc_life_min); + d->tc_life_min.current = d->life_min; + d->tc_life_min.min = d->tc_life.min; + d->tc_life_min.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_life_max); + d->tc_life_max.current = d->life_max; + d->tc_life_max.min = d->tc_life.min; + d->tc_life_max.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_renew_min); + d->tc_renew_min.current = d->renew_min; + d->tc_renew_min.min = d->tc_renew.min; + d->tc_renew_min.max = d->tc_renew.max; + + khui_tracker_initialize(&d->tc_renew_max); + d->tc_renew_max.current = d->renew_max; + d->tc_renew_max.min = d->tc_renew.min; + d->tc_renew_max.max = d->tc_renew.max; +} + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_ids_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = malloc(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k5_ids_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN), + &d->tc_life_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX), + &d->tc_life_max); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN), + &d->tc_renew_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX), + &d->tc_renew_max); + khui_tracker_refresh(&d->tc_life); + khui_tracker_refresh(&d->tc_life_min); + khui_tracker_refresh(&d->tc_life_max); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_renew_min); + khui_tracker_refresh(&d->tc_renew_max); + break; + + case WM_DESTROY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_life_min); + khui_tracker_kill_controls(&d->tc_life_max); + khui_tracker_kill_controls(&d->tc_renew_min); + khui_tracker_kill_controls(&d->tc_renew_max); + break; + } + return FALSE; +} + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + + +void +k5_register_config_panels(void) { + khui_config_node node; + khui_config_node_reg reg; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"Kerberos5"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); + reg.dlg_proc = k5_config_dlgproc; + reg.flags = 0; + + khui_cfg_register(NULL, ®); + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5RLM_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5RLM_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosRealms"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_REALMS); + reg.dlg_proc = k5_realms_dlgproc; + reg.flags = 0; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_IDS_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_IDS_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentities"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); + reg.dlg_proc = k5_ids_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(node, ®); + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_ID_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_ID_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentitiesPlural"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); + reg.dlg_proc = k5_id_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); +} + +void +k5_unregister_config_panels(void) { + khui_config_node node_main; + khui_config_node node_realms; + khui_config_node node_ids; + khui_config_node node_tab; + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node_main))) { + node_main = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosRealms", + &node_realms))) { + khui_cfg_remove(node_realms); + khui_cfg_release(node_realms); + } +#ifdef DEBUG + else + assert(FALSE); +#endif + + if (node_main) { + khui_cfg_remove(node_main); + khui_cfg_release(node_main); + } + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node_ids))) { + node_ids = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentities", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentitiesPlural", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + + if (node_ids) + khui_cfg_release(node_ids); +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c new file mode 100644 index 0000000..d3c97ff --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -0,0 +1,1889 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + +long +khm_convert524(krb5_context alt_ctx) +{ + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) + { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) + { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) + { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) + { + goto cleanup; + } + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) + { + goto cleanup; + } + +cleanup: + memset(v4creds, 0, sizeof(v4creds)); + free(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + pkrb5_free_cred_contents(ctx, &increds); + if (server) { + pkrb5_free_principal(ctx, server); + } + if (me) { + pkrb5_free_principal(ctx, me); + } + pkrb5_cc_close(ctx, cc); + + if (ctx && (ctx != alt_ctx)) { + pkrb5_free_context(ctx); + } + return !(code || icode); +} + +#ifdef DEPRECATED_REMOVABLE +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address, loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} +#endif + +#ifndef ENCTYPE_LOCAL_RC4_MD4 +#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 +#endif + +static long get_tickets_from_cache(krb5_context ctx, + krb5_ccache cache) +{ + krb5_error_code code; + krb5_principal KRBv5Principal; + krb5_flags flags = 0; + krb5_cc_cursor KRBv5Cursor; + krb5_creds KRBv5Credentials; + krb5_ticket *tkt=NULL; + char *ClientName; + char *PrincipalName; + wchar_t wbuf[256]; /* temporary conversion buffer */ + wchar_t *wcc_name = NULL; /* credential cache name */ + char *sServerName; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + khm_int64 ft, eft; + khm_int32 ti; + + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#else + flags = 0; +#endif + + { + char * cc_name; + size_t namelen; + + cc_name = (*pkrb5_cc_get_name)(ctx, cache); + if(cc_name) { + namelen = strlen(cc_name); + namelen = (namelen + 1 + 4) * sizeof(wchar_t); + /* the +4 is for the possible addtion of API: during the + cannonicalization process */ + wcc_name = malloc(namelen); + AnsiStrToUnicode(wcc_name, namelen, cc_name); + khm_krb5_canon_cc_name(wcc_name, namelen); + } + } + + if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache); + + goto _exit; + } + + if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache); + + goto _exit; + } + + PrincipalName = NULL; + ClientName = NULL; + sServerName = NULL; + if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, + (char **)&PrincipalName))) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + if (!strcspn(PrincipalName, "@" )) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &ident))) { + /* something bad happened */ + code = 1; + goto _exit; + } + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials)); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, + &KRBv5Credentials))) + { + khm_handle tident = NULL; + + if(ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + if(sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + if(cred) + kcdb_cred_release(cred); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + /* if the ClientName differs from PrincipalName for some + reason, we need to create a new identity */ + if(strcmp(ClientName, PrincipalName)) { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &tident))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + } else { + tident = ident; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName); + if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, + &cred))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + + if (!KRBv5Credentials.times.starttime) + KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, (LPFILETIME) &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, (LPFILETIME) &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft)); + + eft -= ft; + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &eft, sizeof(eft)); + + if (KRBv5Credentials.times.renew_till >= 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, (LPFILETIME) &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, + sizeof(eft)); + + eft -= ft; + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &eft, + sizeof(eft)); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti)); + + /* special flags understood by NetIDMgr */ + { + khm_int32 oflags, nflags; + + kcdb_cred_get_flags(cred, &oflags); + nflags = oflags; + + if (ti & TKT_FLG_RENEWABLE) + nflags |= KCDB_CRED_FLAG_RENEWABLE; + if (ti & TKT_FLG_INITIAL) + nflags |= KCDB_CRED_FLAG_INITIAL; + + if (oflags != nflags) + kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_ALL); + } + + if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { + ti = tkt->enc_part.enctype; + kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti)); + pkrb5_free_ticket(ctx, tkt); + tkt = NULL; + } + + ti = KRBv5Credentials.keyblock.enctype; + kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti)); + + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, KCDB_CBSIZE_AUTO); + + /*TODO: going here */ +#if 0 + if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) { + int n = 0; + while ( KRBv5Credentials.addresses[n] ) + n++; + list->addrList = calloc(1, n * sizeof(char *)); + if (!list->addrList) { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + list->addrCount = n; + for ( n=0; naddrCount; n++ ) { + wsprintf(Buffer, "Address: %s", one_addr(KRBv5Credentials.addresses[n])); + list->addrList[n] = (char*) calloc(1, strlen(Buffer)+1); + if (!list->addrList[n]) + { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + strcpy(list->addrList[n], Buffer); + } + } +#endif + + if(KRBv5Credentials.ticket_flags & TKT_FLG_INITIAL) { + __int64 t_expire_old; + __int64 t_expire_new; + khm_size cb; + + /* an initial ticket! If we find one, we generally set + the lifetime, and primary ccache based on this, but + only if this initial cred has a greater lifetime than + the current primary credential. */ + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, (LPFILETIME) &t_expire_new); + + cb = sizeof(t_expire_old); + if(KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, &t_expire_old, + &cb)) + || t_expire_new > t_expire_old) + { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + wcc_name, KCDB_CBSIZE_AUTO); + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_expire_new, + sizeof(t_expire_new)); + + if (KRBv5Credentials.times.renew_till >= 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, (LPFILETIME) &ft); + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + &ft, sizeof(ft)); + } else { + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &ti, sizeof(ti)); + } + } + + kcdb_credset_add_cred(krb5_credset, cred, -1); + + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + + if(tident != ident) + kcdb_identity_release(tident); + } + + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + if (ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + + if (sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + + if (cred) + kcdb_cred_release(cred); + + if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) + { + if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + flags = KRB5_TC_OPENCLOSE; +#ifdef KRB5_TC_NOTICKET + flags |= KRB5_TC_NOTICKET; +#endif + if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) + { + goto _exit; + } + } + else + { + goto _exit; + } + +_exit: + if(wcc_name) + free(wcc_name); + + return code; +} + +long +khm_krb5_list_tickets(krb5_context *krbv5Context) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code code; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i; + + ctx = NULL; + cache = NULL; + + kcdb_credset_flush(krb5_credset); + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + if (code) + goto _exit; + + if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { + goto _exit; + } + + ctx = (*krbv5Context); + + for(i=0; pNCi[i]; i++) { + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache); + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + +_exit: + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); + + return(code); + +} + +int +khm_krb5_renew(khm_handle identity) +{ + 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 ) + goto cleanup; + + memset(&my_creds, 0, sizeof(krb5_creds)); + + code = khm_krb5_initialize(identity, &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; + + my_creds.client = me; + my_creds.server = server; + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, 0); +#endif + code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); +#endif + if (code) { + if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || + code != KRB5_KDC_UNREACH) + khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); + 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 (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) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + return(code); +} + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data) +{ + 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; + } + +// code = pkrb5_cc_default(ctx, &cc); + if (ccache) + code = pkrb5_cc_resolve(ctx, ccache, &cc); + else + code = pkrb5_cc_resolve(ctx, principal_name, &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) { + khc_read_int32(csp_params, L"DefaultLifetime", &lifetime); + } + + 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); + assert(0); + } + 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); + assert(0); + } + + 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); + assert(0); + } + + 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) + assert(0); + + 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) + assert(0); + + 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 + prompter, // prompter + p_data, // 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) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src) { + krb5_context ctx = NULL; + krb5_error_code code = 0; + khm_boolean free_ctx; + krb5_ccache cc_src = NULL; + krb5_ccache cc_dest = NULL; + krb5_principal princ_src = NULL; + char scc_dest[KRB5_MAXCCH_CCNAME]; + char scc_src[KRB5_MAXCCH_CCNAME]; + int t; + + t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest); + if (t == 0) + return KHM_ERROR_TOO_LONG; + t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src); + if (t == 0) + return KHM_ERROR_TOO_LONG; + + if (in_ctx) { + ctx = in_ctx; + free_ctx = FALSE; + } else { + code = pkrb5_init_context(&ctx); + if (code) { + if (ctx) + pkrb5_free_context(ctx); + return code; + } + free_ctx = TRUE; + } + + code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest); + if (code) + goto _cleanup; + + code = pkrb5_cc_resolve(ctx, scc_src, &cc_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_initialize(ctx, cc_dest, princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest); + + _cleanup: + if (princ_src) + pkrb5_free_principal(ctx, princ_src); + + if (cc_dest) + pkrb5_cc_close(ctx, cc_dest); + + if (cc_src) + pkrb5_cc_close(ctx, cc_src); + + if (free_ctx && ctx) + pkrb5_free_context(ctx); + + return code; +} + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name) { + size_t cb_len; + wchar_t * colon; + + if (FAILED(StringCbLength(wcc_name, + cb_cc_name, + &cb_len))) { +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_TOO_LONG; +#endif + } + + cb_len += sizeof(wchar_t); + + colon = wcschr(wcc_name, L':'); + + if (colon) + return 0; + + if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[4], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4); + + return 0; +} + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2) { + if (!wcsncmp(cc_name_1, L"API:", 4)) + cc_name_1 += 4; + + if (!wcsncmp(cc_name_2, L"API:", 4)) + cc_name_2 += 4; + + return wcscmp(cc_name_1, cc_name_2); +} + +static khm_int32 KHMAPI +khmint_location_comp_func(khm_handle cred1, + khm_handle cred2, + void * rock) { + return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION); +} + +struct khmint_location_check { + khm_handle credset; + khm_handle cred; + wchar_t * ccname; + khm_boolean success; +}; + +static khm_int32 KHMAPI +khmint_find_matching_cred_func(khm_handle cred, + void * rock) { + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (!kcdb_creds_is_equal(cred, lc->cred)) + return KHM_ERROR_SUCCESS; + if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION)) + return KHM_ERROR_SUCCESS; + + /* found it */ + lc->success = TRUE; + + /* break the search */ + return !KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_location_check_func(khm_handle cred, + void * rock) { + khm_int32 t; + khm_size cb; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t))) + return KHM_ERROR_SUCCESS; + + if (t != credtype_id_krb5) + return KHM_ERROR_SUCCESS; + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + return KHM_ERROR_SUCCESS; + + if(wcscmp(ccname, lc->ccname)) + return KHM_ERROR_SUCCESS; + + lc->cred = cred; + + lc->success = FALSE; + + kcdb_credset_apply(lc->credset, + khmint_find_matching_cred_func, + (void *) lc); + + if (!lc->success) + return KHM_ERROR_NOT_FOUND; + else + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_delete_location_func(khm_handle cred, + void * rock) { + wchar_t cc_cred[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + khm_size cb; + + lc = (struct khmint_location_check *) rock; + + cb = sizeof(cc_cred); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + cc_cred, + &cb))) + return KHM_ERROR_SUCCESS; + + if (wcscmp(cc_cred, lc->ccname)) + return KHM_ERROR_SUCCESS; + + kcdb_credset_del_cred_ref(lc->credset, + cred); + + return KHM_ERROR_SUCCESS; +} + +int +khm_krb5_destroy_by_credset(khm_handle p_cs) +{ + khm_handle d_cs = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size s, cb; + krb5_context ctx; + krb5_error_code code = 0; + int i; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check lc; + + rv = kcdb_credset_create(&d_cs); + + assert(KHM_SUCCEEDED(rv) && d_cs != NULL); + + kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5); + + kcdb_credset_get_size(d_cs, &s); + + if (s == 0) { + /* nothing to do */ + kcdb_credset_delete(d_cs); + return 0; + } + + code = pkrb5_init_context(&ctx); + if (code != 0) { + rv = code; + goto _cleanup; + } + + /* we should synchronize the credential lists before we attempt to + make any assumptions on the state of the root credset */ + khm_krb5_list_tickets(&ctx); + + /* so, we need to make a decision about whether to destroy entire + ccaches or just individual credentials. Therefore we first + sort them by ccache. */ + kcdb_credset_sort(d_cs, + khmint_location_comp_func, + NULL); + + /* now, for each ccache we encounter, we check if we have all the + credentials from that ccache in the to-be-deleted list. */ + for (i=0; i < (int) s; i++) { + khm_handle cred; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(ccname); + rv = kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb); + +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + kcdb_cred_release(cred); + + lc.credset = d_cs; + lc.cred = NULL; + lc.ccname = ccname; + lc.success = FALSE; + + kcdb_credset_apply(NULL, + khmint_location_check_func, + (void *) &lc); + + if (lc.success) { + /* ok the destroy the ccache */ + char a_ccname[KRB5_MAXCCH_CCNAME]; + krb5_ccache cc = NULL; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + if (code) + goto _delete_this_set; + + code = pkrb5_cc_destroy(ctx, cc); + + if (code) { + /*TODO: report error */ + } + + _delete_this_set: + + lc.credset = d_cs; + lc.ccname = ccname; + + /* note that although we are deleting credentials off the + credential set, the size of the credential set does not + decrease since we are doing it from inside + kcdb_credset_apply(). The deleted creds will simply be + marked as deleted until kcdb_credset_purge() is + called. */ + + kcdb_credset_apply(d_cs, + khmint_delete_location_func, + (void *) &lc); + } + } + + kcdb_credset_purge(d_cs); + + /* the remainder need to be deleted one by one */ + + kcdb_credset_get_size(d_cs, &s); + + for (i=0; i < (int) s; ) { + khm_handle cred; + char a_ccname[KRB5_MAXCCH_CCNAME]; + char a_srvname[KCDB_CRED_MAXCCH_NAME]; + wchar_t srvname[KCDB_CRED_MAXCCH_NAME]; + krb5_ccache cc; + krb5_creds in_cred, out_cred; + krb5_principal princ; + khm_int32 etype; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) { + i++; + continue; + } + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + goto _done_with_this_cred; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + + if (code) + goto _skip_similar; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + + if (code) { + pkrb5_cc_close(ctx, cc); + goto _skip_similar; + } + + _del_this_cred: + + cb = sizeof(etype); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + attr_id_key_enctype, + NULL, + &etype, + &cb))) + goto _do_next_cred; + + cb = sizeof(srvname); + if (KHM_FAILED(kcdb_cred_get_name(cred, + srvname, + &cb))) + goto _do_next_cred; + + UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); + + ZeroMemory(&in_cred, sizeof(in_cred)); + + code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server); + if (code) + goto _do_next_cred; + in_cred.client = princ; + in_cred.keyblock.enctype = etype; + + code = pkrb5_cc_retrieve_cred(ctx, + cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES, + &in_cred, + &out_cred); + if (code) + goto _do_next_cred_0; + + code = pkrb5_cc_remove_cred(ctx, cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES | + KRB5_TC_MATCH_AUTHDATA, + &out_cred); + + pkrb5_free_cred_contents(ctx, &out_cred); + _do_next_cred_0: + pkrb5_free_principal(ctx, in_cred.server); + _do_next_cred: + + /* check if the next cred is also of the same ccache */ + kcdb_cred_release(cred); + + for (i++; i < (int) s; i++) { + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + } + + if (i < (int) s) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + newcc, + &cb)) || + wcscmp(newcc, ccname)) { + i--; /* we have to look at this again */ + goto _done_with_this_set; + } + goto _del_this_cred; + } + + + _done_with_this_set: + pkrb5_free_principal(ctx, princ); + + pkrb5_cc_close(ctx, cc); + + _done_with_this_cred: + kcdb_cred_release(cred); + i++; + continue; + + _skip_similar: + kcdb_cred_release(cred); + + for (++i; i < (int) s; i++) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + &newcc, + &cb))) { + kcdb_cred_release(cred); + continue; + } + + if (wcscmp(newcc, ccname)) { + kcdb_cred_release(cred); + break; + } + } + } + + _cleanup: + + if (d_cs) + kcdb_credset_delete(&d_cs); + + return rv; +} + +int +khm_krb5_destroy_identity(khm_handle identity) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code rc; + + ctx = NULL; + cache = NULL; + + if (rc = khm_krb5_initialize(identity, &ctx, &cache)) + return(rc); + + rc = pkrb5_cc_destroy(ctx, cache); + + if (ctx != NULL) + pkrb5_free_context(ctx); + + return(rc); +} + +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; +} + +// 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 +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); + StringCbCatW (buffer, sizeof(buffer), L""); + if ( !lstrcmpW(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +BOOL +khm_krb5_ms2mit(BOOL save_creds) +{ +#ifdef NO_KRB5 + return(FALSE); +#else /* NO_KRB5 */ + krb5_context kcontext = 0; + krb5_error_code code; + krb5_ccache ccache=0; + krb5_ccache mslsa_ccache=0; + krb5_creds creds; + krb5_cc_cursor cursor=0; + krb5_principal princ = 0; + char *cache_name = NULL; + char *princ_name = NULL; + BOOL rc = FALSE; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (code = pkrb5_init_context(&kcontext)) + goto cleanup; + + if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if ( save_creds ) { + if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) + goto cleanup; + + if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) + goto cleanup; + + /* TODO: actually look up the preferred ccache name */ + if ((code = pkrb5_cc_resolve(kcontext, princ_name, &ccache)) || + (code = pkrb5_cc_default(kcontext, &ccache))) + goto cleanup; + + if (code = pkrb5_cc_initialize(kcontext, ccache, princ)) + goto cleanup; + + if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) + goto cleanup; + + rc = TRUE; + } else { + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) + goto cleanup; + + while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds))) + { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + rc = TRUE; + pkrb5_free_cred_contents(kcontext, &creds); + break; + } + pkrb5_free_cred_contents(kcontext, &creds); + } + pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); + } + +cleanup: + if (princ_name) + pkrb5_free_unparsed_name(kcontext, princ_name); + if (princ) + pkrb5_free_principal(kcontext, princ); + if (ccache) + pkrb5_cc_close(kcontext, ccache); + if (mslsa_ccache) + pkrb5_cc_close(kcontext, mslsa_ccache); + if (kcontext) + pkrb5_free_context(kcontext); + return(rc); +#endif /* NO_KRB5 */ +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode + strings, each of which denotes one realm. The set is terminated + by a zero length null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the + operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, + §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = malloc(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = malloc(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The + caller should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = malloc(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +wchar_t * khm_get_realm_from_princ(wchar_t * princ) { + wchar_t * t; + + if(!princ) + return NULL; + + for (t = princ; *t; t++) { + if(*t == L'\\') { /* escape */ + t++; + if(! *t) /* malformed */ + break; + } else if (*t == L'@') + break; + } + + if (*t == '@' && *(t+1) != L'\0') + return (t+1); + else + return NULL; +} + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, + password, 0, 0, 0, + "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = malloc(len + 1); + if (*error_str) + StringCchPrintfA(*error_str, len+1, + "%.*s%s%.*s", + result_code_string.length, + result_code_string.data, + result_string.length?": ":"", + result_string.length, + result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h new file mode 100644 index 0000000..79ca956 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5funcs.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +#define KRB5_MAXCCH_CCNAME 1024 + +// Function Prototypes. + +BOOL +khm_krb5_ms2mit(BOOL); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data); + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str); + +int +khm_krb5_destroy_by_credset(khm_handle p_cs); + +int +khm_krb5_destroy_identity(khm_handle identity); + +long +khm_convert524(krb5_context ctx); + +int +khm_krb5_renew(khm_handle identity); + +wchar_t * +khm_krb5_get_default_realm(void); + +wchar_t * +khm_krb5_get_realm_list(void); + +long +khm_krb5_list_tickets(krb5_context *krbv5Context); + +long +khm_krb4_list_tickets(void); + +wchar_t * +khm_get_realm_from_princ(wchar_t * princ); + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src); + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name); + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2); + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname); + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c new file mode 100644 index 0000000..c568e49 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -0,0 +1,1108 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include + +#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0) +#define K5_NCID_UN (KHUI_CW_ID_MIN + 1) +#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2) +#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3) + +#define NC_UNCHANGE_TIMEOUT 3000 +#define NC_UNCHANGE_TIMER 2 +#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT +#define NC_REALMCHANGE_TIMER 3 + +typedef struct tag_k5_new_cred_data { + HWND hw_username_label; + HWND hw_username; + HWND hw_realm_label; + HWND hw_realm; +} k5_new_cred_data; + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + return GetWindowText(d->hw_realm, buf, (int) cch_buf); +} + +/* set the primary identity of a new credentials dialog depending on + the selection of the username and realm + + Runs in the UI thread +*/ +static void +set_identity_from_ui(khui_new_creds * nc, + k5_new_cred_data * d) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * realm; + khm_size cch; + khm_size cch_left; + khm_handle ident; + LRESULT idx = CB_ERR; + + cch = GetWindowTextLength(d->hw_username); + + /* we already set the max length of the edit control to be this. + shouldn't exceed it unless the edit control is confused. */ + assert(cch < KCDB_IDENT_MAXCCH_NAME - 1); + + GetWindowText(d->hw_username, un, ARRAYLENGTH(un)); + + realm = khm_get_realm_from_princ(un); + if (realm) /* realm was specified */ + goto _set_ident; + + /* the cch we got from GetWindowTextLength can not be trusted to + be exact. For caveats see MSDN for GetWindowTextLength. */ + StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); + + realm = un + cch; /* now points at terminating NULL */ + cch_left = KCDB_IDENT_MAXCCH_NAME - cch; + + *realm++ = L'@'; + cch_left--; + + cch = GetWindowTextLength(d->hw_realm); + if (cch == 0 || cch >= cch_left) + goto _set_null_ident; + + GetWindowText(d->hw_realm, realm, (int) cch_left); + + _set_ident: + if (KHM_FAILED(kcdb_identity_create(un, + KCDB_IDENT_FLAG_CREATE, + &ident))) + goto _set_null_ident; + + khui_cw_set_primary_id(nc, ident); + + kcdb_identity_release(ident); + return; + + _set_null_ident: + khui_cw_set_primary_id(nc, NULL); + return; +} + +static BOOL +update_crossfeed(khui_new_creds * nc, + k5_new_cred_data * d, + int ctrl_id_src) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * un_realm; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + khm_size cch; + khm_size cch_left; + + cch = (khm_size) GetWindowTextLength(d->hw_username); +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_username, + un, + ARRAYLENGTH(un)); + + un_realm = khm_get_realm_from_princ(un); + + if (un_realm == NULL) + return FALSE; + + if (ctrl_id_src == K5_NCID_UN) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un_realm); + + SetWindowText(d->hw_realm, + un_realm); + + return TRUE; + } + /* else... */ + + cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un); + + cch = (khm_size) GetWindowTextLength(d->hw_realm); + +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_realm, realm, + ARRAYLENGTH(realm)); + + StringCchCopy(un_realm, cch_left, realm); + + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un); + + SetWindowText(d->hw_username, un); + + return TRUE; +} + +/* Handle window messages for the identity specifiers + + runs in UI thread */ +static LRESULT +handle_wnd_msg(khui_new_creds * nc, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(uMsg) { + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE): + /* the username has changed. Instead of handling this + for every keystroke, set a timer that elapses some + time afterwards and then handle the event. */ + SetTimer(hwnd, NC_UNCHANGE_TIMER, + NC_UNCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP): + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE): + SetTimer(hwnd, NC_REALMCHANGE_TIMER, + NC_REALMCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP): + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + + case WM_TIMER: + if(wParam == NC_UNCHANGE_TIMER) { + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + } else if (wParam == NC_REALMCHANGE_TIMER) { + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + } + return FALSE; +} + +/* UI Callback + + runs in UI thread */ +static LRESULT KHMAPI +ui_cb(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(cmd) { + case WMNC_IDENT_INIT: + { + wchar_t defident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wbuf[1024]; + wchar_t * ms = NULL; + wchar_t * t; + wchar_t * defrealm = NULL; + LRESULT lr; + khm_size cb_ms; + khm_size cb; + HWND hw_parent; + khm_int32 rv; + khm_handle hident; + + hw_parent = (HWND) lParam; + defident[0] = L'\0'; + +#ifdef DEBUG + assert(d == NULL); + assert(hw_parent != NULL); +#endif + + d = malloc(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + khui_cw_lock_nc(nc); + nc->ident_aux = (LPARAM) d; + khui_cw_unlock_nc(nc); + + LoadString(hResModule, IDS_NC_USERNAME, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_username_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN_LABEL, + hInstance, + NULL); + assert(d->hw_username_label != NULL); + + d->hw_username = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN, + hInstance, + NULL); + assert(d->hw_username != NULL); + + SendMessage(d->hw_username, + CB_LIMITTEXT, + (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_username, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_username_label, + d->hw_username, + KHUI_CTRLSIZE_SMALL); + + LoadString(hResModule, IDS_NC_REALM, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_realm_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM_LABEL, + hInstance, + NULL); + assert(d->hw_realm_label != NULL); + + d->hw_realm = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM, + hInstance, + NULL); + assert(d->hw_realm != NULL); + + SendMessage(d->hw_realm, + CB_LIMITTEXT, + (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_realm, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_realm_label, + d->hw_realm, + KHUI_CTRLSIZE_SMALL); + + /* add the LRU realms and principals to the dropdown + lists */ + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + + if (rv != KHM_ERROR_TOO_LONG) + goto _add_lru_realms; + + ms = malloc(cb_ms); + assert(ms != NULL); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + /* the first of these is considered the default identity + if no other default is known */ + StringCbCopy(defident, sizeof(defident), ms); + + t = ms; + while(t && *t) { + SendMessage(d->hw_username, + CB_ADDSTRING, + 0, + (LPARAM) t); + + t = multi_string_next(t); + } + + _add_lru_realms: + /* add the default realm first */ + defrealm = khm_krb5_get_default_realm(); + if (defrealm) { + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) defrealm); + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + NULL, + &cb); + + if (rv != KHM_ERROR_TOO_LONG) + goto _done_adding_lru; + + if (ms != NULL) { + if (cb_ms < cb) { + free(ms); + ms = malloc(cb); + assert(ms); + cb_ms = cb; + } + } else { + ms = malloc(cb); + cb_ms = cb; + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + + _done_adding_lru: + /* set the current selection of the realms list */ + if (defrealm) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + } else { + SendMessage(d->hw_realm, + CB_SETCURSEL, + (WPARAM) 0, + (LPARAM) 0); + } + + if (defrealm) + free(defrealm); + + if (ms) + free(ms); + + /* now see about that default identity */ + if (nc->ctx.identity) { + cb = sizeof(defident); + kcdb_identity_get_name(nc->ctx.identity, + defident, + &cb); + } + + if (defident[0] == L'\0' && + KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) { + cb = sizeof(defident); + kcdb_identity_get_name(hident, defident, &cb); + kcdb_identity_release(hident); + } + + if (defident[0] == L'\0') { + DWORD dw; + + dw = ARRAYLENGTH(defident); + GetUserName(defident, &dw); + } + + t = khm_get_realm_from_princ(defident); + if (t) { + /* there is a realm */ + assert(t != defident); + *--t = L'\0'; + t++; + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) t); + + SendMessage(d->hw_realm, + WM_SETTEXT, + 0, + (LPARAM) t); + } + + if (defident[0] != L'\0') { + /* there is a username */ + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defident); + + SendMessage(d->hw_username, + WM_SETTEXT, + 0, + (LPARAM) defident); + } + + set_identity_from_ui(nc, d); + } + return TRUE; + + case WMNC_IDENT_WMSG: + return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam); + + case WMNC_IDENT_EXIT: + { +#ifdef DEBUG + assert(d != NULL); +#endif + khui_cw_lock_nc(nc); + nc->ident_aux = 0; + khui_cw_unlock_nc(nc); + + /* since we created all the windows as child windows of + the new creds window, they will be destroyed when that + window is destroyed. */ + free(d); + } + return TRUE; + } + return FALSE; +} + +static khm_int32 +k5_ident_valiate_name(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + krb5_principal princ = NULL; + char princ_name[KCDB_IDENT_MAXCCH_NAME]; + kcdb_ident_name_xfer * nx; + krb5_error_code code; + + nx = (kcdb_ident_name_xfer *) vparam; + + if(UnicodeStrToAnsi(princ_name, sizeof(princ_name), + nx->name_src) == 0) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_parse_name(k5_identpro_ctx, + princ_name, + &princ); + + if (code) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + if (princ != NULL) + pkrb5_free_principal(k5_identpro_ctx, + princ); + + nx->result = KHM_ERROR_SUCCESS; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_set_default(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* Logic for setting the default identity: + + When setting identity I as the default; + + - If KRB5CCNAME is set + - If I["Krb5CCName"] == %KRB5CCNAME% + - do nothing + - Else + - Copy the contents of I["Krb5CCName"] to %KRB5CCNAME + - Set I["Krb5CCName"] to %KRB5CCNAME + - Else + - Set HKCU\Software\MIT\kerberos5,ccname to + "API:".I["Krb5CCName"] + */ + + if (uparam) { + /* an identity is being made default */ + khm_handle def_ident = (khm_handle) vparam; + wchar_t env_ccname[KRB5_MAXCCH_CCNAME]; + wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; + khm_size cb; + DWORD dw; + LONG l; + +#ifdef DEBUG + assert(def_ident != NULL); +#endif + + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(def_ident, + attr_id_krb5_ccname, + NULL, + id_ccname, + &cb))) + return KHM_ERROR_UNKNOWN; + + khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); + + StringCbLength(id_ccname, sizeof(id_ccname), &cb); + cb += sizeof(wchar_t); + + dw = GetEnvironmentVariable(L"KRB5CCNAME", + env_ccname, + ARRAYLENGTH(env_ccname)); + + if (dw == 0 && + GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + /* KRB5CCNAME not set */ + HKEY hk_ccname; + DWORD dwType; + DWORD dwSize; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dw); + + if (l != ERROR_SUCCESS) + return KHM_ERROR_UNKNOWN; + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ || + khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { + + /* we have to write the new value in */ + + l = RegSetValueEx(hk_ccname, + L"ccname", + 0, + REG_SZ, + (BYTE *) id_ccname, + (DWORD) cb); + } + + RegCloseKey(hk_ccname); + + if (l == ERROR_SUCCESS) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_UNKNOWN; + + } else if (dw > ARRAYLENGTH(env_ccname)) { + /* buffer was not enough */ +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_UNKNOWN; +#endif + } else { + /* KRB5CCNAME is set */ + long code; + krb5_context ctx; + + /* if the %KRB5CCNAME is the same as the identity + ccache, then it is already the default. */ + if (!khm_krb5_cc_name_cmp(id_ccname, env_ccname)) + return KHM_ERROR_SUCCESS; + + /* if not, we have to copy the contents of id_ccname + to env_ccname */ + code = pkrb5_init_context(&ctx); + if (code) + return KHM_ERROR_UNKNOWN; + + code = khm_krb5_copy_ccache_by_name(ctx, + env_ccname, + id_ccname); + + if (code == 0) + khm_krb5_list_tickets(&ctx); + + if (ctx) + pkrb5_free_context(ctx); + + return (code == 0)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; + } + } else { + /* the default identity is being forgotten */ + + /* we don't really do anything about this case */ + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_get_ui_cb(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khui_ident_new_creds_cb * cb; + + cb = (khui_ident_new_creds_cb *) vparam; + + *cb = ui_cb; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_notify_create(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* a new identity has been created. What we want to do at + this point is to check if the identity belongs to krb5 + and to see if it is the default. */ + + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle ident; + + ident = (khm_handle) vparam; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + cb = sizeof(id_nameW); + + if (KHM_FAILED(kcdb_identity_get_name(ident, + id_nameW, + &cb))) + goto _nc_cleanup; + + if (!wcscmp(id_nameW, princ_nameW)) { + kcdb_identity_set_default_int(ident); + } + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +k5_ident_update_apply_proc(khm_handle cred, + void * rock) { + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + khm_handle tident = (khm_handle) rock; + khm_handle ident = NULL; + khm_int32 t; + khm_int32 flags; + __int64 t_expire; + __int64 t_rexpire; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) || + t != credtype_id_krb5 || + KHM_FAILED(kcdb_cred_get_identity(cred, &ident))) + return KHM_ERROR_SUCCESS; + + if (ident != tident) + goto _cleanup; + + if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags))) + flags = 0; + + cb = sizeof(t_expire); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + KCDB_ATTR_EXPIRE, + NULL, + &t_expire, + &cb))) { + __int64 t_cexpire; + + cb = sizeof(t_cexpire); + if ((flags & KCDB_CRED_FLAG_INITIAL) || + KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, + &t_cexpire, + &cb)) || + t_cexpire > t_expire) + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_expire, sizeof(t_expire)); + } else if (flags & KCDB_CRED_FLAG_INITIAL) { + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, NULL, 0); + } + + cb = sizeof(ccname); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + ccname, cb); + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + NULL, 0); + } + + if (!(flags & KCDB_CRED_FLAG_INITIAL)) + goto _cleanup; + + cb = sizeof(t); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + attr_id_krb5_flags, + NULL, + &t, + &cb))) { + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &t, sizeof(t)); + + cb = sizeof(t_rexpire); + if (!(t & TKT_FLG_RENEWABLE) || + KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_RENEW_EXPIRE, + NULL, + &t_rexpire, + &cb))) { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + &t_rexpire, sizeof(t_rexpire)); + } + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + NULL, 0); + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + rv = KHM_ERROR_EXIT; + + _cleanup: + if (ident) + kcdb_identity_release(ident); + + return rv; +} + +static khm_int32 +k5_ident_update(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_handle ident; + + ident = (khm_handle) vparam; + if (ident == NULL) + return KHM_ERROR_SUCCESS; + + kcdb_credset_apply(NULL, + k5_ident_update_apply_proc, + (void *) ident); + + return KHM_ERROR_SUCCESS; +} + + +static khm_int32 +k5_ident_init(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* just like notify_create, except now we set the default identity + based on what we find in the configuration */ + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_handle ident = NULL; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + if (KHM_FAILED(kcdb_identity_create(princ_nameW, + 0, + &ident))) + goto _nc_cleanup; + + kcdb_identity_set_default_int(ident); + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_exit(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* don't really do anything */ + return KHM_ERROR_SUCCESS; +} + +#if 0 +/* copy and paste template for ident provider messages */ +static khm_int32 +k5_ident_(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { +} +#endif + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + switch(msg_subtype) { + case KMSG_IDENT_INIT: + return k5_ident_init(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_EXIT: + return k5_ident_exit(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_NAME: + return k5_ident_valiate_name(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_IDENTITY: + /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */ + break; + + case KMSG_IDENT_CANON_NAME: + /* TODO: handle KMSG_IDENT_CANON_NAME */ + break; + + case KMSG_IDENT_COMPARE_NAME: + /* TODO: handle KMSG_IDENT_COMPARE_NAME */ + break; + + case KMSG_IDENT_SET_DEFAULT: + return k5_ident_set_default(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_SET_SEARCHABLE: + /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */ + break; + + case KMSG_IDENT_GET_INFO: + /* TODO: handle KMSG_IDENT_GET_INFO */ + break; + + case KMSG_IDENT_UPDATE: + return k5_ident_update(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_ENUM_KNOWN: + /* TODO: handle KMSG_IDENT_ENUM_KNOWN */ + break; + + case KMSG_IDENT_GET_UI_CALLBACK: + return k5_ident_get_ui_cb(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_NOTIFY_CREATE: + return k5_ident_notify_create(msg_type, + msg_subtype, + uparam, + vparam); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c new file mode 100644 index 0000000..968e0e2 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -0,0 +1,2167 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#include + +extern LPVOID k5_main_fiber; +extern LPVOID k5_kinit_fiber; + +typedef struct k5_dlg_data_t { + khui_new_creds * nc; + + khui_tracker tc_lifetime; + khui_tracker tc_renew; + + BOOL dirty; + + DWORD renewable; + DWORD forwardable; + DWORD proxiable; + DWORD addressless; + DWORD publicIP; + + wchar_t * cred_message; /* overrides the credential text, if + non-NULL */ +} k5_dlg_data; + + +INT_PTR +k5_handle_wm_initdialog(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + HWND hw; + k5_dlg_data * d; + khui_new_creds_by_type * nct; + + d = malloc(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + /* lParam is a pointer to a khui_new_creds structure */ + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + nct->aux = (LPARAM) d; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_initialize(&d->tc_lifetime); + khui_tracker_initialize(&d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT); + khui_tracker_install(hw, &d->tc_lifetime); + + hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT); + khui_tracker_install(hw, &d->tc_renew); + } + return TRUE; +} + +INT_PTR +k5_handle_wm_destroy(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + k5_dlg_data * d; + khui_new_creds_by_type * nct = NULL; + + d = (k5_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#ifdef DEBUG + assert(nct); +#endif + + nct->aux = 0; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_lifetime); + } + + free(d); + + return TRUE; +} + +INT_PTR +k5_handle_wmnc_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_MOVE: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_reposition(&d->tc_lifetime); + khui_tracker_reposition(&d->tc_renew); + } + + return TRUE; + } + break; + + case WMNC_DIALOG_SETUP: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + return TRUE; + + /* need to update the controls with d->* */ + if(d->renewable) { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_CHECKED, + 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + TRUE); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + FALSE); + } + + khui_tracker_refresh(&d->tc_lifetime); + khui_tracker_refresh(&d->tc_renew); + + if(d->forwardable) { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_CHECKED, 0); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + } + } + break; + + case WMNC_UPDATE_CREDTEXT: + { + k5_dlg_data * d; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t sbuf[1024]; + wchar_t fbuf[256]; + wchar_t tbuf[256]; + size_t cbsize; + khm_int32 flags; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + nc = d->nc; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(nct == NULL) + break; + + if(nct->credtext) + free(nct->credtext); + nct->credtext = NULL; + + tbuf[0] = L'\0'; + + if (nc->n_identities > 0 && + KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID) && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + if (is_k5_identpro) + k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf)); + else + GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, + ARRAYLENGTH(tbuf)); + + /*TODO: if additional realms were specified, then those + must be listed as well */ + LoadString(hResModule, IDS_KRB5_CREDTEXT_0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, + tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else if (nc->n_identities > 0 && + nc->subtype == KMSG_CRED_PASSWORD) { + cbsize = sizeof(tbuf); + kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize); + + LoadString(hResModule, IDS_KRB5_CREDTEXT_P0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else { + if (d->cred_message) { + StringCbLength(d->cred_message, KHUI_MAXCB_BANNER, + &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, d->cred_message); + } + } + } + break; + + case WMNC_IDENTITY_CHANGE: + { + /* There has been a change of identity */ + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_IDENTITY, + 0, (void *) d->nc); + } + break; + + case WMNC_DIALOG_PREPROCESS: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if(d->dirty) { + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_OPTIONS, + 0, (void *) d->nc); + + /* the above notification effectively takes + all our changes into account. The data we + have is no longer dirty */ + d->dirty = FALSE; + } + } + break; + } + + return 0; +} + +INT_PTR +k5_handle_wm_command(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + int cid; + int notif; + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + cid = LOWORD(wParam); + notif = HIWORD(wParam); + + if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE); + d->renewable = TRUE; + } else { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE); + d->renewable = FALSE; + } + d->dirty = TRUE; + } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + d->forwardable = TRUE; + } else { + d->forwardable = FALSE; + } + d->dirty = TRUE; + } else if((notif == CBN_SELCHANGE || + notif == CBN_KILLFOCUS) && + cid == IDC_NCK5_REALM && + !is_k5_identpro) { + /* find out what the realm of the current identity + is, and if they are the same, then we don't do + anything */ + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + wchar_t *r; + khm_size cbsize; + khm_handle ident; + int idx; + + if(d->nc->n_identities > 0) { + if(notif == CBN_SELCHANGE) { + idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETCURSEL, 0, 0); + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETLBTEXT, idx, (LPARAM) realm); + } else { + GetDlgItemText(hwnd, IDC_NCK5_REALM, + realm, ARRAYLENGTH(realm)); + } + cbsize = sizeof(idname); + if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], + idname, &cbsize))) { + r = wcschr(idname, L'@'); + if(r && !wcscmp(realm, r+1)) + return 0; /* nothing to do */ + + if(!r) { + r = idname + wcslen(idname); + *r++ = L'@'; + *r++ = 0; + } + + /* if we get here, we have a new user */ + StringCchCopy(r+1, + ARRAYLENGTH(idname) - ((r+1) - idname), + realm); + if(KHM_SUCCEEDED(kcdb_identity_create(idname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khui_cw_set_primary_id(d->nc, ident); + kcdb_identity_release(ident); + } + return 0; + } + } + + /* if we get here, we have a new realm, but there is no + identity */ + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } + + return 0; +} + + +/* Dialog procedure for the Krb5 credentials type panel. + + NOTE: Runs in the context of the UI thread +*/ +INT_PTR CALLBACK +k5_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return k5_handle_wm_initdialog(hwnd, wParam, lParam); + + case WM_COMMAND: + return k5_handle_wm_command(hwnd, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return k5_handle_wmnc_notify(hwnd, wParam, lParam); + + case WM_DESTROY: + return k5_handle_wm_destroy(hwnd, wParam, lParam); + } + return FALSE; +} + +/* forward dcl */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]); + + + +fiber_job g_fjob; /* global fiber job object */ + +static BOOL +k5_cached_kinit_prompter(void); + +static BOOL +k5_cp_check_continue(void); + +/* + Runs in the context of the krb5 plugin's slave fiber +*/ +VOID CALLBACK +k5_kinit_fiber_proc(PVOID lpParameter) +{ + while(TRUE) + { + if(g_fjob.command == FIBER_CMD_KINIT) { + g_fjob.state = FIBER_STATE_KINIT; + + g_fjob.prompt_set = 0; + + if (k5_cached_kinit_prompter()) { + SwitchToFiber(k5_main_fiber); + + if (g_fjob.command != FIBER_CMD_CONTINUE) + goto _switch_to_main; + + if (!k5_cp_check_continue()) { + goto _switch_to_main; + } + } + + g_fjob.code = khm_krb5_kinit( + 0, + g_fjob.principal, + g_fjob.password, + g_fjob.ccache, + g_fjob.lifetime, + g_fjob.forwardable, + g_fjob.proxiable, + (g_fjob.renewable ? g_fjob.renew_life : 0), + g_fjob.addressless, + g_fjob.publicIP, + k5_kinit_prompter, + &g_fjob); + } + + _switch_to_main: + g_fjob.state = FIBER_STATE_NONE; + + SwitchToFiber(k5_main_fiber); + } +} + +/* return TRUE if we should go ahead with creds acquisition */ +static BOOL +k5_cp_check_continue(void) { + khm_size i; + khm_size n_p; + khui_new_creds_prompt * p; + size_t cch; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) { +#ifdef DEBUG + assert(FALSE); +#endif + return TRUE; + } + + khui_cw_sync_prompt_values(g_fjob.nc); + + g_fjob.null_password = FALSE; + + /* we are just checking whether there was a password field that + was left empty, in which case we can't continue with the + credentials acquisition. */ + for (i=0; i < n_p; i++) { + if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, + (int) i, + &p))) + continue; + if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + if (p->value == NULL || + FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT, + &cch)) || + cch == 0) { + g_fjob.null_password = TRUE; + return FALSE; + } else + break; + } + } + + return TRUE; +} + +/* returns true if we find cached prompts */ +static BOOL +k5_cached_kinit_prompter(void) { + BOOL rv = FALSE; + khm_handle ident; + khm_handle csp_idconfig = NULL; + khm_handle csp_k5config = NULL; + khm_handle csp_prcache = NULL; + khm_size cb; + khm_size n_cur_prompts; + khm_int32 n_prompts; + khm_int32 i; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + ident = g_fjob.identity; + if (!ident) + return FALSE; + + /* don't need to hold ident, since it is already held in g_fjob + and it doesn't change until we return */ + + if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) || + + KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED, + 0, &csp_k5config)) || + + KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE, + 0, &csp_prcache)) || + + KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount", + &n_prompts)) || + n_prompts == 0) + + goto _cleanup; + + /* check if there are any prompts currently showing. If there are + we check if they are the same as the ones we are going to show. + In which case we just reuse the exisitng prompts */ + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, + &n_cur_prompts)) || + n_prompts != (khm_int32) n_cur_prompts) + goto _show_new_prompts; + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p))) + break; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + + /* the type should match */ + (p_type != p->type) || + + /* if this prompt should be hidden, + then it must also be so */ + (p_flags != p->flags) + ) { + + khc_close_space(csp_p); + break; + + } + + + khc_close_space(csp_p); + } + + if (i == n_prompts) { + rv = TRUE; + goto _cleanup; + } + + _show_new_prompts: + + khui_cw_clear_prompts(g_fjob.nc); + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wpname[KHUI_MAXCCH_PNAME]; + + cb = sizeof(wbanner); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", + wbanner, &cb))) + wbanner[0] = 0; + + cb = sizeof(wpname); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Name", + wpname, &cb))) + wpname[0] = 0; + + khui_cw_begin_custom_prompts(g_fjob.nc, + n_prompts, + (wbanner[0]? wbanner: NULL), + (wpname[0]? wpname: NULL)); + } + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags); + + khc_close_space(csp_p); + } + + if (i < n_prompts) { + khui_cw_clear_prompts(g_fjob.nc); + } else { + rv = TRUE; + } + + _cleanup: + + if (csp_prcache) + khc_close_space(csp_prcache); + + if (csp_k5config) + khc_close_space(csp_k5config); + + if (csp_idconfig) + khc_close_space(csp_idconfig); + + return rv; +} + +/* Runs in the context of the Krb5 plugin's slave fiber */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]) +{ + int i; + khui_new_creds * nc; + krb5_prompt_type * ptypes; + khm_size ncp; + krb5_error_code code = 0; + BOOL new_prompts = TRUE; + + khm_handle csp_prcache = NULL; + + nc = g_fjob.nc; + + if(pkrb5_get_prompt_types) + ptypes = pkrb5_get_prompt_types(context); + else + ptypes = NULL; + + /* check if we are already showing the right prompts */ + khui_cw_get_prompt_count(nc, &ncp); + + if (num_prompts != (int) ncp) + goto _show_new_prompts; + + for (i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khui_new_creds_prompt * p; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p))) + break; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + /* the type should match */ + (ptypes && + ptypes[i] != p->type) || + (!ptypes && + p->type != 0) || + /* if this prompt should be hidden, + then it must also be so */ + (prompts[i].hidden && + !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) || + (!prompts[i].hidden && + (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) + ) + break; + } + + if (i < num_prompts) + goto _show_new_prompts; + + new_prompts = FALSE; + + /* ok. looks like we are already showing the same set of prompts + that we were supposed to show. Sync up the values and go + ahead. */ + khui_cw_sync_prompt_values(nc); + goto _process_prompts; + + _show_new_prompts: + /* special case. if there are no actual input controls involved, + then we have to show an alerter window and pass through */ + if (num_prompts == 0) { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + wchar_t wident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t wfmt[KHUI_MAXCCH_BANNER]; + khm_size cb; + + if (!banner) { + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } else { + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + } + + if (name) { + AnsiStrToUnicode(wname, sizeof(wname), name); + } else { + LoadString(hResModule, + IDS_KRB5_WARNING, + wname, + ARRAYLENGTH(wname)); + } + + cb = sizeof(wident); + if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb))) + wident[0] = L'\0'; + + LoadString(hResModule, + IDS_KRB5_WARN_FMT, + wfmt, + ARRAYLENGTH(wfmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner); + + khui_alert_show_simple(wname, wmsg, KHERR_WARNING); + + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } + + /* in addition to showing new prompts, we also cache the set of + prompts. */ + if(g_fjob.prompt_set == 0) { + khm_handle csp_idconfig = NULL; + khm_handle csp_idk5 = NULL; + + kcdb_identity_get_config(g_fjob.identity, + KHM_FLAG_CREATE, + &csp_idconfig); + + if (csp_idconfig != NULL) + khc_open_space(csp_idconfig, + CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_idk5); + + if (csp_idk5 != NULL) + khc_open_space(csp_idk5, + CSNAME_PROMPTCACHE, + KHM_FLAG_CREATE, + &csp_prcache); + + khc_close_space(csp_idconfig); + khc_close_space(csp_idk5); + } + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + + if(banner) + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + if(name) + AnsiStrToUnicode(wname, sizeof(wname), name); + + khui_cw_clear_prompts(nc); + + khui_cw_begin_custom_prompts( + nc, + num_prompts, + (banner)?wbanner:NULL, + (name)?wname:NULL); + + if (banner && csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + wbanner); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + L""); + + if (name && csp_prcache) + khc_write_string(csp_prcache, + L"Name", + wname); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Name", + L""); + + if (csp_prcache) + khc_write_int32(csp_prcache, + L"PromptCount", + (khm_int32) num_prompts); + } + + for(i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + khui_cw_add_prompt( + nc, + (ptypes?ptypes[i]:0), + wprompt, + NULL, + (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + if (csp_prcache) { + khm_handle csp_p = NULL; + wchar_t wnum[8]; /* should be enough for 10 + million prompts */ + + wnum[0] = 0; + StringCbPrintf(wnum, sizeof(wnum), L"%d", i); + + khc_open_space(csp_prcache, wnum, + KHM_FLAG_CREATE, &csp_p); + + if (csp_p) { + khc_write_string(csp_p, L"Prompt", wprompt); + khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0)); + khc_write_int32(csp_p, L"Flags", + (prompts[i].hidden? + KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + khc_close_space(csp_p); + } + } + } + + if (csp_prcache) { + khc_close_space(csp_prcache); + csp_prcache = NULL; + } + + _process_prompts: + /* switch back to main thread if we showed new prompts */ + if (new_prompts) + SwitchToFiber(k5_main_fiber); + + /* we get here after the user selects an action that either + cancles the credentials acquisition operation or triggers the + actual acquisition of credentials. */ + if(g_fjob.command != FIBER_CMD_CONTINUE && + g_fjob.command != FIBER_CMD_KINIT) { + code = -2; + goto _exit; + } + + g_fjob.null_password = FALSE; + + /* otherwise, we need to get the data back from the UI and + return 0 */ + for(i=0; idata, d->length, wbuf); + if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch))) + d->length = (unsigned int) cch; + else + d->length = 0; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->length = 0; + } + + if (ptypes && + ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD && + d->length == 0) + + g_fjob.null_password = TRUE; + } + + _exit: + + g_fjob.prompt_set++; + + /* entering a NULL password is equivalent to cancelling out */ + if (g_fjob.null_password) + return -2; + else + return code; +} + + +void +k5_read_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khm_int32 i; + + khc_read_int32(conf, L"Renewable", &d->renewable); + khc_read_int32(conf, L"Forwardable", &d->forwardable); + khc_read_int32(conf, L"Proxiable", &d->proxiable); + khc_read_int32(conf, L"Addressless", &d->addressless); + + khc_read_int32(conf, L"DefaultLifetime", &i); + d->tc_lifetime.current = i; + khc_read_int32(conf, L"MaxLifetime", &i); + d->tc_lifetime.max = i; + khc_read_int32(conf, L"MinLifetime", &i); + d->tc_lifetime.min = i; + + khc_read_int32(conf, L"DefaultRenewLifetime", &i); + d->tc_renew.current = i; + khc_read_int32(conf, L"MaxRenewLifetime", &i); + d->tc_renew.max = i; + khc_read_int32(conf, L"MinRenewLifetime", &i); + d->tc_renew.min = i; + + /* however, if this has externally supplied defaults, we have to + use them too. */ + if (d->nc && d->nc->ctx.vparam && + d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) { + LPNETID_DLGINFO pdlginfo; + + pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam; + if (pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.use_defaults == 0) { + d->forwardable = pdlginfo->in.forwardable; + d->addressless = pdlginfo->in.noaddresses; + d->tc_lifetime.current = pdlginfo->in.lifetime; + d->tc_renew.current = pdlginfo->in.renew_till; + + if (pdlginfo->in.renew_till == 0) + d->renewable = FALSE; + else + d->renewable = TRUE; + + d->proxiable = pdlginfo->in.proxiable; + d->publicIP = pdlginfo->in.publicip; + } + } + + /* once we read the new data, in, it is no longer considered + dirty */ + d->dirty = FALSE; +} + +void +k5_write_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khc_write_int32(conf, L"Renewable", d->renewable); + khc_write_int32(conf, L"Forwardable", d->forwardable); + khc_write_int32(conf, L"Proxiable", d->proxiable); + khc_write_int32(conf, L"Addressless", d->addressless); + + khc_write_int32(conf, L"DefaultLifetime", + (khm_int32) d->tc_lifetime.current); + khc_write_int32(conf, L"MaxLifetime", + (khm_int32) d->tc_lifetime.max); + khc_write_int32(conf, L"MinLifetime", + (khm_int32) d->tc_lifetime.min); + + khc_write_int32(conf, L"DefaultRenewLifetime", + (khm_int32) d->tc_renew.current); + khc_write_int32(conf, L"MaxRenewLifetime", + (khm_int32) d->tc_renew.max); + khc_write_int32(conf, L"MinRenewLifetime", + (khm_int32) d->tc_renew.min); + + /* as in k5_read_dlg_params, once we write the data in, the local + data is no longer dirty */ + d->dirty = FALSE; +} + +void +k5_prep_kinit_job(khui_new_creds * nc) +{ + khui_new_creds_by_type * nct; + k5_dlg_data * d; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cbbuf; + size_t size; + khm_handle ident; + LPNETID_DLGINFO pdlginfo; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + return; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + khui_cw_lock_nc(nc); + ident = nc->identities[0]; + kcdb_identity_hold(ident); + khui_cw_unlock_nc(nc); + + cbbuf = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cbbuf); + StringCchLength(idname, ARRAYLENGTH(idname), &size); + size++; + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + g_fjob.command = FIBER_CMD_KINIT; + g_fjob.nc = nc; + g_fjob.nct = nct; + g_fjob.dialog = nct->hwnd_panel; + g_fjob.principal = malloc(size); + UnicodeStrToAnsi(g_fjob.principal, size, idname); + g_fjob.password = NULL; + g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current; + g_fjob.forwardable = d->forwardable; + g_fjob.proxiable = d->proxiable; + g_fjob.renewable = d->renewable; + g_fjob.renew_life = (krb5_deltat) d->tc_renew.current; + g_fjob.addressless = d->addressless; + g_fjob.publicIP = 0; + g_fjob.code = 0; + g_fjob.identity = ident; + g_fjob.prompt_set = 0; + + /* if we have external parameters, we should use them as well */ + if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ) { + wchar_t * t; + + if (pdlginfo->in.ccache[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.ccache, + NETID_CCACHE_NAME_SZ, + &size))) { + g_fjob.ccache = malloc(sizeof(char) * (size + 1)); +#ifdef DEBUG + assert(g_fjob.ccache); +#endif + UnicodeStrToAnsi(g_fjob.ccache, size + 1, + pdlginfo->in.ccache); + + /* this is the same as the output cache */ + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + pdlginfo->in.ccache); + } else { + g_fjob.ccache = NULL; + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + idname); + + khm_krb5_canon_cc_name(pdlginfo->out.ccache, + sizeof(pdlginfo->out.ccache)); + } + + t = khm_get_realm_from_princ(idname); + + if (t) { + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + t); + + if ((t - idname) > 1) { + StringCchCopyN(pdlginfo->out.username, + ARRAYLENGTH(pdlginfo->out.username), + idname, + (t - idname) - 1); + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + L""); + } + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + idname); + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + L""); + } + } + + /* leave identity held, since we added a reference above */ +} + +void +k5_free_kinit_job(void) +{ + if (g_fjob.principal) + free(g_fjob.principal); + + if (g_fjob.password) + free(g_fjob.password); + + if (g_fjob.identity) + kcdb_identity_release(g_fjob.identity); + + if (g_fjob.ccache) + free(g_fjob.ccache); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); +} + +static khm_int32 KHMAPI +k5_find_tgt_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khm_handle ident = (khm_handle) rock; + khm_handle cident = NULL; + khm_int32 f; + khm_int32 rv; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, + &cident)) && + cident == ident && + KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && + (f & KCDB_CRED_FLAG_INITIAL)) + rv = 1; + else + rv = 0; + + if (cident) + kcdb_identity_release(cident); + + return rv; +} + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + + case KMSG_CRED_PASSWORD: + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t wbuf[256]; + size_t cbsize; + + nc = (khui_new_creds *) vparam; + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + nct->ordinal = 1; + + LoadString(hResModule, IDS_KRB5_SHORT_DESC, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = malloc(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->h_module = hResModule; + nct->dlg_proc = k5_nc_dlg_proc; + if (nc->subtype == KMSG_CRED_PASSWORD) + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD); + else + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + HWND hwnd; + wchar_t * realms; + wchar_t * t; + wchar_t * defrealm; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + hwnd = nct->hwnd_panel; + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (!is_k5_identpro) { + + /* enumerate all realms and place in realms combo box */ + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_RESETCONTENT, + 0, 0); + + realms = khm_krb5_get_realm_list(); + if(realms) { + t = realms; + while(t && *t) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_ADDSTRING, + 0, (LPARAM) t); + t = multi_string_next(t); + } + free(realms); + } + + /* and set the default realm */ + defrealm = khm_krb5_get_default_realm(); + if(defrealm) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + WM_SETTEXT, + 0, (LPARAM) defrealm); + free(defrealm); + } + } else { /* if krb5 is the identity provider */ + HWND hw_realms; + + /* in this case, the realm selection is done by the + identity provider prompts. */ + + hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM); +#ifdef DEBUG + assert(hw_realms); +#endif + EnableWindow(hw_realms, FALSE); + } + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + k5_read_dlg_params(csp_params, d); + } + + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } + break; + + case KMSG_CRED_DIALOG_NEW_IDENTITY: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + /* we only load the identity specific defaults if the user + hasn't changed the options */ + khui_cw_lock_nc(nc); + + if(!d->dirty && nc->n_identities > 0 && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + khm_handle h_id = NULL; + khm_handle h_idk5 = NULL; + + do { + if(KHM_FAILED + (kcdb_identity_get_config(nc->identities[0], + 0, + &h_id))) + break; + + if(KHM_FAILED + (khc_open_space(h_id, CSNAME_KRB5CRED, + 0, &h_idk5))) + break; + + if(KHM_FAILED(khc_shadow_space(h_idk5, csp_params))) + break; + + k5_read_dlg_params(h_idk5, d); + + PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } while(FALSE); + + if(h_id) + khc_close_space(h_id); + if(h_idk5) + khc_close_space(h_idk5); + } + + khui_cw_unlock_nc(nc); + } + + /* fallthrough */ + case KMSG_CRED_DIALOG_NEW_OPTIONS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (nc->subtype == KMSG_CRED_PASSWORD) { + khm_size n_prompts = 0; + + khui_cw_get_prompt_count(nc, &n_prompts); + + if (nc->n_identities == 0) { + if (n_prompts) + khui_cw_clear_prompts(nc); + } else if (n_prompts != 3) { + wchar_t wbuf[KHUI_MAXCCH_BANNER]; + + khui_cw_clear_prompts(nc); + + LoadString(hResModule, IDS_NC_PWD_BANNER, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf); + + LoadString(hResModule, IDS_NC_PWD_PWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + } + + return KHM_ERROR_SUCCESS; + } + /* else; nc->subtype == KMSG_CRED_NEW_CREDS */ + + assert(nc->subtype == KMSG_CRED_NEW_CREDS); + + /* if the fiber is already in a kinit, cancel it */ + if(g_fjob.state == FIBER_STATE_KINIT) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + /* we get here when the cancel operation completes */ + k5_free_kinit_job(); + } + + khui_cw_lock_nc(nc); + + if(nc->n_identities > 0) { + khm_handle ident = nc->identities[0]; + + kcdb_identity_hold(ident); + + k5_prep_kinit_job(nc); + khui_cw_unlock_nc(nc); + + SwitchToFiber(k5_kinit_fiber); + /* we get here when the fiber switches back */ + if(g_fjob.state == FIBER_STATE_NONE) { + wchar_t msg[KHUI_MAXCCH_BANNER]; + khm_size cb; + + /* we can't possibly have succeeded without a + password */ + if(g_fjob.code) { + if (is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_INVALID); + + khui_cw_clear_prompts(nc); + } + + if (d->cred_message) { + free(d->cred_message); + d->cred_message = NULL; + } + + msg[0] = L'\0'; + + switch(g_fjob.code) { + case KRB5KDC_ERR_NAME_EXP: + /* principal expired */ + LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + case KRB5KDC_ERR_KEY_EXP: + /* password needs changing */ + LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + default: + { + DWORD dw_dummy; + kherr_suggestion sug_dummy; + wchar_t fmt[KHUI_MAXCCH_BANNER]; + wchar_t desc[KHUI_MAXCCH_BANNER]; + + LoadString(hResModule, IDS_K5ERR_FMT, + fmt, ARRAYLENGTH(fmt)); + + khm_err_describe(g_fjob.code, + desc, + sizeof(desc), + &dw_dummy, + &sug_dummy); + + StringCbPrintf(msg, sizeof(msg), fmt, desc); + } + } + + if (msg[0]) { + StringCbLength(msg, sizeof(msg), &cb); + cb += sizeof(wchar_t); + + d->cred_message = malloc(cb); + StringCbCopy(d->cred_message, cb, msg); + } + + k5_free_kinit_job(); + + } else if(g_fjob.state == FIBER_STATE_KINIT) { + /* this is what we want. Leave the fiber there. */ + + if(is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_VALID); + } else { + /* huh?? */ +#ifdef DEBUG + assert(FALSE); +#endif + } + + /* since the attributes of the identity have changed, + we should update the cred text as well */ + kcdb_identity_release(ident); + khui_cw_lock_nc(nc); + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } else { + khui_cw_unlock_nc(nc); + khui_cw_clear_prompts(nc); + khui_cw_lock_nc(nc); + } + + khui_cw_unlock_nc(nc); + } + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + khm_int32 r; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + /* reset the null_password flag, just in case */ + g_fjob.null_password = FALSE; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + d = (k5_dlg_data *) nct->aux; + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS); + _describe(); + + if (g_fjob.state == FIBER_STATE_KINIT) { + if(nc->result == KHUI_NC_RESULT_CANCEL) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + + /* if we cancelled out, then we shouldn't care + about the return code. */ +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + khui_cw_sync_prompt_values(nc); + g_fjob.command = FIBER_CMD_CONTINUE; + SwitchToFiber(k5_kinit_fiber); + + /* We get back here once the fiber finishes + processing */ + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + } else { + /* we weren't in a KINIT state */ + if (nc->result == KHUI_NC_RESULT_CANCEL) { + /* nothing to report */ + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + /* g_fjob.code should have the result of the + last kinit attempt. We should leave it + as-is */ + } +#ifdef DEBUG + else { + /* unknown result */ + assert(FALSE); + } +#endif + } + + /* special case: if there was no password entered, and + if there is a valid TGT we allow the credential + acquisition to go through */ + if (g_fjob.state == FIBER_STATE_NONE && + g_fjob.code && + g_fjob.null_password && + + (nc->n_identities == 0 || + nc->identities[0] == NULL || + KHM_SUCCEEDED(kcdb_credset_find_filtered + (NULL, + -1, + k5_find_tgt_filter, + nc->identities[0], + NULL, + NULL)))) + g_fjob.code = 0; + + + if(g_fjob.code != 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion suggest_code; + + khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf), + &suggestion, &suggest_code); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion != 0) + _suggest_mr(suggestion, suggest_code); + + _resolve(); + + r = KHUI_NC_RESPONSE_FAILED; + + if (suggest_code == KHERR_SUGGEST_RETRY) { + r |= KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING; + } + +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS && + g_fjob.state == FIBER_STATE_NONE) { + khm_handle sp = NULL; + khm_handle ep = NULL; + krb5_context ctx = NULL; + wchar_t * wbuf; + wchar_t * idname; + wchar_t * atsign; + khm_size cb; + khm_size cb_ms; + khm_int32 rv; + + r = KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT; + + /* if we successfully obtained credentials, we + should save the current settings in the + identity config space */ + + assert(nc->n_identities > 0); + assert(nc->identities[0]); + + if(KHM_SUCCEEDED + (kcdb_identity_get_config(nc->identities[0], + KHM_FLAG_CREATE, + &sp)) && + KHM_SUCCEEDED + (khc_open_space(sp, CSNAME_KRB5CRED, + KHM_FLAG_CREATE, &ep))) { + k5_write_dlg_params(ep, d); + } + + if(ep != NULL) + khc_close_space(ep); + if(sp != NULL) + khc_close_space(sp); + + /* We should also quickly refresh the credentials + so that the identity flags and ccache + properties reflect the current state of + affairs. This has to be done here so that + other credentials providers which depend on + Krb5 can properly find the initial creds to + obtain their respective creds. */ + + khm_krb5_list_tickets(&ctx); + + /* also add the principal and the realm in to the + LRU lists */ + rv = kcdb_identity_get_name(nc->identities[0], + NULL, + &cb); + assert(rv == KHM_ERROR_TOO_LONG); + + idname = malloc(cb); + assert(idname); + + rv = kcdb_identity_get_name(nc->identities[0], + idname, + &cb); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + if (rv != KHM_ERROR_TOO_LONG) + cb_ms = cb + sizeof(wchar_t); + else + cb_ms += cb + sizeof(wchar_t); + + wbuf = malloc(cb_ms); + assert(wbuf); + + cb = cb_ms; + + if (rv == KHM_ERROR_TOO_LONG) { + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + wbuf, + &cb); + assert(KHM_SUCCEEDED(rv)); + + if (multi_string_find(wbuf, + idname, + KHM_CASE_SENSITIVE) + != NULL) + /* it's already there */ + goto _add_realm_to_LRU; + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, &cb, idname); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_multi_string(csp_params, + L"LRUPrincipals", + wbuf); + + _add_realm_to_LRU: + + atsign = wcschr(idname, L'@'); + assert(atsign != NULL); + + atsign++; + assert(*atsign != L'\0'); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + if (rv == KHM_ERROR_TOO_LONG) { + free(wbuf); + wbuf = malloc(cb); + assert(wbuf); + + cb_ms = cb; + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + assert(KHM_SUCCEEDED(rv)); + } else if (rv == KHM_ERROR_SUCCESS) { + if (multi_string_find(wbuf, + atsign, + KHM_CASE_SENSITIVE) + != NULL) + goto _done_with_LRU; + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + if (rv == KHM_ERROR_TOO_LONG) { + wbuf = realloc(wbuf, cb); + + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + assert(KHM_SUCCEEDED(rv)); + } + + rv = khc_write_multi_string(csp_params, + L"LRURealms", + wbuf); + assert(KHM_SUCCEEDED(rv)); + + _done_with_LRU: + + if (ctx != NULL) + pkrb5_free_context(ctx); + + if (idname) + free(idname); + + if (wbuf) + free(wbuf); + } else if (g_fjob.state == FIBER_STATE_NONE) { + /* the user cancelled the operation */ + r = KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS; + } + + if(g_fjob.state == FIBER_STATE_NONE) { + khui_cw_set_response(nc, credtype_id_krb5, r); + + if (r & KHUI_NC_RESPONSE_NOEXIT) { + /* if we are retrying the call, we should + restart the kinit fiber */ +#ifdef DEBUG + assert(r & KHUI_NC_RESPONSE_PENDING); +#endif + + k5_prep_kinit_job(nc); + SwitchToFiber(k5_kinit_fiber); + } else { + /* free up the fiber data fields. */ + k5_free_kinit_job(); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING | r); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS); + _describe(); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT || + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb5)) { + int code; + + if (nc->ctx.identity != 0) + code = khm_krb5_renew(nc->ctx.identity); + else + code = 1; /* it just has to be non-zero */ + + if (code == 0) { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } else if (nc->ctx.identity == 0) { + + _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + } else { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) | + KHUI_NC_RESPONSE_FAILED); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_PASSWORD && + nc->result == KHUI_NC_RESULT_GET_CREDS) { + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); + _describe(); + + khui_cw_lock_nc(nc); + + if (nc->n_identities == 0 || + nc->identities[0] == NULL) { + _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY); + _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_NOEXIT); + } else { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wpwd[KHUI_MAXCCH_PASSWORD]; + char pwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd[KHUI_MAXCCH_PASSWORD]; + char npwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD]; + wchar_t * wresult; + char * result; + khm_size n_prompts = 0; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + long code = 0; + khm_handle ident; + + khui_cw_get_prompt_count(nc, &n_prompts); + assert(n_prompts == 3); + + ident = nc->identities[0]; + cb = sizeof(widname); + rv = kcdb_identity_get_name(ident, widname, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wpwd); + rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd); + rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd2); + rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + if (wcscmp(wnpwd, wnpwd2)) { + rv = KHM_ERROR_INVALID_PARM; + _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME); + _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + if (!wcscmp(wpwd, wnpwd)) { + rv = KHM_ERROR_INVALID_PARM; + _report_mr0(KHERR_ERROR, MSG_PWD_SAME); + _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd); + + result = NULL; + + code = khm_krb5_changepwd(idname, + pwd, + npwd, + &result); + + if (code) + rv = KHM_ERROR_UNKNOWN; + + /* result is only set when code != 0 */ + if (code && result) { + size_t len; + + StringCchLengthA(result, KHERR_MAXCCH_STRING, + &len); + wresult = malloc((len + 1) * sizeof(wchar_t)); +#ifdef DEBUG + assert(wresult); +#endif + AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t), + result); + + _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult)); + _resolve(); + + free(result); + free(wresult); + + /* leave wresult. It will get freed when the + reported event is freed. */ + + /* we don't need to report anything more */ + code = 0; + } + + _pwd_exit: + if (KHM_FAILED(rv)) { + if (code) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + _report_cs0(KHERR_ERROR, tbuf); + + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + } + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT| + KHUI_NC_RESPONSE_FAILED); + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + } + } + + khui_cw_unlock_nc(nc); + + _end_task(); + } /* KMSG_CRED_PASSWORD */ + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + khui_cw_del_type(nc, credtype_id_krb5); + + if(nct->name) + free(nct->name); + + free(nct); + } + break; + + case KMSG_CRED_IMPORT: + { + khm_krb5_ms2mit(TRUE); + } + break; + } + + return rv; +} diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c new file mode 100644 index 0000000..4b53ed3 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5plugin.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include + +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; +khm_boolean krb5_initialized = FALSE; +khm_handle krb5_credset = NULL; + +khm_handle k5_sub = NULL; + +LPVOID k5_main_fiber = NULL; +LPVOID k5_kinit_fiber = NULL; + +VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter); + +krb5_context k5_identpro_ctx = NULL; + +/* The system message handler. + + Runs in the context of the plugin thread */ +khm_int32 KHMAPI k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB5_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = malloc(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB5_LONG_DESC, buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = malloc(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + + kmq_create_subscription(k5_msg_callback, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb5_credset); + + if(ct.short_desc) + free(ct.short_desc); + + if(ct.long_desc) + free(ct.long_desc); + + if (is_k5_identpro) + kcdb_identity_set_type(credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) { + krb5_context ctx = NULL; + + krb5_initialized = TRUE; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + + /* now convert this thread to a fiber and create a + separate fiber to do kinit stuff */ + k5_main_fiber = ConvertThreadToFiber(NULL); + k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + + kmq_create_subscription(k5_msg_callback, &k5_sub); + + pkrb5_init_context(&k5_identpro_ctx); + + k5_register_config_panels(); + } + } + break; + + case KMSG_SYSTEM_EXIT: + + k5_unregister_config_panels(); + + if(credtype_id_krb5 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb5); + + /* kcdb knows how to deal with bad handles */ + kcdb_credset_delete(krb5_credset); + krb5_credset = NULL; + } + + if(k5_main_fiber != NULL) { + ConvertFiberToThread(); + k5_main_fiber = NULL; + } + + if(k5_sub != NULL) { + kmq_delete_subscription(k5_sub); + k5_sub = NULL; + } + + if (k5_identpro_ctx) { + pkrb5_free_context(k5_identpro_ctx); + k5_identpro_ctx = NULL; + } + + break; + } + + return rv; +} + + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + krb5_context ctx = NULL; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + + ctx = (khui_action_context *) vparam; + + if (ctx->credset) + khm_krb5_destroy_by_credset(ctx->credset); + } + break; + + case KMSG_CRED_PP_BEGIN: + k5_pp_begin((khui_property_sheet *) vparam); + break; + + case KMSG_CRED_PP_END: + k5_pp_end((khui_property_sheet *) vparam); + break; + + default: + if(IS_CRED_ACQ_MSG(msg_subtype)) + return k5_msg_cred_dialog(msg_type, msg_subtype, + uparam, vparam); + } + + return rv; +} + +/* The main message handler. We don't do much here, except delegate + to other message handlers + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return k5_msg_cred(msg_type, msg_subtype, uparam, vparam); + case KMSG_IDENT: + return k5_msg_ident(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5props.c b/src/windows/identity/plugins/krb5/krb5props.c new file mode 100644 index 0000000..9134de2 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5props.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include + +/* Property page + + Runs in the context of the UI thread. + */ +INT_PTR CALLBACK krb5_pp_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + wchar_t buf[512]; + khm_size cbsize; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + if(s->cred) { + cbsize = sizeof(buf); + kcdb_cred_get_name(s->cred, buf, &cbsize); + SetDlgItemText(hwnd, IDC_PPK5_NAME, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_ISSUE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_EXPIRE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_VALID, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_RENEW_EXPIRE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf); + + /*TODO: select other properties */ + } else { + /*TODO: select properties */ + } + } + return FALSE; + } + + return FALSE; +} + +void k5_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->credtype == credtype_id_krb5) { + p = malloc(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = hResModule; + p->pszTemplate = (s->cred)? MAKEINTRESOURCE(IDD_PP_KRB5C): MAKEINTRESOURCE(IDD_PP_KRB5); + p->pfnDlgProc = krb5_pp_proc; + p->lParam = (LPARAM) s; + khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL); + } +} + +void k5_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, credtype_id_krb5, &p); + if(p) { + if(p->p_page) + free(p->p_page); + p->p_page = NULL; + } +} + diff --git a/src/windows/identity/plugins/krb5/krb5util.c b/src/windows/identity/plugins/krb5/krb5util.c new file mode 100644 index 0000000..b892531 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5util.c @@ -0,0 +1,1362 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include "leashdll.h" +#include +#include +#include + +#include +#include "leasherr.h" +#include "leash-int.h" +#include "leashids.h" + +#include + +#include +#include "reminder.h" + +static char FAR *err_context; + +char KRB_HelpFile[_MAX_PATH] = HELPFILE; + +#define LEN 64 /* Maximum Hostname Length */ + +#define LIFE DEFAULT_TKT_LIFE /* lifetime of ticket in 5-minute units */ + +char * +short_date(dp) + long *dp; +{ + register char *cp; + cp = ctime(dp) + 4; // skip day of week + // cp[15] = '\0'; + cp[12] = '\0'; // Don't display seconds + return (cp); +} + + +static +char* +clean_string( + char* s + ) +{ + char* p = s; + char* b = s; + + if (!s) return s; + + for (p = s; *p; p++) { + switch (*p) { + case '\007': + /* Add more cases here */ + break; + default: + *b = *p; + b++; + } + } + *b = *p; + return s; +} + +static +int +leash_error_message( + const char *error, + int rcL, + int rc4, + int rc5, + int rcA, + char* result_string, + int displayMB + ) +{ + char message[2048]; + char *p = message; + int size = sizeof(message); + int n; + + // XXX: ignore AFS for now. + + if (!rc5 && !rc4 && !rcL) + return 0; + + n = _snprintf(p, size, "%s\n\n", error); + p += n; + size -= n; + + if (rc5 && !result_string) + { + n = _snprintf(p, size, + "Kerberos 5: %s (error %ld)\n", + perror_message(rc5), + rc5 & 255 // XXX: & 255??!!! + ); + p += n; + size -= n; + } + if (rc4 && !result_string) + { + char buffer[1024]; + n = _snprintf(p, size, + "Kerberos 4: %s\n", + err_describe(buffer, rc4) + ); + p += n; + size -= n; + } + if (rcL) + { + char buffer[1024]; + n = _snprintf(p, size, + "\n%s\n", + err_describe(buffer, rcL) + ); + p += n; + size -= n; + } + if (result_string) + { + n = _snprintf(p, size, + "%s\n", + result_string); + p += n; + size -= n; + } + if ( displayMB ) + MessageBox(NULL, message, "Leash", MB_OK | MB_ICONERROR | MB_TASKMODAL | + MB_SETFOREGROUND); + + if (rc5) return rc5; + if (rc4) return rc4; + if (rcL) return rcL; + return 0; +} + + +static +char * +make_postfix( + const char * base, + const char * postfix, + char ** rcopy + ) +{ + int base_size; + int ret_size; + char * copy = 0; + char * ret = 0; + + base_size = strlen(base) + 1; + ret_size = base_size + strlen(postfix) + 1; + copy = malloc(base_size); + ret = malloc(ret_size); + + if (!copy || !ret) + goto cleanup; + + strncpy(copy, base, base_size); + copy[base_size - 1] = 0; + + strncpy(ret, base, base_size); + strncpy(ret + (base_size - 1), postfix, ret_size - (base_size - 1)); + ret[ret_size - 1] = 0; + + cleanup: + if (!copy || !ret) { + if (copy) + free(copy); + if (ret) + free(ret); + copy = ret = 0; + } + // INVARIANT: (ret ==> copy) && (copy ==> ret) + *rcopy = copy; + return ret; +} + +static +long +make_temp_cache_v4( + const char * postfix + ) +{ + static char * old_cache = 0; + + if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) + return 0; // XXX - is this appropriate? + + if (old_cache) { + pdest_tkt(); + pkrb_set_tkt_string(old_cache); + free(old_cache); + old_cache = 0; + } + + if (postfix) + { + char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); + + if (!tmp_cache) + return KFAILURE; + + pkrb_set_tkt_string(tmp_cache); + free(tmp_cache); + } + return 0; +} + +static +long +make_temp_cache_v5( + const char * postfix, + krb5_context * pctx + ) +{ + static krb5_context ctx = 0; + static char * old_cache = 0; + + // INVARIANT: old_cache ==> ctx && ctx ==> old_cache + + if (pctx) + *pctx = 0; + + if (!pkrb5_init_context || !pkrb5_free_context || !pkrb5_cc_resolve || + !pkrb5_cc_default_name || !pkrb5_cc_set_default_name) + return 0; + + if (old_cache) { + krb5_ccache cc = 0; + if (!pkrb5_cc_resolve(ctx, pkrb5_cc_default_name(ctx), &cc)) + pkrb5_cc_destroy(ctx, cc); + pkrb5_cc_set_default_name(ctx, old_cache); + free(old_cache); + old_cache = 0; + } + if (ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + + if (postfix) + { + char * tmp_cache = 0; + krb5_error_code rc = 0; + + rc = pkrb5_init_context(&ctx); + if (rc) goto cleanup; + + tmp_cache = make_postfix(pkrb5_cc_default_name(ctx), postfix, + &old_cache); + + if (!tmp_cache) { + rc = ENOMEM; + goto cleanup; + } + + rc = pkrb5_cc_set_default_name(ctx, tmp_cache); + + cleanup: + if (rc && ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + if (tmp_cache) + free(tmp_cache); + if (pctx) + *pctx = ctx; + return rc; + } + return 0; +} + +long +Leash_checkpwd( + char *principal, + char *password + ) +{ + return Leash_int_checkpwd(principal, password, 0); +} + +long +Leash_int_checkpwd( + char * principal, + char * password, + int displayErrors + ) +{ + long rc = 0; + krb5_context ctx = 0; // statically allocated in make_temp_cache_v5 + // XXX - we ignore errors in make_temp_cache_v? This is BAD!!! + make_temp_cache_v4("_checkpwd"); + make_temp_cache_v5("_checkpwd", &ctx); + rc = Leash_int_kinit_ex( ctx, 0, + principal, password, 0, 0, 0, 0, + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + displayErrors + ); + make_temp_cache_v4(0); + make_temp_cache_v5(0, &ctx); + return rc; +} + +static +long +Leash_changepwd_v5(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + DWORD addressless = 0; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { +#if 0 + com_err(argv[0], ret, "initializing kerberos library"); +#endif + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { +#if 0 + com_err(argv[0], ret, "parsing client name"); +#endif + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + + addressless = Leash_get_default_noaddresses(); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, password, + 0, 0, 0, "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = malloc(len + 1); + if (*error_str) + _snprintf(*error_str, len + 1, + "%.*s%s%.*s", + result_code_string.length, result_code_string.data, + result_string.length?": ":"", + result_string.length, result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} + +static +long +Leash_changepwd_v4( + char * principal, + char * password, + char * newpassword, + char** error_str + ) +{ + long k_errno; + + if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || + !pdest_tkt) + return KFAILURE; + + k_errno = make_temp_cache_v4("_chgpwd"); + if (k_errno) return k_errno; + k_errno = pkadm_change_your_password(principal, password, newpassword, + error_str); + make_temp_cache_v4(0); + return k_errno; +} + +/* + * Leash_changepwd + * + * Try to change the password using one of krb5 or krb4 -- whichever one + * works. We return ok on the first one that works. + */ +long +Leash_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string + ) +{ + return Leash_int_changepwd(principal, password, newpassword, result_string, 0); +} + +long +Leash_int_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string, + int displayErrors + ) +{ + char* v5_error_str = 0; + char* v4_error_str = 0; + char* error_str = 0; + int rc4 = 0; + int rc5 = 0; + int rc = 0; + if (hKrb5) + rc = rc5 = Leash_changepwd_v5(principal, password, newpassword, + &v5_error_str); + if (hKrb4 && + Leash_get_default_use_krb4() && + (!hKrb5 || rc5)) + rc = rc4 = Leash_changepwd_v4(principal, password, newpassword, + &v4_error_str); + if (!rc) + return 0; + if (v5_error_str || v4_error_str) { + int len = 0; + char v5_prefix[] = "Kerberos 5: "; + char sep[] = "\n"; + char v4_prefix[] = "Kerberos 4: "; + + clean_string(v5_error_str); + clean_string(v4_error_str); + + if (v5_error_str) + len += sizeof(sep) + sizeof(v5_prefix) + strlen(v5_error_str) + + sizeof(sep); + if (v4_error_str) + len += sizeof(sep) + sizeof(v4_prefix) + strlen(v4_error_str) + + sizeof(sep); + error_str = malloc(len + 1); + if (error_str) { + char* p = error_str; + int size = len + 1; + int n; + if (v5_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v5_prefix, v5_error_str, sep); + p += n; + size -= n; + } + if (v4_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v4_prefix, v4_error_str, sep); + p += n; + size -= n; + } + if (result_string) + *result_string = error_str; + } + } + return leash_error_message("Error while changing password.", + rc4, rc4, rc5, 0, error_str, + displayErrors + ); +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + + +long +Leash_kinit( + char * principal, + char * password, + int lifetime + ) +{ + return Leash_int_kinit_ex( 0, 0, + principal, + password, + lifetime, + Leash_get_default_forwardable(), + Leash_get_default_proxiable(), + Leash_get_default_renew_till(), + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + 0 + ); +} + +long +Leash_kinit_ex( + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip + ) +{ + return Leash_int_kinit_ex( 0, /* krb5 context */ + 0, /* parent window */ + principal, + password, + lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip, + 0 + ); +} + +long +Leash_int_kinit_ex( + krb5_context ctx, + HWND hParent, + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip, + int displayErrors + ) +{ + LPCSTR functionName; + char aname[ANAME_SZ]; + char inst[INST_SZ]; + char realm[REALM_SZ]; + char first_part[256]; + char second_part[256]; + char temp[1024]; + int count; + int i; + int rc4 = 0; + int rc5 = 0; + int rcA = 0; + int rcL = 0; + + if (lifetime < 5) + lifetime = 1; + else + lifetime /= 5; + + if (renew_life > 0 && renew_life < 5) + renew_life = 1; + else + renew_life /= 5; + + /* This should be changed if the maximum ticket lifetime */ + /* changes */ + + if (lifetime > 255) + lifetime = 255; + + err_context = "parsing principal"; + + memset(temp, '\0', sizeof(temp)); + memset(inst, '\0', sizeof(inst)); + memset(realm, '\0', sizeof(realm)); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + + sscanf(principal, "%[/0-9a-zA-Z._-]@%[/0-9a-zA-Z._-]", first_part, second_part); + strcpy(temp, first_part); + strcpy(realm, second_part); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + if (sscanf(temp, "%[@0-9a-zA-Z._-]/%[@0-9a-zA-Z._-]", first_part, second_part) == 2) + { + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + count = 0; + i = 0; + for (i = 0; temp[i]; i++) + { + if (temp[i] == '.') + ++count; + } + if (count > 1) + { + strcpy(aname, temp); + } + else + { + if (pkname_parse != NULL) + { + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + sscanf(temp, "%[@/0-9a-zA-Z_-].%[@/0-9a-zA-Z_-]", first_part, second_part); + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + strcpy(aname, temp); + } + } + } + + memset(temp, '\0', sizeof(temp)); + strcpy(temp, aname); + if (strlen(inst) != 0) + { + strcat(temp, "/"); + strcat(temp, inst); + } + if (strlen(realm) != 0) + { + strcat(temp, "@"); + strcat(temp, realm); + } + + rc5 = Leash_krb5_kinit(ctx, hParent, + temp, password, lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip + ); + if ( Leash_get_default_use_krb4() ) { + if ( !rc5 ) { + if (!Leash_convert524(ctx)) + rc4 = KFAILURE; + } else { + if (pkname_parse == NULL) + { + goto cleanup; + } + + err_context = "getting realm"; + if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_FAILEDREALM; + goto cleanup; + } + + err_context = "checking principal"; + if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_INVPRINCIPAL; + goto cleanup; + } + + /* optional instance */ + if (!(rc4 = (int)(*pk_isinst)(inst))) + { + functionName = "k_isinst()"; + rcL = LSH_INVINSTANCE; + goto cleanup; + } + + if (!(rc4 = (int)(*pk_isrealm)(realm))) + { + functionName = "k_isrealm()"; + rcL = LSH_INVREALM; + goto cleanup; + } + + err_context = "fetching ticket"; + rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, + lifetime, password); + if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ + { + functionName = "krb_get_pw_in_tkt()"; + rcL = KRBERR(rc4); + goto cleanup; + } + } + } + +#ifndef NO_AFS + if ( !rc5 || (Leash_get_default_use_krb4() && !rc4) ) { + char c; + char *r; + char *t; + for ( r=realm, t=temp; c=*r; r++,t++ ) + *t = isupper(c) ? tolower(c) : c; + *t = '\0'; + + rcA = Leash_afs_klog("afs", temp, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + } +#endif /* NO_AFS */ + + cleanup: + return leash_error_message("Ticket initialization failed.", + rcL, (rc5 && rc4)?KRBERR(rc4):0, rc5, rcA, 0, + displayErrors); +} + +long FAR +Leash_renew(void) +{ + if ( hKrb5 && !LeashKRB5_renew() ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + TicketList * list = NULL, * token; + afs_get_tokens(NULL,&list,NULL); + for ( token = list ; token ; token = token->next ) + Leash_afs_klog("afs", token->realm, "", lifetime); + not_an_API_LeashFreeTicketList(&list); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData || !pLsaGetLogonSessionData) + 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; +} + +// 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 +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) + { + lstrcpyn (buffer, usBuffer, usLength); + lstrcat (buffer,L""); + if ( !lstrcmp(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +// This looks really ugly because it is. The result of IsKerberosLogon() +// does not prove whether or not there are Kerberos tickets available to +// be imported. Only the call to khm_krb5_ms2mit() which actually attempts +// to import tickets can do that. However, calling khm_krb5_ms2mit() can +// result in a TGS_REQ being sent to the KDC and since Leash_importable() +// is called quite often we want to avoid this if at all possible. +// Unfortunately, we have be shown at least one case in which the primary +// authentication package was not Kerberos and yet there were Kerberos +// tickets available. Therefore, if IsKerberosLogon() is not TRUE we +// must call khm_krb5_ms2mit() but we still do not want to call it in a +// tight loop so we cache the response and assume it won't change. +long FAR +Leash_importable(void) +{ + if ( IsKerberosLogon() ) + return TRUE; + else { + static int response = -1; + if (response == -1) { + response = khm_krb5_ms2mit(0); + } + return response; + } +} + +long FAR +Leash_import(void) +{ + if ( khm_krb5_ms2mit(1) ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + char c; + char *r; + char *t; + char cell[256]; + char realm[256]; + int i = 0; + int rcA = 0; + + krb5_context ctx = 0; + krb5_error_code code = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + for ( r=realm, t=cell, i=0; ilength; r++,t++,i++ ) { + c = krb5_princ_realm(ctx, me)->data[i]; + *r = c; + *t = isupper(c) ? tolower(c) : c; + } + *r = *t = '\0'; + + rcA = Leash_afs_klog("afs", cell, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + + cleanup: + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +long +Leash_kdestroy(void) +{ + int k_errno; + + Leash_afs_unlog(); + khm_krb5_destroy_identity(NULL); + + if (pdest_tkt != NULL) + { + k_errno = (*pdest_tkt)(); + if (k_errno && (k_errno != RET_TKFIL)) + return KRBERR(k_errno); + } + + return 0; +} + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; +// char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + strcpy(loc_addr,inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + +long FAR +not_an_API_LeashFreeTicketList(TicketList** ticketList) +{ + TicketList* tempList = *ticketList, *killList; + + //if (tempList == NULL) + //return -1; + + while (tempList) + { + killList = tempList; + + tempList = (TicketList*)tempList->next; + free(killList->theTicket); + if (killList->tktEncType) + free(killList->tktEncType); + if (killList->keyEncType) + free(killList->keyEncType); + if (killList->addrCount) { + int n; + for ( n=0; naddrCount; n++) { + if (killList->addrList[n]) + free(killList->addrList[n]); + } + } + if (killList->addrList) + free(killList->addrList); + if (killList->name) + free(killList->name); + if (killList->inst) + free(killList->inst); + if (killList->realm) + free(killList->realm); + free(killList); + } + + *ticketList = NULL; + return 0; +} + + +long FAR Leash_klist(HWND hlist, TICKETINFO FAR *ticketinfo) +{ + // Don't think this function will be used anymore - ADL 5-15-99 + // Old fucntion to put tickets in a listbox control + // Use function "not_an_API_LeashKRB4GetTickets()" instead! + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + char buf[MAX_K_NAME_SZ+40]; + LPSTR cp; + long expdate; + int k_errno; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + + /* + * Since krb_get_tf_realm will return a ticket_file error, + * we will call tf_init and tf_close first to filter out + * things like no ticket file. Otherwise, the error that + * the user would see would be + * klist: can't find realm of ticket file: No ticket file (tf_util) + * instead of + * klist: No ticket file (tf_util) + */ + if (ptf_init == NULL) + return(KSUCCESS); + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, FALSE, 0L); + SendMessage(hlist, LB_RESETCONTENT, 0, 0L); + } + com_addr(); + newtickets = NO_TICKETS; + + err_context = (LPSTR)"tktf1"; + + /* Open ticket file */ + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + /* Close ticket file */ + (void) (*ptf_close)(); + /* + * We must find the realm of the ticket file here before calling + * tf_init because since the realm of the ticket file is not + * really stored in the principal section of the file, the + * routine we use must itself call tf_init and tf_close. + */ + err_context = "tf realm"; + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + /* Open ticket file */ + err_context = "tf init"; + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + open = 1; + err_context = "tf pname"; + /* Get principal name and instance */ + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + /* + * You may think that this is the obvious place to get the + * realm of the ticket file, but it can't be done here as the + * routine to do this must open the ticket file. This is why + * it was done before tf_init. + */ + + wsprintf((LPSTR)ticketinfo->principal,"%s%s%s%s%s", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + newtickets = GOOD_TICKETS; + + err_context = "tf cred"; + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + expdate = c.issue_date + c.lifetime * 5L * 60L; + + if (!lstrcmp((LPSTR)c.service, (LPSTR)TICKET_GRANTING_TICKET) && !lstrcmp((LPSTR)c.instance, (LPSTR)prealm)) + { + ticketinfo->issue_date = c.issue_date; + ticketinfo->lifetime = c.lifetime * 5L * 60L; + ticketinfo->renew_till = 0; + } + + cp = (LPSTR)buf; + lstrcpy(cp, (LPSTR)short_date(&c.issue_date)); + cp += lstrlen(cp); + wsprintf(cp,"\t%s\t%s%s%s%s%s", + (LPSTR)short_date(&expdate), (LPSTR)c.service, + (LPSTR)(c.instance[0] ? "." : ""), + (LPSTR)c.instance, (LPSTR)(c.realm[0] ? "@" : ""), + (LPSTR) c.realm); + if (hlist) + SendMessage(hlist, LB_ADDSTRING, 0, (LONG)(LPSTR)buf); + } /* WHILE */ + +cleanup: + + if (open) + (*ptf_close)(); /* close ticket file */ + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, TRUE, 0L); + InvalidateRect(hlist, NULL, TRUE); + UpdateWindow(hlist); + } + if (k_errno == EOF) + k_errno = 0; + + /* XXX the if statement directly below was inserted to eliminate + an error 20 on Leash startup. The error occurs from an error + number thrown from krb_get_tf_realm. We believe this change + does not eliminate other errors, but it may. */ + + if (k_errno == RET_NOTKT) + k_errno = 0; + + ticketinfo->btickets = newtickets; + if (k_errno != 0) + return KRBERR(k_errno); + return 0; +} + + + +static BOOL CALLBACK +EnumChildProc(HWND hwnd, LPARAM lParam) +{ + HWND * h = (HWND *)lParam; + *h = hwnd; + return FALSE; +} + + +static HWND +FindFirstChildWindow(HWND parent) +{ + HWND hFirstChild = 0; + EnumChildWindows(parent, EnumChildProc, (LPARAM) &hFirstChild); + return hFirstChild; +} + +void FAR +not_an_API_Leash_AcquireInitialTicketsIfNeeded(krb5_context context, krb5_principal desiredKrb5Principal) +{ + krb5_error_code err; + LSH_DLGINFO_EX dlginfo; + HGLOBAL hData; + HWND hLeash; + HWND hForeground; + char *desiredName = 0; + char *desiredRealm = 0; + char *p; + TicketList * list = NULL; + TICKETINFO ticketinfo; + krb5_context ctx; + char newenv[256]; + char * env = 0; + DWORD dwMsLsaImport = Leash_get_default_mslsa_import(); + + char loginenv[16]; + BOOL prompt; + + GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv)); + prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); + + if ( !prompt || !pkrb5_init_context ) + return; + + ctx = context; + env = getenv("KRB5CCNAME"); + if ( !env && context ) { + sprintf(newenv,"KRB5CCNAME=%s",pkrb5_cc_default_name(ctx)); + env = (char *)putenv(newenv); + } + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + + if ( ticketinfo.btickets != GOOD_TICKETS && + Leash_get_default_mslsa_import() && Leash_importable() ) { + // We have the option of importing tickets from the MSLSA + // but should we? Do the tickets in the MSLSA cache belong + // to the default realm used by Leash? If so, import. + int import = 0; + + if ( dwMsLsaImport == 1 ) { /* always import */ + import = 1; + } else if ( dwMsLsaImport == 2 ) { /* import when realms match */ + krb5_error_code code; + krb5_ccache mslsa_ccache=0; + krb5_principal princ = 0; + char ms_realm[128] = "", *def_realm = 0, *r; + int i; + + if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ)) + goto cleanup; + + for ( r=ms_realm, i=0; ilength; r++, i++ ) { + *r = krb5_princ_realm(ctx, princ)->data[i]; + } + *r = '\0'; + + if (code = pkrb5_get_default_realm(ctx, &def_realm)) + goto cleanup; + + import = !strcmp(def_realm, ms_realm); + + cleanup: + if (def_realm) + pkrb5_free_default_realm(ctx, def_realm); + + if (princ) + pkrb5_free_principal(ctx, princ); + + if (mslsa_ccache) + pkrb5_cc_close(ctx, mslsa_ccache); + } + + if ( import ) { + Leash_import(); + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + } + } + + if ( ticketinfo.btickets != GOOD_TICKETS ) + { + /* do we want a specific client principal? */ + if (desiredKrb5Principal != NULL) { + err = pkrb5_unparse_name (ctx, desiredKrb5Principal, &desiredName); + if (!err) { + dlginfo.username = desiredName; + for (p = desiredName; *p && *p != '@'; p++); + if ( *p == '@' ) { + *p = '\0'; + desiredRealm = dlginfo.realm = ++p; + } + } + } + +#ifdef COMMENT + memset(&dlginfo, 0, sizeof(LSH_DLGINFO_EX)); + dlginfo.size = sizeof(LSH_DLGINFO_EX); + dlginfo.dlgtype = DLGTYPE_PASSWD; + dlginfo.title = "Obtain Kerberos Ticket Getting Tickets"; + dlginfo.use_defaults = 1; + + err = Leash_kinit_dlg_ex(NULL, &dlginfo); +#else + /* construct a marshalling of data + * <principal><realm> + * then send to Leash + */ + + hData = GlobalAlloc( GHND, 4096 ); + hForeground = GetForegroundWindow(); + hLeash = FindWindow("LEASH.0WNDCLASS", NULL); + SetForegroundWindow(hLeash); + hLeash = FindFirstChildWindow(hLeash); + if ( hData && hLeash ) { + char * strs = GlobalLock( hData ); + if ( strs ) { + strcpy(strs, "Obtain Kerberos Ticket Getting Tickets"); + strs += strlen(strs) + 1; + if ( desiredName ) { + strcpy(strs, desiredName); + strs += strlen(strs) + 1; + if (desiredRealm) { + strcpy(strs, desiredRealm); + strs += strlen(strs) + 1; + } + } else { + *strs = 0; + strs++; + *strs = 0; + strs++; + } + + GlobalUnlock( hData ); + SendMessage(hLeash, 32809, 0, (LPARAM) hData); + } + + GlobalFree( hData ); + } + SetForegroundWindow(hForeground); +#endif + if (desiredName != NULL) + pkrb5_free_unparsed_name(ctx, desiredName); + } + + if ( !env && context ) + putenv("KRB5CCNAME="); + + if ( !context ) + pkrb5_free_context(ctx); +} diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv new file mode 100644 index 0000000..c577eec --- /dev/null +++ b/src/windows/identity/plugins/krb5/krbconfig.csv @@ -0,0 +1,34 @@ +Name,Type,Value,Description +Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider + Module,KC_STRING,MITKrb5, + Description,KC_STRING,Kerberos V Credentials Provider, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + CreateMissingConfig,KC_INT32,0,Create missing configuration files + MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials + AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) + Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) + Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + Renewable,KC_INT32,1,Obtain renewable tickets (boolean) + DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime + MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime + MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime + LRURealms,KC_STRING,, + LRUPrincipals,KC_STRING,, + PromptCache,KC_SPACE,0,Cache of prompts (only per identity) + Name,KC_STRING,, + Banner,KC_STRING,, + PromptCount,KC_INT32,0, + (n),KC_SPACE,0,Parameters for each prompt + Prompt,KC_STRING,, + Type,KC_INT32,0, + Flags,KC_INT32,0, + (n),KC_ENDSPACE,0, + PromptCache,KC_ENDSPACE,0, + Parameters,KC_ENDSPACE,0, +Krb5Cred,KC_ENDSPACE,0, diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h new file mode 100644 index 0000000..08978f1 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krbcred.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include<windows.h> + +/* While we generally pull resources out of hResModule, the message + strings for all the languages are kept in the main DLL. */ +#define KHERR_HMODULE hInstance +#define KHERR_FACILITY k5_facility +#define KHERR_FACILITY_ID 64 + +#include<khdefs.h> +#include<kcreddb.h> +#include<kmm.h> +#include<kconfig.h> +#include<khuidefs.h> +#include<kherr.h> + +#include<krb5funcs.h> +#include<krb5common.h> +#include<errorfuncs.h> +#include<dynimport.h> + +#include<langres.h> +#include<datarep.h> +#include<krb5_msgs.h> + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_KRB5_CCNAME L"Krb5CCName" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; +extern const wchar_t * k5_facility; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_krb5_ccname; + +/* Configuration spaces */ +#define CSNAME_KRB5CRED L"Krb5Cred" +#define CSNAME_PARAMS L"Parameters" +#define CSNAME_PROMPTCACHE L"PromptCache" + +/* plugin constants */ +#define KRB5_PLUGIN_NAME L"Krb5Cred" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb5_initialized; + +extern khm_handle krb5_credset; + +extern khm_handle k5_sub; + +extern krb5_context k5_identpro_ctx; + +extern BOOL is_k5_identpro; + +/* plugin callbacks */ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/* kinit fiber */ +typedef struct _fiber_job_t { + int command; + + khui_new_creds * nc; + khui_new_creds_by_type * nct; + HWND dialog; + + khm_handle identity; + char * principal; + char * password; + char * ccache; + krb5_deltat lifetime; + DWORD forwardable; + DWORD proxiable; + DWORD renewable; + krb5_deltat renew_life; + DWORD addressless; + DWORD publicIP; + + int code; + int state; + int prompt_set; + + BOOL null_password; +} fiber_job; + +extern fiber_job g_fjob; /* global fiber job object */ + +#define FIBER_CMD_KINIT 1 +#define FIBER_CMD_CANCEL 2 +#define FIBER_CMD_CONTINUE 3 + +#define FIBER_STATE_NONE 0 +#define FIBER_STATE_KINIT 1 + +void +k5_pp_begin(khui_property_sheet * s); + +void +k5_pp_end(khui_property_sheet * s); + +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf); + +void +k5_register_config_panels(void); + +void +k5_unregister_config_panels(void); + +#endif diff --git a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc new file mode 100644 index 0000000..087b93e --- /dev/null +++ b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc @@ -0,0 +1,406 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB5 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | WS_DISABLED + LTEXT "&Lifetime",IDC_STATIC,7,67,61,12 + EDITTEXT IDC_NCK5_LIFETIME_EDIT,85,67,107,12,ES_AUTOHSCROLL + CONTROL "&Renewable for",IDC_NCK5_RENEWABLE,"Button", + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,7,87,64,12 + EDITTEXT IDC_NCK5_RENEW_EDIT,85,87,108,12,ES_AUTOHSCROLL + CONTROL "Can be &forwarded to other machines", + IDC_NCK5_FORWARDABLE,"Button",BS_AUTOCHECKBOX | + BS_NOTIFY | WS_TABSTOP,7,107,132,12 + CONTROL "Kerberos 5 Ticket Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 +END + +IDD_PP_KRB5C DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Name",IDC_STATIC,7,7,19,8 + LTEXT "Valid till",IDC_STATIC,7,39,24,8 + LTEXT "Renewable till",IDC_STATIC,7,55,45,12 + CONTROL "Renewable",IDC_PPK5_CRENEW,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,31,125,51,10 + CONTROL "Forwardable",IDC_PPK5_CFORWARD,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,91,125,56,10 + CONTROL "Proxiable",IDC_PPK5_CPROXY,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,156,125,45,10 + LTEXT "Issued on",IDC_STATIC,7,23,32,8 + GROUPBOX "Ticket flags",IDC_STATIC,7,108,221,41 + LTEXT "Static",IDC_PPK5_NAME,72,7,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_ISSUE,72,23,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_VALID,72,39,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_RENEW,72,55,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE +END + +IDD_PP_KRB5 DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Default realm",IDC_STATIC,7,7,44,8 + LTEXT "Default lifetime",IDC_STATIC,7,22,49,8 + LTEXT "Minimum lifetime",IDC_STATIC,7,37,52,8 + LTEXT "Maximum lifetime",IDC_STATIC,7,52,55,8 + LTEXT "Renewable lifetime",IDC_STATIC,7,67,61,8 + LTEXT "Min. Renewable lifetime",IDC_STATIC,7,82,76,8 + LTEXT "Max. Renewable lifetime",IDC_STATIC,7,97,79,8 + GROUPBOX "Default ticket flags",IDC_STATIC,7,113,221,36 + CONTROL "Proxiable",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,129,45,10 + CONTROL "Renewable",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,129,51,10 + CONTROL "Forwardable",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,89,129,56,10 + LTEXT "ATHENA.MIT.EDU",IDC_STATIC,95,7,133,11,0, + WS_EX_CLIENTEDGE + LTEXT "10 hours",IDC_STATIC,95,22,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,37,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,52,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,67,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,82,133,11,0,WS_EX_CLIENTEDGE + LTEXT "21 days",IDC_STATIC,95,97,133,11,0,WS_EX_CLIENTEDGE +END + +IDD_CONFIG DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Default Realm",IDC_CFG_LBL_REALM,13,9,46,8 + COMBOBOX IDC_CFG_DEFREALM,76,7,166,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure Realms ...",IDC_CFG_CFGREALMS,76,25,84,14 + GROUPBOX "Keberos Configuration File",IDC_CFG_CFGFILEGRP,7,57,241, + 48 + LTEXT "Location",IDC_CFG_LBL_CFGFILE,13,71,28,8 + EDITTEXT IDC_CFG_CFGFILE,76,68,119,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_BROWSE,198,68,44,14 + CONTROL "Create file if missing",IDC_CFG_CREATECONFIG,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,76,89,80,10 + GROUPBOX "Windows® Options",IDC_CFG_WINGRP,7,110,241,65 + LTEXT "Hostname",IDC_CFG_LBL_HOSTNAME,13,123,33,8 + EDITTEXT IDC_CFG_HOSTNAME,76,120,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Domain",IDC_CFG_LBL_DOMAIN,13,141,24,8 + EDITTEXT IDC_CFG_DOMAIN,76,138,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Import tickets",IDC_LBL_IMPORT,13,158,45,8 + COMBOBOX IDC_CFG_IMPORT,76,156,166,30,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP +END + +IDD_CFG_REALMS DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_REALMS,"SysListView32",LVS_ALIGNLEFT | + WS_BORDER | WS_TABSTOP,7,19,81,148 + GROUPBOX "Servers",IDC_CFG_SERVERSGRP,93,7,155,91 + GROUPBOX "Domain/Hostname mappings",IDC_CFG_DOMAINGRP,93,101,155, + 74 + CONTROL "",IDC_LIST3,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,99,19,143,72 + CONTROL "",IDC_LIST4,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,99,111,143,56 +END + +IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + GROUPBOX "Ticket lifetime range",IDC_CFG_LIFEGRP,7,43,221,49 + LTEXT "Minimum",IDC_STATIC,13,56,28,8 + EDITTEXT IDC_CFG_LRNG_MIN,91,53,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,75,30,8 + EDITTEXT IDC_CFG_LRNG_MAX,91,72,131,14,ES_AUTOHSCROLL + GROUPBOX "Ticket renewable lifetime range",IDC_STATIC,7,95,221,49 + LTEXT "Minimum",IDC_STATIC,13,108,28,8 + EDITTEXT IDC_CFG_RLRNG_MIN,91,105,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,128,30,8 + EDITTEXT IDC_CFG_RLRNG_MAX,91,125,131,14,ES_AUTOHSCROLL +END + +IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + LTEXT "Credentials cache",IDC_STATIC,7,63,58,8 + EDITTEXT IDC_CFG_CCACHE,91,60,137,14,ES_AUTOHSCROLL +END + +IDD_NC_KRB5_PASSWORD DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Kerberos 5 Change Password Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | WS_DISABLED +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_PP_KRB5C, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PP_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 13 + VERTGUIDE, 76 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_REALMS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 93 + VERTGUIDE, 99 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + HORZGUIDE, 19 + HORZGUIDE, 167 + END + + IDD_CFG_IDS_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 13 + VERTGUIDE, 91 + VERTGUIDE, 222 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 91 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_NC_KRB5_PASSWORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_UNK_ADDR_FMT "Unknown address type %d" + IDS_KRB5_CREDTEXT_0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Creds for realm %s</p>" + IDS_KRB5_CCNAME_SHORT_DESC "Krb5 CCache" + IDS_KEY_ENCTYPE_SHORT_DESC "Key EncType" + IDS_TKT_ENCTYPE_SHORT_DESC "Ticket EncType" + IDS_KEY_ENCTYPE_LONG_DESC "Session Key Encryption Type" + IDS_TKT_ENCTYPE_LONG_DESC "Ticket Encryption Type" + IDS_ADDR_LIST_SHORT_DESC "Addresses" + IDS_ADDR_LIST_LONG_DESC "Address List" + IDS_ETYPE_NULL "NULL" + IDS_ETYPE_DES_CBC_CRC "DES-CBC-CRC" +END + +STRINGTABLE +BEGIN + IDS_ETYPE_DES_CBC_MD4 "DES-CBC-MD4" + IDS_ETYPE_DES_CBC_MD5 "DES-CBC-MD5" + IDS_ETYPE_DES_CBC_RAW "DES-CBC-RAW" + IDS_ETYPE_DES3_CBC_SHA "DES3-CBC-SHA" + IDS_ETYPE_DES3_CBC_RAW "DES3-CBC-RAW" + IDS_ETYPE_DES_HMAC_SHA1 "DES-HMAC-SHA1" + IDS_ETYPE_DES3_CBC_SHA1 "DES3-CBC-SHA1" + IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 "AES128_CTS-HMAC-SHA1_96" + IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 "AES256_CTS-HMAC-SHA1_96" + IDS_ETYPE_ARCFOUR_HMAC "RC4-HMAC-NT" + IDS_ETYPE_ARCFOUR_HMAC_EXP "RC4-HMAC-NT-EXP" + IDS_ETYPE_UNKNOWN "(Unknown)" + IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 "LOCAL-DES3-HMAC-SHA1" + IDS_ETYPE_LOCAL_RC4_MD4 "LOCAL-RC4-MD4" + IDS_KRB5_SHORT_DESC "Kerberos 5" + IDS_KRB5_LONG_DESC "Kerberos 5 tickets" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_KRB5_FLAGS_SHORT_DESC "Flags" + IDS_RENEW_TILL_SHORT_DESC "Renew Till" + IDS_RENEW_TILL_LONG_DESC "Renewable Till" + IDS_RENEW_FOR_SHORT_DESC "Renew for" + IDS_RENEW_FOR_LONG_DESC "Renewable for" + IDS_KRB5_CCNAME_LONG_DESC "Krb5 Primary Credentials Cache" + IDS_NC_USERNAME "Username" + IDS_NC_REALM "Realm" + IDS_KRB5_WARNING "Kerberos 5 Warning" + IDS_K5ERR_NAME_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The selected principal name has expired.</p><p><tab> Please contact your system administrator.</p>" + IDS_K5ERR_KEY_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The password for the selected identity has expired.</p><p><tab> Click <a id=""Krb5Cred:Passwd"">here</a> to change the password</p>" + IDS_KRB5_WARN_FMT "Kerberos 5: %s\n\n%s" + IDS_K5ERR_FMT "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tag>: %s</p>" + IDS_K5CFG_SHORT_DESC "Kerberos 5" +END + +STRINGTABLE +BEGIN + IDS_K5CFG_LONG_DESC "Kerberos 5 Configuration" + IDS_K5RLM_SHORT_DESC "Realms" + IDS_K5RLM_LONG_DESC "Kerberos Realm Configuration" + IDS_K5CFG_IDS_SHORT_DESC "Kerberos 5" + IDS_K5CFG_IDS_LONG_DESC "Kerberos 5 options for all identities" + IDS_K5CFG_ID_SHORT_DESC "Kerberos 5" + IDS_K5CFG_ID_LONG_DESC "Kerberos 5 options for this identity" + IDS_PLUGIN_DESC "Kerberos 5 Credentials Provider" + IDS_NC_PWD_BANNER "Changing Kerberos 5 Password" + IDS_NC_PWD_PWD "Current Password" + IDS_NC_PWD_NPWD "New Password" + IDS_NC_PWD_NPWD_AGAIN "New Password again" + IDS_KRB5_CREDTEXT_P0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Changing password for %s</p>" + IDS_K5CFG_IMPORT_OPTIONS + "Never\000Always\000Only when the principal name matches\000 \000" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc new file mode 100644 index 0000000..22f973f --- /dev/null +++ b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc @@ -0,0 +1,151 @@ +; // ** krb5_msgs.mc + +; /* Since .mc files can contain strings from any language, we define +; all our messages in one file in the /lang/ directory instead of +; language specific subdirectories. */ + +; /* The type is set to (wchar_t *) because that's what we will be +; feeding kherr_report() function. */ + +; // MessageIdTypedef=LPWSTR + +; /* Severity values as defined in the message definition file are +; currently ignored. */ + +SeverityNames=( + Success=0x0 +) + +LanguageNames=( + English=0x409:MSG_ENU +) + +OutputBase=16 + +; /* Actual messages start here */ + +MessageId=1 +Severity=Success +SymbolicName=MSG_INITIAL +Language=English +Initial placeholder message +. + +MessageId= +SymbolicName=MSG_CTX_INITAL_CREDS +Language=English +Obtaining initial Krb5 credentials +. + +MessageId= +SymbolicName=MSG_CTX_RENEW_CREDS +Language=English +Renewing Krb5 credentials +. + +MessageId= +SymbolicName=MSG_ERR_UNKNOWN +Language=English +An unknown error has occurred. +. + +MessageId= +SymbolicName=MSG_ERR_PR_UNKNOWN +Language=English +You have entered an unknown username/instance/realm combination. +. + +MessageId= +SymbolicName=MSG_ERR_TKFIL +Language=English +The tickets could not be accessed from the memory location where they were stored. +. + +MessageId= +SymbolicName=MSG_ERR_S_TKFIL +Language=English +This may be due to a problem with the memory where your tickets are stored. Restarting your computer might be worth a try. +. + +MessageId= +SymbolicName=MSG_ERR_CLOCKSKEW +Language=English +Your computer's clock is out of sync with the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_S_CLOCKSKEW +Language=English +Synchronize your clock withe the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_KDC_CONTACT +Language=English +Cannot contact the Kerberos server for the requested realm. +. + +MessageId= +SymbolicName=MSG_ERR_INSECURE_PW +Language=English +You have entered an insecure or weak password. +. + +MessageId= +SymbolicName=MSG_ERR_NO_IDENTITY +Language=English +There were no identities for which to renew credentials. +. + +MessageId= +SymbolicName=MSG_CTX_PASSWD +Language=English +Changing Kerberos 5 Password +. + +MessageId= +SymbolicName=MSG_PWD_UNKNOWN +Language=English +Unknown error +. + +MessageId= +SymbolicName=MSG_PWD_NOT_SAME +Language=English +The new passwords are not the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_NOT_SAME +Language=English +The new password is asked for twice to protect against a mistake when setting the new password. Both instances of the new password must be the same. Please correct this and try again. +. + +MessageId= +SymbolicName=MSG_PWD_SAME +Language=English +The new and the old passwords are the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_SAME +Language=English +Please type a new password to continue. +. + +MessageId= +SymbolicName=MSG_PWD_NO_IDENTITY +Language=English +There are no identities selected. +. + +MessageId= +SymbolicName=MSG_PWD_S_NO_IDENTITY +Language=English +Please select an identity to change the password. +. + +MessageId= +SymbolicName=MSG_ +Language=English +. diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h new file mode 100644 index 0000000..87f74f5 --- /dev/null +++ b/src/windows/identity/plugins/krb5/langres.h @@ -0,0 +1,127 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\plugins\krb5\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDD_NC_KRB5 102 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDS_KRB5_CCNAME_SHORT_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CONFIG 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDD_CFG_REALMS 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDD_CFG_IDS_TAB 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDD_PP_KRB5C 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDD_PP_KRB5 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDD_CFG_ID_TAB 109 +#define IDS_ETYPE_NULL 110 +#define IDD_NC_KRB5_PASSWORD 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_KRB5_CCNAME_LONG_DESC 135 +#define IDS_NC_USERNAME 136 +#define IDS_NC_REALM 137 +#define IDS_KRB5_WARNING 138 +#define IDS_K5ERR_NAME_EXPIRED 139 +#define IDS_K5ERR_KEY_EXPIRED 140 +#define IDS_KRB5_WARN_FMT 141 +#define IDS_K5ERR_FMT 142 +#define IDS_K5CFG_SHORT_DESC 143 +#define IDS_K5CFG_LONG_DESC 144 +#define IDS_K5RLM_SHORT_DESC 145 +#define IDS_K5RLM_LONG_DESC 146 +#define IDS_K5CFG_IDS_SHORT_DESC 147 +#define IDS_K5CFG_IDS_LONG_DESC 148 +#define IDS_K5CFG_ID_SHORT_DESC 149 +#define IDS_K5CFG_ID_LONG_DESC 150 +#define IDS_PLUGIN_DESC 151 +#define IDS_NC_PWD_BANNER 152 +#define IDS_NC_PWD_PWD 153 +#define IDS_NC_PWD_NPWD 154 +#define IDS_NC_PWD_NPWD_AGAIN 155 +#define IDS_KRB5_CREDTEXT_P0 156 +#define IDS_K5CFG_IMPORT_OPTIONS 157 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_REALM 1025 +#define IDC_CFG_DEFREALM 1026 +#define IDC_CFG_LBL_CFGFILE 1029 +#define IDC_CFG_CFGFILE 1030 +#define IDC_CFG_WINGRP 1031 +#define IDC_LBL_IMPORT 1032 +#define IDC_CFG_IMPORT 1033 +#define IDC_CFG_LBL_HOSTNAME 1034 +#define IDC_CFG_HOSTNAME 1035 +#define IDC_CFG_LBL_DOMAIN 1036 +#define IDC_CFG_DOMAIN 1037 +#define IDC_CFG_CREATECONFIG 1038 +#define IDC_CFG_BROWSE 1039 +#define IDC_CFG_CFGFILEGRP 1040 +#define IDC_CFG_CFGREALMS 1041 +#define IDC_CFG_REALMS 1044 +#define IDC_CFG_DOMAINGRP 1045 +#define IDC_CFG_SERVERSGRP 1046 +#define IDC_LIST3 1047 +#define IDC_LIST4 1048 +#define IDC_CFG_LBL_DEFLIFE 1049 +#define IDC_CFG_DEFLIFE 1050 +#define IDC_CFG_LBL_DEFRLIFE 1051 +#define IDC_CFG_DEFRLIFE 1052 +#define IDC_CFG_LIFEGRP 1053 +#define IDC_CFG_LRNG_MIN 1054 +#define IDC_CFG_LRNG_MAX 1055 +#define IDC_CFG_RLRNG_MIN 1056 +#define IDC_CFG_RLRNG_MAX 1057 +#define IDC_CFG_CCACHE 1058 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1059 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/plugins/krb5/main.c b/src/windows/identity/plugins/krb5/main.c new file mode 100644 index 0000000..db996d9 --- /dev/null +++ b/src/windows/identity/plugins/krb5/main.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<krbcred.h> +#include<kherror.h> + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ +const wchar_t * k5_facility = L"Krb5"; + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +BOOL type_regd_enctype = FALSE; +BOOL type_regd_addr_list = FALSE; +BOOL type_regd_krb5_flags = FALSE; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_krb5_ccname = -1; + +BOOL attr_regd_key_enctype = FALSE; +BOOL attr_regd_tkt_enctype = FALSE; +BOOL attr_regd_addr_list = FALSE; +BOOL attr_regd_krb5_flags = FALSE; +BOOL attr_regd_krb5_ccname = FALSE; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +BOOL is_k5_identpro = TRUE; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; +int n_locales = ARRAYLENGTH(locales); + +/* These two should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + /* register the plugin */ + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = KHM_PIFLAG_IDENTITY_PROVIDER; + pi.msg_proc = k5_msg_callback; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Register common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ENCTYPE; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = enctype_toString; + + rv = kcdb_type_register(&type, &type_id_enctype); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + kcdb_type type; + kcdb_type *tdata; + + kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ADDR_LIST; + type.flags = KCDB_TYPE_FLAG_CB_MIN; + type.cb_min = 0; + type.cb_max = 0; + type.isValid = tdata->isValid; + type.comp = tdata->comp; + type.dup = tdata->dup; + type.toString = addr_list_toString; + + rv = kcdb_type_register(&type, &type_id_addr_list); + kcdb_type_release_info(tdata); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_KRB5_FLAGS; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = krb5flags_toString; + + rv = kcdb_type_register(&type, &type_id_krb5_flags); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_krb5_flags = TRUE; + } + + /* Register common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KEY_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_key_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_TKT_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_tkt_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_ADDR_LIST; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_addr_list; + attrib.flags = 0; + LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_FLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_krb5_flags; + attrib.flags = 0; + LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_flags = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_CCNAME; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_STRING; + attrib.flags = KCDB_ATTR_FLAG_PROPERTY; + LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_ccname = TRUE; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(attr_regd_key_enctype) + kcdb_attrib_unregister(attr_id_key_enctype); + if(attr_regd_tkt_enctype) + kcdb_attrib_unregister(attr_id_tkt_enctype); + if(attr_regd_addr_list) + kcdb_attrib_unregister(attr_id_addr_list); + if(attr_regd_krb5_flags) + kcdb_attrib_unregister(attr_id_krb5_flags); + if(attr_regd_krb5_ccname) + kcdb_attrib_unregister(attr_id_krb5_ccname); + + if(type_regd_enctype) + kcdb_type_unregister(type_id_enctype); + if(type_regd_addr_list) + kcdb_type_unregister(type_id_addr_list); + if(type_regd_krb5_flags) + kcdb_type_unregister(type_id_krb5_flags); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} -- cgit v1.1