From e11f8fd7f2c26968ed1560d9c3b2ef27ff707093 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Wed, 8 Mar 2006 22:39:38 +0000 Subject: [PATCH] pull up r17712 from trunk ticket: 3501 version_fixed: 1.4.4 git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-4@17722 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/identity/ChangeLog | 124 + src/windows/identity/Makefile | 6 + src/windows/identity/apiversion.txt | 77 + src/windows/identity/config/Makefile | 14 +- src/windows/identity/config/Makefile.w32 | 13 +- .../identity/config/netidmgr_intver.h.in | 15 +- .../identity/config/netidmgr_version.h.in | 3 +- src/windows/identity/help/Makefile | 2 +- .../identity/help/html/concept_identity.htm | 11 +- src/windows/identity/help/html/welcome.htm | 6 + src/windows/identity/help/popups_password.txt | 19 + src/windows/identity/include/khmsgtypes.h | 63 +- src/windows/identity/kconfig/api.c | 120 +- src/windows/identity/kconfig/kconfig.h | 10 +- src/windows/identity/kcreddb/attrib.c | 27 +- src/windows/identity/kcreddb/credential.c | 19 +- src/windows/identity/kcreddb/credset.c | 153 +- src/windows/identity/kcreddb/identity.c | 16 +- src/windows/identity/kcreddb/kcreddb.h | 33 +- src/windows/identity/kcreddb/type.c | 9 +- src/windows/identity/kherr/kherr.c | 71 +- src/windows/identity/kherr/kherr.h | 104 +- src/windows/identity/kmm/kmm.h | 30 + src/windows/identity/kmm/kmm_module.c | 31 +- src/windows/identity/kmm/kmm_plugin.c | 52 +- src/windows/identity/kmm/kmm_reg.c | 35 +- src/windows/identity/kmm/kmm_registrar.c | 183 +- src/windows/identity/kmm/kmminternal.h | 41 +- src/windows/identity/kmm/kmmmain.c | 2 +- src/windows/identity/kmm/lang/kmm_msgs.mc | 45 + src/windows/identity/kmq/consumer.c | 30 + src/windows/identity/kmq/init.c | 22 +- src/windows/identity/kmq/kmq.h | 21 + src/windows/identity/nidmgrdll/Makefile | 230 +- .../identity/plugins/common/dynimport.c | 45 +- src/windows/identity/plugins/krb4/Makefile | 182 +- src/windows/identity/plugins/krb4/krb4funcs.c | 76 +- src/windows/identity/plugins/krb4/krb4funcs.h | 4 + src/windows/identity/plugins/krb4/krb4main.c | 12 +- .../identity/plugins/krb4/krb4newcreds.c | 186 +- .../identity/plugins/krb4/krb4plugin.c | 1 - src/windows/identity/plugins/krb4/krbcred.h | 1 + .../plugins/krb4/lang/en_us/langres.rc | 19 +- .../identity/plugins/krb4/lang/krb4_msgs.mc | 57 + src/windows/identity/plugins/krb4/langres.h | 7 +- src/windows/identity/plugins/krb4/version.rc | 31 +- src/windows/identity/plugins/krb5/Makefile | 208 +- src/windows/identity/plugins/krb5/datarep.c | 166 +- src/windows/identity/plugins/krb5/datarep.h | 42 +- .../identity/plugins/krb5/krb5configdlg.c | 4602 ++++++++++------- .../identity/plugins/krb5/krb5configid.c | 97 +- src/windows/identity/plugins/krb5/krb5funcs.c | 289 +- src/windows/identity/plugins/krb5/krb5funcs.h | 5 +- .../identity/plugins/krb5/krb5identpro.c | 90 +- src/windows/identity/plugins/krb5/krb5main.c | 21 +- .../identity/plugins/krb5/krb5newcreds.c | 234 +- .../identity/plugins/krb5/krb5plugin.c | 32 +- .../identity/plugins/krb5/krbconfig.csv | 3 +- src/windows/identity/plugins/krb5/krbcred.h | 2 + .../plugins/krb5/lang/en_us/langres.rc | 71 +- .../identity/plugins/krb5/lang/krb5_msgs.mc | 5 + src/windows/identity/plugins/krb5/langres.h | 35 +- src/windows/identity/plugins/krb5/version.rc | 30 +- src/windows/identity/ui/Makefile | 191 +- src/windows/identity/ui/appglobal.h | 18 +- src/windows/identity/ui/cfg_general_wnd.c | 48 +- src/windows/identity/ui/cfg_identities_wnd.c | 8 +- src/windows/identity/ui/cfg_notif_wnd.c | 15 + src/windows/identity/ui/cfg_plugins_wnd.c | 470 +- src/windows/identity/ui/configwnd.c | 113 +- src/windows/identity/ui/configwnd.h | 2 + src/windows/identity/ui/credfuncs.c | 32 +- src/windows/identity/ui/credfuncs.h | 3 +- src/windows/identity/ui/credwnd.c | 1140 +++- src/windows/identity/ui/credwnd.h | 61 +- src/windows/identity/ui/debugfuncs.c | 252 + src/windows/identity/ui/debugfuncs.h | 37 + .../identity/ui/images/app_notify_none.ico | Bin 25214 -> 2862 bytes src/windows/identity/ui/images/cfg_plugin.ico | Bin 10134 -> 9110 bytes .../identity/ui/images/cfg_plugin_dis.ico | Bin 0 -> 8854 bytes .../identity/ui/images/cfg_plugin_err.ico | Bin 0 -> 8854 bytes src/windows/identity/ui/images/tk-delete.bmp | Bin 2430 -> 2430 bytes src/windows/identity/ui/images/tk-sm.bmp | Bin 1014 -> 822 bytes src/windows/identity/ui/khmapp.h | 2 + src/windows/identity/ui/lang/en_us/khapp.rc | 117 +- src/windows/identity/ui/main.c | 129 +- src/windows/identity/ui/mainmenu.c | 60 +- src/windows/identity/ui/mainwnd.c | 308 +- src/windows/identity/ui/mainwnd.h | 3 + .../identity/ui/netidmgr.manifest.amd64.vc7 | 22 + .../ui/netidmgr.manifest.amd64.vc7.debug | 22 + .../identity/ui/netidmgr.manifest.amd64.vc8 | 31 + .../ui/netidmgr.manifest.amd64.vc8.debug | 31 + src/windows/identity/ui/newcredwnd.c | 4 +- src/windows/identity/ui/notifier.c | 50 +- src/windows/identity/ui/reqdaemon.c | 2 +- src/windows/identity/ui/resource.h | 38 +- src/windows/identity/ui/timer.c | 158 +- src/windows/identity/ui/uiconfig.csv | 73 +- src/windows/identity/uilib/accel.csv | 4 + src/windows/identity/uilib/acceldef.cfg | 1 + src/windows/identity/uilib/action.c | 557 +- src/windows/identity/uilib/actiondef.cfg | 6 +- src/windows/identity/uilib/actions.csv | 12 +- src/windows/identity/uilib/alert.c | 18 +- src/windows/identity/uilib/configui.c | 32 +- src/windows/identity/uilib/creddlg.c | 38 +- src/windows/identity/uilib/khaction.h | 554 +- src/windows/identity/uilib/khactiondef.h | 25 +- src/windows/identity/uilib/khalerts.h | 16 + src/windows/identity/uilib/khconfigui.h | 18 +- src/windows/identity/uilib/khnewcred.h | 4 +- src/windows/identity/uilib/khversion.h | 32 + src/windows/identity/uilib/trackerwnd.c | 26 +- src/windows/identity/util/perfstat.c | 11 +- 115 files changed, 9552 insertions(+), 3432 deletions(-) create mode 100644 src/windows/identity/help/popups_password.txt create mode 100644 src/windows/identity/plugins/krb4/lang/krb4_msgs.mc create mode 100644 src/windows/identity/ui/debugfuncs.c create mode 100644 src/windows/identity/ui/debugfuncs.h create mode 100644 src/windows/identity/ui/images/cfg_plugin_dis.ico create mode 100644 src/windows/identity/ui/images/cfg_plugin_err.ico create mode 100644 src/windows/identity/ui/netidmgr.manifest.amd64.vc7 create mode 100644 src/windows/identity/ui/netidmgr.manifest.amd64.vc7.debug create mode 100644 src/windows/identity/ui/netidmgr.manifest.amd64.vc8 create mode 100644 src/windows/identity/ui/netidmgr.manifest.amd64.vc8.debug create mode 100644 src/windows/identity/uilib/khversion.h diff --git a/src/windows/identity/ChangeLog b/src/windows/identity/ChangeLog index ada18d283..f18508a35 100644 --- a/src/windows/identity/ChangeLog +++ b/src/windows/identity/ChangeLog @@ -1,3 +1,127 @@ +2006-03-07 Jeffrey Altman + +nidmgr32.dll (1.0.2.1) + +- Attempting to obtain new credentials for a principal name that + contains numbers may result in a 'Identity not specified' + error. Fixed. + +- If an invalid identity name was specified, an 'Identity not + specified' error is reported without specifying that the cause was + an invalid name. Fixed: reports proper error. + +- Identity names were being validated at the application layer before + being sent to the identity provider. This may cause valid names to + be marked as invalid if the identity provider and the application + disagree on what a valid name is. Fixed: identity name validation + is solely a function of the identity provider. + +- Canonicalizing an identity name that contained certain characters + failed due to a validation error. Fixed. + +- Possible deadlock in the new credentials dialog. (If one plugin + tries to synchronize custom prompter values from the plugin thread, + while the UI thread tries to obtain a lock on the new credentials + data, a deadlock occurs.) Fixed. + +- State information for configuration panels may persist between two + invocations of the configuration window. Fixed to clean up state + information properly. + +- The UI library now has full support for custom actions and custom + menus. + +- When there are queued alerts and a normal alert is shown, a 'next + alert...' button appears in the alert which lets the user view the + next queued alert. However, if the alert which is displayed + requires the user to select a command button, selecting the 'next' + button would be the equivalent of cancelling out of the alert and + viewing the next one. The library was updated to not show the + 'next' button if the alert requires user interaction. + +- Credential renewal on half-lifes is now supported as a configurable + option. + +- Destroying all credentials on exiting netidmgr is a configurable + option. + +- Debug logging to a file has been added + +netidmgr.exe (1.0.2.1) + +- Selecting 'Ok' in the configuration window didn't notify all the + configuration panels to apply the changes. Fixed. + +- PgUp / PgDn / Shift+PgUp / Shift+PgDn keys now work as expected. + +- Root level configuration nodes in the Options dialog now also appear + on the Options menu. Configuration nodes that are registered at the + root level are automatically added to the menu. + +- The UI now has full support for custom actions and custom menus. + +- The UI does not automatically add submenus for actions which are + associated with menus unless the declaration specifies that it + should be rendered as a submenu. + +- When displaying alerts, the first button of the alert is always made + the default. + +- 'Change summary' button in the configuration dialog was removed, + since it was unused and unnecessary. + +- Ticket icons are displayed in the status column for all credentials. + Clicking an icon opens the properties dialog for that credential. + +- The UI now has View by Type functionality + +- The UI now has Column selection and reorganization. The choice + of columns and their order are preserved between restarts. + +- Handle multiple copies of NetIDMgr.exe being started with different + version numbers. Higher version number wins. + +krb4cred.dll (1.0.2.1) + +- During new credentials acquisition, under some circumstances, the + Kerberos 4 plugin would not notify NetIDMgr about the state of the + Kerberos 4 ticket acquisition. This results in other plugins (such + as AFS) which are depending on the feedback to fail. Fixed. + +krb5cred.dll (1.0.2.1) + +- If no password is entered while obtaining new credentials, a new TGT + will not be obtained, but the new credentials operation will not + fail if there already is a TGT. Added check to see if the TGT is + expired and fail the operation if no valid TGT is found. + +- The identity provider can set the Krb5 CCName property for an + identity incorrectly if there is more than one credential cache + containing tickets for the same principal. Fixed. + +- When enumerating ccaches, krb5_cc_resolve was being called with the + name of the ccache without a type prefix. Fixed. + +- Tracker control usability issues due to loss of focus. Fixed. + +- Realm Editor added. + +- Addressed tickets can be requested as in Leash + + +All modules: + +- removed grayed out UI components that are not being backed + by current functionality. + +- new icons + +- support for 64-bit Windows builds under Visual Studio 8 + +- proper versioning for language resources + + + 2005-11-29 Jeffrey Altman Second Beta of KFW 3.0.0: diff --git a/src/windows/identity/Makefile b/src/windows/identity/Makefile index 253d71935..078e7cb2f 100644 --- a/src/windows/identity/Makefile +++ b/src/windows/identity/Makefile @@ -33,7 +33,13 @@ MODULE=all !ifndef CLEANRUN !ifndef TESTRUN !ifndef ETAGRUN + +# Define KH_NO_WX if the build should not fail on warnings. The +# default is to treat warnings as errors. + +#RMAKE=$(MAKECMD) /nologo all KH_NO_WX=1 RMAKE=$(MAKECMD) /nologo all + !else RMAKE=$(MAKECMD) /nologo etag !endif diff --git a/src/windows/identity/apiversion.txt b/src/windows/identity/apiversion.txt index e2367db2a..008510fba 100644 --- a/src/windows/identity/apiversion.txt +++ b/src/windows/identity/apiversion.txt @@ -52,6 +52,83 @@ AppVersion=0.1.2.0 Date=Nov 30, 2005 # Alpha 2 release of NetIDMgr, along with KFW 3.0.0 beta 2 +#---------------------------------------------------------------- Version=4 AppVersion=1.0.0.0 Date=Dec 05, 2005 +# Released with KfW 3.0.0 + +#---------------------------------------------------------------- +Version=5 +AppVersion=1.1.0.0 +Date=(TBD) +# Released with KFW 3.1.0 + ++khui_alert_show_modal(),KMSG_ALERT_SHOW_MODAL, KHUI_ALERT_FLAG_MODAL +# Support for modal alert boxes + ++KHUI_PACTION_YES, KHUI_PACTION_NO, KHUI_PACTION_YESALL, KHUI_PACTION_NOALL, KHUI_PACTION_KEEP, KHUI_PACTION_REMOVE, KHUI_PACTION_DISCARD +# Additional pseudo actions + +!tag_khui_action, khui_action +# Membership extension for supporting custom actions. Type changes +# from 'int' to khm_int32. + ++khui_action_create(), khui_action_get_data(), khui_action_delete() +# Support for creating custom actions + +!kmq_msg_subscription, tag_kmq_msg_subscription +# Add 'magic' field. + ++KHUI_MENU_NONE +# New identifier for unspecified menu commands. + ++khui_menu_insert_action(), khui_menu_get_action(), khui_menu_get_size(), khui_menu_remove_action() +# Functions for manipulating custom menus + ++khui_menu_insert_paction() +# Exported, but not exposed as an API. For inserting actions by +# reference in to menus. + +-khui_menu_add_action(), khui_menu_add_paction() +# Removed deprecated functions. Temporarily provided as macros. The +# replacements are khui_menu_insert_action() and +# khui_menu_insert_paction() respectively. + ++kmq_create_hwnd_subscription() +# Ad-hoc subscriptions can now be obtained for Win32 windows. + +-khui_create_gloabl_accel_table() +# Exported but no longer exposed. + +-khui_action_list_length() +# Exported but no longer exposed. + ++kmm_enable_plugin() +# New API for enabling or disabling plugins + +!kmm_plugin_info +# Added 'flags' field. + ++KCDB_ATTR_FLAG_TRANSIENT +# New flag for transient attributes. + ++kherr_get_prev_event(), kherr_get_last_event() +# For more efficient traversal of the event lists for use by error context handlers. + ++KHERR_RF_COMMIT +# Flag for error events to signal that the error event has been committed. + ++khui_action_trigger() + ++khui_action_set_hwnd() + ++KEPT_PTR + ++_cptr + +!khc_open_space +# name parameter is now a const string + +!KCDB_ATTRNAME_ISSUE +# Fixed typo \ No newline at end of file diff --git a/src/windows/identity/config/Makefile b/src/windows/identity/config/Makefile index f10928fc5..5e242824b 100644 --- a/src/windows/identity/config/Makefile +++ b/src/windows/identity/config/Makefile @@ -25,7 +25,7 @@ MODULE=config !include -all: showvars mkalldirs mkversion +all: showvars showvers mkalldirs mkversion showvars: $(ECHO) SRC= $(SRC) @@ -36,6 +36,18 @@ showvars: $(ECHO) DOXYGEN = $(DOXYGEN) $(ECHO) HHC = $(HHC) +showvers: + $(ECHO) ---- Version Information ---- + $(ECHO) NETIDMGR_VERSION= $(NETIDMGR_VERSION) + $(ECHO) NETIDMGR_VERSION_API=$(NETIDMGR_VERSION_API) + $(ECHO) NETIDMGR_RELEASEDESC=$(NETIDMGR_RELEASEDESC) + $(ECHO) Build Type :$(KH_BUILD), $(KH_RELEASE) + $(ECHO) Strings: + $(ECHO) Company = $(NETIDMGR_SRC_COMPANY_1033) + $(ECHO) Copyright = $(NETIDMGR_SRC_COPYRIGHT_1033) + $(ECHO) ---- End Version Information --- + $(ECHO). + mkalldirs: ! if !exist($(DESTROOT)) -$(MKDIR) $(DESTROOT) diff --git a/src/windows/identity/config/Makefile.w32 b/src/windows/identity/config/Makefile.w32 index 264d19ed2..5d8026420 100644 --- a/src/windows/identity/config/Makefile.w32 +++ b/src/windows/identity/config/Makefile.w32 @@ -45,7 +45,7 @@ KHIMAIRA_WIN32_CONFIG=1 # Version info NETIDMGR_VERSION_MAJOR=1 -NETIDMGR_VERSION_MINOR=0 +NETIDMGR_VERSION_MINOR=1 NETIDMGR_VERSION_PATCH=0 NETIDMGR_VERSION_AUX=0 NETIDMGR_RELEASEDESC= @@ -57,7 +57,12 @@ NETIDMGR_RELEASEDESC= # # Changes to the API version numbers should be documented in # apiversion.txt at the root of the source tree. -NETIDMGR_VERSION_API=4 +NETIDMGR_VERSION_API=5 + +# Minimum backwards compatible version. API versions from +# NETIDMGR_VERSION_API_MINCOMPAT through NETIDMGR_VERSION_API +# inclusive, are compatible with this version. +NETIDMGR_VERSION_API_MINCOMPAT=5 NETIDMGR_VERSION=$(NETIDMGR_VERSION_MAJOR).$(NETIDMGR_VERSION_MINOR).$(NETIDMGR_VERSION_PATCH).$(NETIDMGR_VERSION_AUX) NETIDMGR_VERSIONC=$(NETIDMGR_VERSION_MAJOR),$(NETIDMGR_VERSION_MINOR),$(NETIDMGR_VERSION_PATCH),$(NETIDMGR_VERSION_AUX) @@ -153,7 +158,7 @@ RM=del /q MKDIR=mkdir RMDIR=rmdir ECHO=echo -MAKECMD=nmake +MAKECMD=nmake /nologo CP=copy /y LINK=link CCSV=perl $(SRC)\config\ccsv.pl @@ -272,6 +277,4 @@ etag:: .SUFFIXES: .h -.SILENT: - !endif diff --git a/src/windows/identity/config/netidmgr_intver.h.in b/src/windows/identity/config/netidmgr_intver.h.in index d1863c433..15d47217f 100644 --- a/src/windows/identity/config/netidmgr_intver.h.in +++ b/src/windows/identity/config/netidmgr_intver.h.in @@ -1,4 +1,4 @@ -$(VERSIONINT): Makefile +$(VERSIONINT): Makefile Makefile.w32 $(CP) << $(VERSIONINT) /* * This is an autogenerated file. Do not modify directly. @@ -30,5 +30,18 @@ $(VERSIONINT): Makefile #define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_SPECIAL_1033 !endif #endif + +#define KH_BUILD "$(KH_BUILD)" + +! if "$(KH_BUILD)"=="RETAIL" +#define KH_BUILD_RETAIL +! elseif "$(KH_RELEASE)"=="PRERELEASE" +#define KH_BUILD_PRERELEASE +! elseif "$(KH_RELEASE)"=="PRIVATE" +#define KH_BUILD_PRIVATE +! elseif "$(KH_RELEASE)"=="SPECIAL" +#define KH_BUILD_SPECIAL +! endif + << diff --git a/src/windows/identity/config/netidmgr_version.h.in b/src/windows/identity/config/netidmgr_version.h.in index 2be3943a5..be53060d0 100644 --- a/src/windows/identity/config/netidmgr_version.h.in +++ b/src/windows/identity/config/netidmgr_version.h.in @@ -1,4 +1,4 @@ -$(VERSIONEXT): Makefile +$(VERSIONEXT): Makefile Makefile.w32 $(CP) << $(VERSIONEXT) /* Copyright (c) 2004 Massachusetts Institute of Technology * @@ -36,6 +36,7 @@ $(VERSIONEXT): Makefile #define KH_VERSION_AUX $(NETIDMGR_VERSION_AUX) #define KH_VERSION_API $(NETIDMGR_VERSION_API) +#define KH_VERSION_API_MINCOMPAT $(NETIDMGR_VERSION_API_MINCOMPAT) #define KH_VERSION_LIST $(NETIDMGR_VERSIONC) #define KH_VERSION_STRING "$(NETIDMGR_VERSION)" diff --git a/src/windows/identity/help/Makefile b/src/windows/identity/help/Makefile index c45a83f80..752ffc996 100644 --- a/src/windows/identity/help/Makefile +++ b/src/windows/identity/help/Makefile @@ -32,5 +32,5 @@ INCFILES=$(INCDIR)\khhelp.h all: mkdirs $(CHMFILE) $(INCFILES) $(CHMFILE): netidmgr.hhp - -hhc netidmgr.hhp + -$(HHC) netidmgr.hhp $(CP) netidmgr.chm $(CHMFILE) diff --git a/src/windows/identity/help/html/concept_identity.htm b/src/windows/identity/help/html/concept_identity.htm index 5e39963da..50802d95b 100644 --- a/src/windows/identity/help/html/concept_identity.htm +++ b/src/windows/identity/help/html/concept_identity.htm @@ -1,11 +1,16 @@ - title - - + Concepts: Identity + + +

Concepts: Identity

+ +

+

+ \ No newline at end of file diff --git a/src/windows/identity/help/html/welcome.htm b/src/windows/identity/help/html/welcome.htm index 7423b848d..b7d545ba6 100644 --- a/src/windows/identity/help/html/welcome.htm +++ b/src/windows/identity/help/html/welcome.htm @@ -54,6 +54,12 @@ included in the Kerberos for Windows SDK, which itself is a part of the Kerberos for Windows distribution.

+

+We highly recommend interested developers to contact the netidmgr@secure-endpoints.com +mailing list. +

+

External links

    diff --git a/src/windows/identity/help/popups_password.txt b/src/windows/identity/help/popups_password.txt new file mode 100644 index 000000000..39583252b --- /dev/null +++ b/src/windows/identity/help/popups_password.txt @@ -0,0 +1,19 @@ +.topic IDH_NC_TABMAIN +Switches to the identity selection panel. + +.topic IDH_NC_TABBUTTON +Switches to the options pangel for this credential type. + +.topic IDH_NC_OK +Change the password for the selected identity. + +.topic IDH_NC_CANCEL +Cancel the change password operation. + +.topic IDH_NC_OPTIONS +Expand the dialog and make the option pages visible for the credential +types for which you will be changing the password for. + +.topic IDH_NC_CREDWND +A brief overview of the credential types and the identities for which +the password will be changed. diff --git a/src/windows/identity/include/khmsgtypes.h b/src/windows/identity/include/khmsgtypes.h index c2237ca19..b590e056b 100644 --- a/src/windows/identity/include/khmsgtypes.h +++ b/src/windows/identity/include/khmsgtypes.h @@ -85,7 +85,8 @@ /*! \brief Action list messages - Notifications of changes in action state. + Notifications of changes in action state and firing of custom + actions. \see \ref kmq_msg_act */ @@ -138,6 +139,7 @@ \see \ref pi_pt_cred_init */ #define KMSG_SYSTEM_INIT 1 + /*! \brief Generic uninitialization message Used by specific components to signal that the recipient should @@ -187,7 +189,7 @@ khui_enable_actions() or khui_enable_action() and indicates that one or more actions have changed their state. */ -#define KMSG_ACT_ENABLE 1 +#define KMSG_ACT_ENABLE 1 /*! \brief One or more actions changed check state @@ -195,18 +197,49 @@ khui_check_action() and indicates that one or more actions have either been checked or unchecked. */ -#define KMSG_ACT_CHECK 2 +#define KMSG_ACT_CHECK 2 /*! \brief Refresh action states Sent after a batch of modifications were made to action states. */ -#define KMSG_ACT_REFRESH 3 +#define KMSG_ACT_REFRESH 3 + +/*! \brief A new action was created + + Sent when a new custom action was created. The \a uparam + parameter of the message contains the identifier of the newly + created action. +*/ +#define KMSG_ACT_NEW 4 + +/*! \brief A custom action was deleted + + Sent after a custom action is deleted. The \a uparam parameter of + the message contains the identifier of the deleted action. + */ +#define KMSG_ACT_DELETE 5 + +/*! \brief A custom action has been activated + + When a custom action is activated, then the listener of that + custom action receives this message. Note that only the listener + for that custom action will receive this notification. + + \a uparam of the message is set to the identifier of the custom + action. + */ +#define KMSG_ACT_ACTIVATE 6 +/*! \brief Internal */ #define KMSG_ACT_BEGIN_CMDLINE 128 +/*! \brief Internal */ #define KMSG_ACT_CONTINUE_CMDLINE 129 +/*! \brief Internal */ +#define KMSG_ACT_SYNC_CFG 130 + /*@}*/ /*! \defgroup kmq_msg_cred KMSG_CRED subtypes @@ -228,7 +261,7 @@ respective credentials. \note May be sent to individual credential subscriptions. -*/ + */ #define KMSG_CRED_REFRESH 2 /*! \brief Change the password @@ -266,7 +299,7 @@ /*! \brief Dialog setup - Once KMSG_CRED_NEW_CREDS has been responded to by all the + Once ::KMSG_CRED_NEW_CREDS has been responded to by all the credential types, the UI creates the dialog windows using the data supplied in the ::khui_new_creds_by_type structures and issues this message. Each credentials provider is expected to respond by @@ -282,7 +315,7 @@ /*! \brief Dialog pre-start Sent after all the credentials providers have responded to - KMSG_CRED_DIALOG_SETUP and all the initialization has been + ::KMSG_CRED_DIALOG_SETUP and all the initialization has been completed. Credentials providers are expected to respond to this message by loading any default data into the dialog controls for each credential type. @@ -348,8 +381,8 @@ processing. If the \a result field in the structure is set to - KHUI_NC_RESULT_GET_CREDS, then new credentials should be obtained - using the given data. + ::KHUI_NC_RESULT_PROCESS, then new credentials should be + obtained using the given data. Set the \a response field in the structure to indicate how the UI should proceed from here. @@ -516,6 +549,16 @@ */ #define KMSG_ALERT_CHECK_QUEUE 4 +/*! \brief Show a modal alert + + Message parameters: + - \b vparam : held pointer to a ::khui_alert object. + + \note the ::khui_alert object will be released when the queued + messages are displayed. + */ +#define KMSG_ALERT_SHOW_MODAL 5 + /*@}*/ /*! \defgroup kmq_msg_ident KMSG_IDENT Subtypes @@ -552,7 +595,7 @@ name to be validated will be in the \a name_src member. The buffer will be NULL terminated with a maximum limit of KCDB_IDENT_MAXCCH_NAME characters including the terminating - NULL. + NULL, consisting only of characters in KCDB_IDENT_VALID_CHARS The \a result member should be set to one of the following depending on the result of the validation: diff --git a/src/windows/identity/kconfig/api.c b/src/windows/identity/kconfig/api.c index 30e5f488f..72a20acbc 100644 --- a/src/windows/identity/kconfig/api.c +++ b/src/windows/identity/kconfig/api.c @@ -313,6 +313,47 @@ khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions, return rv; } +LONG +khcint_RegDeleteKey(HKEY hKey, + LPCWSTR lpSubKey) { + int i; + wchar_t sk_name[KCONF_MAXCCH_NAME]; + FILETIME ft; + size_t cch; + LONG rv = ERROR_SUCCESS; + + /* go through and find the case sensitive match for the key */ + + if (FAILED(StringCchLength(lpSubKey, KCONF_MAXCCH_NAME, &cch))) + return ERROR_BADKEY; + + for (i=0; ;i++) { + LONG l; + DWORD dw; + + dw = ARRAYLENGTH(sk_name); + l = RegEnumKeyEx(hKey, i, sk_name, &dw, + NULL, NULL, NULL, &ft); + + if (l != ERROR_SUCCESS) { + rv = ERROR_BADKEY; + goto _cleanup; + } + + if (!(wcsncmp(sk_name, lpSubKey, cch))) { + /* bingo! ?? */ + if ((sk_name[cch] == L'\0' || + sk_name[cch] == L'~')) { + rv = RegDeleteKey(hKey, sk_name); + goto _cleanup; + } + } + } + + _cleanup: + return rv; +} + LONG khcint_RegCreateKeyEx(HKEY hKey, LPCWSTR lpSubKey, @@ -533,14 +574,10 @@ khcint_space_open_key(kconf_conf_space * s, khm_int32 flags) { } if(!hk && (flags & KHM_FLAG_CREATE)) { khcint_RegCreateKeyEx(HKEY_CURRENT_USER, - s->regpath, - 0, - NULL, + s->regpath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, - NULL, - &hk, - &disp); + NULL, &hk, &disp); } if(hk) { EnterCriticalSection(&cs_conf_global); @@ -632,7 +669,7 @@ khcint_free_space(kconf_conf_space * r) { khm_int32 khcint_open_space_int(kconf_conf_space * parent, - wchar_t * sname, size_t n_sname, + const wchar_t * sname, size_t n_sname, khm_int32 flags, kconf_conf_space **result) { kconf_conf_space * p; kconf_conf_space * c; @@ -735,13 +772,13 @@ khcint_open_space_int(kconf_conf_space * parent, } KHMEXP khm_int32 KHMAPI -khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, +khc_open_space(khm_handle parent, const wchar_t * cspace, khm_int32 flags, khm_handle * result) { kconf_handle * h; kconf_conf_space * p; kconf_conf_space * c = NULL; size_t cbsize; - wchar_t * str; + const wchar_t * str; khm_int32 rv = KHM_ERROR_SUCCESS; if(!khc_is_config_running()) { @@ -781,7 +818,7 @@ khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, str = cspace; while(TRUE) { - wchar_t * end = NULL; + const wchar_t * end = NULL; if (!(flags & KCONF_FLAG_NOPARSENAME)) { @@ -1788,16 +1825,17 @@ khc_value_exists(khm_handle conf, wchar_t * value) { c = khc_space_from_handle(conf); - if(!khc_is_machine_handle(conf)) + if (khc_is_user_handle(conf)) hku = khcint_space_open_key(c, KHM_PERM_READ); - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + if (khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); if(hku && (RegQueryValueEx(hku, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS)) rv |= KCONF_FLAG_USER; if(hkm && (RegQueryValueEx(hkm, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS)) rv |= KCONF_FLAG_MACHINE; - if(c->schema) { + if(c->schema && khc_is_schema_handle(conf)) { for(i=0; inSchema; i++) { if(!wcscmp(c->schema[i].name, value)) { rv |= KCONF_FLAG_SCHEMA; @@ -1856,14 +1894,26 @@ khc_remove_value(khm_handle conf, wchar_t * value, khm_int32 flags) { return rv; } +/* called with cs_conf_global held */ khm_int32 khcint_remove_space(kconf_conf_space * c, khm_int32 flags) { kconf_conf_space * cc; kconf_conf_space * cn; + kconf_conf_space * p; /* TODO: if this is the last child space and the parent is marked for deletion, delete the parent as well. */ + p = TPARENT(c); + + /* We don't allow deleting top level keys. They are + predefined. */ +#ifdef DEBUG + assert(p); +#endif + if (!p) + return KHM_ERROR_INVALID_OPERATION; + cc = TFIRSTCHILD(c); while (cc) { cn = LNEXT(cc); @@ -1874,40 +1924,38 @@ khcint_remove_space(kconf_conf_space * c, khm_int32 flags) { } cc = TFIRSTCHILD(c); - if (!cc) { - kconf_conf_space * p; - - if (c->refcount) { - c->flags |= (flags & - (KCONF_SPACE_FLAG_DELETE_M | - KCONF_SPACE_FLAG_DELETE_U)); - } else { - p = TPARENT(c); - - TDELCHILD(p, c); - - if (c->regpath) { - if (flags & KCONF_SPACE_FLAG_DELETE_U) - RegDeleteKey(HKEY_CURRENT_USER, - c->regpath); - if (flags & KCONF_SPACE_FLAG_DELETE_M) - RegDeleteKey(HKEY_LOCAL_MACHINE, - c->regpath); - } - - khcint_free_space(c); - } + if (!cc && c->refcount == 0) { + TDELCHILD(p, c); + khcint_free_space(c); } else { c->flags |= (flags & (KCONF_SPACE_FLAG_DELETE_M | KCONF_SPACE_FLAG_DELETE_U)); } + if (c->regpath && p->regpath) { + HKEY hk; + + if (flags & KCONF_SPACE_FLAG_DELETE_U) { + hk = khcint_space_open_key(p, KCONF_FLAG_USER); + + if (hk) + khcint_RegDeleteKey(hk, c->name); + } + if (flags & KCONF_SPACE_FLAG_DELETE_M) { + hk = khcint_space_open_key(p, KCONF_FLAG_MACHINE); + + if (hk) + khcint_RegDeleteKey(hk, c->name); + } + } + return KHM_ERROR_SUCCESS; } KHMEXP khm_int32 KHMAPI khc_remove_space(khm_handle conf) { + /* - mark this space as well as all child spaces as 'delete-on-close' using flags. Mark should indicate which diff --git a/src/windows/identity/kconfig/kconfig.h b/src/windows/identity/kconfig/kconfig.h index 4e9a49e9b..5ec65f703 100644 --- a/src/windows/identity/kconfig/kconfig.h +++ b/src/windows/identity/kconfig/kconfig.h @@ -42,7 +42,7 @@ \see kconf_load_schema() */ -typedef struct kconf_schema_t { +typedef struct tag_kconf_schema { wchar_t * name; /*!< name of the object being described. Optional for KC_ENDSPACE type object, but required for everything else. @@ -63,7 +63,7 @@ typedef struct kconf_schema_t { not support defining a default value here. */ wchar_t * description;/*!< a friendly description of the value - or configuration space */ + or configuration space. */ } kconf_schema; /*! \name Configuration data types @@ -153,12 +153,12 @@ typedef struct kconf_schema_t { By default, the configuration space name, \code - L"foo/bar" + L"foo\\bar" \endcode is taken to mean the configuration space \a bar which is a subspace of \a foo. If ::KCONF_FLAG_NOPARSENAME is set, then this - is taken to mean configuration space \a foo/bar. + is taken to mean configuration space \a foo\\bar. */ #define KCONF_FLAG_NOPARSENAME 0x00000040 @@ -229,7 +229,7 @@ typedef struct kconf_schema_t { */ KHMEXP khm_int32 KHMAPI -khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, +khc_open_space(khm_handle parent, const wchar_t * cspace, khm_int32 flags, khm_handle * result); /*! \brief Set the shadow space for a configuration handle diff --git a/src/windows/identity/kcreddb/attrib.c b/src/windows/identity/kcreddb/attrib.c index f77ebccf1..4e9d7bf34 100644 --- a/src/windows/identity/kcreddb/attrib.c +++ b/src/windows/identity/kcreddb/attrib.c @@ -173,13 +173,22 @@ kcdb_attr_sys_cb(khm_handle vcred, *((FILETIME *) buf) = IntToFt(_I64_MAX); } else { FILETIME ftc; + khm_int64 i_re; + khm_int64 i_ct; GetSystemTimeAsFileTime(&ftc); - *((FILETIME *) buf) = - IntToFt(FtToInt(((FILETIME *) - kcdb_cred_buf_get(c,KCDB_ATTR_RENEW_EXPIRE)) - - FtToInt(&ftc))); + i_re = FtToInt(((FILETIME *) + kcdb_cred_buf_get(c, KCDB_ATTR_RENEW_EXPIRE))); + i_ct = FtToInt(&ftc); + + if (i_re > i_ct) + *((FILETIME *) buf) = + IntToFt(i_re - i_ct); + else + *((FILETIME *) buf) = + IntToFt(0); + *pcb_buf = sizeof(FILETIME); } @@ -329,7 +338,7 @@ kcdb_attrib_init(void) LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf)); attrib.short_desc = sbuf; attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | KCDB_ATTR_FLAG_HIDDEN; attrib.compute_cb = NULL; attrib.compute_min_cbsize = 0; attrib.compute_max_cbsize = 0; @@ -392,8 +401,8 @@ kcdb_attrib_init(void) KCDB_ATTR_FLAG_ALTVIEW | KCDB_ATTR_FLAG_VOLATILE; attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(__int64); - attrib.compute_max_cbsize = sizeof(__int64); + attrib.compute_min_cbsize = sizeof(FILETIME); + attrib.compute_max_cbsize = sizeof(FILETIME); kcdb_attrib_register(&attrib, NULL); @@ -411,8 +420,8 @@ kcdb_attrib_init(void) KCDB_ATTR_FLAG_ALTVIEW | KCDB_ATTR_FLAG_VOLATILE; attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(__int64); - attrib.compute_max_cbsize = sizeof(__int64); + attrib.compute_min_cbsize = sizeof(FILETIME); + attrib.compute_max_cbsize = sizeof(FILETIME); kcdb_attrib_register(&attrib, NULL); diff --git a/src/windows/identity/kcreddb/credential.c b/src/windows/identity/kcreddb/credential.c index 37f246534..6886cc5b6 100644 --- a/src/windows/identity/kcreddb/credential.c +++ b/src/windows/identity/kcreddb/credential.c @@ -156,10 +156,23 @@ KHMEXP khm_int32 KHMAPI kcdb_cred_update(khm_handle vdest, kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf); rv = KHM_ERROR_SUCCESS; -_skip_copy: + _skip_copy: kcdb_attrib_release_info(a); kcdb_type_release_info(t); - } + } else { + if (KHM_FAILED(kcdb_attrib_get_info(i, &a))) + continue; + + if (!(a->flags & KCDB_ATTR_FLAG_COMPUTED) && + (a->flags & KCDB_ATTR_FLAG_TRANSIENT) && + kcdb_cred_val_exist(dest, i)) { + kcdb_buf_set_value(&dest->buf, i, i, NULL, 0); + + rv = KHM_ERROR_SUCCESS; + } + + kcdb_attrib_release_info(a); + } } if (dest->flags != src->flags) { @@ -174,7 +187,7 @@ _skip_copy: rv = KHM_ERROR_SUCCESS; } -_exit: + _exit: kcdb_cred_unlock_write(); return rv; } diff --git a/src/windows/identity/kcreddb/credset.c b/src/windows/identity/kcreddb/credset.c index 9be551ba1..dda9817d3 100644 --- a/src/windows/identity/kcreddb/credset.c +++ b/src/windows/identity/kcreddb/credset.c @@ -31,7 +31,8 @@ CRITICAL_SECTION cs_credset; kcdb_credset * kcdb_credsets = NULL; kcdb_credset * kcdb_root_credset = NULL; -void kcdb_credset_init(void) +void +kcdb_credset_init(void) { khm_handle rc; @@ -43,14 +44,16 @@ void kcdb_credset_init(void) kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT; } -void kcdb_credset_exit(void) +void +kcdb_credset_exit(void) { /*TODO: free the credsets */ DeleteCriticalSection(&cs_credset); } /* called on an unreleased credset, or with credset::cs held */ -void kcdb_credset_buf_new(kcdb_credset * cs) +void +kcdb_credset_buf_new(kcdb_credset * cs) { cs->clist = PMALLOC(KCDB_CREDSET_INITIAL_SIZE * sizeof(kcdb_credset_credref)); @@ -62,14 +65,16 @@ void kcdb_credset_buf_new(kcdb_credset * cs) } /* called on an unreleased credset, or with credset::cs held */ -void kcdb_credset_buf_delete(kcdb_credset * cs) +void +kcdb_credset_buf_delete(kcdb_credset * cs) { PFREE(cs->clist); cs->nc_clist = 0; cs->nclist = 0; } -void kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist) +void +kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist) { if(cs->nc_clist < nclist) { kcdb_credset_credref * new_clist; @@ -89,7 +94,8 @@ void kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist) } } -KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result) +KHMEXP khm_int32 KHMAPI +kcdb_credset_create(khm_handle * result) { kcdb_credset * cs; @@ -112,7 +118,8 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result) return KHM_ERROR_SUCCESS; } -KHMEXP khm_int32 KHMAPI kcdb_credset_delete(khm_handle vcredset) +KHMEXP khm_int32 KHMAPI +kcdb_credset_delete(khm_handle vcredset) { kcdb_credset * cs; int i; @@ -227,12 +234,12 @@ kcdb_credset_collect_core(kcdb_credset * cs1, return KHM_ERROR_SUCCESS; } -KHMEXP khm_int32 KHMAPI kcdb_credset_collect( - khm_handle cs_dest, - khm_handle cs_src, - khm_handle identity, - khm_int32 type, - khm_int32 * delta) +KHMEXP khm_int32 KHMAPI +kcdb_credset_collect(khm_handle cs_dest, + khm_handle cs_src, + khm_handle identity, + khm_int32 type, + khm_int32 * delta) { kcdb_credset * cs; kcdb_credset * rcs; @@ -317,12 +324,12 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_collect( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_collect_filtered( - khm_handle cs_dest, - khm_handle cs_src, - kcdb_cred_filter_func filter, - void * rock, - khm_int32 * delta) +KHMEXP khm_int32 KHMAPI +kcdb_credset_collect_filtered(khm_handle cs_dest, + khm_handle cs_src, + kcdb_cred_filter_func filter, + void * rock, + khm_int32 * delta) { kcdb_credset * cs; kcdb_credset * rcs; @@ -418,7 +425,8 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_collect_filtered( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_flush(khm_handle vcredset) +KHMEXP khm_int32 KHMAPI +kcdb_credset_flush(khm_handle vcredset) { int i; kcdb_credset * cs; @@ -448,11 +456,11 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_flush(khm_handle vcredset) return KHM_ERROR_SUCCESS; } -KHMEXP khm_int32 KHMAPI kcdb_credset_extract( - khm_handle destcredset, - khm_handle sourcecredset, - khm_handle identity, - khm_int32 type) +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract(khm_handle destcredset, + khm_handle sourcecredset, + khm_handle identity, + khm_int32 type) { khm_int32 code = KHM_ERROR_SUCCESS; kcdb_credset * dest; @@ -500,7 +508,7 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_extract( c = src->clist[i].cred; if(kcdb_cred_is_active_cred((khm_handle) c) && (!identity || c->identity == identity) && - (type==KCDB_TYPE_INVALID || c->type == type)) + (type < 0 || c->type == type)) { if(isRoot) { khm_handle newcred; @@ -527,11 +535,11 @@ _exit: return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_extract_filtered( - khm_handle destcredset, - khm_handle sourcecredset, - kcdb_cred_filter_func filter, - void * rock) +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract_filtered(khm_handle destcredset, + khm_handle sourcecredset, + kcdb_cred_filter_func filter, + void * rock) { khm_int32 code = KHM_ERROR_SUCCESS; kcdb_credset * dest; @@ -607,7 +615,9 @@ _exit: return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_func f, void * rock) +KHMEXP khm_int32 KHMAPI +kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_func f, + void * rock) { kcdb_credset * cs; khm_int32 rv = KHM_ERROR_SUCCESS; @@ -648,10 +658,10 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_ return rv; } -KHMEXP khm_int32 KHMAPI kcdb_credset_get_cred( - khm_handle vcredset, - khm_int32 idx, - khm_handle * cred) +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_cred(khm_handle vcredset, + khm_int32 idx, + khm_handle * cred) { kcdb_credset * cs; khm_int32 code = KHM_ERROR_SUCCESS; @@ -681,13 +691,13 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_get_cred( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_find_filtered( - khm_handle credset, - khm_int32 idx_start, - kcdb_cred_filter_func f, - void * rock, - khm_handle * cred, - khm_int32 * idx) +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_filtered(khm_handle credset, + khm_int32 idx_start, + kcdb_cred_filter_func f, + void * rock, + khm_handle * cred, + khm_int32 * idx) { kcdb_credset * cs; khm_int32 rv = KHM_ERROR_SUCCESS; @@ -782,9 +792,9 @@ kcdb_credset_find_cred(khm_handle vcredset, } } -KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred( - khm_handle vcredset, - khm_int32 idx) +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred(khm_handle vcredset, + khm_int32 idx) { kcdb_credset * cs; khm_int32 code = KHM_ERROR_SUCCESS; @@ -825,9 +835,9 @@ _exit: return code; } -khm_int32 kcdb_credset_update_cred_ref( - khm_handle credset, - khm_handle cred) +khm_int32 +kcdb_credset_update_cred_ref(khm_handle credset, + khm_handle cred) { kcdb_credset * cs; khm_int32 code = KHM_ERROR_SUCCESS; @@ -855,9 +865,9 @@ khm_int32 kcdb_credset_update_cred_ref( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred_ref( - khm_handle credset, - khm_handle cred) +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred_ref(khm_handle credset, + khm_handle cred) { kcdb_credset * cs; khm_int32 code = KHM_ERROR_SUCCESS; @@ -888,10 +898,10 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred_ref( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_add_cred( - khm_handle credset, - khm_handle cred, - khm_int32 idx) +KHMEXP khm_int32 KHMAPI +kcdb_credset_add_cred(khm_handle credset, + khm_handle cred, + khm_int32 idx) { int new_idx; kcdb_credset * cs; @@ -930,9 +940,9 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_add_cred( return code; } -KHMEXP khm_int32 KHMAPI kcdb_credset_get_size( - khm_handle credset, - khm_size * size) +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_size(khm_handle credset, + khm_size * size) { kcdb_credset * cs; @@ -957,7 +967,8 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_get_size( return KHM_ERROR_SUCCESS; } -KHMEXP khm_int32 KHMAPI kcdb_credset_purge(khm_handle credset) +KHMEXP khm_int32 KHMAPI +kcdb_credset_purge(khm_handle credset) { khm_int32 code = KHM_ERROR_SUCCESS; kcdb_credset * cs; @@ -1037,7 +1048,8 @@ kcdb_credset_unseal(khm_handle credset) { /* wrapper for qsort and also parameter gobbling FSM. */ -int __cdecl kcdb_creds_comp_wrapper(const void * a, const void * b) +int __cdecl +kcdb_creds_comp_wrapper(const void * a, const void * b) { static void * rock = NULL; static kcdb_cred_comp_func comp = NULL; @@ -1057,10 +1069,10 @@ int __cdecl kcdb_creds_comp_wrapper(const void * a, const void * b) rock); } -KHMEXP khm_int32 KHMAPI kcdb_credset_sort( - khm_handle credset, - kcdb_cred_comp_func comp, - void * rock) +KHMEXP khm_int32 KHMAPI +kcdb_credset_sort(khm_handle credset, + kcdb_cred_comp_func comp, + void * rock) { khm_int32 code = KHM_ERROR_SUCCESS; kcdb_credset * cs; @@ -1082,16 +1094,17 @@ KHMEXP khm_int32 KHMAPI kcdb_credset_sort( kcdb_creds_comp_wrapper(rock, NULL); kcdb_creds_comp_wrapper(NULL, (void *) comp); - qsort(cs->clist, cs->nclist, sizeof(kcdb_credset_credref), kcdb_creds_comp_wrapper); + qsort(cs->clist, cs->nclist, + sizeof(kcdb_credset_credref), kcdb_creds_comp_wrapper); LeaveCriticalSection(&(cs->cs)); return code; } -KHMEXP khm_int32 KHMAPI kcdb_cred_comp_generic( - khm_handle cred1, - khm_handle cred2, - void * rock) +KHMEXP khm_int32 KHMAPI +kcdb_cred_comp_generic(khm_handle cred1, + khm_handle cred2, + void * rock) { kcdb_cred_comp_order * o = (kcdb_cred_comp_order *) rock; int i; diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c index e96c99608..b9b8194b1 100644 --- a/src/windows/identity/kcreddb/identity.c +++ b/src/windows/identity/kcreddb/identity.c @@ -1146,6 +1146,13 @@ kcdb_identpro_validate_name(const wchar_t * name) before calling the identity provider */ if(FAILED(StringCchLength(name, KCDB_IDENT_MAXCCH_NAME, &cch))) return KHM_ERROR_TOO_LONG; + + /* We can't really make an assumption about the valid characters + in an identity. So we let the identity provider decide */ +#ifdef VALIDATE_IDENTIY_CHARACTERS + if(wcsspn(name, KCDB_IDENT_VALID_CHARS) != cch) + return KHM_ERROR_INVALID_NAME; +#endif EnterCriticalSection(&cs_ident); if(kcdb_ident_sub != NULL) { @@ -1204,8 +1211,7 @@ kcdb_identpro_validate_identity(khm_handle identity) } KHMEXP khm_int32 KHMAPI -kcdb_identpro_canon_name( - const wchar_t * name_in, +kcdb_identpro_canon_name(const wchar_t * name_in, wchar_t * name_out, khm_size * cb_name_out) { @@ -1237,8 +1243,7 @@ kcdb_identpro_canon_name( namex.cb_name_dest = sizeof(name_tmp); namex.result = KHM_ERROR_NOT_IMPLEMENTED; - rv = kmq_send_sub_msg( - sub, + rv = kmq_send_sub_msg(sub, KMSG_IDENT, KMSG_IDENT_CANON_NAME, 0, @@ -1273,8 +1278,7 @@ kcdb_identpro_canon_name( } KHMEXP khm_int32 KHMAPI -kcdb_identpro_compare_name( - const wchar_t * name1, +kcdb_identpro_compare_name(const wchar_t * name1, const wchar_t * name2) { khm_handle sub; diff --git a/src/windows/identity/kcreddb/kcreddb.h b/src/windows/identity/kcreddb/kcreddb.h index 52ca980ef..7826a82c0 100644 --- a/src/windows/identity/kcreddb/kcreddb.h +++ b/src/windows/identity/kcreddb/kcreddb.h @@ -99,6 +99,9 @@ Functions, macros etc. for manipulating identities. name */ #define KCDB_IDENT_MAXCB_NAME (sizeof(wchar_t) * KCDB_IDENT_MAXCCH_NAME) +/*! \brief Valid characters in an identity name */ +#define KCDB_IDENT_VALID_CHARS L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._@-/" + /*! \name Flags for identities */ /*@{*/ @@ -1104,7 +1107,7 @@ kcdb_credset_flush(khm_handle credset); set. If set to NULL, matches all identities. \param[in] type The credential type to match in the source credential set. - If set to KCDB_TYPE_INVALID, matches all types. + If set to KCDB_CREDTYPE_INVALID, matches all types. \note This function does not check for duplicate credentials. @@ -1926,8 +1929,9 @@ kcdb_creds_is_equal(khm_handle cred1, /********************************************************************/ -/*! \defgroup kcdb_type Credential attribute types */ -/*@{*/ +/*! \defgroup kcdb_type Credential attribute types + +@{*/ /*! \brief Convert a field to a string @@ -2217,13 +2221,24 @@ kcdb_type_get_id(wchar_t *name, khm_int32 * id); info parameter is NULL, the function returns KHM_ERROR_SUCCESS if \a id is a valid type id, and returns KHM_ERROR_NOT_FOUND otherwise. + + \see kcdb_type_release_info() */ KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info); +/*! \brief Release a reference to a type info structure + + Releases the reference to the type information obtained with a + prior call to kcdb_type_get_info(). + */ KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info); +/*! \brief Get the name of a type + + Retrieves the non-localized name of the specified type. + */ KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, @@ -2659,6 +2674,16 @@ kcdb_attrib_get_ids(khm_int32 and_flags, required. */ #define KCDB_ATTR_FLAG_ALTVIEW 0x00000200 + +/*! \brief Transient attribute + + A transient attribute is one whose absence is meaningful. When + updating one record using another, if a transient attribute is + absent in the source but present in the destination, then the + attribute is removed from the destination. +*/ +#define KCDB_ATTR_FLAG_TRANSIENT 0x00000400 + /*@}*/ /*! \defgroup kcdb_credattr_idnames Standard attribute IDs and names */ @@ -2803,7 +2828,7 @@ kcdb_attrib_get_ids(khm_int32 and_flags, #define KCDB_ATTRNAME_FLAGS L"Flags" #define KCDB_ATTRNAME_PARENT_NAME L"Parent" -#define KCDB_ATTRNAME_ISSUE L"Issed" +#define KCDB_ATTRNAME_ISSUE L"Issued" #define KCDB_ATTRNAME_EXPIRE L"Expires" #define KCDB_ATTRNAME_RENEW_EXPIRE L"RenewExpires" #define KCDB_ATTRNAME_TIMELEFT L"TimeLeft" diff --git a/src/windows/identity/kcreddb/type.c b/src/windows/identity/kcreddb/type.c index 3df10482c..30771c07a 100644 --- a/src/windows/identity/kcreddb/type.c +++ b/src/windows/identity/kcreddb/type.c @@ -212,7 +212,7 @@ khm_int32 KHMAPI kcdb_type_date_toString( GetLocalTime(&st_now); FileTimeToSystemTime(ft, &st_d); SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl); - if(st_now.wYear == st_dl.wYear && + if (st_now.wYear == st_dl.wYear && st_now.wMonth == st_dl.wMonth && st_now.wDay == st_dl.wDay) today = 1; @@ -227,7 +227,6 @@ khm_int32 KHMAPI kcdb_type_date_toString( NULL, NULL, 0) * sizeof(wchar_t); - cbsize += sizeof(wchar_t); } cbsize += GetTimeFormat( @@ -238,8 +237,6 @@ khm_int32 KHMAPI kcdb_type_date_toString( NULL, 0) * sizeof(wchar_t); - cbsize += sizeof(wchar_t); - if(!buffer || *cb_buf < cbsize) { *cb_buf = cbsize; return KHM_ERROR_TOO_LONG; @@ -374,7 +371,11 @@ FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf) d = s / (3600*24); if(ift == _I64_MAX) { +#ifdef INDICATE_UNKNOWN_EXPIRY_TIMES LoadString(hinst_kcreddb, IDS_IVL_UNKNOWN, ibuf, sizeof(ibuf)/sizeof(wchar_t)); +#else + StringCbCopy(ibuf, sizeof(ibuf), L""); +#endif } else if(s < 0) { LoadString(hinst_kcreddb, IDS_IVL_EXPIRED, ibuf, sizeof(ibuf)/sizeof(wchar_t)); } else if(d > 0) { diff --git a/src/windows/identity/kherr/kherr.c b/src/windows/identity/kherr/kherr.c index d8b145d24..3b7a5d453 100644 --- a/src/windows/identity/kherr/kherr.c +++ b/src/windows/identity/kherr/kherr.c @@ -59,6 +59,8 @@ KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, khm_int32 filter, kherr_serial serial) { + khm_size idx; + assert(h); EnterCriticalSection(&cs_error); @@ -86,9 +88,21 @@ KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, KHERR_CTX_END | KHERR_CTX_ERROR; - ctx_handlers[n_ctx_handlers].h = h; - ctx_handlers[n_ctx_handlers].filter = filter; - ctx_handlers[n_ctx_handlers].serial = serial; + /* Since commit events are the most frequent, we put those + handlers at the top of the list. When dispatching a commit + event, we stop looking at the list when we find a filter that + doesn't filter for commit events. */ + if (filter & KHERR_CTX_EVTCOMMIT) { + idx = 0; + memmove(&ctx_handlers[1], &ctx_handlers[0], + n_ctx_handlers * sizeof(ctx_handlers[0])); + } else { + idx = n_ctx_handlers; + } + + ctx_handlers[idx].h = h; + ctx_handlers[idx].filter = filter; + ctx_handlers[idx].serial = serial; n_ctx_handlers++; @@ -139,7 +153,14 @@ void notify_ctx_event(enum kherr_ctx_event e, kherr_context * c) { if (h != ctx_handlers[i].h) i--; } - } + } else if (e == KHERR_CTX_EVTCOMMIT && + !(ctx_handlers[i].filter & KHERR_CTX_EVTCOMMIT)) { + /* All handlers that filter for commit events are at the + top of the list. If this handler wasn't filtering for + it, then there's no point in goint further down the + list. */ + break; + } } } @@ -384,7 +405,15 @@ void free_context(kherr_context * c) { void add_event(kherr_context * c, kherr_event * e) { + kherr_event * te; + EnterCriticalSection(&cs_error); + te = QBOTTOM(c); + if (te && !(te->flags & KHERR_RF_COMMIT)) { + notify_ctx_event(KHERR_CTX_EVTCOMMIT, c); + te->flags |= KHERR_RF_COMMIT; + } + QPUT(c,e); if(c->severity >= e->severity) { if (e->severity <= KHERR_ERROR) @@ -436,7 +465,8 @@ static void arg_from_param(DWORD_PTR ** parm, kherr_param p) { if (t == KEPT_INT32 || t == KEPT_UINT32 || t == KEPT_STRINGC || - t == KEPT_STRINGT) { + t == KEPT_STRINGT || + t == KEPT_PTR) { *(*parm)++ = (DWORD_PTR) parm_data(p); @@ -648,6 +678,9 @@ void resolve_event_strings(kherr_event * e) KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e) { + if (!e) + return; + EnterCriticalSection(&cs_error); resolve_event_strings(e); LeaveCriticalSection(&cs_error); @@ -673,7 +706,7 @@ KHMEXP void KHMAPI kherr_evaluate_last_event(void) { resolve_event_strings(e); -_exit: + _exit: LeaveCriticalSection(&cs_error); } @@ -1051,6 +1084,12 @@ KHMEXP void KHMAPI kherr_release_context(kherr_context * c) { kherr_event * e; kherr_context * p; + e = QBOTTOM(c); + if (e && !(e->flags & KHERR_RF_COMMIT)) { + notify_ctx_event(KHERR_CTX_EVTCOMMIT, c); + e->flags |= KHERR_RF_COMMIT; + } + notify_ctx_event(KHERR_CTX_END, c); p = TPARENT(c); @@ -1172,6 +1211,26 @@ KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e) return ee; } +KHMEXP kherr_event * KHMAPI kherr_get_prev_event(kherr_event * e) +{ + kherr_event * ee; + + EnterCriticalSection(&cs_error); + ee = QPREV(e); + LeaveCriticalSection(&cs_error); + + return ee; +} + +KHMEXP kherr_event * KHMAPI kherr_get_last_event(kherr_context * c) +{ + kherr_event * e; + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + LeaveCriticalSection(&cs_error); + return e; +} + KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c) { kherr_context * cc; diff --git a/src/windows/identity/kherr/kherr.h b/src/windows/identity/kherr/kherr.h index 6ae943e4e..99e785622 100644 --- a/src/windows/identity/kherr/kherr.h +++ b/src/windows/identity/kherr/kherr.h @@ -97,8 +97,9 @@ enum kherr_parm_types { KEPT_INT64, KEPT_UINT64, KEPT_STRINGC, /*!< String constant */ - KEPT_STRINGT /*!< String. Will be freed using + KEPT_STRINGT, /*!< String. Will be freed using free() when the event is freed */ + KEPT_PTR /*!< Pointer type. */ }; #ifdef _WIN32 @@ -114,16 +115,25 @@ typedef khm_ui_8 kherr_param; enum tag_kherr_severity { KHERR_FATAL = 0, /*!< Fatal error.*/ KHERR_ERROR, /*!< Non-fatal error. We'll probably - survive. See the suggested action. */ + survive. See the suggested action. */ KHERR_WARNING, /*!< Warning. Something almost broke - or soon will. See the suggested - action. */ + or soon will. See the suggested + action. */ KHERR_INFO, /*!< Informational. Something happened that we would like you to know about. */ - KHERR_DEBUG_3 = 64, /*!< Verbose debug level 3 (high) */ - KHERR_DEBUG_2 = 65, /*!< Verbose debug level 2 (medium) */ - KHERR_DEBUG_1 = 66, /*!< Verbose debug level 1 (low) */ + KHERR_DEBUG_1 = 64, /*!< Verbose debug level 1 (high) + Events at this severity level are + not required to be based on + localized strings. */ + KHERR_DEBUG_2 = 65, /*!< Verbose debug level 2 (medium) + Events at this severity level are + not required to be based on + localized strings. */ + KHERR_DEBUG_3 = 66, /*!< Verbose debug level 3 (low) + Events at this severity level are + not required to be based on + localized strings. */ KHERR_RESERVED_BANK = 127, /*!< Internal use */ KHERR_NONE = 128 /*!< Nothing interesting has happened so far */ @@ -255,10 +265,14 @@ enum kherr_event_flags { /*!< The event is a representation of a folded context. */ - KHERR_RF_INERT = 0x00040000 + KHERR_RF_INERT = 0x00040000, /*!< Inert event. The event has already been dealt with and is no longer considered significant. */ + KHERR_RF_COMMIT = 0x00080000 + /*!< Committed event. The commit + handlers for this event have already + been called. */ }; /*! \brief Serial number for error contexts */ @@ -284,7 +298,7 @@ typedef struct tag_kherr_context { context object. */ kherr_severity severity; - /*!< Severity level. One of the + /*!< Severity level. One of the severity levels listed below. This is the severity level of the context and is the maximum severity level of @@ -367,8 +381,10 @@ enum kherr_ctx_event { KHERR_CTX_BEGIN = 0x0001, /*!< A new context was created */ KHERR_CTX_DESCRIBE=0x0002, /*!< A context was described */ KHERR_CTX_END = 0x0004, /*!< A context was closed */ - KHERR_CTX_ERROR = 0x0008 /*!< A context switched to an error + KHERR_CTX_ERROR = 0x0008, /*!< A context switched to an error state */ + KHERR_CTX_EVTCOMMIT = 0x0010 /*!< A event was committed into the + context */ }; /*! \brief Context event handler @@ -428,6 +444,15 @@ typedef void (KHMAPI * kherr_ctx_handler)(enum kherr_ctx_event, still intact. The pointer that is supplied should not be used to obtain a handle on the context. + KHERR_CTX_EVTCOMMIT: An event was committed into the error + context. An event is committed when another event is reported + after the event, or if the context is closed. Since the last + event that is reported can still be modified by adding new + information, the event remains open until it is no longer the last + event or the context is no longer active. When this notification + is received, the last event in the context's event queue is the + event that was committed. + \param[in] h Context event handler, of type ::kherr_ctx_handler \param[in] filter A combination of ::kherr_ctx_event values @@ -585,6 +610,7 @@ kherr_reportf_ex(enum kherr_severity severity, #endif const wchar_t * long_desc_fmt, ...); +#define _reportf_ex kherr_reportf_ex /*! \brief Report a formatted message @@ -596,6 +622,7 @@ kherr_reportf_ex(enum kherr_severity severity, KHMEXP kherr_event * __cdecl kherr_reportf(const wchar_t * long_desc_fmt, ...); +#define _reportf kherr_reportf /*! \brief Create a parameter out of a transient string @@ -620,6 +647,7 @@ KHMEXP kherr_param kherr_dup_string(const wchar_t * s); #define _uint64(ui) kherr_val(KEPT_UINT64, ui) #define _cstr(cs) kherr_val(KEPT_STRINGC, cs) #define _tstr(ts) kherr_val(KEPT_STRINGT, ts) +#define _cptr(p) kherr_val(KEPT_PTR, p) #define _dupstr(s) kherr_dup_string(s) /* convenience macros for calling kherr_report */ @@ -887,9 +915,14 @@ KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, khm_ui_4 * num, khm_u The returned pointer is only valid as long as there is a hold on \a c. Once the context is released with a call to kherr_release_context() all pointers to events in the context - becomes invalid. + become invalid. - Use kherr_get_next_event() to obtain the other events. + In addition, the last event in a context may still be "active". A + thread can still modify the last event as long as the context is + active. + + \see kherr_get_next_event(), kherr_get_prev_event(), + kherr_get_last_event() */ KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c); @@ -903,10 +936,55 @@ KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c); The returned pointer is only valid as long as there is a hold on \a c. Once the context is released with a call to kherr_release_context() all pointers to events in the context - becomes invalid. + become invalid. + + In addition, the last event in a context may still be "active". A + thread can still modify the last event as long as the context is + active. + + \see kherr_get_first_event(), kherr_get_prev_event(), + kherr_get_last_event() */ KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e); +/*! \brief Get the previous event + + Returns a pointer to the event that was reported in the context + containing \a e prior to \a e being reported. + + The returned pointer is only valid as long as there is a hold on + the error context. Once the context is released with a call to + kherr_release_context() all pointers to events in the context + become invalid. + + In addition, the last event in a context may still be "active". A + thread can still modify the last event as long as the context is + active. + + \see kherr_get_first_event(), kherr_get_next_event(), + kherr_get_last_event() + */ +KHMEXP kherr_event * KHMAPI kherr_get_prev_event(kherr_event * e); + +/*! \brief Get the last event in an error context + + Returns a pointer to the last error event that that was reported + to the context \a c. + + The returned pointer is only valid as long as there is a hold on + the error context. Once the context is released with a call to + kherr_release_context(), all pointers to events in the context + become invalid. + + In addtion, the last event in a context may still be "active". A + thread can still modify the last event as long as the context is + active. + + \see kherr_get_first_event(), kherr_get_next_event(), + kherr_get_prev_event() + */ +KHMEXP kherr_event * KHMAPI kherr_get_last_event(kherr_context * c); + /*! \brief Get the first child context of a context Contexts are arranged in a hiearchy. This function returns the diff --git a/src/windows/identity/kmm/kmm.h b/src/windows/identity/kmm/kmm.h index 0dc7e4cea..be2981b96 100644 --- a/src/windows/identity/kmm/kmm.h +++ b/src/windows/identity/kmm/kmm.h @@ -146,8 +146,23 @@ typedef struct tag_kmm_plugin_info { failure */ kmm_plugin h_plugin; /*!< Handle to plugin */ + + khm_int32 flags; /*!< Flags for the plugin. Currently + this can only specify + ::KMM_PLUGIN_FLAG_DISABLED. */ } kmm_plugin_info; +/*! \brief The plugin is disabled + + This flag will be set in the \a flags field of the + ::kmm_plugin_info structure for a plugin that has been marked as + disabled. If the plugin is currently running, but marked as + disabled for future sessions, then this bit will be set in \a + flags , but the \a state of the plugin will indicate that the + plugin is running. + */ +#define KMM_PLUGIN_FLAG_DISABLED 0x0400 + /*! \name Plugin types @{*/ /*! \brief A credentials provider @@ -178,6 +193,7 @@ typedef struct tag_kmm_plugin_info { /*! \brief Plugin states */ enum _kmm_plugin_states { + KMM_PLUGIN_STATE_FAIL_INIT = -6, /*!< Failed to initialize */ KMM_PLUGIN_STATE_FAIL_UNKNOWN = -5, /*!< Failed due to unknown reasons */ KMM_PLUGIN_STATE_FAIL_MAX_FAILURE = -4, /*!< The plugin has @@ -796,6 +812,20 @@ kmm_release_plugin_info_i(kmm_plugin_info * info); KHMEXP khm_int32 KHMAPI kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next); +/*! \brief Enables or disables a plugin + + This function currently does not take effect immediately. However + it marks the plugin as enabled or disabled so that the next time + NetIDMgr starts, the module manager will act accordingly. + + \param[in] p Handle to the plugin + + \param[in] enable If non-zero, the plugin will be marked as + enabled. Otherwise the plugin will be marked as disabled. + */ +KHMEXP khm_int32 KHMAPI +kmm_enable_plugin(kmm_plugin p, khm_boolean enable); + /*! \brief Register a plugin The \a plugin member defines the plugin to be registered. The \a diff --git a/src/windows/identity/kmm/kmm_module.c b/src/windows/identity/kmm/kmm_module.c index d5a61c740..932bdf8ef 100644 --- a/src/windows/identity/kmm/kmm_module.c +++ b/src/windows/identity/kmm/kmm_module.c @@ -28,6 +28,9 @@ #include #include +/* should only be accessed from the registrar thread */ +khm_size kmm_active_modules = 0; + kmm_module_i * kmmint_get_module_i(wchar_t * name) { kmm_module_i * m; @@ -95,9 +98,6 @@ void kmmint_free_module(kmm_module_i * m) PFREE(m->version_info); PFREE(m); - - if (kmm_all_modules == NULL) - SetEvent(evt_exit); } KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) @@ -114,6 +114,7 @@ KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm) { kmm_module_i * m; + if(!kmm_is_module(vm)) return KHM_ERROR_INVALID_PARAM; @@ -131,14 +132,16 @@ KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm) khm_int32 kmmint_check_api_version(DWORD v) { - /* for now, we require an exact match. In the future when we are - swamped with so much time that we don't know what to do with - it, we can actually parse the apiversion.txt file and create a - compatibility table which we can check against the functions - used by the module and decide whether or not it is - compatible. */ - - if (v != KH_VERSION_API) + /* for now, we allow API versions in the range + KH_VERSION_API_MINCOMPAT through KH_VERSION_API, inclusive. In + the future when we are swamped with so much time that we don't + know what to do with it, we can actually parse the + apiversion.txt file and create a compatibility table which we + can check against the functions used by the module and decide + whether or not it is compatible. */ + + if (v < KH_VERSION_API_MINCOMPAT || + v > KH_VERSION_API) return KHM_ERROR_INCOMPATIBLE; else return KHM_ERROR_SUCCESS; @@ -582,6 +585,9 @@ kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) { info->state = m->state; info->h_module = vm; + + info->file_version = m->file_version; + info->product_version = m->prod_version; kmm_hold_module(vm); rv = KHM_ERROR_SUCCESS; @@ -629,6 +635,7 @@ kmm_load_default_modules(void) { if(KHM_FAILED(rv)) return rv; + _begin_task(KHERR_CF_TRANSITIVE); _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT); _describe(); @@ -652,6 +659,8 @@ kmm_load_default_modules(void) { if(csm) khc_close_space(csm); + _end_task(); + return rv; } diff --git a/src/windows/identity/kmm/kmm_plugin.c b/src/windows/identity/kmm/kmm_plugin.c index b8a90c9fe..665eb6330 100644 --- a/src/windows/identity/kmm/kmm_plugin.c +++ b/src/windows/identity/kmm/kmm_plugin.c @@ -160,6 +160,52 @@ kmmint_free_plugin(kmm_plugin_i * pi) PFREE(pi); } +KHMEXP khm_int32 KHMAPI +kmm_enable_plugin(kmm_plugin p, khm_boolean enable) { + kmm_plugin_i * pi; + khm_int32 rv = KHM_ERROR_NOT_FOUND; /* default to error */ + khm_handle csp_plugin = NULL; + khm_int32 flags; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_plugin(p)) { + rv = KHM_ERROR_INVALID_PARAM; + goto _cleanup; + } + + pi = kmm_plugin_from_handle(p); + + if (KHM_FAILED(rv = kmm_get_plugin_config(pi->p.name, 0, &csp_plugin))) { + goto _cleanup; + } + + if (KHM_FAILED(rv = khc_read_int32(csp_plugin, L"Flags", &flags))) { + goto _cleanup; + } + + if (enable) { + flags &= ~KMM_PLUGIN_FLAG_DISABLED; + pi->flags &= ~KMM_PLUGIN_FLAG_DISABLED; + } else { + flags |= KMM_PLUGIN_FLAG_DISABLED; + pi->flags |= KMM_PLUGIN_FLAG_DISABLED; + } + + if (KHM_FAILED(rv = khc_write_int32(csp_plugin, L"Flags", flags))) { + goto _cleanup; + } + + rv = KHM_ERROR_SUCCESS; + + _cleanup: + LeaveCriticalSection(&cs_kmm); + + if (csp_plugin) + khc_close_space(csp_plugin); + + return rv; +} + KHMEXP khm_int32 KHMAPI kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info) { khm_int32 rv = KHM_ERROR_SUCCESS; @@ -203,8 +249,10 @@ kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info) { info->state = pi->state; - info->h_plugin = p; kmm_hold_plugin(p); + info->h_plugin = p; + + info->flags = (pi->flags & KMM_PLUGIN_FLAG_DISABLED); _cleanup: LeaveCriticalSection(&cs_kmm); @@ -331,7 +379,7 @@ kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) p = kmmint_get_plugin_i(plugin->name); - /* released below or in kmm_init_module() */ + /* released below or in kmmint_init_module() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); if(p->state != KMM_PLUGIN_STATE_NONE && diff --git a/src/windows/identity/kmm/kmm_reg.c b/src/windows/identity/kmm/kmm_reg.c index 131cb7514..98b3cdd92 100644 --- a/src/windows/identity/kmm/kmm_reg.c +++ b/src/windows/identity/kmm/kmm_reg.c @@ -281,13 +281,40 @@ _exit: KHMEXP khm_int32 KHMAPI kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags) { - /*TODO: implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; + khm_handle csp_plugin = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmm_get_plugin_config(plugin, config_flags, &csp_plugin); + + if (KHM_FAILED(rv)) + goto _cleanup; + + rv = khc_remove_space(csp_plugin); + + _cleanup: + + if (csp_plugin) + khc_close_space(csp_plugin); + + return rv; } KHMEXP khm_int32 KHMAPI kmm_unregister_module(wchar_t * module, khm_int32 config_flags) { - /*TODO: implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; + khm_handle csp_module = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmm_get_module_config(module, config_flags, &csp_module); + + if (KHM_FAILED(rv)) + goto _cleanup; + + rv = khc_remove_space(csp_module); + + _cleanup: + if (csp_module) + khc_close_space(csp_module); + + return rv; } diff --git a/src/windows/identity/kmm/kmm_registrar.c b/src/windows/identity/kmm/kmm_registrar.c index 1e632c7ba..73651d44c 100644 --- a/src/windows/identity/kmm/kmm_registrar.c +++ b/src/windows/identity/kmm/kmm_registrar.c @@ -25,6 +25,9 @@ /* $Id$ */ #include +#ifdef DEBUG +#include +#endif static LONG pending_modules = 0; static LONG pending_plugins = 0; @@ -88,11 +91,10 @@ kmm_load_pending(void) { /*! \internal \brief Message handler for the registrar thread. */ -khm_boolean KHMAPI kmm_reg_cb( - khm_int32 msg_type, - khm_int32 msg_sub_type, - khm_ui_4 uparam, - void *vparam) +khm_boolean KHMAPI kmmint_reg_cb(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam) { /* we should only be getting anyway */ if(msg_type != KMSG_KMM || msg_sub_type != KMSG_KMM_I_REG) @@ -100,22 +102,22 @@ khm_boolean KHMAPI kmm_reg_cb( switch(uparam) { case KMM_REG_INIT_MODULE: - kmm_init_module((kmm_module_i *) vparam); + kmmint_init_module((kmm_module_i *) vparam); kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); break; case KMM_REG_EXIT_MODULE: - kmm_exit_module((kmm_module_i *) vparam); + kmmint_exit_module((kmm_module_i *) vparam); kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); break; case KMM_REG_INIT_PLUGIN: - kmm_init_plugin((kmm_plugin_i *) vparam); + kmmint_init_plugin((kmm_plugin_i *) vparam); kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); break; case KMM_REG_EXIT_PLUGIN: - kmm_exit_plugin((kmm_plugin_i *) vparam); + kmmint_exit_plugin((kmm_plugin_i *) vparam); kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); break; } @@ -126,15 +128,13 @@ khm_boolean KHMAPI kmm_reg_cb( \brief The registrar thread. The only thing this function does is to dispatch messages to the - callback routine ( kmm_reg_cb() ) */ -DWORD WINAPI kmm_registrar( - LPVOID lpParameter -) + callback routine ( kmmint_reg_cb() ) */ +DWORD WINAPI kmmint_registrar(LPVOID lpParameter) { tid_registrar = GetCurrentThreadId(); - kmq_subscribe(KMSG_KMM, kmm_reg_cb); - kmq_subscribe(KMSG_SYSTEM, kmm_reg_cb); + kmq_subscribe(KMSG_KMM, kmmint_reg_cb); + kmq_subscribe(KMSG_SYSTEM, kmmint_reg_cb); SetEvent(evt_startup); @@ -151,11 +151,15 @@ DWORD WINAPI kmm_registrar( Each plugin gets its own plugin thread which is used to dispatch messages to the plugin. This acts as the thread function for the plugin thread.*/ -DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter) +DWORD WINAPI kmmint_plugin_broker(LPVOID lpParameter) { DWORD rv = 0; kmm_plugin_i * p = (kmm_plugin_i *) lpParameter; + _begin_task(0); + _report_mr1(KHERR_NONE, MSG_PB_START, _cstr(p->p.name)); + _describe(); + TlsSetValue(tls_kmm, (LPVOID) p); kmm_hold_plugin(kmm_handle_from_plugin(p)); @@ -163,16 +167,46 @@ DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter) p->tid_thread = GetCurrentThreadId(); if (IsBadCodePtr(p->p.msg_proc)) { + _report_mr0(KHERR_WARNING, MSG_PB_INVALID_CODE_PTR); rv = KHM_ERROR_INVALID_PARAM; } else { - rv = (p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_INIT, - 0, (void *) &(p->p))); + rv = (*p->p.msg_proc)(KMSG_SYSTEM, KMSG_SYSTEM_INIT, + 0, (void *) &(p->p)); + _report_mr1(KHERR_INFO, MSG_PB_INIT_RV, _int32(rv)); } /* if it fails to initialize, we exit the plugin */ if(KHM_FAILED(rv)) { + + kherr_report(KHERR_ERROR, + (wchar_t *) MSG_PB_INIT_FAIL_S, + (wchar_t *) KHERR_FACILITY, + NULL, + (wchar_t *) MSG_PB_INIT_FAIL, + (wchar_t *) MSG_PB_INIT_FAIL_G, + KHERR_FACILITY_ID, + KHERR_SUGGEST_NONE, + _cstr(p->p.name), + _cstr(p->p.description), + _cstr(p->module->path), + _cstr(p->module->support), + KHERR_RF_MSG_SHORT_DESC | + KHERR_RF_MSG_LONG_DESC | + KHERR_RF_MSG_SUGGEST +#ifdef _WIN32 + ,KHERR_HMODULE +#endif + ); + _resolve(); + + /* exit the plugin first. Otherwise it may not uninitialize correctly */ + (*p->p.msg_proc)(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p)); + kmmint_remove_from_plugin_queue(p); rv = 1; + _end_task(); + + p->state = KMM_PLUGIN_STATE_FAIL_INIT; goto _exit; } @@ -196,6 +230,10 @@ DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter) p->state = KMM_PLUGIN_STATE_RUNNING; + _report_mr0(KHERR_INFO, MSG_PB_INIT_DONE); + + _end_task(); + /* if there were any plugins that were waiting for this one to start, we should start them too */ EnterCriticalSection(&cs_kmm); @@ -237,8 +275,9 @@ DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter) p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p)); -_exit: - p->state = KMM_PLUGIN_STATE_EXITED; + _exit: + if (p->state >= 0) + p->state = KMM_PLUGIN_STATE_EXITED; /* the following call will automatically release the plugin */ kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, @@ -255,17 +294,17 @@ _exit: /*! \internal \brief Initialize a plugin - \note If kmm_init_plugin() is called on a plugin, then kmm_exit_plugin() + \note If kmmint_init_plugin() is called on a plugin, then kmmint_exit_plugin() \b must be called for the plugin. \note Should only be called from the context of the registrar thread */ -void kmm_init_plugin(kmm_plugin_i * p) { +void kmmint_init_plugin(kmm_plugin_i * p) { DWORD dummy; khm_handle csp_plugin = NULL; khm_handle csp_plugins = NULL; khm_int32 t; - /* the following will be undone in kmm_exit_plugin() */ + /* the following will be undone in kmmint_exit_plugin() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); EnterCriticalSection(&cs_kmm); @@ -290,6 +329,10 @@ void kmm_init_plugin(kmm_plugin_i * p) { } p->state = KMM_PLUGIN_STATE_PREINIT; + + kmmint_delist_plugin(p); + kmmint_list_plugin(p); + LeaveCriticalSection(&cs_kmm); if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) { @@ -300,7 +343,7 @@ void kmm_init_plugin(kmm_plugin_i * p) { } if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin)) || - KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) { + KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) { if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); @@ -321,11 +364,11 @@ void kmm_init_plugin(kmm_plugin_i * p) { p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; goto _exit; } + } if(t & KMM_PLUGIN_FLAG_DISABLED) { - _report_mr0(KHERR_ERROR, MSG_IP_DISABLED); - + p->flags |= KMM_PLUGIN_FLAG_DISABLED; p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; goto _exit; } @@ -400,12 +443,9 @@ void kmm_init_plugin(kmm_plugin_i * p) { PFREE(deps); } while(FALSE); - LeaveCriticalSection(&cs_kmm); - EnterCriticalSection(&cs_kmm); p->module->plugin_count++; - kmmint_delist_plugin(p); - kmmint_list_plugin(p); + LeaveCriticalSection(&cs_kmm); if(p->state == KMM_PLUGIN_STATE_HOLD) { @@ -418,7 +458,7 @@ void kmm_init_plugin(kmm_plugin_i * p) { p->ht_thread = CreateThread(NULL, 0, - kmm_plugin_broker, + kmmint_plugin_broker, (LPVOID) p, CREATE_SUSPENDED, &dummy); @@ -466,18 +506,20 @@ _exit: linked list and hashtable, it also frees up p. \note Should only be called from the context of the registrar thread. */ -void kmm_exit_plugin(kmm_plugin_i * p) { +void kmmint_exit_plugin(kmm_plugin_i * p) { int np; + khm_boolean release_plugin = TRUE; if(p->state == KMM_PLUGIN_STATE_RUNNING || - p->state == KMM_PLUGIN_STATE_INIT) - { + p->state == KMM_PLUGIN_STATE_INIT) { + kmq_post_thread_quit_message(p->tid_thread, 0, NULL); /* when we post the quit message to the plugin thread, the plugin broker terminates the plugin and posts a EXIT_PLUGIN message, which calls this function again. We just exit here because the EXIT_PLUGIN message will end up calling us again momentarily */ return; + } if(p->ht_thread) { @@ -488,16 +530,25 @@ void kmm_exit_plugin(kmm_plugin_i * p) { EnterCriticalSection(&cs_kmm); - /* undo reference count done in kmm_init_plugin() */ + /* undo reference count done in kmmint_init_plugin() */ if(p->state == KMM_PLUGIN_STATE_EXITED || - p->state == KMM_PLUGIN_STATE_HOLD) - { + p->state == KMM_PLUGIN_STATE_HOLD) { + np = --(p->module->plugin_count); + } else { /* the plugin was never active. We can't base a module unload decision on np */ np = TRUE; } + + /* The plugin is in an error state. We need to keep the plugin + record in tact so that the failure information is kept + around. */ + if (p->state < KMM_PLUGIN_STATE_NONE) { + release_plugin = FALSE; + } + LeaveCriticalSection(&cs_kmm); if(!np) { @@ -507,8 +558,9 @@ void kmm_exit_plugin(kmm_plugin_i * p) { kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module); } - /* release the hold obtained in kmm_init_plugin() */ - kmm_release_plugin(kmm_handle_from_plugin(p)); + /* release the hold obtained in kmmint_init_plugin() */ + if (release_plugin) + kmm_release_plugin(kmm_handle_from_plugin(p)); } /*! \internal @@ -517,7 +569,7 @@ void kmm_exit_plugin(kmm_plugin_i * p) { \a m is not in the linked list yet. \note Should only be called from the context of the registrar thread. */ -void kmm_init_module(kmm_module_i * m) { +void kmmint_init_module(kmm_module_i * m) { HMODULE hm; init_module_t p_init_module; kmm_plugin_i * pi; @@ -666,6 +718,10 @@ void kmm_init_module(kmm_module_i * m) { /* from this point on, we need to discard the module through exit_module */ + ResetEvent(evt_exit); + + kmm_active_modules++; + release_module = FALSE; exit_module = TRUE; @@ -711,7 +767,7 @@ void kmm_init_module(kmm_module_i * m) { LPOP(&(m->plugins), &pi); if(pi) { pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; - kmm_init_plugin(pi); + kmmint_init_plugin(pi); /* release the hold obtained in kmm_provide_plugin() */ kmm_release_plugin(kmm_handle_from_plugin(pi)); @@ -719,9 +775,14 @@ void kmm_init_module(kmm_module_i * m) { } while(pi); if(!m->plugin_count) { + /* We don't want to report this case. This usually means that + the plugins that were provided by the module were + disabled. */ +#ifdef REPORT_EMPTY_MODULES _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; +#endif record_failure = FALSE; goto _exit; } @@ -731,8 +792,6 @@ void kmm_init_module(kmm_module_i * m) { exit_module = FALSE; record_failure = FALSE; - ResetEvent(evt_exit); - _exit: if(csp_mod) { if(record_failure) { @@ -764,7 +823,7 @@ void kmm_init_module(kmm_module_i * m) { /* if something went wrong after init_module was called on the module code, we need to call exit_module */ if(exit_module) - kmm_exit_module(m); + kmmint_exit_module(m); if(release_module) kmm_release_module(kmm_handle_from_module(m)); @@ -822,21 +881,21 @@ void kmm_init_module(kmm_module_i * m) { \note Should only be called from the context of the registrar thread */ -void kmm_exit_module(kmm_module_i * m) { +void kmmint_exit_module(kmm_module_i * m) { kmm_plugin_i * p; - /* exiting a module happens in two stages. - + /* Exiting a module happens in two stages. + If the module state is running (there are active plugins) then those plugins must be exited. This has to be done from the plugin threads. The signal for the plugins to exit must be issued from the registrar. Therefore, we post messages to the registrar for each plugin we want to remove and exit - kmm_exit_module(). + kmmint_exit_module(). When the last plugin is exited, the plugin management code automatically signalls the registrar to remove the module. - kmm_exit_module() gets called again. This is the second + kmmint_exit_module() gets called again. This is the second stage, where we call exit_module() for the module and start unloading everything. */ @@ -847,7 +906,7 @@ void kmm_exit_module(kmm_module_i * m) { LPOP(&(m->plugins), &p); while(p) { p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; - kmm_exit_plugin(p); + kmmint_exit_plugin(p); /* release hold from kmm_provide_plugin() */ kmm_release_plugin(kmm_handle_from_plugin(p)); @@ -883,8 +942,7 @@ void kmm_exit_module(kmm_module_i * m) { } } - if(m->flags & KMM_MODULE_FLAG_INITP) - { + if(m->flags & KMM_MODULE_FLAG_INITP) { exit_module_t p_exit_module; if(m->state > 0) @@ -895,16 +953,16 @@ void kmm_exit_module(kmm_module_i * m) { EXP_EXIT_MODULE); if(p_exit_module) { LeaveCriticalSection(&cs_kmm); - p_exit_module(kmm_handle_from_module(m)); + (*p_exit_module)(kmm_handle_from_module(m)); EnterCriticalSection(&cs_kmm); } } - LeaveCriticalSection(&cs_kmm); - if(m->state > 0) m->state = KMM_MODULE_STATE_EXITED; + LeaveCriticalSection(&cs_kmm); + if(m->h_module) { FreeLibrary(m->h_module); } @@ -917,6 +975,19 @@ void kmm_exit_module(kmm_module_i * m) { m->h_resource = NULL; m->flags = 0; - /* release the hold obtained in kmm_init_module() */ + /* release the hold obtained in kmmint_init_module() */ kmm_release_module(kmm_handle_from_module(m)); + + /* Last but not least, now see if there are any modules left that + are running. If not, we can safely signal an exit. */ + +#ifdef DEBUG + assert(kmm_active_modules > 0); +#endif + + kmm_active_modules--; + + if (kmm_active_modules == 0) { + SetEvent(evt_exit); + } } diff --git a/src/windows/identity/kmm/kmminternal.h b/src/windows/identity/kmm/kmminternal.h index c4e472387..e0ce6b270 100644 --- a/src/windows/identity/kmm/kmminternal.h +++ b/src/windows/identity/kmm/kmminternal.h @@ -131,19 +131,23 @@ typedef struct kmm_plugin_i_t { #define kmm_plugin_from_handle(ph) ((kmm_plugin_i *) ph) /* the plugin has already been marked for unload */ -#define KMM_PLUGIN_FLAG_UNLOAD 1 - -/* the plugin is disabled by the user - (option specified in configuration) */ -#define KMM_PLUGIN_FLAG_DISABLED 1024 +#define KMM_PLUGIN_FLAG_UNLOAD 0x0001 /* the plugin is in the kmm_listed_plugins list */ -#define KMM_PLUGIN_FLAG_IN_LIST 2 +#define KMM_PLUGIN_FLAG_IN_LIST 0x0002 /* the plugin is in the module's plugin list */ -#define KMM_PLUGIN_FLAG_IN_MODLIST 4 +#define KMM_PLUGIN_FLAG_IN_MODLIST 0x0004 + +#define KMM_PLUGIN_FLAG_IN_QUEUE 0x0010 + +/* the plugin is disabled by the user + (option specified in configuration) */ +/* (this is defined in kmm.h) + + #define KMM_PLUGIN_FLAG_DISABLED 0x0400 -#define KMM_PLUGIN_FLAG_IN_QUEUE 0x10 +*/ enum kmm_registrar_uparam_t { KMM_REG_INIT_MODULE, @@ -153,6 +157,7 @@ enum kmm_registrar_uparam_t { }; extern kmm_module_i * kmm_all_modules; +extern khm_size kmm_active_modules; extern kmm_plugin_i * kmm_listed_plugins; extern HANDLE ht_registrar; extern DWORD tid_registrar; @@ -174,19 +179,19 @@ extern kconf_schema schema_kmmconfig[]; /* Registrar */ khm_boolean KHMAPI -kmm_reg_cb(khm_int32 msg_type, - khm_int32 msg_sub_type, - khm_ui_4 uparam, - void *vparam); +kmmint_reg_cb(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam); -DWORD WINAPI kmm_registrar(LPVOID lpParameter); +DWORD WINAPI kmmint_registrar(LPVOID lpParameter); -DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter); +DWORD WINAPI kmmint_plugin_broker(LPVOID lpParameter); -void kmm_init_plugin(kmm_plugin_i * p); -void kmm_exit_plugin(kmm_plugin_i * p); -void kmm_init_module(kmm_module_i * m); -void kmm_exit_module(kmm_module_i * m); +void kmmint_init_plugin(kmm_plugin_i * p); +void kmmint_exit_plugin(kmm_plugin_i * p); +void kmmint_init_module(kmm_module_i * m); +void kmmint_exit_module(kmm_module_i * m); /* Modules */ kmm_module_i * diff --git a/src/windows/identity/kmm/kmmmain.c b/src/windows/identity/kmm/kmmmain.c index 6489313f8..aa94a59a1 100644 --- a/src/windows/identity/kmm/kmmmain.c +++ b/src/windows/identity/kmm/kmmmain.c @@ -72,7 +72,7 @@ KHMEXP void KHMAPI kmm_init(void) ht_registrar = CreateThread( NULL, 0, - kmm_registrar, + kmmint_registrar, NULL, 0, &dummy); diff --git a/src/windows/identity/kmm/lang/kmm_msgs.mc b/src/windows/identity/kmm/lang/kmm_msgs.mc index 17bc6b80e..a33c523ac 100644 --- a/src/windows/identity/kmm/lang/kmm_msgs.mc +++ b/src/windows/identity/kmm/lang/kmm_msgs.mc @@ -212,3 +212,48 @@ SymbolicName=MSG_RMI_API_MISMATCH Language=English The module was compile for API version %1!d!. However the current API version is %2!d!. . + +MessageId= +SymbolicName=MSG_PB_START +Language=English +Starting plugin [%1!s!] +. + +MessageId= +SymbolicName=MSG_PB_INVALID_CODE_PTR +Language=English +The plugin is no longer valid. This maybe because the module containing the plugin was unloaded. +. + +MessageId= +SymbolicName=MSG_PB_INIT_RV +Language=English +Initialization of the plugin returned code %1!d!. +. + +MessageId= +SymbolicName=MSG_PB_INIT_FAIL +Language=English +Initialization of the %1!s! plugin failed. The plugin will be unloaded and any functionality provided will not be available. +. + +MessageId= +SymbolicName=MSG_PB_INIT_FAIL_S +Language=English +Plugin %1!s! failed to initialize +. + +MessageId= +SymbolicName=MSG_PB_INIT_FAIL_G +Language=English +Details for plugin: +Description: %2!s! +Module: %3!s! +Support: %4!s! +. + +MessageId= +SymbolicName=MSG_PB_INIT_DONE +Language=English +Plugin running +. diff --git a/src/windows/identity/kmq/consumer.c b/src/windows/identity/kmq/consumer.c index 03519bafd..ed7d548f1 100644 --- a/src/windows/identity/kmq/consumer.c +++ b/src/windows/identity/kmq/consumer.c @@ -216,6 +216,8 @@ KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd) { kmq_msg_subscription * s; s = PMALLOC(sizeof(kmq_msg_subscription)); + ZeroMemory(s, sizeof(*s)); + s->magic = KMQ_MSG_SUB_MAGIC; LINIT(s); s->queue = NULL; s->rcpt_type = KMQ_RCPTTYPE_HWND; @@ -232,6 +234,8 @@ KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb) { kmq_msg_subscription * s; s = PMALLOC(sizeof(kmq_msg_subscription)); + ZeroMemory(s, sizeof(*s)); + s->magic = KMQ_MSG_SUB_MAGIC; LINIT(s); s->queue = kmqint_get_thread_queue(); s->rcpt_type = KMQ_RCPTTYPE_CB; @@ -241,6 +245,28 @@ KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb) { return KHM_ERROR_SUCCESS; } +KHMEXP khm_int32 KHMAPI kmq_create_hwnd_subscription(HWND hw, + khm_handle * result) +{ + kmq_msg_subscription * s; + + s = PMALLOC(sizeof(kmq_msg_subscription)); + ZeroMemory(s, sizeof(*s)); + s->magic = KMQ_MSG_SUB_MAGIC; + LINIT(s); + s->queue = NULL; + s->rcpt_type = KMQ_RCPTTYPE_HWND; + s->recipient.hwnd = hw; + + EnterCriticalSection(&cs_kmq_global); + LPUSH(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + *result = (khm_handle) s; + + return KHM_ERROR_SUCCESS; +} + /*! \internal \note Obtains ::cs_kmq_global */ @@ -250,6 +276,8 @@ KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, kmq_msg_subscription * s; s = PMALLOC(sizeof(kmq_msg_subscription)); + ZeroMemory(s, sizeof(*s)); + s->magic = KMQ_MSG_SUB_MAGIC; LINIT(s); s->queue = kmqint_get_thread_queue(); s->rcpt_type = KMQ_RCPTTYPE_CB; @@ -270,6 +298,8 @@ KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub) s = (kmq_msg_subscription *) sub; + assert(s->magic == KMQ_MSG_SUB_MAGIC); + s->type = 0; EnterCriticalSection(&cs_kmq_global); diff --git a/src/windows/identity/kmq/init.c b/src/windows/identity/kmq/init.c index f157e6ab2..77b8dd0e1 100644 --- a/src/windows/identity/kmq/init.c +++ b/src/windows/identity/kmq/init.c @@ -77,10 +77,10 @@ void kmqint_exit(void) { void kmqint_attach_this_thread(void) { kmq_queue * q; + EnterCriticalSection(&cs_kmq_global); + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); if(!q) { - EnterCriticalSection(&cs_kmq_global); - q = PMALLOC(sizeof(kmq_queue)); InitializeCriticalSection(&q->cs); @@ -90,13 +90,14 @@ void kmqint_attach_this_thread(void) { q->wait_o = CreateEvent(NULL, FALSE, FALSE, NULL); q->load = 0; q->last_post = 0; + q->flags = 0; LPUSH(&queues, q); TlsSetValue(kmq_tls_queue, (LPVOID) q); - - LeaveCriticalSection(&cs_kmq_global); } + + LeaveCriticalSection(&cs_kmq_global); } /*! \internal @@ -108,18 +109,11 @@ void kmqint_detach_this_thread(void) { q = (kmq_queue *) TlsGetValue(kmq_tls_queue); if(q) { - EnterCriticalSection(&cs_kmq_global); - - LDELETE(&queues, q); - - DeleteCriticalSection(&q->cs); - CloseHandle(q->wait_o); + EnterCriticalSection(&q->cs); + q->flags |= KMQ_QUEUE_FLAG_DELETED; + LeaveCriticalSection(&q->cs); /* TODO: free up the queued messages */ - - TlsSetValue(kmq_tls_queue, (LPVOID) 0); - - LeaveCriticalSection(&cs_kmq_global); } } diff --git a/src/windows/identity/kmq/kmq.h b/src/windows/identity/kmq/kmq.h index 4c8c610cd..fef6a3096 100644 --- a/src/windows/identity/kmq/kmq.h +++ b/src/windows/identity/kmq/kmq.h @@ -149,6 +149,8 @@ typedef struct tag_kmq_queue { kmq_timer last_post; /*!< Time the last message was received */ + khm_int32 flags; /*!< Flags. Currently, it's just KMQ_QUEUE_FLAG_DELETED */ + /*Q*/ QDCL(kmq_message_ref); /*!< Queue of message references */ @@ -156,6 +158,8 @@ typedef struct tag_kmq_queue { LDCL(struct tag_kmq_queue); } kmq_queue; +#define KMQ_QUEUE_FLAG_DELETED 0x0008 + /*! \brief Message subscription A subscription binds a recipient with a message type. These are @@ -163,6 +167,8 @@ typedef struct tag_kmq_queue { thread will not receive messages in the context of another thread. */ typedef struct tag_kmq_msg_subscription { + khm_int32 magic; /*!< Magic number. Should always be + ::KMQ_MSG_SUB_MAGIC */ khm_int32 type; /*!< Type of message */ khm_int32 rcpt_type; /*!< Type of recipient. One of ::KMQ_RCPTTYPE_CB or @@ -180,6 +186,8 @@ typedef struct tag_kmq_msg_subscription { LDCL(struct tag_kmq_msg_subscription); } kmq_msg_subscription; +#define KMQ_MSG_SUB_MAGIC 0x3821b58e + /*! \brief Callback recipient type The recipient is a callback function */ @@ -482,6 +490,19 @@ KHMEXP khm_int32 KHMAPI kmq_create_subscription( kmq_callback_t cb, khm_handle * result); +/*! \brief Create an ad-hoc subscription for a window + + An ad-hoc subscription describes a window that will be dispatched + messages individually without broadcasting. + + \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(), + kmq_send_sub_msg(), kmq_post_subs_msg(), + kmq_post_subs_msg_ex(), kmq_send_subs_msg(), + kmq_delete_subscription() + */ +KHMEXP khm_int32 KHMAPI kmq_create_hwnd_subscription(HWND hw, + khm_handle * result); + /*! \brief Delete an ad-hoc subscription Deletes a subscriptoin that was created using diff --git a/src/windows/identity/nidmgrdll/Makefile b/src/windows/identity/nidmgrdll/Makefile index 03d3c3d54..d3f50021c 100644 --- a/src/windows/identity/nidmgrdll/Makefile +++ b/src/windows/identity/nidmgrdll/Makefile @@ -1,110 +1,120 @@ -# -# 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=nidmgrdll -!include <../config/Makefile.w32> - -DLLFILE=$(BINDIR)\nidmgr32.dll - -LIBFILE=$(LIBDIR)\nidmgr32.lib - -UTILDIR=$(OBJDIR)\util - -KHERRDIR=$(OBJDIR)\kherr - -KCONFIGDIR=$(OBJDIR)\kconfig - -KMQDIR=$(OBJDIR)\kmq - -KCDBDIR=$(OBJDIR)\kcreddb - -KMMDIR=$(OBJDIR)\kmm - -UIDIR=$(OBJDIR)\uilib - -OBJFILES= \ - $(OBJ)\dllmain.obj \ - $(UTILDIR)\hashtable.obj \ - $(UTILDIR)\sync.obj \ - $(UTILDIR)\mstring.obj \ - $(UTILDIR)\perfstat.obj \ - $(KHERRDIR)\kherrmain.obj \ - $(KHERRDIR)\kherr.obj \ - $(KCONFIGDIR)\kconfigmain.obj \ - $(KCONFIGDIR)\api.obj \ - $(KMQDIR)\kmqmain.obj \ - $(KMQDIR)\init.obj \ - $(KMQDIR)\msgtype.obj \ - $(KMQDIR)\consumer.obj \ - $(KMQDIR)\publisher.obj \ - $(KMQDIR)\kmqconfig.obj \ - $(KCDBDIR)\buf.obj \ - $(KCDBDIR)\attrib.obj \ - $(KCDBDIR)\credential.obj \ - $(KCDBDIR)\credset.obj \ - $(KCDBDIR)\credtype.obj \ - $(KCDBDIR)\identity.obj \ - $(KCDBDIR)\init.obj \ - $(KCDBDIR)\kcreddbmain.obj \ - $(KCDBDIR)\type.obj \ - $(KCDBDIR)\kcdbconfig.obj \ - $(KMMDIR)\kmmmain.obj \ - $(KMMDIR)\kmm.obj \ - $(KMMDIR)\kmm_plugin.obj \ - $(KMMDIR)\kmm_module.obj \ - $(KMMDIR)\kmm_reg.obj \ - $(KMMDIR)\kmm_registrar.obj \ - $(KMMDIR)\kmmconfig.obj \ - $(UIDIR)\rescache.obj \ - $(UIDIR)\action.obj \ - $(UIDIR)\creddlg.obj \ - $(UIDIR)\alert.obj \ - $(UIDIR)\propsheet.obj \ - $(UIDIR)\propwnd.obj \ - $(UIDIR)\uilibmain.obj \ - $(UIDIR)\actiondef.obj \ - $(UIDIR)\acceldef.obj \ - $(UIDIR)\configui.obj \ - $(UIDIR)\trackerwnd.obj \ - $(UIDIR)\version.obj - -RESFILES= \ - $(OBJ)\nidmgrdll.res \ - $(KCDBDIR)\kcredres.res \ - $(KMMDIR)\kmm_msgs.res \ - -SDKLIBFILES= \ - advapi32.lib \ - strsafe.lib \ - comctl32.lib \ - shlwapi.lib \ - version.lib - -$(DLLFILE): $(OBJFILES) $(RESFILES) - $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) - -all: mkdirs $(DLLFILE) - -clean:: - $(RM) $(DLLFILE) +# +# 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=nidmgrdll +!include <../config/Makefile.w32> + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +DLLFILE=$(BINDIR)\nidmgr64.dll +LIBFILE=$(LIBDIR)\nidmgr64.lib +!else +DLLFILE=$(BINDIR)\nidmgr32.dll +LIBFILE=$(LIBDIR)\nidmgr32.lib +!endif + +UTILDIR=$(OBJDIR)\util + +KHERRDIR=$(OBJDIR)\kherr + +KCONFIGDIR=$(OBJDIR)\kconfig + +KMQDIR=$(OBJDIR)\kmq + +KCDBDIR=$(OBJDIR)\kcreddb + +KMMDIR=$(OBJDIR)\kmm + +UIDIR=$(OBJDIR)\uilib + +OBJFILES= \ + $(OBJ)\dllmain.obj \ + $(UTILDIR)\hashtable.obj \ + $(UTILDIR)\sync.obj \ + $(UTILDIR)\mstring.obj \ + $(UTILDIR)\perfstat.obj \ + $(KHERRDIR)\kherrmain.obj \ + $(KHERRDIR)\kherr.obj \ + $(KCONFIGDIR)\kconfigmain.obj \ + $(KCONFIGDIR)\api.obj \ + $(KMQDIR)\kmqmain.obj \ + $(KMQDIR)\init.obj \ + $(KMQDIR)\msgtype.obj \ + $(KMQDIR)\consumer.obj \ + $(KMQDIR)\publisher.obj \ + $(KMQDIR)\kmqconfig.obj \ + $(KCDBDIR)\buf.obj \ + $(KCDBDIR)\attrib.obj \ + $(KCDBDIR)\credential.obj \ + $(KCDBDIR)\credset.obj \ + $(KCDBDIR)\credtype.obj \ + $(KCDBDIR)\identity.obj \ + $(KCDBDIR)\init.obj \ + $(KCDBDIR)\kcreddbmain.obj \ + $(KCDBDIR)\type.obj \ + $(KCDBDIR)\kcdbconfig.obj \ + $(KMMDIR)\kmmmain.obj \ + $(KMMDIR)\kmm.obj \ + $(KMMDIR)\kmm_plugin.obj \ + $(KMMDIR)\kmm_module.obj \ + $(KMMDIR)\kmm_reg.obj \ + $(KMMDIR)\kmm_registrar.obj \ + $(KMMDIR)\kmmconfig.obj \ + $(UIDIR)\rescache.obj \ + $(UIDIR)\action.obj \ + $(UIDIR)\creddlg.obj \ + $(UIDIR)\alert.obj \ + $(UIDIR)\propsheet.obj \ + $(UIDIR)\propwnd.obj \ + $(UIDIR)\uilibmain.obj \ + $(UIDIR)\actiondef.obj \ + $(UIDIR)\acceldef.obj \ + $(UIDIR)\configui.obj \ + $(UIDIR)\trackerwnd.obj \ + $(UIDIR)\version.obj + +RESFILES= \ + $(OBJ)\nidmgrdll.res \ + $(KCDBDIR)\kcredres.res \ + $(KMMDIR)\kmm_msgs.res \ + +SDKLIBFILES= \ + advapi32.lib \ + strsafe.lib \ + comctl32.lib \ + shlwapi.lib \ + version.lib + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +SCLIB=bufferoverflowu.lib +!else +SCLIB= +!endif + +$(DLLFILE): $(OBJFILES) $(RESFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) $(SCLIB) + +all: mkdirs $(DLLFILE) + +clean:: + $(RM) $(DLLFILE) diff --git a/src/windows/identity/plugins/common/dynimport.c b/src/windows/identity/plugins/common/dynimport.c index b906b6ae9..016af86e9 100644 --- a/src/windows/identity/plugins/common/dynimport.c +++ b/src/windows/identity/plugins/common/dynimport.c @@ -360,15 +360,33 @@ FUNC_INFO toolhelp_fi[] = { khm_int32 init_imports(void) { OSVERSIONINFO osvi; + int imp_rv = 1; - 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); +#define CKRV if(!imp_rv) goto _err_ret + + imp_rv = LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + CKRV; + + imp_rv = LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + CKRV; + + imp_rv = LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + CKRV; + + imp_rv = LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + CKRV; + + imp_rv = LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + CKRV; + + imp_rv = LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + CKRV; + + imp_rv = LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + CKRV; + + imp_rv = LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + CKRV; memset(&osvi, 0, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -382,19 +400,26 @@ khm_int32 init_imports(void) { if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { // Windows 9x - LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + imp_rv = LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + CKRV; + hPsapi = 0; } else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) { // Windows NT - LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + imp_rv = LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + CKRV; + hToolHelp32 = 0; } AfsAvailable = TRUE; //afscompat_init(); return KHM_ERROR_SUCCESS; + + _err_ret: + return KHM_ERROR_NOT_FOUND; } khm_int32 exit_imports(void) { diff --git a/src/windows/identity/plugins/krb4/Makefile b/src/windows/identity/plugins/krb4/Makefile index 2385e6179..b1ad963f0 100644 --- a/src/windows/identity/plugins/krb4/Makefile +++ b/src/windows/identity/plugins/krb4/Makefile @@ -1,81 +1,101 @@ -# -# 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)\krb4main.obj \ - $(OBJ)\krb4plugin.obj \ - $(OBJ)\krb4funcs.obj \ - $(OBJ)\errorfuncs.obj \ - $(OBJ)\krb4config.obj \ - $(OBJ)\krb4configdlg.obj \ - $(OBJ)\krb4newcreds.obj - -LIBFILES= \ - $(LIBDIR)\nidmgr32.lib \ - $(KFWLIBDIR)\loadfuncs.lib - -SDKLIBFILES= - -VERRESFILE=$(OBJ)\version.res - -$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg - $(CCSV) $** $@ - -$(DLLFILE): $(OBJFILES) $(VERRESFILE) - $(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 +# +# 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)\krb4main.obj \ + $(OBJ)\krb4plugin.obj \ + $(OBJ)\krb4funcs.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb4config.obj \ + $(OBJ)\krb4configdlg.obj \ + $(OBJ)\krb4newcreds.obj + + + +SDKLIBFILES= + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +SCLIB=bufferoverflowu.lib +LIBFILES= \ + $(LIBDIR)\nidmgr64.lib \ + $(KFWLIBDIR)\loadfuncs.lib +!else +SCLIB= +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib +!endif + +VERRESFILE=$(OBJ)\version.res + +MSGRESFILE=$(OBJ)\krb4_msgs.res + +$(MSGRESFILE): $(OBJ)\krb4_msgs.rc + +$(OBJ)\krb4_msgs.rc: lang\krb4_msgs.mc + $(MC2RC) + +$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(OBJFILES) $(VERRESFILE) $(MSGRESFILE) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) $(SCLIB) + +all: mkdirs $(MSGRESFILE) $(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 $(OBJ)\langres_ver_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) + +$(OBJ)\langres_ver_$(LANG).res: version.rc + $(RC) $(RFLAGS) $(rincflags) /d LANGVER /d LANG_$(LANG) /fo $@ $** +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/src/windows/identity/plugins/krb4/krb4funcs.c b/src/windows/identity/plugins/krb4/krb4funcs.c index 7798e5c9e..8928f71fd 100644 --- a/src/windows/identity/plugins/krb4/krb4funcs.c +++ b/src/windows/identity/plugins/krb4/krb4funcs.c @@ -182,15 +182,16 @@ khm_krb4_list_tickets(void) kcdb_credset_add_cred(krb4_credset, cred, -1); + kcdb_cred_release(cred); } // while -cleanup: + cleanup: if (ptf_close == NULL) return(KSUCCESS); if (open) (*ptf_close)(); //close ticket file - + if (k_errno == EOF) k_errno = 0; @@ -601,6 +602,76 @@ khm_krb4_changepwd(char * principal, return k_errno; } +struct tgt_filter_data { + khm_handle identity; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; +}; + +khm_int32 KHMAPI +krb4_tgt_filter(khm_handle cred, khm_int32 flags, void * rock) { + struct tgt_filter_data * pdata; + wchar_t credname[KCDB_MAXCCH_NAME]; + wchar_t * t; + khm_size cb; + khm_int32 ctype; + + pdata = (struct tgt_filter_data *) rock; + cb = sizeof(credname); + + if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) || + ctype != credtype_id_krb4) + return 0; + + if (KHM_FAILED(kcdb_cred_get_name(cred, credname, &cb))) + return 0; + + if (wcsncmp(credname, L"krbtgt.", 7)) + return 0; + + t = wcsrchr(credname, L'@'); + if (t == NULL) + return 0; + + if (wcscmp(t+1, pdata->realm)) + return 0; + + return 1; +} + +khm_handle +khm_krb4_find_tgt(khm_handle credset, khm_handle identity) { + khm_handle result = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * t; + khm_size cb; + struct tgt_filter_data filter_data; + + cb = sizeof(idname); + + if (KHM_FAILED(kcdb_identity_get_name(identity, + idname, + &cb))) + return NULL; + + t = wcsrchr(idname, L'@'); + if (t == NULL) + return NULL; + + StringCbCopy(filter_data.realm, sizeof(filter_data.realm), + t + 1); + filter_data.identity = identity; + + if (KHM_FAILED(kcdb_credset_find_filtered(credset, + -1, + krb4_tgt_filter, + &filter_data, + &result, + NULL))) + return NULL; + else + return result; +} + long khm_convert524(khm_handle identity) { @@ -677,6 +748,7 @@ khm_convert524(khm_handle identity) != KSUCCESS)) { goto cleanup; } + /* stash ticket, session key, etc. for future use */ if ((icode = pkrb_save_credentials(v4creds->service, v4creds->instance, diff --git a/src/windows/identity/plugins/krb4/krb4funcs.h b/src/windows/identity/plugins/krb4/krb4funcs.h index 742036878..8abb7ac33 100644 --- a/src/windows/identity/plugins/krb4/krb4funcs.h +++ b/src/windows/identity/plugins/krb4/krb4funcs.h @@ -64,6 +64,10 @@ khm_krb4_list_tickets(void); int khm_krb4_kdestroy(void); +khm_handle +khm_krb4_find_tgt(khm_handle credset, + khm_handle identity); + LONG write_registry_setting( char* setting, diff --git a/src/windows/identity/plugins/krb4/krb4main.c b/src/windows/identity/plugins/krb4/krb4main.c index b83cd5eb4..57e33a8d8 100644 --- a/src/windows/identity/plugins/krb4/krb4main.c +++ b/src/windows/identity/plugins/krb4/krb4main.c @@ -74,7 +74,8 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { ZeroMemory(&pi, sizeof(pi)); pi.name = KRB4_PLUGIN_NAME; pi.type = KHM_PITYPE_CRED; - pi.icon = NULL; /*TODO: Assign icon */ + pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); pi.flags = 0; pi.msg_proc = krb4_cb; pi.dependencies = KRB4_PLUGIN_DEPS; @@ -101,7 +102,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); if(KHM_FAILED(rv)) goto _exit; -_exit: + _exit: return rv; } @@ -114,17 +115,19 @@ KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { 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 */ + return KHM_ERROR_SUCCESS; /* the return code is ignored */ } BOOL WINAPI DllMain( @@ -138,11 +141,14 @@ BOOL WINAPI DllMain( hInstance = hinstDLL; init_krb(); break; + case DLL_PROCESS_DETACH: exit_krb(); break; + case DLL_THREAD_ATTACH: break; + case DLL_THREAD_DETACH: break; } diff --git a/src/windows/identity/plugins/krb4/krb4newcreds.c b/src/windows/identity/plugins/krb4/krb4newcreds.c index 28ae71a1f..3a1a72bfa 100644 --- a/src/windows/identity/plugins/krb4/krb4newcreds.c +++ b/src/windows/identity/plugins/krb4/krb4newcreds.c @@ -55,6 +55,7 @@ typedef struct tag_k4_dlg_data { } k4_dlg_data; void k4_update_display(k4_dlg_data * d) { + CheckDlgButton(d->hwnd, IDC_NCK4_OBTAIN, (d->k4_enabled)?BST_CHECKED: BST_UNCHECKED); @@ -68,8 +69,11 @@ void k4_update_display(k4_dlg_data * d) { EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), FALSE); } - CheckRadioButton(d->hwnd, IDC_NCK4_AUTO, IDC_NCK4_PWD, - method_to_id[d->method]); +#ifdef DEBUG + assert(d->method >= 0 && d->method < ARRAYLENGTH(method_to_id)); +#endif + + CheckDlgButton(d->hwnd, method_to_id[d->method], BST_CHECKED); khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); } @@ -103,6 +107,9 @@ void k4_update_data(k4_dlg_data * d) { khm_boolean k4_should_identity_get_k4(khm_handle ident) { khm_int32 idflags = 0; + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + khm_boolean get_k4 = TRUE; if (KHM_FAILED(kcdb_identity_get_flags(ident, &idflags))) return FALSE; @@ -122,7 +129,20 @@ khm_boolean k4_should_identity_get_k4(khm_handle ident) { } } - return TRUE; + if (KHM_SUCCEEDED(kcdb_identity_get_config(ident, 0, &csp_ident))) { + if (KHM_SUCCEEDED(khc_open_space(csp_ident, CSNAME_KRB4CRED, 0, + &csp_k4))) { + khm_int32 t = 0; + if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4NewCreds", &t)) && + !t) + get_k4 = FALSE; + + khc_close_space(csp_k4); + } + khc_close_space(csp_ident); + } + + return get_k4; } void k4_read_identity_data(k4_dlg_data * d) { @@ -433,9 +453,6 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, if (!nc->ctx.identity) break; - if (!k4_should_identity_get_k4(nc->ctx.identity)) - break; - nct = PMALLOC(sizeof(*nct)); #ifdef DEBUG assert(nct); @@ -469,6 +486,8 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, khm_handle ident = NULL; k4_dlg_data * d = NULL; long code = 0; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; nc = (khui_new_creds *) vparam; if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) @@ -484,17 +503,33 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, if (!d || nc->n_identities == 0 || nc->identities[0] == NULL || - nc->result != KHUI_NC_RESULT_GET_CREDS) + nc->result != KHUI_NC_RESULT_PROCESS) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); break; + } if (!d->k4_enabled) { k4_write_identity_data(d); + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); break; } method = d->method; ident = nc->identities[0]; + cb = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cb); + _begin_task(0); + _report_mr2(KHERR_NONE, MSG_K4_NEW_CREDS, + _cstr(ident), _int32(method)); + _resolve(); + _describe(); + + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { if ((nc->ctx.scope == KHUI_SCOPE_IDENT && @@ -511,12 +546,30 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, ident = nc->ctx.identity; + if (!k4_should_identity_get_k4(ident)) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_EXIT); + break; + } + } else { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_EXIT); break; } method = K4_METHOD_K524; /* only k524 is supported for renewals */ + + _begin_task(0); + cb = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cb); + _report_mr2(KHERR_NONE, MSG_K4_RENEW_CREDS, + _cstr(ident), _int32(method)); + _resolve(); + _describe(); } else { assert(FALSE); } @@ -525,8 +578,29 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, method == K4_METHOD_K524) && khui_cw_type_succeeded(nc, credtype_id_krb5)) { + khm_handle tgt; + FILETIME ft_prev; + FILETIME ft_new; + khm_size cb; + + _report_mr0(KHERR_INFO, MSG_K4_TRY_K524); + + tgt = khm_krb4_find_tgt(NULL, ident); + if (tgt) { + cb = sizeof(ft_prev); + if (KHM_FAILED(kcdb_cred_get_attr(tgt, + KCDB_ATTR_EXPIRE, + NULL, + &ft_prev, + &cb))) + ZeroMemory(&ft_prev, sizeof(ft_prev)); + kcdb_cred_release(tgt); + } + code = khm_convert524(ident); + _reportf(L"khm_convert524 returns code %d", code); + if (code == 0) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_SUCCESS | @@ -536,13 +610,92 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, assert(d != NULL); k4_write_identity_data(d); + + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS && + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE || + nc->ctx.scope == KHUI_SCOPE_CRED)) { + + khm_krb4_list_tickets(); + + tgt = khm_krb4_find_tgt(NULL, ident); + + if (tgt) { + cb = sizeof(ft_new); + ZeroMemory(&ft_new, sizeof(ft_new)); + + kcdb_cred_get_attr(tgt, + KCDB_ATTR_EXPIRE, + NULL, + &ft_new, + &cb); + + kcdb_cred_release(tgt); + } + + if (!tgt || + CompareFileTime(&ft_new, + &ft_prev) <= 0) { + /* The new TGT wasn't much of an + improvement over what we already + had. We should go out and try to + renew the identity now. */ + + khui_action_context ctx; + + _reportf(L"Renewal of Krb4 creds failed to get a longer TGT. Triggering identity renewal"); + + khui_context_create(&ctx, + KHUI_SCOPE_IDENT, + nc->ctx.identity, + KCDB_CREDTYPE_INVALID, + NULL); + khui_action_trigger(KHUI_ACTION_RENEW_CRED, + &ctx); + + khui_context_release(&ctx); + } } + + _end_task(); break; + } else if (method == K4_METHOD_K524) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_FAILED | KHUI_NC_RESPONSE_EXIT); + + if (nc->subtype == KMSG_CRED_RENEW_CREDS && + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE || + nc->ctx.scope == KHUI_SCOPE_CRED)) { + /* We were trying to get a new Krb4 TGT + for this identity. Sometimes this + fails because of restrictions placed on + K524d regarding the lifetime of the + issued K4 TGT. In this case, we + trigger a renewal of the identity in + the hope that the new K5 TGT will allow + us to successfully get a new K4 TGT + next time over using the new K5 TGT. */ + + khui_action_context ctx; + + _reportf(L"Renewal of Krb4 creds failed using k524. Triggerring identity renewal."); + + khui_context_create(&ctx, + KHUI_SCOPE_IDENT, + nc->ctx.identity, + KCDB_CREDTYPE_INVALID, + NULL); + + khui_action_trigger(KHUI_ACTION_RENEW_CRED, + &ctx); + + khui_context_release(&ctx); + } + + _end_task(); break; + } } @@ -564,6 +717,8 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, assert(nc->subtype == KMSG_CRED_NEW_CREDS); + _report_mr0(KHERR_INFO, MSG_K4_TRY_PASSWORD); + code = TRUE; /* just has to be non-zero */ khui_cw_get_prompt_count(nc, &n_prompts); @@ -581,16 +736,20 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, break; } - if (idx >= n_prompts) + if (idx >= n_prompts) { + _reportf(L"Password prompt not found"); goto _skip_pwd; + } khui_cw_sync_prompt_values(nc); cb = sizeof(wpwd); if (KHM_FAILED(khui_cw_get_prompt_value(nc, idx, wpwd, - &cb))) + &cb))) { + _reportf(L"Failed to obtain password value"); goto _skip_pwd; + } UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); @@ -605,8 +764,10 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, char * atsign; atsign = strchr(idname, '@'); - if (atsign == NULL) + if (atsign == NULL) { + _reportf(L"Identity name does not contain an '@'"); goto _skip_pwd; + } *atsign++ = 0; @@ -629,6 +790,9 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, code = khm_krb4_kinit(aname, inst, realm, (long) d->lifetime, pwd); + + _reportf(L"khm_krb4_kinit returns code %d", code); + _skip_pwd: if (code) { @@ -649,6 +813,8 @@ krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, } } } + + _end_task(); } } break; diff --git a/src/windows/identity/plugins/krb4/krb4plugin.c b/src/windows/identity/plugins/krb4/krb4plugin.c index 23f913bd9..972ed4a01 100644 --- a/src/windows/identity/plugins/krb4/krb4plugin.c +++ b/src/windows/identity/plugins/krb4/krb4plugin.c @@ -200,7 +200,6 @@ krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, &attr_id_krb5_flags))) { rv = KHM_ERROR_UNKNOWN; } - } break; diff --git a/src/windows/identity/plugins/krb4/krbcred.h b/src/windows/identity/plugins/krb4/krbcred.h index 9f5d3c932..f31c4a4d3 100644 --- a/src/windows/identity/plugins/krb4/krbcred.h +++ b/src/windows/identity/plugins/krb4/krbcred.h @@ -41,6 +41,7 @@ #include #include +#include #define TYPENAME_ENCTYPE L"EncType" #define TYPENAME_ADDR_LIST L"AddrList" diff --git a/src/windows/identity/plugins/krb4/lang/en_us/langres.rc b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc index a07dc4b30..d9114e5b6 100644 --- a/src/windows/identity/plugins/krb4/lang/en_us/langres.rc +++ b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc @@ -61,14 +61,14 @@ BEGIN SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 CONTROL "Obtain Kerberos 4 tickets",IDC_NCK4_OBTAIN,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,26,97,10 + GROUPBOX "Obtain Kerberos 4 tickets using",IDC_STATIC,7,43,286,72, + WS_GROUP CONTROL "Automatically determine method",IDC_NCK4_AUTO,"Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,23,58,119,10 CONTROL "Kerberos 5 to 4 translation",IDC_NCK4_K524,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,23,76,101,10 - CONTROL "Password",IDC_NCK4_PWD,"Button",BS_AUTORADIOBUTTON | - WS_TABSTOP,23,94,47,10 - GROUPBOX "Obtain Kerberos 4 tickets using",IDC_STATIC,7,43,286,72, - WS_GROUP + BS_AUTORADIOBUTTON,23,76,101,10 + CONTROL "Password",IDC_NCK4_PWD,"Button",BS_AUTORADIOBUTTON,23, + 94,47,10 END IDD_CFG_KRB4 DIALOGEX 0, 0, 255, 182 @@ -154,6 +154,15 @@ END #endif // APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PLUGIN ICON "..\\..\\images\\plugin.ico" + ///////////////////////////////////////////////////////////////////////////// // // String Table diff --git a/src/windows/identity/plugins/krb4/lang/krb4_msgs.mc b/src/windows/identity/plugins/krb4/lang/krb4_msgs.mc new file mode 100644 index 000000000..9fa410f2f --- /dev/null +++ b/src/windows/identity/plugins/krb4/lang/krb4_msgs.mc @@ -0,0 +1,57 @@ +; // ** 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_K4_NEW_CREDS +Language=English +Getting new Krb4 credentials for [%1!s!] using method [%2!d!] +. + +MessageId= +SymbolicName=MSG_K4_RENEW_CREDS +Language=English +Renewing Krb4 credentials for [%1!s!] using method [%2!d!] +. + +MessageId= +SymbolicName=MSG_K4_TRY_K524 +Language=English +Trying Krb524 ... +. + +MessageId= +SymbolicName=MSG_K4_TRY_PASSWORD +Language=English +Trying Password ... +. + diff --git a/src/windows/identity/plugins/krb4/langres.h b/src/windows/identity/plugins/krb4/langres.h index ceb236007..2cf0de137 100644 --- a/src/windows/identity/plugins/krb4/langres.h +++ b/src/windows/identity/plugins/krb4/langres.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb4\lang\en_us\langres.rc +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb4\lang\en_us\langres.rc // #define IDS_UNK_ADDR_FMT 101 #define IDS_KRB5_CREDTEXT_0 102 @@ -17,6 +17,8 @@ #define IDD_CFG_ID_KRB4 106 #define IDS_TKT_ENCTYPE_LONG_DESC 107 #define IDS_ERR_INVINST 107 +#define IDI_ICON1 107 +#define IDI_PLUGIN 107 #define IDS_ADDR_LIST_SHORT_DESC 108 #define IDS_ERR_PWINTKT 108 #define IDS_ADDR_LIST_LONG_DESC 109 @@ -83,13 +85,12 @@ #define IDC_NCK4_K524 1035 #define IDC_NCK4_AUTO 1036 #define IDC_CFG_GETTIX 1037 -#define IDC_CHECK1 1038 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_RESOURCE_VALUE 108 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1039 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/src/windows/identity/plugins/krb4/version.rc b/src/windows/identity/plugins/krb4/version.rc index 3ca6b1cb9..90105f827 100644 --- a/src/windows/identity/plugins/krb4/version.rc +++ b/src/windows/identity/plugins/krb4/version.rc @@ -26,6 +26,28 @@ #include +#ifndef LANGVER + +#define STR_FILEDESC "Kerberos 4 Plugin for NetIDMgr" +#define STR_INTNAME "krb4cred" +#define STR_ORIGNAME "krb4cred.dll" + +#else + +#ifdef LANG_en_us + +#define STR_FILEDESC "English(US) language resources for the Keberos 4 plugin" +#define STR_INTNAME "krb4cred_en_us" +#define STR_ORIGNAME "krb4cred_en_us.dll" + +#else + +#error Unknown langugae + +#endif + +#endif + 1 VERSIONINFO FILEVERSION KH_VERSION_LIST PRODUCTVERSION KH_VERSION_LIST @@ -41,20 +63,22 @@ BLOCK "040904b0" { VALUE "CompanyName", KH_VERSTR_COMPANY_1033 - VALUE "FileDescription", "Kerberos 4 plugin for NetIDMgr" + VALUE "FileDescription", STR_FILEDESC VALUE "FileVersion", KH_VERSTR_VERSION_1033 - VALUE "InternalName", "krb4cred" + VALUE "InternalName", STR_INTNAME VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 - VALUE "OriginalFilename", "krb4cred.dll" + VALUE "OriginalFilename", STR_ORIGNAME VALUE "ProductName", "NetIDMgr" VALUE "ProductVersion", KH_VERSTR_PRODUCT_1033 #ifdef KH_VERSTR_COMMENT_1033 VALUE "Comment", KH_VERSTR_COMMENT_1033 #endif +#ifndef LANGVER VALUE NIMV_MODULE, "MITKrb4" VALUE NIMV_PLUGINS, "Krb4Cred" VALUE NIMV_APIVER, KH_VERSION_STRINGAPI VALUE NIMV_SUPPORT, "http://web.mit.edu/kerberos" +#endif } } @@ -62,5 +86,4 @@ { VALUE "Translation", 0x409, 1200 } - } diff --git a/src/windows/identity/plugins/krb5/Makefile b/src/windows/identity/plugins/krb5/Makefile index e0553d846..67475ee01 100644 --- a/src/windows/identity/plugins/krb5/Makefile +++ b/src/windows/identity/plugins/krb5/Makefile @@ -1,98 +1,110 @@ -# -# 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)\krb5main.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 \ - $(OBJ)\krb5configcc.obj \ - $(OBJ)\krb5configid.obj \ - $(OBJ)\krb5configids.obj - -LIBFILES= \ - $(LIBDIR)\nidmgr32.lib \ - $(KFWLIBDIR)\loadfuncs.lib - -SDKLIBFILES= \ - netapi32.lib \ - shlwapi.lib \ - comctl32.lib - -MSGRESFILE=$(OBJ)\krb5_msgs.res - -VERRESFILE=$(OBJ)\version.res - -$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg - $(CCSV) $** $@ - -$(DLLFILE): $(MSGRESFILE) $(VERRESFILE) $(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 +# +# 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)\krb5main.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 \ + $(OBJ)\krb5configcc.obj \ + $(OBJ)\krb5configid.obj \ + $(OBJ)\krb5configids.obj + + + +SDKLIBFILES= \ + netapi32.lib \ + shlwapi.lib \ + comctl32.lib + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +SCLIB=bufferoverflowu.lib +LIBFILES= \ + $(LIBDIR)\nidmgr64.lib \ + $(KFWLIBDIR)\loadfuncs.lib +!else +SCLIB= +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib +!endif + +MSGRESFILE=$(OBJ)\krb5_msgs.res + +VERRESFILE=$(OBJ)\version.res + +$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(OBJFILES) $(VERRESFILE) + $(DLLGUILINK) $(MSGRESFILE) $(LIBFILES) $(SDKLIBFILES) $(SCLIB) + +$(MSGRESFILE): $(OBJ)\krb5_msgs.rc + +$(OBJ)\krb5_msgs.rc: lang\krb5_msgs.mc + $(MC2RC) + +all: mkdirs $(MSGRESFILE) $(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 $(OBJ)\langres_ver_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) + +$(OBJ)\langres_ver_$(LANG).res: version.rc + $(RC) $(RFLAGS) $(rincflags) /d LANGVER /d LANG_$(LANG) /fo $@ $** +# 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 index 2c4036083..97d629eb4 100644 --- a/src/windows/identity/plugins/krb5/datarep.c +++ b/src/windows/identity/plugins/krb5/datarep.c @@ -26,12 +26,17 @@ /* Data representation and related functions */ +#include #include #include #include #include +#include -khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags) +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; @@ -130,17 +135,90 @@ khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *d } } -khm_int32 KHMAPI addr_list_toString(const void *d, khm_size cb_d, wchar_t *buf, khm_size *pcb_buf, khm_int32 flags) +khm_int32 KHMAPI +addr_list_comp(const void *d1, khm_size cb_d1, + const void *d2, khm_size cb_d2) { - /*TODO: implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; + if (cb_d1 < cb_d2) + return -1; + if (cb_d1 > cb_d2) + return 1; + return memcmp(d1, d2, cb_d1); } -khm_int32 KHMAPI krb5flags_toString(const void *d, - khm_size cb_d, - wchar_t *buf, - khm_size *pcb_buf, - khm_int32 f) +khm_int32 KHMAPI +addr_list_toString(const void *d, khm_size cb_d, + wchar_t *buf, khm_size *pcb_buf, + khm_int32 flags) +{ + wchar_t tbuf[2048]; + wchar_t * strpos; + khm_size cbleft; + size_t t; + k5_serial_address * addrs; + + if (cb_d == 0 || d == NULL) { + tbuf[0] = L'\0'; + } else { + addrs = (k5_serial_address *) d; + + strpos = tbuf; + cbleft = sizeof(tbuf); + tbuf[0] = L'\0'; + + while (TRUE) { + if (cb_d < sizeof(*addrs) || + addrs->magic != K5_SERIAL_ADDRESS_MAGIC || + cb_d < sizeof(*addrs) + addrs->length - sizeof(khm_int32)) + break; + + if (strpos != tbuf) { + if (FAILED(StringCbCatEx(strpos, cbleft, L" ", + &strpos, &cbleft, + 0))) + break; + } + +#ifdef DEBUG + assert(*strpos == L'\0'); +#endif + + one_addr(addrs, strpos, cbleft); + + t = 0; + if (FAILED(StringCchLength(strpos, + cbleft / sizeof(wchar_t), + &t))) + break; + + strpos += t; + cbleft -= t * sizeof(wchar_t); + + t = sizeof(*addrs) + addrs->length - sizeof(khm_int32); + addrs = (k5_serial_address *) BYTEOFFSET(addrs, t); + cb_d -= t; + } + } + + StringCbLength(tbuf, sizeof(tbuf), &t); + + if (!buf || *pcb_buf < t) { + *pcb_buf = t; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buf, *pcb_buf, tbuf); + *pcb_buf = t; + + return KHM_ERROR_SUCCESS; +} + +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; @@ -196,19 +274,42 @@ khm_int32 KHMAPI krb5flags_toString(const void *d, } } -khm_int32 serialize_krb5_addresses(krb5_address ** a, void ** buf, size_t * pcbbuf) +khm_int32 +serialize_krb5_addresses(krb5_address ** a, void * buf, size_t * pcbbuf) { - /*TODO: implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; -} + k5_serial_address * addr; + khm_size cb_req; + khm_size t; + khm_boolean overflow = FALSE; + + addr = (k5_serial_address *) buf; + cb_req = 0; + + for(; *a; a++) { + t = sizeof(k5_serial_address) + (*a)->length - sizeof(khm_int32); + cb_req += t; + if (cb_req < *pcbbuf) { + addr->magic = K5_SERIAL_ADDRESS_MAGIC; + addr->addrtype = (*a)->addrtype; + addr->length = (*a)->length; + memcpy(&addr->data, (*a)->contents, (*a)->length); + + addr = (k5_serial_address *) BYTEOFFSET(addr, t); + } else { + overflow = TRUE; + } + } -#if 0 + *pcbbuf = cb_req; -wchar_t * -one_addr(krb5_address *a) + return (overflow)?KHM_ERROR_TOO_LONG: KHM_ERROR_SUCCESS; +} + +void +one_addr(k5_serial_address *a, wchar_t * buf, khm_size cbbuf) { - static wchar_t retstr[256]; - struct hostent *h; + wchar_t retstr[256]; + struct hostent *h = NULL; int no_resolve = 1; retstr[0] = L'\0'; @@ -227,43 +328,50 @@ one_addr(krb5_address *a) if (!no_resolve) { #ifdef HAVE_GETIPNODEBYADDR int err; - h = getipnodebyaddr(a->contents, a->length, af, &err); + h = getipnodebyaddr(&a->data, 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); + else + h = gethostbyaddr(&a->data, a->length, af); if (h) { StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); } #endif if (h) - return(retstr); + goto _copy_string; } if (no_resolve || !h) { #ifdef HAVE_INET_NTOP char buf[46]; - const char *name = inet_ntop(a->addrtype, a->contents, buf, sizeof(buf)); + const char *name = inet_ntop(a->addrtype, &a->data, buf, sizeof(buf)); if (name) { StringCbPrintf(retstr, sizeof(retstr), L"%S", name); - return; + goto _copy_string; } #else if (a->addrtype == ADDRTYPE_INET) { + khm_ui_4 addr = a->data; StringCbPrintf(retstr, sizeof(retstr), - L"%d.%d.%d.%d", a->contents[0], a->contents[1], - a->contents[2], a->contents[3]); - return(retstr); + L"%d.%d.%d.%d", + (int) (addr & 0xff), + (int) ((addr >> 8) & 0xff), + (int) ((addr >> 16)& 0xff), + (int) ((addr >> 24)& 0xff)); + goto _copy_string; } #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); + + _copy_string: + StringCbCopy(buf, cbbuf, retstr); } -#endif + diff --git a/src/windows/identity/plugins/krb5/datarep.h b/src/windows/identity/plugins/krb5/datarep.h index ac6771cb9..eeb6970da 100644 --- a/src/windows/identity/plugins/krb5/datarep.h +++ b/src/windows/identity/plugins/krb5/datarep.h @@ -27,11 +27,45 @@ #ifndef __KHIMAIRA_KRB_DATAREP_H #define __KHIMAIRA_KRB_DATAREP_H +typedef struct tag_k5_serial_address { + khm_int32 magic; /* should be K5_SERIAL_ADDRESS_MAGIC */ + khm_int32 addrtype; /* Address type. We only know what to + do with ADDRTYPE_INET and + ADDRTYPE_INET6 */ + khm_size length; /* number of bytes of data in [data]. + This should always be greater than + sizeof(khm_int32) */ + khm_int32 data; /* actually, &data is the beginning of + the data buffer that is [length] + bytes long. */ +} k5_serial_address; -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); +#define K5_SERIAL_ADDRESS_MAGIC 0x44ce832d +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_comp(const void *d1, khm_size cb_d1, + const void *d2, khm_size cb_d2); + +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); + +khm_int32 +serialize_krb5_addresses(krb5_address ** a, void * buf, size_t * pcbbuf); + +void +one_addr(k5_serial_address *a, wchar_t * buf, khm_size cbbuf); #endif diff --git a/src/windows/identity/plugins/krb5/krb5configdlg.c b/src/windows/identity/plugins/krb5/krb5configdlg.c index 8cf89c7cd..0cb8b2ab7 100644 --- a/src/windows/identity/plugins/krb5/krb5configdlg.c +++ b/src/windows/identity/plugins/krb5/krb5configdlg.c @@ -1,1856 +1,2746 @@ -/* - * Copyright (c) 2005 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 - -#pragma warning(push) -#pragma warning(disable: 4995) -#include -#pragma warning(pop) - - -typedef struct tag_k5_realm_kdc { - wchar_t name[K5_MAXCCH_HOST]; - khm_boolean admin; /* admin server? */ - khm_boolean master; /* master kdc? */ - khm_int32 flags; -} k5_realm_kdc; - -#define K5_RKFLAG_DELETED 1 -#define K5_RKFLAG_NEW 2 -#define K5_RKFLAG_MOD_ADMIN 4 -#define K5_RKFLAG_MOD_MASTER 8 - -typedef struct tag_k5_domain_map { - wchar_t name[K5_MAXCCH_HOST]; /* name of host that maps to a - realm */ - khm_int32 flags; -} k5_domain_map; - -#define K5_DMFLAG_DELETED 1 -#define K5_DMFLAG_NEW 2 - -typedef struct tag_k5_realm_data { - wchar_t realm[K5_MAXCCH_REALM]; - k5_realm_kdc kdcs[K5_MAX_KDC]; - khm_size n_kdcs; - k5_domain_map domain_maps[K5_MAX_DOMAIN_MAPPINGS]; - khm_size n_domain_maps; - - khm_int32 flags; -} k5_realm_data; - -#define K5_RDFLAG_DELETED 1 -#define K5_RDFLAG_NEW 2 -#define K5_RDFLAG_MODIFED 4 - -#define K5_REALMS_ALLOC_INCR 8 - -typedef struct tag_k5_config_data { - wchar_t def_realm[K5_MAXCCH_REALM]; /* default realm */ - - wchar_t config_file[MAX_PATH]; /* path to configuration file */ - khm_boolean create_config_file; /* create config_file if missing? */ - khm_boolean inc_realms; /* include full realm list in new - credentials dialog? */ - - /* [libdefaults] */ - khm_boolean dns_lookup_kdc; - khm_boolean dns_lookup_realm; - khm_boolean dns_fallback; - - khm_boolean noaddresses; - - k5_lsa_import lsa_import; /* import mslsa creds? */ - - /* [realms] */ - k5_realm_data *realms; - khm_size n_realms; - khm_size nc_realms; - khm_size c_realm; - - khui_config_node node_main; - khui_config_node node_realm; - - khm_int32 flags; -} k5_config_data; - -#define K5_CDFLAG_MOD_DEF_REALM 0x00000001 -#define K5_CDFLAG_MOD_CONF_FILE 0x00000002 -#define K5_CDFLAG_MOD_DNS_LOOKUP_KDC 0x00000004 -#define K5_CDFLAG_MOD_DNS_LOOKUP_RLM 0x00000008 -#define K5_CDFLAG_MOD_DNS_FALLBACK 0x00000010 -#define K5_CDFLAG_MOD_NOADDRESSES 0x00000020 -#define K5_CDFLAG_MOD_LSA_IMPORT 0x00000040 -#define K5_CDFLAG_MOD_CREATE_CONF 0x00000080 -#define K5_CDFLAG_MOD_INC_REALMS 0x00000100 -#define K5_CDFLAG_MOD_REALMS 0x00001000 - -static const char *const conf_yes[] = { - "y", "yes", "true", "t", "1", "on", - 0, -}; - -static const char *const conf_no[] = { - "n", "no", "false", "nil", "0", "off", - 0, -}; - -int -k5_parse_boolean(const char *s) -{ - const char *const *p; - - for(p=conf_yes; *p; p++) { - if (!stricmp(*p,s)) - return 1; - } - - for(p=conf_no; *p; p++) { - if (!stricmp(*p,s)) - return 0; - } - - /* Default to "no" */ - return 0; -} - -void -k5_init_config_data(k5_config_data * d) { - ZeroMemory(d, sizeof(*d)); -} - -void -k5_free_config_data(k5_config_data * d) { - if (d->realms) - PFREE(d->realms); - - k5_init_config_data(d); -} - -static void -k5_assert_n_realms(k5_config_data * d, khm_size n) { - khm_size nc_realms; - - if (n <= d->nc_realms) - return; - - nc_realms = UBOUNDSS(n, K5_REALMS_ALLOC_INCR, K5_REALMS_ALLOC_INCR); - assert(nc_realms > d->nc_realms); - - d->realms = PREALLOC(d->realms, nc_realms * sizeof(*(d->realms))); - d->nc_realms = nc_realms; - - ZeroMemory(&d->realms[d->n_realms], - (d->nc_realms - d->n_realms) * sizeof(*(d->realms))); -} - -void -k5_purge_config_data(k5_config_data * d, - khm_boolean purge_realms, - khm_boolean purge_kdcs, - khm_boolean purge_dmap) { - khm_size r; - khm_size k; - khm_size m; - - for (r=0; r < d->n_realms; r++) { - if (purge_realms && - (d->realms[r].flags & K5_RDFLAG_NEW) && - (d->realms[r].flags & K5_RDFLAG_DELETED)) { - - if (d->n_realms > r+1) - MoveMemory(&d->realms[r], &d->realms[r+1], - sizeof(d->realms[0]) * (d->n_realms - (r+1))); - r--; - d->n_realms--; - continue; - } - - for (k=0; k < d->realms[r].n_kdcs; k++) { - if (purge_kdcs && - (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) && - (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { - if (d->realms[r].n_kdcs > k + 1) - MoveMemory(&d->realms[r].kdcs[k], - &d->realms[r].kdcs[k+1], - sizeof(d->realms[0].kdcs[0]) * - (d->realms[r].n_kdcs - (k+1))); - k--; - d->realms[r].n_kdcs--; - continue; - } - } - - if (K5_MAX_KDC > k+1) - ZeroMemory(&d->realms[r].kdcs[k], - sizeof(d->realms[0].kdcs[0]) * - (K5_MAX_KDC - (k + 1))); - - for (m=0; m < d->realms[r].n_domain_maps; m++) { - if (purge_dmap && - (d->realms[r].domain_maps[m].flags & K5_DMFLAG_NEW) && - (d->realms[r].domain_maps[m].flags & K5_DMFLAG_DELETED)) { - if (d->realms[r].n_domain_maps > m + 1) - MoveMemory(&d->realms[r].domain_maps[m], - &d->realms[r].domain_maps[m+1], - sizeof(d->realms[0].domain_maps[0]) * - (d->realms[r].n_domain_maps - (m+1))); - m--; - d->realms[r].n_domain_maps--; - continue; - } - } - - if (K5_MAX_DOMAIN_MAPPINGS > m+1) - ZeroMemory(&d->realms[r].domain_maps[m], - sizeof(d->realms[0].domain_maps[0]) * - (K5_MAX_DOMAIN_MAPPINGS - (m+1))); - } - - if (d->nc_realms > r + 1) - ZeroMemory(&d->realms[r], - sizeof(d->realms[0]) * - (d->nc_realms - (r + 1))); -} - -static khm_boolean -k5_is_profile_loaded(void) { -#ifdef DEBUG - assert(pprofile_init); - assert(pprofile_get_subsection_names); - assert(pprofile_get_values); - assert(pprofile_get_string); - assert(pprofile_get_relation_names); - assert(pprofile_free_list); - assert(pprofile_release_string); - assert(pprofile_release); - assert(pprofile_clear_relation); - assert(pprofile_add_relation); - assert(pprofile_update_relation); - assert(pprofile_flush); -#endif - - if (!pprofile_init || - !pprofile_get_subsection_names || - !pprofile_get_values || - !pprofile_get_string || - !pprofile_get_relation_names || - !pprofile_free_list || - !pprofile_release_string || - !pprofile_release || - !pprofile_clear_relation || - !pprofile_add_relation || - !pprofile_update_relation || - !pprofile_flush) - - return FALSE; - - return TRUE; -} - -void -k5_read_config_data(k5_config_data * d) { - wchar_t * defrealm; - char config_file[MAX_PATH]; - profile_t profile = NULL; - const char *filenames[2]; - long rv; - khm_size s; - - if (!k5_is_profile_loaded()) - return; - - defrealm = khm_krb5_get_default_realm(); - - if (defrealm) { - StringCbCopy(d->def_realm, sizeof(d->def_realm), defrealm); - PFREE(defrealm); - } else { - StringCbCopy(d->def_realm, sizeof(d->def_realm), L""); - } - - khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); - - AnsiStrToUnicode(d->config_file, sizeof(d->config_file), config_file); - - filenames[0] = config_file; - filenames[1] = NULL; - - rv = pprofile_init(filenames, &profile); - - if (!rv) { - const char * sec_realms[] = { "realms", NULL }; - const char * sec_domain_realm[] = { "domain_realm", NULL }; - char ** sections; - char ** dr_from; - char * boolv; - - /* first fish out a few values from [libdefaults] */ - - rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_kdc", - NULL, NULL, &boolv); - if (!rv && boolv) { - d->dns_lookup_kdc = k5_parse_boolean(boolv); - pprofile_release_string(boolv); - } else - d->dns_lookup_kdc = FALSE; - - rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_realm", - NULL, NULL, &boolv); - if (!rv && boolv) { - d->dns_lookup_realm = k5_parse_boolean(boolv); - pprofile_release_string(boolv); - } else - d->dns_lookup_realm = FALSE; - - rv = pprofile_get_string(profile, "libdefaults", "dns_fallback", - NULL, NULL, &boolv); - if (!rv && boolv) { - d->dns_fallback = k5_parse_boolean(boolv); - pprofile_release_string(boolv); - } else - d->dns_fallback = FALSE; - - rv = pprofile_get_string(profile, "libdefaults", "noaddresses", - NULL, NULL, &boolv); - if (!rv && boolv) { - d->noaddresses = k5_parse_boolean(boolv); - pprofile_release_string(boolv); - } else - d->noaddresses = TRUE; - - /* now we look at the [realms] section */ - rv = pprofile_get_subsection_names(profile, sec_realms, §ions); - - /* what? no realms? whatever */ - if (rv) goto _skip_realms; - - /* get a count first */ - for (s=0; sections[s] && sections[s][0]; s++); - - k5_assert_n_realms(d, s); - d->n_realms = s; - - /* now go through each and fish out the kdcs, admin_server - and master_kdc. */ - for (s=0; sections[s] && sections[s][0]; s++) { - const char * sec_kdcs[] = - { "realms", sections[s], "kdc", NULL }; - - const char * sec_admin[] = - { "realms", sections[s], "admin_server", NULL }; - - const char * sec_master[] = - { "realms", sections[s], "master_kdc", NULL }; - - char ** values; - - AnsiStrToUnicode(d->realms[s].realm, sizeof(d->realms[s].realm), - sections[s]); - d->realms[s].n_kdcs = 0; - d->realms[s].n_domain_maps = 0; - - rv = pprofile_get_values(profile, sec_kdcs, &values); - if (!rv) { - khm_size i; - - for (i=0 ; values[i] && values[i][0] && i < K5_MAX_KDC; i++) { - AnsiStrToUnicode(d->realms[s].kdcs[i].name, - sizeof(d->realms[s].kdcs[i].name), - values[i]); - - } - d->realms[s].n_kdcs = i; - - pprofile_free_list(values); - } - - rv = pprofile_get_values(profile, sec_admin, &values); - if (!rv) { - khm_size i; - khm_size j; - wchar_t kdc_name[K5_MAXCCH_HOST]; - - for (i=0; values[i] && values[i][0]; i++) { - AnsiStrToUnicode(kdc_name, - sizeof(kdc_name), values[i]); - - for (j=0; j < d->realms[s].n_kdcs; j++) - if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) - break; - - if (j < d->realms[s].n_kdcs) { - d->realms[s].kdcs[j].admin = TRUE; - } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { - j = d->realms[s].n_kdcs; - StringCbCopy(d->realms[s].kdcs[j].name, - sizeof(d->realms[s].kdcs[j].name), - kdc_name); - d->realms[s].kdcs[j].admin = TRUE; - d->realms[s].n_kdcs ++; - } - } - pprofile_free_list(values); - } - - rv = pprofile_get_values(profile, sec_master, &values); - if (!rv) { - khm_size i; - khm_size j; - wchar_t kdc_name[K5_MAXCCH_HOST]; - - for (i=0; values[i] && values[i][0]; i++) { - AnsiStrToUnicode(kdc_name, sizeof(kdc_name), values[i]); - - for (j=0; j < d->realms[s].n_kdcs; j++) - if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) - break; - - if (j < d->realms[s].n_kdcs) { - d->realms[s].kdcs[j].master = TRUE; - } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { - j = d->realms[s].n_kdcs; - StringCbCopy(d->realms[s].kdcs[j].name, - sizeof(d->realms[s].kdcs[j].name), - kdc_name); - d->realms[s].kdcs[j].master = TRUE; - d->realms[s].n_kdcs ++; - } - } - - pprofile_free_list(values); - } - } - pprofile_free_list(sections); - - _skip_realms: - - rv = pprofile_get_relation_names(profile, sec_domain_realm, &dr_from); - if (!rv) { - khm_size i; - khm_size j; - char * dr_to; - wchar_t wdr_from[K5_MAXCCH_HOST]; - wchar_t wdr_to[K5_MAXCCH_HOST]; - - for (i=0; dr_from[i] && dr_from[i][0]; i++) { - AnsiStrToUnicode(wdr_from, sizeof(wdr_from), dr_from[i]); - - rv = pprofile_get_string(profile, "domain_realm", dr_from[i], - NULL, NULL, &dr_to); - - if (rv || !dr_to) - continue; - - AnsiStrToUnicode(wdr_to, sizeof(wdr_to), dr_to); - - for (j=0; j < d->n_realms; j++) { - if (!wcsicmp(wdr_to, d->realms[j].realm)) - break; - } - - if (j >= d->n_realms) { - j = d->n_realms; - k5_assert_n_realms(d, j + 1); - - StringCbCopy(d->realms[j].realm, - sizeof(d->realms[j].realm), - wdr_to); - d->realms[j].n_kdcs = 0; - d->realms[j].n_domain_maps = 0; - - d->n_realms++; - } - - if (d->realms[j].n_domain_maps < K5_MAX_DOMAIN_MAPPINGS) { - khm_size k; - - k = d->realms[j].n_domain_maps; - - StringCbCopy(d->realms[j].domain_maps[k].name, - sizeof(d->realms[j].domain_maps[k].name), - wdr_from); - - d->realms[j].n_domain_maps++; - } - - pprofile_release_string(dr_to); - } - pprofile_free_list(dr_from); - } - pprofile_release(profile); - } - - { - khm_int32 t; - - /* last, read the MSLSA import setting */ - if (KHM_SUCCEEDED(khc_read_int32(csp_params, - L"MsLsaImport", &t))) { - d->lsa_import = t; - } else { - d->lsa_import = K5_LSAIMPORT_ALWAYS; - } - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, - L"UseFullRealmList", &t))) { - d->inc_realms = !!t; - } else { - d->inc_realms = TRUE; - } - } - - d->flags = 0; -} - -void -k5_write_config_data(k5_config_data * d) { - char astr[MAX_PATH * 2]; - char config_file[MAX_PATH]; - profile_t profile = NULL; - const char *filenames[2]; - long rv; - khm_size s; - - if (d->flags == 0) - return; - - if (!k5_is_profile_loaded()) - return; - - if (d->flags & K5_CDFLAG_MOD_DEF_REALM) { - if (SUCCEEDED(StringCbLength(d->def_realm, - sizeof(d->def_realm), &s)) && - s > 0) { - khm_krb5_set_default_realm(d->def_realm); - } - } - - /* write the MSLSA import setting */ - if (d->flags & K5_CDFLAG_MOD_LSA_IMPORT) { - khc_write_int32(csp_params, L"MsLsaImport", d->lsa_import); - } - - if (d->flags & K5_CDFLAG_MOD_INC_REALMS) { - khc_write_int32(csp_params, L"UseFullRealmList", d->inc_realms); - } - - if (!(d->flags & - (K5_CDFLAG_MOD_CONF_FILE | - K5_CDFLAG_MOD_DNS_FALLBACK | - K5_CDFLAG_MOD_DNS_LOOKUP_RLM | - K5_CDFLAG_MOD_DNS_LOOKUP_KDC | - K5_CDFLAG_MOD_NOADDRESSES | - K5_CDFLAG_MOD_CREATE_CONF | - K5_CDFLAG_MOD_REALMS))) { - - d->flags = 0; - return; - - } - - khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); - - UnicodeStrToAnsi(astr, sizeof(astr), d->config_file); - - if (stricmp(config_file, astr)) { - assert(FALSE); - } - - filenames[0] = config_file; - filenames[1] = NULL; - - rv = pprofile_init(filenames, &profile); - -#if FAILOVER_TO_TEMPORARY_FILE - if (rv) { - char temp_file[MAX_PATH]; - - khm_krb5_get_temp_profile_file(temp_file, - ARRAYLENGTH(temp_file)); - - filenames[0] = temp_file; - - rv = pprofile_init(filenames, &profile); - - ?? TODO: Also warn if we are doing this - } -#endif - - - if (!rv) { - const char * sec_realms[] = { "realms", NULL }; - const char * sec_domain_realm[] = { "domain_realm", NULL }; - const char * sec_libdefaults[] = { "libdefaults", NULL, NULL }; - khm_size r; - - if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_KDC) { - - sec_libdefaults[1] = "dns_lookup_kdc"; - - pprofile_clear_relation(profile, sec_libdefaults); - - rv = pprofile_add_relation(profile, sec_libdefaults, - (d->dns_lookup_kdc)? - conf_yes[0]: - conf_no[0]); - } - - - if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_RLM) { - - sec_libdefaults[1] = "dns_lookup_realm"; - - pprofile_clear_relation(profile, sec_libdefaults); - - rv = pprofile_add_relation(profile, sec_libdefaults, - (d->dns_lookup_realm)? - conf_yes[0]: - conf_no[0]); - - } - - if (d->flags & K5_CDFLAG_MOD_DNS_FALLBACK) { - - sec_libdefaults[1] = "dns_fallback"; - - pprofile_clear_relation(profile, sec_libdefaults); - - rv = pprofile_add_relation(profile, sec_libdefaults, - (d->dns_fallback)? - conf_yes[0]: - conf_no[0]); - } - - if (d->flags & K5_CDFLAG_MOD_NOADDRESSES) { - - sec_libdefaults[1] = "noaddresses"; - - pprofile_clear_relation(profile, sec_libdefaults); - - rv = pprofile_add_relation(profile, sec_libdefaults, - (d->noaddresses)? - conf_yes[0]: - conf_no[0]); - } - - /* now we look at the [realms] section */ - - for (r=0; r < d->n_realms; r++) { - char realm[K5_MAXCCH_REALM]; - char host[K5_MAXCCH_HOST]; - - const char * sec_kdcs[] = - { "realms", realm, "kdc", NULL }; - - const char * sec_admin[] = - { "realms", realm, "admin_server", NULL }; - - const char * sec_master[] = - { "realms", realm, "master_kdc", NULL }; - - const char * sec_domain_map[] = - { "domain_realm", host, NULL }; - - char ** values; - - UnicodeStrToAnsi(realm, sizeof(realm), - d->realms[r].realm); - - if (!(d->realms[r].flags & K5_RDFLAG_DELETED) && - (d->realms[r].flags & K5_RDFLAG_NEW)) { - - khm_size k; - khm_size m; - - /* this is a new realm */ - - for (k=0; k < d->realms[r].n_kdcs; k++) { - if (!(d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { - UnicodeStrToAnsi(host, sizeof(host), - d->realms[r].kdcs[k].name); - - if (d->realms[r].kdcs[k].master) - pprofile_add_relation(profile, sec_master, - host); - else - pprofile_add_relation(profile, sec_kdcs, - host); - - if (d->realms[r].kdcs[k].admin) - pprofile_add_relation(profile, sec_admin, - host); - } - } - - for (m=0; m < d->realms[r].n_domain_maps; m++) { - - UnicodeStrToAnsi(host, sizeof(host), - d->realms[r].domain_maps[m].name); - - if ((d->realms[r].domain_maps[m].flags & - K5_DMFLAG_DELETED) && - !(d->realms[r].domain_maps[m].flags & - K5_DMFLAG_NEW)) - pprofile_clear_relation(profile, sec_domain_map); - else if (!(d->realms[r].domain_maps[m].flags & - K5_DMFLAG_DELETED) && - (d->realms[r].domain_maps[m].flags & - K5_DMFLAG_NEW)) - pprofile_add_relation(profile, sec_domain_map, - realm); - } - } else if ((d->realms[r].flags & K5_RDFLAG_DELETED) && - !(d->realms[r].flags & K5_RDFLAG_NEW)) { - - const char * sec_all[] = - { "realms", realm, NULL, NULL }; - khm_size v; - - /* this realm should be deleted */ - - rv = pprofile_get_relation_names(profile, sec_all, - &values); - if (!rv) { - for (v=0; values[v] && values[v][0]; v++) { - sec_all[2] = values[v]; - pprofile_clear_relation(profile, sec_all); - } - pprofile_free_list(values); - } - - rv = pprofile_get_relation_names(profile, sec_domain_realm, - &values); - if (!rv) { - char * maprealm; - - for (v=0; values[v] && values[v][0]; v++) { - - rv = pprofile_get_string(profile, "domain_realm", - values[v], NULL, NULL, - &maprealm); - - if (!rv) { - if (!strcmp(maprealm, realm)) { - StringCbCopyA(host, sizeof(host), - values[v]); - pprofile_clear_relation(profile, - sec_domain_map); - } - pprofile_release_string(maprealm); - } - } - - pprofile_free_list(values); - } - } else if (!(d->realms[r].flags & K5_RDFLAG_DELETED)) { - khm_size k; - khm_size m; - - /* same as before. check if we have to update the kdc - list or the domain_realm mappings */ - - for (k=0; k < d->realms[r].n_kdcs; k++) { - UnicodeStrToAnsi(host, sizeof(host), - d->realms[r].kdcs[k].name); - if (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED) { - pprofile_update_relation(profile, sec_kdcs, - host, NULL); - pprofile_update_relation(profile, sec_admin, - host, NULL); - pprofile_update_relation(profile, sec_master, - host, NULL); - - continue; - } - - if (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) { - if (d->realms[r].kdcs[k].master) - pprofile_add_relation(profile, sec_master, - host); - else - pprofile_add_relation(profile, sec_kdcs, - host); - - if (d->realms[r].kdcs[k].admin) - pprofile_add_relation(profile, sec_admin, - host); - continue; - } - - if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_MASTER) { - if (!d->realms[r].kdcs[k].master) { - pprofile_add_relation(profile, sec_kdcs, - host); - pprofile_update_relation(profile, sec_master, - host, NULL); - } else { - pprofile_add_relation(profile, sec_master, - host); - pprofile_update_relation(profile, sec_kdcs, - host, NULL); - } - } - - if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_ADMIN) { - if (d->realms[r].kdcs[k].admin) - pprofile_add_relation(profile, sec_admin, - host); - else - pprofile_update_relation(profile, sec_admin, - host, NULL); - } - } - - for (m=0; m < d->realms[r].n_domain_maps; m++) { - - UnicodeStrToAnsi(host, sizeof(host), - d->realms[r].domain_maps[m].name); - - if ((d->realms[r].domain_maps[m].flags & - K5_DMFLAG_DELETED) && - !(d->realms[r].domain_maps[m].flags & - K5_DMFLAG_NEW)) - pprofile_clear_relation(profile, sec_domain_map); - else if (!(d->realms[r].domain_maps[m].flags & - K5_DMFLAG_DELETED) && - (d->realms[r].domain_maps[m].flags & - K5_DMFLAG_NEW)) - pprofile_add_relation(profile, sec_domain_map, - realm); - } - } - } - - rv = pprofile_flush(profile); - - pprofile_release(profile); - } - - if (rv) { - khui_alert * alert; - wchar_t title[KHUI_MAXCCH_TITLE]; - wchar_t fmsg[KHUI_MAXCCH_MESSAGE]; - wchar_t msg[KHUI_MAXCCH_MESSAGE]; - wchar_t sugg[KHUI_MAXCCH_SUGGESTION]; - - LoadString(hResModule, IDS_K5ERR_CANTWRITEPROFILE, - title, ARRAYLENGTH(title)); - if (rv) - LoadString(hResModule, IDS_K5ERR_PROFNOWRITE, - fmsg, ARRAYLENGTH(fmsg)); - - LoadString(hResModule, IDS_K5ERR_PROFSUGGEST, - sugg, ARRAYLENGTH(sugg)); - - StringCbPrintf(msg, sizeof(msg), fmsg, config_file); - - khui_alert_create_empty(&alert); - khui_alert_set_severity(alert, (rv)?KHERR_ERROR:KHERR_WARNING); - khui_alert_set_title(alert, title); - khui_alert_set_message(alert, msg); - khui_alert_set_suggestion(alert, sugg); - - khui_alert_show(alert); - } - - d->flags = 0; -} - -/* actual dialog stuff */ - -#define IDX_NORMAL 1 -#define IDX_MODIFIED 2 -#define IDX_NEW 3 -#define IDX_DELETED 4 - -static k5_config_data k5_config_dlg_data; -static khm_boolean k5_dlg_data_valid = FALSE; - -INT_PTR CALLBACK -k5_config_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - { - HWND hw; - khm_size i; - k5_config_data * d; - - wchar_t * t; - wchar_t importopts[256]; - WKSTA_INFO_100 * winfo100; - -#ifdef DEBUG - assert(!k5_dlg_data_valid); -#endif - - k5_init_config_data(&k5_config_dlg_data); - k5_read_config_data(&k5_config_dlg_data); - - k5_dlg_data_valid = TRUE; - - d = &k5_config_dlg_data; - - d->node_main = (khui_config_node) lParam; - - CheckDlgButton(hwnd, IDC_CFG_INCREALMS, - (d->inc_realms)? BST_CHECKED: BST_UNCHECKED); - - hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM); -#ifdef DEBUG - assert(hw); -#endif - - SendMessage(hw, CB_RESETCONTENT, 0, 0); - - for (i=0; i < d->n_realms; i++) { - SendMessage(hw, CB_ADDSTRING, 0, - (LPARAM) d->realms[i].realm); - } - - SendMessage(hw, CB_SELECTSTRING, -1, - (LPARAM) d->def_realm); - - SetDlgItemText(hwnd, IDC_CFG_CFGFILE, d->config_file); - - /* 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, d->lsa_import); - t = importopts; - SendMessage(hw, CB_GETLBTEXT, d->lsa_import,(LPARAM) t); - SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) t); - } - break; - - case WM_COMMAND: - { - k5_config_data * d; - - d = &k5_config_dlg_data; - - if (wParam == MAKEWPARAM(IDC_CFG_IMPORT, CBN_SELCHANGE)) { - int idx; - int modified = FALSE; - - idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_IMPORT, - CB_GETCURSEL, 0, 0); - if (idx != CB_ERR && idx != d->lsa_import) { - d->lsa_import = idx; - d->flags |= K5_CDFLAG_MOD_LSA_IMPORT; - modified = TRUE; - } - - khui_cfg_set_flags(d->node_main, - (modified)?KHUI_CNFLAG_MODIFIED:0, - KHUI_CNFLAG_MODIFIED); - return TRUE; - } - - if (wParam == MAKEWPARAM(IDC_CFG_INCREALMS, BN_CLICKED)) { - if (IsDlgButtonChecked(hwnd, IDC_CFG_INCREALMS) == - BST_CHECKED) { - d->inc_realms = TRUE; - } else { - d->inc_realms = FALSE; - } - d->flags |= K5_CDFLAG_MOD_INC_REALMS; - - khui_cfg_set_flags(d->node_main, - KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - return TRUE; - } - } - break; - - case KHUI_WM_CFG_NOTIFY: - { - k5_config_data * d; - - d = &k5_config_dlg_data; - - if (HIWORD(wParam) == WMCFG_APPLY) { - khm_int32 oflags; - - oflags = d->flags; - k5_write_config_data(d); - - if (d->flags != oflags) { - khui_cfg_set_flags(d->node_main, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | - KHUI_CNFLAG_MODIFIED); - } - return TRUE; - } - } - break; - - case WM_DESTROY: - { - k5_free_config_data(&k5_config_dlg_data); - k5_dlg_data_valid = FALSE; - } - break; - } - return FALSE; -} - -static HIMAGELIST -k5_get_state_image_list(void) { - HIMAGELIST hil; - HICON hicon; - - hil = ImageList_Create(GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - ILC_COLOR | ILC_MASK, - 4, - 2); - - hicon = LoadImage(hResModule, - MAKEINTRESOURCE(IDI_NORMAL), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_DEFAULTCOLOR); - - ImageList_AddIcon(hil, hicon); - - DestroyIcon(hicon); - - hicon = LoadImage(hResModule, - MAKEINTRESOURCE(IDI_MODIFIED), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_DEFAULTCOLOR); - - ImageList_AddIcon(hil, hicon); - - DestroyIcon(hicon); - - hicon = LoadImage(hResModule, - MAKEINTRESOURCE(IDI_NEW), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_DEFAULTCOLOR); - - ImageList_AddIcon(hil, hicon); - - DestroyIcon(hicon); - - hicon = LoadImage(hResModule, - MAKEINTRESOURCE(IDI_DELETED), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_DEFAULTCOLOR); - - ImageList_AddIcon(hil, hicon); - - DestroyIcon(hicon); - - return hil; -} - -static void -k5_update_realms_display(HWND hw_list, k5_config_data * d) { - khm_size i; - LVITEM lvi; - wchar_t buf[64]; - - ListView_DeleteAllItems(hw_list); - - for (i=0; i < d->n_realms; i++) { - if ((d->realms[i].flags & K5_RDFLAG_DELETED) && - (d->realms[i].flags & K5_RDFLAG_NEW)) - continue; - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - lvi.iItem = 0; - lvi.iSubItem = 0; - lvi.pszText = d->realms[i].realm; - lvi.lParam = i; - - if (d->realms[i].flags & K5_RDFLAG_DELETED) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); - } else if (d->realms[i].flags & K5_RDFLAG_NEW) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - } else if (d->realms[i].flags & K5_RDFLAG_MODIFED) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); - } else { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); - } - lvi.stateMask = LVIS_STATEIMAGEMASK; - - ListView_InsertItem(hw_list, &lvi); - } - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - lvi.iItem = 0; - lvi.iSubItem = 0; - lvi.pszText = buf; - lvi.lParam = (LPARAM) -1; - - LoadString(hResModule, IDS_CFG_RE_NEWREALM, - buf, ARRAYLENGTH(buf)); - - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - lvi.stateMask = LVIS_STATEIMAGEMASK; - - ListView_InsertItem(hw_list, &lvi); - - if (d->flags & K5_CDFLAG_MOD_REALMS) { - khui_cfg_set_flags(d->node_realm, KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - } else { - khui_cfg_set_flags(d->node_realm, 0, - KHUI_CNFLAG_MODIFIED); - } -} - -static void -k5_update_kdcs_display(HWND hw_kdc, k5_config_data * d, khm_size idx_rlm) { - khm_size k; - LVITEM lvi; - int idx_item; - k5_realm_kdc * pkdc; - wchar_t wyes[8]; - wchar_t wno[8]; - wchar_t wbuf[64]; - - ListView_DeleteAllItems(hw_kdc); - - if (d == NULL) - return; - -#ifdef DEBUG - assert(idx_rlm < d->n_realms); -#endif - LoadString(hResModule, IDS_YES, wyes, ARRAYLENGTH(wyes)); - LoadString(hResModule, IDS_NO, wno, ARRAYLENGTH(wno)); - - for (k=0; k < d->realms[idx_rlm].n_kdcs; k++) { - if ((d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_DELETED) && - (d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_NEW)) - continue; - - pkdc = &(d->realms[idx_rlm].kdcs[k]); - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - lvi.iItem = K5_MAX_KDC; - lvi.iSubItem = 0; - lvi.lParam = k; - lvi.pszText = pkdc->name; - if (pkdc->flags & K5_RKFLAG_DELETED) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); - } else if (pkdc->flags & K5_RKFLAG_NEW) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - } else if ((pkdc->flags & K5_RKFLAG_MOD_ADMIN) || - (pkdc->flags & K5_RKFLAG_MOD_MASTER)) { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); - } else { - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); - } - lvi.stateMask = LVIS_STATEIMAGEMASK; - - idx_item = ListView_InsertItem(hw_kdc, &lvi); - - lvi.mask = LVIF_TEXT; - lvi.iItem = idx_item; - lvi.iSubItem = 1; - if (pkdc->admin) - lvi.pszText = wyes; - else - lvi.pszText = wno; - ListView_SetItem(hw_kdc, &lvi); - - lvi.iSubItem = 2; - if (pkdc->master) - lvi.pszText = wyes; - else - lvi.pszText = wno; - ListView_SetItem(hw_kdc, &lvi); - } - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; - lvi.iItem = 0; - lvi.iSubItem = 0; - lvi.pszText = wbuf; - lvi.lParam = (LPARAM) -1; - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - lvi.stateMask = LVIS_STATEIMAGEMASK; - - LoadString(hResModule, IDS_CFG_RE_NEWSERVER, - wbuf, ARRAYLENGTH(wbuf)); - - ListView_InsertItem(hw_kdc, &lvi); -} - -static void -k5_update_dmap_display(HWND hw_dm, k5_config_data * d, khm_size idx_rlm) { - khm_size m; - LVITEM lvi; - k5_domain_map * map; - wchar_t wbuf[64]; - - ListView_DeleteAllItems(hw_dm); - - if (d == NULL) - return; - -#ifdef DEBUG - assert(idx_rlm < d->n_realms); -#endif - - for (m=0; m < d->realms[idx_rlm].n_domain_maps; m++) { - map = &(d->realms[idx_rlm].domain_maps[m]); - - if ((map->flags & K5_DMFLAG_NEW) && - (map->flags & K5_DMFLAG_DELETED)) - continue; - - ZeroMemory(&lvi, sizeof(lvi)); - - lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; - lvi.pszText = map->name; - if (map->flags & K5_DMFLAG_DELETED) - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); - else if (map->flags & K5_DMFLAG_NEW) - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - else - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); - lvi.stateMask = LVIS_STATEIMAGEMASK; - lvi.lParam = m; - - lvi.iItem = K5_MAX_DOMAIN_MAPPINGS; - lvi.iSubItem = 0; - - ListView_InsertItem(hw_dm, &lvi); - } - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; - lvi.pszText = wbuf; - lvi.lParam = (LPARAM) -1; - lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); - lvi.stateMask = LVIS_STATEIMAGEMASK; - lvi.iItem = 0; - lvi.iSubItem = 0; - - LoadString(hResModule, IDS_CFG_RE_NEWDMAP, - wbuf, ARRAYLENGTH(wbuf)); - - ListView_InsertItem(hw_dm, &lvi); -} - -INT_PTR CALLBACK -k5_realms_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - k5_config_data * d; - - d = &k5_config_dlg_data; - - switch(uMsg) { - case WM_INITDIALOG: - { - LVCOLUMN lvc; - HWND hw; - RECT r; - wchar_t buf[256]; - - assert(k5_dlg_data_valid); - - d->node_realm = (khui_config_node) lParam; - - /* set up columns for the Realms list */ - hw = GetDlgItem(hwnd, IDC_CFG_REALMS); -#ifdef DEBUG - assert(hw); -#endif - GetWindowRect(hw, &r); - r.right -= 5; /* shave a few pixels off the width */ - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - lvc.pszText = buf; - lvc.cx = (r.right - r.left); - LoadString(hResModule, IDS_CFG_RE_REALMS, - buf, ARRAYLENGTH(buf)); - - ListView_InsertColumn(hw, 0, &lvc); - - ListView_SetImageList(hw, - k5_get_state_image_list(), - LVSIL_STATE); - - k5_update_realms_display(hw, d); - - /* set up columns for the servers list */ - hw = GetDlgItem(hwnd, IDC_CFG_KDC); -#ifdef DEBUG - assert(hw); -#endif - GetWindowRect(hw, &r); - r.right -= 5; - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - lvc.pszText = buf; - lvc.cx = (r.right - r.left) * 2 / 4; - LoadString(hResModule, IDS_CFG_RE_HEAD_SVR, - buf, ARRAYLENGTH(buf)); - - ListView_InsertColumn(hw, 0, &lvc); - - lvc.cx = (r.right - r.left) * 1 / 4; - LoadString(hResModule, IDS_CFG_RE_HEAD_ADMIN, - buf, ARRAYLENGTH(buf)); - ListView_InsertColumn(hw, 1, &lvc); - - LoadString(hResModule, IDS_CFG_RE_HEAD_MASTER, - buf, ARRAYLENGTH(buf)); - ListView_InsertColumn(hw, 2, &lvc); - - ListView_SetImageList(hw, - k5_get_state_image_list(), - LVSIL_STATE); - - /* set up columns for the domain/host mapping list */ - hw = GetDlgItem(hwnd, IDC_CFG_DMAP); -#ifdef DEBUG - assert(hw); -#endif - GetWindowRect(hw, &r); - r.right -= 5; - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - lvc.pszText = buf; - lvc.cx = (r.right - r.left); - LoadString(hResModule, IDS_CFG_RE_HEAD_DOMAIN, - buf, ARRAYLENGTH(buf)); - - ListView_InsertColumn(hw, 0, &lvc); - - - ListView_SetImageList(hw, - k5_get_state_image_list(), - LVSIL_STATE); - } - break; - - case WM_NOTIFY: - { - LPNMHDR pnmh; - HWND hw_rlm = NULL; - HWND hw_kdc = NULL; - HWND hw_dmp = NULL; - int i; - - pnmh = (LPNMHDR) lParam; - - if (pnmh->idFrom == IDC_CFG_REALMS) { - - hw_rlm = pnmh->hwndFrom; - - switch(pnmh->code) { - case LVN_ITEMCHANGED: - i = ListView_GetSelectedCount(hw_rlm); - hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); - hw_dmp = GetDlgItem(hwnd, IDC_CFG_DMAP); - - d->c_realm = (khm_size) -1; - - if (i == 1) { - LVITEM lvi; - - i = ListView_GetNextItem(hw_rlm, -1, - LVNI_SELECTED); - if (i == -1) - goto _no_selection; - - ZeroMemory(&lvi, sizeof(lvi)); - - lvi.iItem = i; - lvi.iSubItem = 0; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw_rlm, &lvi); - - if (lvi.lParam == -1) - goto _no_selection; - - d->c_realm = lvi.lParam; - - k5_update_kdcs_display(hw_kdc, d, lvi.lParam); - k5_update_dmap_display(hw_dmp, d, lvi.lParam); - return TRUE; - } - - _no_selection: - ListView_DeleteAllItems(hw_kdc); - ListView_DeleteAllItems(hw_dmp); - break; - - case LVN_BEGINLABELEDIT: - { - NMLVDISPINFO * pdisp; - LVITEM lvi; - - pdisp = (NMLVDISPINFO *) lParam; - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.iItem = pdisp->item.iItem; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw_rlm, &lvi); - - if (pdisp->item.iItem == -1 || - lvi.lParam != -1) { - SetWindowLongPtr(hwnd, DWL_MSGRESULT, TRUE); - } else { - /* allow editing */ - HWND hw_edit; - - hw_edit = ListView_GetEditControl(hw_rlm); - if (hw_edit != NULL) { - SendMessage(hw_edit, - EM_SETLIMITTEXT, - K5_MAXCCH_REALM - 1, - 0); - } - SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); - } - - return TRUE; - } - break; - - case LVN_ENDLABELEDIT: - { - NMLVDISPINFO * pdisp; - khm_size n; - - pdisp = (NMLVDISPINFO *) lParam; - - if (pdisp->item.pszText) { - n = d->n_realms; - k5_assert_n_realms(d, n+1); - StringCbCopy(d->realms[n].realm, - sizeof(d->realms[n].realm), - pdisp->item.pszText); - d->realms[n].flags = K5_RDFLAG_NEW; - d->n_realms++; - - d->flags |= K5_CDFLAG_MOD_REALMS; - - k5_update_realms_display(hw_rlm, d); - } - - return TRUE; - } - break; - - case LVN_KEYDOWN: - { - NMLVKEYDOWN * pnmk; - LVITEM lvi; - khm_size r; - int idx; - BOOL modified = FALSE; - - pnmk = (NMLVKEYDOWN *) lParam; - - if (pnmk->wVKey == VK_DELETE) { - idx = -1; - while((idx = ListView_GetNextItem(hw_rlm, idx, - LVNI_SELECTED)) - != -1) { - ZeroMemory(&lvi, sizeof(lvi)); - lvi.iItem = idx; - lvi.iSubItem = 0; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw_rlm, &lvi); - - if (lvi.lParam != -1 && - (r = lvi.lParam) < d->n_realms) { - d->realms[r].flags ^= K5_RDFLAG_DELETED; - modified = TRUE; - } - } - - if (modified) { - d->flags |= K5_CDFLAG_MOD_REALMS; - - k5_purge_config_data(d, TRUE, TRUE, TRUE); - k5_update_realms_display(hw_rlm, d); - k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); - k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); - } - return TRUE; - } - } - break; - } - } else if (pnmh->idFrom == IDC_CFG_KDC) { - hw_kdc = pnmh->hwndFrom; - - switch (pnmh->code) { - case LVN_BEGINLABELEDIT: - { - NMLVDISPINFO * pdisp; - LVITEM lvi; - - pdisp = (NMLVDISPINFO *) lParam; - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.iItem = pdisp->item.iItem; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw_kdc, &lvi); - - if (pdisp->item.iItem == -1 || - lvi.lParam != -1) { - SetWindowLongPtr(hwnd, DWL_MSGRESULT, TRUE); - } else { - /* allow editing */ - HWND hw_edit; - - hw_edit = ListView_GetEditControl(hw_kdc); - if (hw_edit != NULL) { - SendMessage(hw_edit, - EM_SETLIMITTEXT, - K5_MAXCCH_HOST - 1, - 0); - } - SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); - } - return TRUE; - } - break; - - case LVN_ENDLABELEDIT: - { - NMLVDISPINFO * pdisp; - khm_size r; - khm_size k; - - r = d->c_realm; - - pdisp = (NMLVDISPINFO *) lParam; - - if (pdisp->item.pszText) { - k = d->realms[r].n_kdcs; - - if (k >= K5_MAX_KDC) { - SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); - /* TODO: show a message box saying - there are too many KDC's - already. */ - return TRUE; - } - - StringCbCopy(d->realms[r].kdcs[k].name, - sizeof(d->realms[0].kdcs[0].name), - pdisp->item.pszText); - d->realms[r].kdcs[k].flags = K5_RKFLAG_NEW; - d->realms[r].n_kdcs++; - - d->realms[r].flags |= K5_RDFLAG_MODIFED; - - k5_update_kdcs_display(hw_kdc, d, d->c_realm); - } - return TRUE; - } - break; - - case LVN_KEYDOWN: - { -#if 0 - NMLVKEYDOWN * pnmk; - LVITEM lvi; - khm_size r; - int idx; - BOOL modified = FALSE; - - pnmk = (NMLVKEYDOWN *) lParam; - - if (pnmk->wVKey == VK_DELETE) { - idx = -1; - while((idx = ListView_GetNextItem(hw_rlm, idx, - LVNI_SELECTED)) - != -1) { - ZeroMemory(&lvi, sizeof(lvi)); - lvi.iItem = idx; - lvi.iSubItem = 0; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw_rlm, &lvi); - - if (lvi.lParam != -1 && - (r = lvi.lParam) < d->n_realms) { - d->realms[r].flags ^= K5_RDFLAG_DELETED; - modified = TRUE; - } - } - - if (modified) { - d->flags |= K5_CDFLAG_MOD_REALMS; - - k5_purge_config_data(d, TRUE, TRUE, TRUE); - k5_update_realms_display(hw_rlm, d); - k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); - k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); - } - return TRUE; - } -#endif - } - break; - } - } - } - 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 - } - -#ifdef REALM_EDITOR - 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, ®); -#endif - - ZeroMemory(®, sizeof(reg)); - - LoadString(hResModule, IDS_K5CCC_SHORT_DESC, - wshort, ARRAYLENGTH(wshort)); - LoadString(hResModule, IDS_K5CCC_LONG_DESC, - wlong, ARRAYLENGTH(wlong)); - - reg.name = L"KerberosCCaches"; - reg.short_desc = wshort; - reg.long_desc = wlong; - reg.h_module = hResModule; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_CACHES); - reg.dlg_proc = k5_ccconfig_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; -#ifdef REALM_EDITOR - khui_config_node node_realms; -#endif - khui_config_node node_ids; - khui_config_node node_tab; - khui_config_node node_ccaches; - - if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node_main))) { - node_main = NULL; -#ifdef DEBUG - assert(FALSE); -#endif - } - -#ifdef REALM_EDITOR - 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 -#endif - - if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosCCaches", - &node_ccaches))) { - khui_cfg_remove(node_ccaches); - khui_cfg_release(node_ccaches); - } -#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); -} +/* + * Copyright (c) 2005 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 + +#pragma warning(push) +#pragma warning(disable: 4995) +#include +#pragma warning(pop) + + +typedef struct tag_k5_realm_kdc { + wchar_t name[K5_MAXCCH_HOST]; + khm_boolean admin; /* admin server? */ + khm_boolean master; /* master kdc? */ + khm_int32 flags; +} k5_realm_kdc; + +#define K5_RKFLAG_DELETED 1 +#define K5_RKFLAG_NEW 2 +#define K5_RKFLAG_MOD_ADMIN 4 +#define K5_RKFLAG_MOD_MASTER 8 + +typedef struct tag_k5_domain_map { + wchar_t name[K5_MAXCCH_HOST]; /* name of host that maps to a + realm */ + khm_int32 flags; +} k5_domain_map; + +#define K5_DMFLAG_DELETED 1 +#define K5_DMFLAG_NEW 2 + +typedef struct tag_k5_realm_data { + wchar_t realm[K5_MAXCCH_REALM]; + k5_realm_kdc kdcs[K5_MAX_KDC]; + khm_size n_kdcs; + k5_domain_map domain_maps[K5_MAX_DOMAIN_MAPPINGS]; + khm_size n_domain_maps; + + khm_int32 flags; +} k5_realm_data; + +#define K5_RDFLAG_DELETED 1 +#define K5_RDFLAG_NEW 2 +#define K5_RDFLAG_MODIFED 4 + +#define K5_REALMS_ALLOC_INCR 8 + +typedef struct tag_k5_config_data { + wchar_t def_realm[K5_MAXCCH_REALM]; /* default realm */ + + wchar_t config_file[MAX_PATH]; /* path to configuration file */ + khm_boolean create_config_file; /* create config_file if missing? */ + khm_boolean inc_realms; /* include full realm list in new + credentials dialog? */ + + /* [libdefaults] */ + khm_boolean dns_lookup_kdc; + khm_boolean dns_lookup_realm; + khm_boolean dns_fallback; + + khm_boolean noaddresses; + + k5_lsa_import lsa_import; /* import mslsa creds? */ + + /* [realms] */ + k5_realm_data *realms; + khm_size n_realms; + khm_size nc_realms; + khm_size c_realm; + + khui_config_node node_main; + khui_config_node node_realm; + + khm_int32 flags; + + /* used by the realm editor */ + HMENU hm_realms_ctx; + HMENU hm_kdc_ctx; + HMENU hm_dmap_ctx; +} k5_config_data; + +#define K5_CDFLAG_MOD_DEF_REALM 0x00000001 +#define K5_CDFLAG_MOD_CONF_FILE 0x00000002 +#define K5_CDFLAG_MOD_DNS_LOOKUP_KDC 0x00000004 +#define K5_CDFLAG_MOD_DNS_LOOKUP_RLM 0x00000008 +#define K5_CDFLAG_MOD_DNS_FALLBACK 0x00000010 +#define K5_CDFLAG_MOD_NOADDRESSES 0x00000020 +#define K5_CDFLAG_MOD_LSA_IMPORT 0x00000040 +#define K5_CDFLAG_MOD_CREATE_CONF 0x00000080 +#define K5_CDFLAG_MOD_INC_REALMS 0x00000100 +#define K5_CDFLAG_MOD_REALMS 0x00001000 + +static const char *const conf_yes[] = { + "y", "yes", "true", "t", "1", "on", + 0, +}; + +static const char *const conf_no[] = { + "n", "no", "false", "nil", "0", "off", + 0, +}; + +int +k5_parse_boolean(const char *s) +{ + const char *const *p; + + for(p=conf_yes; *p; p++) { + if (!stricmp(*p,s)) + return 1; + } + + for(p=conf_no; *p; p++) { + if (!stricmp(*p,s)) + return 0; + } + + /* Default to "no" */ + return 0; +} + +void +k5_init_config_data(k5_config_data * d) { + ZeroMemory(d, sizeof(*d)); +} + +void +k5_free_config_data(k5_config_data * d) { + if (d->realms) + PFREE(d->realms); + + k5_init_config_data(d); +} + +static void +k5_assert_n_realms(k5_config_data * d, khm_size n) { + khm_size nc_realms; + + if (n <= d->nc_realms) + return; + + nc_realms = UBOUNDSS(n, K5_REALMS_ALLOC_INCR, K5_REALMS_ALLOC_INCR); + assert(nc_realms > d->nc_realms); + + d->realms = PREALLOC(d->realms, nc_realms * sizeof(*(d->realms))); + d->nc_realms = nc_realms; + + ZeroMemory(&d->realms[d->n_realms], + (d->nc_realms - d->n_realms) * sizeof(*(d->realms))); +} + +void +k5_purge_config_data(k5_config_data * d, + khm_boolean purge_realms, + khm_boolean purge_kdcs, + khm_boolean purge_dmap) { + khm_size r; + khm_size k; + khm_size m; + + for (r=0; r < d->n_realms; r++) { + if (purge_realms && + (d->realms[r].flags & K5_RDFLAG_NEW) && + (d->realms[r].flags & K5_RDFLAG_DELETED)) { + + if (d->n_realms > r+1) + MoveMemory(&d->realms[r], &d->realms[r+1], + sizeof(d->realms[0]) * (d->n_realms - (r+1))); + r--; + d->n_realms--; + continue; + } + + for (k=0; k < d->realms[r].n_kdcs; k++) { + if (purge_kdcs && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { + if (d->realms[r].n_kdcs > k + 1) + MoveMemory(&d->realms[r].kdcs[k], + &d->realms[r].kdcs[k+1], + sizeof(d->realms[0].kdcs[0]) * + (d->realms[r].n_kdcs - (k+1))); + k--; + d->realms[r].n_kdcs--; + continue; + } + } + + if (K5_MAX_KDC > k+1) + ZeroMemory(&d->realms[r].kdcs[k], + sizeof(d->realms[0].kdcs[0]) * + (K5_MAX_KDC - (k + 1))); + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + if (purge_dmap && + (d->realms[r].domain_maps[m].flags & K5_DMFLAG_NEW) && + (d->realms[r].domain_maps[m].flags & K5_DMFLAG_DELETED)) { + if (d->realms[r].n_domain_maps > m + 1) + MoveMemory(&d->realms[r].domain_maps[m], + &d->realms[r].domain_maps[m+1], + sizeof(d->realms[0].domain_maps[0]) * + (d->realms[r].n_domain_maps - (m+1))); + m--; + d->realms[r].n_domain_maps--; + continue; + } + } + + if (K5_MAX_DOMAIN_MAPPINGS > m+1) + ZeroMemory(&d->realms[r].domain_maps[m], + sizeof(d->realms[0].domain_maps[0]) * + (K5_MAX_DOMAIN_MAPPINGS - (m+1))); + } + + if (d->nc_realms > r + 1) + ZeroMemory(&d->realms[r], + sizeof(d->realms[0]) * + (d->nc_realms - (r + 1))); +} + +static khm_boolean +k5_is_profile_loaded(void) { +#ifdef DEBUG + assert(pprofile_init); + assert(pprofile_get_subsection_names); + assert(pprofile_get_values); + assert(pprofile_get_string); + assert(pprofile_get_relation_names); + assert(pprofile_free_list); + assert(pprofile_release_string); + assert(pprofile_release); + assert(pprofile_clear_relation); + assert(pprofile_add_relation); + assert(pprofile_update_relation); + assert(pprofile_flush); +#endif + + if (!pprofile_init || + !pprofile_get_subsection_names || + !pprofile_get_values || + !pprofile_get_string || + !pprofile_get_relation_names || + !pprofile_free_list || + !pprofile_release_string || + !pprofile_release || + !pprofile_clear_relation || + !pprofile_add_relation || + !pprofile_update_relation || + !pprofile_flush) + + return FALSE; + + return TRUE; +} + +void +k5_read_config_data(k5_config_data * d) { + wchar_t * defrealm; + char config_file[MAX_PATH]; + profile_t profile = NULL; + const char *filenames[2]; + long rv; + khm_size s; + + if (!k5_is_profile_loaded()) + return; + + defrealm = khm_krb5_get_default_realm(); + + if (defrealm) { + StringCbCopy(d->def_realm, sizeof(d->def_realm), defrealm); + PFREE(defrealm); + } else { + StringCbCopy(d->def_realm, sizeof(d->def_realm), L""); + } + + khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); + + AnsiStrToUnicode(d->config_file, sizeof(d->config_file), config_file); + + filenames[0] = config_file; + filenames[1] = NULL; + + rv = pprofile_init(filenames, &profile); + + if (!rv) { + const char * sec_realms[] = { "realms", NULL }; + const char * sec_domain_realm[] = { "domain_realm", NULL }; + char ** sections; + char ** dr_from; + char * boolv; + + /* first fish out a few values from [libdefaults] */ + + rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_kdc", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_lookup_kdc = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_lookup_kdc = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_realm", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_lookup_realm = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_lookup_realm = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "dns_fallback", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_fallback = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_fallback = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "noaddresses", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->noaddresses = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->noaddresses = TRUE; + + /* now we look at the [realms] section */ + rv = pprofile_get_subsection_names(profile, sec_realms, §ions); + + /* what? no realms? whatever */ + if (rv) goto _skip_realms; + + /* get a count first */ + for (s=0; sections[s] && sections[s][0]; s++); + + k5_assert_n_realms(d, s); + d->n_realms = s; + + /* now go through each and fish out the kdcs, admin_server + and master_kdc. */ + for (s=0; sections[s] && sections[s][0]; s++) { + const char * sec_kdcs[] = + { "realms", sections[s], "kdc", NULL }; + + const char * sec_admin[] = + { "realms", sections[s], "admin_server", NULL }; + + const char * sec_master[] = + { "realms", sections[s], "master_kdc", NULL }; + + char ** values; + + AnsiStrToUnicode(d->realms[s].realm, sizeof(d->realms[s].realm), + sections[s]); + d->realms[s].n_kdcs = 0; + d->realms[s].n_domain_maps = 0; + + rv = pprofile_get_values(profile, sec_kdcs, &values); + if (!rv) { + khm_size i; + + for (i=0 ; values[i] && values[i][0] && i < K5_MAX_KDC; i++) { + AnsiStrToUnicode(d->realms[s].kdcs[i].name, + sizeof(d->realms[s].kdcs[i].name), + values[i]); + + } + d->realms[s].n_kdcs = i; + + pprofile_free_list(values); + } + + rv = pprofile_get_values(profile, sec_admin, &values); + if (!rv) { + khm_size i; + khm_size j; + wchar_t kdc_name[K5_MAXCCH_HOST]; + + for (i=0; values[i] && values[i][0]; i++) { + AnsiStrToUnicode(kdc_name, + sizeof(kdc_name), values[i]); + + for (j=0; j < d->realms[s].n_kdcs; j++) + if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) + break; + + if (j < d->realms[s].n_kdcs) { + d->realms[s].kdcs[j].admin = TRUE; + } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { + j = d->realms[s].n_kdcs; + StringCbCopy(d->realms[s].kdcs[j].name, + sizeof(d->realms[s].kdcs[j].name), + kdc_name); + d->realms[s].kdcs[j].admin = TRUE; + d->realms[s].n_kdcs ++; + } + } + pprofile_free_list(values); + } + + rv = pprofile_get_values(profile, sec_master, &values); + if (!rv) { + khm_size i; + khm_size j; + wchar_t kdc_name[K5_MAXCCH_HOST]; + + for (i=0; values[i] && values[i][0]; i++) { + AnsiStrToUnicode(kdc_name, sizeof(kdc_name), values[i]); + + for (j=0; j < d->realms[s].n_kdcs; j++) + if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) + break; + + if (j < d->realms[s].n_kdcs) { + d->realms[s].kdcs[j].master = TRUE; + } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { + j = d->realms[s].n_kdcs; + StringCbCopy(d->realms[s].kdcs[j].name, + sizeof(d->realms[s].kdcs[j].name), + kdc_name); + d->realms[s].kdcs[j].master = TRUE; + d->realms[s].n_kdcs ++; + } + } + + pprofile_free_list(values); + } + } + pprofile_free_list(sections); + + _skip_realms: + + rv = pprofile_get_relation_names(profile, sec_domain_realm, &dr_from); + if (!rv) { + khm_size i; + khm_size j; + char * dr_to; + wchar_t wdr_from[K5_MAXCCH_HOST]; + wchar_t wdr_to[K5_MAXCCH_HOST]; + + for (i=0; dr_from[i] && dr_from[i][0]; i++) { + AnsiStrToUnicode(wdr_from, sizeof(wdr_from), dr_from[i]); + + rv = pprofile_get_string(profile, "domain_realm", dr_from[i], + NULL, NULL, &dr_to); + + if (rv || !dr_to) + continue; + + AnsiStrToUnicode(wdr_to, sizeof(wdr_to), dr_to); + + for (j=0; j < d->n_realms; j++) { + if (!wcsicmp(wdr_to, d->realms[j].realm)) + break; + } + + if (j >= d->n_realms) { + j = d->n_realms; + k5_assert_n_realms(d, j + 1); + + StringCbCopy(d->realms[j].realm, + sizeof(d->realms[j].realm), + wdr_to); + d->realms[j].n_kdcs = 0; + d->realms[j].n_domain_maps = 0; + + d->n_realms++; + } + + if (d->realms[j].n_domain_maps < K5_MAX_DOMAIN_MAPPINGS) { + khm_size k; + + k = d->realms[j].n_domain_maps; + + StringCbCopy(d->realms[j].domain_maps[k].name, + sizeof(d->realms[j].domain_maps[k].name), + wdr_from); + + d->realms[j].n_domain_maps++; + } + + pprofile_release_string(dr_to); + } + pprofile_free_list(dr_from); + } + pprofile_release(profile); + } + + { + khm_int32 t; + + /* last, read the MSLSA import setting */ + if (KHM_SUCCEEDED(khc_read_int32(csp_params, + L"MsLsaImport", &t))) { + d->lsa_import = t; + } else { + d->lsa_import = K5_LSAIMPORT_ALWAYS; + } + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, + L"UseFullRealmList", &t))) { + d->inc_realms = !!t; + } else { + d->inc_realms = TRUE; + } + } + + d->flags = 0; +} + +void +k5_write_config_data(k5_config_data * d) { + char astr[MAX_PATH * 2]; + char config_file[MAX_PATH]; + profile_t profile = NULL; + const char *filenames[2]; + long rv; + khm_size s; + + if (d->flags == 0) + return; + + if (!k5_is_profile_loaded()) + return; + + if (d->flags & K5_CDFLAG_MOD_DEF_REALM) { + if (SUCCEEDED(StringCbLength(d->def_realm, + sizeof(d->def_realm), &s)) && + s > 0) { + khm_krb5_set_default_realm(d->def_realm); + } + d->flags &= ~K5_CDFLAG_MOD_DEF_REALM; + } + + /* write the MSLSA import setting */ + if (d->flags & K5_CDFLAG_MOD_LSA_IMPORT) { + khc_write_int32(csp_params, L"MsLsaImport", d->lsa_import); + d->flags &= ~K5_CDFLAG_MOD_LSA_IMPORT; + } + + if (d->flags & K5_CDFLAG_MOD_INC_REALMS) { + khc_write_int32(csp_params, L"UseFullRealmList", d->inc_realms); + d->flags &= ~K5_CDFLAG_MOD_INC_REALMS; + } + + if (!(d->flags & + (K5_CDFLAG_MOD_CONF_FILE | + K5_CDFLAG_MOD_DNS_FALLBACK | + K5_CDFLAG_MOD_DNS_LOOKUP_RLM | + K5_CDFLAG_MOD_DNS_LOOKUP_KDC | + K5_CDFLAG_MOD_NOADDRESSES | + K5_CDFLAG_MOD_CREATE_CONF | + K5_CDFLAG_MOD_REALMS))) { + + d->flags = 0; + return; + } + + khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); + + UnicodeStrToAnsi(astr, sizeof(astr), d->config_file); + + if (stricmp(config_file, astr)) { + assert(FALSE); + } + + filenames[0] = config_file; + filenames[1] = NULL; + + rv = pprofile_init(filenames, &profile); + +#if FAILOVER_TO_TEMPORARY_FILE + if (rv) { + char temp_file[MAX_PATH]; + + khm_krb5_get_temp_profile_file(temp_file, + ARRAYLENGTH(temp_file)); + + filenames[0] = temp_file; + + rv = pprofile_init(filenames, &profile); + + ?? TODO: Also warn if we are doing this + } +#endif + + if (!rv) { + const char * sec_realms[] = { "realms", NULL }; + const char * sec_domain_realm[] = { "domain_realm", NULL }; + const char * sec_libdefaults[] = { "libdefaults", NULL, NULL }; + khm_size r; + + if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_KDC) { + + sec_libdefaults[1] = "dns_lookup_kdc"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_lookup_kdc)? + conf_yes[0]: + conf_no[0]); + d->flags &= ~K5_CDFLAG_MOD_DNS_LOOKUP_KDC; + } + + + if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_RLM) { + + sec_libdefaults[1] = "dns_lookup_realm"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_lookup_realm)? + conf_yes[0]: + conf_no[0]); + + d->flags &= ~K5_CDFLAG_MOD_DNS_LOOKUP_RLM; + } + + if (d->flags & K5_CDFLAG_MOD_DNS_FALLBACK) { + + sec_libdefaults[1] = "dns_fallback"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_fallback)? + conf_yes[0]: + conf_no[0]); + + d->flags &= ~K5_CDFLAG_MOD_DNS_FALLBACK; + } + + if (d->flags & K5_CDFLAG_MOD_NOADDRESSES) { + + sec_libdefaults[1] = "noaddresses"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->noaddresses)? + conf_yes[0]: + conf_no[0]); + + d->flags &= ~K5_CDFLAG_MOD_NOADDRESSES; + } + + /* now we look at the [realms] section */ + + for (r=0; r < d->n_realms; r++) { + char realm[K5_MAXCCH_REALM]; + char host[K5_MAXCCH_HOST]; + + const char * sec_kdcs[] = + { "realms", realm, "kdc", NULL }; + + const char * sec_admin[] = + { "realms", realm, "admin_server", NULL }; + + const char * sec_master[] = + { "realms", realm, "master_kdc", NULL }; + + const char * sec_domain_map[] = + { "domain_realm", host, NULL }; + + char ** values; + + UnicodeStrToAnsi(realm, sizeof(realm), + d->realms[r].realm); + + if (!(d->realms[r].flags & K5_RDFLAG_DELETED) && + (d->realms[r].flags & K5_RDFLAG_NEW)) { + + khm_size k; + khm_size m; + + /* this is a new realm */ + + for (k=0; k < d->realms[r].n_kdcs; k++) { + if (!(d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].kdcs[k].name); + + if (d->realms[r].kdcs[k].master) + pprofile_add_relation(profile, sec_master, + host); + else + pprofile_add_relation(profile, sec_kdcs, + host); + + if (d->realms[r].kdcs[k].admin) + pprofile_add_relation(profile, sec_admin, + host); + + d->realms[r].kdcs[k].flags &= ~K5_RKFLAG_NEW; + } + } + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].domain_maps[m].name); + + if ((d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + !(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) { + pprofile_clear_relation(profile, sec_domain_map); + + /* setting this flag indicates that the item + is deleted and not in the profile file + anymore. */ + d->realms[r].domain_maps[m].flags |= K5_DMFLAG_NEW; + } else if (!(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + (d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) { + pprofile_add_relation(profile, sec_domain_map, + realm); + + d->realms[r].domain_maps[m].flags &= ~K5_DMFLAG_NEW; + } + } + + d->realms[r].flags &= ~K5_RDFLAG_NEW; + + } else if ((d->realms[r].flags & K5_RDFLAG_DELETED) && + !(d->realms[r].flags & K5_RDFLAG_NEW)) { + + const char * sec_all[] = + { "realms", realm, NULL, NULL }; + khm_size v; + + /* this realm should be deleted */ + + rv = pprofile_get_relation_names(profile, sec_all, + &values); + if (!rv) { + for (v=0; values[v] && values[v][0]; v++) { + sec_all[2] = values[v]; + pprofile_clear_relation(profile, sec_all); + } + pprofile_free_list(values); + } + + rv = pprofile_get_relation_names(profile, sec_domain_realm, + &values); + if (!rv) { + char * maprealm; + + for (v=0; values[v] && values[v][0]; v++) { + + rv = pprofile_get_string(profile, "domain_realm", + values[v], NULL, NULL, + &maprealm); + + if (!rv) { + if (!strcmp(maprealm, realm)) { + StringCbCopyA(host, sizeof(host), + values[v]); + pprofile_clear_relation(profile, + sec_domain_map); + } + pprofile_release_string(maprealm); + } + } + + pprofile_free_list(values); + } + + /* setting this flag indicate that the realm is + deleted and is not in the profile file. */ + d->realms[r].flags |= K5_RDFLAG_NEW; + + } else if (!(d->realms[r].flags & K5_RDFLAG_DELETED)) { + khm_size k; + khm_size m; + + /* same as before. check if we have to update the kdc + list or the domain_realm mappings */ + + for (k=0; k < d->realms[r].n_kdcs; k++) { + + if ((d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) + continue; + + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].kdcs[k].name); + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED) { + pprofile_update_relation(profile, sec_kdcs, + host, NULL); + pprofile_update_relation(profile, sec_admin, + host, NULL); + pprofile_update_relation(profile, sec_master, + host, NULL); + + /* as above, setting 'new' flag to indicate + that the item does not exist in the profile + file. */ + d->realms[r].kdcs[k].flags |= K5_RKFLAG_NEW; + continue; + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) { + if (d->realms[r].kdcs[k].master) + pprofile_add_relation(profile, sec_master, + host); + else + pprofile_add_relation(profile, sec_kdcs, + host); + + if (d->realms[r].kdcs[k].admin) + pprofile_add_relation(profile, sec_admin, + host); + + d->realms[r].kdcs[k].flags &= ~K5_RKFLAG_NEW; + continue; + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_MASTER) { + if (!d->realms[r].kdcs[k].master) { + pprofile_update_relation(profile, sec_kdcs, + host, NULL); + pprofile_add_relation(profile, sec_kdcs, + host); + pprofile_update_relation(profile, sec_master, + host, NULL); + } else { + pprofile_update_relation(profile, sec_master, + host, NULL); + pprofile_add_relation(profile, sec_master, + host); + pprofile_update_relation(profile, sec_kdcs, + host, NULL); + } + + d->realms[r].kdcs[k].flags &= ~K5_RKFLAG_MOD_MASTER; + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_ADMIN) { + if (d->realms[r].kdcs[k].admin) { + pprofile_update_relation(profile, sec_admin, + host, NULL); + pprofile_add_relation(profile, sec_admin, + host); + } else { + pprofile_update_relation(profile, sec_admin, + host, NULL); + } + + d->realms[r].kdcs[k].flags &= ~K5_RKFLAG_MOD_ADMIN; + } + } + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].domain_maps[m].name); + + if ((d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + + !(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) { + + pprofile_clear_relation(profile, sec_domain_map); + d->realms[r].domain_maps[m].flags |= K5_DMFLAG_NEW; + + } else if (!(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + + (d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) { + + pprofile_add_relation(profile, sec_domain_map, + realm); + d->realms[r].domain_maps[m].flags &= ~K5_DMFLAG_NEW; + } + } + + d->realms[r].flags &= ~K5_RDFLAG_MODIFED; + } + } + + rv = pprofile_flush(profile); + + pprofile_release(profile); + } + + if (rv) { + khui_alert * alert; + wchar_t title[KHUI_MAXCCH_TITLE]; + wchar_t fmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t msg[KHUI_MAXCCH_MESSAGE]; + wchar_t sugg[KHUI_MAXCCH_SUGGESTION]; + + LoadString(hResModule, IDS_K5ERR_CANTWRITEPROFILE, + title, ARRAYLENGTH(title)); + if (rv) + LoadString(hResModule, IDS_K5ERR_PROFNOWRITE, + fmsg, ARRAYLENGTH(fmsg)); + + LoadString(hResModule, IDS_K5ERR_PROFSUGGEST, + sugg, ARRAYLENGTH(sugg)); + + StringCbPrintf(msg, sizeof(msg), fmsg, config_file); + + khui_alert_create_empty(&alert); + khui_alert_set_severity(alert, (rv)?KHERR_ERROR:KHERR_WARNING); + khui_alert_set_title(alert, title); + khui_alert_set_message(alert, msg); + khui_alert_set_suggestion(alert, sugg); + + khui_alert_show(alert); + } + + d->flags = 0; +} + +/* actual dialog stuff */ + +#define IDX_NORMAL 1 +#define IDX_MODIFIED 2 +#define IDX_NEW 3 +#define IDX_DELETED 4 + +static k5_config_data k5_config_dlg_data; +static khm_boolean k5_dlg_data_valid = FALSE; + +INT_PTR CALLBACK +k5_config_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + HWND hw; + khm_size i; + k5_config_data * d; + + wchar_t * t; + wchar_t importopts[256]; + WKSTA_INFO_100 * winfo100; + +#ifdef DEBUG + assert(!k5_dlg_data_valid); +#endif + + k5_init_config_data(&k5_config_dlg_data); + k5_read_config_data(&k5_config_dlg_data); + + k5_dlg_data_valid = TRUE; + + d = &k5_config_dlg_data; + + d->node_main = (khui_config_node) lParam; + + CheckDlgButton(hwnd, IDC_CFG_INCREALMS, + (d->inc_realms)? BST_CHECKED: BST_UNCHECKED); + + hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM); +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for (i=0; i < d->n_realms; i++) { + SendMessage(hw, CB_ADDSTRING, 0, + (LPARAM) d->realms[i].realm); + } + + SendMessage(hw, CB_SELECTSTRING, -1, + (LPARAM) d->def_realm); + + SetDlgItemText(hwnd, IDC_CFG_CFGFILE, d->config_file); + + /* 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, d->lsa_import); + t = importopts; + SendMessage(hw, CB_GETLBTEXT, d->lsa_import,(LPARAM) t); + SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) t); + } + break; + + case WM_COMMAND: + { + k5_config_data * d; + + d = &k5_config_dlg_data; + + if (wParam == MAKEWPARAM(IDC_CFG_IMPORT, CBN_SELCHANGE)) { + int idx; + int modified = FALSE; + + idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_IMPORT, + CB_GETCURSEL, 0, 0); + if (idx != CB_ERR && idx != d->lsa_import) { + d->lsa_import = idx; + d->flags |= K5_CDFLAG_MOD_LSA_IMPORT; + modified = TRUE; + } + + khui_cfg_set_flags(d->node_main, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); + return TRUE; + } + + if (wParam == MAKEWPARAM(IDC_CFG_INCREALMS, BN_CLICKED)) { + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCREALMS) == + BST_CHECKED) { + d->inc_realms = TRUE; + } else { + d->inc_realms = FALSE; + } + d->flags |= K5_CDFLAG_MOD_INC_REALMS; + + khui_cfg_set_flags(d->node_main, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + return TRUE; + } + } + break; + + case KHUI_WM_CFG_NOTIFY: + { + k5_config_data * d; + + d = &k5_config_dlg_data; + + if (HIWORD(wParam) == WMCFG_APPLY) { + khm_int32 oflags; + + oflags = d->flags; + k5_write_config_data(d); + + if (d->flags != oflags) { + khui_cfg_set_flags(d->node_main, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | + KHUI_CNFLAG_MODIFIED); + } + return TRUE; + } + } + break; + + case WM_DESTROY: + { + k5_free_config_data(&k5_config_dlg_data); + k5_dlg_data_valid = FALSE; + } + break; + } + return FALSE; +} + +static HIMAGELIST +k5_get_state_image_list(void) { + HIMAGELIST hil; + HICON hicon; + + hil = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_COLOR | ILC_MASK, + 4, + 2); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_NORMAL), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_MODIFIED), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_NEW), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_DELETED), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + return hil; +} + +static void +k5_update_realms_display(HWND hw_list, k5_config_data * d) { + khm_size i; + LVITEM lvi; + wchar_t buf[64]; + + ListView_DeleteAllItems(hw_list); + + for (i=0; i < d->n_realms; i++) { + if ((d->realms[i].flags & K5_RDFLAG_DELETED) && + (d->realms[i].flags & K5_RDFLAG_NEW)) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = d->realms[i].realm; + lvi.lParam = i; + + if (d->realms[i].flags & K5_RDFLAG_DELETED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + } else if (d->realms[i].flags & K5_RDFLAG_NEW) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + } else if (d->realms[i].flags & K5_RDFLAG_MODIFED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + } + lvi.stateMask = LVIS_STATEIMAGEMASK; + + ListView_InsertItem(hw_list, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = buf; + lvi.lParam = (LPARAM) -1; + + LoadString(hResModule, IDS_CFG_RE_NEWREALM, + buf, ARRAYLENGTH(buf)); + + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + + ListView_InsertItem(hw_list, &lvi); + + if (d->flags & K5_CDFLAG_MOD_REALMS) { + khui_cfg_set_flags(d->node_realm, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + } else { + khui_cfg_set_flags(d->node_realm, 0, + KHUI_CNFLAG_MODIFIED); + } +} + +#define K5_KDCSI_ADMIN 1 +#define K5_KDCSI_MASTER 2 + +static void +k5_update_kdcs_display(HWND hw_kdc, k5_config_data * d, khm_size idx_rlm) { + khm_size k; + LVITEM lvi; + int idx_item; + k5_realm_kdc * pkdc; + wchar_t wyes[8]; + wchar_t wno[8]; + wchar_t wbuf[64]; + + ListView_DeleteAllItems(hw_kdc); + + if (d == NULL) + return; + +#ifdef DEBUG + assert(idx_rlm < d->n_realms); +#endif + LoadString(hResModule, IDS_YES, wyes, ARRAYLENGTH(wyes)); + LoadString(hResModule, IDS_NO, wno, ARRAYLENGTH(wno)); + + for (k=0; k < d->realms[idx_rlm].n_kdcs; k++) { + if ((d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_DELETED) && + (d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_NEW)) + continue; + + pkdc = &(d->realms[idx_rlm].kdcs[k]); + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = K5_MAX_KDC; + lvi.iSubItem = 0; + lvi.lParam = k; + lvi.pszText = pkdc->name; + if (pkdc->flags & K5_RKFLAG_DELETED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + } else if (pkdc->flags & K5_RKFLAG_NEW) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + } else if ((pkdc->flags & K5_RKFLAG_MOD_ADMIN) || + (pkdc->flags & K5_RKFLAG_MOD_MASTER)) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + } + lvi.stateMask = LVIS_STATEIMAGEMASK; + + idx_item = ListView_InsertItem(hw_kdc, &lvi); + + lvi.mask = LVIF_TEXT; + lvi.iItem = idx_item; + lvi.iSubItem = K5_KDCSI_ADMIN; + if (pkdc->admin) + lvi.pszText = wyes; + else + lvi.pszText = wno; + ListView_SetItem(hw_kdc, &lvi); + + lvi.iSubItem = K5_KDCSI_MASTER; + if (pkdc->master) + lvi.pszText = wyes; + else + lvi.pszText = wno; + ListView_SetItem(hw_kdc, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = wbuf; + lvi.lParam = (LPARAM) -1; + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + + LoadString(hResModule, IDS_CFG_RE_NEWSERVER, + wbuf, ARRAYLENGTH(wbuf)); + + ListView_InsertItem(hw_kdc, &lvi); +} + +static void +k5_update_dmap_display(HWND hw_dm, k5_config_data * d, khm_size idx_rlm) { + khm_size m; + LVITEM lvi; + k5_domain_map * map; + wchar_t wbuf[64]; + + ListView_DeleteAllItems(hw_dm); + + if (d == NULL) + return; + +#ifdef DEBUG + assert(idx_rlm < d->n_realms); +#endif + + for (m=0; m < d->realms[idx_rlm].n_domain_maps; m++) { + map = &(d->realms[idx_rlm].domain_maps[m]); + + if ((map->flags & K5_DMFLAG_NEW) && + (map->flags & K5_DMFLAG_DELETED)) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; + lvi.pszText = map->name; + if (map->flags & K5_DMFLAG_DELETED) + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + else if (map->flags & K5_DMFLAG_NEW) + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + else + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + lvi.stateMask = LVIS_STATEIMAGEMASK; + lvi.lParam = m; + + lvi.iItem = K5_MAX_DOMAIN_MAPPINGS; + lvi.iSubItem = 0; + + ListView_InsertItem(hw_dm, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; + lvi.pszText = wbuf; + lvi.lParam = (LPARAM) -1; + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + lvi.iItem = 0; + lvi.iSubItem = 0; + + LoadString(hResModule, IDS_CFG_RE_NEWDMAP, + wbuf, ARRAYLENGTH(wbuf)); + + ListView_InsertItem(hw_dm, &lvi); +} + +#define CMD_BASE 3000 +#define CMD_NEW_REALM (CMD_BASE + 1) +#define CMD_DEL_REALM (CMD_BASE + 2) +#define CMD_NEW_SERVER (CMD_BASE + 3) +#define CMD_DEL_SERVER (CMD_BASE + 4) +#define CMD_MAKE_ADMIN (CMD_BASE + 5) +#define CMD_MAKE_MASTER (CMD_BASE + 6) +#define CMD_NEW_DMAP (CMD_BASE + 7) +#define CMD_DEL_DMAP (CMD_BASE + 8) + +struct k5_menu_def { + UINT string; + UINT id; + UINT type; + UINT state; +}; + +struct k5_menu_def k5_menu_realms[] = { + {IDS_CFG_RE_MNR, CMD_NEW_REALM, MFT_STRING, 0}, + {IDS_CFG_RE_MDR, CMD_DEL_REALM, MFT_STRING, 0} +}; + +struct k5_menu_def k5_menu_kdc[] = { + {IDS_CFG_RE_MNK, CMD_NEW_SERVER, MFT_STRING, 0}, + {IDS_CFG_RE_MDK, CMD_DEL_SERVER, MFT_STRING, 0}, + {IDS_CFG_RE_MAK, CMD_MAKE_ADMIN, MFT_STRING, 0}, + {IDS_CFG_RE_MMK, CMD_MAKE_MASTER, MFT_STRING, 0} +}; + +struct k5_menu_def k5_menu_dmap[] = { + {IDS_CFG_RE_MND, CMD_NEW_DMAP, MFT_STRING, 0}, + {IDS_CFG_RE_MDD, CMD_DEL_DMAP, MFT_STRING, 0} +}; + +HMENU +k5_menu_from_def(struct k5_menu_def * def, khm_size n) { + HMENU menu; + MENUITEMINFO mii; + khm_size i; + khm_size cch; + wchar_t buf[1024]; + + menu = CreatePopupMenu(); + + for (i=0; i < n; i++) { + ZeroMemory(&mii, sizeof(mii)); + + mii.cbSize = sizeof(mii); + + if (def[i].type == MFT_STRING) { + LoadString(hResModule, def[i].string, + buf, ARRAYLENGTH(buf)); + StringCchLength(buf, ARRAYLENGTH(buf), &cch); + + mii.fMask = MIIM_STRING | MIIM_ID; + mii.fType = MFT_STRING; + + mii.fState = def[i].state; + mii.wID = def[i].id; + mii.cch = (UINT) cch; + mii.dwTypeData = buf; + + InsertMenuItem(menu, (UINT) i, TRUE, &mii); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } + + return menu; +} + +void +k5_delete_realms(HWND hwnd, k5_config_data * d) { + LVITEM lvi; + int idx; + HWND hw_rlm; + BOOL modified = FALSE; + khm_size r; + + hw_rlm = GetDlgItem(hwnd, IDC_CFG_REALMS); + + idx = -1; + while((idx = ListView_GetNextItem(hw_rlm, idx, + LVNI_SELECTED)) + != -1) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (lvi.lParam != -1 && + (r = lvi.lParam) < d->n_realms) { + d->realms[r].flags ^= K5_RDFLAG_DELETED; + modified = TRUE; + } + } + + if (modified) { + d->flags |= K5_CDFLAG_MOD_REALMS; + + k5_purge_config_data(d, TRUE, TRUE, TRUE); + k5_update_realms_display(hw_rlm, d); + k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); + k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); + } +} + +void +k5_delete_servers(HWND hwnd, k5_config_data * d) { + HWND hw_kdc; + LVITEM lvi; + khm_size r; + khm_size k; + int idx; + BOOL modified = FALSE; + + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); + r = d->c_realm; + + idx = -1; + while((idx = ListView_GetNextItem(hw_kdc, idx, + LVNI_SELECTED)) + != -1) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_kdc, &lvi); + + if (lvi.lParam != -1 && + (k = lvi.lParam) < d->n_realms) { + d->realms[r].kdcs[k].flags ^= K5_RKFLAG_DELETED; + modified = TRUE; + } + } + + if (modified) { + d->flags |= K5_CDFLAG_MOD_REALMS; + d->realms[r].flags |= K5_RDFLAG_MODIFED; + + k5_purge_config_data(d, TRUE, TRUE, TRUE); + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + k5_update_kdcs_display(hw_kdc, d, r); + } +} + +void +k5_delete_dmap(HWND hwnd, k5_config_data * d) { + HWND hw_dmp; + LVITEM lvi; + khm_size r; + khm_size m; + int idx; + BOOL modified = FALSE; + + hw_dmp = GetDlgItem(hwnd, IDC_CFG_DMAP); + r = d->c_realm; + + idx = -1; + while((idx = ListView_GetNextItem(hw_dmp, idx, + LVNI_SELECTED)) + != -1) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_dmp, &lvi); + + if (lvi.lParam != -1 && + (m = lvi.lParam) < d->n_realms) { + d->realms[r].domain_maps[m].flags ^= K5_DMFLAG_DELETED; + modified = TRUE; + } + } + + if (modified) { + d->flags |= K5_CDFLAG_MOD_REALMS; + k5_purge_config_data(d, FALSE, FALSE, TRUE); + + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->realms[r].flags |= K5_RDFLAG_MODIFED; + + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + } + + k5_update_dmap_display(hw_dmp, d, r); + } +} + +INT_PTR CALLBACK +k5_realms_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_config_data * d; + + d = &k5_config_dlg_data; + + switch(uMsg) { + case WM_INITDIALOG: + { + LVCOLUMN lvc; + HWND hw; + RECT r; + wchar_t buf[256]; + + assert(k5_dlg_data_valid); + + d->node_realm = (khui_config_node) lParam; + + /* set up columns for the Realms list */ + hw = GetDlgItem(hwnd, IDC_CFG_REALMS); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; /* shave a few pixels off the width */ + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left); + LoadString(hResModule, IDS_CFG_RE_REALMS, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + + k5_update_realms_display(hw, d); + + /* set up columns for the servers list */ + hw = GetDlgItem(hwnd, IDC_CFG_KDC); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left) * 2 / 4; + LoadString(hResModule, IDS_CFG_RE_HEAD_SVR, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + lvc.cx = (r.right - r.left) * 1 / 4; + LoadString(hResModule, IDS_CFG_RE_HEAD_ADMIN, + buf, ARRAYLENGTH(buf)); + ListView_InsertColumn(hw, 1, &lvc); + + LoadString(hResModule, IDS_CFG_RE_HEAD_MASTER, + buf, ARRAYLENGTH(buf)); + ListView_InsertColumn(hw, 2, &lvc); + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + + /* set up columns for the domain/host mapping list */ + hw = GetDlgItem(hwnd, IDC_CFG_DMAP); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left); + LoadString(hResModule, IDS_CFG_RE_HEAD_DOMAIN, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + + /* Now set up the context menus */ + d->hm_realms_ctx = k5_menu_from_def(k5_menu_realms, ARRAYLENGTH(k5_menu_realms)); + d->hm_kdc_ctx = k5_menu_from_def(k5_menu_kdc, ARRAYLENGTH(k5_menu_kdc)); + d->hm_dmap_ctx = k5_menu_from_def(k5_menu_dmap, ARRAYLENGTH(k5_menu_dmap)); + } + break; + + case WM_CONTEXTMENU: + { + UINT id; + HMENU hm = NULL; + int x,y; + + id = GetDlgCtrlID((HWND) wParam); + + if (id == IDC_CFG_REALMS) { + HWND hw_realms; + int n; + MENUITEMINFO mii; + + hm = d->hm_realms_ctx; + + hw_realms = GetDlgItem(hwnd, IDC_CFG_REALMS); +#ifdef DEBUG + assert(hw_realms); +#endif + n = ListView_GetSelectedCount(hw_realms); + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + + if (n == 0) { + mii.fMask = MIIM_STATE; + mii.fState = MFS_DISABLED; + + SetMenuItemInfo(hm, CMD_DEL_REALM, FALSE, &mii); + } else { + + mii.fMask = MIIM_STATE; + mii.fState = MFS_ENABLED; + + SetMenuItemInfo(hm, CMD_DEL_REALM, FALSE, &mii); + } + + } else if (id == IDC_CFG_KDC) { + HWND hw_kdc; + int n; + MENUITEMINFO mii; + + hm = d->hm_kdc_ctx; + + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); +#ifdef DEBUG + assert(hw_kdc); +#endif + n = ListView_GetSelectedCount(hw_kdc); + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + + if (n == 1) { + mii.fMask = MIIM_STATE; + mii.fState = MFS_ENABLED; + + SetMenuItemInfo(hm, CMD_DEL_SERVER, FALSE, &mii); + SetMenuItemInfo(hm, CMD_MAKE_ADMIN, FALSE, &mii); + SetMenuItemInfo(hm, CMD_MAKE_MASTER, FALSE, &mii); + } else if (n == 0) { + + mii.fMask = MIIM_STATE; + mii.fState = MFS_DISABLED; + + SetMenuItemInfo(hm, CMD_DEL_SERVER, FALSE, &mii); + SetMenuItemInfo(hm, CMD_MAKE_ADMIN, FALSE, &mii); + SetMenuItemInfo(hm, CMD_MAKE_MASTER,FALSE, &mii); + } else { + + mii.fMask = MIIM_STATE; + mii.fState = MFS_ENABLED; + + SetMenuItemInfo(hm, CMD_DEL_SERVER, FALSE, &mii); + + mii.fState = MFS_DISABLED; + + SetMenuItemInfo(hm, CMD_MAKE_ADMIN, FALSE, &mii); + SetMenuItemInfo(hm, CMD_MAKE_MASTER,FALSE, &mii); + } + + } else if (id == IDC_CFG_DMAP) { + HWND hw_dmap; + MENUITEMINFO mii; + int n; + + hm = d->hm_dmap_ctx; + + hw_dmap = GetDlgItem(hwnd, IDC_CFG_DMAP); +#ifdef DEBUG + assert(hw_dmap); +#endif + + n = ListView_GetSelectedCount(hw_dmap); + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + + if (n == 0) { + mii.fMask = MIIM_STATE; + mii.fState = MFS_DISABLED; + + SetMenuItemInfo(hm, CMD_DEL_DMAP, FALSE, &mii); + } else { + mii.fMask = MIIM_STATE; + mii.fState = MFS_ENABLED; + + SetMenuItemInfo(hm, CMD_DEL_DMAP, FALSE, &mii); + } + } + + if (hm) { + if (LOWORD(lParam) == 0xffff) { + HWND hw; + RECT r; + + hw = GetDlgItem(hwnd, id); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + x = r.left; + y = r.top; + } else { + x = LOWORD(lParam); + y = HIWORD(lParam); + } + + TrackPopupMenu(hm, + TPM_LEFTALIGN | TPM_TOPALIGN, + x, y, + 0, hwnd, NULL); + } + + return TRUE; + } + break; + + case WM_NOTIFY: + { + LPNMHDR pnmh; + HWND hw_rlm = NULL; + HWND hw_kdc = NULL; + HWND hw_dmp = NULL; + int i; + + pnmh = (LPNMHDR) lParam; + + /* catchalls for all three list views */ + switch (pnmh->code) { + case NM_DBLCLK: + { + HWND hw_ctl; + LVITEM lvi; + LVHITTESTINFO hti; + LPNMITEMACTIVATE pnmi; + + if (pnmh->idFrom != IDC_CFG_REALMS && + pnmh->idFrom != IDC_CFG_KDC && + pnmh->idFrom != IDC_CFG_DMAP) + break; + + /* if the user double clicks on the 'new + [something]' item, we start editing it. */ + hw_ctl = pnmh->hwndFrom; + pnmi = (LPNMITEMACTIVATE) lParam; + + ZeroMemory(&hti, sizeof(hti)); + hti.pt = pnmi->ptAction; + + ListView_SubItemHitTest(hw_ctl, &hti); + if (hti.flags & LVHT_ONITEM) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM; + lvi.iItem = hti.iItem; + + ListView_GetItem(hw_ctl, &lvi); + + if (lvi.lParam == -1) + ListView_EditLabel(hw_ctl, hti.iItem); + } + + return TRUE; + } + break; + } + + if (pnmh->idFrom == IDC_CFG_REALMS) { + + hw_rlm = pnmh->hwndFrom; + + switch(pnmh->code) { + case LVN_ITEMCHANGED: + i = ListView_GetSelectedCount(hw_rlm); + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); + hw_dmp = GetDlgItem(hwnd, IDC_CFG_DMAP); + + d->c_realm = (khm_size) -1; + + if (i == 1) { + LVITEM lvi; + wchar_t fmt[256]; + wchar_t buf[K5_MAXCCH_REALM + 256]; + + i = ListView_GetNextItem(hw_rlm, -1, + LVNI_SELECTED); + if (i == -1) + goto _no_selection; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (lvi.lParam == -1) + goto _no_selection; + + d->c_realm = lvi.lParam; + + k5_update_kdcs_display(hw_kdc, d, lvi.lParam); + k5_update_dmap_display(hw_dmp, d, lvi.lParam); + + LoadString(hResModule, IDS_CFG_RE_KDCS_R, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + d->realms[d->c_realm].realm); + + SetDlgItemText(hwnd, IDC_CFG_SERVERSGRP, buf); + + LoadString(hResModule, IDS_CFG_RE_DMAPS_R, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + d->realms[d->c_realm].realm); + + SetDlgItemText(hwnd, IDC_CFG_DOMAINGRP, buf); + return TRUE; + } + + _no_selection: + { + wchar_t buf[256]; + + k5_update_kdcs_display(hw_kdc, NULL, 0); + k5_update_dmap_display(hw_dmp, NULL, 0); + + LoadString(hResModule, IDS_CFG_RE_KDCS, + buf, ARRAYLENGTH(buf)); + SetDlgItemText(hwnd, IDC_CFG_SERVERSGRP, buf); + + LoadString(hResModule, IDS_CFG_RE_DMAPS, + buf, ARRAYLENGTH(buf)); + SetDlgItemText(hwnd, IDC_CFG_DOMAINGRP, buf); + } + break; + + case LVN_BEGINLABELEDIT: + { + NMLVDISPINFO * pdisp; + LVITEM lvi; + + pdisp = (NMLVDISPINFO *) lParam; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = pdisp->item.iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (pdisp->item.iItem == -1 || + lvi.lParam != -1) { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + } else { + /* allow editing */ + HWND hw_edit; + + hw_edit = ListView_GetEditControl(hw_rlm); + if (hw_edit != NULL) { + SendMessage(hw_edit, + EM_SETLIMITTEXT, + K5_MAXCCH_REALM - 1, + 0); + } + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + } + + return TRUE; + } + break; + + case LVN_ENDLABELEDIT: + { + NMLVDISPINFO * pdisp; + khm_size n; + + pdisp = (NMLVDISPINFO *) lParam; + + if (pdisp->item.pszText && pdisp->item.pszText[0]) { + khm_size i; + + /* first find out whether this is actually + a new realm */ + + for (i=0; i < d->n_realms; i++) { + if ((d->realms[i].flags & K5_RDFLAG_NEW) && + (d->realms[i].flags & K5_RDFLAG_DELETED)) + continue; + + if (!wcsicmp(d->realms[i].realm, pdisp->item.pszText)) + break; + } + + if (i < d->n_realms) { + khui_alert * alert = NULL; + wchar_t buf[KHUI_MAXCCH_MESSAGE]; + wchar_t fmt[KHUI_MAXCCH_MESSAGE]; + + khui_alert_create_empty(&alert); + + LoadString(hResModule, IDS_CFG_RE_ARNUT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText); + khui_alert_set_title(alert, buf); + + LoadString(hResModule, IDS_CFG_RE_ARNUM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText); + khui_alert_set_message(alert, buf); + + khui_alert_add_command(alert, KHUI_PACTION_CLOSE); + khui_alert_set_severity(alert, KHERR_INFO); + + khui_alert_show_modal(alert); + khui_alert_release(alert); + + return TRUE; + } + + n = d->n_realms; + k5_assert_n_realms(d, n+1); + StringCbCopy(d->realms[n].realm, + sizeof(d->realms[n].realm), + pdisp->item.pszText); + d->realms[n].flags = K5_RDFLAG_NEW; + d->n_realms++; + + d->flags |= K5_CDFLAG_MOD_REALMS; + + k5_update_realms_display(hw_rlm, d); + } + + return TRUE; + } + break; + + case LVN_KEYDOWN: + { + NMLVKEYDOWN * pnmk; + + pnmk = (NMLVKEYDOWN *) lParam; + + if (pnmk->wVKey == VK_DELETE) { + k5_delete_realms(hwnd, d); + return TRUE; + } + } + break; + } + } else if (pnmh->idFrom == IDC_CFG_KDC) { + hw_kdc = pnmh->hwndFrom; + + switch (pnmh->code) { + case LVN_BEGINLABELEDIT: + { + NMLVDISPINFO * pdisp; + LVITEM lvi; + + pdisp = (NMLVDISPINFO *) lParam; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = pdisp->item.iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_kdc, &lvi); + + /* Only allow editing if the user is trying to + edit the entry. */ + if (pdisp->item.iItem == -1 || + lvi.lParam != -1) { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + } else { + HWND hw_edit; + + hw_edit = ListView_GetEditControl(hw_kdc); + if (hw_edit != NULL) { + SendMessage(hw_edit, + EM_SETLIMITTEXT, + K5_MAXCCH_HOST - 1, + 0); + } + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + } + return TRUE; + } + break; + + case LVN_ENDLABELEDIT: + { + NMLVDISPINFO * pdisp; + khm_size r; + khm_size k; + + r = d->c_realm; + + pdisp = (NMLVDISPINFO *) lParam; + + if (pdisp->item.pszText && pdisp->item.pszText[0]) { + + /* first of all, check if we already have + a KDC by this name... */ + for (k=0; k < d->realms[r].n_kdcs; k++) { + if ((d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) + continue; + + if (!wcsicmp(d->realms[r].kdcs[k].name, + pdisp->item.pszText)) + break; + } + + if (k < d->realms[r].n_kdcs) { + khui_alert * alert = NULL; + wchar_t buf[K5_MAXCCH_HOST + 256]; + wchar_t fmt[256]; + + khui_alert_create_empty(&alert); + + LoadString(hResModule, IDS_CFG_RE_ASNUT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText, + d->realms[r].realm); + khui_alert_set_title(alert, buf); + + LoadString(hResModule, IDS_CFG_RE_ASNUM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText, + d->realms[r].realm); + khui_alert_set_message(alert, buf); + + khui_alert_set_severity(alert, KHERR_INFO); + khui_alert_show_modal(alert); + + khui_alert_release(alert); + + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + return TRUE; + } + + if (k >= K5_MAX_KDC) { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + /* TODO: show a message box saying + there are too many KDC's + already. */ + return TRUE; + } + + StringCbCopy(d->realms[r].kdcs[k].name, + sizeof(d->realms[0].kdcs[0].name), + pdisp->item.pszText); + d->realms[r].kdcs[k].flags = K5_RKFLAG_NEW; + d->realms[r].n_kdcs++; + + k5_update_kdcs_display(hw_kdc, d, d->c_realm); + + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->flags |= K5_CDFLAG_MOD_REALMS; + d->realms[r].flags |= K5_RDFLAG_MODIFED; + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + } + } + return TRUE; + } + break; + + case LVN_KEYDOWN: + { + NMLVKEYDOWN * pnmk; + + pnmk = (NMLVKEYDOWN *) lParam; + + if (pnmk->wVKey == VK_DELETE) { + k5_delete_servers(hwnd, d); + } + return TRUE; + } + break; + + case NM_CLICK: + { + LPNMITEMACTIVATE lpnmi; + LVHITTESTINFO hti; + LVITEM lvi; + khm_size r; + khm_size k; + + r = d->c_realm; + + lpnmi = (LPNMITEMACTIVATE) lParam; + + ZeroMemory(&hti, sizeof(hti)); + hti.pt = lpnmi->ptAction; + ListView_SubItemHitTest(hw_kdc, &hti); + + if (hti.iSubItem != 0) { + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM; + lvi.iItem = hti.iItem; + ListView_GetItem(hw_kdc, &lvi); + + if (lvi.lParam < 0 || lvi.lParam >= (int) d->realms[r].n_kdcs) + return TRUE; + + k = lvi.lParam; + + if (hti.iSubItem == K5_KDCSI_ADMIN) { + d->realms[r].kdcs[k].admin = !d->realms[r].kdcs[k].admin; + d->realms[r].kdcs[k].flags |= K5_RKFLAG_MOD_ADMIN; + } else if (hti.iSubItem == K5_KDCSI_MASTER) { + if (d->realms[r].kdcs[k].master) { + d->realms[r].kdcs[k].master = FALSE; + d->realms[r].kdcs[k].flags |= K5_RKFLAG_MOD_MASTER; + } else { + khm_size i; + + for (i=0; i < d->realms[r].n_kdcs; i++) { + if ((d->realms[r].kdcs[i].flags & K5_RKFLAG_DELETED) && + (d->realms[r].kdcs[i].flags & K5_RKFLAG_NEW)) + continue; + if (d->realms[r].kdcs[i].master) { + d->realms[r].kdcs[i].master = FALSE; + d->realms[r].kdcs[i].flags |= K5_RKFLAG_MOD_MASTER; + } + } + + d->realms[r].kdcs[k].master = TRUE; + d->realms[r].kdcs[k].flags |= K5_RKFLAG_MOD_MASTER; + } + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->realms[r].flags |= K5_RDFLAG_MODIFED; + d->flags |= K5_CDFLAG_MOD_REALMS; + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + } + + k5_update_kdcs_display(hw_kdc, d, r); + } + } + break; + } + } else if (pnmh->idFrom == IDC_CFG_DMAP) { + hw_dmp = pnmh->hwndFrom; + + switch (pnmh->code) { + case LVN_BEGINLABELEDIT: + { + NMLVDISPINFO * pdisp; + LVITEM lvi; + + pdisp = (NMLVDISPINFO *) lParam; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = pdisp->item.iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_dmp, &lvi); + + /* Only allow editing if the user is trying to + edit the entry. */ + if (pdisp->item.iItem == -1 || + lvi.lParam != -1) { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + } else { + HWND hw_edit; + + hw_edit = ListView_GetEditControl(hw_dmp); + if (hw_edit != NULL) { + SendMessage(hw_edit, + EM_SETLIMITTEXT, + K5_MAXCCH_HOST - 1, + 0); + } + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + } + return TRUE; + } + break; + + case LVN_ENDLABELEDIT: + { + NMLVDISPINFO * pdisp; + khm_size r; + khm_size m; + + r = d->c_realm; + + pdisp = (NMLVDISPINFO *) lParam; + + if (pdisp->item.pszText && pdisp->item.pszText[0]) { + + /* first check if this is unique */ + for (m=0; m < d->realms[r].n_domain_maps; m++) { + if ((d->realms[r].domain_maps[m].flags & K5_DMFLAG_NEW) && + (d->realms[r].domain_maps[m].flags & K5_DMFLAG_DELETED)) + continue; + + if (!wcsicmp(d->realms[r].domain_maps[m].name, + pdisp->item.pszText)) + break; + } + + if (m < d->realms[r].n_domain_maps) { + khui_alert * alert; + wchar_t buf[K5_MAXCCH_HOST + 256]; + wchar_t fmt[256]; + + khui_alert_create_empty(&alert); + + LoadString(hResModule, IDS_CFG_RE_DMNUT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText, + d->realms[r].realm); + khui_alert_set_title(alert, buf); + + LoadString(hResModule, IDS_CFG_RE_DMNUM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + pdisp->item.pszText, + d->realms[r].realm); + khui_alert_set_message(alert, buf); + + khui_alert_set_severity(alert, KHERR_INFO); + khui_alert_show_modal(alert); + + khui_alert_release(alert); + + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + return TRUE; + } + + if (m >= K5_MAX_DOMAIN_MAPPINGS) { + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, FALSE); + /* TODO: show a message box saying + there are too many domain mappings + already. */ + return TRUE; + } + + StringCbCopy(d->realms[r].domain_maps[m].name, + sizeof(d->realms[0].domain_maps[0].name), + pdisp->item.pszText); + d->realms[r].domain_maps[m].flags = K5_DMFLAG_NEW; + d->realms[r].n_domain_maps++; + + k5_update_dmap_display(hw_dmp, d, d->c_realm); + + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->flags |= K5_CDFLAG_MOD_REALMS; + d->realms[r].flags |= K5_RDFLAG_MODIFED; + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + } + } + return TRUE; + } + break; + + case LVN_KEYDOWN: + { + NMLVKEYDOWN * pnmk; + + pnmk = (NMLVKEYDOWN *) lParam; + + if (pnmk->wVKey == VK_DELETE) { + k5_delete_dmap(hwnd, d); + return TRUE; + } + } + break; + } + } /* end of handling DMAP notifications */ + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case CMD_NEW_REALM: + { + ListView_EditLabel(GetDlgItem(hwnd, IDC_CFG_REALMS), 0); + + return TRUE; + } + break; + + case CMD_DEL_REALM: + { + k5_delete_realms(hwnd, d); + + return TRUE; + } + break; + + case CMD_NEW_SERVER: + { + ListView_EditLabel(GetDlgItem(hwnd, IDC_CFG_KDC), 0); + + return TRUE; + } + break; + + case CMD_DEL_SERVER: + { + k5_delete_servers(hwnd, d); + + return TRUE; + } + break; + + case CMD_MAKE_ADMIN: + { + HWND hw_kdc; + int idx; + khm_size r; + khm_size k; + BOOL modified = FALSE; + + r = d->c_realm; + + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); + + if (ListView_GetSelectedCount(hw_kdc) != 1) + return TRUE; + + idx = -1; + while ((idx = ListView_GetNextItem(hw_kdc, idx, + LVNI_SELECTED)) != -1) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM; + lvi.iItem = idx; + ListView_GetItem(hw_kdc, &lvi); + + k = lvi.lParam; + + if (lvi.lParam >= 0 && lvi.lParam < (int) d->realms[r].n_kdcs) { + d->realms[r].kdcs[k].admin = !d->realms[r].kdcs[k].admin; + d->realms[r].kdcs[k].flags |= K5_RKFLAG_MOD_ADMIN; + modified = TRUE; + + break; + } + } + + if (modified) { + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->flags |= K5_CDFLAG_MOD_REALMS; + d->realms[r].flags |= K5_RDFLAG_MODIFED; + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + } + } + + k5_update_kdcs_display(hw_kdc, d, r); + + return TRUE; + } + break; + + case CMD_MAKE_MASTER: + { + HWND hw_kdc; + int idx; + khm_size r; + khm_size k; + BOOL modified = FALSE; + + r = d->c_realm; + + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); + + if (ListView_GetSelectedCount(hw_kdc) != 1) + return TRUE; + + idx = -1; + while ((idx = ListView_GetNextItem(hw_kdc, idx, + LVNI_SELECTED)) != -1) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM; + lvi.iItem = idx; + ListView_GetItem(hw_kdc, &lvi); + + k = lvi.lParam; + + if (lvi.lParam >= 0 && lvi.lParam < (int) d->realms[r].n_kdcs) { + if (d->realms[r].kdcs[k].master) { + d->realms[r].kdcs[k].master = FALSE; + } else { + khm_size i; + + for (i=0; i < d->realms[r].n_kdcs; i++) { + if ((d->realms[r].kdcs[i].flags & K5_RKFLAG_NEW) && + (d->realms[r].kdcs[i].flags & K5_RKFLAG_DELETED)) + continue; + + if (d->realms[r].kdcs[i].master) { + d->realms[r].kdcs[i].master = FALSE; + d->realms[r].kdcs[i].flags |= K5_RKFLAG_MOD_MASTER; + } + } + + d->realms[r].kdcs[k].master = TRUE; + } + d->realms[r].kdcs[k].flags |= K5_RKFLAG_MOD_MASTER; + modified = TRUE; + + break; + } + } + + if (modified) { + if (!(d->realms[r].flags & K5_RDFLAG_MODIFED)) { + d->flags |= K5_CDFLAG_MOD_REALMS; + d->realms[r].flags |= K5_RDFLAG_MODIFED; + k5_update_realms_display(hwnd, d); + } + } + + k5_update_kdcs_display(hw_kdc, d, r); + + return TRUE; + } + break; + + case CMD_NEW_DMAP: + { + ListView_EditLabel(GetDlgItem(hwnd, IDC_CFG_DMAP), 0); + + return TRUE; + } + break; + + case CMD_DEL_DMAP: + { + k5_delete_dmap(hwnd, d); + + return TRUE; + } + break; + } + break; + + case WM_DESTROY: + if (d->hm_realms_ctx) + DestroyMenu(d->hm_realms_ctx); + if (d->hm_kdc_ctx) + DestroyMenu(d->hm_kdc_ctx); + if (d->hm_dmap_ctx) + DestroyMenu(d->hm_dmap_ctx); + + d->hm_realms_ctx = NULL; + d->hm_kdc_ctx = NULL; + d->hm_dmap_ctx = NULL; + break; + + case KHUI_WM_CFG_NOTIFY: + /* the realms dialog receives this notification after the top + level krb5 configuration panel has received it. Therefore, + we assume that any changes have already been applied. When + applying changes, we switch the mod bits off to indicate + that the changes have been written. We just have to + repaint the screen at this point. */ + if (HIWORD(wParam) == WMCFG_APPLY) { + k5_purge_config_data(d, TRUE, TRUE, TRUE); + k5_update_realms_display(GetDlgItem(hwnd, IDC_CFG_REALMS), d); + if (d->c_realm != -1) { + k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), d, d->c_realm); + k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), d, d->c_realm); + } else { + k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); + k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); + } + } + 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, ®); + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CCC_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CCC_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosCCaches"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_CACHES); + reg.dlg_proc = k5_ccconfig_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; + khui_config_node node_ccaches; + + 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); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosCCaches", + &node_ccaches))) { + khui_cfg_remove(node_ccaches); + khui_cfg_release(node_ccaches); + } +#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/krb5configid.c b/src/windows/identity/plugins/krb5/krb5configid.c index a4e549d3d..ccc38941a 100644 --- a/src/windows/identity/plugins/krb5/krb5configid.c +++ b/src/windows/identity/plugins/krb5/krb5configid.c @@ -45,6 +45,13 @@ typedef struct tag_k5_id_dlg_data { wchar_t ccache[KRB5_MAXCCH_CCNAME]; + khm_boolean renewable; + khm_boolean forwardable; + khm_boolean proxiable; + khm_boolean addressless; + + DWORD public_ip; + time_t life; time_t renew_life; } k5_id_dlg_data; @@ -94,6 +101,36 @@ k5_id_read_params(k5_id_dlg_data * d) { else d->renew_life = 604800; + rv = khc_read_int32(csp_ident, L"Renewable", &t); + if (KHM_SUCCEEDED(rv)) + d->renewable = !!t; + else + d->renewable = TRUE; + + rv = khc_read_int32(csp_ident, L"Forwardable", &t); + if (KHM_SUCCEEDED(rv)) + d->forwardable = !!t; + else + d->forwardable = FALSE; + + rv = khc_read_int32(csp_ident, L"Proxiable", &t); + if (KHM_SUCCEEDED(rv)) + d->proxiable = !!t; + else + d->proxiable = FALSE; + + rv = khc_read_int32(csp_ident, L"Addressless", &t); + if (KHM_SUCCEEDED(rv)) + d->addressless = !!t; + else + d->addressless = TRUE; + + rv = khc_read_int32(csp_ident, L"PublicIP", &t); + if (KHM_SUCCEEDED(rv)) + d->public_ip = (khm_ui_4) t; + else + d->public_ip = 0; + cb = sizeof(d->ccache); rv = khc_read_string(csp_ident, L"DefaultCCName", d->ccache, &cb); if (KHM_FAILED(rv) || cb <= sizeof(wchar_t)) { @@ -120,13 +157,30 @@ k5_id_read_params(k5_id_dlg_data * d) { static khm_boolean k5_id_is_mod(HWND hw, k5_id_dlg_data * d) { wchar_t ccache[KRB5_MAXCCH_CCNAME]; + DWORD dwaddress = 0; GetDlgItemText(hw, IDC_CFG_CCACHE, ccache, ARRAYLENGTH(ccache)); + SendDlgItemMessage(hw, IDC_CFG_PUBLICIP, IPM_GETADDRESS, + 0, (LPARAM) &dwaddress); + if (wcsicmp(ccache, d->ccache) || + d->tc_renew.current != d->renew_life || - d->tc_life.current != d->life) + + d->tc_life.current != d->life || + + (IsDlgButtonChecked(hw, IDC_CFG_RENEW) == BST_CHECKED) != d->renewable || + + (IsDlgButtonChecked(hw, IDC_CFG_FORWARD) == BST_CHECKED) != d->forwardable || + + (IsDlgButtonChecked(hw, IDC_CFG_ADDRESSLESS) == BST_CHECKED) + != d->addressless || + + dwaddress != d->public_ip) + return TRUE; + return FALSE; } @@ -147,6 +201,8 @@ k5_id_write_params(HWND hw, k5_id_dlg_data * d) { wchar_t ccache[KRB5_MAXCCH_CCNAME]; khm_size cb; khm_int32 rv; + khm_boolean b; + DWORD dwaddress = 0; if (!k5_id_is_mod(hw, d)) return; @@ -174,6 +230,32 @@ k5_id_write_params(HWND hw, k5_id_dlg_data * d) { khc_write_int32(csp_ident, L"DefaultRenewLifetime", (khm_int32) d->renew_life); } + b = (IsDlgButtonChecked(hw, IDC_CFG_RENEW) == BST_CHECKED); + if (b != d->renewable) { + d->renewable = b; + khc_write_int32(csp_ident, L"Renewable", (khm_int32) b); + } + + b = (IsDlgButtonChecked(hw, IDC_CFG_FORWARD) == BST_CHECKED); + if (b != d->forwardable) { + d->forwardable = b; + khc_write_int32(csp_ident, L"Forwardable", (khm_int32) b); + } + + b = (IsDlgButtonChecked(hw, IDC_CFG_ADDRESSLESS) == BST_CHECKED); + if (b != d->addressless) { + d->addressless = b; + khc_write_int32(csp_ident, L"Addressless", (khm_int32) b); + } + + SendDlgItemMessage(hw, IDC_CFG_PUBLICIP, IPM_GETADDRESS, + 0, (LPARAM) &dwaddress); + + if (dwaddress != d->public_ip) { + d->public_ip = dwaddress; + khc_write_int32(csp_ident, L"PublicIP", (khm_int32) dwaddress); + } + GetDlgItemText(hw, IDC_CFG_CCACHE, ccache, ARRAYLENGTH(ccache)); if (SUCCEEDED(StringCbLength(ccache, sizeof(ccache), &cb)) && @@ -225,6 +307,19 @@ k5_id_tab_dlgproc(HWND hwnd, khui_tracker_refresh(&d->tc_renew); SetDlgItemText(hwnd, IDC_CFG_CCACHE, d->ccache); + + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (d->renewable? BST_CHECKED: BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_CFG_FORWARD, + (d->forwardable? BST_CHECKED: BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_CFG_ADDRESSLESS, + (d->addressless? BST_CHECKED: BST_UNCHECKED)); + + SendDlgItemMessage(hwnd, IDC_CFG_PUBLICIP, + IPM_SETADDRESS, + 0, (LPARAM) d->public_ip); break; case WM_COMMAND: diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c index 5c076951a..af2d997c8 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.c +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -203,6 +203,8 @@ int com_addr(void) #define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 #endif +#define MAX_ADDRS 256 + static long get_tickets_from_cache(krb5_context ctx, krb5_ccache cache) { @@ -223,7 +225,6 @@ static long get_tickets_from_cache(krb5_context ctx, FILETIME ft, eft; khm_int32 ti; - #ifdef KRB5_TC_NOTICKET flags = KRB5_TC_NOTICKET; #else @@ -442,30 +443,33 @@ static long get_tickets_from_cache(krb5_context ctx, 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 = PCALLOC(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*) PCALLOC(1, strlen(Buffer)+1); - if (!list->addrList[n]) - { - MessageBox(NULL, "Memory Error", "Error", MB_OK); - return ENOMEM; - } - strcpy(list->addrList[n], Buffer); - } + khm_int32 buffer[1024]; + void * bufp; + khm_size cb; + khm_int32 rv; + + bufp = (void *) buffer; + cb = sizeof(buffer); + + rv = serialize_krb5_addresses(KRBv5Credentials.addresses, + bufp, + &cb); + if (rv == KHM_ERROR_TOO_LONG) { + bufp = PMALLOC(cb); + rv = serialize_krb5_addresses(KRBv5Credentials.addresses, + bufp, + &cb); + } + + if (KHM_SUCCEEDED(rv)) { + kcdb_cred_set_attr(cred, attr_id_addr_list, + bufp, cb); + } + + if (bufp != (void *) buffer) + PFREE(bufp); } -#endif if(cred_flags & KCDB_CRED_FLAG_INITIAL) { FILETIME ft_issue_new; @@ -597,10 +601,16 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) ctx = (*krbv5Context); for(i=0; pNCi[i]; i++) { + char ccname[KRB5_MAXCCH_CCNAME]; + if (pNCi[i]->vers != CC_CRED_V5) continue; - code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + if (FAILED(StringCchPrintfA(ccname, sizeof(ccname), "API:%s", + pNCi[i]->name))) + continue; + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); if (code) continue; @@ -668,7 +678,49 @@ _exit: } int -khm_krb5_renew(khm_handle identity) +khm_krb5_renew_cred(khm_handle cred) +{ + khm_handle identity = NULL; + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + + if (cred == NULL) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _cleanup; + } + + if (KHM_FAILED(kcdb_cred_get_identity(cred, &identity))) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _cleanup; + } + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto _cleanup; + + /* TODO: going here */ + + _cleanup: + + if (identity) + kcdb_identity_release(identity); + + if (cc && ctx) + pkrb5_cc_close(ctx, cc); + + if (ctx) + pkrb5_free_context(ctx); + + return code; +} + +int +khm_krb5_renew_ident(khm_handle identity) { krb5_error_code code = 0; krb5_context ctx = 0; @@ -771,24 +823,67 @@ khm_krb5_kinit(krb5_context alt_ctx, if (!pkrb5_init_context) return 0; + _reportf(L"In khm_krb5_kinit"); + pkrb5_get_init_creds_opt_init(&options); memset(&my_creds, 0, sizeof(my_creds)); - if (alt_ctx) - { + if (alt_ctx) { ctx = alt_ctx; - } - else - { + } else { code = pkrb5_init_context(&ctx); - if (code) goto cleanup; + if (code) + goto cleanup; } -// code = pkrb5_cc_default(ctx, &cc); - if (ccache) + if (ccache) { + _reportf(L"Using supplied ccache name %S", ccache); code = pkrb5_cc_resolve(ctx, ccache, &cc); - else - code = pkrb5_cc_resolve(ctx, principal_name, &cc); + } else { + khm_handle identity = NULL; + khm_handle csp_ident = NULL; + khm_handle csp_k5 = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wccname[MAX_PATH]; + char ccname[MAX_PATH]; + char * pccname = principal_name; + khm_size cb; + + idname[0] = L'\0'; + AnsiStrToUnicode(idname, sizeof(idname), principal_name); + + cb = sizeof(wccname); + + if (KHM_SUCCEEDED(kcdb_identity_create(idname, 0, &identity)) && + + KHM_SUCCEEDED(kcdb_identity_get_config(identity, 0, &csp_ident)) && + + KHM_SUCCEEDED(khc_open_space(csp_ident, CSNAME_KRB5CRED, 0, + &csp_k5)) && + + KHM_SUCCEEDED(khc_read_string(csp_k5, L"DefaultCCName", + wccname, &cb)) && + + cb > sizeof(wchar_t)) { + + _reportf(L"Using DefaultCCName [%s] from identity", wccname); + + UnicodeStrToAnsi(ccname, sizeof(ccname), wccname); + pccname = ccname; + } + + if (csp_k5) + khc_close_space(csp_k5); + if (csp_ident) + khc_close_space(csp_ident); + if (identity) + kcdb_identity_release(identity); + + code = pkrb5_cc_resolve(ctx, pccname, &cc); + } + + _reportf(L"krb5_cc_resolve returns code %d", code); + if (code) goto cleanup; code = pkrb5_parse_name(ctx, principal_name, &me); @@ -803,55 +898,57 @@ khm_krb5_kinit(krb5_context alt_ctx, 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 **) PMALLOC((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 *)PMALLOC(sizeof(krb5_address)); - if (addrs[i] == NULL) { - pkrb5_free_addresses(ctx, local_addrs); - assert(0); - } + krb5_address ** local_addrs=NULL; + DWORD netIPAddr; + + pkrb5_os_localaddr(ctx, &local_addrs); + i = 0; + while ( local_addrs[i++] ); + addr_count = i + 1; + + addrs = (krb5_address **) PMALLOC((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 *)PMALLOC(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 *)PMALLOC(addrs[i]->length); - if (!addrs[i]->contents) { - 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 *)PMALLOC(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); + memcpy(addrs[i]->contents,local_addrs[i]->contents, + local_addrs[i]->length); /* safe */ + i++; + } + pkrb5_free_addresses(ctx, local_addrs); + if (publicIP) { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system addrs[i] = (krb5_address *)PMALLOC(sizeof(krb5_address)); if (addrs[i] == NULL) assert(0); @@ -865,27 +962,31 @@ khm_krb5_kinit(krb5_context alt_ctx, netIPAddr = htonl(publicIP); memcpy(addrs[i]->contents,&netIPAddr,4); - - pkrb5_get_init_creds_opt_set_address_list(&options,addrs); - } + + 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); + 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); + _reportf(L"krb5_get_init_creds_password returns code %d", code); + if (code) goto cleanup; code = pkrb5_cc_initialize(ctx, cc, me); + _reportf(L"krb5_cc_initialize returns code %d", code); if (code) goto cleanup; code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + _reportf(L"krb5_cc_store_cred returns code %d", code); if (code) goto cleanup; cleanup: @@ -1157,7 +1258,8 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) kcdb_credset_get_size(d_cs, &s); if (s == 0) { - /* nothing to do */ + _reportf(L"No tickets to delete"); + kcdb_credset_delete(d_cs); return 0; } @@ -1215,6 +1317,8 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) char a_ccname[KRB5_MAXCCH_CCNAME]; krb5_ccache cc = NULL; + _reportf(L"Destroying ccache [%s]", ccname); + UnicodeStrToAnsi(a_ccname, sizeof(a_ccname), ccname); @@ -1228,7 +1332,7 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) code = pkrb5_cc_destroy(ctx, cc); if (code) { - /*TODO: report error */ + _reportf(L"krb5_cc_destroy returns code %d", code); } _delete_this_set: @@ -1280,6 +1384,8 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) &cb))) goto _done_with_this_cred; + _reportf(L"Looking at ccache [%s]", ccname); + UnicodeStrToAnsi(a_ccname, sizeof(a_ccname), ccname); @@ -1315,6 +1421,8 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) &cb))) goto _do_next_cred; + _reportf(L"Attempting to delete ticket %s", srvname); + UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); ZeroMemory(&in_cred, sizeof(in_cred)); @@ -1740,7 +1848,8 @@ readstring(FILE * file, char * buf, int len) \return The string with the list of realms or NULL if the operation fails. */ -wchar_t * khm_krb5_get_realm_list(void) +wchar_t * +khm_krb5_get_realm_list(void) { wchar_t * rlist = NULL; @@ -1865,7 +1974,8 @@ wchar_t * khm_krb5_get_realm_list(void) Returns NULL if the operation fails. */ -wchar_t * khm_krb5_get_default_realm(void) +wchar_t * +khm_krb5_get_default_realm(void) { wchar_t * realm; size_t cch; @@ -1914,7 +2024,8 @@ khm_krb5_set_default_realm(wchar_t * realm) { return rv; } -wchar_t * khm_get_realm_from_princ(wchar_t * princ) { +wchar_t * +khm_get_realm_from_princ(wchar_t * princ) { wchar_t * t; if(!princ) diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h index 6c2c3eb6b..d69950836 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.h +++ b/src/windows/identity/plugins/krb5/krb5funcs.h @@ -84,8 +84,11 @@ khm_krb5_destroy_identity(khm_handle identity); long khm_convert524(krb5_context ctx); +int +khm_krb5_renew_cred(khm_handle cred); + int -khm_krb5_renew(khm_handle identity); +khm_krb5_renew_ident(khm_handle identity); wchar_t * khm_krb5_get_default_realm(void); diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c index 2ad904b43..f12e6a9b9 100644 --- a/src/windows/identity/plugins/krb5/krb5identpro.c +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -74,6 +74,7 @@ set_identity_from_ui(khui_new_creds * nc, khm_size cch_left; khm_handle ident; LRESULT idx = CB_ERR; + khm_int32 rv = KHM_ERROR_SUCCESS; cch = GetWindowTextLength(d->hw_username); @@ -91,23 +92,34 @@ set_identity_from_ui(khui_new_creds * nc, be exact. For caveats see MSDN for GetWindowTextLength. */ StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); + if (cch >= KCDB_IDENT_MAXCCH_NAME - 3) { + /* has to allow space for the '@' and at least a single + character realm, and the NULL terminator. */ + rv = KHM_ERROR_TOO_LONG; + goto _set_null_ident; + } + realm = un + cch; /* now points at terminating NULL */ cch_left = KCDB_IDENT_MAXCCH_NAME - cch; *realm++ = L'@'; + *realm = L'\0'; cch_left--; cch = GetWindowTextLength(d->hw_realm); - if (cch == 0 || cch >= cch_left) + if (cch == 0 || cch >= cch_left) { + rv = KHM_ERROR_INVALID_NAME; 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))) + if (KHM_FAILED(rv = kcdb_identity_create(un, + KCDB_IDENT_FLAG_CREATE, + &ident))) { goto _set_null_ident; + } khui_cw_set_primary_id(nc, ident); @@ -115,7 +127,37 @@ set_identity_from_ui(khui_new_creds * nc, return; _set_null_ident: - khui_cw_set_primary_id(nc, NULL); + { + khui_new_creds_by_type * nct = NULL; + wchar_t cmsg[256]; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (nct && nct->hwnd_panel) { + + switch(rv) { + case KHM_ERROR_TOO_LONG: + LoadString(hResModule, IDS_NCERR_IDENT_TOO_LONG, + cmsg, ARRAYLENGTH(cmsg)); + break; + + case KHM_ERROR_INVALID_NAME: + LoadString(hResModule, IDS_NCERR_IDENT_INVALID, + cmsg, ARRAYLENGTH(cmsg)); + break; + + default: + LoadString(hResModule, IDS_NCERR_IDENT_UNKNOWN, + cmsg, ARRAYLENGTH(cmsg)); + } + + SendMessage(nct->hwnd_panel, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, K5_SET_CRED_MSG), + (LPARAM) cmsg); + } + + khui_cw_set_primary_id(nc, NULL); + } return; } @@ -957,9 +999,9 @@ k5_ident_update_apply_proc(khm_handle cred, khm_handle ident = NULL; khm_int32 t; khm_int32 flags; - __int64 t_expire; - __int64 t_cexpire; - __int64 t_rexpire; + FILETIME t_expire; + FILETIME t_cexpire; + FILETIME t_rexpire; khm_size cb; khm_int32 rv = KHM_ERROR_SUCCESS; @@ -980,24 +1022,26 @@ k5_ident_update_apply_proc(khm_handle cred, KCDB_ATTR_EXPIRE, NULL, &t_cexpire, - &cb))) { - t_expire = 0; - cb = sizeof(t_expire); - if (KHM_FAILED(kcdb_identity_get_attr(tident, - KCDB_ATTR_EXPIRE, - NULL, - &t_expire, - &cb)) || - (t_cexpire > t_expire)) - kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, - &t_cexpire, sizeof(t_cexpire)); - } else { - kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, NULL, 0); + &cb))) { + cb = sizeof(t_expire); + if (KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, + &t_expire, + &cb)) || + CompareFileTime(&t_cexpire, &t_expire) > 0) { + goto update_identity; + } } - } else { - goto _cleanup; } + goto _cleanup; + + update_identity: + + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_cexpire, sizeof(t_cexpire)); + cb = sizeof(ccname); if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, NULL, diff --git a/src/windows/identity/plugins/krb5/krb5main.c b/src/windows/identity/plugins/krb5/krb5main.c index d324857fe..ee85355a0 100644 --- a/src/windows/identity/plugins/krb5/krb5main.c +++ b/src/windows/identity/plugins/krb5/krb5main.c @@ -94,10 +94,12 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { ZeroMemory(&pi, sizeof(pi)); pi.name = KRB5_PLUGIN_NAME; pi.type = KHM_PITYPE_CRED; - pi.icon = NULL; /*TODO: Assign icon */ + pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); pi.flags = 0; pi.msg_proc = k5_msg_callback; pi.description = buf; + pi.dependencies = NULL; LoadString(hResModule, IDS_PLUGIN_DESC, buf, ARRAYLENGTH(buf)); kmm_provide_plugin(h_module, &pi); @@ -105,7 +107,8 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { ZeroMemory(&pi, sizeof(pi)); pi.name = KRB5_IDENTPRO_NAME; pi.type = KHM_PITYPE_IDENT; - pi.icon = NULL; /* ignored */ + pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); pi.flags = 0; pi.msg_proc = k5_ident_callback; pi.description = buf; @@ -157,7 +160,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { type.cb_min = 0; type.cb_max = 0; type.isValid = tdata->isValid; - type.comp = tdata->comp; + type.comp = addr_list_comp; type.dup = tdata->dup; type.toString = addr_list_toString; @@ -206,7 +209,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attrib.name = ATTRNAME_KEY_ENCTYPE; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_enctype; - attrib.flags = 0; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; @@ -232,7 +235,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attrib.name = ATTRNAME_TKT_ENCTYPE; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_enctype; - attrib.flags = 0; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; @@ -258,7 +261,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attrib.name = ATTRNAME_ADDR_LIST; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_addr_list; - attrib.flags = 0; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; @@ -284,7 +287,7 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attrib.name = ATTRNAME_KRB5_FLAGS; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_krb5_flags; - attrib.flags = 0; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); attrib.short_desc = sbuf; attrib.long_desc = NULL; @@ -309,7 +312,9 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attrib.name = ATTRNAME_KRB5_CCNAME; attrib.id = KCDB_ATTR_INVALID; attrib.type = KCDB_TYPE_STRING; - attrib.flags = KCDB_ATTR_FLAG_PROPERTY; + attrib.flags = + KCDB_ATTR_FLAG_PROPERTY | + KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c index e6bf6479d..c89653779 100644 --- a/src/windows/identity/plugins/krb5/krb5newcreds.c +++ b/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -30,6 +30,8 @@ #include #include +#include + #include extern LPVOID k5_main_fiber; @@ -41,8 +43,10 @@ typedef struct k5_dlg_data_t { khui_tracker tc_lifetime; khui_tracker tc_renew; - BOOL dirty; - + BOOL dirty; /* is the data in sync with the + configuration store? */ + BOOL sync; /* is the data in sync with the kinit + request? */ DWORD renewable; DWORD forwardable; DWORD proxiable; @@ -99,9 +103,9 @@ k5_handle_wm_destroy(HWND hwnd, d = (k5_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); -#ifdef DEBUG - assert(d); -#endif + + if (!d) + return TRUE; khui_cw_find_type(d->nc, credtype_id_krb5, &nct); @@ -154,29 +158,31 @@ k5_handle_wmnc_notify(HWND hwnd, 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); - } + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, + (d->renewable? BST_CHECKED : BST_UNCHECKED), + 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + !!d->renewable); 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); - } + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, + (d->forwardable ? BST_CHECKED : BST_UNCHECKED), + 0); + + SendDlgItemMessage(hwnd, IDC_NCK5_ADDRESS, + BM_SETCHECK, + (d->addressless ? BST_CHECKED : BST_UNCHECKED), + 0); + + SendDlgItemMessage(hwnd, IDC_NCK5_PUBLICIP, + IPM_SETADDRESS, + 0, d->publicIP); + + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_PUBLICIP), !d->addressless); } break; @@ -280,15 +286,45 @@ k5_handle_wmnc_notify(HWND hwnd, d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - if(d->dirty) { + if(!d->sync) { 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; + /* the above notification effectively takes all our + changes into account. The data we have is no + longer out of sync */ + d->sync = FALSE; + } + } + break; + + case K5_SET_CRED_MSG: + { + k5_dlg_data * d; + khm_size cb; + wchar_t * msg; + + d = (k5_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + msg = (wchar_t *) lParam; + + if (d->cred_message) { + PFREE(d->cred_message); + d->cred_message = NULL; + } + + if (msg && + SUCCEEDED(StringCbLength(msg, + KHUI_MAXCB_MESSAGE, + &cb))) { + cb += sizeof(wchar_t); + d->cred_message = PMALLOC(cb); +#ifdef DEBUG + assert(d->cred_message); +#endif + StringCbCopy(d->cred_message, cb, msg); } } break; @@ -297,6 +333,32 @@ k5_handle_wmnc_notify(HWND hwnd, return 0; } +INT_PTR +k5_handle_wm_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) { + LPNMHDR pnmh; + k5_dlg_data * d; + + pnmh = (LPNMHDR) lParam; + if (pnmh->idFrom == IDC_NCK5_PUBLICIP && + pnmh->code == IPN_FIELDCHANGED) { + + d = (k5_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + SendDlgItemMessage(hwnd, IDC_NCK5_PUBLICIP, + IPM_GETADDRESS, + 0, (LPARAM) &d->publicIP); + + d->dirty = TRUE; + d->sync = FALSE; + + return TRUE; + } + + return 0; +} + INT_PTR k5_handle_wm_command(HWND hwnd, WPARAM wParam, @@ -323,9 +385,10 @@ k5_handle_wm_command(HWND hwnd, d->renewable = FALSE; } d->dirty = TRUE; + d->sync = FALSE; } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { int c; - c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, BM_GETCHECK, 0, 0); if(c==BST_CHECKED) { d->forwardable = TRUE; @@ -333,6 +396,26 @@ k5_handle_wm_command(HWND hwnd, d->forwardable = FALSE; } d->dirty = TRUE; + d->sync = FALSE; + } else if (notif == BN_CLICKED && cid == IDC_NCK5_ADDRESS) { + int c; + + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_ADDRESS, + BM_GETCHECK, 0, 0); + + if (c==BST_CHECKED) { + d->addressless = TRUE; + } else { + d->addressless = FALSE; + } + d->dirty = TRUE; + d->sync = FALSE; + + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_PUBLICIP), !d->addressless); + } else if (notif == EN_CHANGE && (cid == IDC_NCK5_RENEW_EDIT || + cid == IDC_NCK5_LIFETIME_EDIT)) { + d->dirty = TRUE; + d->sync = FALSE; } else if((notif == CBN_SELCHANGE || notif == CBN_KILLFOCUS) && cid == IDC_NCK5_REALM && @@ -414,6 +497,9 @@ k5_nc_dlg_proc(HWND hwnd, case KHUI_WM_NC_NOTIFY: return k5_handle_wmnc_notify(hwnd, wParam, lParam); + case WM_NOTIFY: + return k5_handle_wm_notify(hwnd, wParam, lParam); + case WM_DESTROY: return k5_handle_wm_destroy(hwnd, wParam, lParam); } @@ -464,19 +550,19 @@ k5_kinit_fiber_proc(PVOID lpParameter) } } - 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); + 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: @@ -1027,6 +1113,7 @@ k5_read_dlg_params(khm_handle conf, 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"PublicIP", &d->publicIP); khc_read_int32(conf, L"DefaultLifetime", &i); d->tc_lifetime.current = i; @@ -1079,6 +1166,7 @@ k5_write_dlg_params(khm_handle conf, 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"PublicIP", d->publicIP); khc_write_int32(conf, L"DefaultLifetime", (khm_int32) d->tc_lifetime.current); @@ -1117,6 +1205,9 @@ k5_prep_kinit_job(khui_new_creds * nc) d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + if (!d) + return; + khui_cw_lock_nc(nc); ident = nc->identities[0]; kcdb_identity_hold(ident); @@ -1141,7 +1232,7 @@ k5_prep_kinit_job(khui_new_creds * nc) 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.publicIP = d->publicIP; g_fjob.code = 0; g_fjob.identity = ident; g_fjob.prompt_set = 0; @@ -1238,7 +1329,8 @@ k5_find_tgt_filter(khm_handle cred, &cident)) && cident == ident && KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && - (f & KCDB_CRED_FLAG_INITIAL)) + (f & KCDB_CRED_FLAG_INITIAL) && + !(f & KCDB_CRED_FLAG_EXPIRED)) rv = 1; else rv = 0; @@ -1406,7 +1498,9 @@ k5_msg_cred_dialog(khm_int32 msg_type, hasn't changed the options */ khui_cw_lock_nc(nc); - if(!d->dirty && nc->n_identities > 0 && + /* ?: It might be better to not load identity defaults if + the user has already changed options in the dialog. */ + if(/* !d->dirty && */ nc->n_identities > 0 && nc->subtype == KMSG_CRED_NEW_CREDS) { khm_handle h_id = NULL; @@ -1648,7 +1742,9 @@ k5_msg_cred_dialog(khm_int32 msg_type, assert(g_fjob.state == FIBER_STATE_NONE); #endif g_fjob.code = 0; - } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + + _reportf(L"Cancelling"); + } else if (nc->result == KHUI_NC_RESULT_PROCESS) { khui_cw_sync_prompt_values(nc); g_fjob.command = FIBER_CMD_CONTINUE; SwitchToFiber(k5_kinit_fiber); @@ -1666,7 +1762,7 @@ k5_msg_cred_dialog(khm_int32 msg_type, if (nc->result == KHUI_NC_RESULT_CANCEL) { /* nothing to report */ g_fjob.code = 0; - } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + } else if (nc->result == KHUI_NC_RESULT_PROCESS) { /* g_fjob.code should have the result of the last kinit attempt. We should leave it as-is */ @@ -1694,8 +1790,10 @@ k5_msg_cred_dialog(khm_int32 msg_type, k5_find_tgt_filter, nc->identities[0], NULL, - NULL)))) + NULL)))) { + _reportf(L"No password entered, but a valid TGT exists. Continuing"); g_fjob.code = 0; + } if(g_fjob.code != 0) { wchar_t tbuf[1024]; @@ -1722,7 +1820,7 @@ k5_msg_cred_dialog(khm_int32 msg_type, assert(g_fjob.state == FIBER_STATE_NONE); #endif - } else if (nc->result == KHUI_NC_RESULT_GET_CREDS && + } else if (nc->result == KHUI_NC_RESULT_PROCESS && g_fjob.state == FIBER_STATE_NONE) { khm_handle sp = NULL; khm_handle ep = NULL; @@ -1734,6 +1832,8 @@ k5_msg_cred_dialog(khm_int32 msg_type, khm_size cb_ms; khm_int32 rv; + _reportf(L"Tickets successfully acquired"); + r = KHUI_NC_RESPONSE_SUCCESS | KHUI_NC_RESPONSE_EXIT; @@ -1770,6 +1870,7 @@ k5_msg_cred_dialog(khm_int32 msg_type, khm_krb5_list_tickets(&ctx); if (nc->set_default) { + _reportf(L"Setting default identity"); kcdb_identity_set_default(nc->identities[0]); } @@ -1781,6 +1882,7 @@ k5_msg_cred_dialog(khm_int32 msg_type, if (KHM_SUCCEEDED(kcdb_identity_get_default(&tdefault))) { kcdb_identity_release(tdefault); } else { + _reportf(L"There was no default identity. Setting default"); kcdb_identity_set_default(nc->identities[0]); } } @@ -1957,10 +2059,29 @@ k5_msg_cred_dialog(khm_int32 msg_type, if (nc->ctx.scope == KHUI_SCOPE_IDENT || (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && - nc->ctx.cred_type == credtype_id_krb5)) { + nc->ctx.cred_type == credtype_id_krb5) || + (nc->ctx.scope == KHUI_SCOPE_CRED && + nc->ctx.cred_type == credtype_id_krb5)) { int code; - if (nc->ctx.identity != 0) { + if (nc->ctx.scope == KHUI_SCOPE_CRED && + nc->ctx.cred != NULL) { + + /* get the expiration time for the identity first. */ + cb = sizeof(ftidexp); +#ifdef DEBUG + assert(nc->ctx.identity != NULL); +#endif + kcdb_identity_get_attr(nc->ctx.identity, + KCDB_ATTR_EXPIRE, + NULL, + &ftidexp, + &cb); + + code = khm_krb5_renew_cred(nc->ctx.cred); + + } else if (nc->ctx.scope == KHUI_SCOPE_IDENT && + nc->ctx.identity != 0) { /* get the current identity expiration time */ cb = sizeof(ftidexp); @@ -1970,12 +2091,17 @@ k5_msg_cred_dialog(khm_int32 msg_type, &ftidexp, &cb); - code = khm_krb5_renew(nc->ctx.identity); + code = khm_krb5_renew_ident(nc->ctx.identity); } else { + + _reportf(L"No identity specified. Can't renew Kerberos tickets"); + code = 1; /* it just has to be non-zero */ } if (code == 0) { + _reportf(L"Tickets successfully renewed"); + khui_cw_set_response(nc, credtype_id_krb5, KHUI_NC_RESPONSE_EXIT | KHUI_NC_RESPONSE_SUCCESS); @@ -2035,7 +2161,7 @@ k5_msg_cred_dialog(khm_int32 msg_type, _end_task(); } else if (nc->subtype == KMSG_CRED_PASSWORD && - nc->result == KHUI_NC_RESULT_GET_CREDS) { + nc->result == KHUI_NC_RESULT_PROCESS) { _begin_task(0); _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c index e58e69f34..7c5287769 100644 --- a/src/windows/identity/plugins/krb5/krb5plugin.c +++ b/src/windows/identity/plugins/krb5/krb5plugin.c @@ -134,23 +134,21 @@ k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, 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(credtype_id_krb5 >= 0) { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb5); - if(k5_main_fiber != NULL) { + /* kcdb knows how to deal with bad handles */ + kcdb_credset_delete(krb5_credset); + krb5_credset = NULL; + } + if(k5_main_fiber != NULL) { if (k5_kinit_fiber) { #ifdef DEBUG assert(k5_kinit_fiber != GetCurrentFiber()); #endif -#if CLEANUP_FIBERS_ON_EXIT +#ifdef CLEANUP_FIBERS_ON_EXIT DeleteFiber(k5_kinit_fiber); CloseHandle(k5_kinit_fiber); #endif @@ -158,7 +156,6 @@ k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, } k5_main_fiber = NULL; - } if(k5_sub != NULL) { @@ -200,9 +197,16 @@ k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, khui_action_context * ctx; ctx = (khui_action_context *) vparam; - - if (ctx->credset) + + if (ctx->credset) { + _begin_task(0); + _report_mr0(KHERR_INFO, MSG_ERR_CTX_DESTROY_CREDS); + _describe(); + khm_krb5_destroy_by_credset(ctx->credset); + + _end_task(); + } } break; diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv index 9b849c88f..49da4f2df 100644 --- a/src/windows/identity/plugins/krb5/krbconfig.csv +++ b/src/windows/identity/plugins/krb5/krbconfig.csv @@ -13,9 +13,10 @@ Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider 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) + Forwardable,KC_INT32,0,Obtain forwardable tickets (boolean) Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + PublicIP,KC_INT32,0,Additional public IP address to use (int32) Renewable,KC_INT32,1,Obtain renewable tickets (boolean) DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h index 7ab035c8c..3e64b0077 100644 --- a/src/windows/identity/plugins/krb5/krbcred.h +++ b/src/windows/identity/plugins/krb5/krbcred.h @@ -180,6 +180,8 @@ extern fiber_job g_fjob; /* global fiber job object */ #define FIBER_STATE_NONE 0 #define FIBER_STATE_KINIT 1 +#define K5_SET_CRED_MSG WMNC_USER + void k5_pp_begin(khui_property_sheet * s); diff --git a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc index d54fc101e..c54bdb4b1 100644 --- a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc +++ b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc @@ -58,6 +58,8 @@ STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN + CONTROL "Kerberos 5 Ticket 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 @@ -71,8 +73,12 @@ BEGIN 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 + CONTROL "Addressless",IDC_NCK5_ADDRESS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,128,54,10 + LTEXT "Additional IP address",IDC_STATIC,118,129,68,8,NOT + WS_VISIBLE + CONTROL "",IDC_NCK5_PUBLICIP,"SysIPAddress32",NOT WS_VISIBLE | + WS_TABSTOP,193,125,100,15 END IDD_PP_KRB5C DIALOGEX 0, 0, 235, 156 @@ -129,18 +135,19 @@ 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, - WS_DISABLED + PUSHBUTTON "Configure Realms ...",IDC_CFG_CFGREALMS,76,25,84,14,NOT + WS_VISIBLE | WS_DISABLED GROUPBOX "Keberos Configuration File",IDC_CFG_CFGFILEGRP,7,45,241, 61 LTEXT "Location",IDC_CFG_LBL_CFGFILE,13,61,28,8 EDITTEXT IDC_CFG_CFGFILE,76,58,119,14,ES_AUTOHSCROLL PUSHBUTTON "Browse...",IDC_CFG_BROWSE,198,58,44,14 CONTROL "Create file if missing",IDC_CFG_CREATECONFIG,"Button", - BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,76,76,80,10 + BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | + WS_TABSTOP,76,90,80,10 CONTROL "Include realms in New Credentials realm list", IDC_CFG_INCREALMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, - 76,91,153,10 + 76,78,153,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 | @@ -200,11 +207,19 @@ 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 + CONTROL "Renewable for",IDC_CFG_RENEW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,41,63,10 + EDITTEXT IDC_CFG_DEFRLIFE,91,39,137,14,ES_AUTOHSCROLL + CONTROL "Can be forwarded to other machines",IDC_CFG_FORWARD, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,59,133,10 + CONTROL "Addressless",IDC_CFG_ADDRESSLESS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,77,54,10 + LTEXT "Additional IP address",IDC_STATIC,91,78,68,8,NOT + WS_VISIBLE + CONTROL "",IDC_CFG_PUBLICIP,"SysIPAddress32",NOT WS_VISIBLE | + WS_TABSTOP,128,89,100,15 + LTEXT "Credentials cache",IDC_STATIC,7,132,58,8 + EDITTEXT IDC_CFG_CCACHE,91,130,137,14,ES_AUTOHSCROLL END IDD_NC_KRB5_PASSWORD DIALOGEX 0, 0, 300, 166 @@ -226,18 +241,19 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "File Caches",IDC_CFG_FCGRP,7,38,241,137 + GROUPBOX "File Caches",IDC_CFG_FCGRP,7,26,241,149 CONTROL "",IDC_CFG_FCLIST,"SysListView32",LVS_REPORT | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | - WS_TABSTOP,13,48,229,86 + WS_TABSTOP,13,37,229,97 EDITTEXT IDC_CFG_FCNAME,13,139,173,14,ES_AUTOHSCROLL PUSHBUTTON "&Browse ...",IDC_CFG_BROWSE,192,139,50,14 PUSHBUTTON "Add",IDC_CFG_ADD,13,156,50,14 PUSHBUTTON "Remove Selected",IDC_CFG_REMOVE,88,156,80,14 - CHECKBOX "Include all API: credentials caches",IDC_CFG_INCAPI,13, - 7,125,10 + CONTROL "Include all API: credentials caches",IDC_CFG_INCAPI, + "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP, + 123,7,125,10 CONTROL "Include Windows LSA cache (MSLSA:)",IDC_CFG_INCMSLSA, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,22,136,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,7,136,10 END @@ -396,7 +412,7 @@ STRINGTABLE BEGIN IDS_KRB4_SHORT_DESC "Kerberos 4" IDS_KRB4_LONG_DESC "Kerberos 4 tickets" - IDS_KRB5_FLAGS_SHORT_DESC "Flags" + IDS_KRB5_FLAGS_SHORT_DESC "Krb5 Flags" IDS_RENEW_TILL_SHORT_DESC "Renew Till" IDS_RENEW_TILL_LONG_DESC "Renewable Till" IDS_RENEW_FOR_SHORT_DESC "Renew for" @@ -484,6 +500,27 @@ BEGIN IDS_CFG_RE_NEWSERVER "" IDS_CFG_RE_NEWDMAP "" IDS_KRB5_NC_NAME "Kerberos 5" + IDS_NCERR_IDENT_TOO_LONG "The identity name is too long." + IDS_NCERR_IDENT_INVALID "The identity name is invalid." + IDS_NCERR_IDENT_UNKNOWN "An unknown error occurred while validating the identity name." + IDS_CFG_RE_ARNUT "Can't add new realm %s" + IDS_CFG_RE_ARNUM "The new realm name %s can't be added because there is already a realm with the same name listed. Please type another name." + IDS_CFG_RE_ASNUT "Can't add new server %s for realm %s" + IDS_CFG_RE_ASNUM "There already is a server named %s for realm %s. The new server can not be added." + IDS_CFG_RE_DMNUT "Can't add new domain map %s for realm %s" +END + +STRINGTABLE +BEGIN + IDS_CFG_RE_DMNUM "There already is a domain named %s mapping to realm %s. The new domain map could not be added." + IDS_CFG_RE_MNR "&Add new realm" + IDS_CFG_RE_MDR "&Remove realm" + IDS_CFG_RE_MNK "&Add new server" + IDS_CFG_RE_MDK "&Remove server" + IDS_CFG_RE_MAK "Toggle a&dmin server" + IDS_CFG_RE_MMK "Toggle &master KDC" + IDS_CFG_RE_MND "&Add new domain mapping" + IDS_CFG_RE_MDD "&Remove domain mapping" END #endif // English (U.S.) resources diff --git a/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc index 2b637ac9f..01e01761f 100644 --- a/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc +++ b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc @@ -151,6 +151,11 @@ Language=English This is commonly caused by an incorrect password. Please verify that the password is correct and note that passwords are case sensitive. . +MessageId= +SymbolicName=MSG_ERR_CTX_DESTROY_CREDS +Language=English +Destroying Krb5 tickets +. MessageId= SymbolicName=MSG_ diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h index 6f76cc56b..edda7dd02 100644 --- a/src/windows/identity/plugins/krb5/langres.h +++ b/src/windows/identity/plugins/krb5/langres.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb5\lang\en_us\langres.rc +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb5\lang\en_us\langres.rc // #define IDS_UNK_ADDR_FMT 101 #define IDD_NC_KRB5 102 @@ -115,6 +115,23 @@ #define IDS_CFG_RE_NEWSERVER 197 #define IDS_CFG_RE_NEWDMAP 198 #define IDS_KRB5_NC_NAME 199 +#define IDS_NCERR_IDENT_TOO_LONG 200 +#define IDS_NCERR_IDENT_INVALID 201 +#define IDS_NCERR_IDENT_UNKNOWN 202 +#define IDS_CFG_RE_ARNUT 203 +#define IDS_CFG_RE_ARNUM 204 +#define IDS_CFG_RE_ASNUT 205 +#define IDS_CFG_RE_ASNUM 206 +#define IDS_CFG_RE_DMNUT 207 +#define IDS_CFG_RE_DMNUM 208 +#define IDS_CFG_RE_MNR 209 +#define IDS_CFG_RE_MDR 210 +#define IDS_CFG_RE_MNK 211 +#define IDS_CFG_RE_MDK 212 +#define IDS_CFG_RE_MAK 213 +#define IDS_CFG_RE_MMK 214 +#define IDS_CFG_RE_MND 215 +#define IDS_CFG_RE_MDD 216 #define IDC_NCK5_RENEWABLE 1002 #define IDC_NCK5_FORWARDABLE 1004 #define IDC_NCK5_REALM 1005 @@ -172,16 +189,24 @@ #define IDC_CFG_INCAPI 1066 #define IDC_CFG_INCMSLSA 1067 #define IDC_PPK5_FLAGS 1072 -#define IDC_CHECK1 1073 #define IDC_CFG_INCREALMS 1073 +#define IDC_NCK5_ADDRESS 1074 +#define IDC_IPADDRESS1 1075 +#define IDC_NCK5_PUBLICIP 1075 +#define IDC_CFG_PUBLICIP 1075 +#define IDC_CFG_RENEW 1076 +#define IDC_CHECK3 1077 +#define IDC_CFG_ADDRESSLESS 1077 +#define IDC_CFG_FORWARD 1078 +#define ID_FOO_BAR 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 117 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1074 +#define _APS_NEXT_RESOURCE_VALUE 118 +#define _APS_NEXT_COMMAND_VALUE 40002 +#define _APS_NEXT_CONTROL_VALUE 1079 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/windows/identity/plugins/krb5/version.rc b/src/windows/identity/plugins/krb5/version.rc index 10b16dd29..ec58aa90b 100644 --- a/src/windows/identity/plugins/krb5/version.rc +++ b/src/windows/identity/plugins/krb5/version.rc @@ -26,6 +26,28 @@ #include +#ifndef LANGVER + +#define STR_FILEDESC "Kerberos 5 Plugin for NetIDMgr" +#define STR_INTNAME "krb5cred" +#define STR_ORIGNAME "krb5cred.dll" + +#else + +#ifdef LANG_en_us + +#define STR_FILEDESC "English(US) language resources for the Keberos 5 plugin" +#define STR_INTNAME "krb5cred_en_us" +#define STR_ORIGNAME "krb5cred_en_us.dll" + +#else + +#error Unknown langugae + +#endif + +#endif + 1 VERSIONINFO FILEVERSION KH_VERSION_LIST PRODUCTVERSION KH_VERSION_LIST @@ -40,20 +62,22 @@ BLOCK "040904b0" { VALUE "CompanyName", KH_VERSTR_COMPANY_1033 - VALUE "FileDescription", "Kerberos 5 plugin for NetIDMgr" + VALUE "FileDescription", STR_FILEDESC VALUE "FileVersion", KH_VERSTR_VERSION_1033 - VALUE "InternalName", "krb5cred" + VALUE "InternalName", STR_INTNAME VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 - VALUE "OriginalFilename", "krb5cred.dll" + VALUE "OriginalFilename", STR_ORIGNAME VALUE "ProductName", "NetIDMgr" VALUE "ProductVersion", KH_VERSTR_PRODUCT_1033 #ifdef KH_VERSTR_COMMENT_1033 VALUE "Comment", KH_VERSTR_COMMENT_1033 #endif +#ifndef LANGVER VALUE NIMV_MODULE, "MITKrb5" VALUE NIMV_PLUGINS, "Krb5Cred,Krb5Ident" VALUE NIMV_APIVER, KH_VERSION_STRINGAPI VALUE NIMV_SUPPORT, "http://web.mit.edu/kerberos" +#endif } } diff --git a/src/windows/identity/ui/Makefile b/src/windows/identity/ui/Makefile index 7b3acc40f..c2a78e21b 100644 --- a/src/windows/identity/ui/Makefile +++ b/src/windows/identity/ui/Makefile @@ -1,90 +1,101 @@ -# -# 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=ui -!include <../config/Makefile.w32> - -EXEFILE=$(BINDIR)\netidmgr.exe - -MANIFESTFILE=$(BINDIR)\netidmgr.exe.manifest - -OBJFILES= \ - $(OBJ)\main.obj \ - $(OBJ)\mainmenu.obj \ - $(OBJ)\toolbar.obj \ - $(OBJ)\statusbar.obj \ - $(OBJ)\notifier.obj \ - $(OBJ)\timer.obj \ - $(OBJ)\uiconfig.obj \ - $(OBJ)\mainwnd.obj \ - $(OBJ)\credwnd.obj \ - $(OBJ)\htwnd.obj \ - $(OBJ)\passwnd.obj \ - $(OBJ)\newcredwnd.obj \ - $(OBJ)\propertywnd.obj \ - $(OBJ)\credfuncs.obj \ - $(OBJ)\configwnd.obj \ - $(OBJ)\aboutwnd.obj \ - $(OBJ)\reqdaemon.obj \ - $(OBJ)\addrchange.obj \ - $(OBJ)\cfg_general_wnd.obj \ - $(OBJ)\cfg_identities_wnd.obj \ - $(OBJ)\cfg_notif_wnd.obj \ - $(OBJ)\cfg_plugins_wnd.obj - -RESFILES= \ - $(OBJ)\khapp.res \ - $(OBJ)\appver.res - -LIBFILES= \ - $(LIBDIR)\nidmgr32.lib - -SDKLIBFILES= \ - comctl32.lib \ - shell32.lib \ - htmlhelp.lib \ - iphlpapi.lib \ - shlwapi.lib - -$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg - $(CCSV) $** $@ - -$(OBJ)\khapp.res: lang\en_us\khapp.rc - $(RC2RES) - -$(OBJ)\appver.res: appver.rc - $(RC2RES) - -!if "$(KH_BUILD)"=="RETAIL" -$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER) -!else -$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER).debug -!endif - $(CP) $** $@ - -$(EXEFILE): $(OBJFILES) $(RESFILES) $(LIBFILES) - $(EXEGUILINK) $(SDKLIBFILES) - -all: mkdirs $(EXEFILE) $(MANIFESTFILE) - +# +# 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=ui +!include <../config/Makefile.w32> + +EXEFILE=$(BINDIR)\netidmgr.exe + +MANIFESTFILE=$(BINDIR)\netidmgr.exe.manifest + +OBJFILES= \ + $(OBJ)\main.obj \ + $(OBJ)\mainmenu.obj \ + $(OBJ)\toolbar.obj \ + $(OBJ)\statusbar.obj \ + $(OBJ)\notifier.obj \ + $(OBJ)\timer.obj \ + $(OBJ)\uiconfig.obj \ + $(OBJ)\mainwnd.obj \ + $(OBJ)\credwnd.obj \ + $(OBJ)\htwnd.obj \ + $(OBJ)\passwnd.obj \ + $(OBJ)\newcredwnd.obj \ + $(OBJ)\propertywnd.obj \ + $(OBJ)\credfuncs.obj \ + $(OBJ)\configwnd.obj \ + $(OBJ)\aboutwnd.obj \ + $(OBJ)\reqdaemon.obj \ + $(OBJ)\addrchange.obj \ + $(OBJ)\debugfuncs.obj \ + $(OBJ)\cfg_general_wnd.obj \ + $(OBJ)\cfg_identities_wnd.obj \ + $(OBJ)\cfg_notif_wnd.obj \ + $(OBJ)\cfg_plugins_wnd.obj + +RESFILES= \ + $(OBJ)\khapp.res \ + $(OBJ)\appver.res + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +LIBFILES=$(LIBDIR)\nidmgr64.lib +!else +LIBFILES=$(LIBDIR)\nidmgr32.lib +!endif + +SDKLIBFILES= \ + comctl32.lib \ + shell32.lib \ + htmlhelp.lib \ + iphlpapi.lib \ + shlwapi.lib + +$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(OBJ)\khapp.res: lang\en_us\khapp.rc + $(RC2RES) + +$(OBJ)\appver.res: appver.rc + $(RC2RES) + +!if "$(KH_BUILD)"=="RETAIL" +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER) +!else +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER).debug +!endif + $(CP) $** $@ + + +!if ("$(CPU)" == "IA64" ) || ("$(CPU)" == "AMD64" ) || ("$(CPU)" == "ALPHA64" ) +SCLIB=bufferoverflowu.lib +!else +SCLIB= +!endif + +$(EXEFILE): $(OBJFILES) $(RESFILES) $(LIBFILES) + $(EXEGUILINK) $(SDKLIBFILES) $(SCLIB) + +all: mkdirs $(EXEFILE) $(MANIFESTFILE) + diff --git a/src/windows/identity/ui/appglobal.h b/src/windows/identity/ui/appglobal.h index 9baa9b9e2..952996107 100644 --- a/src/windows/identity/ui/appglobal.h +++ b/src/windows/identity/ui/appglobal.h @@ -36,10 +36,11 @@ extern int khm_nCmdShow; extern const wchar_t * khm_facility; extern kconf_schema schema_uiconfig[]; extern khm_ui_4 khm_commctl_version; +extern khm_version app_version; #define IS_COMMCTL6() (khm_commctl_version >= 0x60000) -typedef struct tag_khm_startup_options { +typedef struct tag_khm_startup_options_v1 { BOOL seen; BOOL processing; @@ -57,6 +58,19 @@ typedef struct tag_khm_startup_options { extern khm_startup_options khm_startup; +typedef struct tag_khm_query_app_version_v1 { + khm_int32 magic; + + khm_int32 code; + + khm_version ver_caller; + khm_version ver_remote; + + khm_boolean request_swap; +} khm_query_app_version; + +#define KHM_QUERY_APP_VER_MAGIC 0x38f8c2eb + void khm_add_dialog(HWND dlg); void khm_del_dialog(HWND dlg); BOOL khm_is_dialog_active(void); @@ -75,6 +89,8 @@ void khm_register_window_classes(void); HWND khm_html_help(HWND hwnd, wchar_t * suffix, UINT command, DWORD_PTR data); +WPARAM khm_message_loop_int(khm_boolean * p_exit); + #define MAX_RES_STRING 1024 #define ELIPSIS L"..." diff --git a/src/windows/identity/ui/cfg_general_wnd.c b/src/windows/identity/ui/cfg_general_wnd.c index 7b48975a9..c01402b84 100644 --- a/src/windows/identity/ui/cfg_general_wnd.c +++ b/src/windows/identity/ui/cfg_general_wnd.c @@ -33,6 +33,8 @@ typedef struct tag_cfg_data { BOOL auto_import; BOOL keep_running; BOOL auto_detect_net; + BOOL log_to_file; + BOOL destroy_creds; } cfg_data; typedef struct tag_dlg_data { @@ -72,6 +74,12 @@ read_params(dlg_data * dd) { khc_read_int32(csp_cw, L"AutoDetectNet", &t); d->auto_detect_net = !!t; + khc_read_int32(csp_cw, L"LogToFile", &t); + d->log_to_file = !!t; + + khc_read_int32(csp_cw, L"DestroyCredsOnExit", &t); + d->destroy_creds = !!t; + khc_close_space(csp_cw); dd->work = *d; @@ -119,6 +127,22 @@ write_params(dlg_data * dd) { applied = TRUE; } + if (!!d->log_to_file != !!s->log_to_file) { + khc_write_int32(csp_cw, L"LogToFile", d->log_to_file); + applied = TRUE; + + if (d->log_to_file) { + khm_start_file_log(); + } else { + khm_stop_file_log(); + } + } + + if (!!d->destroy_creds != !!s->destroy_creds) { + khc_write_int32(csp_cw, L"DestroyCredsOnExit", d->destroy_creds); + applied = TRUE; + } + khc_close_space(csp_cw); khui_cfg_set_flags(dd->node, @@ -138,7 +162,9 @@ check_for_modification(dlg_data * dd) { !!d->auto_start != !!s->auto_start || !!d->auto_import != !!s->auto_import || !!d->keep_running != !!s->keep_running || - !!d->auto_detect_net != !!s->auto_detect_net) { + !!d->auto_detect_net != !!s->auto_detect_net || + !!d->log_to_file != !!s->log_to_file || + !!d->destroy_creds != !!s->destroy_creds) { khui_cfg_set_flags(dd->node, KHUI_CNFLAG_MODIFIED, @@ -155,6 +181,8 @@ check_for_modification(dlg_data * dd) { static void refresh_view(HWND hwnd, dlg_data * d) { + wchar_t buf[512]; + CheckDlgButton(hwnd, IDC_CFG_AUTOINIT, (d->work.auto_init?BST_CHECKED:BST_UNCHECKED)); CheckDlgButton(hwnd, IDC_CFG_AUTOSTART, @@ -165,6 +193,20 @@ refresh_view(HWND hwnd, dlg_data * d) { (d->work.keep_running?BST_CHECKED:BST_UNCHECKED)); CheckDlgButton(hwnd, IDC_CFG_NETDETECT, (d->work.auto_detect_net?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_LOGTOFILE, + (d->work.log_to_file?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_DESTROYALL, + (d->work.destroy_creds?BST_CHECKED:BST_UNCHECKED)); + + /* in addition, we correct the label on the trace log control to + reflect the actual path that is going to get used */ + if (GetDlgItemText(hwnd, IDC_CFG_LOGPATH, buf, + ARRAYLENGTH(buf)) == 0) { + + khm_get_file_log_path(sizeof(buf), buf); + + SetDlgItemText(hwnd, IDC_CFG_LOGPATH, buf); + } } static void @@ -179,6 +221,10 @@ refresh_data(HWND hwnd, dlg_data * d) { == BST_CHECKED); d->work.auto_detect_net = (IsDlgButtonChecked(hwnd, IDC_CFG_NETDETECT) == BST_CHECKED); + d->work.log_to_file = (IsDlgButtonChecked(hwnd, IDC_CFG_LOGTOFILE) + == BST_CHECKED); + d->work.destroy_creds = (IsDlgButtonChecked(hwnd, IDC_CFG_DESTROYALL) + == BST_CHECKED); } INT_PTR CALLBACK diff --git a/src/windows/identity/ui/cfg_identities_wnd.c b/src/windows/identity/ui/cfg_identities_wnd.c index 0ec3dcbbb..26a60e5e0 100644 --- a/src/windows/identity/ui/cfg_identities_wnd.c +++ b/src/windows/identity/ui/cfg_identities_wnd.c @@ -155,7 +155,7 @@ apply_all(HWND hwnd, assert(hw); #endif - PostMessage(hw, KHUI_WM_CFG_NOTIFY, + SendMessage(hw, KHUI_WM_CFG_NOTIFY, MAKEWPARAM(0, WMCFG_APPLY), 0); } } @@ -169,6 +169,7 @@ show_tab_panel(HWND hwnd, TCITEM tci; HWND hw; HWND hw_target; + HWND hw_firstctl; RECT r; RECT rref; khui_config_node_reg reg; @@ -213,6 +214,11 @@ show_tab_panel(HWND hwnd, r.right - r.left, r.bottom - r.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_SHOWWINDOW); + + hw_firstctl = GetNextDlgTabItem(hw, NULL, FALSE); + if (hw_firstctl) { + SetFocus(hw_firstctl); + } } static INT_PTR diff --git a/src/windows/identity/ui/cfg_notif_wnd.c b/src/windows/identity/ui/cfg_notif_wnd.c index 220865113..ac5f93028 100644 --- a/src/windows/identity/ui/cfg_notif_wnd.c +++ b/src/windows/identity/ui/cfg_notif_wnd.c @@ -34,6 +34,7 @@ typedef struct tag_notif_data { BOOL monitor; BOOL renew; + BOOL halflife; BOOL warn1; BOOL warn2; @@ -59,6 +60,10 @@ read_params(notif_data * d) { assert(KHM_SUCCEEDED(rv)); d->renew = !!t; + rv = khc_read_int32(csp_cw, L"RenewAtHalfLife", &t); + assert(KHM_SUCCEEDED(rv)); + d->halflife = !!t; + rv = khc_read_int32(csp_cw, L"AllowWarn", &t); assert(KHM_SUCCEEDED(rv)); d->warn1 = !!t; @@ -106,6 +111,7 @@ check_for_modification(notif_data * d) { if ((!!d->monitor) != (!!t.monitor) || (!!d->renew) != (!!t.renew) || + (!!d->halflife) != (!!t.halflife) || (!!d->warn1) != (!!t.warn1) || (!!d->warn2) != (!!t.warn2) || d->tc_renew.current != t.tc_renew.current || @@ -144,6 +150,9 @@ write_params(notif_data * d) { rv = khc_write_int32(csp_cw, L"AllowAutoRenew", d->renew); assert(KHM_SUCCEEDED(rv)); + rv = khc_write_int32(csp_cw, L"RenewAtHalfLife", d->halflife); + assert(KHM_SUCCEEDED(rv)); + rv = khc_write_int32(csp_cw, L"AllowWarn", d->warn1); assert(KHM_SUCCEEDED(rv)); @@ -178,6 +187,8 @@ refresh_view(HWND hwnd, notif_data * d) { (d->monitor?BST_CHECKED:BST_UNCHECKED)); CheckDlgButton(hwnd, IDC_NOTIF_RENEW, (d->renew?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_NOTIF_HALFLIFE, + (d->halflife?BST_CHECKED:BST_UNCHECKED)); CheckDlgButton(hwnd, IDC_NOTIF_WARN1, (d->warn1?BST_CHECKED:BST_UNCHECKED)); CheckDlgButton(hwnd, IDC_NOTIF_WARN2, @@ -187,6 +198,7 @@ refresh_view(HWND hwnd, notif_data * d) { khui_tracker_refresh(&d->tc_warn2); if (!d->monitor) { EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_HALFLIFE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), FALSE); @@ -194,6 +206,7 @@ refresh_view(HWND hwnd, notif_data * d) { EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), FALSE); } else { EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_HALFLIFE), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), !!(d->renew)); @@ -208,6 +221,8 @@ refresh_data(HWND hwnd, notif_data * d) { == BST_CHECKED); d->renew = (IsDlgButtonChecked(hwnd, IDC_NOTIF_RENEW) == BST_CHECKED); + d->halflife = (IsDlgButtonChecked(hwnd, IDC_NOTIF_HALFLIFE) + == BST_CHECKED); d->warn1 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN1) == BST_CHECKED); d->warn2 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN2) diff --git a/src/windows/identity/ui/cfg_plugins_wnd.c b/src/windows/identity/ui/cfg_plugins_wnd.c index 6dad3698f..cab71c4ea 100644 --- a/src/windows/identity/ui/cfg_plugins_wnd.c +++ b/src/windows/identity/ui/cfg_plugins_wnd.c @@ -37,8 +37,163 @@ typedef struct tag_plugin_data { typedef struct tag_plugin_dlg_data { plugin_data * info[MAX_PLUGINS]; khm_size n_info; + + plugin_data * selected; + HICON plugin_ico; } plugin_dlg_data; +void update_dialog_fields(HWND hwnd, + plugin_dlg_data * d, + plugin_data * info) { + wchar_t buf[256]; + UINT resid; + wchar_t * t; + khm_handle csp_module = NULL; + + d->selected = info; + + if (info->plugin.reg.description) + SetDlgItemText(hwnd, IDC_CFG_DESC, info->plugin.reg.description); + else { + wchar_t fmt[128]; + + LoadString(khm_hInstance, IDS_CFG_NODESC, fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, info->plugin.reg.name); + SetDlgItemText(hwnd, IDC_CFG_DESC, buf); + } + + switch(info->plugin.state) { + case KMM_PLUGIN_STATE_FAIL_INIT: + resid = IDS_PISTATE_FAILINIT; + break; + + case KMM_PLUGIN_STATE_FAIL_UNKNOWN: + resid = IDS_PISTATE_FAILUNK; + break; + + case KMM_PLUGIN_STATE_FAIL_MAX_FAILURE: + resid = IDS_PISTATE_FAILMAX; + break; + + case KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED: + resid = IDS_PISTATE_FAILREG; + break; + + case KMM_PLUGIN_STATE_FAIL_DISABLED: + resid = IDS_PISTATE_FAILDIS; + break; + + case KMM_PLUGIN_STATE_FAIL_LOAD: + resid = IDS_PISTATE_FAILLOD; + break; + + case KMM_PLUGIN_STATE_NONE: + case KMM_PLUGIN_STATE_PLACEHOLDER: + resid = IDS_PISTATE_PLACEHOLD; + break; + + case KMM_PLUGIN_STATE_REG: + case KMM_PLUGIN_STATE_PREINIT: + resid = IDS_PISTATE_REG; + break; + + case KMM_PLUGIN_STATE_HOLD: + resid = IDS_PISTATE_HOLD; + break; + + case KMM_PLUGIN_STATE_INIT: + resid = IDS_PISTATE_INIT; + break; + + case KMM_PLUGIN_STATE_RUNNING: + resid = IDS_PISTATE_RUN; + break; + + case KMM_PLUGIN_STATE_EXITED: + resid = IDS_PISTATE_EXIT; + break; + + default: +#ifdef DEBUG + assert(FALSE); +#endif + resid = IDS_PISTATE_FAILUNK; + } + + LoadString(khm_hInstance, resid, + buf, ARRAYLENGTH(buf)); + + SetDlgItemText(hwnd, IDC_CFG_STATE, buf); + + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_RESETCONTENT, 0, 0); + + for (t = info->plugin.reg.dependencies; t && *t; + t = multi_string_next(t)) { + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_INSERTSTRING, -1, (LPARAM) t); + } + + if (info->plugin.reg.module) + SetDlgItemText(hwnd, IDC_CFG_MODULE, + info->plugin.reg.module); + else + SetDlgItemText(hwnd, IDC_CFG_MODULE, + L""); + + if (info->module.reg.vendor) + SetDlgItemText(hwnd, IDC_CFG_VENDOR, + info->module.reg.vendor); + else + SetDlgItemText(hwnd, IDC_CFG_VENDOR, + L""); + + StringCbPrintf(buf, sizeof(buf), L"%u.%u.%u.%u", + (unsigned int) info->module.product_version.major, + (unsigned int) info->module.product_version.minor, + (unsigned int) info->module.product_version.patch, + (unsigned int) info->module.product_version.aux); + + SetDlgItemText(hwnd, IDC_CFG_VERSION, buf); + + if (info->plugin.reg.icon) { + SendDlgItemMessage(hwnd, IDC_CFG_ICON, + STM_SETICON, + (WPARAM) info->plugin.reg.icon, + 0); + } else { + SendDlgItemMessage(hwnd, IDC_CFG_ICON, + STM_SETICON, + (WPARAM) d->plugin_ico, + 0); + } + + if (KHM_SUCCEEDED(kmm_get_module_config(info->module.reg.name, + 0, &csp_module)) && + (khc_value_exists(csp_module, L"ImagePath") & + (KCONF_FLAG_MACHINE | KCONF_FLAG_USER))) { + + EnableWindow(GetDlgItem(hwnd, IDC_CFG_UNREGISTER), TRUE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_UNREGISTER), FALSE); + } + + if (csp_module) + khc_close_space(csp_module); + + if (info->plugin.flags & KMM_PLUGIN_FLAG_DISABLED) { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), FALSE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), TRUE); + } +} + +#define IDX_PLUGIN_NORMAL 1 +#define IDX_PLUGIN_DISABLED 2 +#define IDX_PLUGIN_ERROR 3 + INT_PTR CALLBACK khm_cfg_plugins_proc(HWND hwnd, UINT uMsg, @@ -58,7 +213,8 @@ khm_cfg_plugins_proc(HWND hwnd, RECT r; HWND hw; wchar_t buf[256]; - + HIMAGELIST h_ilist; + HICON h_icon; d = PMALLOC(sizeof(*d)); #ifdef DEBUG @@ -87,6 +243,8 @@ khm_cfg_plugins_proc(HWND hwnd, #ifdef DEBUG assert(d->info[i]); #endif + ZeroMemory(&d->info[i]->plugin, + sizeof(d->info[i]->plugin)); if (KHM_FAILED(kmm_get_plugin_info_i(p, &d->info[i]->plugin))) { PFREE(d->info[i]); @@ -120,6 +278,50 @@ khm_cfg_plugins_proc(HWND hwnd, #ifdef DEBUG assert(hw); #endif + + h_ilist = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_COLOR8, + 4, 4); + + h_icon = LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDI_CFG_PLUGIN), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); +#ifdef DEBUG + assert(h_icon); +#endif + ImageList_AddIcon(h_ilist, h_icon); + DestroyIcon(h_icon); + + h_icon = LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDI_CFG_PLUGIN_DIS), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); +#ifdef DEBUG + assert(h_icon); +#endif + ImageList_AddIcon(h_ilist, h_icon); + DestroyIcon(h_icon); + + h_icon = LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDI_CFG_PLUGIN_ERR), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); +#ifdef DEBUG + assert(h_icon); +#endif + ImageList_AddIcon(h_ilist, h_icon); + DestroyIcon(h_icon); + + ListView_SetImageList(hw, h_ilist, LVSIL_STATE); + ZeroMemory(&lvc, sizeof(lvc)); lvc.mask = LVCF_TEXT | LVCF_WIDTH; @@ -137,12 +339,28 @@ khm_cfg_plugins_proc(HWND hwnd, ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvi.lParam = (LPARAM) d->info[i]; lvi.pszText = d->info[i]->plugin.reg.name; + if (d->info[i]->plugin.flags & KMM_PLUGIN_FLAG_DISABLED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_PLUGIN_DISABLED); + } else if (d->info[i]->plugin.state < 0) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_PLUGIN_ERROR); + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_PLUGIN_NORMAL); + } + ListView_InsertItem(hw, &lvi); } + + d->plugin_ico = + (HICON) LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDI_CFG_PLUGIN), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_DEFAULTCOLOR); } return FALSE; @@ -169,16 +387,18 @@ khm_cfg_plugins_proc(HWND hwnd, SetDlgItemText(hwnd, IDC_CFG_STATE, L""); SetDlgItemText(hwnd, IDC_CFG_MODULE, L""); SetDlgItemText(hwnd, IDC_CFG_VENDOR, L""); + SetDlgItemText(hwnd, IDC_CFG_VERSION, L""); EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_UNREGISTER), FALSE); SendDlgItemMessage(hwnd, IDC_CFG_DEPS, LB_RESETCONTENT, 0, 0); + SendDlgItemMessage(hwnd, IDC_CFG_ICON, STM_SETICON, + (WPARAM) d->plugin_ico, 0); + d->selected = NULL; } else { int idx; plugin_data * info; - wchar_t buf[256]; - UINT resid; - wchar_t * t; idx = ListView_GetNextItem(hw, -1, LVNI_SELECTED); #ifdef DEBUG @@ -195,95 +415,205 @@ khm_cfg_plugins_proc(HWND hwnd, #endif info = (plugin_data *) lvi.lParam; - if (info->plugin.reg.description) - SetDlgItemText(hwnd, IDC_CFG_DESC, info->plugin.reg.description); - else - SetDlgItemText(hwnd, IDC_CFG_DESC, L""); + update_dialog_fields(hwnd, d, info); + } + } + } + return TRUE; - switch(info->plugin.state) { - case KMM_PLUGIN_STATE_FAIL_UNKNOWN: - resid = IDS_PISTATE_FAILUNK; - break; + case WM_COMMAND: + { - case KMM_PLUGIN_STATE_FAIL_MAX_FAILURE: - resid = IDS_PISTATE_FAILMAX; - break; + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); - case KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED: - resid = IDS_PISTATE_FAILREG; - break; + switch (wParam) { + case MAKEWPARAM(IDC_CFG_ENABLE, BN_CLICKED): + if (d->selected != NULL) { + khui_alert * alert = NULL; + wchar_t buf[KHUI_MAXCCH_MESSAGE]; + wchar_t fmt[KHUI_MAXCCH_MESSAGE]; + kmm_plugin p; - case KMM_PLUGIN_STATE_FAIL_DISABLED: - resid = IDS_PISTATE_FAILDIS; - break; + khui_alert_create_empty(&alert); - case KMM_PLUGIN_STATE_FAIL_LOAD: - resid = IDS_PISTATE_FAILLOD; - break; + LoadString(khm_hInstance, IDS_CFG_P_ENBCNFT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, d->selected->plugin.reg.name); + khui_alert_set_title(alert, buf); - case KMM_PLUGIN_STATE_NONE: - case KMM_PLUGIN_STATE_PLACEHOLDER: - resid = IDS_PISTATE_PLACEHOLD; - break; + LoadString(khm_hInstance, IDS_CFG_P_ENBCNFM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, d->selected->plugin.reg.name); + khui_alert_set_message(alert, buf); - case KMM_PLUGIN_STATE_REG: - case KMM_PLUGIN_STATE_PREINIT: - resid = IDS_PISTATE_REG; - break; + khui_alert_set_severity(alert, KHERR_INFO); - case KMM_PLUGIN_STATE_HOLD: - resid = IDS_PISTATE_HOLD; - break; + khui_alert_show_modal(alert); - case KMM_PLUGIN_STATE_INIT: - resid = IDS_PISTATE_INIT; - break; + kmm_enable_plugin(d->selected->plugin.h_plugin, TRUE); - case KMM_PLUGIN_STATE_RUNNING: - resid = IDS_PISTATE_RUN; - break; + khui_alert_release(alert); + + p = d->selected->plugin.h_plugin; + kmm_hold_plugin(p); + kmm_release_plugin_info_i(&d->selected->plugin); + kmm_get_plugin_info_i(p, &d->selected->plugin); + kmm_release_plugin(p); - case KMM_PLUGIN_STATE_EXITED: - resid = IDS_PISTATE_EXIT; + update_dialog_fields(hwnd, d, d->selected); + } + break; + + case MAKEWPARAM(IDC_CFG_DISABLE, BN_CLICKED): + if (d->selected != NULL) { + khui_alert * alert = NULL; + wchar_t buf[KHUI_MAXCCH_MESSAGE]; + wchar_t fmt[KHUI_MAXCCH_MESSAGE]; + wchar_t depends[KHUI_MAXCCH_MESSAGE]; + khm_size i; + kmm_plugin p; + + khui_alert_create_empty(&alert); +#ifdef DEBUG + assert(alert); +#endif + if (alert == NULL) break; - default: + LoadString(khm_hInstance, IDS_CFG_P_DELCNFT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, d->selected->plugin.reg.name); + khui_alert_set_title(alert, buf); + + LoadString(khm_hInstance, IDS_CFG_P_DELCNFM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, d->selected->plugin.reg.name); + khui_alert_set_message(alert, buf); + + depends[0] = L'\0'; + + for (i=0; in_info; i++) { + wchar_t * t; + + t = d->info[i]->plugin.reg.dependencies; + + while(t) { + if (!wcscmp(t, d->selected->plugin.reg.name)) { + if (depends[0]) + StringCbCat(depends, sizeof(depends), L", "); + StringCbCat(depends, sizeof(depends), + d->info[i]->plugin.reg.name); + break; + } + t = multi_string_next(t); + } + } + + if (depends[0]) { + LoadString(khm_hInstance, IDS_CFG_P_DELCNFS, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, depends); + khui_alert_set_suggestion(alert, buf); + } else { + LoadString(khm_hInstance, IDS_CFG_P_DELNDEP, + buf, ARRAYLENGTH(buf)); + khui_alert_set_suggestion(alert, buf); + } + + khui_alert_add_command(alert, KHUI_PACTION_YES); + khui_alert_add_command(alert, KHUI_PACTION_NO); + + khui_alert_set_severity(alert, KHERR_WARNING); + + if (KHM_SUCCEEDED(khui_alert_show_modal(alert)) && + alert->response == KHUI_PACTION_YES) { + kmm_enable_plugin(d->selected->plugin.h_plugin, FALSE); + } + + khui_alert_release(alert); + + p = d->selected->plugin.h_plugin; + kmm_hold_plugin(p); + kmm_release_plugin_info_i(&d->selected->plugin); + kmm_get_plugin_info_i(p, &d->selected->plugin); + kmm_release_plugin(p); + + update_dialog_fields(hwnd, d, d->selected); + } + break; + + case MAKEWPARAM(IDC_CFG_UNREGISTER, BN_CLICKED): + { + khui_alert * alert = NULL; + wchar_t buf[KHUI_MAXCCH_MESSAGE]; + wchar_t fmt[KHUI_MAXCCH_MESSAGE]; + wchar_t plist[KHUI_MAXCCH_MESSAGE]; + khm_size i; + + if (d->selected == NULL) { #ifdef DEBUG assert(FALSE); #endif - resid = IDS_PISTATE_FAILUNK; + break; } - LoadString(khm_hInstance, resid, - buf, ARRAYLENGTH(buf)); + khui_alert_create_empty(&alert); - SetDlgItemText(hwnd, IDC_CFG_STATE, buf); + LoadString(khm_hInstance, IDS_CFG_P_UNRCNFT, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + d->selected->plugin.reg.name); - SendDlgItemMessage(hwnd, IDC_CFG_DEPS, - LB_RESETCONTENT, 0, 0); + khui_alert_set_title(alert, buf); + + LoadString(khm_hInstance, IDS_CFG_P_UNRCNFM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + d->selected->plugin.reg.name); + + khui_alert_set_message(alert, buf); - for (t = info->plugin.reg.dependencies; t && *t; - t = multi_string_next(t)) { - SendDlgItemMessage(hwnd, IDC_CFG_DEPS, - LB_INSERTSTRING, - -1, - (LPARAM) t); + plist[0] = L'\0'; + for (i=0; i < d->n_info; i++) { + if (!wcscmp(d->info[i]->module.reg.name, + d->selected->module.reg.name)) { + if (plist[0]) + StringCbCat(plist, sizeof(plist), L", "); + StringCbCat(plist, sizeof(plist), + d->info[i]->plugin.reg.name); + } } - if (info->plugin.reg.module) - SetDlgItemText(hwnd, IDC_CFG_MODULE, - info->plugin.reg.module); - else - SetDlgItemText(hwnd, IDC_CFG_MODULE, - L""); - - if (info->module.reg.vendor) - SetDlgItemText(hwnd, IDC_CFG_VENDOR, - info->module.reg.vendor); - else - SetDlgItemText(hwnd, IDC_CFG_VENDOR, - L""); +#ifdef DEBUG + /* there should have been at least one plugin */ + assert(plist[0]); +#endif + + LoadString(khm_hInstance, IDS_CFG_P_UNRCNFS, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, plist); + khui_alert_set_suggestion(alert, buf); + + khui_alert_add_command(alert, KHUI_PACTION_YES); + khui_alert_add_command(alert, KHUI_PACTION_NO); + + khui_alert_set_severity(alert, KHERR_WARNING); + + if (KHM_SUCCEEDED(khui_alert_show_modal(alert)) && + alert->response == KHUI_PACTION_YES) { + kmm_unregister_module(d->selected->module.reg.name, 0); + + update_dialog_fields(hwnd, d, d->selected); + } + } + break; + + case MAKEWPARAM(IDC_CFG_REGISTER, BN_CLICKED): + { + } + break; } } return TRUE; diff --git a/src/windows/identity/ui/configwnd.c b/src/windows/identity/ui/configwnd.c index 7441b54f8..63ec2d5fe 100644 --- a/src/windows/identity/ui/configwnd.c +++ b/src/windows/identity/ui/configwnd.c @@ -450,10 +450,8 @@ cfgui_update_state(HWND hwnd, TreeView_SetItem(hwtv, &itx); if(cfgui_check_mod_state(NULL)) { - EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), TRUE); EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE); } else { - EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), FALSE); EnableWindow(GetDlgItem(hwnd, IDAPPLY), FALSE); } } @@ -512,7 +510,7 @@ cfgui_dlgproc_generic(HWND hwnd, r_fill.bottom = r_logo.top; FillRect(hdc, &r_fill, d->hbr_white); - SetWindowLong(hwnd, DWL_MSGRESULT, (LONG) TRUE); + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG) TRUE); } return TRUE; } @@ -591,6 +589,8 @@ cfgui_dlgproc(HWND hwnd, { LPNMHDR lpnm; LPNMTREEVIEW lptv; + LPNMTVGETINFOTIP lpgi; + khui_config_node node; lpnm = (LPNMHDR) lParam; @@ -601,6 +601,31 @@ cfgui_dlgproc(HWND hwnd, (khui_config_node) lptv->itemNew.lParam); return TRUE; + + case TVN_GETINFOTIP: + lpgi = (LPNMTVGETINFOTIP) lParam; + node = (khui_config_node) lpgi->lParam; + + if (node) { + khm_int32 flags = 0; + + flags = khui_cfg_get_flags(node); + + if (flags & KHUI_CNFLAG_MODIFIED) { + LoadString(khm_hInstance, IDS_CFG_IT_MOD, + lpgi->pszText, lpgi->cchTextMax); + } else if (flags & KHUI_CNFLAG_APPLIED) { + LoadString(khm_hInstance, IDS_CFG_IT_APP, + lpgi->pszText, lpgi->cchTextMax); + } else { + LoadString(khm_hInstance, IDS_CFG_IT_NONE, + lpgi->pszText, lpgi->cchTextMax); + } + } else { + StringCchCopy(lpgi->pszText, lpgi->cchTextMax, L""); + } + + return TRUE; } } return TRUE; @@ -691,6 +716,9 @@ void khm_refresh_config(void) { khm_int32 rv; int n_tries = 0; khui_config_node cfg_ids = NULL; + khui_config_node cfg_r = NULL; + khui_menu_def * omenu; + khm_boolean refresh_menu = FALSE; do { rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, @@ -766,10 +794,81 @@ void khm_refresh_config(void) { } } + /* Now iterate through the root level configuration nodes and make + sure we have a menu item for each of them. */ + if (KHM_FAILED(khui_cfg_get_first_child(NULL, &cfg_r))) + goto _cleanup; + + omenu = khui_find_menu(KHUI_MENU_OPTIONS); + if (omenu == NULL) + goto _cleanup; + + do { + khm_int32 action; + khm_int32 flags; + khui_action * paction; + wchar_t cname[KHUI_MAXCCH_NAME]; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + khm_size cb; + khm_handle sub; + khui_config_node_reg reg; + + flags = khui_cfg_get_flags(cfg_r); + if (flags & KHUI_CNFLAG_SYSTEM) + goto _next_cfg; + + cb = sizeof(cname); + if (KHM_FAILED(khui_cfg_get_name(cfg_r, cname, &cb))) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _next_cfg; + } + + paction = khui_find_named_action(cname); + + if (!paction) { + khui_cfg_get_reg(cfg_r, ®); + + kmq_create_hwnd_subscription(khm_hwnd_main, &sub); + + StringCbCopy(wshort, sizeof(wshort), reg.short_desc); + StringCbCat(wshort, sizeof(wshort), L" ..."); + + action = khui_action_create(cname, + wshort, + reg.long_desc, + (void *) CFGACTION_MAGIC, + KHUI_ACTIONTYPE_TRIGGER, + sub); + + if (action == 0) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _next_cfg; + } + + khui_menu_insert_action(omenu, -1, action, 0); + + refresh_menu = TRUE; + } + + _next_cfg: + if (KHM_FAILED(khui_cfg_get_next_release(&cfg_r))) + break; + } while(cfg_r); + + if (refresh_menu) + khm_menu_refresh_items(); + _cleanup: if (cfg_ids) khui_cfg_release(cfg_ids); + if (cfg_r) + khui_cfg_release(cfg_r); + if (idents) PFREE(idents); } @@ -783,7 +882,7 @@ void khm_init_config(void) { reg.short_desc = wshort; reg.long_desc = wlong; reg.h_module = khm_hInstance; - reg.flags = 0; + reg.flags = KHUI_CNFLAG_SYSTEM; reg.name = L"KhmGeneral"; reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_GENERAL); @@ -818,7 +917,7 @@ void khm_init_config(void) { wshort, ARRAYLENGTH(wshort)); LoadString(khm_hInstance, IDS_CFG_IDS_TAB_LONG, wlong, ARRAYLENGTH(wlong)); - reg.flags = KHUI_CNFLAG_SUBPANEL; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; khui_cfg_register(node, ®); @@ -829,11 +928,11 @@ void khm_init_config(void) { wshort, ARRAYLENGTH(wshort)); LoadString(khm_hInstance, IDS_CFG_ID_TAB_LONG, wlong, ARRAYLENGTH(wlong)); - reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL; + reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; khui_cfg_register(node, ®); - reg.flags = 0; + reg.flags = KHUI_CNFLAG_SYSTEM; khui_cfg_release(node); reg.name = L"KhmNotifications"; diff --git a/src/windows/identity/ui/configwnd.h b/src/windows/identity/ui/configwnd.h index 62747fcad..61db340c8 100644 --- a/src/windows/identity/ui/configwnd.h +++ b/src/windows/identity/ui/configwnd.h @@ -27,6 +27,8 @@ #ifndef __KHIMAIRA_CONFIGWND_H #define __KHIMAIRA_CONFIGWND_H +#define CFGACTION_MAGIC 0x38f8 + void khm_show_config_pane(khui_config_node node); diff --git a/src/windows/identity/ui/credfuncs.c b/src/windows/identity/ui/credfuncs.c index 7e0756fb4..e09791e7b 100644 --- a/src/windows/identity/ui/credfuncs.c +++ b/src/windows/identity/ui/credfuncs.c @@ -380,7 +380,7 @@ void khm_cred_set_default(void) khui_context_release(&ctx); } -void khm_cred_destroy_creds(void) +void khm_cred_destroy_creds(khm_boolean sync, khm_boolean quiet) { khui_action_context * pctx; @@ -391,7 +391,7 @@ void khm_cred_destroy_creds(void) khui_context_get(pctx); - if(pctx->scope == KHUI_SCOPE_NONE) { + if(pctx->scope == KHUI_SCOPE_NONE && !quiet) { /* this really shouldn't be necessary once we start enabling and disbling actions based on context */ wchar_t title[256]; @@ -413,18 +413,26 @@ void khm_cred_destroy_creds(void) khui_context_release(pctx); PFREE(pctx); - } else { - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); - _describe(); + return; + } + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_DESTROY_CREDS); + _describe(); + + if (sync) + kmq_send_message(KMSG_CRED, + KMSG_CRED_DESTROY_CREDS, + 0, + (void *) pctx); + else kmq_post_message(KMSG_CRED, KMSG_CRED_DESTROY_CREDS, 0, (void *) pctx); - _end_task(); - } + _end_task(); } void khm_cred_renew_identity(khm_handle identity) @@ -434,7 +442,7 @@ void khm_cred_renew_identity(khm_handle identity) khui_cw_create_cred_blob(&c); c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_GET_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; khui_context_create(&c->ctx, KHUI_SCOPE_IDENT, identity, @@ -457,7 +465,7 @@ void khm_cred_renew_cred(khm_handle cred) khui_cw_create_cred_blob(&c); c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_GET_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; khui_context_create(&c->ctx, KHUI_SCOPE_CRED, NULL, @@ -479,7 +487,7 @@ void khm_cred_renew_creds(void) khui_cw_create_cred_blob(&c); c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_GET_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; khui_context_get(&c->ctx); _begin_task(KHERR_CF_TRANSITIVE); @@ -855,7 +863,7 @@ khm_cred_process_commandline(void) { NULL, NULL, 0, NULL); - khm_cred_destroy_creds(); + khm_cred_destroy_creds(FALSE, FALSE); } khm_startup.destroy = FALSE; diff --git a/src/windows/identity/ui/credfuncs.h b/src/windows/identity/ui/credfuncs.h index b9be3d487..fe8ed6c25 100644 --- a/src/windows/identity/ui/credfuncs.h +++ b/src/windows/identity/ui/credfuncs.h @@ -31,7 +31,8 @@ void KHMAPI kmsg_cred_completion(kmq_message *m); void -khm_cred_destroy_creds(void); +khm_cred_destroy_creds(khm_boolean sync, + khm_boolean quiet); void khm_cred_renew_identity(khm_handle identity); diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c index 5211d50b1..1d5d6643e 100644 --- a/src/windows/identity/ui/credwnd.c +++ b/src/windows/identity/ui/credwnd.c @@ -31,6 +31,55 @@ ATOM khui_credwnd_cls; khm_int32 khui_cw_flag_id; +khm_int32 attr_to_action[KCDB_ATTR_MAX_ID + 1]; + +void +cw_refresh_attribs(HWND hwnd) { + khm_int32 act; + kcdb_attrib * attrib; + khui_menu_def * menu; + khm_int32 i; + + menu = khui_find_menu(KHUI_MENU_COLUMNS); +#ifdef DEBUG + assert(menu); +#endif + + for (i=0; i <= KCDB_ATTR_MAX_ID; i++) { + if (KHM_FAILED(kcdb_attrib_get_info(i, &attrib))) { + if (attr_to_action[i] != 0) { + /* the action should be removed */ + khui_menu_remove_action(menu, attr_to_action[i]); + khui_action_delete(attr_to_action[i]); + attr_to_action[i] = 0; + } + } else { + if (attr_to_action[i] == 0 && + !(attrib->flags & KCDB_ATTR_FLAG_HIDDEN) && + (attrib->short_desc || attrib->long_desc)) { + /* new action */ + khm_handle sub = NULL; + + kmq_create_hwnd_subscription(hwnd, &sub); + + act = khui_action_create(attrib->name, + (attrib->short_desc? + attrib->short_desc: attrib->long_desc), + NULL, + (void *)(UINT_PTR) i, + KHUI_ACTIONTYPE_TOGGLE, + sub); + + attr_to_action[i] = act; + + khui_menu_insert_action(menu, 5000, act, 0); + } + + kcdb_attrib_release_info(attrib); + } + } +} + khm_int32 cw_get_custom_attr_id(wchar_t * s) { @@ -41,6 +90,142 @@ cw_get_custom_attr_id(wchar_t * s) return 0; } +const wchar_t * +cw_get_custom_attr_string(khm_int32 attr_id) +{ + if (attr_id == CW_CA_FLAGS) + return CW_CANAME_FLAGS; + if (attr_id == CW_CA_TYPEICON) + return CW_CANAME_TYPEICON; + return NULL; +} + +void +cw_save_view(khui_credwnd_tbl * tbl, wchar_t * view_name) { + wchar_t * col_list = NULL; + khm_size cb_col_list; + khm_handle csp_cw = NULL; + khm_handle csp_views = NULL; + khm_handle csp_view = NULL; + khm_handle csp_cols = NULL; + khm_size cb; + int i; + + if (tbl->n_cols == 0) + return; + + cb_col_list = (KCONF_MAXCB_NAME + 1) * tbl->n_cols; + + col_list = PMALLOC(cb_col_list); +#ifdef DEBUG + assert(col_list); +#endif + + if (!col_list) + goto _cleanup; + + multi_string_init(col_list, cb_col_list); + + if (!view_name && (tbl->flags & KHUI_CW_TBL_CUSTVIEW)) { + view_name = L"Custom_0"; + } + + if (view_name) { + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ | KHM_PERM_WRITE, &csp_cw))) + goto _cleanup; + + if (KHM_FAILED(khc_open_space(csp_cw, L"Views", KHM_PERM_READ, &csp_views))) + goto _cleanup; + + if (KHM_FAILED(khc_open_space(csp_views, view_name, + KHM_PERM_WRITE | KHM_FLAG_CREATE, + &csp_view))) + goto _cleanup; + + /* if we are switching to a custom view, then we should mark + that as the default. */ + if (tbl->flags & KHUI_CW_TBL_CUSTVIEW) { + khc_write_string(csp_cw, L"DefaultView", L"Custom_0"); + } + + } else { + csp_view = tbl->csp_view; + } + + if (!csp_view) + goto _cleanup; + + if (KHM_FAILED(khc_open_space(csp_view, L"Columns", + KHM_PERM_WRITE | KHM_FLAG_CREATE, + &csp_cols))) + goto _cleanup; + + for (i=0; i < tbl->n_cols; i++) { + const wchar_t * attr_name; + kcdb_attrib * attrib = NULL; + khm_handle csp_col = NULL; + + if (tbl->cols[i].attr_id < 0) { + attr_name = cw_get_custom_attr_string(tbl->cols[i].attr_id); + } else { + if (KHM_FAILED(kcdb_attrib_get_info(tbl->cols[i].attr_id, + &attrib))) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _clean_col; + } + + attr_name = attrib->name; + } +#ifdef DEBUG + assert(attr_name); +#endif + + cb = cb_col_list; + multi_string_append(col_list, &cb, attr_name); + + if (KHM_FAILED(khc_open_space(csp_cols, attr_name, + KHM_PERM_WRITE | KHM_FLAG_CREATE, + &csp_col))) + goto _clean_col; + + khc_write_int32(csp_col, L"Width", tbl->cols[i].width); + khc_write_int32(csp_col, L"SortIndex", tbl->cols[i].sort_index); + khc_write_int32(csp_col, L"Flags", tbl->cols[i].flags); + + _clean_col: + + if (csp_col) + khc_close_space(csp_col); + + if (attrib) + kcdb_attrib_release_info(attrib); + } + + khc_write_multi_string(csp_view, L"ColumnList", col_list); + + _cleanup: + + if (view_name) { + if (csp_view) + khc_close_space(csp_view); + + if (csp_views) + khc_close_space(csp_views); + + if (csp_cw) + khc_close_space(csp_cw); + } + + if (csp_cols) + khc_close_space(csp_cols); + + if (col_list) + PFREE(col_list); +} + void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { khm_handle hc_cw = NULL; @@ -58,7 +243,8 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { tbl->hwnd = hwnd; - if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &hc_cw))) + if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ | KHM_PERM_WRITE, + &hc_cw))) return; if(KHM_FAILED(khc_open_space(hc_cw, L"Views", KHM_PERM_READ, &hc_vs))) @@ -69,11 +255,33 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { if(KHM_FAILED(khc_read_string(hc_cw, L"DefaultView", buf, &cbsize))) goto _exit; view = buf; + + /* in addition, if we are loading the default view, we should + also check the appropriate menu item */ + + if (!wcscmp(view, L"ByIdentity")) + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_ID); + else if (!wcscmp(view, L"ByLocation")) + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_LOC); + else if (!wcscmp(view, L"ByType")) + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_TYPE); + else if (!wcscmp(view, L"Custom_0")) + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_CUST); + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + } else { + khc_write_string(hc_cw, L"DefaultView", view); } if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v))) goto _exit; + tbl->csp_view = hc_v; + if(KHM_FAILED(khc_open_space(hc_v, L"Columns", KHM_PERM_READ, &hc_cs))) goto _exit; @@ -88,10 +296,13 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { goto _exit; tbl->n_cols = (int) multi_string_length_n(clist); - tbl->n_total_cols = UBOUNDSS(tbl->n_cols, KHUI_CW_COL_INITIAL, KHUI_CW_COL_INCREMENT); + tbl->n_total_cols = UBOUNDSS(tbl->n_cols, + KHUI_CW_COL_INITIAL, KHUI_CW_COL_INCREMENT); tbl->cols = PMALLOC(sizeof(khui_credwnd_col) * tbl->n_total_cols); ZeroMemory(tbl->cols, sizeof(khui_credwnd_col) * tbl->n_total_cols); + tbl->flags &= ~(KHUI_CW_TBL_CUSTVIEW | KHUI_CW_TBL_COLSKIP); + iter = clist; i = 0; while(iter) { @@ -100,13 +311,27 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { attr_id = cw_get_custom_attr_id(iter); if(!attr_id) { /* a KCDB attribute */ - if(KHM_FAILED(kcdb_attrib_get_id(iter, &attr_id))) + if(KHM_FAILED(kcdb_attrib_get_id(iter, &attr_id))) { + tbl->flags |= KHUI_CW_TBL_COLSKIP; goto _skip_col; - if(kcdb_attrib_describe(attr_id, NULL, &cbsize, KCDB_TS_SHORT) != KHM_ERROR_TOO_LONG || - cbsize == 0) + } + + if(kcdb_attrib_describe(attr_id, NULL, + &cbsize, KCDB_TS_SHORT) != KHM_ERROR_TOO_LONG || + cbsize == 0) { + tbl->flags |= KHUI_CW_TBL_COLSKIP; goto _skip_col; + } + tbl->cols[i].title = PMALLOC(cbsize); kcdb_attrib_describe(attr_id, tbl->cols[i].title, &cbsize, KCDB_TS_SHORT); + + if (attr_id >= 0 && + attr_id <= KCDB_ATTR_MAX_ID && + attr_to_action[attr_id]) { + khui_check_action(attr_to_action[attr_id], TRUE); + } + } else { /* All current custom attributes are represented by icons, not names */ @@ -119,8 +344,9 @@ cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { if(KHM_FAILED(khc_read_int32(hc_c, L"Flags", &(tbl->cols[i].flags)))) tbl->cols[i].flags = 0; if(KHM_FAILED(khc_read_int32(hc_c, L"Width", &(tbl->cols[i].width)))) - tbl->cols[i].width = -1; - if(KHM_FAILED(khc_read_int32(hc_c, L"SortIndex", &(tbl->cols[i].sort_index)))) + tbl->cols[i].width = 100; + if(KHM_FAILED(khc_read_int32(hc_c, L"SortIndex", + &(tbl->cols[i].sort_index)))) tbl->cols[i].sort_index = -1; khc_close_space(hc_c); hc_c = NULL; @@ -134,6 +360,9 @@ _skip_col: iter = multi_string_next(iter); } + /* refresh the menus since we checked a few items */ + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + /* adjust the number of columns. We may have skipped columns due to inconsistencies above */ tbl->n_cols = i; @@ -148,8 +377,10 @@ _skip_col: khc_read_int32(hc_cw, L"PaddingHeader", &(tbl->hpad_h)); if(KHM_FAILED(khc_read_int32(hc_v, L"WarnThreshold", &(tbl->threshold_warn)))) khc_read_int32(hc_cw, L"WarnThreshold", &(tbl->threshold_warn)); - if(KHM_FAILED(khc_read_int32(hc_v, L"CriticalThreshold", &(tbl->threshold_critical)))) - khc_read_int32(hc_cw, L"CriticalThreshold", &(tbl->threshold_critical)); + if(KHM_FAILED(khc_read_int32(hc_v, L"CriticalThreshold", + &(tbl->threshold_critical)))) + khc_read_int32(hc_cw, L"CriticalThreshold", + &(tbl->threshold_critical)); /* and the font resources and stuff */ @@ -159,74 +390,74 @@ _skip_col: hdc = GetWindowDC(hwnd); - tbl->hf_header = CreateFont( - -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ - 0,0, /* escapement */ - FW_THIN, - FALSE, - FALSE, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - FF_SWISS, - L"MS Shell Dlg"); + tbl->hf_header = + CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); if(tbl->hf_header && tbl->hwnd_header) SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0); - tbl->hf_bold_header = CreateFont( - -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ - 0,0, /* escapement */ - FW_BOLD, - FALSE, - FALSE, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - FF_SWISS, - L"MS Shell Dlg"); - - tbl->hf_normal = CreateFont( - -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ - 0,0, /* escapement */ - FW_THIN, - FALSE, - FALSE, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - FF_SWISS, - L"MS Shell Dlg"); - - tbl->hf_bold = CreateFont( - -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ - 0,0, /* escapement */ - FW_BOLD, - FALSE, - FALSE, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - FF_SWISS, - L"MS Shell Dlg"); + tbl->hf_bold_header = + CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_normal = + CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_bold = + CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); ReleaseDC(hwnd, hdc); - khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade),LoadImage( - khm_hInstance, - MAKEINTRESOURCE(IDB_LOGO_SHADE), - IMAGE_BITMAP, - 0, - 0, - LR_DEFAULTCOLOR)); + khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade), + LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_SHADE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); tbl->hb_normal = CreateSolidBrush(RGB(255,255,255)); tbl->hb_grey = CreateSolidBrush(RGB(240,240,240)); @@ -259,20 +490,25 @@ _skip_col: ADD_BITMAP(IDB_WDG_EXPAND); ADD_BITMAP(IDB_ID_SM); ADD_BITMAP(IDB_ID_DIS_SM); + ADD_BITMAP(IDB_TK_NEW_SM); ADD_BITMAP(IDB_TK_REFRESH_SM); ADD_BITMAP(IDB_WDG_COLLAPSE_HI); ADD_BITMAP(IDB_WDG_EXPAND_HI); + ADD_BITMAP(IDB_WDG_FLAG); ADD_BITMAP(IDB_WDG_CREDTYPE); ADD_BITMAP(IDB_FLAG_WARN); ADD_BITMAP(IDB_FLAG_EXPIRED); + ADD_BITMAP(IDB_FLAG_CRITICAL); ADD_BITMAP(IDB_FLAG_RENEW); ADD_BITMAP(IDB_WDG_STUCK); ADD_BITMAP(IDB_WDG_STUCK_HI); + ADD_BITMAP(IDB_WDG_STICK); ADD_BITMAP(IDB_WDG_STICK_HI); + ADD_BITMAP(IDB_TK_SM); #undef ADD_BITMAP } @@ -288,12 +524,12 @@ _exit: khc_close_space(hc_cw); if(hc_vs) khc_close_space(hc_vs); - if(hc_v) - khc_close_space(hc_v); if(hc_cs) khc_close_space(hc_cs); if(clist) PFREE(clist); + /* we leave hc_v held, because tbl->csp_view is the same handle. + We keep that open until the view is unloaded. */ } void @@ -301,7 +537,7 @@ cw_update_creds(khui_credwnd_tbl * tbl) { kcdb_cred_comp_field * fields; kcdb_cred_comp_order comp_order; - khm_size i; + int i; khm_int32 n; khm_int32 delta; khm_handle hc; @@ -330,8 +566,7 @@ cw_update_creds(khui_credwnd_tbl * tbl) for(i=0, n=0; in_cols; i++) { if((tbl->cols[i].flags & KHUI_CW_COL_SORT_INC) || (tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) || - (tbl->cols[i].flags & KHUI_CW_COL_GROUP)) - { + (tbl->cols[i].flags & KHUI_CW_COL_GROUP)) { int si; /* we need to sort by this column */ si = tbl->cols[i].sort_index; @@ -356,8 +591,7 @@ cw_update_creds(khui_credwnd_tbl * tbl) Also, if we are sorting by credential type name, then we allow the primary credential type first before - others. - */ + others. */ if (fields[si].attrib == KCDB_ATTR_NAME || fields[si].attrib == KCDB_ATTR_TYPE_NAME) @@ -384,8 +618,8 @@ cw_update_creds(khui_credwnd_tbl * tbl) khm_size s; kcdb_credset_get_size(tbl->credset, &s); - for(i=0;icredset, + for(i=0;i< (int) s;i++) { + if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, (khm_int32) i, &hc))) continue; /* lost a race */ if(KHM_FAILED(kcdb_cred_get_attr(hc, khui_cw_flag_id, NULL, @@ -413,6 +647,7 @@ cw_del_outline(khui_credwnd_outline *o) { if(o->header) PFREE(o->header); + if ((o->flags & KHUI_CW_O_DATAALLOC) && o->data) PFREE(o->data); @@ -485,7 +720,7 @@ cw_timer_proc(HWND hwnd, khui_credwnd_tbl * tbl; khui_credwnd_row * r; khm_int32 nflags; - khm_size nr; + int nr; long ms; FILETIME ft; khm_size cbsize; @@ -493,7 +728,7 @@ cw_timer_proc(HWND hwnd, tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); r = (khui_credwnd_row *) idEvent; - nr = r - tbl->rows; + nr = (int)(r - tbl->rows); if(nr < 0 || nr >= tbl->n_rows) return; @@ -523,8 +758,9 @@ cw_timer_proc(HWND hwnd, } cbsize = sizeof(ft); - if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) - { + if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, + KCDB_ATTR_TIMELEFT, NULL, + &ft, &cbsize))) { ms = FtIntervalMsToRepChange(&ft); if(ms > 0) { SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); @@ -545,7 +781,7 @@ cw_set_tbl_row_cred(khui_credwnd_tbl * tbl, if((int) tbl->n_total_rows <= row) { /* we need to resize the allocation */ khui_credwnd_row * newrows; - khm_size newsize; + int newsize; newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); @@ -578,7 +814,7 @@ cw_set_tbl_row_header(khui_credwnd_tbl * tbl, if((int) tbl->n_total_rows <= row) { /* we need to resize the allocation */ khui_credwnd_row * newrows; - khm_size newsize; + int newsize; newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); @@ -609,7 +845,7 @@ cw_update_outline(khui_credwnd_tbl * tbl) int i,j,n_rows; int level; int visible; - khm_size n_creds; + khm_size n_creds = 0; khm_handle prevcred = NULL; khm_handle thiscred = NULL; /* grouping[0..n_grouping-1] are the columns that we are going to @@ -882,7 +1118,8 @@ cw_update_outline(khui_credwnd_tbl * tbl) /* we need to do this here too just in case we were already at the level we were supposed to be in */ - visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + if (ol) + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); flags = cw_get_cred_exp_flags(tbl, thiscred); expstate |= flags; @@ -1040,11 +1277,16 @@ cw_update_outline(khui_credwnd_tbl * tbl) tbl->flags |= KHUI_CW_TBL_ROW_DIRTY; tbl->flags &= ~KHUI_CW_TBL_COL_DIRTY; + + if (tbl->cursor_row >= tbl->n_rows) + tbl->cursor_row = tbl->n_rows - 1; + if (tbl->cursor_row < 0) + tbl->cursor_row = 0; _exit: if(grouping) PFREE(grouping); - if (tbl->n_rows == 0) + if (n_creds == 0) khm_notify_icon_expstate(KHM_NOTIF_EMPTY); else if (expstate & CW_EXPSTATE_EXPIRED) khm_notify_icon_expstate(KHM_NOTIF_EXP); @@ -1092,16 +1334,27 @@ cw_unload_view(khui_credwnd_tbl * tbl) } if(tbl->cols) { - khm_size i; + int i; + for(i=0; i < tbl->n_cols; i++) { if(tbl->cols[i].title) PFREE(tbl->cols[i].title); Header_DeleteItem(tbl->hwnd_header, 0); + + if (tbl->cols[i].attr_id >= 0 && + tbl->cols[i].attr_id <= KCDB_ATTR_MAX_ID && + attr_to_action[tbl->cols[i].attr_id]) { + + khui_check_action(attr_to_action[tbl->cols[i].attr_id], FALSE); + + } } PFREE(tbl->cols); tbl->cols = NULL; tbl->n_cols = 0; tbl->n_total_cols = 0; + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); } if(tbl->rows) { @@ -1112,6 +1365,11 @@ cw_unload_view(khui_credwnd_tbl * tbl) } khui_delete_bitmap(&tbl->kbm_logo_shade); + + if (tbl->csp_view) { + khc_close_space(tbl->csp_view); + tbl->csp_view = NULL; + } } void @@ -1208,7 +1466,7 @@ cw_update_extents(khui_credwnd_tbl * tbl, /* update the header control first */ -retry_update_scroll: + retry_update_scroll: GetClientRect(tbl->hwnd, &r); cl_w = r.right - r.left; @@ -1302,19 +1560,19 @@ cw_erase_rect(HDC hdc, if(RectVisible(hdc, r_erase)) { switch(type) { - case CW_ER_BLANK: - hbr = tbl->hb_normal; - break; + case CW_ER_BLANK: + hbr = tbl->hb_normal; + break; - case CW_ER_GREY: - hbr = tbl->hb_grey; - break; + case CW_ER_GREY: + hbr = tbl->hb_grey; + break; - case CW_ER_SEL: - hbr = tbl->hb_sel; - break; + case CW_ER_SEL: + hbr = tbl->hb_sel; + break; - default: + default: return; } @@ -1510,57 +1768,308 @@ cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { switch(ph->hdr.code) { /*TODO:Make it track smoother */ - case HDN_BEGINTRACK: - { - if(tbl->cols[ph->iItem].flags & KHUI_CW_COL_FIXED_WIDTH) - return TRUE; + case HDN_BEGINTRACK: + { + ZeroMemory(&hi, sizeof(hi)); + hi.mask = HDI_ORDER; + Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); + + if(tbl->cols[hi.iOrder].flags & KHUI_CW_COL_FIXED_WIDTH) + return TRUE; + else + return FALSE; + } + + case HDN_TRACK: + case HDN_ENDTRACK: + { + int width; + hi.mask = HDI_ORDER; + Header_GetItem(ph->hdr.hwndFrom, ph->iItem, &hi); + Header_GetItemRect(ph->hdr.hwndFrom, ph->iItem, &r); + width = r.right - r.left; + if(width != tbl->cols[hi.iOrder].width) { + tbl->cols[hi.iOrder].width = width; + cw_update_extents(tbl, TRUE); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } + } + break; + + case HDN_BEGINDRAG: + { + + ZeroMemory(&hi, sizeof(hi)); + hi.mask = HDI_ORDER; + Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); + + if (tbl->cols[hi.iOrder].flags & KHUI_CW_COL_FIXED_WIDTH) { + return TRUE; + } else { + return FALSE; + } + } + break; + + case HDN_ENDDRAG: + { + int drag_start_index; + int drag_end_index; + int i; + khui_credwnd_col tcol; + int sort_index = 0; + khm_int32 old_flags; + + if (ph->pitem == NULL) + return TRUE; + + hi.mask = HDI_ORDER; + Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); + drag_start_index = hi.iOrder; + drag_end_index = ph->pitem->iOrder; + + /* the user dragged the column which was at drag_start_index + to drag_end_index. */ + + if (drag_end_index == drag_start_index) + return TRUE; + + /* we don't allow dragging in to the "fixed" area. */ + for (i=0; i < tbl->n_cols; i++) { + if (tbl->cols[i].attr_id >= 0) + break; + } + + if (drag_end_index <= i) + return TRUE; + + tcol = tbl->cols[drag_start_index]; + if (drag_end_index < drag_start_index) { + MoveMemory(&tbl->cols[drag_end_index + 1], + &tbl->cols[drag_end_index], + sizeof(tbl->cols[0]) * + (drag_start_index - drag_end_index)); + } else { + MoveMemory(&tbl->cols[drag_start_index], + &tbl->cols[drag_start_index + 1], + sizeof(tbl->cols[0]) * + (drag_end_index - drag_start_index)); + } + tbl->cols[drag_end_index] = tcol; + + old_flags = tbl->cols[drag_end_index].flags; + + if (drag_end_index < tbl->n_cols - 1) { + khm_int32 tflags = tbl->cols[drag_end_index + 1].flags; + + if (tflags & KHUI_CW_COL_GROUP) { + tbl->cols[drag_end_index].flags |= KHUI_CW_COL_GROUP; + } + + if ((tflags & (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC)) && + !(old_flags & (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC))) + tbl->cols[drag_end_index].flags |= KHUI_CW_COL_SORT_INC; + } + + if (drag_end_index > 0) { + khm_int32 tflags = tbl->cols[drag_end_index - 1].flags; + + if (!(tflags & KHUI_CW_COL_GROUP)) + tbl->cols[drag_end_index].flags &= ~KHUI_CW_COL_GROUP; + + if (!(tflags & (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC))) + tbl->cols[drag_end_index].flags &= + ~(KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC); + } + + if (old_flags != tbl->cols[drag_end_index].flags) { + cw_hditem_from_tbl_col(&tbl->cols[drag_end_index], &hi); + hi.mask = HDI_FORMAT; + Header_SetItem(tbl->hwnd_header, ph->iItem, &hi); + } + + if ((old_flags ^ tbl->cols[drag_end_index].flags) & + KHUI_CW_COL_GROUP) + tbl->flags |= KHUI_CW_TBL_COL_DIRTY; + + for (i=0; i < tbl->n_cols; i++) { + if (tbl->cols[i].attr_id < 0) + continue; + + if (tbl->cols[i].flags & + (KHUI_CW_COL_GROUP | + KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC)) + tbl->cols[i].sort_index = sort_index++; else - return FALSE; + break; } - case HDN_TRACK: - case HDN_ENDTRACK: - { - int width; - hi.mask = HDI_ORDER; - Header_GetItem(ph->hdr.hwndFrom, ph->iItem, &hi); - Header_GetItemRect(ph->hdr.hwndFrom, ph->iItem, &r); - width = r.right - r.left; - if(width != tbl->cols[hi.iOrder].width) { - tbl->cols[hi.iOrder].width = width; - cw_update_extents(tbl, TRUE); - InvalidateRect(tbl->hwnd, NULL, FALSE); + tbl->flags |= KHUI_CW_TBL_CUSTVIEW; + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, FALSE); + + return FALSE; + } + break; + + case HDN_ITEMCLICK: + { + int idx; + int hidx; + + hi.mask = HDI_ORDER; + Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); + idx = hi.iOrder; + + if (idx == 0 || idx >= tbl->n_cols) + return FALSE; + + if (tbl->cols[idx].flags & + (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC)) { + + tbl->cols[idx].flags ^= + (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC); + + cw_hditem_from_tbl_col(&tbl->cols[idx], &hi); + hi.mask = HDI_FORMAT; + Header_SetItem(tbl->hwnd_header, ph->iItem, &hi); + + } else { + int i; + int sort_idx = 0; + + for (i=0; i <= idx; i++) { + if (tbl->cols[i].attr_id < 0) + continue; + + if (!(tbl->flags & + (KHUI_CW_COL_SORT_INC | KHUI_CW_COL_SORT_DEC))) { + tbl->cols[i].flags |= KHUI_CW_COL_SORT_INC; + + cw_hditem_from_tbl_col(&tbl->cols[i], &hi); + hi.mask = HDI_FORMAT; + hidx = Header_OrderToIndex(tbl->hwnd_header, i); + Header_SetItem(tbl->hwnd_header, hidx, &hi); + } + + tbl->cols[i].sort_index = sort_idx++; } } - break; - case NM_CUSTOMDRAW: - { - LPNMCUSTOMDRAW cd; - int idx; - - cd = (LPNMCUSTOMDRAW) ph; - switch(cd->dwDrawStage) - { - case CDDS_PREPAINT: - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - return CDRF_NOTIFYPOSTPAINT; - - case CDDS_ITEMPOSTPAINT: - if(cd->lItemlParam == CW_CA_FLAGS) - idx = IDB_WDG_FLAG; - else if(cd->lItemlParam == CW_CA_TYPEICON) - idx = IDB_WDG_CREDTYPE; - else - idx = -1; + tbl->flags |= KHUI_CW_TBL_CUSTVIEW; + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, FALSE); + + } + break; + + case HDN_ITEMDBLCLICK: + { + int idx; + int hidx; - khui_ilist_draw_id(tbl->ilist, idx, cd->hdc, cd->rc.left, cd->rc.top, 0); - return 0; + hi.mask = HDI_ORDER; + Header_GetItem(tbl->hwnd_header, ph->iItem, &hi); + idx = hi.iOrder; + + if (idx == 0 || idx >= tbl->n_cols) + return FALSE; + + if (tbl->cols[idx].flags & KHUI_CW_COL_GROUP) { + /* we are removing grouping from this level */ + + int i; + + for (i=idx; i < tbl->n_cols; i++) { + if (!(tbl->cols[i].flags & + (KHUI_CW_COL_GROUP | + KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC))) + break; + + tbl->cols[i].flags &= + ~(KHUI_CW_COL_GROUP | + KHUI_CW_COL_SORT_DEC | + KHUI_CW_COL_SORT_INC); + + cw_hditem_from_tbl_col(&tbl->cols[idx], &hi); + hi.mask = HDI_FORMAT; + hidx = Header_OrderToIndex(tbl->hwnd_header, i); + Header_SetItem(tbl->hwnd_header, hidx, &hi); + } + + } else { + int i; + int sort_index = 0; + + for (i=0; i <= idx; i++) { + if (tbl->cols[i].attr_id < 0) + continue; + + if (!(tbl->cols[i].flags & KHUI_CW_COL_GROUP)) { + tbl->cols[i].flags |= KHUI_CW_COL_GROUP; + + if (!(tbl->cols[i].flags & + (KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC))) + tbl->cols[i].flags |= KHUI_CW_COL_SORT_INC; + + cw_hditem_from_tbl_col(&tbl->cols[i], &hi); + hi.mask = HDI_FORMAT; + hidx = Header_OrderToIndex(tbl->hwnd_header, i); + Header_SetItem(tbl->hwnd_header, hidx, &hi); + } + + tbl->cols[i].sort_index = sort_index++; } } - break; + + tbl->flags |= KHUI_CW_TBL_COL_DIRTY; + tbl->flags |= KHUI_CW_TBL_CUSTVIEW; + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, FALSE); + } + break; + + case NM_CUSTOMDRAW: + { + LPNMCUSTOMDRAW cd; + int idx; + + cd = (LPNMCUSTOMDRAW) ph; + switch(cd->dwDrawStage) { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + return CDRF_NOTIFYPOSTPAINT; + + case CDDS_ITEMPOSTPAINT: + if(cd->lItemlParam == CW_CA_FLAGS) + idx = IDB_WDG_FLAG; + else if(cd->lItemlParam == CW_CA_TYPEICON) + idx = IDB_WDG_CREDTYPE; + else + idx = -1; + + khui_ilist_draw_id(tbl->ilist, idx, cd->hdc, cd->rc.left, cd->rc.top, 0); + return 0; + } + } + break; } return 0; } @@ -1572,6 +2081,7 @@ cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) kmq_subscribe_hwnd(KMSG_CRED, hwnd); kmq_subscribe_hwnd(KMSG_KCDB, hwnd); + kmq_subscribe_hwnd(KMSG_KMM, hwnd); /* freed in cw_wm_destroy */ tbl = PMALLOC(sizeof(*tbl)); @@ -1584,12 +2094,15 @@ cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) SetWindowLongPtr(hwnd, 0, (LONG_PTR) tbl); #pragma warning(pop) + cw_refresh_attribs(hwnd); + tbl->hwnd_header = CreateWindowEx( 0, WC_HEADER, (LPWSTR) NULL, WS_CHILD | HDS_BUTTONS | - HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK + HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK | + HDS_DRAGDROP #if (_WIN32_WINNT >= 0x501) | ((IS_COMMCTL6())?HDS_FLAT:0) #endif @@ -1627,16 +2140,19 @@ cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return DefWindowProc(hwnd, uMsg, wParam, lParam); } -LRESULT +LRESULT cw_wm_destroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { khui_credwnd_tbl * tbl; kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); kmq_unsubscribe_hwnd(KMSG_KCDB, hwnd); + kmq_unsubscribe_hwnd(KMSG_KMM, hwnd); tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + cw_save_view(tbl, NULL); + cw_unload_view(tbl); PFREE(tbl); @@ -1814,7 +2330,7 @@ cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) khui_ilist_draw_id(tbl->ilist, IDB_FLAG_CRITICAL, hdc, x, y, 0); } else if(flag == CW_EXPSTATE_EXPIRED) { khui_ilist_draw_id(tbl->ilist, IDB_FLAG_EXPIRED, hdc, x, y, 0); - } else { + } else if(!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { khm_int32 flags; if (KHM_SUCCEEDED(kcdb_cred_get_flags((khm_handle) tbl->rows[i].data, &flags)) && @@ -1823,6 +2339,11 @@ cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) IDB_FLAG_RENEW, hdc, x, y, 0); + } else { + khui_ilist_draw_id(tbl->ilist, + IDB_TK_SM, + hdc, + x, y, 0); } } } @@ -1944,6 +2465,7 @@ cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); kmq_wm_begin(lParam, &m); + if(m->type == KMSG_CRED) { switch (m->subtype) { case KMSG_CRED_ROOTDELTA: @@ -1982,7 +2504,173 @@ cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) InvalidateRect(hwnd, NULL, FALSE); } + else if (m->subtype == KMSG_KCDB_ATTRIB && + (m->uparam == KCDB_OP_INSERT || + m->uparam == KCDB_OP_DELETE)) { + cw_refresh_attribs(hwnd); + } + } else if (m->type == KMSG_KMM && + m->subtype == KMSG_KMM_I_DONE) { + + if (tbl->flags & KHUI_CW_TBL_COLSKIP) { + wchar_t cname[KCONF_MAXCCH_NAME]; + khm_size cb; + + cname[0] = L'\0'; + + if (tbl->csp_view) { + cb = sizeof(cname); + khc_get_config_space_name(tbl->csp_view, + cname, + &cb); + } + + cw_unload_view(tbl); + + cw_load_view(tbl, ((cname[0])?cname: NULL), hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + } + + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_ACTIVATE) { + /* a column selector menu item was activated */ + + khm_int32 attr_id; + khm_int32 action; + khui_action * paction; + int i; + int first_non_fixed = -1; + + action = m->uparam; + paction = khui_find_action(action); + + if (paction == NULL) + goto _skip_action; + + attr_id = (khm_int32)(INT_PTR) paction->data; + + if (attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + goto _skip_action; + + for (i=0; i < tbl->n_cols; i++) { + if (tbl->cols[i].attr_id >= 0 && + first_non_fixed == -1) + first_non_fixed = i; + + if (tbl->cols[i].attr_id == attr_id) + break; + } + + if (first_non_fixed == i && + i == tbl->n_cols - 1) { + /* this is the only non-fixed column. We don't allow + deleting it, althoguh there's nothing wrong with doing + so other than not being very useful. */ + goto _skip_action; + } + + if (i < tbl->n_cols) { + khm_int32 sort_index; + + /* we need to remove a column */ + + Header_DeleteItem(tbl->hwnd_header, i); + sort_index = tbl->cols[i].sort_index; + + if (tbl->cols[i].title) + PFREE(tbl->cols[i].title); + tbl->cols[i].title = NULL; + + if (i < tbl->n_cols - 1) { + MoveMemory(&tbl->cols[i], &tbl->cols[i+1], + sizeof(tbl->cols[0]) * (tbl->n_cols - (i + 1))); + } + tbl->n_cols--; + + /* fix the sort index */ + if (sort_index >= 0) { + for (i=0; i < tbl->n_cols; i++) { + if (tbl->cols[i].sort_index > sort_index) + tbl->cols[i].sort_index--; + } + } + + tbl->flags |= KHUI_CW_TBL_COL_DIRTY; + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_action(attr_to_action[attr_id], FALSE); + + tbl->flags |= KHUI_CW_TBL_CUSTVIEW; + + } else { + /* we need to add a column */ + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + khm_size cb; + khm_int32 idx = tbl->n_cols; + HDITEM hi; + + /* for now, we only allow KHUI_CW_COL_INITIAL columns */ + if (tbl->n_rows == tbl->n_total_rows) + goto _skip_action; + + cb = sizeof(buf); + if (KHM_FAILED(kcdb_attrib_describe(attr_id, + buf, + &cb, + KCDB_TS_SHORT))) + goto _skip_action; + + tbl->cols[idx].attr_id = attr_id; + tbl->cols[idx].width = 100; + tbl->cols[idx].x = -1; + tbl->cols[idx].flags = 0; + tbl->cols[idx].sort_index = -1; + tbl->cols[idx].title = PMALLOC(cb); +#ifdef DEBUG + assert(tbl->cols[idx].title); +#endif + if (!tbl->cols[idx].title) + goto _skip_action; + + StringCbCopy(tbl->cols[idx].title, + cb, + buf); + + tbl->n_cols++; + + cw_hditem_from_tbl_col(&(tbl->cols[idx]), &hi); + Header_InsertItem(tbl->hwnd_header, 512, &hi); + + tbl->flags |= KHUI_CW_TBL_COL_DIRTY; + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_action(attr_to_action[attr_id], TRUE); + + tbl->flags |= KHUI_CW_TBL_CUSTVIEW; + } + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + + _skip_action: + ; } + return kmq_wm_end(m, rv); } @@ -2013,7 +2701,7 @@ cw_select_outline(khui_credwnd_outline * o, static void cw_unselect_all(khui_credwnd_tbl * tbl) { - khm_size i; + int i; for(i=0; in_rows; i++) { tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; @@ -2069,7 +2757,7 @@ cw_update_outline_selection_state(khui_credwnd_tbl * tbl, static void cw_update_selection_state(khui_credwnd_tbl * tbl) { - khm_size i; + int i; cw_select_outline_level(tbl->outline, FALSE); @@ -2219,7 +2907,7 @@ cw_set_row_context(khui_credwnd_tbl * tbl, int row) static void cw_select_all(khui_credwnd_tbl * tbl) { - khm_size i; + int i; for(i=0; in_rows; i++) { tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; @@ -2307,7 +2995,6 @@ cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) (select)?KCDB_CRED_FLAG_SELECTED:0, KCDB_CRED_FLAG_SELECTED); } - } } else if (extend) { int range_begin; @@ -2349,7 +3036,7 @@ cw_toggle_outline_state(khui_credwnd_tbl * tbl, old_range_begin = o->start; old_range_end = o->start + o->length - 1; - + o->flags ^= KHUI_CW_O_EXPAND; cw_update_outline(tbl); @@ -2448,7 +3135,7 @@ cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) (nm_row != tbl->mouse_row)) { nm_state &= ~CW_MOUSE_WMASK; } - + if(!(nm_state & CW_MOUSE_LDOWN) && (tbl->mouse_state & CW_MOUSE_LDOWN) && tbl->mouse_row == nm_row) { @@ -2490,6 +3177,15 @@ cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } else { /* click on a row */ cw_select_row(tbl, nm_row, wParam); + + if (tbl->mouse_col == nm_col && + nm_col >= 0 && + tbl->cols[nm_col].attr_id == CW_CA_FLAGS && + !(tbl->rows[nm_row].flags & KHUI_CW_ROW_HEADER)) { + /* clicked on a cred icon */ + + cw_properties(hwnd); + } } } @@ -3270,6 +3966,7 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case KHUI_ACTION_LAYOUT_ID: { + cw_save_view(tbl, NULL); cw_unload_view(tbl); cw_load_view(tbl, L"ByIdentity", hwnd); @@ -3288,6 +3985,7 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case KHUI_ACTION_LAYOUT_LOC: { + cw_save_view(tbl, NULL); cw_unload_view(tbl); cw_load_view(tbl, L"ByLocation", hwnd); @@ -3300,7 +3998,47 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) InvalidateRect(tbl->hwnd, NULL, TRUE); khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), - KHUI_ACTION_LAYOUT_LOC); + KHUI_ACTION_LAYOUT_LOC); + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + } + break; + + case KHUI_ACTION_LAYOUT_TYPE: + { + cw_save_view(tbl, NULL); + cw_unload_view(tbl); + + cw_load_view(tbl, L"ByType", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_TYPE); + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + } + break; + + case KHUI_ACTION_LAYOUT_CUST: + { + cw_save_view(tbl, NULL); + cw_unload_view(tbl); + + cw_load_view(tbl, L"Custom_0", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_CUST); kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); } break; @@ -3337,6 +4075,33 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } break; + case KHUI_PACTION_PGUP_EXTEND: + case KHUI_PACTION_PGUP: + { + khm_int32 new_row; + WPARAM wp; + RECT r; + + if (LOWORD(wParam) == KHUI_PACTION_PGUP_EXTEND) + wp = MK_SHIFT; + else + wp = 0; + + GetClientRect(hwnd, &r); + + new_row = tbl->cursor_row - + ((r.bottom - r.top) - tbl->header_height) / tbl->cell_height; + + if (new_row < 0) + new_row = 0; + if (new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + break; + case KHUI_PACTION_DOWN: case KHUI_PACTION_DOWN_EXTEND: case KHUI_PACTION_DOWN_TOGGLE: @@ -3368,6 +4133,33 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } break; + case KHUI_PACTION_PGDN_EXTEND: + case KHUI_PACTION_PGDN: + { + khm_int32 new_row; + RECT r; + WPARAM wp; + + if (LOWORD(wParam) == KHUI_PACTION_PGDN_EXTEND) + wp = MK_SHIFT; + else + wp = 0; + + GetClientRect(hwnd, &r); + + new_row = tbl->cursor_row + + ((r.bottom - r.top) - tbl->header_height) / tbl->cell_height; + + if (new_row < 0) + new_row = 0; + if (new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + break; + case KHUI_PACTION_SELALL: { cw_select_all(tbl); @@ -3439,6 +4231,8 @@ cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } r++; + if (r >= (int) tbl->n_rows) + r = (int)tbl->n_rows - 1; cw_select_row(tbl, r, 0); } @@ -3465,6 +4259,15 @@ cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) x += tbl->scr_left - r.left; y += tbl->scr_top - tbl->header_height - r.top; + if (y < 0) { + /* context menu for header control */ + khm_menu_show_panel(KHUI_MENU_CWHEADER_CTX, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); + + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + row = y / tbl->cell_height; if(row < 0 || row >= (int) tbl->n_rows) @@ -3591,18 +4394,25 @@ khm_unregister_credwnd_class(void) { HWND khm_create_credwnd(HWND parent) { RECT r; + HWND hwnd; + + ZeroMemory(attr_to_action, sizeof(attr_to_action)); + GetClientRect(parent, &r); - return CreateWindowEx( - 0, - MAKEINTATOM(khui_credwnd_cls), - L"", - WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, - r.left, - r.top, - r.right - r.left, - r.bottom - r.top, - parent, - NULL, - khm_hInstance, - NULL); + + hwnd = CreateWindowEx + (0, + MAKEINTATOM(khui_credwnd_cls), + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, + r.left, + r.top, + r.right - r.left, + r.bottom - r.top, + parent, + NULL, + khm_hInstance, + NULL); + + return hwnd; } diff --git a/src/windows/identity/ui/credwnd.h b/src/windows/identity/ui/credwnd.h index 33e00bacb..0c1e766b5 100644 --- a/src/windows/identity/ui/credwnd.h +++ b/src/windows/identity/ui/credwnd.h @@ -34,12 +34,12 @@ extern khm_int32 khui_cw_flag_id; /* The expiration states */ -#define CW_EXPSTATE_NONE 0 -#define CW_EXPSTATE_WARN 1024 -#define CW_EXPSTATE_CRITICAL 2048 -#define CW_EXPSTATE_EXPIRED 3072 +#define CW_EXPSTATE_NONE 0x00000000 +#define CW_EXPSTATE_WARN 0x00000400 +#define CW_EXPSTATE_CRITICAL 0x00000800 +#define CW_EXPSTATE_EXPIRED 0x00000c00 -#define CW_EXPSTATE_MASK 3072 +#define CW_EXPSTATE_MASK 0x00000c00 typedef struct khui_credwnd_outline_t { khm_int32 flags; /* combination of KHUI_CW_O_* */ @@ -61,12 +61,12 @@ typedef struct khui_credwnd_outline_t { TDCL(struct khui_credwnd_outline_t); } khui_credwnd_outline; -#define KHUI_CW_O_EXPAND 0x00000001 -#define KHUI_CW_O_STICKY 0x00000002 -#define KHUI_CW_O_VISIBLE 0x00000004 -#define KHUI_CW_O_SHOWFLAG 0x00000008 -#define KHUI_CW_O_SELECTED 0x00000010 -#define KHUI_CW_O_DATAALLOC 0x00000020 +#define KHUI_CW_O_EXPAND 0x00000001 +#define KHUI_CW_O_STICKY 0x00000002 +#define KHUI_CW_O_VISIBLE 0x00000004 +#define KHUI_CW_O_SHOWFLAG 0x00000008 +#define KHUI_CW_O_SELECTED 0x00000010 +#define KHUI_CW_O_DATAALLOC 0x00000020 typedef struct khui_credwnd_row_t { khm_int32 flags; @@ -76,10 +76,10 @@ typedef struct khui_credwnd_row_t { khm_size idx_end; } khui_credwnd_row; -#define KHUI_CW_ROW_CRED 2 -#define KHUI_CW_ROW_HEADER 4 -#define KHUI_CW_ROW_TIMERSET 8 -#define KHUI_CW_ROW_SELECTED 16 +#define KHUI_CW_ROW_CRED 0x00000002 +#define KHUI_CW_ROW_HEADER 0x00000004 +#define KHUI_CW_ROW_TIMERSET 0x00000008 +#define KHUI_CW_ROW_SELECTED 0x00000010 /* row allocation */ /* initial number of rows to be allocated */ @@ -102,13 +102,13 @@ typedef struct khui_credwnd_col_t { /* allocation increment, if we run out of space */ #define KHUI_CW_COL_INCREMENT 16 -#define KHUI_CW_COL_AUTOSIZE 1 -#define KHUI_CW_COL_SORT_INC 2 -#define KHUI_CW_COL_SORT_DEC 4 -#define KHUI_CW_COL_GROUP 8 -#define KHUI_CW_COL_FIXED_WIDTH 16 -#define KHUI_CW_COL_FIXED_POS 32 -#define KHUI_CW_COL_META 64 +#define KHUI_CW_COL_AUTOSIZE 0x00000001 +#define KHUI_CW_COL_SORT_INC 0x00000002 +#define KHUI_CW_COL_SORT_DEC 0x00000004 +#define KHUI_CW_COL_GROUP 0x00000008 +#define KHUI_CW_COL_FIXED_WIDTH 0x00000010 +#define KHUI_CW_COL_FIXED_POS 0x00000020 +#define KHUI_CW_COL_META 0x00000040 /* Custom column attributes (are not kcdb attributes) */ #define CW_CA_FLAGS -1 @@ -122,6 +122,9 @@ typedef struct khui_credwnd_col_t { typedef struct khui_credwnd_tbl_t { HWND hwnd; /* the window that this table belongs to */ + khm_handle csp_view; /* handle to the configuration space + that defined the view */ + khm_int32 scr_top; /* screen units */ khm_int32 scr_left; /* screen units */ khm_int32 ext_width; /* screen units */ @@ -134,19 +137,19 @@ typedef struct khui_credwnd_tbl_t { khui_credwnd_col * cols; /* n_cols elements */ khui_credwnd_row * rows; /* n_rows elements */ - khm_size n_cols; - khm_size n_total_cols; /* number of columns actually + int n_cols; + int n_total_cols; /* number of columns actually allocated in cols */ - khm_size n_rows; - khm_size n_total_rows; /* number of rows actually allocated + int n_rows; + int n_total_rows; /* number of rows actually allocated in rows */ khui_credwnd_outline * outline; khm_int32 flags; /* combo of KHUI_CW_TBL_* */ - khm_int32 cursor_row; /* cursor and selection */ - khm_int32 anchor_row; /* anchor, for range selections */ + int cursor_row; /* cursor and selection */ + int anchor_row; /* anchor, for range selections */ /* view parameters */ khm_int32 hpad; @@ -204,6 +207,8 @@ typedef struct khui_credwnd_tbl_t { #define KHUI_CW_TBL_COL_DIRTY 0x00000002 #define KHUI_CW_TBL_ROW_DIRTY 0x00000004 #define KHUI_CW_TBL_ACTIVE 0x00000100 +#define KHUI_CW_TBL_CUSTVIEW 0x00000200 +#define KHUI_CW_TBL_COLSKIP 0x00000400 /* mouse_state constants */ #define CW_MOUSE_NONE 0x00000000 /* nothing interesting */ diff --git a/src/windows/identity/ui/debugfuncs.c b/src/windows/identity/ui/debugfuncs.c new file mode 100644 index 000000000..b18ef42bb --- /dev/null +++ b/src/windows/identity/ui/debugfuncs.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2005 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 + +#if DEBUG +#include +#endif + +#define LOGFILENAME "nidmdbg.log" + +CRITICAL_SECTION cs_log; +FILE * logfile = NULL; +BOOL log_started = FALSE; + +wchar_t * +severity_string(kherr_severity severity) { + switch(severity) { + case KHERR_FATAL: + return L"FATAL"; + + case KHERR_ERROR: + return L"ERROR"; + + case KHERR_WARNING: + return L"Warning"; + + case KHERR_INFO: + return L"Info"; + + case KHERR_DEBUG_3: + return L"Debug(3)"; + + case KHERR_DEBUG_2: + return L"Debug(2)"; + + case KHERR_DEBUG_1: + return L"Debug(1)"; + + case KHERR_NONE: + return L"(None)"; + + default: + return L"(Unknown severity)"; + } +} + +void +fprint_systime(FILE * f, SYSTEMTIME *psystime) { + fprintf(logfile, + "%d-%d-%d %02d:%02d:%02d.%03d", + + (int) psystime->wYear, + (int) psystime->wMonth, + (int) psystime->wDay, + + (int) psystime->wHour, + (int) psystime->wMinute, + (int) psystime->wSecond, + (int) psystime->wMilliseconds); +} + +void KHMAPI +debug_event_handler(enum kherr_ctx_event e, + kherr_context * c) { + kherr_event * evt; + + EnterCriticalSection(&cs_log); + + if (!logfile) + goto _done; + + if (e == KHERR_CTX_BEGIN) { + SYSTEMTIME systime; + + GetSystemTime(&systime); + fprintf(logfile, + "%d\t", + c->serial); + + fprint_systime(logfile, &systime); + + fprintf(logfile, + "\t<< Context begin --\n"); + + } else if (e == KHERR_CTX_DESCRIBE) { + evt = kherr_get_desc_event(c); + if (evt) { + kherr_evaluate_event(evt); + fprintf(logfile, + "%d\t Description: %S\n", + c->serial, + (evt->long_desc)? evt->long_desc: evt->short_desc); + } + } else if (e == KHERR_CTX_END) { + SYSTEMTIME systime; + + fprintf(logfile, + "%d\t", + c->serial); + + GetSystemTime(&systime); + fprint_systime(logfile, &systime); + + fprintf(logfile, + "\t>> Context end --\n"); + + } else if (e == KHERR_CTX_EVTCOMMIT) { + evt = kherr_get_last_event(c); + if (evt && (evt->short_desc || evt->long_desc)) { + SYSTEMTIME systime; + + kherr_evaluate_event(evt); + FileTimeToSystemTime(&evt->time_ft, &systime); + + fprintf(logfile, + "%d[%d](%S)\t", + c->serial, + evt->thread_id, + (evt->facility ? evt->facility: L"")); + + fprint_systime(logfile, &systime); + + fprintf(logfile, + "\t%S: %S %S%S%S %S%S%S\n", + + severity_string(evt->severity), + + (evt->short_desc ? evt->short_desc: L""), + + (evt->short_desc ? L"(":L""), + (evt->long_desc ? evt->long_desc: L""), + (evt->short_desc ? L")":L""), + + (evt->suggestion ? L"[":L""), + (evt->suggestion ? evt->suggestion: L""), + (evt->suggestion ? L"]":L"") + ); + } + } + + _done: + + LeaveCriticalSection(&cs_log); +} + +void khm_get_file_log_path(khm_size cb_buf, wchar_t * buf) { +#ifdef DEBUG + assert(cb_buf > sizeof(wchar_t)); +#endif + *buf = L'\0'; + + GetTempPath((DWORD) cb_buf / sizeof(wchar_t), buf); + + StringCbCat(buf, cb_buf, _T(LOGFILENAME)); +} + +void khm_start_file_log(void) { + wchar_t temppath[MAX_PATH]; + khm_handle cs_cw = NULL; + khm_int32 t = 0; + + EnterCriticalSection(&cs_log); + + if (log_started) + goto _done; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", 0, &cs_cw))) + goto _done; + + if (KHM_FAILED(khc_read_int32(cs_cw, L"LogToFile", &t)) || + !t) + goto _done; + + khm_get_file_log_path(sizeof(temppath), temppath); + + logfile = _wfopen(temppath, L"w"); + + kherr_add_ctx_handler(debug_event_handler, + KHERR_CTX_BEGIN | + KHERR_CTX_END | + KHERR_CTX_DESCRIBE | + KHERR_CTX_EVTCOMMIT, + 0); + + log_started = TRUE; + + _done: + if (cs_cw) + khc_close_space(cs_cw); + + LeaveCriticalSection(&cs_log); +} + +void khm_stop_file_log(void) { + + EnterCriticalSection(&cs_log); + + if (!log_started) + goto _done; + + kherr_remove_ctx_handler(debug_event_handler, 0); + + if (logfile) + fclose (logfile); + logfile = NULL; + + log_started = FALSE; + + _done: + LeaveCriticalSection(&cs_log); +} + +void khm_init_debug(void) { + InitializeCriticalSection(&cs_log); + + khm_start_file_log(); +} + +void khm_exit_debug(void) { + khm_stop_file_log(); + + DeleteCriticalSection(&cs_log); +} diff --git a/src/windows/identity/ui/debugfuncs.h b/src/windows/identity/ui/debugfuncs.h new file mode 100644 index 000000000..4c378a3a1 --- /dev/null +++ b/src/windows/identity/ui/debugfuncs.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 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 __NETIDMGR_DEBUGFUNCS_H +#define __NETIDMGR_DEBUGFUNCS_H + +void khm_init_debug(void); +void khm_exit_debug(void); + +void khm_start_file_log(void); +void khm_stop_file_log(void); +void khm_get_file_log_path(khm_size cb_buf, wchar_t * buf); + +#endif diff --git a/src/windows/identity/ui/images/app_notify_none.ico b/src/windows/identity/ui/images/app_notify_none.ico index 8dcb29e7a66f097ad2f67b181bb352fb2421d3d9..cf60a3e6a38b22c96abf1af201a0452e212eeb26 100644 GIT binary patch literal 2862 zcmeHJOG{%}5H53#iP5xiNbF9JCb`2bdecL%{0H*~W;YB>Z)VXjn}J!hs7O{49nfJG ziXzeoDu{^aN)e3@!u5$SeBv|W`~8g1>aT8cLuVLtF~h7p;k)P7sqFh~CH?zy}EL?@e?@^UDh!{@9B@CipQB z3i9QC(q5h3N=Aq*VWa*jmV!ccgS??pUK2RQ&1A)Xo z5}+s%y;Wz#{V~4}2fZ+433`zx3l^&YkN$#~v8n_W=2ayzPu95I_zQ9?&15oBad9z) zLLu7R+@ywv2AY|fp^AzMy1cxk&dyHC&(Ei^u`xP4JfxPE7Fu3jrrO$CDl03ahldC1 z>+7T3+*~RxEv2EMA==&DrKYAPT3A@1>gsB`xw)b4?rth7Dx%5BNjg0}rM9*L9fC@mH@9!^!w zc;&OYqH>zWt*WnlS+AqA%avwPRbQ6J6qOaPD@RqcJXRYN7Ps4OS6r&dN4Cp`Y!bJq9R{-s0tE%5FMdt}~qFJ)ryv`~*lTNi8fa0dm9@YTu@Lj3*IN-7r=uW!xBSHO%0EZj>dfo@BI9n zudc2bb%KwMj#$P-9v&V(1h)iuE8ME8Dn`BFj*bpSjbYRyJ!bJ6i9~e1jEM~y6MNuF zzTO#J)FnL!U-D7s;{2VR9TprPAG3@beDNz>$suYb@9pjBe$LL$^m&GVS$jAf*5i|P z7<_|^{PM`ih|U)u#@es1ule@&mRDC-d1+~h#g6ze_~KW%{r&y=-pPI$IX8UY-QDrx z;v&z^&N6B=qn^k41{XQyxw*N7*bU$J_xFt2&*S6c`ka-Ol{jDg3U_L1O1Ew7+n2tD zFW-iIU((Od&&T=A&CP$+*Vl7vYb*Em_VPb{I}(TN9qt;8dxY)_>n{f00#s5`@&oQA z$FRlI)6)rgl3dE38*7pEOP)dd5%36K8onb(V`F2RrfDIpQ$wya%+-)@4g0R`@9%4f uLBoGR!+%2qMgBvn!u?lGc^{@E+~)}QIl_I8aGxXG=N^F{x*$dGbDsfUb5*DS literal 25214 zcmeHv30#j^+yBYFjGZJTQT8NcoseWF*)w)Rk%UUfPQwf{F_{S=BZO3v3hgEBixz2< zHkGuHZN~NgUia_!i<#$r=6T-F`@H}6{rvyWJ#*aM=RV8#T<1F1b*}4N_fH5V(Ol^0 zw8g!VSl>hlXCZ{Ty6m~Mfe@dN*S4+fxv!EC#mxoE3zTmruC^AUbxSTUe{Lp(Ul%Sf zdtTpIh-Dgz^6KKMrVvqm6y@=Za+Wg{<<-UdMnWhr6QVCLpbN1AiE;h;Lbdv9FaL#q z_R9a*D}UIFjF6BJLHr*7ko*slKaebg-~P>Y#MXA}-((`g&e73Ph<5eex3Q9yvPHg? zQoDAFIz3Q|FI!aD`-l7^vV2t7hkQjtJx&~vTC%mZbv*LNd|Q5jd^<<+xqKS}LRr48 zW82U9d+4n#S3r4NyS++^=9>}c;|1s2ItqDyQ;^^tGVEmK9l0l5N_LJX9ML{{;D78K z_et3eF-FI~%~z7L9UZ0eTuWYlq%8l0l+SNL3AEExUR<7!3ZNYFnX-KGz-$F~BX1%TWs435T4$lsS}QG(LA@~XuD;h z5IvC36`0P7d>$_TmMZ)q|A=VF*;0is%R3&}BV|iH*SCXKWx2ARkuQx4*?-P=l<@p1 z-w|~Gd-*3A|DVfqhLkU1m%8Q=OP9p|iiZ;tC1m-{&`bR#8yG)+o)CWG{1Z}J;1AA_ zU+4pU@eAaC@j?zjp5IJf8g0nwAuIp6f+GK&e6iM7P|#1FU*D1t!$()~A?tXKLZCkVAsFwlq=caa2zFfRuoy#6k%#oV}CFJj!Q>5o+vJ8GENiKZx{EjL4mzPux z|Aa_85y2~&S8p36UbUQfwf>jVUepgk!rD**qJ~%-a=k&se9qIaj`V+%&%r9vCEIgg z|6#WmO!f}^R?E84%GS0@iQe(us)uy915>;^VP$(njN?1@2Fw(=gLq%uo7(b>LgP1; zW)@3A67%4grJb185TXRCHpO5YBK_rmd+|13X|GaM!+a&ClMd1fB;Mct&BZf>t3iVX z!ug=JhzWBNCPum#oAdY??4=(m?on`UqX+2BNH>Oe`=k z66ufQgqg_<5gzU>^mK=b1XpX3mf|BeuU;*#oj)xC{QN|A+EdY>y|Os6f1l{9+*xFL zxro=VD}=e8nsBhT7Lj3L!cs$7g!l!C82_`Pzp{qt*Px*o*-J}&sLK@lO=b!IANC51 z88gJSi&w<*#fycH(?Q|s;USV@<3-`~0x?9bo2V+Q5LsDq;`_r#MM6xFs3&CSKQ{{6(*{u;vF{bvyt6e0?9pNn&+e-Urr)QJZ- zuZX&e8nI;NEMcUfCc}Ekwd` zdlBW~BnlGTao;aKq(=!OJtN@&S_JvIi(F?1;d;tRD7SBqc?c4@K_0?ztbvH}a1nKt z#loO<12MWq6A|cfRJfV;7YE1o76}O+qS(VmcX+_W=}K_HDxIx%g#VcMd#h(5JVc)Gg@AJj{Xi4rQUTZ@>( z<{}FiQ~cb-Zc9tCOmCRjZ>lX^9ZZG0^HE_iP+RQZXf6VLJjJ7+D3KE5CoKE-7jY3@ zB0W7&L8!<^Q{{3`tYJ;gNr zX~IZ%v?$9>7qvAtB0D=u)M4%2a`zO0K7m35eB2zktBT7-SYVLokH399-Nmw5Mq<3G zvUrl7E`C0KT&VHbJYB^PHtWSmtcjSQKoRKfD&m5|L^0-Twvmx&t*k8cR5e6taj~@i zS;qWluC-$a;u_yjWQJ!-*Qh^S;iIrs`SO~xa?zrS$0^@yZmnB#=gyrfeTS~~mxIHQ zC-+R|?EbR+^kIuC-p`)B`oYq=B}-64U*ADi12>evS72i}W!e`NrcYO0Ic19a@NQq} zFW?GQsK6aK@HJ$}y~{S$n{E&MT;ZE)16P#&d+40(d$LUW&u@x-QX z{j=K6@6?{VkQHB%ts2@h0&UGC8e!^SpDfVj(P=2r;2n0A5Xn*+t)9kciro)!6OlX&Pb;)7&SL)QkB^DAZ*N&*Yihc< zv-+Sotr;_hbh+!eaQzf6Jy=%WP~F&A?_J=!bss17D@6I0EmzL5wO#yp{gGSdGq!E> z^*=xRJ<1PeG@N!B8ykO$9Xar{+ppKVbNQ8}i*0SSA0OQF48^xCJutLFD$k{X$KGU< zv2jzk`SaU;=)O^x2*nq5Zd{|S-XOX)ifb)BV6t(H{S+Q457*uh>&19i*8GoFdv!LJ z6RqsLNMn&@jot8mw*sZ|X5Gtm=c%A&{D=QlY{rbynHxC&(DP3^dT772bWufxUCpds zeNT^+%6Bj+FP}Hhm`Q_cFxnrZV-+}Zi{8YEpHLpsWcFx}Z6>L;gHhGU6X@&BwfJXzx)mt{66};?3;I^4FU$jV{hvw(an>tTc!QP}=Wz&|C zBVSK6ZpG!f_>`4%PPRK1-CoOFi!PXK)J17r^9-dPbgET$-5eP>ccSscR;{>v;*=?! zEiLogI5yYRB=^E%hR@}v>Na9PhJ#hCC(RF>t7D7`L=qn^vb5|RHZuDfv`$1tM@F8d`9A~t^vOrBu&~hN6Uw84ygW-4bWjh7M<4_ANe{kXls74?W-=Pe+Q+|t z56~xhc@rCB?xMat%M~5~Mo>QhrqCx{ZXX@k*c4*PeJ;z^8tkd{uznyT1gVtxmm*9)m_Y5KO0qaer`HjJ`lA15TlV0_rW7Z(U$AK2e& z8saFh4TMdxY=MdR@Zp2lykG(B)dj-Z+EN4s1&J}}%fsD8WTmHwVHz63#l=N;yZuKv+*R64;K3hfz_mqhK@dUjsUZ#5spsiRKf5p3?ApvMCrKiKK2 zq7`W3>g+5m_4^A0eSHz*gmL{95oY8ur0^J)(mnvEZkPj z!kmVQlqf%OTwepUDn_05LK(K78T<-rO8@Kz_fRA0xuK`54S7ANJ|xT3KNGxS8dEQ#Ita7 za~1C@Ys68^ZC|vz1N669wMxJk5y#-`xaH|7jvhWNF1fjhGVoyxa3!TAh(J$2ao;ac zOjA=6haL7yHgRG?f^c(j6?s{?qByr$WG1AGo9-T^t zTh^A=;!Rl%)=Gj%Nr)2Xon3@J)`7lOf8g{H4&di3tdmbzCo$l4Ys`K722I3h@a}PI zbCx)NG%EjPN~B+XOGEsvK8!nZ>^B`9o#`t=L$8O1hT3e*Et;w*u&P6?W_5XtNJ`Kd z+ZF{vZEX5(G-$P5VfXoTc-6})^;}OUU2Xs```UEP)hHc*Z)qs@wqU1w=5FD;!j`Qu0~u(sP)H@C!T4XCZI$8@$wbAO*j0d3lxp1kX0m@U!6 zt!{~l!@H{}37s;2pKH^)`IS~hMH_ZaeEaqu(L%SxHEW(dX?Ny_leyEUPq+ET(tVV6 zdESy4mv&`ZhYT12BVV|~G z=U*a%LO{l&h{8r0sXsxqxwQ`4%`qE;IwoiHDY z_j(n@yKAR?yWqa+eOhVMDR_0q42z6KsYPA`w@dFw=2t~N*6sPQfr#0XSUm-Rhu!# zO*^d)zC3tvr|Pt{39+3A*0fr*h$zphy6FJpcO9!tO{-Q12M1r?(WzQ9t)1Gzf&E*h z;=Q(}U0PgR$7NMjbAvCxzr16I^gca4`R9(Qsi{QMRQeAqEgkm7Wv-@{Z0x^8+oEGf zyeGfeX3;I8CJdT3Vu@O;c6tAzRx_8Vsafr`vasvekvS}S(-ZmYWbJa3qE@BjXTB>i zeQL!8_&w34C+!BQOk1Lc_guf!d{`S(qc+-k)poM?ga%aP?Q;X>!?=J^tGsIYd(5)b zzq|u(00kbjk+-iX^tRa~203O5e|kYdI%K$;Fo2I+4Z4T-A~x`~ z9zA*#KDjVahP?pmR2ViwTeUrOv9st8eFuXddLv!hC-^}|V!JKcL*}x+cY@B)gI;90 z?BnSMJ(VllH%Pj=J=#%)&$UkMXT8RH7y7~ja$Z+gSA2kuHG_P0f}SmduC|5`J`j5W zS65e20KH%j-ORGQ1u#TmA7Hc0K+@wH@Rjr4AO&)o<+&F21Fp~|YS4eYr>KFBVtwW8 z?dmsml zgY~X9aI((R2F^NQbOF9H=%gB8`}g&43jC`nVDS&GUgO&?w=h+o+Ej1!TrR3PN^7NB zyZLK+_B7OOi|1CFCWE@^s;a74G+8~MdmoGTGj)~@G3snFw&jS9BUENs^wL?{rAHf! zWh2I!5AN8kg++^{{TolWn9^*-HyyhV>Da=e%Zf1z&2)z~)0j4~L-!%QEVRcgRI;#W zI6}YghOQmD_p%s1c}|1oqS1(TeJ4y>&|$Vk>rS(JtEi0oX5PH78Z=nY-eOSel|u(~ zY}Raq%2z7~4OOi{?P4gB{f$)Tql9D6tYmtT{wM9atUp7j^n~?JA|g-Bd}ZTMruC zO`YDodq=-GJHG^)WB1}c%xj>}nUtd<{8|lQiM=97pkRt8{)1%-JdU!vWB7!0) zH8q?HYinl$o4Lk0QfAjvYNB4v3wQmLoAw zwLnsMVDRT3FUt)UWM#354(;7f_ilskq2Ux49!ZbFLMSEn0cCjoOghSfMghxY^&T`y ztt-aRl_r6HhN>zw4rvV1aNrt@c^SZTM(W37Q338Qsx$!k{gDP@%$#)4#*iM}NVlgJ zO&vCZuot1H=^6Aa=P5n#aibNB7ncCAJCIrW6mq{N6|dh#Tg*6a14-VMJZBj7hg-;;pfi07fJ3K<}cW&FUaqr!6l8uK{t zJOF?5cn0Em5YwHpcL#2?q1!`^hWG4EGluC(_;WL}s30$&!f(5i#av_Bwb7yuXV?#b z_%PBOBt-p60Th3ji)~ihXbZ4!-Mp2yZ`n>eZSCpoPp2s^ERy0MMbgu!@f2=lM(w~u zhU#hF&vP_^zf9QB8( zYtYD^nlycg4t@OikzmVH(X;226&p@l=FXyxGiT5N%ZP`ZY3LFx7%t2V-7_NNbd7-j#*}yIzkTz}+kma0NWNx~M5DW3LQ^$_Hws#>JA$3JUBsL??V+Rh>?Q7@h*|R6Kcbqz*xHJb7)v=Z#izWd3gszZFz&{GO5eq`Y zF-FF%E5|+ryfU=A8VyrZr{Nks3GpyAs&{V^N=<1{LqTV@Eur6j`;DIGJ*Sd_Vk*hc zqGOovjnih(7US8pdiG2*orU>WWA*|2ZeH6zAo1GPM*3>!_8l_pxbL>zDZ_5>K>O_X z(t(}(=;%HN^0|G9o~C+JFW~R4)QG0^1a{C=A3QM*bR7%)%s(SlRUuD-7ubiXF`pwr z&Wu#=Ny9XHkxp+78q-sax(Frejl*&ts2=N!Re(F@(YGO?5 z=FFyVaNx6K_H5d?Y85S6xUdKd;3lwJA@x4!uusD8z%*yvJNMB3U3=-^o&%6chiLz9 z2Xa6A6Z!ewpcLN=G`@|Xah=-H1n|%p@bVbU!5GNaQMhv&fix6roAD3DdeH^1k5*SF zJdu(jz%K7um3n!3t;L8HP+y4>!?tOH4-vK(fe?NVD=n!PmMY?s#jr^}2 zqlDvjG`dAo8Uxx72VaboaI4a2jA1nX9?iTCtiv!iUaM-5pA8!}rhW|@l2!W_bamZK zdKT|aIk^#(kq}Oqi7`}|n?sM|lPNtumEbd@bH@(QrWw=7cK%%2WHN_V%$Y;WOiXCS z+_|)Jz6sfE*ieuE>`%YYe$afM{T@09x*u{lK#qG4(zp8$lH>kEbmG`|bo=^s^0{)E zZr(UYrMJH$hXFmIm#`ky)M$iS4;qcNFsi!>=nq~3=1~~iu&(OVs8I`Q)2I<0Fdax) z*B$ApuQR2k`BPGiFC{#Pq|~TrN_`YfIcaH-*U^yMF%UUwmm64>`0lG1kvj?hu0(@v-8j;AO2UB60R zw|=Fn2WRN;Xie(Z32PD9M|9&cfbV-CVLZA$G-v?E(YSGA+Nj=Ka8dHN3jzA*szDtn-3{6B!aRY$B_A=d9-DYG4Ri&HS#&&ajaP| zkL)*ZuE+nYs~erc9P9(_kL;7t{9EAu{_wZ-{h_1e`tup`_x7fMTOQ

    k3sxyV0h8 z14y-t8tH+*NAcQ(OdO`s1M)=;dxmZj_6v�Jk?KB_&Y&gD^@AzC#JY_b4$ugpwja z`-hJx?NK~s#3sq`hei=%)F=_-dG(@zPHf#k>!(kLE|cM3H5atUe3&hmPrJXs?+*M| zFJ306?|#6VWqt?UF&`(sJqG-abou;63h?ovKrc@U4)vz0m@72CaWfjI)(bLRoksQ4 zfFA7y>>8xjS(#db?zb0C0B-2Nhu#zt^njwnLZJ`CDLx_sI{hIfKa8Qo=r~Gwlt`(u z$rApU&`659A4*S>A5&FDG2M3BPpc+RCUf9l3%WD@we#lDx`hjA*QU?(zXt3czg{Jr zKhU=a9f94EzB_V^et`b^4r94>?FQWg{`=myC^Ymg-Q2&1x;JS8-PwmmXsY85?7cLp zb?YuP3fQBMY@p<1@N!Hf#e@V=Joq9u0{fAN(ZKwOQh+@L*pp%sDJ3R}9>=9nPI?+W z0^fvT|5%b+K(ES6Dg4);Xw|f-WCs2>W4@n<`+|kEZm}s@tyoddKi4i@q3f5g(XA^t z$@%+}&{^No@x$NK502l_FHR@vKK67$K3;VH?q!O+dxoZWZcl0*AvZOlKQ(*N2<%}R zfR`4x_=>WfcT04S4iBTa&|s{`hm;Tv+)=Thc|33L&?E4FSz!rP zz9^;G>t|@qjF}SeubXQ^Yaol(nJ%XJGiG3Kw5}fib$1W)yn2&-u6xmC*Gu4;W7s>K z0RCfi^}HJe-SMShKVOOryG^HU%?O()G8!;YqWe(n!G`wgNr+>kkWFhT1#2`i+yi_b zO39#mLPQ+s9!JTHJ32v1sld#M$H4eA)1UE6V~~$STD$VR z?36?*;Qd=p0n#&iQSyx3PdUUbo%?_bi?gD#l{Ac z?}=SBNmrMaOac9Ydz_XgeXZG>Mr&wEc1^@d3#zLtr>de7dQ)0KZ_27DH}whjG%1wy zD1jbBM=|!tko5}LlZL-JFFPfZe*gFZ_;V=#Ne(@S4HI(Hot6Q&>8#o0uwn_7=cdyO z(7dFefL<0AQT2<@`0x3E?!EyO9B?20hx-(MKZvfoU80|%&#ql|q4*HMiDSmo zlIe`UH+V;r^!sQ^`*^nPPcVs(V(yU^`cRb z|JcJ)rSCC%TUSf37=K9xy(_PxcQ0${-K*DBQTRfVi_9za_`y3&e@-cw9|?bY7GYC)=>8Ku{LzMH0l%T%WLk=d-SK@jX>@;eBrQ^JrAh{k1=UsOQEg=nu$NL@StY$K zuckWSe*^q)tLx}B<{~2@Ra(D12FA_wXWhlJ>3!X6?AbEmgLp!DxlifhF$YQZn1Ww} zpa)6|iwNi3RL1sAA?ROHR?q*Ta=I(9Bjy16ox8B%f1!(~exQg5Pm1*TkyefvN+WfK zLvLw81`VXqJ^M5{Vx1q66fdio>E40NR**G(fBo%nX9v4s7sr9ReeHNAe8Mb)6o z>tbLp19rw=3EBfc)1UEwz<6pgwuFe7dfv%^?#fJfOc~H$N$_Lh%!ZO9@6*QlGie#@ z#l@2i=^pm%MUZQStQ(-;n2*ZPm%{#H?94N~|7P09MLnVikVTh%K1c3nT%i;Eu+IYi z%!lC5`;_WpLkEoqQna%bu$NM8X(82O&Aq|8t$p#5UQ27YR>EH=pM!V6{~mw8!y%8S5D9K!KmJ zM~7gq2>fxdDH5J4fCnF(FI z$8sIbHJVKGf&YQeRVv6Ypn`1ZH@S{3hAdLxe*`@vVaI+Y0Xm=ewGsEi$^G1~u#+!Q zAoic>NuX773ijqnSVPaKte_C<=owWO7f~hTO-)H9)k5aKf!ujhUPE;ikUcNofac(v z%C|@|9^yHuE_o^OP)029$2|sJ9z%9!lDEe#3W5H~NK2=i=YJsM2@}Y~Xd-L^U+Cs% z&<)UU7(*fEp(y`(J^tA6XxMFRd&W`{^gY`Xv7ynhLEQ=GjO2&C(Gy_LhK-sFA0^93 zPSqtZs0O->YcQN8?q?}`i=E-KE}X%3sWiRkz-*qM+U&w_mk|&tQ5%BjBIHh z@-T*HPxI>WCnrLugFn(z(NL0u}_c_`=}HN=i>C~<9qnDpP*gP^hqYLGi@`lSBD*SOl+CH}L&oQXT*a)w;bxzfc87wPh^m+2bzogVI& zVb{BmxAzUY?c+mt{jkRi2qeS>!VV6FUW=fI4L1 z<9OI;Nst}j0oKpi7zfXRf`1SK)9BL0i>F-Ao}-KBFVN*nkUN*LcCTF{PtO~KxHj_j z!5$lWAkaU69z4K)BP0YiSvVmsfudpG#>PT+B_v4rIYj)Kj=37F&M{)wbV;A_b4H0(VxQqp8&;CaAWP~gX1 zy1Z_98D4NbUwR39Pj}$wIk@3*ojh;CHui#j2D=~tXJq&9V~-siOo$7iNYIJrASNb; z;^X6CyJJtEk|NDP26U3dC)wH395DXp&!5-NK|#(Fsa{NY1ZW(O{Y@6t)<722)FMVJ zL()S@Y`ew4=49VuBKRA8^du!+ng@WE{GW38((V53+g;r+T@G~z4_$S?O4qRu^}KO| zyl;7t?`>c5XCAtD??25$JO_W~A>PlI7Ci?qXVA;CQmU>7_S#zLM(jJV7cYS=krbBz zK4O_J^RuKw4)R)fiaGd?@XN=dwP=k&(H4;DldeNkT>X*`mW z^cVj4-+BFa#)vik+=YBkqjv&oO>VZ_RFKoAML!6PN6le6~cPDT@5JS1J1M~9IXgFfjhPUlN z(-GS;xjV=zo(HD@iqwk5smO2nG|EQW1B76Bi7>(&RT=9muCIBLw^Ld1`TFuYM}qFmTf2tvP5Vpq$?;cv zkR~H_*loW9@iDgKfEW{w(ct(Pd=Dh;<#R&adAZYY#8*t|i5R!8-AKP1$HV{w#>%lU zocO$M6yiv@e=a{+vkO&MRZDxv^9S~l^@0Utzut_j)|%1wO`AT>oiir|<#r?Wbv$%X zinGA)oX|n^dkE?1funTk+!<*ADltGe_u<-zwSlK&AyW2ltzOOq?iuG&kXL;m6|keE}hHI zY~6q^E*UG?Xl!RD!bZe*ayY|vL2SSRa#**Hwyj@J+s)UL{iaRz{a?J`N=I=%%`qCs zIJN;8I8N*i&c5#X`eLtIOc{rklUm~@;Bhq?quzzaAwEF6i!2^sWc%jy(DOL@g-y*i zI&8Ys2=;qDqIlT9Ia!HhiT-U@t)}f8){(9G2E@Hs)%Sn(>Qy=ie=v`o&&ZDnLR3D#CYqGz9TB`n`LRM(57bnD@-+Rc~7-M~5Q@Axw(>NXK3}7XHHw z(Bajq5<0SGDQ);>Iqg8-J1s5AX5HsFl^d|bZs45zM87Iyp2jEPpkHiCyPHvX`Cw#8JXQ_OKEgQS+ z+>XaymS0TIa}l!#ze+}G49!QZ!(7B`lxM|DwpdO1=X25k@EG%2@Vy6g6?*8x>7OYa z{jAj1KD z5l^8h(IV)~R>`mT=0!DCJS#?=7S0C1bJE!je9TM}_GLfIeJ1tq?sSxvBfcg%;*P`% zii4J_^k zFRm1bb3*oU<>qFP)8c-F&65;sT~!_`+3s)Qv7V#QyQ;- zoUdnQJf=0qGiesiY?5L_B_G*yoYj;R6!EwuKUYjN{G2!^V1H6nP&oa1&W-N-_)!LY z8GJs%zNh@4pQtu3RN}ig;H|eW(ErP7+1U{=yhs1F@Lls6w(R`nG2OxWe{xbHo!Dnb zGiT1El!S+puk?8i{H6Jy&spN(SCry#fH^KahOW56H|}u@zWr4A#-C6XpPRsE!G4z- z@SJpx1)uo4O7`c!md;YxpI=k@QtCfl?z_K@xRn^h;0617kO|I+v$Nr6hri|-;uya4 z)2Ak5zTkt(Oist#Jtluo_>ykj#hFMJ&J}TXiL;xxW$?k5^SKB2_lAC}!PyP^{H^+f zELFXi&JP|#2J$%t``+1a9SAv=nh-~ig09K@)bQ_eJaWMoe)gdIL6YAm8~#l8mnr-= z{5Sh<{@KL72KG^~zlddr*L6?2e(5U3AYMETzTb5Cc(T&iuMR(X)@MKeg|ioCopL() z%H;;y6uhl6UZm_3$j0l{ZZ@-VP7EYTK2^{lxI0H@|f0k{|nrJ>Xka^v!-@Mc)d4F#F@# zhotbu^I1f_55BmNGSlFb#yQQ)7sV3a6crXpe(MBa;J6C~1_l4)E?s-}>}lY2(`)5b z_D^5GPTufMvtN|`y6jhHpR|Iud>)|irPq&N?n7r8qwpKDzmR=XyoS;czn6r)eG2yY z_?EwZ{VDoa-18pisocDNJ&S#t>=$IeEc?Y3=Mp@}U(%n?BJ$wJSNNV3{WIUN-<2`2 zkBt3H97B?T^_GmY6ZH3Y{bXpbnXk96%b(|;X~6T(XA0~GV;ZoWVjm>y8a@Y6_#T;m zxqluzuU*E#=RCYG#&1h-|9|P{!k8PuZ^ri0|I-({3^2fPNIj6)F8hOhi06OFwHK{~ zAhBQL9nx=dUj-Y+i1m>?6#u|a!MNC0&}h*f7@+q^*o!gt0MsCO2L?N!Z9 zn>OXFUAY?Hf!IoG((A?rYKF3Uu)#;bE^VtMdE01wuTGSnmLU0lAsc?fw+(KnKhDn1 zE@#We&9uvQ2V&?CNpk*>(Libsy9)2Adut^sN(+U>YqJ(Hs}1$XQjGl4@vf))c@kiL#45DEYpXY zcl4s51o6a(LxF5zy@GK|_3>LNIUa}!zH{r2B#*bRok3to&>>wK`y1>DKGwdM;%L|& zVj0DLl-;{`OZC0Hys~|jGvhjA^$$*?=K|I9hxcfRv| zKQ~U@ILR_h3UiRj$Vg?#!9B+?1^7-)rT3XB43qObgLSgXFwKV;=Gy~go!%F|z%Vbp zn6!SFVXhrXTF0}mz05F~csv7t$MKiK;K$vgolQG(D4pINmVS6JmXe;I_vz)blAo^r zSpVlOxlB4cJ!LVQ!{JbsGA%v-{Ab^km;HS0>YcjV@~+O=nQ5y9YvC&8(W4j6ee!i_ zaq@dsiv?@j+uPNqw6yfg<)z6l+N_pnB!a~%Wjg!JyHgY62EEShb`K8?b}Qs6<-E)3 zOvK|f&I<@I32SO{V%4DccszIO>w0?>YL&|EcExue-g)J}u>n@Iyu@+bG8j;K{igF$aGvnD6UA>Dlme*5LR1RA44p zhW;Ytw?UT>x`_T)!`=f=iHlVJrAh{O_=aD%i6 zhrmkK5()gixw*L){b8#Fc|c6aLkSRlR#p~r$}O)rTTonETbmpxZ~*IexxDM^KA(^1 z7Y-Bs1PYcaBgRhAWu4Ob`B{+wH0K9+N`_DHT`Ver074QZfoL?saSnLX>s^PuaKlcG z5(&t@7hEClLT3?tsy{&ADE$89=OuuqG*GXlr9~tFoPBK#R)rH$X}{ke63P^h#r8$- z>+M-ktHcCQf|{BdgaryQjmpZ(M1tKhY9tc2S}ky&)5*crJWt#N4rE4)Dhh+xfj;oK zAI&BbAntojO>kmvd1W#I>PQ;_#Wk6XFu22RM?Yg`phW|L01LapGJDaV4i3Kg{s*ES z0L^?mr>Lk%wAG30Z4!w@Kqn#d~{?u>x-}c)nAO7 zUO=&TvvNfJ;Y1MVR#sM54Q4YqY@EX(dJ2AoV?<#PI?yM^$1Ywf{B~QLbGFer4MG_wCYR``ebJ|@;sbqaYYSserBuQeTCGN}*O`n)Y(vyi6XT{Kq zik+Xs#75q@$)Rg0Ju-lI3_r-DFTK zdgdmG)dpcp)b{R6uv1VdORl+e5*7>q)9BNPjLwYxV6uvrV{NXldW@47b)XXgYT0-`7aT>Q^CPX(kbw6suY`6{Sq=e)NUTLnnol-|DgJkNQ~ zbI$u-+IQ(7&v9$G^_)Vn2|w3y&b1sD$8p@IP15(BYdG$}D;)k#`!;a-8#wN#b@aRR zJ^odW+xD9LyMoKd=NC82zbm+S-248!9Jdo=VhC;zF2Y&*E8(|nUZW`6{(8<@MQqIR zh;u1tQ+~VftNQxiSJj$|GId9Lo7!%(DQ9M;kEZM2QN*77CgR7`l$75uUQpl2zNXex zma97+x2r`v?U~u1uHUia^og(4KO`p!7)QW30>%+Ajv(6Y0`3t2AR=AAb;s$LIxqH0uT|=5Dv!ZEdKpyLex#NigVjr^Z~a z$b~@QZ8^c^FxpyMbk+e&x5wkL=3LKCsIJl`7!8J_ZueMZAP{&{emD5ZbITDxP)Bc1 zx5MdlIvzf#{s#%Dj0U|538;`jf*fQy0*wui9DTh#4&3WN0xBe+GIbeMNIiZfI*^Aw#F45fI=NlOr_IbTtUteFZ4p$?7Z=Cdc8?jpD z#sX92T<#YI|+@Z`x8w&)qXi?NNJ z9gp*uQ-BEY8R>sQraA*EE6TuRG{Uebg2OQawxL0YJah~`h~vZ7d(kIBqtU=5g8Qb3 zpr4VLpPvUT4I?u*HwV+xesDQQVFDAPeVB~P@AGLwOMuu42A*{}6SA*m0m=oXCB@L% zA}|Gxq$o4CE4J`jtu_eegPG}R21pA7VulQW6mgG@!NmADmS<8b z4JyJ)6C@$49GbZdUQu2KI$cK?0U~meuk|iTLJx@5nZ&b9`k=%?0<+-6nq#YB-N#u8 z$*^QnnFN)1C2*~#5^&DEM1cP={ukJH>MR46rJ*_%6chyAFFBup93vxWJSXcYGT#)M zZ#w9i0QzM$@S5r>=rS6@2%rae$jr=SZATmZj4NnqQ0y;27d ziMhGiCBucvPMH&U?ZXFv^Cyfz^cB7qZsp~%mO7G}_7Z_b*8h?M)B!`-y41#_4hP^A zL=rexaHjZtQumPCR|0=jR|mWHe-@^69FLjq+4&Lkwkm&rfF;pFphIORMXj7@@%KaGZuVv<=Y zcE=?1pj0ZKg9k?~BY+O??dbutxgQ3tR=^V-@T>^ygw?>?+gf43Vv)u_dSz+~TNhPg zrlo<#W(hA%y3lqba9T8iOV06fN} zM3|bAuP_de*ozC4wcj?zIL3p`cyR$N0qX+1AE1f5v6K23=^^qE8kw~)mVm~(d=DX?&^&p5N5Ml6 W@!08$UZKk5e!hNf+1+iMhGZu{BxpPH(#WcozW-#!H%h*9BV-YinFWS$3i?RFf zG2zcu2Ccy`f*)!} z#=}dAM$iV#a71vh)Qh${5}L6_DLvq0)!GPS+W@9kO(bEcwOR;3BU*HTt&NF=*0Z9G zrZxr|+Sq^JenuMuvjzhhA$efLs-y8PwP7vz85q<;fcV@Q;zK}gbJ=)P#fWfKi7ez(6A4kCG}! zqt+^8)xlcrW~~xM5s9Y~V@*$`_7!T!KC6v=2GtWwgQDK09R~h(gO(v&h^Gkgq#>4Z9zz0Rh+-k|I|cq`rl+$5NlC06zIMaU zT==PjpFWAXtPp;V!OuGQHw6DW;9n{H^Yjg11@JG2`xnF9L!y`${F|bw41Ap#2>l7Eb>*&OKVI?I~)h>$#7AhDet zJ;}tj&G2#|=Su=Y+nM-Wz{q#8vqM^}tT?!{v*j8fyE1aZjpHlrNWj*LY=dpN2y74p z9^?KgB>{=O^1)@xmOb*=Z1R%x9Z3K_3hkBlN*)g!76Mj|HbQ`due2vVr4|uO`jS8> z3|KhNvz)Hv7J(>$oRkni5E!CWKeP6Bu(Wq14fK#z%AKtpX^1kicAaNGoeO|Zfs+8L z!N?B{g%L|fI89;6MgSu8zqzOR`HI@#+<8tqr_kBNNYXjQartV#Uj_vQ@V(j7(}TH( z$ML<~dA$ce!_XNZA|iq<_wwWC6Bl<+zOU1{!X5i5?Z*iT3Ct@dnV%EZuV2s41kS71 zGj}gkfP$wiZ~ve*XN-6Nj@?)`<*blvBS`8JNnzT{1A; zjBH#LoF1?dguTO!$kkHNLaAfsLP5?ec*ngfoCVq1DyV}I$UV-swo8^M+>97*YiyUy zo~;0wtLxIGg!=Go7Z5l7P}{=6#);KIAUrw7Av>sD7!cXxK?ark+$;5_Ws*4F468`|625bUJ*e~x=SHRYol<=4A9 zJB2!+diDCgzTW=+zK)LeuCC5rea}FDKQ4gl^*#7Z0{3p;#&!EMPG~|HAXke%HS-_% zZ~i6zt-Wt%W*obI?OJnFQ%lQDd^q;mvR6A@tg(IWsCgiq5lZT(wbc6K%g?;9K#06t)0 z0^^7X5D1D5B_w)ybhiZyp3C6>cz^%F%a$#EVK4gadhyBNP<$pc^%FRN?d<62zI98l z*HiWe2Pu2pgh-3*xd6{Neyq5-NR9$8a-#48b5DotMEE=e8sg#Mp|-YGlx27KEz|}o zK^ma3G30zAcy?AM<`f1OXtI^>Z{G=IVQ6FYzC(u&$@oBPxp@;+iXy})_xAP<@G%-4 z8JQIP)XAK(Yo!9;%!I(l^QD(wGQl5gYSN+b+S}Vu&pka_guZcx;kteSg+)AniTxX<-*#U8d{EePz-v6N%dfyKB!EX z5SfSbAk_Tzva*Vb8#UF{_4Rc+U87u16FmnwmMM5b^994i7aXxBj0_Ktj$-1B%9#f^ z{yM|rR$5YmlBle#sHv%LsISNNB+BX1#e(DMA7`W=&Cbj?m6M(K$*Hra^9#*LbtJ8AXCp#~|M7!i2)I(1SUJG~xy0 zix6Oo%BiVI;EN~lvCDjXI293{J)L*;(<>##S25ABuye1fku-2r2p-0%%7&2K{xy{y}z`3`Ou(&=Ktd}F;_Te$i{k_MN{DdB}a^l68-oUFZaB;-!A>IV?)~6X-kc?qE&4E^rzQe6O#Mi+lLEWGZi!U zoF3Ycuy-#c52d8wf;*F&@&Et; literal 0 HcmV?d00001 diff --git a/src/windows/identity/ui/images/cfg_plugin_err.ico b/src/windows/identity/ui/images/cfg_plugin_err.ico new file mode 100644 index 0000000000000000000000000000000000000000..1b1b4ee2e2046f33094256112192ae392f5bd9f6 GIT binary patch literal 8854 zcmeHM3sh9c86K6e>n;I#7y&WrCVC9M5-XlaPQYS94Op5(8&YWnB|U_ab+NPoVidP& zgSRGyHmR7B6r*W~L4=6%2pYr}DiQ=ldCB{2!uFe)yPM16u}RZ5r>FePy?6fk z|M}+s|M}<6?1hkN#GEWxFpE%XolZzFp0j3ge#taKd}a{Hsg#hzazY}^sGRd5_Yv~o z{SvtaAu%=*Ir^@cPskFeFTk}9*E9kE6B6NAtCrqz(~1?X$Y{}!mzPKMRF0cotms8X z&l{-p-$;=H1CvE**)uXypu@@{qvCpK1Nb;C;{_ux#8J60j20nE5cGmxKY|D4qvBwt zNF(3@qmKv<7F)riAxhX|(CPua5Ftbucs*c+7$Gt;QpA85yddn^%^M&F9}_8ra2_nx z9~SmV`KSr}i$Y9<5T)1CL8v~(pm;Ew@fa=mMOudfl^cwKOD24rUQQKgN6-i~32zX) zu+T{~_=M30111gWw;?|A#CwmvQJ?3o-JLfd*9@%;_|gj*{`E-<)dpN&;G%gjaU{K- z<~hyf1-Sl`d5$?@v>oHfP}`0evL}*3N8t`R zCXN36ek4SY?+Ib@kUdmg&6V^K0l8fyCnu8x1^AP?x+>xpok;TY&yt~`KH?UjA%_knlGM~x z@>Xmt@ekIJs;Y9**Vjc_T6CnSsDLc?2_R?B=8}Yj1TsE8Mlv(gNqKoWiH?pYU0q#7 zr_+&wf&$_d98QvxlZls?7s<`dC1Yb_BtHHv;-}dG{Zi<*qdkWNg@&R}9s1;xq@*O0 zo}Nk)6BCG=moMxtC4S-2u)7^L=fK`N;u)I?d-GxM5b+7pkZ=vPu?jZ!!NwNYSVTO1 z{bA!-*p^B5#=J&W1xFJPFCW+(Pa+V9;G%K(A3!|OKk3jRl1}}7D;BnBNFwuVoK(T5 zKKRoDe~REwDtsAdKE%U^Xc7v$lVNXWdOA6jm`KWDYZvUyg`GOs>64I43Sj3L?5u-* zL$I$M_Lagu58nWi5BqYMeKEu}G@5wAK0C(>$s|ryry}s}BB1^spzqIdu#=c+!phdt z23w`5A)7IQRjavN?xf%fTrPJq0y4S6(M)CTNE?}4VeRD4S#!l4OLIF%xvi76wXKuV z$;rW70nW@Ix3Y9}0@)}bqBk3*JtL)~9fPy-e%L{+wsm&%0L^xQ3RO@l&74rfaNZ9; zHAk&pYO{#i6KIY`rT`5FqlVaj*)mIqM`l9qrVyJc0#~47wc2vIod@I#7cH7KhY!!J zL6!DatCu@Wr}F!71wKL*Fg`Wc-kyT1)ec-9x*<@lo@q(t@Q_+)4>6Ui9BKcDl^bxM z%jBX0#LLxc6_+nlK4y?R+u9;5N+rbbU!_L)3Zj_GX=r)SXn#=w zp>Z%*J)oE_XCnfU13Af|04HG6vY%RdIVkK{546xxY3yulX%B9+bCtpoMpL(pg8+p0|L*RFbBFZ#-JR#ea|%717)U&)I4)kn_RFB40Jb-Kc(@VQ z@L0B&tJb)&GYmZgL_|c8#h!lbeB$it!S;1}u5iVEO84XV_;}(Olf=#mYu2n`X9CrV zHN@4^i=9#Ex#YFiqKPv-!{AJ^!p)O-`T7wJ&Jgt66T5dWS>@_Rf`WqB*@K>y=$U56 zjvd6=%b%Sm#>dBr24lIpy0Sg}!Bwun_aUo*2fLZ`nfY^+GMRFf`OKLQd_}D8Vl{zW?h%@QDw_Oz(4P0fx1=fhe~ds- zz|VdiwoQ2bcL)CVZdS(eqQWb>#>T?;BsAUO=oB4!2^jWbF#0MmUeWsj~bNkiVxU|8|AI7t+}6_ z1pc+sl6&A^IDfXX;sz8r{`InJz^6wLMyEc_zIgsz;=AvpBp*KcX%>trzg|{dReAGf zb9Z-lWn~2l>OI}vn2y`GJG;BOvNKP>&P(|hFm7#ajjpkwt+f@--WC5(v2Ug%e|)3- zdS^!m?+&Qmo}RwG-v0i+_V%{U&W_%m?t%V(6oB{ibmKD#%)4_3<<1w3z(N@ySBpM3 zu^;$v|2b~|zPB?oj^leVsHNp*V?({C@22ks?>3gj8w0blvH;%Ki*frg#K_19W(3H? z!@~mu{cWwcaBPB<8rIimj1LD-cxOM5`A29}V8373PR{cC#=oA<&dz4weS-r7zy~ab zz&yeOID%wD3h@@^-5oB1BrI#Nd(7;@9pgkkNmdp+!Urlj~!ghc;f%QoXE2;Gq*M~wJDYq@z7S&AgY zEcf>I4zM{I9T`Db0DdI-uoVB)$(*ulrBeL;`}e~t=@7ei?ULXRHZ|#xcx`R1$mi~E znn)M|esOTbT#A1>_cN?ADgH-ENk~G!?YoRF03VacmjGtAp`pIHsp(cr3l=io69m^XhY9ul^`Vz5bbv_|l7rxd&)=?%XMYv-bnV@9(d; zaihArs=lrc8wcK3#&qJ~m{7zVLx2EYc%`7WriQ+bx{(Y$aFgbPVfjci6W}1^{PnW3 zii#UG)z$U&bvj+6F`ZyJ2S>~i77mWZ1xx69!8EZK4u2<%3=fZvV&RM$BM)%=I>XDY zw4?+nQCV40Q&ZhgUytpHr_<$2`6tpp$w)tzotbeeC;Rkgr_PCC(wH@- z+(;)5>DSsy->67(<{DNjA0751ZE9<4%FC};RaU@vq*D`1C%y}O@P1;_2M0g?=)z?$uNL7APpzVk)9ItVbd5Kgn~@|)bxh*zPAn+A7P_&f5Jprmziz1G`fnT?5-Lmba&_`X}7p{KNq@WR^$tCjTm!H7r8^a6SSV1F1lgn?lyVtFAH>w#c zXoP5Td2{dHS6_L>W%X*KCMsaj2+`yczwa+7FkY%Zckwc*J4@HD`{NsLaLt47A3!nD zm-gj#r$^Vu@7o8>Bgx4qCi>V}um!9QkCS$M%KRO9TwL7KF&`Pb zKnI$6r%$7p=!4bk$5Ev1s6(^h@?{ihI{;U@dqO!aEzS9vO;UVlmX(!Z!*%}QW@9@l z*pb)z21@sRG(P_HMkwRe7Zw&KRlaK-29%T(L%FT3ZG-RgV5Q}um8 h!a`_*@Xo}0^Bx6fZ>f|YJa9JnIs|2tA8{IRZ1ZXp z^P2IIsHw)Wf@q;qF_fr85)E2v5ftjet=nHG%FLqiA1HqCJD1CMzH_*@tl~P`aHA5n zK2>?7@=ztq@IYDah>#Cd(XdKB9YKNt!GrU(Pj_QD9%zV z$aIgr*LxaF0{NW|9vkg9yc)3Ro|d0$v(Q3A5}oIj*gI-tlNCC})*Gylos$09AF zoLnI%F0sZgc>Dc~?u}ELloP5Jj(F~kQTW7FeNNLVAWTAmR1}h$yT2j$n8h!Qo-l=4Qz1Mhb;>Py7G-e*OhgI1!5g diff --git a/src/windows/identity/ui/khmapp.h b/src/windows/identity/ui/khmapp.h index 7f12c7ffa..203f5b02b 100644 --- a/src/windows/identity/ui/khmapp.h +++ b/src/windows/identity/ui/khmapp.h @@ -36,6 +36,7 @@ #define KHERR_HMODULE khm_hInstance #define KHERR_FACILITY khm_facility #define KHERR_FACILITY_ID 3 +#define NOEXPORT #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #include #include diff --git a/src/windows/identity/ui/lang/en_us/khapp.rc b/src/windows/identity/ui/lang/en_us/khapp.rc index b139effdb..0a746199b 100644 --- a/src/windows/identity/ui/lang/en_us/khapp.rc +++ b/src/windows/identity/ui/lang/en_us/khapp.rc @@ -68,6 +68,9 @@ IDI_ID ICON "..\\..\\images\\id.ico" IDI_APPICON_WARN ICON "..\\..\\images\\app_state_warn.ico" IDI_APPICON_EXP ICON "..\\..\\images\\app_state_exp.ico" IDI_APPICON_OK ICON "..\\..\\images\\app_state_ok.ico" +IDI_CFG_PLUGIN ICON "..\\..\\images\\cfg_plugin.ico" +IDI_CFG_PLUGIN_ERR ICON "..\\..\\images\\cfg_plugin_err.ico" +IDI_CFG_PLUGIN_DIS ICON "..\\..\\images\\cfg_plugin_dis.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -245,14 +248,13 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN LTEXT "Title",IDC_CFG_TITLE,0,0,357,20,SS_CENTERIMAGE CONTROL "",IDC_CFG_NODELIST,"SysTreeView32",TVS_HASBUTTONS | - TVS_HASLINES | TVS_LINESATROOT | WS_TABSTOP,0,20,100,182 + TVS_HASLINES | TVS_LINESATROOT | TVS_TRACKSELECT | + WS_TABSTOP | 0x800,0,20,100,182 LTEXT "Static",IDC_CFG_PANE,102,20,255,182,NOT WS_VISIBLE | WS_BORDER PUSHBUTTON "&Ok",IDOK,162,205,78,16 PUSHBUTTON "&Cancel",IDCANCEL,246,205,51,16 PUSHBUTTON "&Apply",IDAPPLY,303,205,51,16,WS_DISABLED - PUSHBUTTON "C&hange Summary ...",IDC_CFG_SUMMARY,3,205,76,16, - WS_DISABLED END IDD_CFG_GENERIC DIALOGEX 0, 0, 255, 182 @@ -267,22 +269,29 @@ IDD_CFG_GENERAL DIALOGEX 0, 0, 255, 182 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "Startup",IDC_CFG_STARTUP_GROUP,7,7,241,50 + GROUPBOX "Startup / Shutdown",IDC_CFG_STARTUP_GROUP,7,7,241,50 CONTROL "&Obtain new credentials at startup (if none are present)", IDC_CFG_AUTOINIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 16,22,196,10 + CONTROL "&Destroy all credentials on exit",IDC_CFG_DESTROYALL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,39,111,10 CONTROL "&Start NetIDMgr during Windows logon",IDC_CFG_AUTOSTART, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16, - 38,135,10 - GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,54 + "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | + WS_TABSTOP,16,48,135,10 + GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,85 CONTROL "&Run NetIDMgr in system tray after window close", IDC_CFG_KEEPRUNNING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,78,170,10 CONTROL "Monitor network connectivity",IDC_CFG_NETDETECT,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,16,96,106,10 + CONTROL "Log trace events to trace log at the following location:", + IDC_CFG_LOGTOFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 16,113,225,10 + EDITTEXT IDC_CFG_LOGPATH,16,127,225,14,ES_AUTOHSCROLL | + ES_READONLY CONTROL "A&utomatically import Windows logon identity", IDC_CFG_AUTOIMPORT,"Button",BS_AUTOCHECKBOX | NOT - WS_VISIBLE | WS_TABSTOP,16,147,165,10 + WS_VISIBLE | WS_TABSTOP,16,158,165,10 END IDD_CFG_IDENTITIES DIALOGEX 0, 0, 255, 182 @@ -300,45 +309,55 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "&Monitor credential expiration",IDC_NOTIF_MONITOR, - "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7, - 111,139,10 CONTROL "&Renew automatically at",IDC_NOTIF_RENEW,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,9,100,10 EDITTEXT IDC_NOTIF_RENEW_THR,122,7,126,14,ES_AUTOHSCROLL + CONTROL "Renew at &half life intervals when possible", + IDC_NOTIF_HALFLIFE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 48,27,148,10 CONTROL "Initial warning at",IDC_NOTIF_WARN1,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,31,100,10 - EDITTEXT IDC_NOTIF_WARN1_THR,122,29,126,14,ES_AUTOHSCROLL + BS_AUTOCHECKBOX | WS_TABSTOP,7,46,100,10 + EDITTEXT IDC_NOTIF_WARN1_THR,122,44,126,14,ES_AUTOHSCROLL CONTROL "Final warning at",IDC_NOTIF_WARN2,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,53,100,10 - EDITTEXT IDC_NOTIF_WARN2_THR,122,51,126,14,ES_AUTOHSCROLL + BS_AUTOCHECKBOX | WS_TABSTOP,7,68,100,10 + EDITTEXT IDC_NOTIF_WARN2_THR,122,66,126,14,ES_AUTOHSCROLL + CONTROL "&Monitor credential expiration",IDC_NOTIF_MONITOR, + "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7, + 103,139,10 END IDD_CFG_PLUGINS 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_PLUGINS,"SysListView32",LVS_REPORT | - LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,75,168 - GROUPBOX "Plugin",IDC_CFG_PLUGINGRP,86,7,162,103 - LTEXT "Description",IDC_CFG_LBL_DESC,90,20,36,8 - EDITTEXT IDC_CFG_DESC,134,17,109,14,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Status",IDC_CFG_LBL_STATE,90,38,22,8 - EDITTEXT IDC_CFG_STATE,134,35,109,14,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Depends on",IDC_CFG_LBL_DEPS,90,52,39,8 - LISTBOX IDC_CFG_DEPS,134,52,109,34,LBS_SORT | - LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Enable",IDC_CFG_ENABLE,134,90,50,14 - PUSHBUTTON "Disable",IDC_CFG_DISABLE,193,90,50,14 - GROUPBOX "Provided by",IDC_CFG_PROVGRP,86,111,162,47 - LTEXT "Module",IDC_CFG_LBL_MOD,90,124,24,8 - EDITTEXT IDC_CFG_MODULE,134,121,109,14,ES_AUTOHSCROLL | + LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,7,7,75,168 + ICON IDI_CFG_PLUGIN,IDC_CFG_ICON,87,11,20,20 + EDITTEXT IDC_CFG_DESC,128,7,120,30,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY - LTEXT "Vendor",IDC_CFG_LBL_VEN,90,142,24,8 - EDITTEXT IDC_CFG_VENDOR,133,139,110,14,ES_AUTOHSCROLL | + LTEXT "&Module",IDC_CFG_LBL_MOD,87,43,24,8 + EDITTEXT IDC_CFG_MODULE,128,43,120,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Register new plugin ...",IDC_CFG_REGISTER,163,161,85,14, + LTEXT "&Version",IDC_STATIC,87,59,24,8 + EDITTEXT IDC_CFG_VERSION,128,59,120,12,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Ve&ndor",IDC_CFG_LBL_VEN,87,75,24,8 + EDITTEXT IDC_CFG_VENDOR,128,75,120,12,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "De&pends on",IDC_CFG_LBL_DEPS,87,93,39,8 + LISTBOX IDC_CFG_DEPS,128,93,120,34,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "&Status",IDC_CFG_LBL_STATE,87,129,22,8 + EDITTEXT IDC_CFG_STATE,128,129,120,12,ES_AUTOHSCROLL | + ES_READONLY + PUSHBUTTON "&Enable ...",IDC_CFG_ENABLE,128,144,50,14,WS_DISABLED + PUSHBUTTON "&Disable ...",IDC_CFG_DISABLE,198,144,50,14,WS_DISABLED + PUSHBUTTON "&Unregister plugin ...",IDC_CFG_UNREGISTER,87,161,72,14, WS_DISABLED + PUSHBUTTON "&Register new plugin ...",IDC_CFG_REGISTER,169,161,79, + 14,NOT WS_VISIBLE | WS_DISABLED END IDD_CFG_IDENTITY DIALOGEX 0, 0, 255, 182 @@ -483,10 +502,8 @@ BEGIN BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 248 - VERTGUIDE, 86 - VERTGUIDE, 90 - VERTGUIDE, 134 - VERTGUIDE, 243 + VERTGUIDE, 87 + VERTGUIDE, 128 TOPMARGIN, 7 BOTTOMMARGIN, 175 END @@ -554,7 +571,7 @@ BEGIN IDS_CFG_GENERAL_SHORT "General" IDS_ACTION_NEW_CRED "&New credentials ..." IDS_ACTION_PASSWD_ID "Change &password ..." - IDS_ACTION_CHOOSE_COLS "Choose columns ..." + IDS_ACTION_CHOOSE_COLS "View columns" IDS_ACTION_DEBUG_WINDOW "Debug window ..." IDS_ACTION_VIEW_REFRESH "Refresh" IDS_MENU_LAYOUT "Layout" @@ -693,6 +710,32 @@ BEGIN IDS_NC_ID_DEF "

    This identity is the default

    " IDS_NC_ID_WDEF "

    Will be the default. (Don't make default)

    " IDS_NC_ID_NDEF "

    Not default identity. (make default)

    " + IDS_PACTION_YES "&Yes" + IDS_PACTION_NO "&No" + IDS_PACTION_YESALL "Y&es to all" + IDS_PACTION_NOALL "N&o to all" + IDS_PACTION_KEEP "&Keep" + IDS_PACTION_REMOVE "&Remove" + IDS_PACTION_DISCARD "&Discard" +END + +STRINGTABLE +BEGIN + IDS_CFG_IT_MOD "Changes need to be applied" + IDS_CFG_IT_APP "Changes have been applied" + IDS_CFG_IT_NONE "No changes" + IDS_CFG_NODESC "(Description for plugin %s is not available)" + IDS_CFG_P_DELCNFT "About to disable plugin %s" + IDS_CFG_P_DELCNFM "Are you sure you want to disable plugin %s ?\n\nOnce disabled, the services provided by the plugin will no longer be available. In addition, any other plugins that depend on this plugin will also become non functional.\n\nNetIDMgr will need to be restarted for the plugin to be deactivated." + IDS_CFG_P_DELCNFS "The following plugins depend on this plugin : %s" + IDS_CFG_P_DELNDEP "No other plugins depend on this plugin." + IDS_CFG_P_ENBCNFT "About to enable plugin %s" + IDS_CFG_P_ENBCNFM "The plugin %s will be marked as enabled. The plugin will be come active the next time NetIDMgr is started." + IDS_PISTATE_FAILINIT "Failed to initialize" + IDS_CFG_P_UNRCNFT "Unregistering plugin %s" + IDS_CFG_P_UNRCNFM "Are you sure you want to unregister plugin %s? In addition to this plugin, any other plugins that are provided by the same module will also be unregistered.\n\nThe plugin will no longer be loaded for subsequent sessions of NetIDMgr." + IDS_CFG_P_UNRCNFS "Note that if the plugin was registered by a seprate installer, it should be unregistered by the same installer and not through NetIDMgr.\n\nThe following plugins will be unregistered: %s" + IDS_ACTION_LAYOUT_CUST "Custom" END #endif // English (U.S.) resources diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c index 6f7f9bd47..6987db3ef 100644 --- a/src/windows/identity/ui/main.c +++ b/src/windows/identity/ui/main.c @@ -26,6 +26,7 @@ #include #include +#include #if DEBUG #include @@ -38,6 +39,8 @@ khm_ui_4 khm_commctl_version = 0; khm_startup_options khm_startup; +khm_version app_version = {KH_VERSION_LIST}; + void khm_init_gui(void) { khui_init_actions(); khui_init_rescache(); @@ -45,9 +48,11 @@ void khm_init_gui(void) { khui_init_toolbar(); khm_init_notifier(); khm_init_config(); + khm_init_debug(); } void khm_exit_gui(void) { + khm_exit_debug(); khm_exit_config(); khm_exit_notifier(); khui_exit_toolbar(); @@ -127,6 +132,7 @@ void khm_register_window_classes(void) { ICC_HOTKEY_CLASS | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | + ICC_INTERNET_CLASSES | #if (_WIN32_WINNT >= 0x501) ((IS_COMMCTL6())? ICC_LINK_CLASS | @@ -319,42 +325,61 @@ BOOL khm_check_ps_message(LPMSG pmsg) { return FALSE; } -WPARAM khm_message_loop(void) { +static HACCEL ha_menu; + +WPARAM khm_message_loop_int(khm_boolean * p_exit) { int r; MSG msg; - HACCEL ha_menu; - ha_menu = khui_create_global_accel_table(); - while(r = GetMessage(&msg, NULL, 0,0)) { + while((r = GetMessage(&msg, NULL, 0,0)) && + (p_exit == NULL || *p_exit)) { if(r == -1) break; if(!khm_check_dlg_message(&msg) && - !khm_check_ps_message(&msg) && - !TranslateAccelerator(khm_hwnd_main, ha_menu, &msg)) { + !khm_check_ps_message(&msg) && + !TranslateAccelerator(khm_hwnd_main, ha_menu, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } - DestroyAcceleratorTable(ha_menu); + return msg.wParam; } +WPARAM khm_message_loop(void) { + WPARAM w; + ha_menu = khui_create_global_accel_table(); + w = khm_message_loop_int(NULL); + DestroyAcceleratorTable(ha_menu); + return w; +} + +/* Handles all context closures which have a signalled error state. + If the context is a top level context, then the errors are + displayed. */ void KHMAPI -khm_module_load_ctx_handler(enum kherr_ctx_event evt, - kherr_context * c) { +khm_err_ctx_completion_handler(enum kherr_ctx_event evt, + kherr_context * c) { kherr_event * e; khui_alert * a; + /* we only handle top level contexts here. For others, we allow + the child contexts to fold upward silently. */ + if (c->parent || !kherr_is_error_i(c)) + return; + for(e = kherr_get_first_event(c); e; e = kherr_get_next_event(e)) { + if (e->severity != KHERR_ERROR && e->severity != KHERR_WARNING) + continue; + kherr_evaluate_event(e); - if ((e->severity == KHERR_ERROR || - e->severity == KHERR_WARNING) && - e->short_desc && - e->long_desc) { + /* we only report errors if there is enough information to + present a message. */ + if (e->short_desc && e->long_desc) { khui_alert_create_empty(&a); @@ -369,9 +394,6 @@ khm_module_load_ctx_handler(enum kherr_ctx_event evt, khui_alert_release(a); } } - - kherr_remove_ctx_handler(khm_module_load_ctx_handler, - c->serial); } static wchar_t helpfile[MAX_PATH] = L""; @@ -405,19 +427,7 @@ HWND khm_html_help(HWND hwnd, wchar_t * suffix, } void khm_load_default_modules(void) { - kherr_context * c; - - _begin_task(KHERR_CF_TRANSITIVE); - kmm_load_default_modules(); - - c = kherr_peek_context(); - kherr_add_ctx_handler(khm_module_load_ctx_handler, - KHERR_CTX_END, - c->serial); - kherr_release_context(c); - - _end_task(); } int WINAPI WinMain(HINSTANCE hInstance, @@ -445,6 +455,8 @@ int WINAPI WinMain(HINSTANCE hInstance, khc_load_schema(NULL, schema_uiconfig); + _start_app: + if(!slave) { /* set this so that we don't accidently invoke an API that @@ -466,6 +478,10 @@ int WINAPI WinMain(HINSTANCE hInstance, kmq_set_completion_handler(KMSG_CRED, kmsg_cred_completion); + kherr_add_ctx_handler(khm_err_ctx_completion_handler, + KHERR_CTX_END, + 0); + /* load the standard plugins */ khm_load_default_modules(); @@ -478,6 +494,8 @@ int WINAPI WinMain(HINSTANCE hInstance, if (!khm_startup.no_main_window) khm_show_main_window(); + khm_refresh_config(); + rv = (int) khm_message_loop(); kmq_set_completion_handler(KMSG_CRED, NULL); @@ -497,6 +515,7 @@ int WINAPI WinMain(HINSTANCE hInstance, wchar_t mapname[256]; DWORD tid; void * xfer; + khm_query_app_version query_app_version; CloseHandle(h_appmutex); @@ -513,6 +532,58 @@ int WINAPI WinMain(HINSTANCE hInstance, if (!hwnd) return 2; + /* first check if the remote instance supports a version + query */ + + StringCbPrintf(mapname, sizeof(mapname), + QUERY_APP_VER_MAP_FMT, + (tid = GetCurrentThreadId())); + + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + 4096, + mapname); + + if (hmap == NULL) + return 3; + + xfer = MapViewOfFile(hmap, FILE_MAP_WRITE, 0, 0, + sizeof(query_app_version)); + + if (xfer) { + ZeroMemory(&query_app_version, sizeof(query_app_version)); + + query_app_version.magic = KHM_QUERY_APP_VER_MAGIC; + query_app_version.code = KHM_ERROR_NOT_IMPLEMENTED; + query_app_version.ver_caller = app_version; + + query_app_version.request_swap = TRUE; + + memcpy(xfer, &query_app_version, sizeof(query_app_version)); + + SendMessage(hwnd, WM_KHUI_QUERY_APP_VERSION, + 0, (LPARAM) tid); + + memcpy(&query_app_version, xfer, sizeof(query_app_version)); + + UnmapViewOfFile(xfer); + xfer = NULL; + } + + CloseHandle(hmap); + hmap = NULL; + + if (query_app_version.code == KHM_ERROR_SUCCESS && + query_app_version.request_swap) { + /* the request for swap was granted. We can now + initialize our instance as the master instance. */ + + slave = FALSE; + goto _start_app; + } + StringCbPrintf(mapname, sizeof(mapname), COMMANDLINE_MAP_FMT, (tid = GetCurrentThreadId())); @@ -546,7 +617,7 @@ int WINAPI WinMain(HINSTANCE hInstance, CloseHandle(hmap); } -#if 0 +#if defined(DEBUG) && ( defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL)) /* writes a report of memory leaks to the specified file. Should only be enabled on development versions. */ PDUMP("memleak.txt"); diff --git a/src/windows/identity/ui/mainmenu.c b/src/windows/identity/ui/mainmenu.c index 10270f2a0..fc3a64b0c 100644 --- a/src/windows/identity/ui/mainmenu.c +++ b/src/windows/identity/ui/mainmenu.c @@ -81,6 +81,8 @@ void add_action_to_menu(HMENU hm, khui_action * act, wchar_t buf[MAX_RES_STRING] = L""; wchar_t accel[MAX_RES_STRING] = L""; + assert(!act || act->cmd); + mii.cbSize = sizeof(mii); mii.fMask = 0; @@ -90,9 +92,13 @@ void add_action_to_menu(HMENU hm, khui_action * act, } else { khui_menu_def * def; - LoadString(khm_hInstance, - act->is_caption, - buf, ARRAYLENGTH(buf)); + if (act->caption) { + StringCbCopy(buf, sizeof(buf), act->caption); + } else { + LoadString(khm_hInstance, + act->is_caption, + buf, ARRAYLENGTH(buf)); + } if(khui_get_cmd_accel_string(act->cmd, accel, ARRAYLENGTH(accel))) { @@ -126,10 +132,12 @@ void add_action_to_menu(HMENU hm, khui_action * act, mii.hbmpItem = HBMMENU_CALLBACK; } - def = khui_find_menu(act->cmd); - if(def) { - mii.fMask |= MIIM_SUBMENU; - mii.hSubMenu = mm_create_menu_from_def(def, FALSE); + if (flags & KHUI_ACTIONREF_SUBMENU) { + def = khui_find_menu(act->cmd); + if(def) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = mm_create_menu_from_def(def, FALSE); + } } if(flags & KHUI_ACTIONREF_DEFAULT) @@ -153,6 +161,21 @@ static void refresh_menu_item(HMENU hm, khui_action * act, else { khui_menu_def * def; + /* first check if the menu item is there. Otherwise we need + to add it. */ + mii.fMask = MIIM_STATE; + if (!GetMenuItemInfo(hm, act->cmd, FALSE, &mii)) { + /* the 1000 is fairly arbitrary, but there should be much + less menu items on a menu anyway. If there are that + many items, the system would be unusable to the extent + that the order of the items would be the least of our + worries. */ + add_action_to_menu(hm, act, 1000, flags); + return; + } + + mii.fMask = 0; + if(act->state & KHUI_ACTIONSTATE_DISABLED) { mii.fMask |= MIIM_STATE; mii.fState = MFS_DISABLED; @@ -211,8 +234,8 @@ static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) { act = def->items; i = 0; - while((def->n_items == -1 && act->action != KHUI_MENU_END) || - (def->n_items >= 0 && i < (int) def->n_items)) { + while((!(def->state & KHUI_MENUSTATE_ALLOCD) && act->action != KHUI_MENU_END) || + ((def->state & KHUI_MENUSTATE_ALLOCD) && i < (int) def->n_items)) { add_action_to_menu(hm,khui_find_action(act->action),i,act->flags); act++; i++; } @@ -392,12 +415,15 @@ LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam) { id = LOWORD(wParam); act = khui_find_action(id); - if(act == NULL || act->is_tooltip == 0) + if(act == NULL || (act->is_tooltip == 0 && act->tooltip == NULL)) khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); else { - LoadString(khm_hInstance, - act->is_tooltip, - buf, ARRAYLENGTH(buf)); + if (act->tooltip) + StringCbCopy(buf, sizeof(buf), act->tooltip); + else + LoadString(khm_hInstance, + act->is_tooltip, + buf, ARRAYLENGTH(buf)); khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); } } @@ -607,9 +633,9 @@ void khm_menu_create_main(HWND parent) { khui_main_menu_toolbar = hwtb; SendMessage(hwtb, - TB_BUTTONSTRUCTSIZE, - (WPARAM) sizeof(TBBUTTON), - 0); + TB_BUTTONSTRUCTSIZE, + (WPARAM) sizeof(TBBUTTON), + 0); for(i=0; imagic != KHM_QUERY_APP_VER_MAGIC) + return; + + papp_ver->ver_remote = app_version; + + /* the remote instance has requested swapping in. we check the + version numbers and if the remote instance is newer than us, + then we exit and let the remote instance take over. */ + if (papp_ver->request_swap) { + khm_version ver_caller = papp_ver->ver_caller; + + if (ver_caller.major > app_version.major || + + (ver_caller.major == app_version.major && + ver_caller.minor > app_version.minor) || + + (ver_caller.major == app_version.major && + ver_caller.minor == app_version.minor && + ver_caller.aux > app_version.aux) || + + (ver_caller.major == app_version.major && + ver_caller.minor == app_version.minor && + ver_caller.aux == app_version.aux && + ver_caller.patch > app_version.patch)) { + + papp_ver->request_swap = TRUE; + + if (khm_hwnd_main) + DestroyWindow(khm_hwnd_main); + + } else { + + papp_ver->request_swap = FALSE; + + } + } + + papp_ver->code = KHM_ERROR_SUCCESS; +} + +LRESULT CALLBACK +khm_main_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { LPNMHDR lpnm; @@ -92,6 +193,7 @@ LRESULT CALLBACK khm_main_wnd_proc( break; case WM_DESTROY: + khm_pre_shutdown(); kmq_unsubscribe_hwnd(KMSG_ACT, hwnd); kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); HtmlHelp(NULL, NULL, HH_CLOSE_ALL, 0); @@ -136,7 +238,7 @@ LRESULT CALLBACK khm_main_wnd_proc( return 0; case KHUI_ACTION_DESTROY_CRED: - khm_cred_destroy_creds(); + khm_cred_destroy_creds(FALSE, FALSE); return 0; case KHUI_ACTION_SET_DEF_ID: @@ -155,12 +257,16 @@ LRESULT CALLBACK khm_main_wnd_proc( khm_hide_main_window(); break; - case KHUI_ACTION_OPT_KHIM: - khm_show_config_pane(NULL); + case KHUI_ACTION_OPT_KHIM: { + khui_config_node node = NULL; + + khui_cfg_open(NULL, L"KhmGeneral", &node); + khm_show_config_pane(node); + } break; case KHUI_ACTION_OPT_IDENTS: { - khui_config_node node; + khui_config_node node = NULL; khui_cfg_open(NULL, L"KhmIdentities", &node); khm_show_config_pane(node); @@ -168,7 +274,7 @@ LRESULT CALLBACK khm_main_wnd_proc( break; case KHUI_ACTION_OPT_NOTIF: { - khui_config_node node; + khui_config_node node = NULL; khui_cfg_open(NULL, L"KhmNotifications", &node); khm_show_config_pane(node); @@ -176,7 +282,7 @@ LRESULT CALLBACK khm_main_wnd_proc( break; case KHUI_ACTION_OPT_PLUGINS: { - khui_config_node node; + khui_config_node node = NULL; khui_cfg_open(NULL, L"KhmPlugins", &node); khm_show_config_pane(node); @@ -216,16 +322,27 @@ LRESULT CALLBACK khm_main_wnd_proc( mm_last_hot_item = LOWORD(lParam); return khm_menu_activate(MENU_ACTIVATE_DEFAULT); + case KHUI_PACTION_ESC: + /* if esc is pressed while no menu is active, we close the + main window */ + if (mm_last_hot_item == -1) { + khm_close_main_window(); + return 0; + } + /* generic, retargetting */ case KHUI_PACTION_UP: case KHUI_PACTION_UP_TOGGLE: case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_PGUP: + case KHUI_PACTION_PGUP_EXTEND: case KHUI_PACTION_DOWN: case KHUI_PACTION_DOWN_TOGGLE: case KHUI_PACTION_DOWN_EXTEND: + case KHUI_PACTION_PGDN: + case KHUI_PACTION_PGDN_EXTEND: case KHUI_PACTION_LEFT: case KHUI_PACTION_RIGHT: - case KHUI_PACTION_ESC: case KHUI_PACTION_ENTER: /* menu tracking */ if(mm_last_hot_item != -1) { @@ -251,16 +368,27 @@ LRESULT CALLBACK khm_main_wnd_proc( } /*FALLTHROUGH*/ - case KHUI_PACTION_DELETE: case KHUI_PACTION_SELALL: case KHUI_ACTION_LAYOUT_ID: case KHUI_ACTION_LAYOUT_TYPE: case KHUI_ACTION_LAYOUT_LOC: + case KHUI_ACTION_LAYOUT_CUST: /* otherwise fallthrough and bounce to the creds window */ return SendMessage(khm_hwnd_main_cred, uMsg, wParam, lParam); + + default: + /* handle custom actions here */ + { + khui_action * act; + + act = khui_find_action(LOWORD(wParam)); + if (act && act->listener) { + kmq_post_sub_msg(act->listener, KMSG_ACT, KMSG_ACT_ACTIVATE, act->cmd, NULL); + } + } } break; /* WM_COMMAND */ @@ -271,34 +399,7 @@ LRESULT CALLBACK khm_main_wnd_proc( return 0; case SC_CLOSE: - { - khm_handle csp_cw; - BOOL keep_running = FALSE; - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", - KHM_PERM_READ, &csp_cw))) { - khm_int32 t; - - if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"KeepRunning", - &t))) - keep_running = t; -#ifdef DEBUG - else - assert(FALSE); -#endif - - khc_close_space(csp_cw); - } -#ifdef DEBUG - else - assert(FALSE); -#endif - - if (keep_running) - khm_hide_main_window(); - else - DestroyWindow(hwnd); - } + khm_close_main_window(); return 0; } break; @@ -416,6 +517,27 @@ LRESULT CALLBACK khm_main_wnd_proc( } else if (m->type == KMSG_ACT && m->subtype == KMSG_ACT_CONTINUE_CMDLINE) { khm_cred_process_commandline(); + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_SYNC_CFG) { + khm_refresh_config(); + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_ACTIVATE) { + /* some custom action fired */ + + khm_int32 action; + khui_action * paction; + + action = m->uparam; + paction = khui_find_action(action); + if (paction && paction->data == (void *) CFGACTION_MAGIC) { + /* a custom configuration needs to be invoked */ + khui_config_node node; + + if (KHM_SUCCEEDED(khui_cfg_open(NULL, paction->name, &node))) { + khm_show_config_pane(node); + khui_cfg_release(node); + } + } } else if (m->type == KMSG_CRED && m->subtype == KMSG_CRED_REFRESH) { mw_restart_refresh_timer(hwnd); @@ -466,20 +588,49 @@ LRESULT CALLBACK khm_main_wnd_proc( khm_cred_begin_commandline(); } break; + + case WM_KHUI_QUERY_APP_VERSION: + { + HANDLE hmap; + void * xfer; + wchar_t mapname[256]; + + StringCbPrintf(mapname, sizeof(mapname), + QUERY_APP_VER_MAP_FMT, (DWORD) lParam); + + hmap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, + FALSE, mapname); + + if (hmap == NULL) + return 1; + + xfer = MapViewOfFile(hmap, FILE_MAP_WRITE, 0, 0, + sizeof(khm_query_app_version)); + + if (xfer) { + khm_process_query_app_ver((khm_query_app_version *) xfer); + + UnmapViewOfFile(xfer); + } + + CloseHandle(hmap); + } + break; + } return DefWindowProc(hwnd,uMsg,wParam,lParam); } -LRESULT CALLBACK khm_null_wnd_proc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ) { +LRESULT CALLBACK +khm_null_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } -LRESULT khm_rebar_notify(LPNMHDR lpnm) { +LRESULT +khm_rebar_notify(LPNMHDR lpnm) { switch(lpnm->code) { #if (_WIN32_WINNT >= 0x0501) case RBN_AUTOBREAK: @@ -508,7 +659,8 @@ LRESULT khm_rebar_notify(LPNMHDR lpnm) { return 1; } -void khm_create_main_window_controls(HWND hwnd_main) { +void +khm_create_main_window_controls(HWND hwnd_main) { REBARINFO rbi; HWND hwRebar; @@ -552,7 +704,8 @@ void khm_create_main_window_controls(HWND hwnd_main) { khm_hwnd_main_cred = khm_create_credwnd(hwnd_main); } -void khm_create_main_window(void) { +void +khm_create_main_window(void) { wchar_t buf[1024]; khm_handle csp_cw = NULL; khm_handle csp_mw = NULL; @@ -615,9 +768,11 @@ void khm_create_main_window(void) { NULL, NULL); + khui_set_main_window(khm_hwnd_main); } -void khm_show_main_window(void) { +void +khm_show_main_window(void) { if (khm_nCmdShow == SW_RESTORE) { HWND hw; @@ -639,7 +794,39 @@ void khm_show_main_window(void) { khm_nCmdShow = SW_RESTORE; } -void khm_hide_main_window(void) { +void +khm_close_main_window(void) { + khm_handle csp_cw; + BOOL keep_running = FALSE; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ, &csp_cw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"KeepRunning", + &t))) { + keep_running = t; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + khc_close_space(csp_cw); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (keep_running) + khm_hide_main_window(); + else + DestroyWindow(khm_hwnd_main); +} + +void +khm_hide_main_window(void) { khm_handle csp_notices = NULL; khm_int32 show_warning = FALSE; @@ -674,11 +861,13 @@ void khm_hide_main_window(void) { ShowWindow(khm_hwnd_main, SW_HIDE); } -BOOL khm_is_main_window_visible(void) { +BOOL +khm_is_main_window_visible(void) { return IsWindowVisible(khm_hwnd_main); } -BOOL khm_is_main_window_active(void) { +BOOL +khm_is_main_window_active(void) { if (!IsWindowVisible(khm_hwnd_main)) return FALSE; if (GetForegroundWindow() == khm_hwnd_main) @@ -686,7 +875,8 @@ BOOL khm_is_main_window_active(void) { return khm_is_dialog_active(); } -void khm_register_main_wnd_class(void) { +void +khm_register_main_wnd_class(void) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); @@ -704,7 +894,6 @@ void khm_register_main_wnd_class(void) { khm_null_window_class = RegisterClassEx(&wc); - wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = khm_main_wnd_proc; @@ -721,7 +910,8 @@ void khm_register_main_wnd_class(void) { khm_main_window_class = RegisterClassEx(&wc); } -void khm_unregister_main_wnd_class(void) { +void +khm_unregister_main_wnd_class(void) { UnregisterClass(MAKEINTATOM(khm_main_window_class),khm_hInstance); UnregisterClass(MAKEINTATOM(khm_null_window_class),khm_hInstance); } diff --git a/src/windows/identity/ui/mainwnd.h b/src/windows/identity/ui/mainwnd.h index 95b28b733..526248b1d 100644 --- a/src/windows/identity/ui/mainwnd.h +++ b/src/windows/identity/ui/mainwnd.h @@ -39,6 +39,7 @@ void khm_unregister_main_wnd_class(void); void khm_create_main_window_controls(HWND); void khm_create_main_window(void); void khm_show_main_window(void); +void khm_close_main_window(void); void khm_hide_main_window(void); BOOL khm_is_main_window_visible(void); BOOL khm_is_main_window_active(void); @@ -54,7 +55,9 @@ khm_main_wnd_proc(HWND hwnd, LPARAM lParam); #define WM_KHUI_ASSIGN_COMMANDLINE 32808 +#define WM_KHUI_QUERY_APP_VERSION 32809 #define COMMANDLINE_MAP_FMT L"Local\\NetIDMgr_Cmdline_%lu" +#define QUERY_APP_VER_MAP_FMT L"Local\\NetIDMgr_QueryVer_%lu" #endif diff --git a/src/windows/identity/ui/netidmgr.manifest.amd64.vc7 b/src/windows/identity/ui/netidmgr.manifest.amd64.vc7 new file mode 100644 index 000000000..0db331bb7 --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.amd64.vc7 @@ -0,0 +1,22 @@ + + + +Khimaira Credentials Manager + + + + + + diff --git a/src/windows/identity/ui/netidmgr.manifest.amd64.vc7.debug b/src/windows/identity/ui/netidmgr.manifest.amd64.vc7.debug new file mode 100644 index 000000000..0db331bb7 --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.amd64.vc7.debug @@ -0,0 +1,22 @@ + + + +Khimaira Credentials Manager + + + + + + diff --git a/src/windows/identity/ui/netidmgr.manifest.amd64.vc8 b/src/windows/identity/ui/netidmgr.manifest.amd64.vc8 new file mode 100644 index 000000000..6fb1e8d1e --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.amd64.vc8 @@ -0,0 +1,31 @@ + + + +Khimaira Credentials Manager + + + + + + + + + diff --git a/src/windows/identity/ui/netidmgr.manifest.amd64.vc8.debug b/src/windows/identity/ui/netidmgr.manifest.amd64.vc8.debug new file mode 100644 index 000000000..6fb1e8d1e --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.amd64.vc8.debug @@ -0,0 +1,31 @@ + + + +Khimaira Credentials Manager + + + + + + + + + diff --git a/src/windows/identity/ui/newcredwnd.c b/src/windows/identity/ui/newcredwnd.c index 619b79687..3730a3c6e 100644 --- a/src/windows/identity/ui/newcredwnd.c +++ b/src/windows/identity/ui/newcredwnd.c @@ -899,7 +899,7 @@ nc_handle_wm_command(HWND hwnd, switch(LOWORD(wParam)) { case IDOK: - d->nc->result = KHUI_NC_RESULT_GET_CREDS; + d->nc->result = KHUI_NC_RESULT_PROCESS; /* fallthrough */ @@ -1178,7 +1178,7 @@ static LRESULT nc_handle_wm_nc_notify(HWND hwnd, if (d->nc->types[i]->dlg_proc == NULL) { d->nc->types[i]->hwnd_panel = NULL; } else { - /* Create the dialog panel */ + /* Create the dialog panel */ d->nc->types[i]->hwnd_panel = CreateDialogParam(d->nc->types[i]->h_module, d->nc->types[i]->dlg_template, diff --git a/src/windows/identity/ui/notifier.c b/src/windows/identity/ui/notifier.c index b7ac46262..cde643ab2 100644 --- a/src/windows/identity/ui/notifier.c +++ b/src/windows/identity/ui/notifier.c @@ -51,6 +51,8 @@ HWND hwnd_notifier = NULL; BOOL notifier_ready = FALSE; +khm_boolean notifier_modal_loop = FALSE; + khui_alert * current_alert = NULL; khui_alert * alert_queue[KHUI_ALERT_QUEUE_MAX]; @@ -184,6 +186,23 @@ notifier_wnd_proc(HWND hwnd, } } break; + + case KMSG_ALERT_SHOW_MODAL: + { + khui_alert * a; + + a = (khui_alert *) m->vparam; + a->flags |= KHUI_ALERT_FLAG_MODAL; + rv = alert_show(a); + khui_alert_release(a); + + if (KHM_SUCCEEDED(rv)) { + notifier_modal_loop = TRUE; + + khm_message_loop_int(¬ifier_modal_loop); + } + } + break; } } else if (m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) { @@ -251,6 +270,7 @@ notifier_wnd_proc(HWND hwnd, } } /* fallthrough */ + case NIN_BALLOONHIDE: case NIN_BALLOONTIMEOUT: khm_notify_icon_change(KHERR_NONE); if (current_alert) { @@ -259,6 +279,7 @@ notifier_wnd_proc(HWND hwnd, } break; #endif + } } else if (uMsg == WM_TIMER) { if (wParam == KHUI_TRIGGER_TIMER_ID) { @@ -445,7 +466,16 @@ alert_show_normal(khui_alert * a) { khui_alert_add_command(a, KHUI_PACTION_CLOSE); } - if (!is_alert_queue_empty()) { + /* if there are other alerts queued up, we should add a 'Next + alert...' button that when clicked, would show the next queued + alert. However, we only do this if the current alert doesn't + actually require a command response. Otherwise, clicking the + 'next' button will be the equivalent of cancelling out of the + alert without selecting any of the commands. */ + if (!is_alert_queue_empty() && + a->n_alert_commands == 1 && + a->alert_commands[0] == KHUI_PACTION_CLOSE) { + khui_alert_add_command(a, KHUI_PACTION_NEXT); } @@ -457,14 +487,15 @@ alert_show_normal(khui_alert * a) { CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP, MAKEINTATOM(atom_alerter), title, - WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | - WS_VISIBLE, + WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN, 0, 0, 300, 300, // bogus values khm_hwnd_main, (HMENU) NULL, khm_hInstance, (LPVOID) a); + ShowWindow(hwa, SW_SHOW); + return KHM_ERROR_SUCCESS; } @@ -491,8 +522,9 @@ alert_show(khui_alert * a) { /* depending on the state of the main window, we need to either show a window or a balloon */ - if(khm_is_main_window_active() && - !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON)) + if ((a->flags & KHUI_ALERT_FLAG_MODAL) || + (khm_is_main_window_active() && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON))) return alert_show_normal(a); else return alert_show_minimized(a); @@ -676,7 +708,9 @@ alerter_wnd_proc(HWND hwnd, CreateWindowEx(0, L"BUTTON", caption, - WS_VISIBLE | WS_CHILD, + WS_VISIBLE | WS_CHILD | + /* the first button is the default */ + ((i==0)? BS_DEFPUSHBUTTON: 0), x,y,width,height, hwnd, (HMENU)(INT_PTR) (action->cmd), @@ -719,6 +753,8 @@ alerter_wnd_proc(HWND hwnd, khui_alert_lock(d->alert); d->alert->flags &= ~KHUI_ALERT_FLAG_DISPLAY_WINDOW; + if (d->alert->flags & KHUI_ALERT_FLAG_MODAL) + notifier_modal_loop = FALSE; khui_alert_unlock(d->alert); khui_alert_release(d->alert); @@ -935,6 +971,8 @@ alerter_wnd_proc(HWND hwnd, SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); + InvalidateRect(hwnd, NULL, TRUE); + x = d->x_message; y = d->dy_client - d->dy_bb; width = d->dx_button; diff --git a/src/windows/identity/ui/reqdaemon.c b/src/windows/identity/ui/reqdaemon.c index 04056566d..684f6c74a 100644 --- a/src/windows/identity/ui/reqdaemon.c +++ b/src/windows/identity/ui/reqdaemon.c @@ -137,7 +137,7 @@ reqdaemonwnd_proc(HWND hwnd, sizeof(widname)))) continue; else { - lr = (result != KHUI_NC_RESULT_GET_CREDS); + lr = (result != KHUI_NC_RESULT_PROCESS); break; } } while(TRUE); diff --git a/src/windows/identity/ui/resource.h b/src/windows/identity/ui/resource.h index b8060c6a0..19396fb23 100644 --- a/src/windows/identity/ui/resource.h +++ b/src/windows/identity/ui/resource.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\ui\lang\en_us\khapp.rc +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\ui\lang\en_us\khapp.rc // #define IDI_MAIN_APP 104 #define IDD_PROPPAGE_MEDIUM 106 @@ -207,8 +207,11 @@ #define IDI_ICON4 206 #define IDI_APPICON_OK 206 #define IDS_PISTATE_FAILREG 207 +#define IDI_CFG_PLUGIN 207 #define IDS_PISTATE_FAILDIS 208 +#define IDI_CFG_PLUGIN_ERR 208 #define IDS_PISTATE_FAILLOD 209 +#define IDI_CFG_PLUGIN_DIS 209 #define IDS_PISTATE_PLACEHOLD 210 #define IDS_PISTATE_REG 211 #define IDS_PISTATE_HOLD 212 @@ -232,6 +235,28 @@ #define IDS_NC_ID_DEF 230 #define IDS_NC_ID_WDEF 231 #define IDS_NC_ID_NDEF 232 +#define IDS_PACTION_YES 233 +#define IDS_PACTION_NO 234 +#define IDS_PACTION_YESALL 235 +#define IDS_PACTION_NOALL 236 +#define IDS_PACTION_KEEP 237 +#define IDS_PACTION_REMOVE 238 +#define IDS_PACTION_DISCARD 239 +#define IDS_CFG_IT_MOD 240 +#define IDS_CFG_IT_APP 241 +#define IDS_CFG_IT_NONE 242 +#define IDS_CFG_NODESC 243 +#define IDS_CFG_P_DELCNFT 244 +#define IDS_CFG_P_DELCNFM 245 +#define IDS_CFG_P_DELCNFS 246 +#define IDS_CFG_P_DELNDEP 247 +#define IDS_CFG_P_ENBCNFT 248 +#define IDS_CFG_P_ENBCNFM 249 +#define IDS_PISTATE_FAILINIT 250 +#define IDS_CFG_P_UNRCNFT 251 +#define IDS_CFG_P_UNRCNFM 252 +#define IDS_CFG_P_UNRCNFS 253 +#define IDS_ACTION_LAYOUT_CUST 254 #define IDC_NC_USERNAME 1007 #define IDC_NC_PASSWORD 1008 #define IDC_NC_CREDTEXT_LABEL 1009 @@ -312,6 +337,13 @@ #define IDC_LIST1 1103 #define IDC_MODULES 1103 #define IDC_PP_CONFIG 1104 +#define IDC_CFG_UNREGISTER 1107 +#define IDC_CFG_VERSION 1108 +#define IDC_CFG_ICON 1109 +#define IDC_CFG_LOGTOFILE 1110 +#define IDC_CFG_LOGPATH 1111 +#define IDC_NOTIF_HALFLIFE 1112 +#define IDC_CFG_DESTROYALL 1113 #define IDA_ACTIVATE_MENU 40003 #define IDA_UP 40004 #define IDA_DOWN 40005 @@ -324,9 +356,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 207 +#define _APS_NEXT_RESOURCE_VALUE 210 #define _APS_NEXT_COMMAND_VALUE 40010 -#define _APS_NEXT_CONTROL_VALUE 1107 +#define _APS_NEXT_CONTROL_VALUE 1114 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/windows/identity/ui/timer.c b/src/windows/identity/ui/timer.c index 5d28e6a58..40464d5ad 100644 --- a/src/windows/identity/ui/timer.c +++ b/src/windows/identity/ui/timer.c @@ -27,6 +27,12 @@ #include #include +/* The minimum half time interval is 60 seconds*/ +#define TT_MIN_HALFLIFE_INTERVAL 60 + +/* as above, in FILETIME units of 100ns */ +#define FT_MIN_HALFLIFE_INTERVAL (TT_MIN_HALFLIFE_INTERVAL * 10000000i64) + /* in seconds */ #if 0 khm_int32 khui_timeout_warn = KHUI_DEF_TIMEOUT_WARN; @@ -161,11 +167,11 @@ tmr_fire_timer(void) { khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; } -#ifdef DEBUG else { +#ifdef DEBUG assert(FALSE); - } #endif + } } } } @@ -323,6 +329,71 @@ tmr_find(khm_handle key, khui_timer_type type, return -1; } +/* called with cs_timers held. */ +static FILETIME +tmr_next_halflife_timeout(int idx, FILETIME * issue, FILETIME * expire) { + FILETIME lifetime; + FILETIME current; + FILETIME ret; + + khm_int64 ilife; + khm_int64 icurrent; + khm_int64 iexpire; + + khm_int64 iret; + + GetSystemTimeAsFileTime(¤t); + + /* wha?? */ + if (CompareFileTime(issue, expire) >= 0) + return current; + + lifetime = FtSub(expire, issue); + icurrent = FtToInt(¤t); + iexpire = FtToInt(expire); + + ilife = FtToInt(&lifetime); + + while(ilife / 2 > FT_MIN_HALFLIFE_INTERVAL) { + ilife /= 2; + + /* is this the next renewal time? */ + if (iexpire - ilife > icurrent) { + if (idx >= 0 && + khui_timers[idx].expire == iexpire - ilife && + (khui_timers[idx].flags & KHUI_TE_FLAG_EXPIRED)) { + + /* if this renewal time has already been triggered + (note that when the timer fires, it also fires all + events that are within a few seconds of the current + time) then we need to set the alarm for the next + slot down the line. */ + + continue; + + } else { + break; + } + } + } + + iret = iexpire - ilife; + + ret = IntToFt(iret); + + /* if the previous renew timer had fired, we need to mark it as + not expired. However, we leave it to the caller to update the + actual timer and mark it as not stale. */ + if (idx >= 0 && + khui_timers[idx].expire < (khm_ui_8) iret) { + + khui_timers[idx].flags &= ~KHUI_TE_FLAG_EXPIRED; + khui_timers[idx].expire = iret; + } + + return ret; +} + /* called with cs_timers held */ static khm_int32 KHMAPI tmr_cred_apply_proc(khm_handle cred, void * rock) { @@ -333,6 +404,8 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { FILETIME ft_current; FILETIME ft_creinst; FILETIME ft_cred_expiry; + FILETIME ft_cred_issue; + FILETIME ft_issue; FILETIME ft; FILETIME fte; FILETIME ft_reinst; @@ -347,7 +420,8 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { cb = sizeof(ft_expiry); if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, - &ft_expiry, &cb))) + &ft_expiry, &cb))) { + cb = sizeof(ft_expiry); if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, NULL, &ft_expiry, &cb))) { @@ -355,6 +429,22 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { kcdb_identity_release(ident); return KHM_ERROR_SUCCESS; } + } + + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, + NULL, + &ft_issue, &cb))) { + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, + &ft_issue, &cb))) { + /* we don't really abandon the timer. In this case, we + fall back to using the threshold value to set the + expiry timer. */ + ZeroMemory(&ft_issue, sizeof(ft_issue)); + } + } /* and the current time */ GetSystemTimeAsFileTime(&ft_current); @@ -383,6 +473,7 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { khm_boolean do_warn = TRUE; khm_boolean do_crit = TRUE; khm_boolean do_renew = TRUE; + khm_boolean do_halflife = TRUE; khm_boolean renew_done = FALSE; khm_boolean monitor = TRUE; khm_int32 to_warn = KHUI_DEF_TIMEOUT_WARN; @@ -423,6 +514,10 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { if (KHM_SUCCEEDED(rv)) do_renew = t; + rv = khc_read_int32(csp_id, L"RenewAtHalfLife", &t); + if (KHM_SUCCEEDED(rv)) + do_halflife = t; + rv = khc_read_int32(csp_id, L"WarnThreshold", &t); if (KHM_SUCCEEDED(rv)) to_warn = t; @@ -441,16 +536,21 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { int prev; TimetToFileTimeInterval(to_renew, &ft); - fte = FtSub(&ft_expiry, &ft); prev = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0); + if (do_halflife) + fte = tmr_next_halflife_timeout(prev, &ft_issue, &ft_expiry); + else + fte = FtSub(&ft_expiry, &ft); + /* we set off a renew notification immediately if the renew threshold has passed but a renew was never sent. This maybe because that NetIDMgr was started at the last minute, or because for some reason the renew timer could not be triggered earlier. */ + if (CompareFileTime(&fte, &ft_current) > 0 || prev == -1 || !(khui_timers[prev].flags & KHUI_TE_FLAG_EXPIRED)) { @@ -462,14 +562,18 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { FtToInt(&fte), FtToInt(&ft), 0, CompareFileTime(&fte,&ft_creinst) > 0); renew_done = TRUE; + } else { + /* special case. If the renew timer was in the past and it was expired, then we retain the record as long as the credentials are around. If the renewal failed we don't want to automatically retry everytime we check the timers. */ + tmr_update(ident, KHUI_TTYPE_ID_RENEW, FtToInt(&fte), FtToInt(&ft), 0, FALSE); + } } @@ -512,9 +616,21 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { &cb))) goto _cleanup; + cb = sizeof(ft_cred_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, + &ft_cred_issue, + &cb))) + goto _cleanup; + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft); { + /* if the credential has a longer lifetime than the identity, + or it expires within KHUI_TIMEEQ_ERROR seconds of the + identity, then we don't need to set any alerts for this + credential. */ + FILETIME ft_delta; ft_delta = FtSub(&ft_expiry, &ft_cred_expiry); @@ -529,12 +645,12 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); if (CompareFileTime(&fte, &ft_current) > 0) { - tmr_update(cred, KHUI_TTYPE_CRED_WARN, - FtToInt(&fte), - khui_timers[idx].offset, 0, - CompareFileTime(&fte, &ft_creinst) > 0); - kcdb_cred_hold(cred); - } + tmr_update(cred, KHUI_TTYPE_CRED_WARN, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } } if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 && @@ -553,7 +669,9 @@ tmr_cred_apply_proc(khm_handle cred, void * rock) { if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 && !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { - fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + //fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + fte = tmr_next_halflife_timeout(idx, &ft_cred_issue, &ft_cred_expiry); + if (CompareFileTime(&fte, &ft_current) > 0) { tmr_update(cred, KHUI_TTYPE_CRED_RENEW, FtToInt(&fte), @@ -648,14 +766,26 @@ khm_timer_refresh(HWND hwnd) { KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + /* When refreshing timers, we go through all of them and mark them + as stale. Then we go through the credentials in the root + credential set and add or refresh the timers associated with + each identity and credential. Once this is done, we remove the + timers that are still stale, since they are no longer in + use. */ + for (i=0; i < (int) khui_n_timers; i++) { #ifdef NOT_IMPLEMENTED_YET if (khui_timers[i].type == KHUI_TTYPE_BMSG || khui_timers[i].type == KHUI_TTYPE_SMSG) { khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; - } else + } else { #endif + khui_timers[i].flags |= KHUI_TE_FLAG_STALE; + +#ifdef NOT_IMPLEMENTED_YET + } +#endif } kcdb_credset_apply(NULL, @@ -666,6 +796,10 @@ khm_timer_refresh(HWND hwnd) { _check_next_event: + /* Before we return, we should check if any timers are set to + expire right now. If there are, we should fire the timer + before returning. */ + next_event = 0; for (i=0; i < (int) khui_n_timers; i++) { if (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) && diff --git a/src/windows/identity/ui/uiconfig.csv b/src/windows/identity/ui/uiconfig.csv index 14057dded..5c512bbac 100644 --- a/src/windows/identity/ui/uiconfig.csv +++ b/src/windows/identity/ui/uiconfig.csv @@ -6,7 +6,7 @@ CredWindow,KC_SPACE,0,Options for the credentials window AutoDetectNet,KC_INT32,1,Automatically detect network connectivity changes KeepRunning,KC_INT32,1,Keep running after closing Khimaira DefaultView,KC_STRING,ByIdentity, - ViewList,KC_STRING,"ByIdentity,ByLocation", + ViewList,KC_STRING,"ByIdentity,ByLocation,ByType", PaddingHorizontal,KC_INT32,4, PaddingVertical,KC_INT32,2, PaddingHeader,KC_INT32,16, @@ -19,10 +19,13 @@ CredWindow,KC_SPACE,0,Options for the credentials window AllowCritical,KC_INT32,1,Boolean. Enables critical. AutoRenewThreshold,KC_INT32,600,In seconds AllowAutoRenew,KC_INT32,1,Boolean. + RenewAtHalfLife,KC_INT32,1,Boolean. Use half-life algorithm for renewals. DefaultAllowAutoRenew,KC_INT32,1,Default AllowAutoRenew value for new identities DefaultSticky,KC_INT32,0,Default Sticky value for new identities MaxThreshold,KC_INT32,86400,Max value for a threshold (1 day) MinThreshold,KC_INT32,10,Min value for a threshold (0) + LogToFile,KC_INT32,0,Boolean. If true logs trace events to a nidmdbg.log in the temp folder + DestroyCredsOnExit,KC_INT32,0,Boolean. If true; all credentials will be destroyed when NetIDMgr exits. Windows,KC_SPACE,0,Window parameters _Schema,KC_SPACE,0,Schema Width,KC_INT32,0, @@ -35,6 +38,33 @@ CredWindow,KC_SPACE,0,Options for the credentials window Windows,KC_ENDSPACE,0, Views,KC_SPACE,0,Preconfigured views for credentials Custom_0,KC_SPACE,0,First custom view. Additional views have names of the form Custom_N + Description,KC_STRING,Custom view, + ColumnList,KC_STRING,"_CWFlags,IdentityName,TypeName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,0, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,1 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,2 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 Custom_0,KC_ENDSPACE,0, ByIdentity,KC_SPACE,0,The default view Description,KC_STRING,View grouped by identity and credential type, @@ -42,12 +72,8 @@ CredWindow,KC_SPACE,0,Options for the credentials window Columns,KC_SPACE,0,Columns _CWFlags,KC_SPACE,0, Width,KC_INT32,20, - Flags,KC_INT32,112, + Flags,KC_INT32,112, _CWFlags,KC_ENDSPACE,0, -# _CWTypeIcon,KC_SPACE,0, -# Width,KC_INT32,20, -# Flags,KC_INT32,112, -# _CWTypeIcon,KC_ENDSPACE,0, IdentityName,KC_SPACE,0, Width,KC_INT32,100, SortIndex,KC_INT32,0, @@ -69,18 +95,43 @@ CredWindow,KC_SPACE,0,Options for the credentials window TimeLeft,KC_ENDSPACE,0 Columns,KC_ENDSPACE,0 ByIdentity,KC_ENDSPACE,0 + ByType,KC_SPACE,0,The default view + Description,KC_STRING,View grouped by type and identity, + ColumnList,KC_STRING,"_CWFlags,TypeName,IdentityName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,0 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,1, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,2 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 + ByType,KC_ENDSPACE,0 ByLocation,KC_SPACE,0,View by location Description,KC_STRING,View grouped by location, ColumnList,KC_STRING,"_CWFlags,Location,IdentityName,TypeName,Name,TimeLeft", Columns,KC_SPACE,0,Columns _CWFlags,KC_SPACE,0, Width,KC_INT32,20, - Flags,KC_INT32,112, + Flags,KC_INT32,112, _CWFlags,KC_ENDSPACE,0, -# _CWTypeIcon,KC_SPACE,0, -# Width,KC_INT32,20, -# Flags,KC_INT32,112, -# _CWTypeIcon,KC_ENDSPACE,0, Location,KC_SPACE,0, Width,KC_INT32,100, SortIndex,KC_INT32,0, diff --git a/src/windows/identity/uilib/accel.csv b/src/windows/identity/uilib/accel.csv index a97b37ba4..f95e89bc8 100644 --- a/src/windows/identity/uilib/accel.csv +++ b/src/windows/identity/uilib/accel.csv @@ -3,9 +3,13 @@ KHUI_PACTION_MENU,FVIRTKEY,VK_F10,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_UP,FVIRTKEY,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_UP_EXTEND,FVIRTKEY|FSHIFT,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_UP_TOGGLE,FVIRTKEY|FCONTROL,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_PGUP,FVIRTKEY,VK_PRIOR,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_PGUP_EXTEND,FVIRTKEY|FSHIFT,VK_PRIOR,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_DOWN,FVIRTKEY,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_DOWN_EXTEND,FVIRTKEY|FSHIFT,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_DOWN_TOGGLE,FVIRTKEY|FCONTROL,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_PGDN,FVIRTKEY,VK_NEXT,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_PGDN_EXTEND,FVIRTKEY|FSHIFT,VK_NEXT,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_LEFT,FVIRTKEY,VK_LEFT,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_RIGHT,FVIRTKEY,VK_RIGHT,KHUI_ACCEL_SCOPE_GLOBAL KHUI_PACTION_ENTER,FVIRTKEY,VK_RETURN,KHUI_ACCEL_SCOPE_GLOBAL diff --git a/src/windows/identity/uilib/acceldef.cfg b/src/windows/identity/uilib/acceldef.cfg index 5dc72e610..3be4f2e46 100644 --- a/src/windows/identity/uilib/acceldef.cfg +++ b/src/windows/identity/uilib/acceldef.cfg @@ -28,6 +28,7 @@ This file was autogenerated from src/ui/acceldef.cfg and src/ui/accel.csv. Do not modify directly. */ +#define NOEXPORT #include khui_accel_def khui_accel_global[] = { diff --git a/src/windows/identity/uilib/action.c b/src/windows/identity/uilib/action.c index b337eb894..4f68bbfa6 100644 --- a/src/windows/identity/uilib/action.c +++ b/src/windows/identity/uilib/action.c @@ -30,11 +30,11 @@ #include khui_action_ref khui_main_menu[] = { - MENU_ACTION(KHUI_MENU_FILE), - MENU_ACTION(KHUI_MENU_CRED), - MENU_ACTION(KHUI_MENU_VIEW), - MENU_ACTION(KHUI_MENU_OPTIONS), - MENU_ACTION(KHUI_MENU_HELP), + MENU_SUBMENU(KHUI_MENU_FILE), + MENU_SUBMENU(KHUI_MENU_CRED), + MENU_SUBMENU(KHUI_MENU_VIEW), + MENU_SUBMENU(KHUI_MENU_OPTIONS), + MENU_SUBMENU(KHUI_MENU_HELP), MENU_END() }; @@ -53,7 +53,10 @@ khui_action_ref khui_menu_cred[] = { MENU_ACTION(KHUI_ACTION_DESTROY_CRED), MENU_SEP(), MENU_ACTION(KHUI_ACTION_SET_DEF_ID), +#if 0 + /* not implemented yet */ MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), +#endif MENU_SEP(), MENU_ACTION(KHUI_ACTION_PASSWD_ID), MENU_END() @@ -63,6 +66,7 @@ khui_action_ref khui_menu_layout[] = { MENU_ACTION(KHUI_ACTION_LAYOUT_ID), MENU_ACTION(KHUI_ACTION_LAYOUT_TYPE), MENU_ACTION(KHUI_ACTION_LAYOUT_LOC), + MENU_ACTION(KHUI_ACTION_LAYOUT_CUST), MENU_END() }; @@ -72,12 +76,18 @@ khui_action_ref khui_menu_toolbars[] = { }; khui_action_ref khui_menu_view[] = { - MENU_ACTION(KHUI_ACTION_CHOOSE_COLS), - MENU_ACTION(KHUI_MENU_LAYOUT), - MENU_ACTION(KHUI_MENU_TOOLBARS), + MENU_SUBMENU(KHUI_MENU_COLUMNS), + MENU_SUBMENU(KHUI_MENU_LAYOUT), +#if 0 + /* not implemented yet */ + MENU_SUBMENU(KHUI_MENU_TOOLBARS), +#endif MENU_SEP(), +#if 0 + /* not implemented yet */ MENU_ACTION(KHUI_ACTION_DEBUG_WINDOW), MENU_SEP(), +#endif MENU_ACTION(KHUI_ACTION_VIEW_REFRESH), MENU_END() }; @@ -87,6 +97,7 @@ khui_action_ref khui_menu_options[] = { MENU_ACTION(KHUI_ACTION_OPT_IDENTS), MENU_ACTION(KHUI_ACTION_OPT_NOTIF), MENU_ACTION(KHUI_ACTION_OPT_PLUGINS), + MENU_SEP(), MENU_END() }; @@ -157,6 +168,16 @@ khui_action_ref khui_menu_ico_ctx_normal[] = { MENU_END() }; +khui_action_ref khui_menu_cwheader_ctx[] = { + MENU_SUBMENU(KHUI_MENU_COLUMNS), + MENU_SUBMENU(KHUI_MENU_LAYOUT), + MENU_END() +}; + +khui_action_ref khui_menu_columns[] = { + MENU_END() +}; + khui_action_ref khui_pmenu_tok_sel[] = { MENU_ACTION(KHUI_ACTION_RENEW_CRED), MENU_ACTION(KHUI_ACTION_DESTROY_CRED), @@ -171,23 +192,25 @@ khui_action_ref khui_pmenu_id_sel[] = { /* all stock menus and toolbars */ khui_menu_def khui_all_menus[] = { - CONSTMENU(KHUI_MENU_MAIN, KHUI_MENUSTATE_CONSTANT, khui_main_menu), - CONSTMENU(KHUI_MENU_FILE, KHUI_MENUSTATE_CONSTANT, khui_menu_file), - CONSTMENU(KHUI_MENU_CRED, KHUI_MENUSTATE_CONSTANT, khui_menu_cred), - CONSTMENU(KHUI_MENU_VIEW, KHUI_MENUSTATE_CONSTANT, khui_menu_view), - CONSTMENU(KHUI_MENU_LAYOUT, KHUI_MENUSTATE_CONSTANT, khui_menu_layout), - CONSTMENU(KHUI_MENU_TOOLBARS, KHUI_MENUSTATE_CONSTANT, khui_menu_toolbars), - CONSTMENU(KHUI_MENU_OPTIONS, KHUI_MENUSTATE_CONSTANT, khui_menu_options), - CONSTMENU(KHUI_MENU_HELP, KHUI_MENUSTATE_CONSTANT, khui_menu_help), + CONSTMENU(KHUI_MENU_MAIN, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_main_menu), + CONSTMENU(KHUI_MENU_FILE, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_file), + CONSTMENU(KHUI_MENU_CRED, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_cred), + CONSTMENU(KHUI_MENU_VIEW, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_view), + CONSTMENU(KHUI_MENU_LAYOUT, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_layout), + CONSTMENU(KHUI_MENU_TOOLBARS, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_toolbars), + CONSTMENU(KHUI_MENU_OPTIONS, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_options), + CONSTMENU(KHUI_MENU_HELP, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_help), + CONSTMENU(KHUI_MENU_COLUMNS, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_columns), /* toolbars */ - CONSTMENU(KHUI_TOOLBAR_STANDARD, KHUI_MENUSTATE_CONSTANT, khui_toolbar_standard), + CONSTMENU(KHUI_TOOLBAR_STANDARD, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_toolbar_standard), /* context menus */ CONSTMENU(KHUI_MENU_IDENT_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_ident_ctx), CONSTMENU(KHUI_MENU_TOK_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_tok_ctx), CONSTMENU(KHUI_MENU_ICO_CTX_MIN, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_min), CONSTMENU(KHUI_MENU_ICO_CTX_NORMAL, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_normal), + CONSTMENU(KHUI_MENU_CWHEADER_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_cwheader_ctx), /* pseudo menus */ CONSTMENU(KHUI_PMENU_TOK_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_tok_sel), @@ -195,8 +218,22 @@ khui_menu_def khui_all_menus[] = { }; int khui_n_all_menus = sizeof(khui_all_menus) / sizeof(khui_menu_def); +khui_menu_def ** khui_cust_menus = NULL; +int khui_nc_cust_menus = 0; +int khui_n_cust_menus = 0; CRITICAL_SECTION cs_actions; +#define CACT_NC_ALLOC 32 + +khui_action ** khui_cust_actions = NULL; +int khui_nc_cust_actions = 0; +int khui_n_cust_actions = 0; + +HWND khui_hwnd_main; /* main window, for notifying + action launches and + dispatching messages to the + application. */ + KHMEXP void KHMAPI khui_init_actions(void) { InitializeCriticalSection(&cs_actions); @@ -207,25 +244,208 @@ khui_exit_actions(void) { DeleteCriticalSection(&cs_actions); } +KHMEXP khm_int32 KHMAPI +khui_action_create(const wchar_t * name, + const wchar_t * caption, + const wchar_t * tooltip, + void * userdata, + khm_int32 type, + khm_handle hsub) { + khui_action * act; + khm_int32 action = 0; + int i; + size_t s; + + if (!caption || + FAILED(StringCchLength(caption, KHUI_MAXCCH_SHORT_DESC, &s)) || + (tooltip && FAILED(StringCchLength(tooltip, KHUI_MAXCCH_SHORT_DESC, &s))) || + (type != KHUI_ACTIONTYPE_TRIGGER && type != KHUI_ACTIONTYPE_TOGGLE)) { + return 0; + } + + EnterCriticalSection(&cs_actions); + if (name && (act = khui_find_named_action(name))) { + /* named action already exists */ + action = act->cmd; + goto _done; + } + + for (i=0; i < khui_n_cust_actions; i++) { + if (khui_cust_actions[i] == NULL || + (khui_cust_actions[i]->state & KHUI_ACTIONSTATE_DELETED)) + break; + } + + if (i >= khui_n_cust_actions && + (khui_cust_actions == NULL || + khui_n_cust_actions + 1 > khui_nc_cust_actions)) { + + khui_nc_cust_actions = UBOUNDSS(khui_n_cust_actions + 1, + CACT_NC_ALLOC, + CACT_NC_ALLOC); +#ifdef DEBUG + assert(khui_nc_cust_actions > khui_n_cust_actions + 1); +#endif + khui_cust_actions = PREALLOC(khui_cust_actions, + sizeof(*khui_cust_actions) * khui_nc_cust_actions); +#ifdef DEBUG + assert(khui_cust_actions); +#endif + } + + if (i >= khui_n_cust_actions) { + i = khui_n_cust_actions ++; + act = PMALLOC(sizeof(khui_action)); + } else { + act = khui_cust_actions[i]; + if (act == NULL) + act = PMALLOC(sizeof(khui_action)); + } + +#ifdef DEBUG + assert(act); +#endif + + khui_cust_actions[i] = act; + + ZeroMemory(act, sizeof(*act)); + + act->cmd = KHUI_USERACTION_BASE + i; + act->type = type; + act->name = (name? PWCSDUP(name) : 0); + act->caption = PWCSDUP(caption); + act->tooltip = (tooltip? PWCSDUP(tooltip) : 0); + act->listener = hsub; + act->data = userdata; + act->state = 0; + + action = act->cmd; + + _done: + LeaveCriticalSection(&cs_actions); + + if (action) + kmq_post_message(KMSG_ACT, KMSG_ACT_NEW, action, NULL); + + return action; +} + +KHMEXP void * KHMAPI +khui_action_get_data(khm_int32 action) { + khui_action * act; + + act = khui_find_action(action); + + if (act == NULL) + return NULL; + else + return act->data; +} + +KHMEXP void KHMAPI +khui_action_delete(khm_int32 action) { + khui_action * act; + + act = khui_find_action(action); + + if (act == NULL) + return; + + /* for the moment, even when the action is deleted, we don't free + up the block of memory used by the khui_action structure. When + a new action is created, it will reuse deleted action + structures. */ + EnterCriticalSection(&cs_actions); + act->state |= KHUI_ACTIONSTATE_DELETED; + if (act->name) + PFREE(act->name); + if (act->caption) + PFREE(act->caption); + if (act->tooltip) + PFREE(act->tooltip); + if (act->listener) + kmq_delete_subscription(act->listener); + act->name = NULL; + act->caption = NULL; + act->tooltip = NULL; + act->listener = NULL; + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_DELETE, action, NULL); +} + #define MENU_NC_ITEMS 8 KHMEXP khui_menu_def * KHMAPI -khui_menu_create(int cmd) +khui_menu_create(khm_int32 action) { khui_menu_def * d; d = PMALLOC(sizeof(*d)); ZeroMemory(d, sizeof(*d)); - d->cmd = cmd; + d->cmd = action; d->nc_items = MENU_NC_ITEMS; - d->items = PMALLOC(sizeof(*(d->items)) * d->nc_items); + d->items = PMALLOC(sizeof(*(d->items)) * d->nc_items); d->state = KHUI_MENUSTATE_ALLOCD; + if (action) { + int i; + EnterCriticalSection(&cs_actions); + + for (i=0; i < khui_n_cust_menus; i++) { + if (khui_cust_menus[i] == NULL) + break; + } + + if (i >= khui_n_cust_menus) { + + if (khui_n_cust_menus + 1 >= khui_nc_cust_menus) { + khui_nc_cust_menus = UBOUNDSS(khui_n_cust_menus + 1, + CACT_NC_ALLOC, CACT_NC_ALLOC); + khui_cust_menus = + PREALLOC(khui_cust_menus, + sizeof(khui_cust_menus[0]) * khui_nc_cust_menus); + } + + i = khui_n_cust_menus ++; + } + + khui_cust_menus[i] = d; + + LeaveCriticalSection(&cs_actions); + } + return d; } +KHMEXP void KHMAPI +khui_set_main_window(HWND hwnd) { + khui_hwnd_main = hwnd; +} + +KHMEXP void KHMAPI +khui_action_trigger(khm_int32 action, khui_action_context * ctx) { + khui_action_context save; + + if (!khui_hwnd_main) + return; + + if (ctx) { + khui_context_get(&save); + + khui_context_set_indirect(ctx); + } + + SendMessage(khui_hwnd_main, WM_COMMAND, + MAKEWPARAM(action, 0), (LPARAM) 0); + + if (ctx) { + khui_context_set_indirect(&save); + } +} + KHMEXP khui_menu_def * KHMAPI khui_menu_dup(khui_menu_def * src) { @@ -235,16 +455,16 @@ khui_menu_dup(khui_menu_def * src) d = khui_menu_create(src->cmd); - if(src->n_items == -1) + if (!(src->state & KHUI_MENUSTATE_ALLOCD)) n = khui_action_list_length(src->items); else n = src->n_items; - for(i=0; iitems[i].flags & KHUI_ACTIONREF_PACTION) { - khui_menu_add_paction(d, src->items[i].p_action, src->items[i].flags); + for (i=0; iitems[i].flags & KHUI_ACTIONREF_PACTION) { + khui_menu_insert_paction(d, -1, src->items[i].p_action, src->items[i].flags); } else { - khui_menu_add_action(d, src->items[i].action); + khui_menu_insert_action(d, -1, src->items[i].action, 0); } } @@ -258,8 +478,22 @@ khui_menu_delete(khui_menu_def * d) /* non-allocated menus are assumed to have no pointers to other allocated blocks */ - if(!(d->state & KHUI_MENUSTATE_ALLOCD)) + if(!(d->state & KHUI_MENUSTATE_ALLOCD)) { + /* we shouldn't have tried to delete a constant menu */ +#ifdef DEBUG + assert(FALSE); +#endif return; + } + + EnterCriticalSection(&cs_actions); + for (i=0; i < khui_n_cust_menus; i++) { + if (khui_cust_menus[i] == d) { + khui_cust_menus[i] = NULL; + break; + } + } + LeaveCriticalSection(&cs_actions); for(i=0; i< (int) d->n_items; i++) { if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION) @@ -271,8 +505,12 @@ khui_menu_delete(khui_menu_def * d) PFREE(d); } -static void khui_menu_assert_size(khui_menu_def * d, size_t n) +static void +menu_assert_size(khui_menu_def * d, size_t n) { + + assert(d->state & KHUI_MENUSTATE_ALLOCD); + if(n > (int) d->nc_items) { khui_action_ref * ni; @@ -284,34 +522,153 @@ static void khui_menu_assert_size(khui_menu_def * d, size_t n) } } -KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id) +static void +menu_const_to_allocd(khui_menu_def * d) { - khui_menu_assert_size(d, d->n_items + 1); - d->items[d->n_items].flags = 0; - d->items[d->n_items ++].action = id; + khui_action_ref * olist; + khui_action_ref * nlist; + khm_size n; + + assert(!(d->state & KHUI_MENUSTATE_ALLOCD)); + + olist = d->items; + n = khui_action_list_length(d->items); + + d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS); + nlist = PMALLOC(sizeof(d->items[0]) * d->nc_items); + memcpy(nlist, olist, sizeof(d->items[0]) * n); + + d->items = nlist; + d->n_items = n; + d->state |= KHUI_MENUSTATE_ALLOCD; } -KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags) +KHMEXP void KHMAPI +khui_menu_insert_action(khui_menu_def * d, khm_size idx, khm_int32 action, khm_int32 flags) { - khui_menu_assert_size(d, d->n_items + 1); - d->items[d->n_items].flags = flags | KHUI_ACTIONREF_PACTION; - d->items[d->n_items ++].p_action = act; + if (!(d->state & KHUI_MENUSTATE_ALLOCD)) + menu_const_to_allocd(d); + + assert(d->state & KHUI_MENUSTATE_ALLOCD); + assert(action == KHUI_MENU_SEP || action > 0); + + if (idx < 0 || idx > d->n_items) + idx = d->n_items; + + menu_assert_size(d, d->n_items + 1); + + if (idx < d->n_items) { + memmove(&d->items[idx + 1], &d->items[idx], (d->n_items - idx) * sizeof(d->items[0])); + } + + d->items[idx].flags = flags; + d->items[idx].action = action; + if (action == KHUI_MENU_SEP) + d->items[idx].flags |= KHUI_ACTIONREF_SEP; + + d->n_items++; +} + +KHMEXP void KHMAPI +khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * paction, int flags) +{ + + if (paction == NULL) + return; + + if (!(d->state & KHUI_MENUSTATE_ALLOCD)) + menu_const_to_allocd(d); + + assert(d->state & KHUI_MENUSTATE_ALLOCD); + + if (idx < 0 || idx > d->n_items) + idx = d->n_items; + + menu_assert_size(d, d->n_items + 1); + + if (idx < d->n_items) { + memmove(&d->items[idx + 1], &d->items[idx], (d->n_items - idx) * sizeof(d->items[0])); + } + + d->items[idx].flags = flags | KHUI_ACTIONREF_PACTION; + d->items[idx].p_action = paction; + + d->n_items++; } -KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id) { +KHMEXP void KHMAPI +khui_menu_remove_action(khui_menu_def * d, khm_size idx) { + + assert(d->state & KHUI_MENUSTATE_ALLOCD); + + if (idx < 0 || idx >= d->n_items) + return; + + if (idx < d->n_items - 1) { + memmove(&d->items[idx], &d->items[idx + 1], + ((d->n_items - 1) - idx) * sizeof(d->items[0])); + } + + d->n_items--; +} + +KHMEXP khm_size KHMAPI +khui_menu_get_size(khui_menu_def * d) { + + if (d->state & KHUI_MENUSTATE_ALLOCD) + return d->n_items; + else + return khui_action_list_length(d->items); +} + +KHMEXP khui_action_ref * +khui_menu_get_action(khui_menu_def * d, khm_size idx) { + + khm_size n; + + if (d->state & KHUI_MENUSTATE_ALLOCD) + n = d->n_items; + else + n = khui_action_list_length(d->items); + + if (idx < 0 || idx >= n) + return NULL; + + return &d->items[idx]; +} + +KHMEXP khui_menu_def * KHMAPI +khui_find_menu(khm_int32 id) { khui_menu_def * d; int i; - d = khui_all_menus; - for(i=0;icmd == id) { + d = khui_cust_menus[i]; + break; + } + } + LeaveCriticalSection(&cs_actions); + + return d; + } } -KHMEXP khui_action * KHMAPI khui_find_action(int id) { +KHMEXP khui_action * KHMAPI +khui_find_action(khm_int32 id) { khui_action * act; int i; @@ -321,12 +678,28 @@ KHMEXP khui_action * KHMAPI khui_find_action(int id) { return &act[i]; } - return NULL; + act = NULL; + + EnterCriticalSection(&cs_actions); + if (id >= KHUI_USERACTION_BASE && + (id - KHUI_USERACTION_BASE) < khui_n_cust_actions) { + act = khui_cust_actions[id - KHUI_USERACTION_BASE]; +#ifdef DEBUG + assert(!act || act->cmd == id); +#endif + if (act && act->state & KHUI_ACTIONSTATE_DELETED) + act = NULL; + } + LeaveCriticalSection(&cs_actions); + + return act; } -KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name) { +KHMEXP khui_action * KHMAPI +khui_find_named_action(const wchar_t * name) { int i; khui_action * act; + khui_action ** pact; if(!name) return NULL; @@ -339,25 +712,42 @@ KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name) { return &act[i]; } + pact = khui_cust_actions; + for(i=0;iname) + continue; + + if(!wcscmp(pact[i]->name, name)) { + if (pact[i]->state & KHUI_ACTIONSTATE_DELETED) + return NULL; + else + return pact[i]; + } + } + return NULL; } -KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref) { +KHMEXP size_t KHMAPI +khui_action_list_length(khui_action_ref * ref) { size_t c = 0; - while(ref && ref->action != KHUI_MENU_END) { + while(ref && ref->action != KHUI_MENU_END && + !(ref->flags & KHUI_ACTIONREF_END)) { c++; ref++; } return c; } -KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) +KHMEXP void KHMAPI +khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) { khui_action_ref * r; khui_action * act; r = d->items; - while(r && r->action != KHUI_MENU_END) { + while(r && r->action != KHUI_MENU_END && + (!(d->state & KHUI_MENUSTATE_ALLOCD) || (r - d->items) < (int) d->n_items)) { if(r->flags & KHUI_ACTIONREF_PACTION) { act = r->p_action; } else { @@ -376,7 +766,8 @@ KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); } -KHMEXP void KHMAPI khui_check_action(int cmd, khm_boolean check) { +KHMEXP void KHMAPI +khui_check_action(khm_int32 cmd, khm_boolean check) { khui_action * act; act = khui_find_action(cmd); @@ -393,14 +784,16 @@ KHMEXP void KHMAPI khui_check_action(int cmd, khm_boolean check) { kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); } -KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable) +KHMEXP void KHMAPI +khui_enable_actions(khui_menu_def * d, khm_boolean enable) { khui_action_ref * r; int delta = FALSE; khui_action * act; r = d->items; - while(r && r->action != KHUI_MENU_END) { + while(r && r->action != KHUI_MENU_END && + (!(d->state & KHUI_MENUSTATE_ALLOCD) || (r - d->items) < (int) d->n_items)) { if(r->flags & KHUI_ACTIONREF_PACTION) { act = r->p_action; } else { @@ -426,7 +819,8 @@ KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable) } } -KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable) { +KHMEXP void KHMAPI +khui_enable_action(khm_int32 cmd, khm_boolean enable) { khui_action * act; act = khui_find_action(cmd); @@ -443,7 +837,8 @@ KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable) { kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); } -KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void) { +KHMEXP HACCEL KHMAPI +khui_create_global_accel_table(void) { int i; ACCEL * accels; HACCEL ha; @@ -463,9 +858,9 @@ KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void) { } KHMEXP khm_boolean KHMAPI -khui_get_cmd_accel_string(int cmd, +khui_get_cmd_accel_string(khm_int32 cmd, wchar_t * buf, - size_t bufsiz) { + khm_size bufsiz) { int i; khui_accel_def * def; @@ -517,10 +912,46 @@ khui_get_cmd_accel_string(int cmd, ap = L"Enter"; break; + case VK_F1: + ap = L"F1"; + break; + + case VK_F2: + ap = L"F2"; + break; + + case VK_F3: + ap = L"F3"; + break; + + case VK_F4: + ap = L"F4"; + break; + case VK_F5: ap = L"F5"; break; + case VK_F6: + ap = L"F6"; + break; + + case VK_F7: + ap = L"F7"; + break; + + case VK_F8: + ap = L"F8"; + break; + + case VK_F9: + ap = L"F9"; + break; + + case VK_F10: + ap = L"F10"; + break; + case VK_DELETE: ap = L"Del"; break; @@ -824,6 +1255,20 @@ khui_context_set_ex(khui_scope scope, LeaveCriticalSection(&cs_actions); } +KHMEXP void KHMAPI +khui_context_set_indirect(khui_action_context * ctx) +{ + EnterCriticalSection(&cs_actions); + + khuiint_context_release(&khui_ctx); + + khuiint_copy_context(&khui_ctx, ctx); + + khui_context_refresh(); + + LeaveCriticalSection(&cs_actions); +} + KHMEXP void KHMAPI khui_context_refresh(void) { khm_int32 flags; diff --git a/src/windows/identity/uilib/actiondef.cfg b/src/windows/identity/uilib/actiondef.cfg index 14600b0b6..0627a67e5 100644 --- a/src/windows/identity/uilib/actiondef.cfg +++ b/src/windows/identity/uilib/actiondef.cfg @@ -29,6 +29,8 @@ This file was autogenerated from src/ui/actiondef.cfg and src/ui/actions.csv. Do not modify directly. */ +#define NOEXPORT + #include #include #include"../ui/resource.h" @@ -36,11 +38,11 @@ Do not modify directly. khui_action khui_actions [] = { EOS -$record_prefix = "{"; +$record_prefix = "ACTION_FULL("; $record_sep = ",\n"; -$record_postfix = "}"; +$record_postfix = ")"; $file_postfix = <flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) { PFREE(alert->message); - alert->message = NULL; alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; - } + alert->message = NULL; + if(message) { alert->message = PMALLOC(cb); StringCbCopy(alert->message, cb, message); @@ -263,6 +263,20 @@ khui_alert_show(khui_alert * alert) return KHM_ERROR_SUCCESS; } +KHMEXP khm_int32 KHMAPI +khui_alert_show_modal(khui_alert * alert) +{ + khm_int32 rv; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + khui_alert_hold(alert); + rv = kmq_send_message(KMSG_ALERT, KMSG_ALERT_SHOW_MODAL, 0, + (void *) alert); + + return rv; +} + KHMEXP khm_int32 KHMAPI khui_alert_queue(khui_alert * alert) { diff --git a/src/windows/identity/uilib/configui.c b/src/windows/identity/uilib/configui.c index 51498c0b2..ae8cd2f7c 100644 --- a/src/windows/identity/uilib/configui.c +++ b/src/windows/identity/uilib/configui.c @@ -182,12 +182,22 @@ khui_cfg_register(khui_config_node vparent, parent = cfgui_node_i_from_handle(vparent); } - //node->owner = kmm_this_plugin(); + /* plugin handles should not be obtained lightly. For the moment, + the cleanup of nodes doesn't happen until module unload and + module unload doesn't happen until all the plugin and module + handles have been freed. */ + /* node->owner = kmm_this_plugin(); */ EnterCriticalSection(&cs_cfgui); TADDCHILD(parent, node); LeaveCriticalSection(&cs_cfgui); + /* when the root config list changes, we need to notify the UI. + this way, the Options menu can be kept in sync. */ + if (parent == cfgui_root_config) { + kmq_post_message(KMSG_ACT, KMSG_ACT_SYNC_CFG, 0, 0); + } + return KHM_ERROR_SUCCESS; } @@ -586,6 +596,11 @@ khui_cfg_set_param(khui_config_node vnode, LPARAM param) { LeaveCriticalSection(&cs_cfgui); } +static void +clear_node_data(khui_config_node_i * node) { + node->n_data = 0; +} + static cfg_node_data * get_node_data(khui_config_node_i * node, void * key, @@ -623,6 +638,10 @@ get_node_data(khui_config_node_i * node, } node->data[node->n_data].key = key; + node->data[node->n_data].hwnd = NULL; + node->data[node->n_data].param = 0; + node->data[node->n_data].flags = 0; + node->n_data++; return &(node->data[node->n_data - 1]); @@ -763,6 +782,8 @@ cfgui_clear_params(khui_config_node_i * node) { node->hwnd = NULL; node->param = 0; node->flags &= KHUI_CNFLAGMASK_STATIC; + clear_node_data(node); + c = TFIRSTCHILD(node); while(c) { cfgui_clear_params(c); @@ -801,8 +822,7 @@ khui_cfg_set_flags(khui_config_node vnode, mask &= KHUI_CNFLAGMASK_DYNAMIC; EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode) && - hwnd_cfgui != NULL) { + if (cfgui_is_valid_node_handle(vnode)) { node = cfgui_node_i_from_handle(vnode); @@ -926,8 +946,7 @@ khui_cfg_get_flags(khui_config_node vnode) { return 0; EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode) && - hwnd_cfgui != NULL) { + if (cfgui_is_valid_node_handle(vnode)) { node = cfgui_node_i_from_handle(vnode); @@ -950,8 +969,7 @@ khui_cfg_get_name(khui_config_node vnode, return KHM_ERROR_INVALID_PARAM; EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode) && - hwnd_cfgui != NULL) { + if (cfgui_is_valid_node_handle(vnode)) { khm_size cb; node = cfgui_node_i_from_handle(vnode); diff --git a/src/windows/identity/uilib/creddlg.c b/src/windows/identity/uilib/creddlg.c index dae98ff68..082f9f257 100644 --- a/src/windows/identity/uilib/creddlg.c +++ b/src/windows/identity/uilib/creddlg.c @@ -247,8 +247,7 @@ khui_cw_del_type(khui_new_creds * c, } KHMEXP khm_int32 KHMAPI -khui_cw_find_type( - khui_new_creds * c, +khui_cw_find_type(khui_new_creds * c, khm_int32 type, khui_new_creds_by_type **t) { @@ -271,8 +270,7 @@ khui_cw_find_type( KHMEXP khm_int32 KHMAPI -khui_cw_enable_type( - khui_new_creds * c, +khui_cw_enable_type(khui_new_creds * c, khm_int32 type, khm_boolean enable) { @@ -299,8 +297,7 @@ khui_cw_enable_type( } KHMEXP khm_boolean KHMAPI -khui_cw_type_succeeded( - khui_new_creds * c, +khui_cw_type_succeeded(khui_new_creds * c, khm_int32 type) { khui_new_creds_by_type * t; @@ -543,8 +540,7 @@ khui_cw_get_prompt_count(khui_new_creds * c, } KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt( - khui_new_creds * c, +khui_cw_get_prompt(khui_new_creds * c, khm_size idx, khui_new_creds_prompt ** prompt) { @@ -570,19 +566,29 @@ KHMEXP khm_int32 KHMAPI khui_cw_sync_prompt_values(khui_new_creds * c) { khm_size i; + khm_size n; + HWND hw; + wchar_t tmpbuf[KHUI_MAXCCH_PROMPT_VALUE]; EnterCriticalSection(&c->cs); - for(i=0;in_prompts;i++) { + redo_loop: + n = c->n_prompts; + for(i=0; iprompts[i]; if(p->hwnd_edit) { - /* Ideally, we would retrieve the text to a temporary - buffer with the c->cs released, obtain c->cs and copy the - text to p->value. However, I'm not going to bother as the - code paths we are touching here do not need c->cs while - setting p->value does */ - GetWindowText(p->hwnd_edit, p->value, - KHUI_MAXCCH_PROMPT_VALUE); + hw = p->hwnd_edit; + LeaveCriticalSection(&c->cs); + + GetWindowText(hw, tmpbuf, ARRAYLENGTH(tmpbuf)); + + EnterCriticalSection(&c->cs); + if (n != c->n_prompts) + goto redo_loop; + SecureZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE); + StringCchCopy(p->value, KHUI_MAXCCH_PROMPT_VALUE, + tmpbuf); } } LeaveCriticalSection(&c->cs); diff --git a/src/windows/identity/uilib/khaction.h b/src/windows/identity/uilib/khaction.h index fccdab549..e8f6cd64a 100644 --- a/src/windows/identity/uilib/khaction.h +++ b/src/windows/identity/uilib/khaction.h @@ -34,28 +34,74 @@ /*! \brief An action */ typedef struct tag_khui_action { - int cmd; /*!< command id */ - int type; /*!< combination of KHUI_ACTIONTYPE_* */ - wchar_t * name; /*!< name for named actions. NULL if not named. */ - - /* normal, hot and disabled are toolbar sized bitmaps */ - int ib_normal; /*!< normal bitmap (index) */ - int ib_hot; /*!< hot bitmap (index) */ - int ib_disabled; /*!< disabled bitmap (index) */ - - int ib_icon; /*!< index of small (16x16) icon (for menu) */ - int ib_icon_dis; /*!< index of disabled (greyed) icon */ - - int is_caption; /*!< index of string resource for caption */ - int is_tooltip; /*!< same for description / tooltip */ - int ih_topic; /*!< help topic */ - int state; /*!< current state. combination of KHUI_ACTIONSTATE_* */ + khm_int32 cmd; /*!< action identifier */ + khm_int32 type; /*!< combination of KHUI_ACTIONTYPE_* */ + wchar_t * name; /*!< name for named actions. NULL if + not named. */ + + /* The following fields are only for use by NetIDMgr */ + khm_int16 ib_normal; /*!< (internal) normal bitmap (index) (toolbar sized icon) */ + khm_int16 ib_hot; /*!< (internal) hot bitmap (index) (toolbar sized icon) */ + khm_int16 ib_disabled; /*!< (internal) disabled bitmap (index) (toolbar sized icon) */ + + khm_int16 ib_icon; /*!< (internal) index of small (16x16) icon (for menu) (small icon) */ + khm_int16 ib_icon_dis; /*!< (internal) index of disabled (greyed) icon (small icon) */ + + khm_int16 is_caption; /*!< (internal) index of string resource for caption */ + khm_int16 is_tooltip; /*!< (internal) same for description / tooltip */ + khm_int16 ih_topic; /*!< (internal) help topic */ + + /* The following fields are specified for custom actions */ + wchar_t * caption; /*!< Caption (localized) (limited by + KHUI_MAXCCH_SHORT_DESC). The + caption is used for representing the + action in menus and toolbars. */ + wchar_t * tooltip; /*!< Tooltip (localized) (limited by + KHUI_MAXCCH_SHORT_DESC). If this is + specified, whenever the user hovers + over the menu item or toolbar button + representing the action, the tooltip + will be displayed either on a + tooltip window or in the status + bar. */ + khm_handle listener; /*!< Listener of this action. Should be + a handle to a message + subscription. When the action is + invoked, a message of type + ::KMSG_ACT and subtype + ::KMSG_ACT_ACTIVATE will be posted + to this subscriber. The \a uparam + parameter of the message will have + the identifier of the action. */ + void * data; /*!< User data for custom action. This + field is not used by the UI library. + It is reserved for plugins to store + data that is specific for this + action. The data that's passed in + in the \a userdata parameter to + khui_action_create() will be stored + here and can be retrieved by calling + khui_action_get_data(). */ + void * reserved1; /*!< Reserved. */ + void * reserved2; /*!< Reserved. */ + void * reserved3; /*!< Reserved. */ + + /* For all actions */ + int state; /*!< current state. combination of + KHUI_ACTIONSTATE_* */ } khui_action; -/*! \brief Unknown action type */ +/*! \brief Unknown action type + + Unknown action type. + */ #define KHUI_ACTIONTYPE_NONE 0 -/*! \brief A trigger type action */ +/*! \brief A trigger type action + + A trigger action usually triggers some event, which is what pretty + much every action does. +*/ #define KHUI_ACTIONTYPE_TRIGGER 1 /*! \brief A toggle type action @@ -65,12 +111,19 @@ typedef struct tag_khui_action { */ #define KHUI_ACTIONTYPE_TOGGLE 2 -/*! \brief The action is enabled */ +/*! \brief The action is enabled + + This is the default if no other state is specified. Just means + not-disabled. +*/ #define KHUI_ACTIONSTATE_ENABLED 0 + /*! \brief The action is diabled */ #define KHUI_ACTIONSTATE_DISABLED 1 + /*! \brief For toggle type actions, the action is checked */ #define KHUI_ACTIONSTATE_CHECKED 2 + /*! \brief The action is hot Typically this means that the user is hovering the pointing device @@ -78,31 +131,97 @@ typedef struct tag_khui_action { */ #define KHUI_ACTIONSTATE_HOT 4 +/*! \brief The action has been marked for deletion + + For custom actions, this means that the custom action was deleted. + The contents of the custom action fields are no longer valid. + */ +#define KHUI_ACTIONSTATE_DELETED 8 + #ifdef NOEXPORT #define ACTION_SIMPLE(c,cap,des,top) \ - {c,KHUI_ACTIONTYPE_TRIGGER,0,0,0,0,0,cap,des,top,0} + {c,KHUI_ACTIONTYPE_TRIGGER,NULL,0,0,0,0,0,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} -#define ACTION_FULL(cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state) \ - {cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state} +#define ACTION_FULL(cmd,type,name,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state) \ + {cmd,type,name,inormal,ihot,idis,isml,ismld,capt,toolt,topic,NULL,NULL,NULL,NULL,NULL,NULL,NULL,state} #define ACTION_SIMPLE_IMAGE(c,inormal, ihot, idis, isml, ismld,cap, des, top) \ - {c,KHUI_ACTIONTYPE_TRIGGER,inormal,ihot,idis,isml,ismld,cap,des,top,0} + {c,KHUI_ACTIONTYPE_TRIGGER,NULL,inormal,ihot,idis,isml,ismld,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} #endif -/*! \brief A reference to an action */ +/*! \brief A reference to an action + + If the \a flags member has the KHUI_ACTIONREF_PACTION bit set, + then the action is referenced by the \a p_action member of the + union. Otherwise the identifier for the action is specified by \a + action member. +*/ typedef struct tag_khui_action_ref { - int flags; + int flags; /*!< A combination of KHUI_ACTIONREF_* */ union { - int action; - khui_action * p_action; + khm_int32 action; /*!< The action identifier for the + action that is being referrred to. + Only valid if + ::KHUI_ACTIONREF_PACTION is not set + in \a flags. */ + khui_action * p_action; /*!< A pointer to the ::khui_action + structure that describes the action + that is being referred to. Only + valid if ::KHUI_ACTIONREF_PACTION is + set. */ }; } khui_action_ref; +/*! \brief A submenu + + There should exist a menu associated with the action that is being + referred. When displaying this action in a menu, the contents of + the associated menu will appear as a submenu. + */ #define KHUI_ACTIONREF_SUBMENU 0x01 + +/*! \brief Separator + + This is not an actual action, but represents a separator between + actions. When displaying this action in a menu or a toolbar, a + separating line will be drawn in place of this action. The \a + action and \a p_action members of the structures are unused if + this flag is set. + */ #define KHUI_ACTIONREF_SEP 0x02 + +/*! \brief Action by reference + + The \a p_action member of the structure points to the + ::khui_action structure that describes the action. + */ #define KHUI_ACTIONREF_PACTION 0x04 + +#ifdef NOEXPORT +/*! \brief Action should be freed + + \note This flag is reserved for internal use in the NetIDMgr + application. Do not use. + */ #define KHUI_ACTIONREF_FREE_PACTION 0x08 + +/*! \brief Marks the end of an action sequence + + \note THis flag is reserved for internal use in the NetIDMgr + application. Do not use. + */ #define KHUI_ACTIONREF_END 0x10 +#endif + +/*! \brief The default action + + When this bit is set in an action reference that describes a menu, + the menu item will be the default item and will be rendered + differently from other menu items. Only useful when defining + context menus. In general, it is good practice to place the + default item at the top of a menu, although the UI library does + not enforce this. This is purely meant as a rendering hint. + */ #define KHUI_ACTIONREF_DEFAULT 0x20 #ifdef NOEXPORT @@ -113,35 +232,94 @@ typedef struct tag_khui_action_ref { #define MENU_END() {KHUI_ACTIONREF_END,KHUI_MENU_END} #endif -/*! \brief Menu definition */ +/*! \brief Menu definition + + Use the khui_menu_create(), khui_menu_insert_action(), + khui_menu_insert_paction(), khui_menu_get_size(), + khui_menu_get_action() functions to create and manipulate custom + menus. Do not manipulate this structure directly as doing so may + cause inconsistencies in the UI library. +*/ typedef struct tag_khui_menu_def { - int cmd; /*!< Action associated with menu */ - int state; /*!< combination of KHUI_MENUSTATE_* */ - size_t n_items; /*!< total number of items or -1 if not - set. If this is -1, then the list of - actions must be terminated with a - ACTION_LIST_END entry. */ - size_t nc_items; /*!< max number of items in the buffer + khm_int32 cmd; /*!< Action associated with menu */ + khm_int32 state; /*!< combination of KHUI_MENUSTATE_* */ + khm_size n_items; /*!< The number of actions in the \a items + list. If this is a custom menu, the + ::KHUI_MENUSTATE_ALLOCD bit will be set, + and the contents of this field will be + valid. Otherwise, the contents of this + field is ignored and the list of actions + must be terminated with a + ACTION_LIST_END action. */ + khm_size nc_items; /*!< max number of items in the buffer alocated for items. Ignored if - KHUI_MENUSTATE_CONSTANT is set in \a - state.*/ + ::KHUI_MENUSTATE_ALLOCD is not set in \a + state. */ khui_action_ref *items; /*!< Action list terminated by, ACTION_LIST_END. If \a n_items is set to a value other than -1, the list doesn't necessarily have to end with a - ACTION_LIST_END. */ + ACTION_LIST_END. When constructing a + menu using khui_menu_* functions, they + will set the size of this list in the \a + n_items member, and there will be no + ACTION_LIST_END action to terminate the + list. */ } khui_menu_def; #ifdef NOEXPORT #define CONSTMENU(c,s,i) {c,s,-1,-1,i} #endif +/*! \brief Unspecified menu + + Used when there is no single command associated with the entire + menu, such as for ad-hoc context menus. + */ +#define KHUI_MENU_NONE -3 + +/*! \brief Menu end indicator + + For static or constant menus this indicates that this action marks + the end of the list of actions which defined the menu. This is + invalid if used in a dynamic menu (a menu with the + ::KHUI_MENUSTATE_ALLOCD bit set). + */ #define KHUI_MENU_END -2 + +/*! \brief Menu separator + + A separator for actions. When displaying a menu or showing a + toolbar based on a menu definition, a separator is rendered as a + bar separating the user interface elements for the actions on + either side of this. +*/ #define KHUI_MENU_SEP -1 +/*! \brief Constant menu + + The contents of the menu cannot be modified (individual actions in + the menu may be modified, but the order and the contents of the + menu itself cannot be modified. + + This is the default if ::KHUI_MENUSTATE_ALLOCD is not specified. + */ #define KHUI_MENUSTATE_CONSTANT 0 + +/*! \brief Variable menu + + The menu is dnamically allocated. The list of actions contained + in the menu can be modified. +*/ #define KHUI_MENUSTATE_ALLOCD 1 +#ifdef NOEXPORT +/* predefined system menu */ +#define KHUI_MENUSTATE_SYSTEM 2 +#endif + +#ifdef NOEXPORT + /*! \brief Accelerator definition */ typedef struct tag_khui_accel_def { int cmd; @@ -152,8 +330,6 @@ typedef struct tag_khui_accel_def { #define KHUI_ACCEL_SCOPE_GLOBAL 0 -#ifdef NOEXPORT - extern khui_accel_def khui_accel_global[]; extern int khui_n_accel_global; @@ -167,11 +343,154 @@ extern int khui_n_all_menus; /* functions */ -KHMEXP khui_menu_def * KHMAPI khui_menu_create(int cmd); -KHMEXP khui_menu_def * KHMAPI khui_menu_dup(khui_menu_def * src); -KHMEXP void KHMAPI khui_menu_delete(khui_menu_def * d); -KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id); -KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags); +/*! \brief Create a new menu + + Creates a new menu. The returned data structure must be freed by + a call to khui_menu_delete(). Custom menus that are created this + way are not reference counted or maintained by the UI library. + The caller is responsible for calling khui_menu_delete() when the + data is no longer needed. + + Specifiying an action in the \a action parameter will associate + the menu with the specified action. In this case, if the action + is added to another menu with the ::KHUI_ACTIONREF_SUBMENU flag, + this menu will appear as a submenu within that menu. Only one + menu can be associated with any given action. Custom menus can + not be associated with standard actions. + */ +KHMEXP khui_menu_def * KHMAPI +khui_menu_create(khm_int32 action); + +/*! \brief Duplicate a menu + + Creates a copy of the specified menu. The returned data structure + must be freed by a call to khui_menu_delete(). Custom menus are + not reference counted or maintained by the UI library. The caller + is responsible for calling khui_menu_delete() when the data is no + longer needed. + + Note that even if the original menu was associated with an action, + the duplicate will not be. Modifying the duplicate will not + modify the original menu. Only one menu can be associated with an + action. + */ +KHMEXP khui_menu_def * KHMAPI +khui_menu_dup(khui_menu_def * src); + +/*! \brief Delete a menu + + Deletes a menu created by a call to khui_menu_create() or + khui_menu_dup(). This frees up the memory and associated + resources used by the menu definition. The pointer that is passed + in will no longer be valid. + */ +KHMEXP void KHMAPI +khui_menu_delete(khui_menu_def * d); + +/*! \brief Insert an action into a menu + + The action specified by \a cmd will be inserted in to the menu \a + d at index \a idx. + + \param[in] d The menu to insert the action into + + \param[in] idx The index at which to insert the action. The index + is zero based. If \a idx is (-1) or larger than the largest + index in the menu, the item is appended to the menu. + + \param[in] cmd The command representing the action to insert into + the menu. This should be either a standard action, a user + action created with khui_action_create(), or certain pseudo + actions. Not all pseudo actions can be placed on a menu. + + \param[in] flags Flags for the action. This is a combination of + KHUI_ACTIONREF_* constants. Currently, the only constants + that are valid for this function are: ::KHUI_ACTIONREF_SEP, + ::KHUI_ACTIONREF_SUBMENU, ::KHUI_ACTIONREF_DEFAULT. + ::KHUI_ACTIONREF_SEP will be automatically added if the + command is ::KHUI_MENU_SEP. + + \note The ::khui_menu_def structure is not thread safe. Multiple + threads modifying the same ::khui_menu_def structure may cause + thread safety issues. + */ +KHMEXP void KHMAPI +khui_menu_insert_action(khui_menu_def * d, khm_size idx, khm_int32 cmd, khm_int32 flags); + +#define khui_menu_add_action(d,c) khui_menu_insert_action((d),-1,(c),0) +#pragma deprecated(khui_menu_add_action) + +#ifdef NOEXPORT + +/*! \brief Insert an action by reference into a menu + + The action specified by \a act will be inserted into the menu \a d + at index \a idx. + + \param[in] d The menu to inser the action into. + + \param[in] idx The index at which to insert the action. The index + is zero based. If the index is (-1) or is larger than the + largest index in the menu, then the action is appended to the + menu. + + \param[in] act The action to insert. This is added by reference. + It is the callers reponsibility to ensure that the structure + pointed to by \a act is available throughout the lifetime of + the menu. + + \param[in] flags Flags for the action. This is a combination of + KHUI_ACTIONREF_* constants. Currently, the only constants + that are valid for this function are: ::KHUI_ACTIONREF_SEP, + ::KHUI_ACTIONREF_SUBMENU, ::KHUI_ACTIONREF_DEFAULT. For this + function, ::KHUI_ACTIONREF_PACTION will automatically be aded + when adding the action. ::KHUI_ACTIONREF_SEP will be + automatically added if the command is ::KHUI_MENU_SEP. + + \note The ::khui_menu_def structure is not thread safe. Multiple + threads modifying the same ::khui_menu_def structure may cause + thread safety issues. +*/ +KHMEXP void KHMAPI +khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * act, khm_int32 flags); + +#define khui_menu_add_paction(d,a,f) khui_menu_insert_paction((d),-1,(a),(f)) +#pragma deprecated(khui_menu_add_paction) + +#endif + +/*! \brief Remove an action from a menu + + The action at the specified index will be removed from the menu. + */ +KHMEXP void KHMAPI +khui_menu_remove_action(khui_menu_def * d, khm_size idx); + +/*! \brief Get the number of items in the menu + + Note that the count includes menu separators. The indices of the + menu items range from 0 to one less than the value returned by + this function. + */ +KHMEXP khm_size KHMAPI +khui_menu_get_size(khui_menu_def * d); + +/*! \brief Get the menu item at a specified index + + The returned reference is only valid while the ::khui_menu_def + structure is valid. In addition, the reference becomes invalid if + the list of actions in the menu data structure is modified in any + way. + + If the specified index is out of bounds, then the function returns + NULL. + + \note The ::khui_menu_def structure is not thread safe. Multiple + threads modifying the same ::khui_menu_def structure may cause + thread safety issues. + */ +KHMEXP khui_action_ref * +khui_menu_get_action(khui_menu_def * d, khm_size idx); /*! \brief Action scope identifiers @@ -399,6 +718,16 @@ khui_context_set_ex(khui_scope scope, void * vparam, khm_size cb_vparam); +/*! \brief Set the current UI context using an existing context + + Copies the context specified in \a ctx into the active UI context. + + \param[in] ctx A pointer to a ::khui_action_context structure that + specifies the new UI context. Cannot be NULL. +*/ +KHMEXP void KHMAPI +khui_context_set_indirect(khui_action_context * ctx); + /*! \brief Obtain the current UI context The parameter specified by \a ctx will receive the current UI @@ -501,21 +830,125 @@ khui_context_cursor_filter(khm_handle cred, \return TRUE if the operation was successful. FALSE otherwise. */ -KHMEXP khm_boolean KHMAPI khui_get_cmd_accel_string(int cmd, wchar_t * buf, size_t bufsiz); +KHMEXP khm_boolean KHMAPI khui_get_cmd_accel_string(khm_int32 cmd, wchar_t * buf, khm_size bufsiz); +#ifdef NOEXPORT +/*! \brief Initializes the global accelerator table + */ KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void); +#endif -/*! \brief Find a menu by id */ -KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id); +/*! \brief Find a menu by id -/*! \brief Find an action by id */ -KHMEXP khui_action * KHMAPI khui_find_action(int id); + Finds the menu that is associated with the specified action. + */ +KHMEXP khui_menu_def * KHMAPI khui_find_menu(khm_int32 action); +#ifdef NOEXPORT + +/* internal */ +KHMEXP void KHMAPI +khui_set_main_window(HWND hwnd); + +#endif + +/*! \brief Trigger an action + + Triggers the specified action using the specified UI context. + + This function does not return until the specified action has been + processed. Many standard actions are asynchronous and they will + return before processing will complete. + + Pseudo actions should not be triggered using khui_action_trigger() + as they only carry meaning when invoked from specific windows or + contexts. + + \param[in] action Action. Should be one of the standard actions + or an action created by khui_action_create() + + \param[in] ctx The UI context to use for the action. If this is + NULL, the action will be triggered under the current UI context. + */ +KHMEXP void KHMAPI +khui_action_trigger(khm_int32 action, khui_action_context * ctx); + +/*! \brief Find an action by id + + \note This function should not be used by plugins. It is there + for use by the NetIDMgr application. +*/ +KHMEXP khui_action * KHMAPI khui_find_action(khm_int32 action); + +#ifdef NOEXPORT /*! \brief Get the length of the action list */ KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref); +#endif + +/*! \brief Create a new action + + \param[in] name Name for a named action. The name must be unique + among all registered actions. (limited by KHUI_MAXCCH_NAME) + (Optional. Set to NULL if the action is not a named action.) + + \param[in] caption The localized caption for the action. This + will be shown in menus, toolbars and buttons when the action + needs to be represented. (limited by KHUI_MAXCCH_SHORT_DESC) + (Required) + + \param[in] tooltip The localized tooltip for the action. (limited + by KHUI_MAXCCH_SHORT_DESC) (Optional, set to NULL if there is + no tooltip associated with the action) + + \param[in] hsub The subscription that is notified when the action + is triggered. (Optional) The subscription can be created with + kmq_create_subscription(). The handle will be released when + it is no longer needed. Hence, the caller should not release + it. + + \param[in] type The type of the action. Currently it should be + set to either ::KHUI_ACTIONTYPE_TRIGGER or + ::KHUI_ACTIONTYPE_TOGGLE. For ::KHUI_ACTIONTYPE_TOGGLE, the + initial state will be unchecked. Use khui_check_action() + function to change the checked state of the action. + + \param[in] userdata A custom value. + + \return The identifier of the new action or zero if the action + could not be created. + + \note For named custom actions, the name of the action can not be + the same as the name of a configuration node. See + khui_cfg_register_node(). + */ +KHMEXP khm_int32 KHMAPI +khui_action_create(const wchar_t * name, + const wchar_t * caption, + const wchar_t * tooltip, + void * userdata, + khm_int32 type, + khm_handle hsub); + +/* \brief Delete a custom action + + Deletes a custom action created by a call to khui_action_create(). + Custom actions should only be deleted when unloading a plugin. + */ +KHMEXP void KHMAPI +khui_action_delete(khm_int32 action); + +/*! \brief Get the user data associated with a custom action + + This function returns the user data that was specified when the + custom action was created usng khui_action_create(). If the + custom action identifier is invalid or if the custom action does + not contain any user data, this function will return NULL. + */ +KHMEXP void * KHMAPI +khui_action_get_data(khm_int32 action); /*! \brief Find an action by name */ -KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name); +KHMEXP khui_action * KHMAPI khui_find_named_action(const wchar_t * name); /*! \brief Enables or disables a group of actions @@ -527,24 +960,32 @@ KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable); /*! \brief Enables or disables an action - The action designated by the command \a cmd will either be enabled + The action designated by the command \a action will either be enabled or disabled depending on the \a enable parameter. If \a enable is TRUE then the action is enabled. */ -KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable); +KHMEXP void KHMAPI khui_enable_action(khm_int32 action, khm_boolean enable); /*! \brief Check an action in an action group - Marks the action denoted by \a cmd as checked and resets the + Marks the action denoted by \a action as checked and resets the checked bit in all other actions. \param[in] d A menu definition. - \param[in] cmd A command identifier. Setting this to -1 will + + \param[in] action A command identifier. Setting this to -1 will reset the checked bit in all the actions in the menu definition. */ -KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd); +KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 action); + +/*! \brief Check an action + For toggle typed actions, this sets or resets the check. + */ +KHMEXP void KHMAPI khui_check_action(khm_int32 cmd, khm_boolean check); + +#ifdef NOEXPORT /*!\cond INTERNAL */ /*! \brief Initialize actions @@ -560,6 +1001,7 @@ KHMEXP void KHMAPI khui_init_actions(void); KHMEXP void KHMAPI khui_exit_actions(void); /*! \endcond */ +#endif /*@}*/ /*@}*/ diff --git a/src/windows/identity/uilib/khactiondef.h b/src/windows/identity/uilib/khactiondef.h index 3f1c43073..a5d4799e8 100644 --- a/src/windows/identity/uilib/khactiondef.h +++ b/src/windows/identity/uilib/khactiondef.h @@ -42,7 +42,6 @@ #define KHUI_ACTION_SET_SRCH_ID (KHUI_ACTION_BASE + 4) #define KHUI_ACTION_PASSWD_ID (KHUI_ACTION_BASE + 7) #define KHUI_ACTION_NEW_CRED (KHUI_ACTION_BASE + 8) -#define KHUI_ACTION_CHOOSE_COLS (KHUI_ACTION_BASE + 9) #define KHUI_ACTION_DEBUG_WINDOW (KHUI_ACTION_BASE + 10) #define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11) #define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12) @@ -63,6 +62,7 @@ #define KHUI_ACTION_CLOSE_APP (KHUI_ACTION_BASE + 27) #define KHUI_ACTION_IMPORT (KHUI_ACTION_BASE + 28) #define KHUI_ACTION_OPT_PLUGINS (KHUI_ACTION_BASE + 29) +#define KHUI_ACTION_LAYOUT_CUST (KHUI_ACTION_BASE + 30) /*@}*/ /*! \name Pseudo actions @@ -92,6 +92,17 @@ context. #define KHUI_PACTION_BLANK (KHUI_PACTION_BASE + 15) #define KHUI_PACTION_NEXT (KHUI_PACTION_BASE + 16) #define KHUI_PACTION_SELALL (KHUI_PACTION_BASE + 17) +#define KHUI_PACTION_YES (KHUI_PACTION_BASE + 18) +#define KHUI_PACTION_NO (KHUI_PACTION_BASE + 19) +#define KHUI_PACTION_YESALL (KHUI_PACTION_BASE + 20) +#define KHUI_PACTION_NOALL (KHUI_PACTION_BASE + 21) +#define KHUI_PACTION_REMOVE (KHUI_PACTION_BASE + 22) +#define KHUI_PACTION_KEEP (KHUI_PACTION_BASE + 23) +#define KHUI_PACTION_DISCARD (KHUI_PACTION_BASE + 24) +#define KHUI_PACTION_PGDN (KHUI_PACTION_BASE + 25) +#define KHUI_PACTION_PGUP (KHUI_PACTION_BASE + 26) +#define KHUI_PACTION_PGUP_EXTEND (KHUI_PACTION_BASE + 27) +#define KHUI_PACTION_PGDN_EXTEND (KHUI_PACTION_BASE + 28) /*@}*/ /*! \name Menus @@ -115,6 +126,9 @@ Stock menus. #define KHUI_MENU_TOK_CTX (KHUI_MENU_BASE + 9) #define KHUI_MENU_ICO_CTX_MIN (KHUI_MENU_BASE + 12) #define KHUI_MENU_ICO_CTX_NORMAL (KHUI_MENU_BASE + 13) +#define KHUI_MENU_CWHEADER_CTX (KHUI_MENU_BASE + 14) + +#define KHUI_MENU_COLUMNS (KHUI_MENU_BASE + 15) #define KHUI_PMENU_TOK_SEL (KHUI_MENU_BASE + 10) #define KHUI_PMENU_ID_SEL (KHUI_MENU_BASE + 11) @@ -129,8 +143,15 @@ Stock menus. #define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0) /*@}*/ -/* base for user actions */ +/*! \brief Base for user actions + + When creating new actions, the UI library will allocate command + identifiers starting with this one. +*/ #define KHUI_USERACTION_BASE (KHUI_ACTION_BASE + 10000) + +/*! \brief Does this command represent a user action? */ +#define IS_USERACTION(cmd) ((cmd) >= KHUI_USERACTION_BASE) /*@}*/ /*@}*/ diff --git a/src/windows/identity/uilib/khalerts.h b/src/windows/identity/uilib/khalerts.h index 36b13a333..f10ffa198 100644 --- a/src/windows/identity/uilib/khalerts.h +++ b/src/windows/identity/uilib/khalerts.h @@ -179,6 +179,9 @@ enum khui_alert_flags { KHUI_ALERT_FLAG_REQUEST_BALLOON =0x08000000, /*!< The alert should be displayed in a balloon */ + KHUI_ALERT_FLAG_MODAL =0x10000000, + /*!< Modal alert. Do not set direclty. */ + KHUI_ALERT_FLAGMASK_RDWR =0x0C000010, /*!< Bit mask of flags that can be set by khui_alert_set_flags() */ }; @@ -306,6 +309,19 @@ khui_alert_add_command(khui_alert * alert, KHMEXP khm_int32 KHMAPI khui_alert_show(khui_alert * alert); +/*! \brief Display a modal alert + + Similar to khui_alert_show(), but shows a modal alert dialog. The + function does not return until the user has closed the alert. + + This function always opens an alert window (never shows a + balloon). + + \note Should only be called from the UI thread. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_show_modal(khui_alert * alert); + /*! \brief Queue an alert Instead of displaying the alert immediately, the alert is queued diff --git a/src/windows/identity/uilib/khconfigui.h b/src/windows/identity/uilib/khconfigui.h index ac9fc614c..f124b513f 100644 --- a/src/windows/identity/uilib/khconfigui.h +++ b/src/windows/identity/uilib/khconfigui.h @@ -131,11 +131,17 @@ typedef struct tag_khui_config_node_reg { /*! \brief Node represents a panel that is replicated for all child nodes */ #define KHUI_CNFLAG_PLURAL 0x0004 -#define KHUI_CNFLAG_MODIFIED 0x0010 -#define KHUI_CNFLAG_APPLIED 0x0020 +/*! \brief System node -#define KHUI_CNFLAGMASK_STATIC 0x000f -#define KHUI_CNFLAGMASK_DYNAMIC 0x00f0 + \note For internal use by the NetIDMgr application. Do not use. +*/ +#define KHUI_CNFLAG_SYSTEM 0x0010 + +#define KHUI_CNFLAG_MODIFIED 0x0100 +#define KHUI_CNFLAG_APPLIED 0x0200 + +#define KHUI_CNFLAGMASK_STATIC 0x00ff +#define KHUI_CNFLAGMASK_DYNAMIC 0x0f00 /*! \brief Maximum length of the name in characters @@ -250,6 +256,10 @@ typedef struct tag_khui_config_init_data { of reg were invalid \retval KHM_ERROR_DUPLICATE A node with the same name exists as a child of the specified parent node. + + \note The name (not the short or long description) of the node can + not be the same as the name of a custom action. See + khui_action_create(). */ KHMEXP khm_int32 KHMAPI khui_cfg_register(khui_config_node parent, diff --git a/src/windows/identity/uilib/khnewcred.h b/src/windows/identity/uilib/khnewcred.h index 257434454..45df19779 100644 --- a/src/windows/identity/uilib/khnewcred.h +++ b/src/windows/identity/uilib/khnewcred.h @@ -263,7 +263,7 @@ typedef struct tag_khui_new_creds { khm_size nc_types; /*!< Internal use */ khm_int32 result; /*!< One of ::KHUI_NC_RESULT_CANCEL or - ::KHUI_NC_RESULT_GET_CREDS indicating + ::KHUI_NC_RESULT_PROCESS indicating the result of the dialog with the user */ @@ -296,7 +296,7 @@ typedef struct tag_khui_new_creds { /*!\name Result values for khui_new_creds_t::result @{*/ -#define KHUI_NC_RESULT_GET_CREDS 0 +#define KHUI_NC_RESULT_PROCESS 0 #define KHUI_NC_RESULT_CANCEL 1 /*@}*/ diff --git a/src/windows/identity/uilib/khversion.h b/src/windows/identity/uilib/khversion.h new file mode 100644 index 000000000..d5dc36d24 --- /dev/null +++ b/src/windows/identity/uilib/khversion.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 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_KHUIDEFS_H +#define __KHIMAIRA_KHUIDEFS_H + + + +#endif diff --git a/src/windows/identity/uilib/trackerwnd.c b/src/windows/identity/uilib/trackerwnd.c index 814e28808..b0da7d15d 100644 --- a/src/windows/identity/uilib/trackerwnd.c +++ b/src/windows/identity/uilib/trackerwnd.c @@ -307,16 +307,19 @@ duration_edit_proc(HWND hwnd, p = GetParent(hwnd); - /* we are being activated. show the panel */ + /* we are being activated. */ if(tc->hw_slider == NULL) { create_edit_sliders(hwnd, p, tc); initialize_tracker(p, tc); } + khui_tracker_reposition(tc); + +#ifdef SHOW_PANEL_ON_FIRST_ACTIVATE ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); +#endif tc->act_time = GetTickCount(); - //SetActiveWindow(p); } break; @@ -338,18 +341,17 @@ duration_edit_proc(HWND hwnd, break; case KHUI_WM_NC_NOTIFY: - if(HIWORD(wParam) == WMNC_DIALOG_SETUP) - { - HWND p; - - p = GetParent(hwnd); + if(HIWORD(wParam) == WMNC_DIALOG_SETUP) { + HWND p; - if(tc->hw_slider == NULL) { - create_edit_sliders(hwnd,p,tc); - } + p = GetParent(hwnd); - initialize_tracker(p, tc); + if(tc->hw_slider == NULL) { + create_edit_sliders(hwnd,p,tc); } + + initialize_tracker(p, tc); + } return TRUE; case WM_LBUTTONUP: @@ -357,7 +359,7 @@ duration_edit_proc(HWND hwnd, DWORD tm; tm = GetTickCount(); - if (tm - tc->act_time > 500) + if (tm - tc->act_time > 000) ShowWindow(tc->hw_slider, SW_HIDE); } else { ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); diff --git a/src/windows/identity/util/perfstat.c b/src/windows/identity/util/perfstat.c index 814920dce..6cf8ae44a 100644 --- a/src/windows/identity/util/perfstat.c +++ b/src/windows/identity/util/perfstat.c @@ -41,6 +41,9 @@ typedef struct tag_allocation { int line; size_t size; void * ptr; +#ifdef _WIN32 + DWORD thread; +#endif LDCL(struct tag_allocation); } allocation; @@ -165,6 +168,9 @@ perf_malloc(char * file, int line, size_t s) { a->line = line; a->size = s; a->ptr = ptr; +#ifdef _WIN32 + a->thread = GetCurrentThreadId(); +#endif h = HASHPTR(ptr); @@ -246,11 +252,12 @@ perf_dump(char * file) { return; fprintf(f, "Leaked allocations list ....\n"); - fprintf(f, "File\tLine\tSize\n"); + fprintf(f, "File\tLine\tThread\tSize\n"); for (i=0; i < HASHSIZE; i++) { for (a = ht[i]; a; a = LNEXT(a)) { - fprintf(f, "%s\t%6d\t%6d\n", a->file, a->line, a->size); + fprintf(f, "%s\t%6d\t%6d\t%6d\n", a->file, a->line, + a->thread, a->size); total += a->size; } } -- 2.26.2